Merge remote-tracking branch 'goog/mirror-m-wireless-internal-release'
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index 85f44f0..3a9fb4c 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -55,7 +55,7 @@
if (camera->connect(c) == NO_ERROR) {
c->mStatus = NO_ERROR;
c->mCamera = camera;
- camera->asBinder()->linkToDeath(c);
+ IInterface::asBinder(camera)->linkToDeath(c);
return c;
}
return 0;
@@ -93,7 +93,7 @@
clientUid, /*out*/c->mCamera);
}
if (status == OK && c->mCamera != 0) {
- c->mCamera->asBinder()->linkToDeath(c);
+ IInterface::asBinder(c->mCamera)->linkToDeath(c);
c->mStatus = NO_ERROR;
camera = c;
} else {
diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp
index 04694cd..65a1a47 100644
--- a/camera/CameraBase.cpp
+++ b/camera/CameraBase.cpp
@@ -107,7 +107,7 @@
/*out*/ c->mCamera);
}
if (status == OK && c->mCamera != 0) {
- c->mCamera->asBinder()->linkToDeath(c);
+ IInterface::asBinder(c->mCamera)->linkToDeath(c);
c->mStatus = NO_ERROR;
} else {
ALOGW("An error occurred while connecting to camera: %d", cameraId);
@@ -122,7 +122,7 @@
ALOGV("%s: disconnect", __FUNCTION__);
if (mCamera != 0) {
mCamera->disconnect();
- mCamera->asBinder()->unlinkToDeath(this);
+ IInterface::asBinder(mCamera)->unlinkToDeath(this);
mCamera = 0;
}
ALOGV("%s: disconnect (done)", __FUNCTION__);
diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp
index e5e4e90..3dbf75e 100644
--- a/camera/CameraParameters.cpp
+++ b/camera/CameraParameters.cpp
@@ -526,7 +526,7 @@
!strcmp(format, PIXEL_FORMAT_RGBA8888) ?
HAL_PIXEL_FORMAT_RGBA_8888 : // RGB8888
!strcmp(format, PIXEL_FORMAT_BAYER_RGGB) ?
- HAL_PIXEL_FORMAT_RAW_SENSOR : // Raw sensor data
+ HAL_PIXEL_FORMAT_RAW16 : // Raw sensor data
-1;
}
diff --git a/camera/ICamera.cpp b/camera/ICamera.cpp
index 8c6e1f7..9943be6 100644
--- a/camera/ICamera.cpp
+++ b/camera/ICamera.cpp
@@ -75,7 +75,7 @@
ALOGV("setPreviewTarget");
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
- sp<IBinder> b(bufferProducer->asBinder());
+ sp<IBinder> b(IInterface::asBinder(bufferProducer));
data.writeStrongBinder(b);
remote()->transact(SET_PREVIEW_TARGET, data, &reply);
return reply.readInt32();
@@ -98,7 +98,7 @@
ALOGV("setPreviewCallbackTarget");
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
- sp<IBinder> b(callbackProducer->asBinder());
+ sp<IBinder> b(IInterface::asBinder(callbackProducer));
data.writeStrongBinder(b);
remote()->transact(SET_PREVIEW_CALLBACK_TARGET, data, &reply);
return reply.readInt32();
@@ -147,7 +147,7 @@
ALOGV("releaseRecordingFrame");
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
- data.writeStrongBinder(mem->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(mem));
remote()->transact(RELEASE_RECORDING_FRAME, data, &reply);
}
@@ -250,7 +250,7 @@
{
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
- data.writeStrongBinder(cameraClient->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(cameraClient));
remote()->transact(CONNECT, data, &reply);
return reply.readInt32();
}
diff --git a/camera/ICameraClient.cpp b/camera/ICameraClient.cpp
index 205c8ba..179a341 100644
--- a/camera/ICameraClient.cpp
+++ b/camera/ICameraClient.cpp
@@ -58,7 +58,7 @@
Parcel data, reply;
data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
data.writeInt32(msgType);
- data.writeStrongBinder(imageData->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(imageData));
if (metadata) {
data.writeInt32(metadata->number_of_faces);
data.write(metadata->faces, sizeof(camera_face_t) * metadata->number_of_faces);
@@ -74,7 +74,7 @@
data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
data.writeInt64(timestamp);
data.writeInt32(msgType);
- data.writeStrongBinder(imageData->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(imageData));
remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply, IBinder::FLAG_ONEWAY);
}
};
diff --git a/camera/ICameraRecordingProxy.cpp b/camera/ICameraRecordingProxy.cpp
index 7223b6d..3dc0ffb 100644
--- a/camera/ICameraRecordingProxy.cpp
+++ b/camera/ICameraRecordingProxy.cpp
@@ -45,7 +45,7 @@
ALOGV("startRecording");
Parcel data, reply;
data.writeInterfaceToken(ICameraRecordingProxy::getInterfaceDescriptor());
- data.writeStrongBinder(listener->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(listener));
remote()->transact(START_RECORDING, data, &reply);
return reply.readInt32();
}
@@ -63,7 +63,7 @@
ALOGV("releaseRecordingFrame");
Parcel data, reply;
data.writeInterfaceToken(ICameraRecordingProxy::getInterfaceDescriptor());
- data.writeStrongBinder(mem->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(mem));
remote()->transact(RELEASE_RECORDING_FRAME, data, &reply);
}
};
diff --git a/camera/ICameraRecordingProxyListener.cpp b/camera/ICameraRecordingProxyListener.cpp
index cb17f19..cf848fc 100644
--- a/camera/ICameraRecordingProxyListener.cpp
+++ b/camera/ICameraRecordingProxyListener.cpp
@@ -42,7 +42,7 @@
data.writeInterfaceToken(ICameraRecordingProxyListener::getInterfaceDescriptor());
data.writeInt64(timestamp);
data.writeInt32(msgType);
- data.writeStrongBinder(imageData->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(imageData));
remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply, IBinder::FLAG_ONEWAY);
}
};
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index 5485205..a75cb48 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -172,7 +172,7 @@
{
Parcel data, reply;
data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
- data.writeStrongBinder(cameraClient->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(cameraClient));
data.writeInt32(cameraId);
data.writeString16(clientPackageName);
data.writeInt32(clientUid);
@@ -194,7 +194,7 @@
{
Parcel data, reply;
data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
- data.writeStrongBinder(cameraClient->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(cameraClient));
data.writeInt32(cameraId);
data.writeInt32(halVersion);
data.writeString16(clientPackageName);
@@ -209,6 +209,20 @@
return status;
}
+ virtual status_t setTorchMode(const String16& cameraId, bool enabled,
+ const sp<IBinder>& clientBinder)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
+ data.writeString16(cameraId);
+ data.writeInt32(enabled ? 1 : 0);
+ data.writeStrongBinder(clientBinder);
+ remote()->transact(BnCameraService::SET_TORCH_MODE, data, &reply);
+
+ if (readExceptionCode(reply)) return -EPROTO;
+ return reply.readInt32();
+ }
+
// connect to camera service (pro client)
virtual status_t connectPro(const sp<IProCameraCallbacks>& cameraCb, int cameraId,
const String16 &clientPackageName, int clientUid,
@@ -217,7 +231,7 @@
{
Parcel data, reply;
data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
- data.writeStrongBinder(cameraCb->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(cameraCb));
data.writeInt32(cameraId);
data.writeString16(clientPackageName);
data.writeInt32(clientUid);
@@ -242,7 +256,7 @@
{
Parcel data, reply;
data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
- data.writeStrongBinder(cameraCb->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(cameraCb));
data.writeInt32(cameraId);
data.writeString16(clientPackageName);
data.writeInt32(clientUid);
@@ -260,7 +274,7 @@
{
Parcel data, reply;
data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
- data.writeStrongBinder(listener->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(listener));
remote()->transact(BnCameraService::ADD_LISTENER, data, &reply);
if (readExceptionCode(reply)) return -EPROTO;
@@ -271,7 +285,7 @@
{
Parcel data, reply;
data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
- data.writeStrongBinder(listener->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(listener));
remote()->transact(BnCameraService::REMOVE_LISTENER, data, &reply);
if (readExceptionCode(reply)) return -EPROTO;
@@ -384,7 +398,7 @@
reply->writeInt32(status);
if (camera != NULL) {
reply->writeInt32(1);
- reply->writeStrongBinder(camera->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(camera));
} else {
reply->writeInt32(0);
}
@@ -404,7 +418,7 @@
reply->writeInt32(status);
if (camera != NULL) {
reply->writeInt32(1);
- reply->writeStrongBinder(camera->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(camera));
} else {
reply->writeInt32(0);
}
@@ -424,7 +438,7 @@
reply->writeInt32(status);
if (camera != NULL) {
reply->writeInt32(1);
- reply->writeStrongBinder(camera->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(camera));
} else {
reply->writeInt32(0);
}
@@ -484,12 +498,22 @@
reply->writeInt32(status);
if (camera != NULL) {
reply->writeInt32(1);
- reply->writeStrongBinder(camera->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(camera));
} else {
reply->writeInt32(0);
}
return NO_ERROR;
} break;
+ case SET_TORCH_MODE: {
+ CHECK_INTERFACE(ICameraService, data, reply);
+ String16 cameraId = data.readString16();
+ bool enabled = data.readInt32() != 0 ? true : false;
+ const sp<IBinder> clientBinder = data.readStrongBinder();
+ status_t status = setTorchMode(cameraId, enabled, clientBinder);
+ reply->writeNoException();
+ reply->writeInt32(status);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/camera/ICameraServiceListener.cpp b/camera/ICameraServiceListener.cpp
index b2f1729..90a8bc2 100644
--- a/camera/ICameraServiceListener.cpp
+++ b/camera/ICameraServiceListener.cpp
@@ -29,6 +29,7 @@
namespace {
enum {
STATUS_CHANGED = IBinder::FIRST_CALL_TRANSACTION,
+ TORCH_STATUS_CHANGED,
};
}; // namespace anonymous
@@ -54,8 +55,21 @@
data,
&reply,
IBinder::FLAG_ONEWAY);
+ }
- reply.readExceptionCode();
+ virtual void onTorchStatusChanged(TorchStatus status, const String16 &cameraId)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ ICameraServiceListener::getInterfaceDescriptor());
+
+ data.writeInt32(static_cast<int32_t>(status));
+ data.writeString16(cameraId);
+
+ remote()->transact(TORCH_STATUS_CHANGED,
+ data,
+ &reply,
+ IBinder::FLAG_ONEWAY);
}
};
@@ -75,7 +89,16 @@
int32_t cameraId = data.readInt32();
onStatusChanged(status, cameraId);
- reply->writeNoException();
+
+ return NO_ERROR;
+ } break;
+ case TORCH_STATUS_CHANGED: {
+ CHECK_INTERFACE(ICameraServiceListener, data, reply);
+
+ TorchStatus status = static_cast<TorchStatus>(data.readInt32());
+ String16 cameraId = data.readString16();
+
+ onTorchStatusChanged(status, cameraId);
return NO_ERROR;
} break;
diff --git a/camera/IProCameraUser.cpp b/camera/IProCameraUser.cpp
index 8f22124..9bd7597 100644
--- a/camera/IProCameraUser.cpp
+++ b/camera/IProCameraUser.cpp
@@ -65,7 +65,7 @@
{
Parcel data, reply;
data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor());
- data.writeStrongBinder(cameraClient->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(cameraClient));
remote()->transact(CONNECT, data, &reply);
return reply.readInt32();
}
@@ -150,7 +150,7 @@
data.writeInt32(height);
data.writeInt32(format);
- sp<IBinder> b(bufferProducer->asBinder());
+ sp<IBinder> b(IInterface::asBinder(bufferProducer));
data.writeStrongBinder(b);
remote()->transact(CREATE_STREAM, data, &reply);
diff --git a/camera/camera2/CaptureRequest.cpp b/camera/camera2/CaptureRequest.cpp
index fb74c8d..66d6913 100644
--- a/camera/camera2/CaptureRequest.cpp
+++ b/camera/camera2/CaptureRequest.cpp
@@ -106,7 +106,7 @@
sp<IBinder> binder;
if (surface != 0) {
- binder = surface->getIGraphicBufferProducer()->asBinder();
+ binder = IInterface::asBinder(surface->getIGraphicBufferProducer());
}
// not sure if readParcelableArray does this, hard to tell from source
diff --git a/camera/camera2/ICameraDeviceUser.cpp b/camera/camera2/ICameraDeviceUser.cpp
index ff4a0c2..d1d63d5 100644
--- a/camera/camera2/ICameraDeviceUser.cpp
+++ b/camera/camera2/ICameraDeviceUser.cpp
@@ -107,7 +107,7 @@
}
}
- if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) {
+ if ((res < NO_ERROR) || (resFrameNumber != NO_ERROR)) {
res = FAILED_TRANSACTION;
}
return res;
@@ -147,7 +147,7 @@
resFrameNumber = reply.readInt64(lastFrameNumber);
}
}
- if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) {
+ if ((res < NO_ERROR) || (resFrameNumber != NO_ERROR)) {
res = FAILED_TRANSACTION;
}
return res;
@@ -167,7 +167,7 @@
status_t resFrameNumber = BAD_VALUE;
if (reply.readInt32() != 0) {
if (lastFrameNumber != NULL) {
- res = reply.readInt64(lastFrameNumber);
+ resFrameNumber = reply.readInt64(lastFrameNumber);
}
}
if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) {
@@ -208,18 +208,15 @@
return reply.readInt32();
}
- virtual status_t createStream(int width, int height, int format,
+ virtual status_t createStream(
const sp<IGraphicBufferProducer>& bufferProducer)
{
Parcel data, reply;
data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
- data.writeInt32(width);
- data.writeInt32(height);
- data.writeInt32(format);
data.writeInt32(1); // marker that bufferProducer is not null
data.writeString16(String16("unknown_name")); // name of surface
- sp<IBinder> b(bufferProducer->asBinder());
+ sp<IBinder> b(IInterface::asBinder(bufferProducer));
data.writeStrongBinder(b);
remote()->transact(CREATE_STREAM, data, &reply);
@@ -296,7 +293,7 @@
status_t resFrameNumber = BAD_VALUE;
if (reply.readInt32() != 0) {
if (lastFrameNumber != NULL) {
- res = reply.readInt64(lastFrameNumber);
+ resFrameNumber = reply.readInt64(lastFrameNumber);
}
}
if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) {
@@ -396,14 +393,6 @@
} break;
case CREATE_STREAM: {
CHECK_INTERFACE(ICameraDeviceUser, data, reply);
- int width, height, format;
-
- width = data.readInt32();
- ALOGV("%s: CREATE_STREAM: width = %d", __FUNCTION__, width);
- height = data.readInt32();
- ALOGV("%s: CREATE_STREAM: height = %d", __FUNCTION__, height);
- format = data.readInt32();
- ALOGV("%s: CREATE_STREAM: format = %d", __FUNCTION__, format);
sp<IGraphicBufferProducer> bp;
if (data.readInt32() != 0) {
@@ -419,7 +408,7 @@
}
status_t ret;
- ret = createStream(width, height, format, bp);
+ ret = createStream(bp);
reply->writeNoException();
ALOGV("%s: CREATE_STREAM: write noException", __FUNCTION__);
diff --git a/camera/tests/Android.mk b/camera/tests/Android.mk
index 61385e5..2db4c14 100644
--- a/camera/tests/Android.mk
+++ b/camera/tests/Android.mk
@@ -14,16 +14,15 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_SRC_FILES:= \
- main.cpp \
ProCameraTests.cpp \
VendorTagDescriptorTests.cpp
LOCAL_SHARED_LIBRARIES := \
libutils \
libcutils \
- libstlport \
libcamera_metadata \
libcamera_client \
libgui \
@@ -32,14 +31,7 @@
libdl \
libbinder
-LOCAL_STATIC_LIBRARIES := \
- libgtest
-
LOCAL_C_INCLUDES += \
- bionic \
- bionic/libstdc++/include \
- external/gtest/include \
- external/stlport/stlport \
system/media/camera/include \
system/media/private/camera/include \
system/media/camera/tests \
diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp
index 1f5867a..24b2327 100644
--- a/camera/tests/ProCameraTests.cpp
+++ b/camera/tests/ProCameraTests.cpp
@@ -89,6 +89,12 @@
mCondition.broadcast();
}
+ void onTorchStatusChanged(TorchStatus status, const String16& cameraId) {
+ dout << "On torch status changed: 0x" << std::hex
+ << (unsigned int) status << " cameraId " << cameraId.string()
+ << std::endl;
+ }
+
status_t waitForStatusChange(Status& newStatus) {
Mutex::Autolock al(mMutex);
@@ -469,7 +475,7 @@
CMP_STR(NV16, YCbCr_422_SP);
CMP_STR(NV21, YCrCb_420_SP);
CMP_STR(YUY2, YCbCr_422_I);
- CMP_STR(RAW, RAW_SENSOR);
+ CMP_STR(RAW, RAW16);
CMP_STR(RGBA, RGBA_8888);
std::cerr << "Unknown format string " << str << std::endl;
diff --git a/cmds/screenrecord/TextRenderer.cpp b/cmds/screenrecord/TextRenderer.cpp
index 6a9176b..01f73e0 100644
--- a/cmds/screenrecord/TextRenderer.cpp
+++ b/cmds/screenrecord/TextRenderer.cpp
@@ -21,6 +21,8 @@
#include "TextRenderer.h"
#include <assert.h>
+#include <malloc.h>
+#include <string.h>
namespace android {
#include "FontBitmap.h"
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index 02df1d2..36a7e73 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -23,7 +23,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <sys/wait.h>
+
#include <termios.h>
#include <unistd.h>
@@ -637,7 +640,13 @@
case FORMAT_MP4: {
// Configure muxer. We have to wait for the CSD blob from the encoder
// before we can start it.
- muxer = new MediaMuxer(fileName, MediaMuxer::OUTPUT_FORMAT_MPEG_4);
+ int fd = open(fileName, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ fprintf(stderr, "ERROR: couldn't open file\n");
+ abort();
+ }
+ muxer = new MediaMuxer(fd, MediaMuxer::OUTPUT_FORMAT_MPEG_4);
+ close(fd);
if (gRotate) {
muxer->setOrientationHint(90); // TODO: does this do anything?
}
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 561ce02..0e3bc68 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -169,6 +169,48 @@
include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= \
+ filters/argbtorgba.rs \
+ filters/nightvision.rs \
+ filters/saturation.rs \
+ mediafilter.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright \
+ liblog \
+ libutils \
+ libbinder \
+ libstagefright_foundation \
+ libmedia \
+ libgui \
+ libcutils \
+ libui \
+ libRScpp \
+
+LOCAL_C_INCLUDES:= \
+ $(TOP)/frameworks/av/media/libstagefright \
+ $(TOP)/frameworks/native/include/media/openmax \
+ $(TOP)/frameworks/rs/cpp \
+ $(TOP)/frameworks/rs \
+
+intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
+LOCAL_C_INCLUDES += $(intermediates)
+
+LOCAL_STATIC_LIBRARIES:= \
+ libstagefright_mediafilter
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE:= mediafilter
+
+include $(BUILD_EXECUTABLE)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
LOCAL_SRC_FILES:= \
muxer.cpp \
diff --git a/cmds/stagefright/SimplePlayer.cpp b/cmds/stagefright/SimplePlayer.cpp
index 1b2f792..ac1a547 100644
--- a/cmds/stagefright/SimplePlayer.cpp
+++ b/cmds/stagefright/SimplePlayer.cpp
@@ -59,14 +59,14 @@
return err;
}
status_t SimplePlayer::setDataSource(const char *path) {
- sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
+ sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
msg->setString("path", path);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
status_t SimplePlayer::setSurface(const sp<IGraphicBufferProducer> &bufferProducer) {
- sp<AMessage> msg = new AMessage(kWhatSetSurface, id());
+ sp<AMessage> msg = new AMessage(kWhatSetSurface, this);
sp<Surface> surface;
if (bufferProducer != NULL) {
@@ -81,25 +81,25 @@
}
status_t SimplePlayer::prepare() {
- sp<AMessage> msg = new AMessage(kWhatPrepare, id());
+ sp<AMessage> msg = new AMessage(kWhatPrepare, this);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
status_t SimplePlayer::start() {
- sp<AMessage> msg = new AMessage(kWhatStart, id());
+ sp<AMessage> msg = new AMessage(kWhatStart, this);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
status_t SimplePlayer::stop() {
- sp<AMessage> msg = new AMessage(kWhatStop, id());
+ sp<AMessage> msg = new AMessage(kWhatStop, this);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
status_t SimplePlayer::reset() {
- sp<AMessage> msg = new AMessage(kWhatReset, id());
+ sp<AMessage> msg = new AMessage(kWhatReset, this);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
@@ -116,7 +116,7 @@
mState = UNPREPARED;
}
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
sp<AMessage> response = new AMessage;
@@ -139,7 +139,7 @@
err = OK;
}
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
sp<AMessage> response = new AMessage;
@@ -161,7 +161,7 @@
}
}
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
sp<AMessage> response = new AMessage;
@@ -194,7 +194,7 @@
}
}
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
sp<AMessage> response = new AMessage;
@@ -217,7 +217,7 @@
}
}
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
sp<AMessage> response = new AMessage;
@@ -240,7 +240,7 @@
mState = UNINITIALIZED;
}
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
sp<AMessage> response = new AMessage;
@@ -332,7 +332,7 @@
size_t j = 0;
sp<ABuffer> buffer;
- while (format->findBuffer(StringPrintf("csd-%d", j).c_str(), &buffer)) {
+ while (format->findBuffer(AStringPrintf("csd-%d", j).c_str(), &buffer)) {
state->mCSD.push_back(buffer);
++j;
@@ -382,7 +382,7 @@
mStartTimeRealUs = -1ll;
- sp<AMessage> msg = new AMessage(kWhatDoMoreStuff, id());
+ sp<AMessage> msg = new AMessage(kWhatDoMoreStuff, this);
msg->setInt32("generation", ++mDoMoreStuffGeneration);
msg->post();
diff --git a/cmds/stagefright/SineSource.h b/cmds/stagefright/SineSource.h
index 76ab669..be05661 100644
--- a/cmds/stagefright/SineSource.h
+++ b/cmds/stagefright/SineSource.h
@@ -3,10 +3,11 @@
#define SINE_SOURCE_H_
#include <media/stagefright/MediaSource.h>
+#include <utils/Compat.h>
namespace android {
-struct MediaBufferGroup;
+class MediaBufferGroup;
struct SineSource : public MediaSource {
SineSource(int32_t sampleRate, int32_t numChannels);
@@ -24,7 +25,7 @@
private:
enum { kBufferSize = 8192 };
- static const double kFrequency = 500.0;
+ static const CONSTEXPR double kFrequency = 500.0;
bool mStarted;
int32_t mSampleRate;
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index 96073f1..7b0de24 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
#include <binder/ProcessState.h>
#include <media/mediarecorder.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -109,7 +113,12 @@
if (fileOut != NULL) {
// target file specified, write encoded AMR output
- sp<AMRWriter> writer = new AMRWriter(fileOut);
+ int fd = open(fileOut, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ return 1;
+ }
+ sp<AMRWriter> writer = new AMRWriter(fd);
+ close(fd);
writer->addSource(encoder);
writer->start();
sleep(duration);
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index fd02bcc..d987250 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -45,9 +45,10 @@
fprintf(stderr, "usage: %s [-a] use audio\n"
"\t\t[-v] use video\n"
"\t\t[-p] playback\n"
- "\t\t[-S] allocate buffers from a surface\n",
+ "\t\t[-S] allocate buffers from a surface\n"
+ "\t\t[-R] render output to surface (enables -S)\n"
+ "\t\t[-T] use render timestamps (enables -R)\n",
me);
-
exit(1);
}
@@ -71,7 +72,9 @@
const char *path,
bool useAudio,
bool useVideo,
- const android::sp<android::Surface> &surface) {
+ const android::sp<android::Surface> &surface,
+ bool renderSurface,
+ bool useTimestamp) {
using namespace android;
static int64_t kTimeout = 500ll;
@@ -136,6 +139,7 @@
CHECK(!stateByTrack.isEmpty());
int64_t startTimeUs = ALooper::GetNowUs();
+ int64_t startTimeRender = -1;
for (size_t i = 0; i < stateByTrack.size(); ++i) {
CodecState *state = &stateByTrack.editValueAt(i);
@@ -260,7 +264,23 @@
++state->mNumBuffersDecoded;
state->mNumBytesDecoded += size;
- err = state->mCodec->releaseOutputBuffer(index);
+ if (surface == NULL || !renderSurface) {
+ err = state->mCodec->releaseOutputBuffer(index);
+ } else if (useTimestamp) {
+ if (startTimeRender == -1) {
+ // begin rendering 2 vsyncs (~33ms) after first decode
+ startTimeRender =
+ systemTime(SYSTEM_TIME_MONOTONIC) + 33000000
+ - (presentationTimeUs * 1000);
+ }
+ presentationTimeUs =
+ (presentationTimeUs * 1000) + startTimeRender;
+ err = state->mCodec->renderOutputBufferAndRelease(
+ index, presentationTimeUs);
+ } else {
+ err = state->mCodec->renderOutputBufferAndRelease(index);
+ }
+
CHECK_EQ(err, (status_t)OK);
if (flags & MediaCodec::BUFFER_FLAG_EOS) {
@@ -320,34 +340,42 @@
bool useVideo = false;
bool playback = false;
bool useSurface = false;
+ bool renderSurface = false;
+ bool useTimestamp = false;
int res;
- while ((res = getopt(argc, argv, "havpSD")) >= 0) {
+ while ((res = getopt(argc, argv, "havpSDRT")) >= 0) {
switch (res) {
case 'a':
{
useAudio = true;
break;
}
-
case 'v':
{
useVideo = true;
break;
}
-
case 'p':
{
playback = true;
break;
}
-
+ case 'T':
+ {
+ useTimestamp = true;
+ }
+ // fall through
+ case 'R':
+ {
+ renderSurface = true;
+ }
+ // fall through
case 'S':
{
useSurface = true;
break;
}
-
case '?':
case 'h':
default:
@@ -422,7 +450,8 @@
player->stop();
player->reset();
} else {
- decode(looper, argv[0], useAudio, useVideo, surface);
+ decode(looper, argv[0], useAudio, useVideo, surface, renderSurface,
+ useTimestamp);
}
if (playback || (useSurface && useVideo)) {
diff --git a/camera/tests/main.cpp b/cmds/stagefright/filters/argbtorgba.rs
similarity index 65%
rename from camera/tests/main.cpp
rename to cmds/stagefright/filters/argbtorgba.rs
index 8c8c515..229ff8c 100644
--- a/camera/tests/main.cpp
+++ b/cmds/stagefright/filters/argbtorgba.rs
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.cppbasic)
+#pragma rs_fp_relaxed
-
-int main(int argc, char **argv) {
-
- ::testing::InitGoogleTest(&argc, argv);
-
- int ret = RUN_ALL_TESTS();
-
- return ret;
-}
+void root(const uchar4 *v_in, uchar4 *v_out) {
+ v_out->x = v_in->y;
+ v_out->y = v_in->z;
+ v_out->z = v_in->w;
+ v_out->w = v_in->x;
+}
\ No newline at end of file
diff --git a/cmds/stagefright/filters/nightvision.rs b/cmds/stagefright/filters/nightvision.rs
new file mode 100644
index 0000000..f61413c
--- /dev/null
+++ b/cmds/stagefright/filters/nightvision.rs
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.cppbasic)
+#pragma rs_fp_relaxed
+
+const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
+const static float3 gNightVisionMult = {0.5f, 1.f, 0.5f};
+
+// calculates luminance of pixel, then biases color balance toward green
+void root(const uchar4 *v_in, uchar4 *v_out) {
+ v_out->x = v_in->x; // don't modify A
+
+ // get RGB, scale 0-255 uchar to 0-1.0 float
+ float3 rgb = {v_in->y * 0.003921569f, v_in->z * 0.003921569f,
+ v_in->w * 0.003921569f};
+
+ // apply filter
+ float3 result = dot(rgb, gMonoMult) * gNightVisionMult;
+
+ v_out->y = (uchar)clamp((result.r * 255.f + 0.5f), 0.f, 255.f);
+ v_out->z = (uchar)clamp((result.g * 255.f + 0.5f), 0.f, 255.f);
+ v_out->w = (uchar)clamp((result.b * 255.f + 0.5f), 0.f, 255.f);
+}
diff --git a/cmds/stagefright/filters/saturation.rs b/cmds/stagefright/filters/saturation.rs
new file mode 100644
index 0000000..1de9dd8
--- /dev/null
+++ b/cmds/stagefright/filters/saturation.rs
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.cppbasic)
+#pragma rs_fp_relaxed
+
+const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
+
+// global variables (parameters accessible to application code)
+float gSaturation = 1.0f;
+
+void root(const uchar4 *v_in, uchar4 *v_out) {
+ v_out->x = v_in->x; // don't modify A
+
+ // get RGB, scale 0-255 uchar to 0-1.0 float
+ float3 rgb = {v_in->y * 0.003921569f, v_in->z * 0.003921569f,
+ v_in->w * 0.003921569f};
+
+ // apply saturation filter
+ float3 result = dot(rgb, gMonoMult);
+ result = mix(result, rgb, gSaturation);
+
+ v_out->y = (uchar)clamp((result.r * 255.f + 0.5f), 0.f, 255.f);
+ v_out->z = (uchar)clamp((result.g * 255.f + 0.5f), 0.f, 255.f);
+ v_out->w = (uchar)clamp((result.b * 255.f + 0.5f), 0.f, 255.f);
+}
diff --git a/cmds/stagefright/mediafilter.cpp b/cmds/stagefright/mediafilter.cpp
new file mode 100644
index 0000000..f77b38b
--- /dev/null
+++ b/cmds/stagefright/mediafilter.cpp
@@ -0,0 +1,785 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "mediafilterTest"
+
+#include <inttypes.h>
+
+#include <binder/ProcessState.h>
+#include <filters/ColorConvert.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/Surface.h>
+#include <media/ICrypto.h>
+#include <media/IMediaHTTPService.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/NuMediaExtractor.h>
+#include <media/stagefright/RenderScriptWrapper.h>
+#include <OMX_IVCommon.h>
+#include <ui/DisplayInfo.h>
+
+#include "RenderScript.h"
+#include "ScriptC_argbtorgba.h"
+#include "ScriptC_nightvision.h"
+#include "ScriptC_saturation.h"
+
+// test parameters
+static const bool kTestFlush = true; // Note: true will drop 1 out of
+static const int kFlushAfterFrames = 25; // kFlushAfterFrames output frames
+static const int64_t kTimeout = 500ll;
+
+// built-in filter parameters
+static const int32_t kInvert = false; // ZeroFilter param
+static const float kBlurRadius = 15.0f; // IntrinsicBlurFilter param
+static const float kSaturation = 0.0f; // SaturationFilter param
+
+static void usage(const char *me) {
+ fprintf(stderr, "usage: [flags] %s\n"
+ "\t[-b] use IntrinsicBlurFilter\n"
+ "\t[-c] use argb to rgba conversion RSFilter\n"
+ "\t[-n] use night vision RSFilter\n"
+ "\t[-r] use saturation RSFilter\n"
+ "\t[-s] use SaturationFilter\n"
+ "\t[-z] use ZeroFilter (copy filter)\n"
+ "\t[-R] render output to surface (enables -S)\n"
+ "\t[-S] allocate buffers from a surface\n"
+ "\t[-T] use render timestamps (enables -R)\n",
+ me);
+ exit(1);
+}
+
+namespace android {
+
+struct SaturationRSFilter : RenderScriptWrapper::RSFilterCallback {
+ void init(RSC::sp<RSC::RS> context) {
+ mScript = new ScriptC_saturation(context);
+ mScript->set_gSaturation(3.f);
+ }
+
+ virtual status_t processBuffers(
+ RSC::Allocation *inBuffer, RSC::Allocation *outBuffer) {
+ mScript->forEach_root(inBuffer, outBuffer);
+
+ return OK;
+ }
+
+ status_t handleSetParameters(const sp<AMessage> &msg) {
+ return OK;
+ }
+
+private:
+ RSC::sp<ScriptC_saturation> mScript;
+};
+
+struct NightVisionRSFilter : RenderScriptWrapper::RSFilterCallback {
+ void init(RSC::sp<RSC::RS> context) {
+ mScript = new ScriptC_nightvision(context);
+ }
+
+ virtual status_t processBuffers(
+ RSC::Allocation *inBuffer, RSC::Allocation *outBuffer) {
+ mScript->forEach_root(inBuffer, outBuffer);
+
+ return OK;
+ }
+
+ status_t handleSetParameters(const sp<AMessage> &msg) {
+ return OK;
+ }
+
+private:
+ RSC::sp<ScriptC_nightvision> mScript;
+};
+
+struct ARGBToRGBARSFilter : RenderScriptWrapper::RSFilterCallback {
+ void init(RSC::sp<RSC::RS> context) {
+ mScript = new ScriptC_argbtorgba(context);
+ }
+
+ virtual status_t processBuffers(
+ RSC::Allocation *inBuffer, RSC::Allocation *outBuffer) {
+ mScript->forEach_root(inBuffer, outBuffer);
+
+ return OK;
+ }
+
+ status_t handleSetParameters(const sp<AMessage> &msg) {
+ return OK;
+ }
+
+private:
+ RSC::sp<ScriptC_argbtorgba> mScript;
+};
+
+struct CodecState {
+ sp<MediaCodec> mCodec;
+ Vector<sp<ABuffer> > mInBuffers;
+ Vector<sp<ABuffer> > mOutBuffers;
+ bool mSignalledInputEOS;
+ bool mSawOutputEOS;
+ int64_t mNumBuffersDecoded;
+};
+
+struct DecodedFrame {
+ size_t index;
+ size_t offset;
+ size_t size;
+ int64_t presentationTimeUs;
+ uint32_t flags;
+};
+
+enum FilterType {
+ FILTERTYPE_ZERO,
+ FILTERTYPE_INTRINSIC_BLUR,
+ FILTERTYPE_SATURATION,
+ FILTERTYPE_RS_SATURATION,
+ FILTERTYPE_RS_NIGHT_VISION,
+ FILTERTYPE_RS_ARGB_TO_RGBA,
+};
+
+size_t inputFramesSinceFlush = 0;
+void tryCopyDecodedBuffer(
+ List<DecodedFrame> *decodedFrameIndices,
+ CodecState *filterState,
+ CodecState *vidState) {
+ if (decodedFrameIndices->empty()) {
+ return;
+ }
+
+ size_t filterIndex;
+ status_t err = filterState->mCodec->dequeueInputBuffer(
+ &filterIndex, kTimeout);
+ if (err != OK) {
+ return;
+ }
+
+ ++inputFramesSinceFlush;
+
+ DecodedFrame frame = *decodedFrameIndices->begin();
+
+ // only consume a buffer if we are not going to flush, since we expect
+ // the dequeue -> flush -> queue operation to cause an error and
+ // not produce an output frame
+ if (!kTestFlush || inputFramesSinceFlush < kFlushAfterFrames) {
+ decodedFrameIndices->erase(decodedFrameIndices->begin());
+ }
+ size_t outIndex = frame.index;
+
+ const sp<ABuffer> &srcBuffer =
+ vidState->mOutBuffers.itemAt(outIndex);
+ const sp<ABuffer> &destBuffer =
+ filterState->mInBuffers.itemAt(filterIndex);
+
+ sp<AMessage> srcFormat, destFormat;
+ vidState->mCodec->getOutputFormat(&srcFormat);
+ filterState->mCodec->getInputFormat(&destFormat);
+
+ int32_t srcWidth, srcHeight, srcStride, srcSliceHeight;
+ int32_t srcColorFormat, destColorFormat;
+ int32_t destWidth, destHeight, destStride, destSliceHeight;
+ CHECK(srcFormat->findInt32("stride", &srcStride)
+ && srcFormat->findInt32("slice-height", &srcSliceHeight)
+ && srcFormat->findInt32("width", &srcWidth)
+ && srcFormat->findInt32("height", & srcHeight)
+ && srcFormat->findInt32("color-format", &srcColorFormat));
+ CHECK(destFormat->findInt32("stride", &destStride)
+ && destFormat->findInt32("slice-height", &destSliceHeight)
+ && destFormat->findInt32("width", &destWidth)
+ && destFormat->findInt32("height", & destHeight)
+ && destFormat->findInt32("color-format", &destColorFormat));
+
+ CHECK(srcWidth <= destStride && srcHeight <= destSliceHeight);
+
+ convertYUV420spToARGB(
+ srcBuffer->data(),
+ srcBuffer->data() + srcStride * srcSliceHeight,
+ srcWidth,
+ srcHeight,
+ destBuffer->data());
+
+ // copy timestamp
+ int64_t timeUs;
+ CHECK(srcBuffer->meta()->findInt64("timeUs", &timeUs));
+ destBuffer->meta()->setInt64("timeUs", timeUs);
+
+ if (kTestFlush && inputFramesSinceFlush >= kFlushAfterFrames) {
+ inputFramesSinceFlush = 0;
+
+ // check that queueing a buffer that was dequeued before flush
+ // fails with expected error EACCES
+ filterState->mCodec->flush();
+
+ err = filterState->mCodec->queueInputBuffer(
+ filterIndex, 0 /* offset */, destBuffer->size(),
+ timeUs, frame.flags);
+
+ if (err == OK) {
+ ALOGE("FAIL: queue after flush returned OK");
+ } else if (err != -EACCES) {
+ ALOGE("queueInputBuffer after flush returned %d, "
+ "expected -EACCES (-13)", err);
+ }
+ } else {
+ err = filterState->mCodec->queueInputBuffer(
+ filterIndex, 0 /* offset */, destBuffer->size(),
+ timeUs, frame.flags);
+ CHECK(err == OK);
+
+ err = vidState->mCodec->releaseOutputBuffer(outIndex);
+ CHECK(err == OK);
+ }
+}
+
+size_t outputFramesSinceFlush = 0;
+void tryDrainOutputBuffer(
+ CodecState *filterState,
+ const sp<Surface> &surface, bool renderSurface,
+ bool useTimestamp, int64_t *startTimeRender) {
+ size_t index;
+ size_t offset;
+ size_t size;
+ int64_t presentationTimeUs;
+ uint32_t flags;
+ status_t err = filterState->mCodec->dequeueOutputBuffer(
+ &index, &offset, &size, &presentationTimeUs, &flags,
+ kTimeout);
+
+ if (err != OK) {
+ return;
+ }
+
+ ++outputFramesSinceFlush;
+
+ if (kTestFlush && outputFramesSinceFlush >= kFlushAfterFrames) {
+ filterState->mCodec->flush();
+ }
+
+ if (surface == NULL || !renderSurface) {
+ err = filterState->mCodec->releaseOutputBuffer(index);
+ } else if (useTimestamp) {
+ if (*startTimeRender == -1) {
+ // begin rendering 2 vsyncs after first decode
+ *startTimeRender = systemTime(SYSTEM_TIME_MONOTONIC)
+ + 33000000 - (presentationTimeUs * 1000);
+ }
+ presentationTimeUs =
+ (presentationTimeUs * 1000) + *startTimeRender;
+ err = filterState->mCodec->renderOutputBufferAndRelease(
+ index, presentationTimeUs);
+ } else {
+ err = filterState->mCodec->renderOutputBufferAndRelease(index);
+ }
+
+ if (kTestFlush && outputFramesSinceFlush >= kFlushAfterFrames) {
+ outputFramesSinceFlush = 0;
+
+ // releasing the buffer dequeued before flush should cause an error
+ // if so, the frame will also be skipped in output stream
+ if (err == OK) {
+ ALOGE("FAIL: release after flush returned OK");
+ } else if (err != -EACCES) {
+ ALOGE("releaseOutputBuffer after flush returned %d, "
+ "expected -EACCES (-13)", err);
+ }
+ } else {
+ CHECK(err == OK);
+ }
+
+ if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+ ALOGV("reached EOS on output.");
+ filterState->mSawOutputEOS = true;
+ }
+}
+
+static int decode(
+ const sp<ALooper> &looper,
+ const char *path,
+ const sp<Surface> &surface,
+ bool renderSurface,
+ bool useTimestamp,
+ FilterType filterType) {
+
+ static int64_t kTimeout = 500ll;
+
+ sp<NuMediaExtractor> extractor = new NuMediaExtractor;
+ if (extractor->setDataSource(NULL /* httpService */, path) != OK) {
+ fprintf(stderr, "unable to instantiate extractor.\n");
+ return 1;
+ }
+
+ KeyedVector<size_t, CodecState> stateByTrack;
+
+ CodecState *vidState = NULL;
+ for (size_t i = 0; i < extractor->countTracks(); ++i) {
+ sp<AMessage> format;
+ status_t err = extractor->getTrackFormat(i, &format);
+ CHECK(err == OK);
+
+ AString mime;
+ CHECK(format->findString("mime", &mime));
+ bool isVideo = !strncasecmp(mime.c_str(), "video/", 6);
+ if (!isVideo) {
+ continue;
+ }
+
+ ALOGV("selecting track %zu", i);
+
+ err = extractor->selectTrack(i);
+ CHECK(err == OK);
+
+ CodecState *state =
+ &stateByTrack.editValueAt(stateByTrack.add(i, CodecState()));
+
+ vidState = state;
+
+ state->mNumBuffersDecoded = 0;
+
+ state->mCodec = MediaCodec::CreateByType(
+ looper, mime.c_str(), false /* encoder */);
+
+ CHECK(state->mCodec != NULL);
+
+ err = state->mCodec->configure(
+ format, NULL /* surface */, NULL /* crypto */, 0 /* flags */);
+
+ CHECK(err == OK);
+
+ state->mSignalledInputEOS = false;
+ state->mSawOutputEOS = false;
+
+ break;
+ }
+ CHECK(!stateByTrack.isEmpty());
+ CHECK(vidState != NULL);
+ sp<AMessage> vidFormat;
+ vidState->mCodec->getOutputFormat(&vidFormat);
+
+ // set filter to use ARGB8888
+ vidFormat->setInt32("color-format", OMX_COLOR_Format32bitARGB8888);
+ // set app cache directory path
+ vidFormat->setString("cacheDir", "/system/bin");
+
+ // create RenderScript context for RSFilters
+ RSC::sp<RSC::RS> context = new RSC::RS();
+ context->init("/system/bin");
+
+ sp<RenderScriptWrapper::RSFilterCallback> rsFilter;
+
+ // create renderscript wrapper for RSFilters
+ sp<RenderScriptWrapper> rsWrapper = new RenderScriptWrapper;
+ rsWrapper->mContext = context.get();
+
+ CodecState *filterState = new CodecState();
+ filterState->mNumBuffersDecoded = 0;
+
+ sp<AMessage> params = new AMessage();
+
+ switch (filterType) {
+ case FILTERTYPE_ZERO:
+ {
+ filterState->mCodec = MediaCodec::CreateByComponentName(
+ looper, "android.filter.zerofilter");
+ params->setInt32("invert", kInvert);
+ break;
+ }
+ case FILTERTYPE_INTRINSIC_BLUR:
+ {
+ filterState->mCodec = MediaCodec::CreateByComponentName(
+ looper, "android.filter.intrinsicblur");
+ params->setFloat("blur-radius", kBlurRadius);
+ break;
+ }
+ case FILTERTYPE_SATURATION:
+ {
+ filterState->mCodec = MediaCodec::CreateByComponentName(
+ looper, "android.filter.saturation");
+ params->setFloat("saturation", kSaturation);
+ break;
+ }
+ case FILTERTYPE_RS_SATURATION:
+ {
+ SaturationRSFilter *satFilter = new SaturationRSFilter;
+ satFilter->init(context);
+ rsFilter = satFilter;
+ rsWrapper->mCallback = rsFilter;
+ vidFormat->setObject("rs-wrapper", rsWrapper);
+
+ filterState->mCodec = MediaCodec::CreateByComponentName(
+ looper, "android.filter.RenderScript");
+ break;
+ }
+ case FILTERTYPE_RS_NIGHT_VISION:
+ {
+ NightVisionRSFilter *nightVisionFilter = new NightVisionRSFilter;
+ nightVisionFilter->init(context);
+ rsFilter = nightVisionFilter;
+ rsWrapper->mCallback = rsFilter;
+ vidFormat->setObject("rs-wrapper", rsWrapper);
+
+ filterState->mCodec = MediaCodec::CreateByComponentName(
+ looper, "android.filter.RenderScript");
+ break;
+ }
+ case FILTERTYPE_RS_ARGB_TO_RGBA:
+ {
+ ARGBToRGBARSFilter *argbToRgbaFilter = new ARGBToRGBARSFilter;
+ argbToRgbaFilter->init(context);
+ rsFilter = argbToRgbaFilter;
+ rsWrapper->mCallback = rsFilter;
+ vidFormat->setObject("rs-wrapper", rsWrapper);
+
+ filterState->mCodec = MediaCodec::CreateByComponentName(
+ looper, "android.filter.RenderScript");
+ break;
+ }
+ default:
+ {
+ LOG_ALWAYS_FATAL("mediacodec.cpp error: unrecognized FilterType");
+ break;
+ }
+ }
+ CHECK(filterState->mCodec != NULL);
+
+ status_t err = filterState->mCodec->configure(
+ vidFormat /* format */, surface, NULL /* crypto */, 0 /* flags */);
+ CHECK(err == OK);
+
+ filterState->mSignalledInputEOS = false;
+ filterState->mSawOutputEOS = false;
+
+ int64_t startTimeUs = ALooper::GetNowUs();
+ int64_t startTimeRender = -1;
+
+ for (size_t i = 0; i < stateByTrack.size(); ++i) {
+ CodecState *state = &stateByTrack.editValueAt(i);
+
+ sp<MediaCodec> codec = state->mCodec;
+
+ CHECK_EQ((status_t)OK, codec->start());
+
+ CHECK_EQ((status_t)OK, codec->getInputBuffers(&state->mInBuffers));
+ CHECK_EQ((status_t)OK, codec->getOutputBuffers(&state->mOutBuffers));
+
+ ALOGV("got %zu input and %zu output buffers",
+ state->mInBuffers.size(), state->mOutBuffers.size());
+ }
+
+ CHECK_EQ((status_t)OK, filterState->mCodec->setParameters(params));
+
+ if (kTestFlush) {
+ status_t flushErr = filterState->mCodec->flush();
+ if (flushErr == OK) {
+ ALOGE("FAIL: Flush before start returned OK");
+ } else {
+ ALOGV("Flush before start returned status %d, usually ENOSYS (-38)",
+ flushErr);
+ }
+ }
+
+ CHECK_EQ((status_t)OK, filterState->mCodec->start());
+ CHECK_EQ((status_t)OK, filterState->mCodec->getInputBuffers(
+ &filterState->mInBuffers));
+ CHECK_EQ((status_t)OK, filterState->mCodec->getOutputBuffers(
+ &filterState->mOutBuffers));
+
+ if (kTestFlush) {
+ status_t flushErr = filterState->mCodec->flush();
+ if (flushErr != OK) {
+ ALOGE("FAIL: Flush after start returned %d, expect OK (0)",
+ flushErr);
+ } else {
+ ALOGV("Flush immediately after start OK");
+ }
+ }
+
+ List<DecodedFrame> decodedFrameIndices;
+
+ // loop until decoder reaches EOS
+ bool sawInputEOS = false;
+ bool sawOutputEOSOnAllTracks = false;
+ while (!sawOutputEOSOnAllTracks) {
+ if (!sawInputEOS) {
+ size_t trackIndex;
+ status_t err = extractor->getSampleTrackIndex(&trackIndex);
+
+ if (err != OK) {
+ ALOGV("saw input eos");
+ sawInputEOS = true;
+ } else {
+ CodecState *state = &stateByTrack.editValueFor(trackIndex);
+
+ size_t index;
+ err = state->mCodec->dequeueInputBuffer(&index, kTimeout);
+
+ if (err == OK) {
+ ALOGV("filling input buffer %zu", index);
+
+ const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index);
+
+ err = extractor->readSampleData(buffer);
+ CHECK(err == OK);
+
+ int64_t timeUs;
+ err = extractor->getSampleTime(&timeUs);
+ CHECK(err == OK);
+
+ uint32_t bufferFlags = 0;
+
+ err = state->mCodec->queueInputBuffer(
+ index, 0 /* offset */, buffer->size(),
+ timeUs, bufferFlags);
+
+ CHECK(err == OK);
+
+ extractor->advance();
+ } else {
+ CHECK_EQ(err, -EAGAIN);
+ }
+ }
+ } else {
+ for (size_t i = 0; i < stateByTrack.size(); ++i) {
+ CodecState *state = &stateByTrack.editValueAt(i);
+
+ if (!state->mSignalledInputEOS) {
+ size_t index;
+ status_t err =
+ state->mCodec->dequeueInputBuffer(&index, kTimeout);
+
+ if (err == OK) {
+ ALOGV("signalling input EOS on track %zu", i);
+
+ err = state->mCodec->queueInputBuffer(
+ index, 0 /* offset */, 0 /* size */,
+ 0ll /* timeUs */, MediaCodec::BUFFER_FLAG_EOS);
+
+ CHECK(err == OK);
+
+ state->mSignalledInputEOS = true;
+ } else {
+ CHECK_EQ(err, -EAGAIN);
+ }
+ }
+ }
+ }
+
+ sawOutputEOSOnAllTracks = true;
+ for (size_t i = 0; i < stateByTrack.size(); ++i) {
+ CodecState *state = &stateByTrack.editValueAt(i);
+
+ if (state->mSawOutputEOS) {
+ continue;
+ } else {
+ sawOutputEOSOnAllTracks = false;
+ }
+
+ DecodedFrame frame;
+ status_t err = state->mCodec->dequeueOutputBuffer(
+ &frame.index, &frame.offset, &frame.size,
+ &frame.presentationTimeUs, &frame.flags, kTimeout);
+
+ if (err == OK) {
+ ALOGV("draining decoded buffer %zu, time = %lld us",
+ frame.index, frame.presentationTimeUs);
+
+ ++(state->mNumBuffersDecoded);
+
+ decodedFrameIndices.push_back(frame);
+
+ if (frame.flags & MediaCodec::BUFFER_FLAG_EOS) {
+ ALOGV("reached EOS on decoder output.");
+ state->mSawOutputEOS = true;
+ }
+
+ } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
+ ALOGV("INFO_OUTPUT_BUFFERS_CHANGED");
+ CHECK_EQ((status_t)OK, state->mCodec->getOutputBuffers(
+ &state->mOutBuffers));
+
+ ALOGV("got %zu output buffers", state->mOutBuffers.size());
+ } else if (err == INFO_FORMAT_CHANGED) {
+ sp<AMessage> format;
+ CHECK_EQ((status_t)OK, state->mCodec->getOutputFormat(&format));
+
+ ALOGV("INFO_FORMAT_CHANGED: %s",
+ format->debugString().c_str());
+ } else {
+ CHECK_EQ(err, -EAGAIN);
+ }
+
+ tryCopyDecodedBuffer(&decodedFrameIndices, filterState, vidState);
+
+ tryDrainOutputBuffer(
+ filterState, surface, renderSurface,
+ useTimestamp, &startTimeRender);
+ }
+ }
+
+ // after EOS on decoder, let filter reach EOS
+ while (!filterState->mSawOutputEOS) {
+ tryCopyDecodedBuffer(&decodedFrameIndices, filterState, vidState);
+
+ tryDrainOutputBuffer(
+ filterState, surface, renderSurface,
+ useTimestamp, &startTimeRender);
+ }
+
+ int64_t elapsedTimeUs = ALooper::GetNowUs() - startTimeUs;
+
+ for (size_t i = 0; i < stateByTrack.size(); ++i) {
+ CodecState *state = &stateByTrack.editValueAt(i);
+
+ CHECK_EQ((status_t)OK, state->mCodec->release());
+
+ printf("track %zu: %" PRId64 " frames decoded and filtered, "
+ "%.2f fps.\n", i, state->mNumBuffersDecoded,
+ state->mNumBuffersDecoded * 1E6 / elapsedTimeUs);
+ }
+
+ return 0;
+}
+
+} // namespace android
+
+int main(int argc, char **argv) {
+ using namespace android;
+
+ const char *me = argv[0];
+
+ bool useSurface = false;
+ bool renderSurface = false;
+ bool useTimestamp = false;
+ FilterType filterType = FILTERTYPE_ZERO;
+
+ int res;
+ while ((res = getopt(argc, argv, "bcnrszTRSh")) >= 0) {
+ switch (res) {
+ case 'b':
+ {
+ filterType = FILTERTYPE_INTRINSIC_BLUR;
+ break;
+ }
+ case 'c':
+ {
+ filterType = FILTERTYPE_RS_ARGB_TO_RGBA;
+ break;
+ }
+ case 'n':
+ {
+ filterType = FILTERTYPE_RS_NIGHT_VISION;
+ break;
+ }
+ case 'r':
+ {
+ filterType = FILTERTYPE_RS_SATURATION;
+ break;
+ }
+ case 's':
+ {
+ filterType = FILTERTYPE_SATURATION;
+ break;
+ }
+ case 'z':
+ {
+ filterType = FILTERTYPE_ZERO;
+ break;
+ }
+ case 'T':
+ {
+ useTimestamp = true;
+ }
+ // fall through
+ case 'R':
+ {
+ renderSurface = true;
+ }
+ // fall through
+ case 'S':
+ {
+ useSurface = true;
+ break;
+ }
+ case '?':
+ case 'h':
+ default:
+ {
+ usage(me);
+ break;
+ }
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1) {
+ usage(me);
+ }
+
+ ProcessState::self()->startThreadPool();
+
+ DataSource::RegisterDefaultSniffers();
+
+ android::sp<ALooper> looper = new ALooper;
+ looper->start();
+
+ android::sp<SurfaceComposerClient> composerClient;
+ android::sp<SurfaceControl> control;
+ android::sp<Surface> surface;
+
+ if (useSurface) {
+ composerClient = new SurfaceComposerClient;
+ CHECK_EQ((status_t)OK, composerClient->initCheck());
+
+ android::sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
+ ISurfaceComposer::eDisplayIdMain));
+ DisplayInfo info;
+ SurfaceComposerClient::getDisplayInfo(display, &info);
+ ssize_t displayWidth = info.w;
+ ssize_t displayHeight = info.h;
+
+ ALOGV("display is %zd x %zd", displayWidth, displayHeight);
+
+ control = composerClient->createSurface(
+ String8("A Surface"), displayWidth, displayHeight,
+ PIXEL_FORMAT_RGBA_8888, 0);
+
+ CHECK(control != NULL);
+ CHECK(control->isValid());
+
+ SurfaceComposerClient::openGlobalTransaction();
+ CHECK_EQ((status_t)OK, control->setLayer(INT_MAX));
+ CHECK_EQ((status_t)OK, control->show());
+ SurfaceComposerClient::closeGlobalTransaction();
+
+ surface = control->getSurface();
+ CHECK(surface != NULL);
+ }
+
+ decode(looper, argv[0], surface, renderSurface, useTimestamp, filterType);
+
+ if (useSurface) {
+ composerClient->dispose();
+ }
+
+ looper->stop();
+
+ return 0;
+}
diff --git a/cmds/stagefright/muxer.cpp b/cmds/stagefright/muxer.cpp
index f4a33e8..461b56c 100644
--- a/cmds/stagefright/muxer.cpp
+++ b/cmds/stagefright/muxer.cpp
@@ -17,6 +17,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "muxer"
#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include <utils/Log.h>
#include <binder/ProcessState.h>
@@ -72,8 +75,15 @@
ALOGV("input file %s, output file %s", path, outputFileName);
ALOGV("useAudio %d, useVideo %d", useAudio, useVideo);
- sp<MediaMuxer> muxer = new MediaMuxer(outputFileName,
+ int fd = open(outputFileName, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+
+ if (fd < 0) {
+ ALOGE("couldn't open file");
+ return fd;
+ }
+ sp<MediaMuxer> muxer = new MediaMuxer(fd,
MediaMuxer::OUTPUT_FORMAT_MPEG_4);
+ close(fd);
size_t trackCount = extractor->countTracks();
// Map the extractor's track index to the muxer's track index.
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index 9f547c7..2ad40bd 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -17,6 +17,10 @@
#include "SineSource.h"
#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
#include <binder/ProcessState.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AudioPlayer.h>
@@ -300,7 +304,13 @@
client.interface(), enc_meta, true /* createEncoder */, source,
0, preferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0);
- sp<MPEG4Writer> writer = new MPEG4Writer(fileName);
+ int fd = open(fileName, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ fprintf(stderr, "couldn't open file");
+ return 1;
+ }
+ sp<MPEG4Writer> writer = new MPEG4Writer(fd);
+ close(fd);
writer->addSource(encoder);
int64_t start = systemTime();
CHECK_EQ((status_t)OK, writer->start());
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index 0f729a3..172dc36 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -72,7 +72,7 @@
}
void startAsync() {
- (new AMessage(kWhatStart, id()))->post();
+ (new AMessage(kWhatStart, this))->post();
}
protected:
@@ -100,7 +100,7 @@
if (ctrlc) {
printf("\n");
printStatistics();
- (new AMessage(kWhatStop, id()))->post();
+ (new AMessage(kWhatStop, this))->post();
ctrlc = false;
}
switch (msg->what()) {
@@ -149,7 +149,7 @@
mDecodeLooper->registerHandler(mCodec);
mCodec->setNotificationMessage(
- new AMessage(kWhatCodecNotify, id()));
+ new AMessage(kWhatCodecNotify, this));
sp<AMessage> format = makeFormat(mSource->getFormat());
@@ -168,7 +168,7 @@
mFinalResult = OK;
mSeekState = SEEK_NONE;
- // (new AMessage(kWhatSeek, id()))->post(5000000ll);
+ // (new AMessage(kWhatSeek, this))->post(5000000ll);
break;
}
@@ -225,12 +225,12 @@
printf((what == CodecBase::kWhatEOS) ? "$\n" : "E\n");
printStatistics();
- (new AMessage(kWhatStop, id()))->post();
+ (new AMessage(kWhatStop, this))->post();
} else if (what == CodecBase::kWhatFlushCompleted) {
mSeekState = SEEK_FLUSH_COMPLETED;
mCodec->signalResume();
- (new AMessage(kWhatSeek, id()))->post(5000000ll);
+ (new AMessage(kWhatSeek, this))->post(5000000ll);
} else if (what == CodecBase::kWhatOutputFormatChanged) {
} else if (what == CodecBase::kWhatShutdownCompleted) {
mDecodeLooper->unregisterHandler(mCodec->id());
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 81edcb4..318b56d 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -19,6 +19,8 @@
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
//#define LOG_NDEBUG 0
#define LOG_TAG "stagefright"
@@ -506,8 +508,13 @@
sp<MPEG4Writer> writer =
new MPEG4Writer(gWriteMP4Filename.string());
#else
+ int fd = open(gWriteMP4Filename.string(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ fprintf(stderr, "couldn't open file");
+ return;
+ }
sp<MPEG2TSWriter> writer =
- new MPEG2TSWriter(gWriteMP4Filename.string());
+ new MPEG2TSWriter(fd);
#endif
// at most one minute.
diff --git a/drm/common/IDrmManagerService.cpp b/drm/common/IDrmManagerService.cpp
index db41e0b..3f62ed7 100644
--- a/drm/common/IDrmManagerService.cpp
+++ b/drm/common/IDrmManagerService.cpp
@@ -148,7 +148,7 @@
data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
data.writeInt32(uniqueId);
- data.writeStrongBinder(drmServiceListener->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(drmServiceListener));
remote()->transact(SET_DRM_SERVICE_LISTENER, data, &reply);
return reply.readInt32();
}
diff --git a/drm/drmserver/Android.mk b/drm/drmserver/Android.mk
index aa0ab9b..48ea385 100644
--- a/drm/drmserver/Android.mk
+++ b/drm/drmserver/Android.mk
@@ -26,7 +26,8 @@
libutils \
liblog \
libbinder \
- libdl
+ libdl \
+ libselinux
LOCAL_STATIC_LIBRARIES := libdrmframeworkcommon
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
index 63341e0..857d73e 100644
--- a/drm/drmserver/DrmManagerService.cpp
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -29,20 +29,68 @@
#include "DrmManagerService.h"
#include "DrmManager.h"
+#include <selinux/android.h>
+
using namespace android;
+static int selinux_enabled;
+static char *drmserver_context;
static Vector<uid_t> trustedUids;
-static bool isProtectedCallAllowed() {
+const char *const DrmManagerService::drm_perm_labels[] = {
+ "consumeRights",
+ "setPlaybackStatus",
+ "openDecryptSession",
+ "closeDecryptSession",
+ "initializeDecryptUnit",
+ "decrypt",
+ "finalizeDecryptUnit",
+ "pread"
+};
+
+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]))) {
+ ALOGE("SELinux: Failed to retrieve permission label(perm=%d).\n", perm);
+ abort();
+ }
+ return drm_perm_labels[index];
+}
+
+bool DrmManagerService::selinuxIsProtectedCallAllowed(pid_t spid, drm_perm_t perm) {
+ if (selinux_enabled <= 0) {
+ return true;
+ }
+
+ char *sctx;
+ const char *selinux_class = "drmservice";
+ const char *str_perm = get_perm_label(perm);
+
+ if (getpidcon(spid, &sctx) != 0) {
+ ALOGE("SELinux: getpidcon(pid=%d) failed.\n", spid);
+ return false;
+ }
+
+ bool allowed = (selinux_check_access(sctx, drmserver_context, selinux_class,
+ str_perm, NULL) == 0);
+ freecon(sctx);
+
+ return allowed;
+}
+
+bool DrmManagerService::isProtectedCallAllowed(drm_perm_t perm) {
// TODO
// Following implementation is just for reference.
// Each OEM manufacturer should implement/replace with their own solutions.
IPCThreadState* ipcState = IPCThreadState::self();
uid_t uid = ipcState->getCallingUid();
+ pid_t spid = ipcState->getCallingPid();
for (unsigned int i = 0; i < trustedUids.size(); ++i) {
if (trustedUids[i] == uid) {
- return true;
+ return selinuxIsProtectedCallAllowed(spid, perm);
}
}
return false;
@@ -60,6 +108,16 @@
// Add trusted uids here
trustedUids.push(AID_MEDIA);
}
+
+ selinux_enabled = is_selinux_enabled();
+ if (selinux_enabled > 0 && getcon(&drmserver_context) != 0) {
+ ALOGE("SELinux: DrmManagerService failed to get context for DrmManagerService. Aborting.\n");
+ abort();
+ }
+
+ union selinux_callback cb;
+ cb.func_log = selinux_log_callback;
+ selinux_set_callback(SELINUX_CB_LOG, cb);
}
DrmManagerService::DrmManagerService() :
@@ -151,7 +209,7 @@
status_t DrmManagerService::consumeRights(
int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
ALOGV("Entering consumeRights");
- if (!isProtectedCallAllowed()) {
+ if (!isProtectedCallAllowed(CONSUME_RIGHTS)) {
return DRM_ERROR_NO_PERMISSION;
}
return mDrmManager->consumeRights(uniqueId, decryptHandle, action, reserve);
@@ -160,7 +218,7 @@
status_t DrmManagerService::setPlaybackStatus(
int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
ALOGV("Entering setPlaybackStatus");
- if (!isProtectedCallAllowed()) {
+ if (!isProtectedCallAllowed(SET_PLAYBACK_STATUS)) {
return DRM_ERROR_NO_PERMISSION;
}
return mDrmManager->setPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
@@ -208,7 +266,7 @@
DecryptHandle* DrmManagerService::openDecryptSession(
int uniqueId, int fd, off64_t offset, off64_t length, const char* mime) {
ALOGV("Entering DrmManagerService::openDecryptSession");
- if (isProtectedCallAllowed()) {
+ if (isProtectedCallAllowed(OPEN_DECRYPT_SESSION)) {
return mDrmManager->openDecryptSession(uniqueId, fd, offset, length, mime);
}
@@ -218,7 +276,7 @@
DecryptHandle* DrmManagerService::openDecryptSession(
int uniqueId, const char* uri, const char* mime) {
ALOGV("Entering DrmManagerService::openDecryptSession with uri");
- if (isProtectedCallAllowed()) {
+ if (isProtectedCallAllowed(OPEN_DECRYPT_SESSION)) {
return mDrmManager->openDecryptSession(uniqueId, uri, mime);
}
@@ -228,7 +286,7 @@
DecryptHandle* DrmManagerService::openDecryptSession(
int uniqueId, const DrmBuffer& buf, const String8& mimeType) {
ALOGV("Entering DrmManagerService::openDecryptSession for streaming");
- if (isProtectedCallAllowed()) {
+ if (isProtectedCallAllowed(OPEN_DECRYPT_SESSION)) {
return mDrmManager->openDecryptSession(uniqueId, buf, mimeType);
}
@@ -237,7 +295,7 @@
status_t DrmManagerService::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
ALOGV("Entering closeDecryptSession");
- if (!isProtectedCallAllowed()) {
+ if (!isProtectedCallAllowed(CLOSE_DECRYPT_SESSION)) {
return DRM_ERROR_NO_PERMISSION;
}
return mDrmManager->closeDecryptSession(uniqueId, decryptHandle);
@@ -246,7 +304,7 @@
status_t DrmManagerService::initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo) {
ALOGV("Entering initializeDecryptUnit");
- if (!isProtectedCallAllowed()) {
+ if (!isProtectedCallAllowed(INITIALIZE_DECRYPT_UNIT)) {
return DRM_ERROR_NO_PERMISSION;
}
return mDrmManager->initializeDecryptUnit(uniqueId,decryptHandle, decryptUnitId, headerInfo);
@@ -256,7 +314,7 @@
int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
ALOGV("Entering decrypt");
- if (!isProtectedCallAllowed()) {
+ if (!isProtectedCallAllowed(DECRYPT)) {
return DRM_ERROR_NO_PERMISSION;
}
return mDrmManager->decrypt(uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
@@ -265,7 +323,7 @@
status_t DrmManagerService::finalizeDecryptUnit(
int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
ALOGV("Entering finalizeDecryptUnit");
- if (!isProtectedCallAllowed()) {
+ if (!isProtectedCallAllowed(FINALIZE_DECRYPT_UNIT)) {
return DRM_ERROR_NO_PERMISSION;
}
return mDrmManager->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
@@ -274,7 +332,7 @@
ssize_t DrmManagerService::pread(int uniqueId, DecryptHandle* decryptHandle,
void* buffer, ssize_t numBytes, off64_t offset) {
ALOGV("Entering pread");
- if (!isProtectedCallAllowed()) {
+ if (!isProtectedCallAllowed(PREAD)) {
return DRM_ERROR_NO_PERMISSION;
}
return mDrmManager->pread(uniqueId, decryptHandle, buffer, numBytes, offset);
diff --git a/drm/libdrmframework/DrmManagerClientImpl.cpp b/drm/libdrmframework/DrmManagerClientImpl.cpp
index 2d2c90e..9457bb6 100644
--- a/drm/libdrmframework/DrmManagerClientImpl.cpp
+++ b/drm/libdrmframework/DrmManagerClientImpl.cpp
@@ -346,7 +346,7 @@
DrmManagerClientImpl::DeathNotifier::~DeathNotifier() {
Mutex::Autolock lock(sMutex);
if (NULL != sDrmManagerService.get()) {
- sDrmManagerService->asBinder()->unlinkToDeath(this);
+ IInterface::asBinder(sDrmManagerService)->unlinkToDeath(this);
}
}
diff --git a/drm/libdrmframework/include/DrmManagerService.h b/drm/libdrmframework/include/DrmManagerService.h
index 8bc59b4..45cee2e 100644
--- a/drm/libdrmframework/include/DrmManagerService.h
+++ b/drm/libdrmframework/include/DrmManagerService.h
@@ -42,9 +42,28 @@
static void instantiate();
private:
+ enum drm_perm_t {
+ CONSUME_RIGHTS = 0,
+ SET_PLAYBACK_STATUS = 1,
+ OPEN_DECRYPT_SESSION = 2,
+ CLOSE_DECRYPT_SESSION = 3,
+ INITIALIZE_DECRYPT_UNIT = 4,
+ DECRYPT = 5,
+ FINALIZE_DECRYPT_UNIT = 6,
+ PREAD = 7,
+ };
+
+ static const char *const drm_perm_labels[];
+
DrmManagerService();
virtual ~DrmManagerService();
+ static const char *get_perm_label(drm_perm_t perm);
+
+ static bool selinuxIsProtectedCallAllowed(pid_t spid, drm_perm_t perm);
+
+ static bool isProtectedCallAllowed(drm_perm_t perm);
+
public:
int addUniqueId(bool isNative);
diff --git a/drm/libdrmframework/include/PlugInManager.h b/drm/libdrmframework/include/PlugInManager.h
index c1d019a..466844d 100644
--- a/drm/libdrmframework/include/PlugInManager.h
+++ b/drm/libdrmframework/include/PlugInManager.h
@@ -234,14 +234,6 @@
}
/**
- * True if the input entry is "." or ".."
- */
- bool isDotOrDDot(const struct dirent* pEntry) const {
- String8 sName(pEntry->d_name);
- return "." == sName || ".." == sName;
- }
-
- /**
* True if input entry is directory
*/
bool isDirectory(const struct dirent* pEntry) const {
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
index 48b0afe..933464f 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
@@ -58,8 +58,7 @@
$(base)/drm/libdrmframework/plugins/forward-lock/internal-format/common \
$(base)/drm/libdrmframework/plugins/forward-lock/internal-format/converter \
$(base)/drm/libdrmframework/plugins/forward-lock/internal-format/decoder \
- $(LOCAL_PATH)/include \
- external/openssl/include
+ $(LOCAL_PATH)/include
LOCAL_MODULE_RELATIVE_PATH := drm
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.mk b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.mk
index 6c5d3cf..3b4c8b4 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.mk
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.mk
@@ -20,9 +20,6 @@
LOCAL_SRC_FILES := \
FwdLockGlue.c
-LOCAL_C_INCLUDES := \
- external/openssl/include
-
LOCAL_SHARED_LIBRARIES := libcrypto
LOCAL_MODULE := libfwdlock-common
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.mk b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.mk
index 8f08c88..2f51f0c 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.mk
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.mk
@@ -21,8 +21,7 @@
FwdLockConv.c
LOCAL_C_INCLUDES := \
- frameworks/av/drm/libdrmframework/plugins/forward-lock/internal-format/common \
- external/openssl/include
+ frameworks/av/drm/libdrmframework/plugins/forward-lock/internal-format/common
LOCAL_SHARED_LIBRARIES := libcrypto
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.mk b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.mk
index 7b493c3..3399ae5 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.mk
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.mk
@@ -21,8 +21,7 @@
FwdLockFile.c
LOCAL_C_INCLUDES := \
- frameworks/av/drm/libdrmframework/plugins/forward-lock/internal-format/common \
- external/openssl/include
+ frameworks/av/drm/libdrmframework/plugins/forward-lock/internal-format/common
LOCAL_SHARED_LIBRARIES := libcrypto
diff --git a/drm/mediadrm/plugins/clearkey/Android.mk b/drm/mediadrm/plugins/clearkey/Android.mk
index 22a85b4..2efdcf5 100644
--- a/drm/mediadrm/plugins/clearkey/Android.mk
+++ b/drm/mediadrm/plugins/clearkey/Android.mk
@@ -31,9 +31,7 @@
Utils.cpp \
LOCAL_C_INCLUDES := \
- bionic \
external/jsmn \
- external/openssl/include \
frameworks/av/drm/mediadrm/plugins/clearkey \
frameworks/av/include \
frameworks/native/include \
diff --git a/drm/mediadrm/plugins/clearkey/tests/Android.mk b/drm/mediadrm/plugins/clearkey/tests/Android.mk
index ac5bb21..392f218 100644
--- a/drm/mediadrm/plugins/clearkey/tests/Android.mk
+++ b/drm/mediadrm/plugins/clearkey/tests/Android.mk
@@ -28,25 +28,16 @@
JsonWebKeyUnittest.cpp \
LOCAL_C_INCLUDES := \
- bionic \
- external/gtest/include \
external/jsmn \
- external/openssl/include \
- external/stlport/stlport \
frameworks/av/drm/mediadrm/plugins/clearkey \
frameworks/av/include \
frameworks/native/include \
-LOCAL_STATIC_LIBRARIES := \
- libgtest \
- libgtest_main \
-
LOCAL_SHARED_LIBRARIES := \
libcrypto \
libdrmclearkeyplugin \
liblog \
libstagefright_foundation \
- libstlport \
libutils \
include $(BUILD_NATIVE_TEST)
diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h
index f7f06bb..194a646 100644
--- a/include/camera/ICameraService.h
+++ b/include/camera/ICameraService.h
@@ -53,6 +53,7 @@
GET_LEGACY_PARAMETERS,
SUPPORTS_CAMERA_API,
CONNECT_LEGACY,
+ SET_TORCH_MODE,
};
enum {
@@ -142,6 +143,21 @@
int clientUid,
/*out*/
sp<ICamera>& device) = 0;
+
+ /**
+ * Turn on or off a camera's torch mode. Torch mode will be turned off by
+ * camera service if the lastest client binder that turns it on dies.
+ *
+ * return values:
+ * 0: on a successful operation.
+ * -ENOSYS: the camera device doesn't support this operation. It it returned
+ * if and only if android.flash.into.available is false.
+ * -EBUSY: the camera device is opened.
+ * -EINVAL: camera_id is invalid or clientBinder is NULL when enabling a
+ * torch mode.
+ */
+ virtual status_t setTorchMode(const String16& cameraId, bool enabled,
+ const sp<IBinder>& clientBinder) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/camera/ICameraServiceListener.h b/include/camera/ICameraServiceListener.h
index 0a0e43a..709ff31 100644
--- a/include/camera/ICameraServiceListener.h
+++ b/include/camera/ICameraServiceListener.h
@@ -66,9 +66,35 @@
STATUS_UNKNOWN = 0xFFFFFFFF,
};
+ /**
+ * The torch mode status of a camera.
+ *
+ * Initial status will be transmitted with onTorchStatusChanged immediately
+ * after this listener is added to the service listener list.
+ *
+ * The enums should be set to values matching
+ * include/hardware/camera_common.h
+ */
+ enum TorchStatus {
+ // The camera's torch mode has become not available to use via
+ // setTorchMode().
+ TORCH_STATUS_NOT_AVAILABLE = TORCH_MODE_STATUS_NOT_AVAILABLE,
+ // The camera's torch mode is off and available to be turned on via
+ // setTorchMode().
+ TORCH_STATUS_AVAILABLE_OFF = TORCH_MODE_STATUS_AVAILABLE_OFF,
+ // The camera's torch mode is on and available to be turned off via
+ // setTorchMode().
+ TORCH_STATUS_AVAILABLE_ON = TORCH_MODE_STATUS_AVAILABLE_ON,
+
+ // Use to initialize variables only
+ TORCH_STATUS_UNKNOWN = 0xFFFFFFFF,
+ };
+
DECLARE_META_INTERFACE(CameraServiceListener);
virtual void onStatusChanged(Status status, int32_t cameraId) = 0;
+
+ virtual void onTorchStatusChanged(TorchStatus status, const String16& cameraId) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/camera/camera2/ICameraDeviceUser.h b/include/camera/camera2/ICameraDeviceUser.h
index 35488bb..bfc2aa0 100644
--- a/include/camera/camera2/ICameraDeviceUser.h
+++ b/include/camera/camera2/ICameraDeviceUser.h
@@ -101,7 +101,6 @@
virtual status_t deleteStream(int streamId) = 0;
virtual status_t createStream(
- int width, int height, int format,
const sp<IGraphicBufferProducer>& bufferProducer) = 0;
// Create a request object from a template.
diff --git a/include/media/AudioResamplerPublic.h b/include/media/AudioResamplerPublic.h
index 97847a0..b705efa 100644
--- a/include/media/AudioResamplerPublic.h
+++ b/include/media/AudioResamplerPublic.h
@@ -26,4 +26,17 @@
// TODO: replace with an API
#define AUDIO_RESAMPLER_DOWN_RATIO_MAX 256
+// Returns the source frames needed to resample to destination frames. This is not a precise
+// value and depends on the resampler (and possibly how it handles rounding internally).
+// Nevertheless, this should be an upper bound on the requirements of the resampler.
+// If srcSampleRate and dstSampleRate are equal, then it returns destination frames, which
+// may not be true if the resampler is asynchronous.
+static inline size_t sourceFramesNeeded(
+ uint32_t srcSampleRate, size_t dstFramesRequired, uint32_t dstSampleRate) {
+ // +1 for rounding - always do this even if matched ratio (resampler may use phases not ratio)
+ // +1 for additional sample needed for interpolation
+ return srcSampleRate == dstSampleRate ? dstFramesRequired :
+ size_t((uint64_t)dstFramesRequired * srcSampleRate / dstSampleRate + 1 + 1);
+}
+
#endif // ANDROID_AUDIO_RESAMPLER_PUBLIC_H
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 843a354..2ab3dd6 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -201,7 +201,7 @@
// IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
//
static status_t setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state,
- const char *device_address);
+ const char *device_address, const char *device_name);
static audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device,
const char *device_address);
static status_t setPhoneState(audio_mode_t state);
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index fd51b8f..3de0774 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -63,7 +63,7 @@
// See AudioTimestamp for the information included with event.
};
- /* Client should declare Buffer on the stack and pass address to obtainBuffer()
+ /* Client should declare a Buffer and pass the address to obtainBuffer()
* and releaseBuffer(). See also callback_t for EVENT_MORE_DATA.
*/
@@ -72,16 +72,20 @@
public:
// FIXME use m prefix
size_t frameCount; // number of sample frames corresponding to size;
- // on input it is the number of frames desired,
- // on output is the number of frames actually filled
- // (currently ignored, but will make the primary field in future)
+ // on input to obtainBuffer() it is the number of frames desired,
+ // on output from obtainBuffer() it is the number of available
+ // [empty slots for] frames to be filled
+ // on input to releaseBuffer() it is currently ignored
size_t size; // input/output in bytes == frameCount * frameSize
- // on input it is unused
- // on output is the number of bytes actually filled
- // FIXME this is redundant with respect to frameCount,
- // and TRANSFER_OBTAIN mode is broken for 8-bit data
- // since we don't define the frame format
+ // on input to obtainBuffer() it is ignored
+ // on output from obtainBuffer() it is the number of available
+ // [empty slots for] bytes to be filled,
+ // which is frameCount * frameSize
+ // on input to releaseBuffer() it is the number of bytes to
+ // release
+ // FIXME This is redundant with respect to frameCount. Consider
+ // removing size and making frameCount the primary field.
union {
void* raw;
@@ -154,9 +158,9 @@
* streamType: Select the type of audio stream this track is attached to
* (e.g. AUDIO_STREAM_MUSIC).
* sampleRate: Data source sampling rate in Hz.
- * format: Audio format. For mixed tracks, any PCM format supported by server is OK
- * or AUDIO_FORMAT_PCM_8_BIT which is handled on client side. For direct
- * and offloaded tracks, the possible format(s) depends on the output sink.
+ * format: Audio format. For mixed tracks, any PCM format supported by server is OK.
+ * For direct and offloaded tracks, the possible format(s) depends on the
+ * output sink.
* channelMask: Channel mask, such that audio_is_output_channel(channelMask) is true.
* frameCount: Minimum size of track PCM buffer in frames. This defines the
* application's contribution to the
@@ -193,7 +197,6 @@
/* Creates an audio track and registers it with AudioFlinger.
* With this constructor, the track is configured for static buffer mode.
- * The format must not be 8-bit linear PCM.
* Data to be rendered is passed in a shared memory buffer
* identified by the argument sharedBuffer, which must be non-0.
* The memory should be initialized to the desired data before calling start().
@@ -487,10 +490,18 @@
*/
status_t attachAuxEffect(int effectId);
- /* Obtains a buffer of up to "audioBuffer->frameCount" empty slots for frames.
+ /* Public API for TRANSFER_OBTAIN mode.
+ * Obtains a buffer of up to "audioBuffer->frameCount" empty slots for frames.
* After filling these slots with data, the caller should release them with releaseBuffer().
* If the track buffer is not full, obtainBuffer() returns as many contiguous
* [empty slots for] frames as are available immediately.
+ *
+ * If nonContig is non-NULL, it is an output parameter that will be set to the number of
+ * additional non-contiguous frames that are predicted to be available immediately,
+ * if the client were to release the first frames and then call obtainBuffer() again.
+ * This value is only a prediction, and needs to be confirmed.
+ * It will be set to zero for an error return.
+ *
* If the track buffer is full and track is stopped, obtainBuffer() returns WOULD_BLOCK
* regardless of the value of waitCount.
* If the track buffer is full and track is not stopped, obtainBuffer() blocks with a
@@ -499,7 +510,6 @@
* is exhausted, at which point obtainBuffer() will either block
* or return WOULD_BLOCK depending on the value of the "waitCount"
* parameter.
- * Each sample is 16-bit signed PCM.
*
* obtainBuffer() and releaseBuffer() are deprecated for direct use by applications,
* which should use write() or callback EVENT_MORE_DATA instead.
@@ -511,24 +521,29 @@
*
* Buffer fields
* On entry:
- * frameCount number of frames requested
+ * frameCount number of [empty slots for] frames requested
+ * size ignored
+ * raw ignored
* After error return:
* frameCount 0
* size 0
* raw undefined
* After successful return:
- * frameCount actual number of frames available, <= number requested
+ * frameCount actual number of [empty slots for] frames available, <= number requested
* size actual number of bytes available
* raw pointer to the buffer
*/
-
/* FIXME Deprecated public API for TRANSFER_OBTAIN mode */
- status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
+ status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount,
+ size_t *nonContig = NULL)
__attribute__((__deprecated__));
private:
/* If nonContig is non-NULL, it is an output parameter that will be set to the number of
- * additional non-contiguous frames that are available immediately.
+ * additional non-contiguous frames that are predicted to be available immediately,
+ * if the client were to release the first frames and then call obtainBuffer() again.
+ * This value is only a prediction, and needs to be confirmed.
+ * It will be set to zero for an error return.
* FIXME We could pass an array of Buffers instead of only one Buffer to obtainBuffer(),
* in case the requested amount of frames is in two or more non-contiguous regions.
* FIXME requested and elapsed are both relative times. Consider changing to absolute time.
@@ -537,9 +552,17 @@
struct timespec *elapsed = NULL, size_t *nonContig = NULL);
public:
- /* Release a filled buffer of "audioBuffer->frameCount" frames for AudioFlinger to process. */
+ /* Public API for TRANSFER_OBTAIN mode.
+ * Release a filled buffer of frames for AudioFlinger to process.
+ *
+ * Buffer fields:
+ * frameCount currently ignored but recommend to set to actual number of frames filled
+ * size actual number of bytes filled, must be multiple of frameSize
+ * raw ignored
+ *
+ */
// FIXME make private when obtainBuffer() for TRANSFER_OBTAIN is removed
- void releaseBuffer(Buffer* audioBuffer);
+ void releaseBuffer(const Buffer* audioBuffer);
/* As a convenience we provide a write() interface to the audio buffer.
* Input parameter 'size' is in byte units.
@@ -614,6 +637,7 @@
void pause(); // suspend thread from execution at next loop boundary
void resume(); // allow thread to execute, if not requested to exit
+ void wake(); // wake to handle changed notification conditions.
private:
void pauseInternal(nsecs_t ns = 0LL);
@@ -628,7 +652,9 @@
bool mPaused; // whether thread is requested to pause at next loop entry
bool mPausedInt; // whether thread internally requests pause
nsecs_t mPausedNs; // if mPausedInt then associated timeout, otherwise ignored
- bool mIgnoreNextPausedInt; // whether to ignore next mPausedInt request
+ bool mIgnoreNextPausedInt; // skip any internal pause and go immediately
+ // to processAudioBuffer() as state may have changed
+ // since pause time calculated.
};
// body of AudioTrackThread::threadLoop()
@@ -680,7 +706,7 @@
float mVolume[2];
float mSendLevel;
- mutable uint32_t mSampleRate; // mutable because getSampleRate() can update it.
+ mutable uint32_t mSampleRate; // mutable because getSampleRate() can update it
size_t mFrameCount; // corresponds to current IAudioTrack, value is
// reported back by AudioFlinger to the client
size_t mReqFrameCount; // frame count to request the first or next time
@@ -698,10 +724,7 @@
const audio_offload_info_t* mOffloadInfo;
audio_attributes_t mAttributes;
- // mFrameSize is equal to mFrameSizeAF for non-PCM or 16-bit PCM data. For 8-bit PCM data, it's
- // twice as large as mFrameSize because data is expanded to 16-bit before it's stored in buffer.
- size_t mFrameSize; // app-level frame size
- size_t mFrameSizeAF; // AudioFlinger frame size
+ size_t mFrameSize; // frame size in bytes
status_t mStatus;
@@ -732,13 +755,20 @@
bool mRefreshRemaining; // processAudioBuffer() should refresh
// mRemainingFrames and mRetryOnPartialBuffer
+ // used for static track cbf and restoration
+ int32_t mLoopCount; // last setLoop loopCount; zero means disabled
+ uint32_t mLoopStart; // last setLoop loopStart
+ uint32_t mLoopEnd; // last setLoop loopEnd
+ int32_t mLoopCountNotified; // the last loopCount notified by callback.
+ // mLoopCountNotified counts down, matching
+ // the remaining loop count for static track
+ // playback.
+
// These are private to processAudioBuffer(), and are not protected by a lock
uint32_t mRemainingFrames; // number of frames to request in obtainBuffer()
bool mRetryOnPartialBuffer; // sleep and retry after partial obtainBuffer()
uint32_t mObservedSequence; // last observed value of mSequence
- uint32_t mLoopPeriod; // in frames, zero means looping is disabled
-
uint32_t mMarkerPosition; // in wrapping (overflow) frame units
bool mMarkerReached;
uint32_t mNewPosition; // in frames
diff --git a/include/media/EffectsFactoryApi.h b/include/media/EffectsFactoryApi.h
index b1ed7b0..64a3212 100644
--- a/include/media/EffectsFactoryApi.h
+++ b/include/media/EffectsFactoryApi.h
@@ -171,6 +171,8 @@
////////////////////////////////////////////////////////////////////////////////
int EffectIsNullUuid(const effect_uuid_t *pEffectUuid);
+int EffectDumpEffects(int fd);
+
#if __cplusplus
} // extern "C"
#endif
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index c98c475..fecc6f1 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -44,7 +44,8 @@
//
virtual status_t setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
- const char *device_address) = 0;
+ const char *device_address,
+ const char *device_name) = 0;
virtual audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device,
const char *device_address) = 0;
virtual status_t setPhoneState(audio_mode_t state) = 0;
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index db62cd5..4153c25 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -56,6 +56,7 @@
virtual status_t stop() = 0;
virtual status_t pause() = 0;
virtual status_t isPlaying(bool* state) = 0;
+ virtual status_t setPlaybackRate(float rate) = 0;
virtual status_t seekTo(int msec) = 0;
virtual status_t getCurrentPosition(int* msec) = 0;
virtual status_t getDuration(int* msec) = 0;
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index d7e584a..49a3d61 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -49,19 +49,9 @@
virtual sp<IMediaRecorder> createMediaRecorder() = 0;
virtual sp<IMediaMetadataRetriever> createMetadataRetriever() = 0;
- virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client, int audioSessionId = 0) = 0;
+ virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client, int audioSessionId = 0)
+ = 0;
- virtual status_t decode(
- const sp<IMediaHTTPService> &httpService,
- const char* url,
- uint32_t *pSampleRate,
- int* pNumChannels,
- audio_format_t* pFormat,
- const sp<IMemoryHeap>& heap, size_t *pSize) = 0;
-
- virtual status_t decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate,
- int* pNumChannels, audio_format_t* pFormat,
- const sp<IMemoryHeap>& heap, size_t *pSize) = 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 3e67550..509c06b 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -41,7 +41,6 @@
virtual status_t setOutputFormat(int of) = 0;
virtual status_t setVideoEncoder(int ve) = 0;
virtual status_t setAudioEncoder(int ae) = 0;
- virtual status_t setOutputFile(const char* path) = 0;
virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) = 0;
virtual status_t setVideoSize(int width, int height) = 0;
virtual status_t setVideoFrameRate(int frames_per_second) = 0;
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 627f23b..6def65b 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -147,6 +147,7 @@
INTERNAL_OPTION_SUSPEND, // data is a bool
INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY, // data is an int64_t
INTERNAL_OPTION_MAX_TIMESTAMP_GAP, // data is int64_t
+ INTERNAL_OPTION_MAX_FPS, // data is float
INTERNAL_OPTION_START_TIME, // data is an int64_t
INTERNAL_OPTION_TIME_LAPSE, // data is an int64_t[2]
};
diff --git a/include/media/JetPlayer.h b/include/media/JetPlayer.h
index 388f767..63d1980 100644
--- a/include/media/JetPlayer.h
+++ b/include/media/JetPlayer.h
@@ -22,6 +22,7 @@
#include <libsonivox/jet.h>
#include <libsonivox/eas_types.h>
#include <media/AudioTrack.h>
+#include <media/MidiIoWrapper.h>
namespace android {
@@ -86,15 +87,13 @@
int mMaxTracks; // max number of MIDI tracks, usually 32
EAS_DATA_HANDLE mEasData;
- EAS_FILE_LOCATOR mEasJetFileLoc;
+ sp<MidiIoWrapper> mIoWrapper;
EAS_PCM* mAudioBuffer;// EAS renders the MIDI data into this buffer,
sp<AudioTrack> mAudioTrack; // and we play it in this audio track
int mTrackBufferSize;
S_JET_STATUS mJetStatus;
S_JET_STATUS mPreviousJetStatus;
- char mJetFilePath[PATH_MAX];
-
class JetPlayerThread : public Thread {
public:
JetPlayerThread(JetPlayer *player) : mPlayer(player) {
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index c412299..d6fe390 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -43,8 +43,6 @@
template<typename T> class SortedVector;
enum player_type {
- PV_PLAYER = 1,
- SONIVOX_PLAYER = 2,
STAGEFRIGHT_PLAYER = 3,
NU_PLAYER = 4,
// Test players are available only in the 'test' and 'eng' builds.
@@ -90,7 +88,6 @@
virtual ~AudioSink() {}
virtual bool ready() const = 0; // audio output is open and ready
- virtual bool realtime() const = 0; // audio output is real-time output
virtual ssize_t bufferSize() const = 0;
virtual ssize_t frameCount() const = 0;
virtual ssize_t channelCount() const = 0;
@@ -116,7 +113,19 @@
const audio_offload_info_t *offloadInfo = NULL) = 0;
virtual status_t start() = 0;
- virtual ssize_t write(const void* buffer, size_t size) = 0;
+
+ /* Input parameter |size| is in byte units stored in |buffer|.
+ * Data is copied over and actual number of bytes written (>= 0)
+ * is returned, or no data is copied and a negative status code
+ * is returned (even when |blocking| is true).
+ * When |blocking| is false, AudioSink will immediately return after
+ * part of or full |buffer| is copied over.
+ * When |blocking| is true, AudioSink will wait to copy the entire
+ * buffer, unless an error occurs or the copy operation is
+ * prematurely stopped.
+ */
+ virtual ssize_t write(const void* buffer, size_t size, bool blocking = true) = 0;
+
virtual void stop() = 0;
virtual void flush() = 0;
virtual void pause() = 0;
@@ -159,6 +168,7 @@
virtual status_t stop() = 0;
virtual status_t pause() = 0;
virtual bool isPlaying() = 0;
+ virtual status_t setPlaybackRate(float rate) { return INVALID_OPERATION; }
virtual status_t seekTo(int msec) = 0;
virtual status_t getCurrentPosition(int *msec) = 0;
virtual status_t getDuration(int *msec) = 0;
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
index d7ac302..f55063e 100644
--- a/include/media/MediaRecorderBase.h
+++ b/include/media/MediaRecorderBase.h
@@ -43,7 +43,6 @@
virtual status_t setCamera(const sp<ICamera>& camera,
const sp<ICameraRecordingProxy>& proxy) = 0;
virtual status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface) = 0;
- virtual status_t setOutputFile(const char *path) = 0;
virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) = 0;
virtual status_t setOutputFileAuxiliary(int fd) {return INVALID_OPERATION;}
virtual status_t setParameters(const String8& params) = 0;
diff --git a/include/media/MidiIoWrapper.h b/include/media/MidiIoWrapper.h
new file mode 100644
index 0000000..e6f8cf7
--- /dev/null
+++ b/include/media/MidiIoWrapper.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifndef MIDI_IO_WRAPPER_H_
+#define MIDI_IO_WRAPPER_H_
+
+#include <libsonivox/eas_types.h>
+
+#include "media/stagefright/DataSource.h"
+
+namespace android {
+
+class MidiIoWrapper : public RefBase {
+public:
+ MidiIoWrapper(const char *path);
+ MidiIoWrapper(int fd, off64_t offset, int64_t size);
+ MidiIoWrapper(const sp<DataSource> &source);
+
+ ~MidiIoWrapper();
+
+ int readAt(void *buffer, int offset, int size);
+ int size();
+
+ EAS_FILE_LOCATOR getLocator();
+
+private:
+ int mFd;
+ off64_t mBase;
+ int64_t mLength;
+ sp<DataSource> mDataSource;
+ EAS_FILE mEasFile;
+};
+
+
+} // namespace android
+
+#endif // MIDI_IO_WRAPPER_H_
diff --git a/include/media/SingleStateQueue.h b/include/media/SingleStateQueue.h
index 04c5fd0..d423962 100644
--- a/include/media/SingleStateQueue.h
+++ b/include/media/SingleStateQueue.h
@@ -21,6 +21,7 @@
// Non-blocking single-reader / single-writer multi-word atomic load / store
#include <stdint.h>
+#include <cutils/atomic.h>
namespace android {
@@ -31,6 +32,12 @@
class Mutator;
class Observer;
+ enum SSQ_STATUS {
+ SSQ_PENDING, /* = 0 */
+ SSQ_READ,
+ SSQ_DONE,
+ };
+
struct Shared {
// needs to be part of a union so don't define constructor or destructor
@@ -41,28 +48,56 @@
void init() { mAck = 0; mSequence = 0; }
volatile int32_t mAck;
-#if 0
- int mPad[7];
- // cache line boundary
-#endif
volatile int32_t mSequence;
T mValue;
};
class Mutator {
public:
- Mutator(Shared *shared);
- /*virtual*/ ~Mutator() { }
+ Mutator(Shared *shared)
+ : mSequence(0), mShared(shared)
+ {
+ // exactly one of Mutator and Observer must initialize, currently it is Observer
+ // shared->init();
+ }
// push new value onto state queue, overwriting previous value;
// returns a sequence number which can be used with ack()
- int32_t push(const T& value);
+ int32_t push(const T& value)
+ {
+ Shared *shared = mShared;
+ int32_t sequence = mSequence;
+ sequence++;
+ android_atomic_acquire_store(sequence, &shared->mSequence);
+ shared->mValue = value;
+ sequence++;
+ android_atomic_release_store(sequence, &shared->mSequence);
+ mSequence = sequence;
+ // consider signalling a futex here, if we know that observer is waiting
+ return sequence;
+ }
- // return true if most recent push has been observed
- bool ack();
+ // returns the status of the last state push. This may be a stale value.
+ //
+ // SSQ_PENDING, or 0, means it has not been observed
+ // SSQ_READ means it has been read
+ // SSQ_DONE means it has been acted upon, after Observer::done() is called
+ enum SSQ_STATUS ack() const
+ {
+ // in the case of SSQ_DONE, prevent any subtle data-races of subsequent reads
+ // being performed (out-of-order) before the ack read, should the caller be
+ // depending on sequentiality of reads.
+ const int32_t ack = android_atomic_acquire_load(&mShared->mAck);
+ return ack - mSequence & ~1 ? SSQ_PENDING /* seq differ */ :
+ ack & 1 ? SSQ_DONE : SSQ_READ;
+ }
// return true if a push with specified sequence number or later has been observed
- bool ack(int32_t sequence);
+ bool ack(int32_t sequence) const
+ {
+ // this relies on 2's complement rollover to detect an ancient sequence number
+ return mShared->mAck - sequence >= 0;
+ }
private:
int32_t mSequence;
@@ -71,11 +106,54 @@
class Observer {
public:
- Observer(Shared *shared);
- /*virtual*/ ~Observer() { }
+ Observer(Shared *shared)
+ : mSequence(0), mSeed(1), mShared(shared)
+ {
+ // exactly one of Mutator and Observer must initialize, currently it is Observer
+ shared->init();
+ }
// return true if value has changed
- bool poll(T& value);
+ bool poll(T& value)
+ {
+ Shared *shared = mShared;
+ int32_t before = shared->mSequence;
+ if (before == mSequence) {
+ return false;
+ }
+ for (int tries = 0; ; ) {
+ const int MAX_TRIES = 5;
+ if (before & 1) {
+ if (++tries >= MAX_TRIES) {
+ return false;
+ }
+ before = shared->mSequence;
+ } else {
+ android_memory_barrier();
+ T temp = shared->mValue;
+ int32_t after = android_atomic_release_load(&shared->mSequence);
+ if (after == before) {
+ value = temp;
+ shared->mAck = before;
+ mSequence = before; // mSequence is even after poll success
+ return true;
+ }
+ if (++tries >= MAX_TRIES) {
+ return false;
+ }
+ before = after;
+ }
+ }
+ }
+
+ // (optional) used to indicate to the Mutator that the state that has been polled
+ // has also been acted upon.
+ void done()
+ {
+ const int32_t ack = mShared->mAck + 1;
+ // ensure all previous writes have been performed.
+ android_atomic_release_store(ack, &mShared->mAck); // mSequence is odd after "done"
+ }
private:
int32_t mSequence;
diff --git a/include/media/SoundPool.h b/include/media/SoundPool.h
deleted file mode 100644
index 5830475..0000000
--- a/include/media/SoundPool.h
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef SOUNDPOOL_H_
-#define SOUNDPOOL_H_
-
-#include <utils/threads.h>
-#include <utils/List.h>
-#include <utils/Vector.h>
-#include <utils/KeyedVector.h>
-#include <media/AudioTrack.h>
-#include <binder/MemoryHeapBase.h>
-#include <binder/MemoryBase.h>
-
-namespace android {
-
-static const int IDLE_PRIORITY = -1;
-
-// forward declarations
-class SoundEvent;
-class SoundPoolThread;
-class SoundPool;
-
-// for queued events
-class SoundPoolEvent {
-public:
- SoundPoolEvent(int msg, int arg1=0, int arg2=0) :
- mMsg(msg), mArg1(arg1), mArg2(arg2) {}
- int mMsg;
- int mArg1;
- int mArg2;
- enum MessageType { INVALID, SAMPLE_LOADED };
-};
-
-// callback function prototype
-typedef void SoundPoolCallback(SoundPoolEvent event, SoundPool* soundPool, void* user);
-
-// tracks samples used by application
-class Sample : public RefBase {
-public:
- enum sample_state { UNLOADED, LOADING, READY, UNLOADING };
- Sample(int sampleID, const char* url);
- Sample(int sampleID, int fd, int64_t offset, int64_t length);
- ~Sample();
- int sampleID() { return mSampleID; }
- int numChannels() { return mNumChannels; }
- int sampleRate() { return mSampleRate; }
- audio_format_t format() { return mFormat; }
- size_t size() { return mSize; }
- int state() { return mState; }
- uint8_t* data() { return static_cast<uint8_t*>(mData->pointer()); }
- status_t doLoad();
- void startLoad() { mState = LOADING; }
- sp<IMemory> getIMemory() { return mData; }
-
- // hack
- void init(int numChannels, int sampleRate, audio_format_t format, size_t size,
- sp<IMemory> data ) {
- mNumChannels = numChannels; mSampleRate = sampleRate; mFormat = format; mSize = size;
- mData = data; }
-
-private:
- void init();
-
- size_t mSize;
- volatile int32_t mRefCount;
- uint16_t mSampleID;
- uint16_t mSampleRate;
- uint8_t mState : 3;
- uint8_t mNumChannels : 2;
- audio_format_t mFormat;
- int mFd;
- int64_t mOffset;
- int64_t mLength;
- char* mUrl;
- sp<IMemory> mData;
- sp<MemoryHeapBase> mHeap;
-};
-
-// stores pending events for stolen channels
-class SoundEvent
-{
-public:
- SoundEvent() : mChannelID(0), mLeftVolume(0), mRightVolume(0),
- mPriority(IDLE_PRIORITY), mLoop(0), mRate(0) {}
- void set(const sp<Sample>& sample, int channelID, float leftVolume,
- float rightVolume, int priority, int loop, float rate);
- sp<Sample> sample() { return mSample; }
- int channelID() { return mChannelID; }
- float leftVolume() { return mLeftVolume; }
- float rightVolume() { return mRightVolume; }
- int priority() { return mPriority; }
- int loop() { return mLoop; }
- float rate() { return mRate; }
- void clear() { mChannelID = 0; mSample.clear(); }
-
-protected:
- sp<Sample> mSample;
- int mChannelID;
- float mLeftVolume;
- float mRightVolume;
- int mPriority;
- int mLoop;
- float mRate;
-};
-
-// for channels aka AudioTracks
-class SoundChannel : public SoundEvent {
-public:
- enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING };
- SoundChannel() : mState(IDLE), mNumChannels(1),
- mPos(0), mToggle(0), mAutoPaused(false) {}
- ~SoundChannel();
- void init(SoundPool* soundPool);
- void play(const sp<Sample>& sample, int channelID, float leftVolume, float rightVolume,
- int priority, int loop, float rate);
- void setVolume_l(float leftVolume, float rightVolume);
- void setVolume(float leftVolume, float rightVolume);
- void stop_l();
- void stop();
- void pause();
- void autoPause();
- void resume();
- void autoResume();
- void setRate(float rate);
- int state() { return mState; }
- void setPriority(int priority) { mPriority = priority; }
- void setLoop(int loop);
- int numChannels() { return mNumChannels; }
- void clearNextEvent() { mNextEvent.clear(); }
- void nextEvent();
- int nextChannelID() { return mNextEvent.channelID(); }
- void dump();
-
-private:
- static void callback(int event, void* user, void *info);
- void process(int event, void *info, unsigned long toggle);
- bool doStop_l();
-
- SoundPool* mSoundPool;
- sp<AudioTrack> mAudioTrack;
- SoundEvent mNextEvent;
- Mutex mLock;
- int mState;
- int mNumChannels;
- int mPos;
- int mAudioBufferSize;
- unsigned long mToggle;
- bool mAutoPaused;
-};
-
-// application object for managing a pool of sounds
-class SoundPool {
- friend class SoundPoolThread;
- friend class SoundChannel;
-public:
- SoundPool(int maxChannels, const audio_attributes_t* pAttributes);
- ~SoundPool();
- int load(const char* url, int priority);
- int load(int fd, int64_t offset, int64_t length, int priority);
- bool unload(int sampleID);
- int play(int sampleID, float leftVolume, float rightVolume, int priority,
- int loop, float rate);
- void pause(int channelID);
- void autoPause();
- void resume(int channelID);
- void autoResume();
- void stop(int channelID);
- void setVolume(int channelID, float leftVolume, float rightVolume);
- void setPriority(int channelID, int priority);
- void setLoop(int channelID, int loop);
- void setRate(int channelID, float rate);
- const audio_attributes_t* attributes() { return &mAttributes; }
-
- // called from SoundPoolThread
- void sampleLoaded(int sampleID);
-
- // called from AudioTrack thread
- void done_l(SoundChannel* channel);
-
- // callback function
- void setCallback(SoundPoolCallback* callback, void* user);
- void* getUserData() { return mUserData; }
-
-private:
- SoundPool() {} // no default constructor
- bool startThreads();
- void doLoad(sp<Sample>& sample);
- sp<Sample> findSample(int sampleID) { return mSamples.valueFor(sampleID); }
- SoundChannel* findChannel (int channelID);
- SoundChannel* findNextChannel (int channelID);
- SoundChannel* allocateChannel_l(int priority);
- void moveToFront_l(SoundChannel* channel);
- void notify(SoundPoolEvent event);
- void dump();
-
- // restart thread
- void addToRestartList(SoundChannel* channel);
- void addToStopList(SoundChannel* channel);
- static int beginThread(void* arg);
- int run();
- void quit();
-
- Mutex mLock;
- Mutex mRestartLock;
- Condition mCondition;
- SoundPoolThread* mDecodeThread;
- SoundChannel* mChannelPool;
- List<SoundChannel*> mChannels;
- List<SoundChannel*> mRestart;
- List<SoundChannel*> mStop;
- DefaultKeyedVector< int, sp<Sample> > mSamples;
- int mMaxChannels;
- audio_attributes_t mAttributes;
- int mAllocated;
- int mNextSampleID;
- int mNextChannelID;
- bool mQuit;
-
- // callback
- Mutex mCallbackLock;
- SoundPoolCallback* mCallback;
- void* mUserData;
-};
-
-} // end namespace android
-
-#endif /*SOUNDPOOL_H_*/
diff --git a/include/media/StringArray.h b/include/media/StringArray.h
index ae47085..48d98bf 100644
--- a/include/media/StringArray.h
+++ b/include/media/StringArray.h
@@ -16,7 +16,7 @@
//
// Sortable array of strings. STL-ish, but STL-free.
-//
+//
#ifndef _LIBS_MEDIA_STRING_ARRAY_H
#define _LIBS_MEDIA_STRING_ARRAY_H
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index 98c4332..8406ed6 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -17,11 +17,12 @@
#ifndef ANDROID_TONEGENERATOR_H_
#define ANDROID_TONEGENERATOR_H_
-#include <utils/RefBase.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
#include <media/AudioSystem.h>
#include <media/AudioTrack.h>
+#include <utils/Compat.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
namespace android {
@@ -207,7 +208,7 @@
static const unsigned int TONEGEN_MAX_WAVES = 3; // Maximun number of sine waves in a tone segment
static const unsigned int TONEGEN_MAX_SEGMENTS = 12; // Maximun number of segments in a tone descriptor
static const unsigned int TONEGEN_INF = 0xFFFFFFFF; // Represents infinite time duration
- static const float TONEGEN_GAIN = 0.9; // Default gain passed to WaveGenerator().
+ static const CONSTEXPR float TONEGEN_GAIN = 0.9; // Default gain passed to WaveGenerator().
// ToneDescriptor class contains all parameters needed to generate a tone:
// - The array waveFreq[]:
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 9cc208e..808e893 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -220,6 +220,7 @@
status_t stop();
status_t pause();
bool isPlaying();
+ status_t setPlaybackRate(float rate);
status_t getVideoWidth(int *w);
status_t getVideoHeight(int *h);
status_t seekTo(int msec);
@@ -232,17 +233,6 @@
bool isLooping();
status_t setVolume(float leftVolume, float rightVolume);
void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
- static status_t decode(
- const sp<IMediaHTTPService> &httpService,
- const char* url,
- uint32_t *pSampleRate,
- int* pNumChannels,
- audio_format_t* pFormat,
- const sp<IMemoryHeap>& heap,
- size_t *pSize);
- static status_t decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate,
- int* pNumChannels, audio_format_t* pFormat,
- const sp<IMemoryHeap>& heap, size_t *pSize);
status_t invoke(const Parcel& request, Parcel *reply);
status_t setMetadataFilter(const Parcel& filter);
status_t getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
@@ -285,6 +275,7 @@
int mVideoWidth;
int mVideoHeight;
int mAudioSessionId;
+ float mPlaybackRate;
float mSendLevel;
struct sockaddr_in mRetransmitEndpoint;
bool mRetransmitEndpointValid;
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index b0a62a7..74a6469 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -221,7 +221,6 @@
status_t setOutputFormat(int of);
status_t setVideoEncoder(int ve);
status_t setAudioEncoder(int ae);
- status_t setOutputFile(const char* path);
status_t setOutputFile(int fd, int64_t offset, int64_t length);
status_t setVideoSize(int width, int height);
status_t setVideoFrameRate(int frames_per_second);
diff --git a/include/media/nbaio/NBAIO.h b/include/media/nbaio/NBAIO.h
index d422576..d9bbc8d 100644
--- a/include/media/nbaio/NBAIO.h
+++ b/include/media/nbaio/NBAIO.h
@@ -231,7 +231,8 @@
virtual status_t getTimestamp(AudioTimestamp& timestamp) { return INVALID_OPERATION; }
protected:
- NBAIO_Sink(const NBAIO_Format& format = Format_Invalid) : NBAIO_Port(format), mFramesWritten(0) { }
+ NBAIO_Sink(const NBAIO_Format& format = Format_Invalid) : NBAIO_Port(format), mFramesWritten(0)
+ { }
virtual ~NBAIO_Sink() { }
// Implementations are free to ignore these if they don't need them
@@ -322,7 +323,8 @@
virtual void onTimestamp(const AudioTimestamp& timestamp) { }
protected:
- NBAIO_Source(const NBAIO_Format& format = Format_Invalid) : NBAIO_Port(format), mFramesRead(0) { }
+ NBAIO_Source(const NBAIO_Format& format = Format_Invalid) : NBAIO_Port(format), mFramesRead(0)
+ { }
virtual ~NBAIO_Source() { }
// Implementations are free to ignore these if they don't need them
diff --git a/include/media/nbaio/NBLog.h b/include/media/nbaio/NBLog.h
index bcbbc04..1297b51 100644
--- a/include/media/nbaio/NBLog.h
+++ b/include/media/nbaio/NBLog.h
@@ -21,7 +21,7 @@
#include <binder/IMemory.h>
#include <utils/Mutex.h>
-#include <media/nbaio/roundup.h>
+#include <audio_utils/roundup.h>
namespace android {
diff --git a/include/media/nbaio/roundup.h b/include/media/nbaio/roundup.h
deleted file mode 100644
index 4c3cc25..0000000
--- a/include/media/nbaio/roundup.h
+++ /dev/null
@@ -1,31 +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 ROUNDUP_H
-#define ROUNDUP_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Round up to the next highest power of 2
-unsigned roundup(unsigned v);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // ROUNDUP_H
diff --git a/include/media/stagefright/AACWriter.h b/include/media/stagefright/AACWriter.h
index df1b053..86417a5 100644
--- a/include/media/stagefright/AACWriter.h
+++ b/include/media/stagefright/AACWriter.h
@@ -17,6 +17,7 @@
#ifndef AAC_WRITER_H_
#define AAC_WRITER_H_
+#include "foundation/ABase.h"
#include <media/stagefright/MediaWriter.h>
#include <utils/threads.h>
@@ -26,7 +27,6 @@
struct MetaData;
struct AACWriter : public MediaWriter {
- AACWriter(const char *filename);
AACWriter(int fd);
status_t initCheck() const;
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 595ace8..442c861 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -214,6 +214,7 @@
int64_t mRepeatFrameDelayUs;
int64_t mMaxPtsGapUs;
+ float mMaxFps;
int64_t mTimePerFrameUs;
int64_t mTimePerCaptureUs;
diff --git a/include/media/stagefright/AMRWriter.h b/include/media/stagefright/AMRWriter.h
index 392f968..bac878b 100644
--- a/include/media/stagefright/AMRWriter.h
+++ b/include/media/stagefright/AMRWriter.h
@@ -29,7 +29,6 @@
struct MetaData;
struct AMRWriter : public MediaWriter {
- AMRWriter(const char *filename);
AMRWriter(int fd);
status_t initCheck() const;
diff --git a/include/media/stagefright/BufferProducerWrapper.h b/include/media/stagefright/BufferProducerWrapper.h
index d8acf30..4caa2c6 100644
--- a/include/media/stagefright/BufferProducerWrapper.h
+++ b/include/media/stagefright/BufferProducerWrapper.h
@@ -19,6 +19,7 @@
#define BUFFER_PRODUCER_WRAPPER_H_
#include <gui/IGraphicBufferProducer.h>
+#include <media/stagefright/foundation/ABase.h>
namespace android {
diff --git a/include/media/stagefright/ClockEstimator.h b/include/media/stagefright/ClockEstimator.h
index 2fd6e75..1455b7f 100644
--- a/include/media/stagefright/ClockEstimator.h
+++ b/include/media/stagefright/ClockEstimator.h
@@ -19,7 +19,7 @@
#define CLOCK_ESTIMATOR_H_
-
+#include "foundation/ABase.h"
#include <utils/RefBase.h>
#include <utils/Vector.h>
diff --git a/include/media/stagefright/MPEG2TSWriter.h b/include/media/stagefright/MPEG2TSWriter.h
index 2e2922e..3d7960b 100644
--- a/include/media/stagefright/MPEG2TSWriter.h
+++ b/include/media/stagefright/MPEG2TSWriter.h
@@ -29,7 +29,6 @@
struct MPEG2TSWriter : public MediaWriter {
MPEG2TSWriter(int fd);
- MPEG2TSWriter(const char *filename);
MPEG2TSWriter(
void *cookie,
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 26ce5f9..a195fe8 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -26,13 +26,13 @@
namespace android {
+class AMessage;
class MediaBuffer;
class MediaSource;
class MetaData;
class MPEG4Writer : public MediaWriter {
public:
- MPEG4Writer(const char *filename);
MPEG4Writer(int fd);
// Limitations
@@ -49,6 +49,7 @@
virtual status_t dump(int fd, const Vector<String16>& args);
void beginBox(const char *fourcc);
+ void beginBox(uint32_t id);
void writeInt8(int8_t x);
void writeInt16(int16_t x);
void writeInt32(int32_t x);
@@ -63,6 +64,7 @@
int32_t getTimeScale() const { return mTimeScale; }
status_t setGeoData(int latitudex10000, int longitudex10000);
+ status_t setCaptureRate(float captureFps);
virtual void setStartTimeOffsetMs(int ms) { mStartTimeOffsetMs = ms; }
virtual int32_t getStartTimeOffsetMs() const { return mStartTimeOffsetMs; }
@@ -89,6 +91,7 @@
off64_t mFreeBoxOffset;
bool mStreamableFile;
off64_t mEstimatedMoovBoxSize;
+ off64_t mMoovExtraSize;
uint32_t mInterleaveDurationUs;
int32_t mTimeScale;
int64_t mStartTimestampUs;
@@ -103,6 +106,8 @@
List<off64_t> mBoxes;
+ sp<AMessage> mMetaKeys;
+
void setStartTimestampUs(int64_t timeUs);
int64_t getStartTimestampUs(); // Not const
status_t startTracks(MetaData *params);
@@ -196,6 +201,12 @@
void writeGeoDataBox();
void writeLatitude(int degreex10000);
void writeLongitude(int degreex10000);
+
+ void addDeviceMeta();
+ void writeHdlr();
+ void writeKeys();
+ void writeIlst();
+ void writeMetaBox();
void sendSessionSummary();
void release();
status_t reset();
diff --git a/include/media/stagefright/MediaClock.h b/include/media/stagefright/MediaClock.h
new file mode 100644
index 0000000..660764f
--- /dev/null
+++ b/include/media/stagefright/MediaClock.h
@@ -0,0 +1,77 @@
+/*
+ * 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 MEDIA_CLOCK_H_
+
+#define MEDIA_CLOCK_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct AMessage;
+
+struct MediaClock : public RefBase {
+ MediaClock();
+
+ void setStartingTimeMedia(int64_t startingTimeMediaUs);
+
+ void clearAnchor();
+ // It's required to use timestamp of just rendered frame as
+ // anchor time in paused state.
+ void updateAnchor(
+ int64_t anchorTimeMediaUs,
+ int64_t anchorTimeRealUs,
+ int64_t maxTimeMediaUs = INT64_MAX);
+
+ void updateMaxTimeMedia(int64_t maxTimeMediaUs);
+
+ void setPlaybackRate(float rate);
+
+ // query media time corresponding to real time |realUs|, and save the
+ // result in |outMediaUs|.
+ status_t getMediaTime(int64_t realUs,
+ int64_t *outMediaUs,
+ bool allowPastMaxTime = false);
+ // query real time corresponding to media time |targetMediaUs|.
+ // The result is saved in |outRealUs|.
+ status_t getRealTimeFor(int64_t targetMediaUs, int64_t *outRealUs);
+
+protected:
+ virtual ~MediaClock();
+
+private:
+ status_t getMediaTime_l(int64_t realUs,
+ int64_t *outMediaUs,
+ bool allowPastMaxTime);
+
+ Mutex mLock;
+
+ int64_t mAnchorTimeMediaUs;
+ int64_t mAnchorTimeRealUs;
+ int64_t mMaxTimeMediaUs;
+ int64_t mStartingTimeMediaUs;
+
+ float mPlaybackRate;
+
+ DISALLOW_EVIL_CONSTRUCTORS(MediaClock);
+};
+
+} // namespace android
+
+#endif // MEDIA_CLOCK_H_
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index d448097..8241e19 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -27,6 +27,7 @@
struct ABuffer;
struct AMessage;
+struct AReplyToken;
struct AString;
struct CodecBase;
struct ICrypto;
@@ -222,7 +223,7 @@
sp<ALooper> mCodecLooper;
sp<CodecBase> mCodec;
AString mComponentName;
- uint32_t mReplyID;
+ sp<AReplyToken> mReplyID;
uint32_t mFlags;
status_t mStickyError;
sp<Surface> mNativeWindow;
@@ -249,10 +250,10 @@
Vector<BufferInfo> mPortBuffers[2];
int32_t mDequeueInputTimeoutGeneration;
- uint32_t mDequeueInputReplyID;
+ sp<AReplyToken> mDequeueInputReplyID;
int32_t mDequeueOutputTimeoutGeneration;
- uint32_t mDequeueOutputReplyID;
+ sp<AReplyToken> mDequeueOutputReplyID;
sp<ICrypto> mCrypto;
@@ -267,7 +268,7 @@
static status_t PostAndAwaitResponse(
const sp<AMessage> &msg, sp<AMessage> *response);
- static void PostReplyWithError(int32_t replyID, int32_t err);
+ static void PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err);
status_t init(const AString &name, bool nameIsType, bool encoder);
@@ -283,8 +284,8 @@
size_t portIndex, size_t index,
sp<ABuffer> *buffer, sp<AMessage> *format);
- bool handleDequeueInputBuffer(uint32_t replyID, bool newRequest = false);
- bool handleDequeueOutputBuffer(uint32_t replyID, bool newRequest = false);
+ bool handleDequeueInputBuffer(const sp<AReplyToken> &replyID, bool newRequest = false);
+ bool handleDequeueOutputBuffer(const sp<AReplyToken> &replyID, bool newRequest = false);
void cancelPendingDequeueOperations();
void extractCSD(const sp<AMessage> &format);
diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h
index 0970b2b..7b8f59d 100644
--- a/include/media/stagefright/MediaCodecSource.h
+++ b/include/media/stagefright/MediaCodecSource.h
@@ -25,6 +25,7 @@
class ALooper;
class AMessage;
+struct AReplyToken;
class IGraphicBufferProducer;
class MediaCodec;
class MetaData;
@@ -99,7 +100,7 @@
sp<Puller> mPuller;
sp<MediaCodec> mEncoder;
uint32_t mFlags;
- List<uint32_t> mStopReplyIDQueue;
+ List<sp<AReplyToken>> mStopReplyIDQueue;
bool mIsVideo;
bool mStarted;
bool mStopping;
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 13695d5..a0036e0 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -36,6 +36,7 @@
extern const char *MEDIA_MIMETYPE_AUDIO_MPEG; // layer III
extern const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I;
extern const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II;
+extern const char *MEDIA_MIMETYPE_AUDIO_MIDI;
extern const char *MEDIA_MIMETYPE_AUDIO_AAC;
extern const char *MEDIA_MIMETYPE_AUDIO_QCELP;
extern const char *MEDIA_MIMETYPE_AUDIO_VORBIS;
diff --git a/include/media/stagefright/MediaFilter.h b/include/media/stagefright/MediaFilter.h
new file mode 100644
index 0000000..7b3f700
--- /dev/null
+++ b/include/media/stagefright/MediaFilter.h
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+#ifndef MEDIA_FILTER_H_
+#define MEDIA_FILTER_H_
+
+#include <media/stagefright/CodecBase.h>
+
+namespace android {
+
+struct ABuffer;
+struct GraphicBufferListener;
+struct MemoryDealer;
+struct SimpleFilter;
+
+struct MediaFilter : public CodecBase {
+ MediaFilter();
+
+ virtual void setNotificationMessage(const sp<AMessage> &msg);
+
+ virtual void initiateAllocateComponent(const sp<AMessage> &msg);
+ virtual void initiateConfigureComponent(const sp<AMessage> &msg);
+ virtual void initiateCreateInputSurface();
+ virtual void initiateStart();
+ virtual void initiateShutdown(bool keepComponentAllocated = false);
+
+ virtual void signalFlush();
+ virtual void signalResume();
+
+ virtual void signalRequestIDRFrame();
+ virtual void signalSetParameters(const sp<AMessage> &msg);
+ virtual void signalEndOfInputStream();
+
+ virtual void onMessageReceived(const sp<AMessage> &msg);
+
+ struct PortDescription : public CodecBase::PortDescription {
+ virtual size_t countBuffers();
+ virtual IOMX::buffer_id bufferIDAt(size_t index) const;
+ virtual sp<ABuffer> bufferAt(size_t index) const;
+
+ protected:
+ PortDescription();
+
+ private:
+ friend struct MediaFilter;
+
+ Vector<IOMX::buffer_id> mBufferIDs;
+ Vector<sp<ABuffer> > mBuffers;
+
+ void addBuffer(IOMX::buffer_id id, const sp<ABuffer> &buffer);
+
+ DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
+ };
+
+protected:
+ virtual ~MediaFilter();
+
+private:
+ struct BufferInfo {
+ enum Status {
+ OWNED_BY_US,
+ OWNED_BY_UPSTREAM,
+ };
+
+ IOMX::buffer_id mBufferID;
+ int32_t mGeneration;
+ int32_t mOutputFlags;
+ Status mStatus;
+
+ sp<ABuffer> mData;
+ };
+
+ enum State {
+ UNINITIALIZED,
+ INITIALIZED,
+ CONFIGURED,
+ STARTED,
+ };
+
+ enum {
+ kWhatInputBufferFilled = 'inpF',
+ kWhatOutputBufferDrained = 'outD',
+ kWhatShutdown = 'shut',
+ kWhatFlush = 'flus',
+ kWhatResume = 'resm',
+ kWhatAllocateComponent = 'allo',
+ kWhatConfigureComponent = 'conf',
+ kWhatCreateInputSurface = 'cisf',
+ kWhatSignalEndOfInputStream = 'eois',
+ kWhatStart = 'star',
+ kWhatSetParameters = 'setP',
+ kWhatProcessBuffers = 'proc',
+ };
+
+ enum {
+ kPortIndexInput = 0,
+ kPortIndexOutput = 1
+ };
+
+ // member variables
+ AString mComponentName;
+ State mState;
+ status_t mInputEOSResult;
+ int32_t mWidth, mHeight;
+ int32_t mStride, mSliceHeight;
+ int32_t mColorFormatIn, mColorFormatOut;
+ size_t mMaxInputSize, mMaxOutputSize;
+ int32_t mGeneration;
+ sp<AMessage> mNotify;
+ sp<AMessage> mInputFormat;
+ sp<AMessage> mOutputFormat;
+
+ sp<MemoryDealer> mDealer[2];
+ Vector<BufferInfo> mBuffers[2];
+ Vector<BufferInfo*> mAvailableInputBuffers;
+ Vector<BufferInfo*> mAvailableOutputBuffers;
+ bool mPortEOS[2];
+
+ sp<SimpleFilter> mFilter;
+ sp<GraphicBufferListener> mGraphicBufferListener;
+
+ // helper functions
+ void signalProcessBuffers();
+ void signalError(status_t error);
+
+ status_t allocateBuffersOnPort(OMX_U32 portIndex);
+ BufferInfo *findBufferByID(
+ uint32_t portIndex, IOMX::buffer_id bufferID,
+ ssize_t *index = NULL);
+ void postFillThisBuffer(BufferInfo *info);
+ void postDrainThisBuffer(BufferInfo *info);
+ void postEOS();
+ void sendFormatChange();
+ void requestFillEmptyInput();
+ void processBuffers();
+
+ void onAllocateComponent(const sp<AMessage> &msg);
+ void onConfigureComponent(const sp<AMessage> &msg);
+ void onStart();
+ void onInputBufferFilled(const sp<AMessage> &msg);
+ void onOutputBufferDrained(const sp<AMessage> &msg);
+ void onShutdown(const sp<AMessage> &msg);
+ void onFlush();
+ void onSetParameters(const sp<AMessage> &msg);
+ void onCreateInputSurface();
+ void onInputFrameAvailable();
+ void onSignalEndOfInputStream();
+
+ DISALLOW_EVIL_CONSTRUCTORS(MediaFilter);
+};
+
+} // namespace android
+
+#endif // MEDIA_FILTER_H_
diff --git a/include/media/stagefright/MediaMuxer.h b/include/media/stagefright/MediaMuxer.h
index bbe4303..e6538d1 100644
--- a/include/media/stagefright/MediaMuxer.h
+++ b/include/media/stagefright/MediaMuxer.h
@@ -22,6 +22,8 @@
#include <utils/Vector.h>
#include <utils/threads.h>
+#include "foundation/ABase.h"
+
namespace android {
struct ABuffer;
@@ -48,9 +50,6 @@
OUTPUT_FORMAT_LIST_END // must be last - used to validate format type
};
- // Construct the muxer with the output file path.
- MediaMuxer(const char *path, OutputFormat format);
-
// Construct the muxer with the file descriptor. Note that the MediaMuxer
// will close this file at stop().
MediaMuxer(int fd, OutputFormat format);
diff --git a/include/media/stagefright/RenderScriptWrapper.h b/include/media/stagefright/RenderScriptWrapper.h
new file mode 100644
index 0000000..b42649e
--- /dev/null
+++ b/include/media/stagefright/RenderScriptWrapper.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#ifndef RENDERSCRIPT_WRAPPER_H_
+#define RENDERSCRIPT_WRAPPER_H_
+
+#include <RenderScript.h>
+
+namespace android {
+
+struct RenderScriptWrapper : public RefBase {
+public:
+ struct RSFilterCallback : public RefBase {
+ public:
+ // called by RSFilter to process each input buffer
+ virtual status_t processBuffers(
+ RSC::Allocation* inBuffer,
+ RSC::Allocation* outBuffer) = 0;
+
+ virtual status_t handleSetParameters(const sp<AMessage> &msg) = 0;
+ };
+
+ sp<RSFilterCallback> mCallback;
+ RSC::sp<RSC::RS> mContext;
+};
+
+} // namespace android
+
+#endif // RENDERSCRIPT_WRAPPER_H_
diff --git a/include/media/stagefright/SurfaceMediaSource.h b/include/media/stagefright/SurfaceMediaSource.h
index d15a226..2177c00 100644
--- a/include/media/stagefright/SurfaceMediaSource.h
+++ b/include/media/stagefright/SurfaceMediaSource.h
@@ -25,6 +25,8 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MediaBuffer.h>
+#include "foundation/ABase.h"
+
namespace android {
// ----------------------------------------------------------------------------
@@ -233,7 +235,7 @@
Condition mMediaBuffersAvailableCondition;
// Avoid copying and equating and default constructor
- DISALLOW_IMPLICIT_CONSTRUCTORS(SurfaceMediaSource);
+ DISALLOW_EVIL_CONSTRUCTORS(SurfaceMediaSource);
};
// ----------------------------------------------------------------------------
diff --git a/include/media/stagefright/foundation/ABase.h b/include/media/stagefright/foundation/ABase.h
index 72e3d87..ef1e010 100644
--- a/include/media/stagefright/foundation/ABase.h
+++ b/include/media/stagefright/foundation/ABase.h
@@ -18,7 +18,9 @@
#define A_BASE_H_
+#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+#endif
#define DISALLOW_EVIL_CONSTRUCTORS(name) \
name(const name &); \
diff --git a/include/media/stagefright/foundation/AHandler.h b/include/media/stagefright/foundation/AHandler.h
index b008b54..fe02a86 100644
--- a/include/media/stagefright/foundation/AHandler.h
+++ b/include/media/stagefright/foundation/AHandler.h
@@ -19,6 +19,7 @@
#define A_HANDLER_H_
#include <media/stagefright/foundation/ALooper.h>
+#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
namespace android {
@@ -27,27 +28,49 @@
struct AHandler : public RefBase {
AHandler()
- : mID(0) {
+ : mID(0),
+ mVerboseStats(false),
+ mMessageCounter(0) {
}
ALooper::handler_id id() const {
return mID;
}
- sp<ALooper> looper();
+ sp<ALooper> looper() const {
+ return mLooper.promote();
+ }
+
+ wp<ALooper> getLooper() const {
+ return mLooper;
+ }
+
+ wp<AHandler> getHandler() const {
+ // allow getting a weak reference to a const handler
+ return const_cast<AHandler *>(this);
+ }
protected:
virtual void onMessageReceived(const sp<AMessage> &msg) = 0;
private:
- friend struct ALooperRoster;
+ friend struct AMessage; // deliverMessage()
+ friend struct ALooperRoster; // setID()
ALooper::handler_id mID;
+ wp<ALooper> mLooper;
- void setID(ALooper::handler_id id) {
+ inline void setID(ALooper::handler_id id, wp<ALooper> looper) {
mID = id;
+ mLooper = looper;
}
+ bool mVerboseStats;
+ uint32_t mMessageCounter;
+ KeyedVector<uint32_t, uint32_t> mMessages;
+
+ void deliverMessage(const sp<AMessage> &msg);
+
DISALLOW_EVIL_CONSTRUCTORS(AHandler);
};
diff --git a/include/media/stagefright/foundation/ALooper.h b/include/media/stagefright/foundation/ALooper.h
index 70e0c5e..09c469b 100644
--- a/include/media/stagefright/foundation/ALooper.h
+++ b/include/media/stagefright/foundation/ALooper.h
@@ -30,6 +30,7 @@
struct AHandler;
struct AMessage;
+struct AReplyToken;
struct ALooper : public RefBase {
typedef int32_t event_id;
@@ -53,11 +54,15 @@
static int64_t GetNowUs();
+ const char *getName() const {
+ return mName.c_str();
+ }
+
protected:
virtual ~ALooper();
private:
- friend struct ALooperRoster;
+ friend struct AMessage; // post()
struct Event {
int64_t mWhenUs;
@@ -75,12 +80,32 @@
sp<LooperThread> mThread;
bool mRunningLocally;
+ // use a separate lock for reply handling, as it is always on another thread
+ // use a central lock, however, to avoid creating a mutex for each reply
+ Mutex mRepliesLock;
+ Condition mRepliesCondition;
+
+ // START --- methods used only by AMessage
+
+ // posts a message on this looper with the given timeout
void post(const sp<AMessage> &msg, int64_t delayUs);
+
+ // creates a reply token to be used with this looper
+ sp<AReplyToken> createReplyToken();
+ // waits for a response for the reply token. If status is OK, the response
+ // is stored into the supplied variable. Otherwise, it is unchanged.
+ status_t awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response);
+ // posts a reply for a reply token. If the reply could be successfully posted,
+ // it returns OK. Otherwise, it returns an error value.
+ status_t postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &msg);
+
+ // END --- methods used only by AMessage
+
bool loop();
DISALLOW_EVIL_CONSTRUCTORS(ALooper);
};
-} // namespace android
+} // namespace android
#endif // A_LOOPER_H_
diff --git a/include/media/stagefright/foundation/ALooperRoster.h b/include/media/stagefright/foundation/ALooperRoster.h
index 4d76b64..9912455 100644
--- a/include/media/stagefright/foundation/ALooperRoster.h
+++ b/include/media/stagefright/foundation/ALooperRoster.h
@@ -20,6 +20,7 @@
#include <media/stagefright/foundation/ALooper.h>
#include <utils/KeyedVector.h>
+#include <utils/String16.h>
namespace android {
@@ -32,15 +33,7 @@
void unregisterHandler(ALooper::handler_id handlerID);
void unregisterStaleHandlers();
- status_t postMessage(const sp<AMessage> &msg, int64_t delayUs = 0);
- void deliverMessage(const sp<AMessage> &msg);
-
- status_t postAndAwaitResponse(
- const sp<AMessage> &msg, sp<AMessage> *response);
-
- void postReply(uint32_t replyID, const sp<AMessage> &reply);
-
- sp<ALooper> findLooper(ALooper::handler_id handlerID);
+ void dump(int fd, const Vector<String16>& args);
private:
struct HandlerInfo {
@@ -51,10 +44,6 @@
Mutex mLock;
KeyedVector<ALooper::handler_id, HandlerInfo> mHandlers;
ALooper::handler_id mNextHandlerID;
- uint32_t mNextReplyID;
- Condition mRepliesCondition;
-
- KeyedVector<uint32_t, sp<AMessage> > mReplies;
DISALLOW_EVIL_CONSTRUCTORS(ALooperRoster);
};
diff --git a/include/media/stagefright/foundation/AMessage.h b/include/media/stagefright/foundation/AMessage.h
index a9e235b..4c6bd21 100644
--- a/include/media/stagefright/foundation/AMessage.h
+++ b/include/media/stagefright/foundation/AMessage.h
@@ -26,11 +26,41 @@
namespace android {
struct ABuffer;
+struct AHandler;
struct AString;
struct Parcel;
+struct AReplyToken : public RefBase {
+ AReplyToken(const sp<ALooper> &looper)
+ : mLooper(looper),
+ mReplied(false) {
+ }
+
+private:
+ friend struct AMessage;
+ friend struct ALooper;
+ wp<ALooper> mLooper;
+ sp<AMessage> mReply;
+ bool mReplied;
+
+ sp<ALooper> getLooper() const {
+ return mLooper.promote();
+ }
+ // if reply is not set, returns false; otherwise, it retrieves the reply and returns true
+ bool retrieveReply(sp<AMessage> *reply) {
+ if (mReplied) {
+ *reply = mReply;
+ mReply.clear();
+ }
+ return mReplied;
+ }
+ // sets the reply for this token. returns OK or error
+ status_t setReply(const sp<AMessage> &reply);
+};
+
struct AMessage : public RefBase {
- AMessage(uint32_t what = 0, ALooper::handler_id target = 0);
+ AMessage();
+ AMessage(uint32_t what, const sp<const AHandler> &handler);
static sp<AMessage> FromParcel(const Parcel &parcel);
void writeToParcel(Parcel *parcel) const;
@@ -38,8 +68,7 @@
void setWhat(uint32_t what);
uint32_t what() const;
- void setTarget(ALooper::handler_id target);
- ALooper::handler_id target() const;
+ void setTarget(const sp<const AHandler> &handler);
void clear();
@@ -76,18 +105,22 @@
const char *name,
int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const;
- void post(int64_t delayUs = 0);
+ status_t post(int64_t delayUs = 0);
// Posts the message to its target and waits for a response (or error)
// before returning.
status_t postAndAwaitResponse(sp<AMessage> *response);
// If this returns true, the sender of this message is synchronously
- // awaiting a response, the "replyID" can be used to send the response
- // via "postReply" below.
- bool senderAwaitsResponse(uint32_t *replyID) const;
+ // awaiting a response and the reply token is consumed from the message
+ // and stored into replyID. The reply token must be used to send the response
+ // using "postReply" below.
+ bool senderAwaitsResponse(sp<AReplyToken> *replyID);
- void postReply(uint32_t replyID);
+ // Posts the message as a response to a reply token. A reply token can
+ // only be used once. Returns OK if the response could be posted; otherwise,
+ // an error.
+ status_t postReply(const sp<AReplyToken> &replyID);
// Performs a deep-copy of "this", contained messages are in turn "dup'ed".
// Warning: RefBase items, i.e. "objects" are _not_ copied but only have
@@ -117,9 +150,16 @@
virtual ~AMessage();
private:
+ friend struct ALooper; // deliver()
+
uint32_t mWhat;
+
+ // used only for debugging
ALooper::handler_id mTarget;
+ wp<AHandler> mHandler;
+ wp<ALooper> mLooper;
+
struct Rect {
int32_t mLeft, mTop, mRight, mBottom;
};
@@ -157,6 +197,8 @@
size_t findItemIndex(const char *name, size_t len) const;
+ void deliver();
+
DISALLOW_EVIL_CONSTRUCTORS(AMessage);
};
diff --git a/include/media/stagefright/foundation/AString.h b/include/media/stagefright/foundation/AString.h
index 7c98699..822dbb3 100644
--- a/include/media/stagefright/foundation/AString.h
+++ b/include/media/stagefright/foundation/AString.h
@@ -23,7 +23,7 @@
namespace android {
-struct String8;
+class String8;
struct Parcel;
struct AString {
@@ -102,7 +102,7 @@
void makeMutable();
};
-AString StringPrintf(const char *format, ...);
+AString AStringPrintf(const char *format, ...);
} // namespace android
diff --git a/include/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h
index c07f4c9..4f6a1ef 100644
--- a/include/ndk/NdkMediaCodec.h
+++ b/include/ndk/NdkMediaCodec.h
@@ -142,7 +142,8 @@
/**
* Get the index of the next available buffer of processed data.
*/
-ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec*, AMediaCodecBufferInfo *info, int64_t timeoutUs);
+ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec*, AMediaCodecBufferInfo *info,
+ int64_t timeoutUs);
AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec*);
/**
diff --git a/include/ndk/NdkMediaDrm.h b/include/ndk/NdkMediaDrm.h
index 10afdd9..3c312a9 100644
--- a/include/ndk/NdkMediaDrm.h
+++ b/include/ndk/NdkMediaDrm.h
@@ -327,24 +327,24 @@
/**
* String property name: identifies the maker of the DRM engine plugin
*/
-const char *PROPERTY_VENDOR = "vendor";
+#define PROPERTY_VENDOR "vendor"
/**
* String property name: identifies the version of the DRM engine plugin
*/
-const char *PROPERTY_VERSION = "version";
+#define PROPERTY_VERSION "version"
/**
* String property name: describes the DRM engine plugin
*/
-const char *PROPERTY_DESCRIPTION = "description";
+#define PROPERTY_DESCRIPTION "description"
/**
* String property name: a comma-separated list of cipher and mac algorithms
* supported by CryptoSession. The list may be empty if the DRM engine
* plugin does not support CryptoSession operations.
*/
-const char *PROPERTY_ALGORITHMS = "algorithms";
+#define PROPERTY_ALGORITHMS "algorithms"
/**
* Read a DRM engine plugin String property value, given the property name string.
@@ -361,7 +361,7 @@
* Byte array property name: the device unique identifier is established during
* device provisioning and provides a means of uniquely identifying each device.
*/
-const char *PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
+#define PROPERTY_DEVICE_UNIQUE_ID "deviceUniqueId"
/**
* Read a DRM engine plugin byte array property value, given the property name string.
diff --git a/include/ndk/NdkMediaExtractor.h b/include/ndk/NdkMediaExtractor.h
index 7a4e702..7324d31 100644
--- a/include/ndk/NdkMediaExtractor.h
+++ b/include/ndk/NdkMediaExtractor.h
@@ -55,12 +55,14 @@
/**
* Set the file descriptor from which the extractor will read.
*/
-media_status_t AMediaExtractor_setDataSourceFd(AMediaExtractor*, int fd, off64_t offset, off64_t length);
+media_status_t AMediaExtractor_setDataSourceFd(AMediaExtractor*, int fd, off64_t offset,
+ off64_t length);
/**
* Set the URI from which the extractor will read.
*/
-media_status_t AMediaExtractor_setDataSource(AMediaExtractor*, const char *location); // TODO support headers
+media_status_t AMediaExtractor_setDataSource(AMediaExtractor*, const char *location);
+ // TODO support headers
/**
* Return the number of tracks in the previously specified media file
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 31dff36..7143f1a 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -24,9 +24,8 @@
#include <utils/threads.h>
#include <utils/Log.h>
#include <utils/RefBase.h>
-#include <media/nbaio/roundup.h>
+#include <audio_utils/roundup.h>
#include <media/SingleStateQueue.h>
-#include <private/media/StaticAudioTrackState.h>
namespace android {
@@ -61,15 +60,57 @@
volatile uint32_t mUnderrunFrames; // server increments for each unavailable but desired frame
};
+// Represents a single state of an AudioTrack that was created in static mode (shared memory buffer
+// supplied by the client). This state needs to be communicated from the client to server. As this
+// state is too large to be updated atomically without a mutex, and mutexes aren't allowed here, the
+// state is wrapped by a SingleStateQueue.
+struct StaticAudioTrackState {
+ // Do not define constructors, destructors, or virtual methods as this is part of a
+ // union in shared memory and they will not get called properly.
+
+ // These fields should both be size_t, but since they are located in shared memory we
+ // force to 32-bit. The client and server may have different typedefs for size_t.
+
+ // The state has a sequence counter to indicate whether changes are made to loop or position.
+ // The sequence counter also currently indicates whether loop or position is first depending
+ // on which is greater; it jumps by max(mLoopSequence, mPositionSequence) + 1.
+
+ uint32_t mLoopStart;
+ uint32_t mLoopEnd;
+ int32_t mLoopCount;
+ uint32_t mLoopSequence; // a sequence counter to indicate changes to loop
+ uint32_t mPosition;
+ uint32_t mPositionSequence; // a sequence counter to indicate changes to position
+};
+
typedef SingleStateQueue<StaticAudioTrackState> StaticAudioTrackSingleStateQueue;
+struct StaticAudioTrackPosLoop {
+ // Do not define constructors, destructors, or virtual methods as this is part of a
+ // union in shared memory and will not get called properly.
+
+ // These fields should both be size_t, but since they are located in shared memory we
+ // force to 32-bit. The client and server may have different typedefs for size_t.
+
+ // This struct information is stored in a single state queue to communicate the
+ // static AudioTrack server state to the client while data is consumed.
+ // It is smaller than StaticAudioTrackState to prevent unnecessary information from
+ // being sent.
+
+ uint32_t mBufferPosition;
+ int32_t mLoopCount;
+};
+
+typedef SingleStateQueue<StaticAudioTrackPosLoop> StaticAudioTrackPosLoopQueue;
+
struct AudioTrackSharedStatic {
+ // client requests to the server for loop or position changes.
StaticAudioTrackSingleStateQueue::Shared
mSingleStateQueue;
- // This field should be a size_t, but since it is located in shared memory we
- // force to 32-bit. The client and server may have different typedefs for size_t.
- uint32_t mBufferPosition; // updated asynchronously by server,
- // "for entertainment purposes only"
+ // position info updated asynchronously by server and read by client,
+ // "for entertainment purposes only"
+ StaticAudioTrackPosLoopQueue::Shared
+ mPosLoopQueue;
};
// ----------------------------------------------------------------------------
@@ -96,7 +137,8 @@
uint32_t mServer; // Number of filled frames consumed by server (mIsOut),
// or filled frames provided by server (!mIsOut).
// It is updated asynchronously by server without a barrier.
- // The value should be used "for entertainment purposes only",
+ // The value should be used
+ // "for entertainment purposes only",
// which means don't make important decisions based on it.
uint32_t mPad1; // unused
@@ -313,8 +355,28 @@
virtual void flush();
#define MIN_LOOP 16 // minimum length of each loop iteration in frames
+
+ // setLoop(), setBufferPosition(), and setBufferPositionAndLoop() set the
+ // static buffer position and looping parameters. These commands are not
+ // synchronous (they do not wait or block); instead they take effect at the
+ // next buffer data read from the server side. However, the client side
+ // getters will read a cached version of the position and loop variables
+ // until the setting takes effect.
+ //
+ // setBufferPositionAndLoop() is equivalent to calling, in order, setLoop() and
+ // setBufferPosition().
+ //
+ // The functions should not be relied upon to do parameter or state checking.
+ // That is done at the AudioTrack level.
+
void setLoop(size_t loopStart, size_t loopEnd, int loopCount);
+ void setBufferPosition(size_t position);
+ void setBufferPositionAndLoop(size_t position, size_t loopStart, size_t loopEnd,
+ int loopCount);
size_t getBufferPosition();
+ // getBufferPositionAndLoopCount() provides the proper snapshot of
+ // position and loopCount together.
+ void getBufferPositionAndLoopCount(size_t *position, int *loopCount);
virtual size_t getMisalignment() {
return 0;
@@ -326,7 +388,9 @@
private:
StaticAudioTrackSingleStateQueue::Mutator mMutator;
- size_t mBufferPosition; // so that getBufferPosition() appears to be synchronous
+ StaticAudioTrackPosLoopQueue::Observer mPosLoopObserver;
+ StaticAudioTrackState mState; // last communicated state to server
+ StaticAudioTrackPosLoop mPosLoop; // snapshot of position and loop.
};
// ----------------------------------------------------------------------------
@@ -447,10 +511,13 @@
virtual uint32_t getUnderrunFrames() const { return 0; }
private:
+ status_t updateStateWithLoop(StaticAudioTrackState *localState,
+ const StaticAudioTrackState &update) const;
+ status_t updateStateWithPosition(StaticAudioTrackState *localState,
+ const StaticAudioTrackState &update) const;
ssize_t pollPosition(); // poll for state queue update, and return current position
StaticAudioTrackSingleStateQueue::Observer mObserver;
- size_t mPosition; // server's current play position in frames, relative to 0
-
+ StaticAudioTrackPosLoopQueue::Mutator mPosLoopMutator;
size_t mFramesReadySafe; // Assuming size_t read/writes are atomic on 32 / 64 bit
// processors, this is a thread-safe version of
// mFramesReady.
@@ -459,7 +526,8 @@
// can cause a track to appear to have a large number
// of frames. INT64_MAX means an infinite loop.
bool mFramesReadyIsCalledByMultipleThreads;
- StaticAudioTrackState mState;
+ StaticAudioTrackState mState; // Server side state. Any updates from client must be
+ // passed by the mObserver SingleStateQueue.
};
// Proxy used by AudioFlinger for servicing AudioRecord
diff --git a/include/private/media/StaticAudioTrackState.h b/include/private/media/StaticAudioTrackState.h
deleted file mode 100644
index d483061..0000000
--- a/include/private/media/StaticAudioTrackState.h
+++ /dev/null
@@ -1,39 +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 STATIC_AUDIO_TRACK_STATE_H
-#define STATIC_AUDIO_TRACK_STATE_H
-
-namespace android {
-
-// Represents a single state of an AudioTrack that was created in static mode (shared memory buffer
-// supplied by the client). This state needs to be communicated from the client to server. As this
-// state is too large to be updated atomically without a mutex, and mutexes aren't allowed here, the
-// state is wrapped by a SingleStateQueue.
-struct StaticAudioTrackState {
- // do not define constructors, destructors, or virtual methods
-
- // These fields should both be size_t, but since they are located in shared memory we
- // force to 32-bit. The client and server may have different typedefs for size_t.
- uint32_t mLoopStart;
- uint32_t mLoopEnd;
-
- int mLoopCount;
-};
-
-} // namespace android
-
-#endif // STATIC_AUDIO_TRACK_STATE_H
diff --git a/media/common_time/ICommonClock.cpp b/media/common_time/ICommonClock.cpp
index 25ae69e..19b7d6e 100644
--- a/media/common_time/ICommonClock.cpp
+++ b/media/common_time/ICommonClock.cpp
@@ -206,7 +206,7 @@
const sp<ICommonClockListener>& listener) {
Parcel data, reply;
data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
- data.writeStrongBinder(listener->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(listener));
status_t status = remote()->transact(REGISTER_LISTENER, data, &reply);
@@ -221,7 +221,7 @@
const sp<ICommonClockListener>& listener) {
Parcel data, reply;
data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
- data.writeStrongBinder(listener->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(listener));
status_t status = remote()->transact(UNREGISTER_LISTENER, data, &reply);
if (status == OK) {
diff --git a/media/img_utils/include/img_utils/TiffEntryImpl.h b/media/img_utils/include/img_utils/TiffEntryImpl.h
index f5ccb5e..c73e231 100644
--- a/media/img_utils/include/img_utils/TiffEntryImpl.h
+++ b/media/img_utils/include/img_utils/TiffEntryImpl.h
@@ -147,7 +147,7 @@
}
template<typename T>
-status_t TiffEntryImpl<T>::writeData(uint32_t offset, EndianOutput* out) const {
+status_t TiffEntryImpl<T>::writeData(uint32_t /*offset*/, EndianOutput* out) const {
status_t ret = OK;
// Some tags have fixed-endian value output
diff --git a/media/img_utils/src/FileInput.cpp b/media/img_utils/src/FileInput.cpp
index 498e715..4c85a51 100644
--- a/media/img_utils/src/FileInput.cpp
+++ b/media/img_utils/src/FileInput.cpp
@@ -78,7 +78,7 @@
ret = BAD_VALUE;
}
mOpen = false;
- return OK;
+ return ret;
}
} /*namespace img_utils*/
diff --git a/media/img_utils/src/FileOutput.cpp b/media/img_utils/src/FileOutput.cpp
index ce763ff..0346762 100644
--- a/media/img_utils/src/FileOutput.cpp
+++ b/media/img_utils/src/FileOutput.cpp
@@ -72,7 +72,7 @@
ret = BAD_VALUE;
}
mOpen = false;
- return OK;
+ return ret;
}
} /*namespace img_utils*/
diff --git a/media/img_utils/src/TiffWriter.cpp b/media/img_utils/src/TiffWriter.cpp
index ac41734..a6f9218 100644
--- a/media/img_utils/src/TiffWriter.cpp
+++ b/media/img_utils/src/TiffWriter.cpp
@@ -106,7 +106,6 @@
for (size_t i = 0; i < offVecSize; ++i) {
uint32_t ifdKey = offsetVector.keyAt(i);
- uint32_t nextOffset = offsetVector[i];
uint32_t sizeToWrite = mNamedIfds[ifdKey]->getStripSize();
bool found = false;
for (size_t j = 0; j < sourcesCount; ++j) {
@@ -124,7 +123,7 @@
ALOGE("%s: No stream for byte strips for IFD %u", __FUNCTION__, ifdKey);
return BAD_VALUE;
}
- assert(nextOffset == endOut.getCurrentOffset());
+ assert(offsetVector[i] == endOut.getCurrentOffset());
}
return ret;
diff --git a/media/libcpustats/ThreadCpuUsage.cpp b/media/libcpustats/ThreadCpuUsage.cpp
index cfdcb51..b43b36c 100644
--- a/media/libcpustats/ThreadCpuUsage.cpp
+++ b/media/libcpustats/ThreadCpuUsage.cpp
@@ -19,6 +19,7 @@
#include <errno.h>
#include <stdlib.h>
+#include <string.h>
#include <time.h>
#include <utils/Log.h>
@@ -74,7 +75,6 @@
bool ThreadCpuUsage::sampleAndEnable(double& ns)
{
- bool ret;
bool wasEverEnabled = mWasEverEnabled;
if (enable()) {
// already enabled, so add a new sample relative to previous
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index 6d30d64..c310fe2 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -28,6 +28,7 @@
static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects
static list_elem_t *gLibraryList; // list of lib_entry_t: all currently loaded libraries
+static list_elem_t *gSkippedEffects; // list of effects skipped because of duplicate uuid
// list of effect_descriptor and list of sub effects : all currently loaded
// It does not contain effects without sub effects.
static list_sub_elem_t *gSubEffectList;
@@ -63,10 +64,10 @@
lib_entry_t **lib,
effect_descriptor_t **desc);
// To search a subeffect in the gSubEffectList
-int findSubEffect(const effect_uuid_t *uuid,
+static int findSubEffect(const effect_uuid_t *uuid,
lib_entry_t **lib,
effect_descriptor_t **desc);
-static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len);
+static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len, int indent);
static int stringToUuid(const char *str, effect_uuid_t *uuid);
static int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen);
@@ -237,8 +238,8 @@
}
#if (LOG_NDEBUG == 0)
- char str[256];
- dumpEffectDescriptor(pDescriptor, str, 256);
+ char str[512];
+ dumpEffectDescriptor(pDescriptor, str, sizeof(str), 0 /* indent */);
ALOGV("EffectQueryEffect() desc:%s", str);
#endif
pthread_mutex_unlock(&gLibLock);
@@ -503,15 +504,31 @@
audio_effect_library_t *desc;
list_elem_t *e;
lib_entry_t *l;
+ char path[PATH_MAX];
+ char *str;
+ size_t len;
node = config_find(root, PATH_TAG);
if (node == NULL) {
return -EINVAL;
}
+ // audio_effects.conf always specifies 32 bit lib path: convert to 64 bit path if needed
+ strlcpy(path, node->value, PATH_MAX);
+#ifdef __LP64__
+ str = strstr(path, "/lib/");
+ if (str == NULL)
+ return -EINVAL;
+ len = str - path;
+ path[len] = '\0';
+ strlcat(path, "/lib64/", PATH_MAX);
+ strlcat(path, node->value + len + strlen("/lib/"), PATH_MAX);
+#endif
+ if (strlen(path) >= PATH_MAX - 1)
+ return -EINVAL;
- hdl = dlopen(node->value, RTLD_NOW);
+ hdl = dlopen(path, RTLD_NOW);
if (hdl == NULL) {
- ALOGW("loadLibrary() failed to open %s", node->value);
+ ALOGW("loadLibrary() failed to open %s", path);
goto error;
}
@@ -535,7 +552,7 @@
// add entry for library in gLibraryList
l = malloc(sizeof(lib_entry_t));
l->name = strndup(name, PATH_MAX);
- l->path = strndup(node->value, PATH_MAX);
+ l->path = strndup(path, PATH_MAX);
l->handle = hdl;
l->desc = desc;
l->effects = NULL;
@@ -547,7 +564,7 @@
e->next = gLibraryList;
gLibraryList = e;
pthread_mutex_unlock(&gLibLock);
- ALOGV("getLibrary() linked library %p for path %s", l, node->value);
+ ALOGV("getLibrary() linked library %p for path %s", l, path);
return 0;
@@ -595,8 +612,8 @@
return -EINVAL;
}
#if (LOG_NDEBUG==0)
- char s[256];
- dumpEffectDescriptor(d, s, 256);
+ char s[512];
+ dumpEffectDescriptor(d, s, sizeof(s), 0 /* indent */);
ALOGV("addSubEffect() read descriptor %p:%s",d, s);
#endif
if (EFFECT_API_VERSION_MAJOR(d->apiVersion) !=
@@ -660,6 +677,13 @@
ALOGW("loadEffect() invalid uuid %s", node->value);
return -EINVAL;
}
+ lib_entry_t *tmp;
+ bool skip = false;
+ if (findEffect(NULL, &uuid, &tmp, NULL) == 0) {
+ ALOGW("skipping duplicate uuid %s %s", node->value,
+ node->next ? "and its sub-effects" : "");
+ skip = true;
+ }
d = malloc(sizeof(effect_descriptor_t));
if (l->desc->get_descriptor(&uuid, d) != 0) {
@@ -670,8 +694,8 @@
return -EINVAL;
}
#if (LOG_NDEBUG==0)
- char s[256];
- dumpEffectDescriptor(d, s, 256);
+ char s[512];
+ dumpEffectDescriptor(d, s, sizeof(s), 0 /* indent */);
ALOGV("loadEffect() read descriptor %p:%s",d, s);
#endif
if (EFFECT_API_VERSION_MAJOR(d->apiVersion) !=
@@ -682,8 +706,14 @@
}
e = malloc(sizeof(list_elem_t));
e->object = d;
- e->next = l->effects;
- l->effects = e;
+ if (skip) {
+ e->next = gSkippedEffects;
+ gSkippedEffects = e;
+ return -EINVAL;
+ } else {
+ e->next = l->effects;
+ l->effects = e;
+ }
// After the UUID node in the config_tree, if node->next is valid,
// that would be sub effect node.
@@ -876,22 +906,30 @@
return ret;
}
-void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len) {
+void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len, int indent) {
char s[256];
+ char ss[256];
+ char idt[indent + 1];
- snprintf(str, len, "\nEffect Descriptor %p:\n", desc);
- strncat(str, "- TYPE: ", len);
- uuidToString(&desc->uuid, s, 256);
- snprintf(str, len, "- UUID: %s\n", s);
- uuidToString(&desc->type, s, 256);
- snprintf(str, len, "- TYPE: %s\n", s);
- sprintf(s, "- apiVersion: %08X\n- flags: %08X\n",
- desc->apiVersion, desc->flags);
- strncat(str, s, len);
- sprintf(s, "- name: %s\n", desc->name);
- strncat(str, s, len);
- sprintf(s, "- implementor: %s\n", desc->implementor);
- strncat(str, s, len);
+ memset(idt, ' ', indent);
+ idt[indent] = 0;
+
+ str[0] = 0;
+
+ snprintf(s, sizeof(s), "%s%s / %s\n", idt, desc->name, desc->implementor);
+ strlcat(str, s, len);
+
+ uuidToString(&desc->uuid, s, sizeof(s));
+ snprintf(ss, sizeof(ss), "%s UUID: %s\n", idt, s);
+ strlcat(str, ss, len);
+
+ uuidToString(&desc->type, s, sizeof(s));
+ snprintf(ss, sizeof(ss), "%s TYPE: %s\n", idt, s);
+ strlcat(str, ss, len);
+
+ sprintf(s, "%s apiVersion: %08X\n%s flags: %08X\n", idt,
+ desc->apiVersion, idt, desc->flags);
+ strlcat(str, s, len);
}
int stringToUuid(const char *str, effect_uuid_t *uuid)
@@ -934,3 +972,40 @@
return 0;
}
+int EffectDumpEffects(int fd) {
+ char s[512];
+ list_elem_t *e = gLibraryList;
+ lib_entry_t *l = NULL;
+ effect_descriptor_t *d = NULL;
+ int found = 0;
+ int ret = 0;
+
+ while (e) {
+ l = (lib_entry_t *)e->object;
+ list_elem_t *efx = l->effects;
+ dprintf(fd, "Library %s\n", l->name);
+ if (!efx) {
+ dprintf(fd, " (no effects)\n");
+ }
+ while (efx) {
+ d = (effect_descriptor_t *)efx->object;
+ dumpEffectDescriptor(d, s, sizeof(s), 2);
+ dprintf(fd, "%s", s);
+ efx = efx->next;
+ }
+ e = e->next;
+ }
+
+ e = gSkippedEffects;
+ if (e) {
+ dprintf(fd, "Skipped effects\n");
+ while(e) {
+ d = (effect_descriptor_t *)e->object;
+ dumpEffectDescriptor(d, s, sizeof(s), 2 /* indent */);
+ dprintf(fd, "%s", s);
+ e = e->next;
+ }
+ }
+ return ret;
+}
+
diff --git a/media/libeffects/loudness/Android.mk b/media/libeffects/loudness/Android.mk
index edf964e..55d0611 100644
--- a/media/libeffects/loudness/Android.mk
+++ b/media/libeffects/loudness/Android.mk
@@ -12,16 +12,11 @@
LOCAL_SHARED_LIBRARIES := \
libcutils \
liblog \
- libstlport
LOCAL_MODULE_RELATIVE_PATH := soundfx
LOCAL_MODULE:= libldnhncr
LOCAL_C_INCLUDES := \
$(call include-path-for, audio-effects) \
- bionic \
- bionic/libstdc++/include \
- external/stlport/stlport
-
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/proxy/Android.mk b/media/libeffects/proxy/Android.mk
index b438796..2ba452e 100644
--- a/media/libeffects/proxy/Android.mk
+++ b/media/libeffects/proxy/Android.mk
@@ -28,7 +28,6 @@
LOCAL_C_INCLUDES := \
system/media/audio_effects/include \
- bionic/libc/include \
frameworks/av/media/libeffects/factory
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/testlibs/Android.mk_ b/media/libeffects/testlibs/Android.mk_
index 672ebba..14c373f 100644
--- a/media/libeffects/testlibs/Android.mk_
+++ b/media/libeffects/testlibs/Android.mk_
@@ -3,24 +3,18 @@
# Test Reverb library
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
+LOCAL_SRC_FILES := \
EffectReverb.c.arm \
EffectsMath.c.arm
-LOCAL_CFLAGS+= -O2
+
+LOCAL_CFLAGS := -O2
LOCAL_SHARED_LIBRARIES := \
- libcutils
+ libcutils \
+ libdl
LOCAL_MODULE_RELATIVE_PATH := soundfx
-LOCAL_MODULE:= libreverbtest
-
-ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
-LOCAL_LDLIBS += -ldl
-endif
-
-ifneq ($(TARGET_SIMULATOR),true)
-LOCAL_SHARED_LIBRARIES += libdl
-endif
+LOCAL_MODULE := libreverbtest
LOCAL_C_INCLUDES := \
$(call include-path-for, audio-effects) \
@@ -33,7 +27,7 @@
# Test Equalizer library
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
+LOCAL_SRC_FILES := \
EffectsMath.c.arm \
EffectEqualizer.cpp \
AudioBiquadFilter.cpp.arm \
@@ -42,21 +36,14 @@
AudioShelvingFilter.cpp.arm \
AudioEqualizer.cpp.arm
-LOCAL_CFLAGS+= -O2
+LOCAL_CFLAGS := -O2
LOCAL_SHARED_LIBRARIES := \
- libcutils
+ libcutils \
+ libdl
LOCAL_MODULE_RELATIVE_PATH := soundfx
-LOCAL_MODULE:= libequalizertest
-
-ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
-LOCAL_LDLIBS += -ldl
-endif
-
-ifneq ($(TARGET_SIMULATOR),true)
-LOCAL_SHARED_LIBRARIES += libdl
-endif
+LOCAL_MODULE := libequalizertest
LOCAL_C_INCLUDES := \
$(call include-path-for, graphics corecg) \
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index a2e0909..5378bf2 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -42,6 +42,7 @@
mediarecorder.cpp \
IMediaMetadataRetriever.cpp \
mediametadataretriever.cpp \
+ MidiIoWrapper.cpp \
ToneGenerator.cpp \
JetPlayer.cpp \
IOMX.cpp \
@@ -57,43 +58,26 @@
AudioEffect.cpp \
Visualizer.cpp \
MemoryLeakTrackUtil.cpp \
- SoundPool.cpp \
- SoundPoolThread.cpp \
StringArray.cpp \
AudioPolicy.cpp
-LOCAL_SRC_FILES += ../libnbaio/roundup.c
-
LOCAL_SHARED_LIBRARIES := \
libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \
libcamera_client libstagefright_foundation \
libgui libdl libaudioutils libnbaio
-LOCAL_STATIC_LIBRARIES += libinstantssq
-
LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper
LOCAL_MODULE:= libmedia
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
LOCAL_C_INCLUDES := \
$(TOP)/frameworks/native/include/media/openmax \
$(TOP)/frameworks/av/include/media/ \
$(TOP)/frameworks/av/media/libstagefright \
- $(TOP)/external/icu/icu4c/source/common \
- $(TOP)/external/icu/icu4c/source/i18n \
$(call include-path-for, audio-effects) \
$(call include-path-for, audio-utils)
include $(BUILD_SHARED_LIBRARY)
-include $(CLEAR_VARS)
-
-# for <cutils/atomic-inline.h>
-LOCAL_CFLAGS += -DANDROID_SMP=$(if $(findstring true,$(TARGET_CPU_SMP)),1,0)
-LOCAL_SRC_FILES += SingleStateQueue.cpp
-LOCAL_CFLAGS += -DSINGLE_STATE_QUEUE_INSTANTIATIONS='"SingleStateQueueInstantiations.cpp"'
-
-LOCAL_MODULE := libinstantssq
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 0d5d7e4..af103c1 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -150,7 +150,7 @@
int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int);
mCblk->buffer = (uint8_t *)mCblk + bufOffset;
- iEffect->asBinder()->linkToDeath(mIEffectClient);
+ IInterface::asBinder(iEffect)->linkToDeath(mIEffectClient);
mClientPid = IPCThreadState::self()->getCallingPid();
ALOGV("set() %p OK effect: %s id: %d status %d enabled %d pid %d", this, mDescriptor.name, mId,
mStatus, mEnabled, mClientPid);
@@ -173,7 +173,7 @@
}
if (mIEffect != NULL) {
mIEffect->disconnect();
- mIEffect->asBinder()->unlinkToDeath(mIEffectClient);
+ IInterface::asBinder(mIEffect)->unlinkToDeath(mIEffectClient);
}
IPCThreadState::self()->flushCommands();
}
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index ca3832d..07ca14f 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -107,7 +107,7 @@
mAudioRecordThread->requestExitAndWait();
mAudioRecordThread.clear();
}
- mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this);
+ IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this);
mAudioRecord.clear();
mCblkMemory.clear();
mBufferMemory.clear();
@@ -525,7 +525,7 @@
// invariant that mAudioRecord != 0 is true only after set() returns successfully
if (mAudioRecord != 0) {
- mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this);
+ IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this);
mDeathNotifier.clear();
}
mAudioRecord = record;
@@ -575,7 +575,7 @@
mProxy->setMinimum(mNotificationFramesAct);
mDeathNotifier = new DeathNotifier(this);
- mAudioRecord->asBinder()->linkToDeath(mDeathNotifier, this);
+ IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);
return NO_ERROR;
}
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 9cae21c..f5a5712 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -499,8 +499,8 @@
OutputDescriptor *outputDesc = new OutputDescriptor(*desc);
gOutputs.add(ioHandle, outputDesc);
- ALOGV("ioConfigChanged() new output samplingRate %u, format %#x channel mask %#x frameCount %zu "
- "latency %d",
+ ALOGV("ioConfigChanged() new output samplingRate %u, format %#x channel mask %#x "
+ "frameCount %zu latency %d",
outputDesc->samplingRate, outputDesc->format, outputDesc->channelMask,
outputDesc->frameCount, outputDesc->latency);
} break;
@@ -523,8 +523,8 @@
if (param2 == NULL) break;
desc = (const OutputDescriptor *)param2;
- ALOGV("ioConfigChanged() new config for output %d samplingRate %u, format %#x channel mask %#x "
- "frameCount %zu latency %d",
+ ALOGV("ioConfigChanged() new config for output %d samplingRate %u, format %#x "
+ "channel mask %#x frameCount %zu latency %d",
ioHandle, desc->samplingRate, desc->format,
desc->channelMask, desc->frameCount, desc->latency);
OutputDescriptor *outputDesc = gOutputs.valueAt(index);
@@ -590,18 +590,22 @@
status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
- const char *device_address)
+ const char *device_address,
+ const char *device_name)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
const char *address = "";
+ const char *name = "";
if (aps == 0) return PERMISSION_DENIED;
if (device_address != NULL) {
address = device_address;
}
-
- return aps->setDeviceConnectionState(device, state, address);
+ if (device_name != NULL) {
+ name = device_name;
+ }
+ return aps->setDeviceConnectionState(device, state, address, name);
}
audio_policy_dev_state_t AudioSystem::getDeviceConnectionState(audio_devices_t device,
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 389aacc..c775e7b 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -33,11 +33,16 @@
#define WAIT_PERIOD_MS 10
#define WAIT_STREAM_END_TIMEOUT_SEC 120
-
+static const int kMaxLoopCountNotifications = 32;
namespace android {
// ---------------------------------------------------------------------------
+template <typename T>
+const T &min(const T &x, const T &y) {
+ return x < y ? x : y;
+}
+
static int64_t convertTimespecToUs(const struct timespec &tv)
{
return tv.tv_sec * 1000000ll + tv.tv_nsec / 1000;
@@ -61,12 +66,11 @@
return BAD_VALUE;
}
- // FIXME merge with similar code in createTrack_l(), except we're missing
- // some information here that is available in createTrack_l():
+ // FIXME handle in server, like createTrack_l(), possible missing info:
// audio_io_handle_t output
// audio_format_t format
// audio_channel_mask_t channelMask
- // audio_output_flags_t flags
+ // audio_output_flags_t flags (FAST)
uint32_t afSampleRate;
status_t status;
status = AudioSystem::getOutputSamplingRate(&afSampleRate, streamType);
@@ -96,16 +100,16 @@
minBufCount = 2;
}
- *frameCount = (sampleRate == 0) ? afFrameCount * minBufCount :
- afFrameCount * minBufCount * uint64_t(sampleRate) / afSampleRate;
- // The formula above should always produce a non-zero value, but return an error
- // in the unlikely event that it does not, as that's part of the API contract.
+ *frameCount = minBufCount * sourceFramesNeeded(sampleRate, afFrameCount, afSampleRate);
+ // The formula above should always produce a non-zero value under normal circumstances:
+ // AudioTrack.SAMPLE_RATE_HZ_MIN <= sampleRate <= AudioTrack.SAMPLE_RATE_HZ_MAX.
+ // Return error in the unlikely event that it does not, as that's part of the API contract.
if (*frameCount == 0) {
- ALOGE("AudioTrack::getMinFrameCount failed for streamType %d, sampleRate %d",
+ ALOGE("AudioTrack::getMinFrameCount failed for streamType %d, sampleRate %u",
streamType, sampleRate);
return BAD_VALUE;
}
- ALOGV("getMinFrameCount=%zu: afFrameCount=%zu, minBufCount=%d, afSampleRate=%d, afLatency=%d",
+ ALOGV("getMinFrameCount=%zu: afFrameCount=%zu, minBufCount=%u, afSampleRate=%u, afLatency=%u",
*frameCount, afFrameCount, minBufCount, afSampleRate, afLatency);
return NO_ERROR;
}
@@ -194,7 +198,7 @@
mAudioTrackThread->requestExitAndWait();
mAudioTrackThread.clear();
}
- mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
+ IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
mAudioTrack.clear();
mCblkMemory.clear();
mSharedBuffer.clear();
@@ -295,6 +299,9 @@
ALOGV("Building AudioTrack with attributes: usage=%d content=%d flags=0x%x tags=[%s]",
mAttributes.usage, mAttributes.content_type, mAttributes.flags, mAttributes.tags);
mStreamType = AUDIO_STREAM_DEFAULT;
+ if ((mAttributes.flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
+ flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
+ }
}
// these below should probably come from the audioFlinger too...
@@ -317,12 +324,6 @@
uint32_t channelCount = audio_channel_count_from_out_mask(channelMask);
mChannelCount = channelCount;
- // AudioFlinger does not currently support 8-bit data in shared memory
- if (format == AUDIO_FORMAT_PCM_8_BIT && sharedBuffer != 0) {
- ALOGE("8-bit data in shared memory is not supported");
- return BAD_VALUE;
- }
-
// force direct flag if format is not linear PCM
// or offload was requested
if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
@@ -346,12 +347,9 @@
} else {
mFrameSize = sizeof(uint8_t);
}
- mFrameSizeAF = mFrameSize;
} else {
ALOG_ASSERT(audio_is_linear_pcm(format));
mFrameSize = channelCount * audio_bytes_per_sample(format);
- mFrameSizeAF = channelCount * audio_bytes_per_sample(
- format == AUDIO_FORMAT_PCM_8_BIT ? AUDIO_FORMAT_PCM_16_BIT : format);
// createTrack will return an error if PCM format is not supported by server,
// so no need to check for specific PCM formats here
}
@@ -420,7 +418,10 @@
mStatus = NO_ERROR;
mState = STATE_STOPPED;
mUserData = user;
- mLoopPeriod = 0;
+ mLoopCount = 0;
+ mLoopStart = 0;
+ mLoopEnd = 0;
+ mLoopCountNotified = 0;
mMarkerPosition = 0;
mMarkerReached = false;
mNewPosition = 0;
@@ -531,14 +532,12 @@
// the playback head position will reset to 0, so if a marker is set, we need
// to activate it again
mMarkerReached = false;
-#if 0
- // Force flush if a shared buffer is used otherwise audioflinger
- // will not stop before end of buffer is reached.
- // It may be needed to make sure that we stop playback, likely in case looping is on.
+
if (mSharedBuffer != 0) {
- flush_l();
+ // clear buffer position and loop count.
+ mStaticProxy->setBufferPositionAndLoop(0 /* position */,
+ 0 /* loopStart */, 0 /* loopEnd */, 0 /* loopCount */);
}
-#endif
sp<AudioTrackThread> t = mAudioTrackThread;
if (t != 0) {
@@ -740,10 +739,15 @@
void AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount)
{
- // Setting the loop will reset next notification update period (like setPosition).
- mNewPosition = updateAndGetPosition_l() + mUpdatePeriod;
- mLoopPeriod = loopCount != 0 ? loopEnd - loopStart : 0;
+ // We do not update the periodic notification point.
+ // mNewPosition = updateAndGetPosition_l() + mUpdatePeriod;
+ mLoopCount = loopCount;
+ mLoopEnd = loopEnd;
+ mLoopStart = loopStart;
+ mLoopCountNotified = loopCount;
mStaticProxy->setLoop(loopStart, loopEnd, loopCount);
+
+ // Waking the AudioTrackThread is not needed as this cannot be called when active.
}
status_t AudioTrack::setMarkerPosition(uint32_t marker)
@@ -757,6 +761,10 @@
mMarkerPosition = marker;
mMarkerReached = false;
+ sp<AudioTrackThread> t = mAudioTrackThread;
+ if (t != 0) {
+ t->wake();
+ }
return NO_ERROR;
}
@@ -786,6 +794,10 @@
mNewPosition = updateAndGetPosition_l() + updatePeriod;
mUpdatePeriod = updatePeriod;
+ sp<AudioTrackThread> t = mAudioTrackThread;
+ if (t != 0) {
+ t->wake();
+ }
return NO_ERROR;
}
@@ -823,12 +835,11 @@
if (mState == STATE_ACTIVE) {
return INVALID_OPERATION;
}
+ // After setting the position, use full update period before notification.
mNewPosition = updateAndGetPosition_l() + mUpdatePeriod;
- mLoopPeriod = 0;
- // FIXME Check whether loops and setting position are incompatible in old code.
- // If we use setLoop for both purposes we lose the capability to set the position while looping.
- mStaticProxy->setLoop(position, mFrameCount, 0);
+ mStaticProxy->setBufferPosition(position);
+ // Waking the AudioTrackThread is not needed as this cannot be called when active.
return NO_ERROR;
}
@@ -893,10 +904,18 @@
return INVALID_OPERATION;
}
mNewPosition = mUpdatePeriod;
- mLoopPeriod = 0;
- // FIXME The new code cannot reload while keeping a loop specified.
- // Need to check how the old code handled this, and whether it's a significant change.
- mStaticProxy->setLoop(0, mFrameCount, 0);
+ (void) updateAndGetPosition_l();
+ mPosition = 0;
+#if 0
+ // The documentation is not clear on the behavior of reload() and the restoration
+ // of loop count. Historically we have not restored loop count, start, end,
+ // but it makes sense if one desires to repeat playing a particular sound.
+ if (mLoopCount != 0) {
+ mLoopCountNotified = mLoopCount;
+ mStaticProxy->setLoop(mLoopStart, mLoopEnd, mLoopCount);
+ }
+#endif
+ mStaticProxy->setBufferPosition(0);
return NO_ERROR;
}
@@ -986,7 +1005,9 @@
// use case 1: shared buffer
(mSharedBuffer != 0) ||
// use case 2: callback transfer mode
- (mTransfer == TRANSFER_CALLBACK)) &&
+ (mTransfer == TRANSFER_CALLBACK) ||
+ // use case 3: obtain/release mode
+ (mTransfer == TRANSFER_OBTAIN)) &&
// matching sample rate
(mSampleRate == afSampleRate))) {
ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client");
@@ -998,11 +1019,9 @@
// The client's AudioTrack buffer is divided into n parts for purpose of wakeup by server, where
// n = 1 fast track with single buffering; nBuffering is ignored
// n = 2 fast track with double buffering
- // n = 2 normal track, no sample rate conversion
- // n = 3 normal track, with sample rate conversion
- // (pessimistic; some non-1:1 conversion ratios don't actually need triple-buffering)
- // n > 3 very high latency or very small notification interval; nBuffering is ignored
- const uint32_t nBuffering = (mSampleRate == afSampleRate) ? 2 : 3;
+ // n = 2 normal track, (including those with sample rate conversion)
+ // n >= 3 very high latency or very small notification interval (unused).
+ const uint32_t nBuffering = 2;
mNotificationFramesAct = mNotificationFramesReq;
@@ -1019,12 +1038,12 @@
mNotificationFramesAct = frameCount;
}
} else if (mSharedBuffer != 0) {
-
- // Ensure that buffer alignment matches channel count
- // 8-bit data in shared memory is not currently supported by AudioFlinger
- size_t alignment = audio_bytes_per_sample(
- mFormat == AUDIO_FORMAT_PCM_8_BIT ? AUDIO_FORMAT_PCM_16_BIT : mFormat);
+ // FIXME: Ensure client side memory buffers need
+ // not have additional alignment beyond sample
+ // (e.g. 16 bit stereo accessed as 32 bit frame).
+ size_t alignment = audio_bytes_per_sample(mFormat);
if (alignment & 1) {
+ // for AUDIO_FORMAT_PCM_24_BIT_PACKED (not exposed through Java).
alignment = 1;
}
if (mChannelCount > 1) {
@@ -1042,40 +1061,10 @@
// there's no frameCount parameter.
// But when initializing a shared buffer AudioTrack via set(),
// there _is_ a frameCount parameter. We silently ignore it.
- frameCount = mSharedBuffer->size() / mFrameSizeAF;
-
- } else if (!(mFlags & AUDIO_OUTPUT_FLAG_FAST)) {
-
- // FIXME move these calculations and associated checks to server
-
- // Ensure that buffer depth covers at least audio hardware latency
- uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
- ALOGV("afFrameCount=%zu, minBufCount=%d, afSampleRate=%u, afLatency=%d",
- afFrameCount, minBufCount, afSampleRate, afLatency);
- if (minBufCount <= nBuffering) {
- minBufCount = nBuffering;
- }
-
- size_t minFrameCount = afFrameCount * minBufCount * uint64_t(mSampleRate) / afSampleRate;
- ALOGV("minFrameCount: %zu, afFrameCount=%zu, minBufCount=%d, sampleRate=%u, afSampleRate=%u"
- ", afLatency=%d",
- minFrameCount, afFrameCount, minBufCount, mSampleRate, afSampleRate, afLatency);
-
- if (frameCount == 0) {
- frameCount = minFrameCount;
- } else if (frameCount < minFrameCount) {
- // not ALOGW because it happens all the time when playing key clicks over A2DP
- ALOGV("Minimum buffer size corrected from %zu to %zu",
- frameCount, minFrameCount);
- frameCount = minFrameCount;
- }
- // Make sure that application is notified with sufficient margin before underrun
- if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/nBuffering) {
- mNotificationFramesAct = frameCount/nBuffering;
- }
-
+ frameCount = mSharedBuffer->size() / mFrameSize;
} else {
- // For fast tracks, the frame count calculations and checks are done by server
+ // For fast and normal streaming tracks,
+ // the frame count calculations and checks are done by server
}
IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
@@ -1103,10 +1092,7 @@
// but we will still need the original value also
sp<IAudioTrack> track = audioFlinger->createTrack(streamType,
mSampleRate,
- // AudioFlinger only sees 16-bit PCM
- mFormat == AUDIO_FORMAT_PCM_8_BIT &&
- !(mFlags & AUDIO_OUTPUT_FLAG_DIRECT) ?
- AUDIO_FORMAT_PCM_16_BIT : mFormat,
+ mFormat,
mChannelMask,
&temp,
&trackFlags,
@@ -1138,7 +1124,7 @@
}
// invariant that mAudioTrack != 0 is true only after set() returns successfully
if (mAudioTrack != 0) {
- mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
+ IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
mDeathNotifier.clear();
}
mAudioTrack = track;
@@ -1161,23 +1147,10 @@
if (trackFlags & IAudioFlinger::TRACK_FAST) {
ALOGV("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %zu", frameCount);
mAwaitBoost = true;
- if (mSharedBuffer == 0) {
- // Theoretically double-buffering is not required for fast tracks,
- // due to tighter scheduling. But in practice, to accommodate kernels with
- // scheduling jitter, and apps with computation jitter, we use double-buffering.
- if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/nBuffering) {
- mNotificationFramesAct = frameCount/nBuffering;
- }
- }
} else {
ALOGV("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu", frameCount);
// once denied, do not request again if IAudioTrack is re-created
mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
- if (mSharedBuffer == 0) {
- if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/nBuffering) {
- mNotificationFramesAct = frameCount/nBuffering;
- }
- }
}
}
if (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
@@ -1200,6 +1173,16 @@
//return NO_INIT;
}
}
+ // Make sure that application is notified with sufficient margin before underrun
+ if (mSharedBuffer == 0 && audio_is_linear_pcm(mFormat)) {
+ // Theoretically double-buffering is not required for fast tracks,
+ // due to tighter scheduling. But in practice, to accommodate kernels with
+ // scheduling jitter, and apps with computation jitter, we use double-buffering
+ // for fast tracks just like normal streaming tracks.
+ if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount / nBuffering) {
+ mNotificationFramesAct = frameCount / nBuffering;
+ }
+ }
// We retain a copy of the I/O handle, but don't own the reference
mOutput = output;
@@ -1230,9 +1213,9 @@
// update proxy
if (mSharedBuffer == 0) {
mStaticProxy.clear();
- mProxy = new AudioTrackClientProxy(cblk, buffers, frameCount, mFrameSizeAF);
+ mProxy = new AudioTrackClientProxy(cblk, buffers, frameCount, mFrameSize);
} else {
- mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, frameCount, mFrameSizeAF);
+ mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, frameCount, mFrameSize);
mProxy = mStaticProxy;
}
@@ -1245,7 +1228,7 @@
mProxy->setMinimum(mNotificationFramesAct);
mDeathNotifier = new DeathNotifier(this);
- mAudioTrack->asBinder()->linkToDeath(mDeathNotifier, this);
+ IInterface::asBinder(mAudioTrack)->linkToDeath(mDeathNotifier, this);
return NO_ERROR;
}
@@ -1258,7 +1241,7 @@
return status;
}
-status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
+status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount, size_t *nonContig)
{
if (audioBuffer == NULL) {
return BAD_VALUE;
@@ -1285,7 +1268,7 @@
ALOGE("%s invalid waitCount %d", __func__, waitCount);
requested = NULL;
}
- return obtainBuffer(audioBuffer, requested);
+ return obtainBuffer(audioBuffer, requested, NULL /*elapsed*/, nonContig);
}
status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, const struct timespec *requested,
@@ -1352,7 +1335,7 @@
} while ((status == DEAD_OBJECT) && (tryCounter-- > 0));
audioBuffer->frameCount = buffer.mFrameCount;
- audioBuffer->size = buffer.mFrameCount * mFrameSizeAF;
+ audioBuffer->size = buffer.mFrameCount * mFrameSize;
audioBuffer->raw = buffer.mRaw;
if (nonContig != NULL) {
*nonContig = buffer.mNonContig;
@@ -1360,13 +1343,14 @@
return status;
}
-void AudioTrack::releaseBuffer(Buffer* audioBuffer)
+void AudioTrack::releaseBuffer(const Buffer* audioBuffer)
{
+ // FIXME add error checking on mode, by adding an internal version
if (mTransfer == TRANSFER_SHARED) {
return;
}
- size_t stepCount = audioBuffer->size / mFrameSizeAF;
+ size_t stepCount = audioBuffer->size / mFrameSize;
if (stepCount == 0) {
return;
}
@@ -1432,14 +1416,8 @@
}
size_t toWrite;
- if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
- // Divide capacity by 2 to take expansion into account
- toWrite = audioBuffer.size >> 1;
- memcpy_to_i16_from_u8(audioBuffer.i16, (const uint8_t *) buffer, toWrite);
- } else {
- toWrite = audioBuffer.size;
- memcpy(audioBuffer.i8, buffer, toWrite);
- }
+ toWrite = audioBuffer.size;
+ memcpy(audioBuffer.i8, buffer, toWrite);
buffer = ((const char *) buffer) + toWrite;
userSize -= toWrite;
written += toWrite;
@@ -1559,9 +1537,8 @@
// that the upper layers can recreate the track
if (!isOffloadedOrDirect_l() || (mSequence == mObservedSequence)) {
status_t status = restoreTrack_l("processAudioBuffer");
- mLock.unlock();
- // Run again immediately, but with a new IAudioTrack
- return 0;
+ // after restoration, continue below to make sure that the loop and buffer events
+ // are notified because they have been cleared from mCblk->mFlags above.
}
}
@@ -1610,7 +1587,6 @@
}
// Cache other fields that will be needed soon
- uint32_t loopPeriod = mLoopPeriod;
uint32_t sampleRate = mSampleRate;
uint32_t notificationFrames = mNotificationFramesAct;
if (mRefreshRemaining) {
@@ -1622,8 +1598,30 @@
uint32_t sequence = mSequence;
sp<AudioTrackClientProxy> proxy = mProxy;
+ // Determine the number of new loop callback(s) that will be needed, while locked.
+ int loopCountNotifications = 0;
+ uint32_t loopPeriod = 0; // time in frames for next EVENT_LOOP_END or EVENT_BUFFER_END
+
+ if (mLoopCount > 0) {
+ int loopCount;
+ size_t bufferPosition;
+ mStaticProxy->getBufferPositionAndLoopCount(&bufferPosition, &loopCount);
+ loopPeriod = ((loopCount > 0) ? mLoopEnd : mFrameCount) - bufferPosition;
+ loopCountNotifications = min(mLoopCountNotified - loopCount, kMaxLoopCountNotifications);
+ mLoopCountNotified = loopCount; // discard any excess notifications
+ } else if (mLoopCount < 0) {
+ // FIXME: We're not accurate with notification count and position with infinite looping
+ // since loopCount from server side will always return -1 (we could decrement it).
+ size_t bufferPosition = mStaticProxy->getBufferPosition();
+ loopCountNotifications = int((flags & (CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL)) != 0);
+ loopPeriod = mLoopEnd - bufferPosition;
+ } else if (/* mLoopCount == 0 && */ mSharedBuffer != 0) {
+ size_t bufferPosition = mStaticProxy->getBufferPosition();
+ loopPeriod = mFrameCount - bufferPosition;
+ }
+
// These fields don't need to be cached, because they are assigned only by set():
- // mTransfer, mCbf, mUserData, mFormat, mFrameSize, mFrameSizeAF, mFlags
+ // mTransfer, mCbf, mUserData, mFormat, mFrameSize, mFlags
// mFlags is also assigned by createTrack_l(), but not the bit we care about.
mLock.unlock();
@@ -1662,10 +1660,9 @@
if (newUnderrun) {
mCbf(EVENT_UNDERRUN, mUserData, NULL);
}
- // FIXME we will miss loops if loop cycle was signaled several times since last call
- // to processAudioBuffer()
- if (flags & (CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL)) {
+ while (loopCountNotifications > 0) {
mCbf(EVENT_LOOP_END, mUserData, NULL);
+ --loopCountNotifications;
}
if (flags & CBLK_BUFFER_END) {
mCbf(EVENT_BUFFER_END, mUserData, NULL);
@@ -1701,10 +1698,11 @@
minFrames = markerPosition - position;
}
if (loopPeriod > 0 && loopPeriod < minFrames) {
+ // loopPeriod is already adjusted for actual position.
minFrames = loopPeriod;
}
- if (updatePeriod > 0 && updatePeriod < minFrames) {
- minFrames = updatePeriod;
+ if (updatePeriod > 0) {
+ minFrames = min(minFrames, uint32_t(newPosition - position));
}
// If > 0, poll periodically to recover from a stuck server. A good value is 2.
@@ -1767,13 +1765,6 @@
}
}
- // Divide buffer size by 2 to take into account the expansion
- // due to 8 to 16 bit conversion: the callback must fill only half
- // of the destination buffer
- if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
- audioBuffer.size >>= 1;
- }
-
size_t reqSize = audioBuffer.size;
mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
size_t writtenSize = audioBuffer.size;
@@ -1793,13 +1784,7 @@
return WAIT_PERIOD_MS * 1000000LL;
}
- if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
- // 8 to 16 bit conversion, note that source and destination are the same address
- memcpy_to_i16_from_u8(audioBuffer.i16, (const uint8_t *) audioBuffer.i8, writtenSize);
- audioBuffer.size <<= 1;
- }
-
- size_t releasedFrames = audioBuffer.size / mFrameSizeAF;
+ size_t releasedFrames = audioBuffer.size / mFrameSize;
audioBuffer.frameCount = releasedFrames;
mRemainingFrames -= releasedFrames;
if (misalignment >= releasedFrames) {
@@ -1856,7 +1841,11 @@
}
// save the old static buffer position
- size_t bufferPosition = mStaticProxy != NULL ? mStaticProxy->getBufferPosition() : 0;
+ size_t bufferPosition = 0;
+ int loopCount = 0;
+ if (mStaticProxy != 0) {
+ mStaticProxy->getBufferPositionAndLoopCount(&bufferPosition, &loopCount);
+ }
// If a new IAudioTrack is successfully created, createTrack_l() will modify the
// following member variables: mAudioTrack, mCblkMemory and mCblk.
@@ -1865,30 +1854,26 @@
result = createTrack_l();
// take the frames that will be lost by track recreation into account in saved position
+ // For streaming tracks, this is the amount we obtained from the user/client
+ // (not the number actually consumed at the server - those are already lost).
(void) updateAndGetPosition_l();
- mPosition = mReleased;
+ if (mStaticProxy != 0) {
+ mPosition = mReleased;
+ }
if (result == NO_ERROR) {
- // continue playback from last known position, but
- // don't attempt to restore loop after invalidation; it's difficult and not worthwhile
- if (mStaticProxy != NULL) {
- mLoopPeriod = 0;
- mStaticProxy->setLoop(bufferPosition, mFrameCount, 0);
- }
- // FIXME How do we simulate the fact that all frames present in the buffer at the time of
- // track destruction have been played? This is critical for SoundPool implementation
- // This must be broken, and needs to be tested/debugged.
-#if 0
- // restore write index and set other indexes to reflect empty buffer status
- if (!strcmp(from, "start")) {
- // Make sure that a client relying on callback events indicating underrun or
- // the actual amount of audio frames played (e.g SoundPool) receives them.
- if (mSharedBuffer == 0) {
- // restart playback even if buffer is not completely filled.
- android_atomic_or(CBLK_FORCEREADY, &mCblk->mFlags);
+ // Continue playback from last known position and restore loop.
+ if (mStaticProxy != 0) {
+ if (loopCount != 0) {
+ mStaticProxy->setBufferPositionAndLoop(bufferPosition,
+ mLoopStart, mLoopEnd, loopCount);
+ } else {
+ mStaticProxy->setBufferPosition(bufferPosition);
+ if (bufferPosition == mFrameCount) {
+ ALOGD("restoring track at end of static buffer");
+ }
}
}
-#endif
if (mState == STATE_ACTIVE) {
result = mAudioTrack->start();
}
@@ -2148,8 +2133,8 @@
case NS_NEVER:
return false;
case NS_WHENEVER:
- // FIXME increase poll interval, or make event-driven
- ns = 1000000000LL;
+ // Event driven: call wake() when callback notifications conditions change.
+ ns = INT64_MAX;
// fall through
default:
LOG_ALWAYS_FATAL_IF(ns < 0, "processAudioBuffer() returned %" PRId64, ns);
@@ -2182,6 +2167,17 @@
}
}
+void AudioTrack::AudioTrackThread::wake()
+{
+ AutoMutex _l(mMyLock);
+ if (!mPaused && mPausedInt && mPausedNs > 0) {
+ // audio track is active and internally paused with timeout.
+ mIgnoreNextPausedInt = true;
+ mPausedInt = false;
+ mMyCond.signal();
+ }
+}
+
void AudioTrack::AudioTrackThread::pauseInternal(nsecs_t ns)
{
AutoMutex _l(mMyLock);
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index ff24475..08241e2 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -28,7 +28,21 @@
// used to clamp a value to size_t. TODO: move to another file.
template <typename T>
size_t clampToSize(T x) {
- return x > SIZE_MAX ? SIZE_MAX : x < 0 ? 0 : (size_t) x;
+ return sizeof(T) > sizeof(size_t) && x > (T) SIZE_MAX ? SIZE_MAX : x < 0 ? 0 : (size_t) x;
+}
+
+// incrementSequence is used to determine the next sequence value
+// for the loop and position sequence counters. It should return
+// a value between "other" + 1 and "other" + INT32_MAX, the choice of
+// which needs to be the "least recently used" sequence value for "self".
+// In general, this means (new_self) returned is max(self, other) + 1.
+
+static uint32_t incrementSequence(uint32_t self, uint32_t other) {
+ int32_t diff = self - other;
+ if (diff >= 0 && diff < INT32_MAX) {
+ return self + 1; // we're already ahead of other.
+ }
+ return other + 1; // we're behind, so move just ahead of other.
}
audio_track_cblk_t::audio_track_cblk_t()
@@ -485,8 +499,11 @@
StaticAudioTrackClientProxy::StaticAudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers,
size_t frameCount, size_t frameSize)
: AudioTrackClientProxy(cblk, buffers, frameCount, frameSize),
- mMutator(&cblk->u.mStatic.mSingleStateQueue), mBufferPosition(0)
+ mMutator(&cblk->u.mStatic.mSingleStateQueue),
+ mPosLoopObserver(&cblk->u.mStatic.mPosLoopQueue)
{
+ memset(&mState, 0, sizeof(mState));
+ memset(&mPosLoop, 0, sizeof(mPosLoop));
}
void StaticAudioTrackClientProxy::flush()
@@ -501,30 +518,72 @@
// FIXME Should return an error status
return;
}
- StaticAudioTrackState newState;
- newState.mLoopStart = (uint32_t) loopStart;
- newState.mLoopEnd = (uint32_t) loopEnd;
- newState.mLoopCount = loopCount;
- size_t bufferPosition;
- if (loopCount == 0 || (bufferPosition = getBufferPosition()) >= loopEnd) {
- bufferPosition = loopStart;
+ mState.mLoopStart = (uint32_t) loopStart;
+ mState.mLoopEnd = (uint32_t) loopEnd;
+ mState.mLoopCount = loopCount;
+ mState.mLoopSequence = incrementSequence(mState.mLoopSequence, mState.mPositionSequence);
+ // set patch-up variables until the mState is acknowledged by the ServerProxy.
+ // observed buffer position and loop count will freeze until then to give the
+ // illusion of a synchronous change.
+ getBufferPositionAndLoopCount(NULL, NULL);
+ // preserve behavior to restart at mState.mLoopStart if position exceeds mState.mLoopEnd.
+ if (mState.mLoopCount != 0 && mPosLoop.mBufferPosition >= mState.mLoopEnd) {
+ mPosLoop.mBufferPosition = mState.mLoopStart;
}
- mBufferPosition = bufferPosition; // snapshot buffer position until loop is acknowledged.
- (void) mMutator.push(newState);
+ mPosLoop.mLoopCount = mState.mLoopCount;
+ (void) mMutator.push(mState);
+}
+
+void StaticAudioTrackClientProxy::setBufferPosition(size_t position)
+{
+ // This can only happen on a 64-bit client
+ if (position > UINT32_MAX) {
+ // FIXME Should return an error status
+ return;
+ }
+ mState.mPosition = (uint32_t) position;
+ mState.mPositionSequence = incrementSequence(mState.mPositionSequence, mState.mLoopSequence);
+ // set patch-up variables until the mState is acknowledged by the ServerProxy.
+ // observed buffer position and loop count will freeze until then to give the
+ // illusion of a synchronous change.
+ if (mState.mLoopCount > 0) { // only check if loop count is changing
+ getBufferPositionAndLoopCount(NULL, NULL); // get last position
+ }
+ mPosLoop.mBufferPosition = position;
+ if (position >= mState.mLoopEnd) {
+ // no ongoing loop is possible if position is greater than loopEnd.
+ mPosLoop.mLoopCount = 0;
+ }
+ (void) mMutator.push(mState);
+}
+
+void StaticAudioTrackClientProxy::setBufferPositionAndLoop(size_t position, size_t loopStart,
+ size_t loopEnd, int loopCount)
+{
+ setLoop(loopStart, loopEnd, loopCount);
+ setBufferPosition(position);
}
size_t StaticAudioTrackClientProxy::getBufferPosition()
{
- size_t bufferPosition;
- if (mMutator.ack()) {
- bufferPosition = (size_t) mCblk->u.mStatic.mBufferPosition;
- if (bufferPosition > mFrameCount) {
- bufferPosition = mFrameCount;
- }
- } else {
- bufferPosition = mBufferPosition;
+ getBufferPositionAndLoopCount(NULL, NULL);
+ return mPosLoop.mBufferPosition;
+}
+
+void StaticAudioTrackClientProxy::getBufferPositionAndLoopCount(
+ size_t *position, int *loopCount)
+{
+ if (mMutator.ack() == StaticAudioTrackSingleStateQueue::SSQ_DONE) {
+ if (mPosLoopObserver.poll(mPosLoop)) {
+ ; // a valid mPosLoop should be available if ackDone is true.
+ }
}
- return bufferPosition;
+ if (position != NULL) {
+ *position = mPosLoop.mBufferPosition;
+ }
+ if (loopCount != NULL) {
+ *loopCount = mPosLoop.mLoopCount;
+ }
}
// ---------------------------------------------------------------------------
@@ -560,7 +619,8 @@
ssize_t filled = rear - newFront;
// Rather than shutting down on a corrupt flush, just treat it as a full flush
if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
- ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, filled %d=%#x",
+ ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, "
+ "filled %d=%#x",
mFlush, flush, front, rear, mask, newFront, filled, filled);
newFront = rear;
}
@@ -739,13 +799,12 @@
StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers,
size_t frameCount, size_t frameSize)
: AudioTrackServerProxy(cblk, buffers, frameCount, frameSize),
- mObserver(&cblk->u.mStatic.mSingleStateQueue), mPosition(0),
+ mObserver(&cblk->u.mStatic.mSingleStateQueue),
+ mPosLoopMutator(&cblk->u.mStatic.mPosLoopQueue),
mFramesReadySafe(frameCount), mFramesReady(frameCount),
mFramesReadyIsCalledByMultipleThreads(false)
{
- mState.mLoopStart = 0;
- mState.mLoopEnd = 0;
- mState.mLoopCount = 0;
+ memset(&mState, 0, sizeof(mState));
}
void StaticAudioTrackServerProxy::framesReadyIsCalledByMultipleThreads()
@@ -762,55 +821,97 @@
return mFramesReadySafe;
}
-ssize_t StaticAudioTrackServerProxy::pollPosition()
+status_t StaticAudioTrackServerProxy::updateStateWithLoop(
+ StaticAudioTrackState *localState, const StaticAudioTrackState &update) const
{
- size_t position = mPosition;
- StaticAudioTrackState state;
- if (mObserver.poll(state)) {
+ if (localState->mLoopSequence != update.mLoopSequence) {
bool valid = false;
- size_t loopStart = state.mLoopStart;
- size_t loopEnd = state.mLoopEnd;
- if (state.mLoopCount == 0) {
- if (loopStart > mFrameCount) {
- loopStart = mFrameCount;
- }
- // ignore loopEnd
- mPosition = position = loopStart;
- mFramesReady = mFrameCount - mPosition;
- mState.mLoopCount = 0;
+ const size_t loopStart = update.mLoopStart;
+ const size_t loopEnd = update.mLoopEnd;
+ size_t position = localState->mPosition;
+ if (update.mLoopCount == 0) {
valid = true;
- } else if (state.mLoopCount >= -1) {
+ } else if (update.mLoopCount >= -1) {
if (loopStart < loopEnd && loopEnd <= mFrameCount &&
loopEnd - loopStart >= MIN_LOOP) {
// If the current position is greater than the end of the loop
// we "wrap" to the loop start. This might cause an audible pop.
if (position >= loopEnd) {
- mPosition = position = loopStart;
+ position = loopStart;
}
- if (state.mLoopCount == -1) {
- mFramesReady = INT64_MAX;
- } else {
- // mFramesReady is 64 bits to handle the effective number of frames
- // that the static audio track contains, including loops.
- // TODO: Later consider fixing overflow, but does not seem needed now
- // as will not overflow if loopStart and loopEnd are Java "ints".
- mFramesReady = int64_t(state.mLoopCount) * (loopEnd - loopStart)
- + mFrameCount - mPosition;
- }
- mState = state;
valid = true;
}
}
- if (!valid || mPosition > mFrameCount) {
+ if (!valid || position > mFrameCount) {
+ return NO_INIT;
+ }
+ localState->mPosition = position;
+ localState->mLoopCount = update.mLoopCount;
+ localState->mLoopEnd = loopEnd;
+ localState->mLoopStart = loopStart;
+ localState->mLoopSequence = update.mLoopSequence;
+ }
+ return OK;
+}
+
+status_t StaticAudioTrackServerProxy::updateStateWithPosition(
+ StaticAudioTrackState *localState, const StaticAudioTrackState &update) const
+{
+ if (localState->mPositionSequence != update.mPositionSequence) {
+ if (update.mPosition > mFrameCount) {
+ return NO_INIT;
+ } else if (localState->mLoopCount != 0 && update.mPosition >= localState->mLoopEnd) {
+ localState->mLoopCount = 0; // disable loop count if position is beyond loop end.
+ }
+ localState->mPosition = update.mPosition;
+ localState->mPositionSequence = update.mPositionSequence;
+ }
+ return OK;
+}
+
+ssize_t StaticAudioTrackServerProxy::pollPosition()
+{
+ StaticAudioTrackState state;
+ if (mObserver.poll(state)) {
+ StaticAudioTrackState trystate = mState;
+ bool result;
+ const int32_t diffSeq = state.mLoopSequence - state.mPositionSequence;
+
+ if (diffSeq < 0) {
+ result = updateStateWithLoop(&trystate, state) == OK &&
+ updateStateWithPosition(&trystate, state) == OK;
+ } else {
+ result = updateStateWithPosition(&trystate, state) == OK &&
+ updateStateWithLoop(&trystate, state) == OK;
+ }
+ if (!result) {
+ mObserver.done();
+ // caution: no update occurs so server state will be inconsistent with client state.
ALOGE("%s client pushed an invalid state, shutting down", __func__);
mIsShutdown = true;
return (ssize_t) NO_INIT;
}
+ mState = trystate;
+ if (mState.mLoopCount == -1) {
+ mFramesReady = INT64_MAX;
+ } else if (mState.mLoopCount == 0) {
+ mFramesReady = mFrameCount - mState.mPosition;
+ } else if (mState.mLoopCount > 0) {
+ // TODO: Later consider fixing overflow, but does not seem needed now
+ // as will not overflow if loopStart and loopEnd are Java "ints".
+ mFramesReady = int64_t(mState.mLoopCount) * (mState.mLoopEnd - mState.mLoopStart)
+ + mFrameCount - mState.mPosition;
+ }
mFramesReadySafe = clampToSize(mFramesReady);
// This may overflow, but client is not supposed to rely on it
- mCblk->u.mStatic.mBufferPosition = (uint32_t) position;
+ StaticAudioTrackPosLoop posLoop;
+
+ posLoop.mLoopCount = (int32_t) mState.mLoopCount;
+ posLoop.mBufferPosition = (uint32_t) mState.mPosition;
+ mPosLoopMutator.push(posLoop);
+ mObserver.done(); // safe to read mStatic variables.
}
- return (ssize_t) position;
+ return (ssize_t) mState.mPosition;
}
status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush __unused)
@@ -849,7 +950,7 @@
}
// As mFramesReady is the total remaining frames in the static audio track,
// it is always larger or equal to avail.
- LOG_ALWAYS_FATAL_IF(mFramesReady < avail);
+ LOG_ALWAYS_FATAL_IF(mFramesReady < (int64_t) avail);
buffer->mNonContig = mFramesReady == INT64_MAX ? SIZE_MAX : clampToSize(mFramesReady - avail);
mUnreleased = avail;
return NO_ERROR;
@@ -858,7 +959,7 @@
void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer)
{
size_t stepCount = buffer->mFrameCount;
- LOG_ALWAYS_FATAL_IF(!(stepCount <= mFramesReady));
+ LOG_ALWAYS_FATAL_IF(!((int64_t) stepCount <= mFramesReady));
LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased));
if (stepCount == 0) {
// prevent accidental re-use of buffer
@@ -868,11 +969,12 @@
}
mUnreleased -= stepCount;
audio_track_cblk_t* cblk = mCblk;
- size_t position = mPosition;
+ size_t position = mState.mPosition;
size_t newPosition = position + stepCount;
int32_t setFlags = 0;
if (!(position <= newPosition && newPosition <= mFrameCount)) {
- ALOGW("%s newPosition %zu outside [%zu, %zu]", __func__, newPosition, position, mFrameCount);
+ ALOGW("%s newPosition %zu outside [%zu, %zu]", __func__, newPosition, position,
+ mFrameCount);
newPosition = mFrameCount;
} else if (mState.mLoopCount != 0 && newPosition == mState.mLoopEnd) {
newPosition = mState.mLoopStart;
@@ -885,7 +987,7 @@
if (newPosition == mFrameCount) {
setFlags |= CBLK_BUFFER_END;
}
- mPosition = newPosition;
+ mState.mPosition = newPosition;
if (mFramesReady != INT64_MAX) {
mFramesReady -= stepCount;
}
@@ -893,7 +995,10 @@
cblk->mServer += stepCount;
// This may overflow, but client is not supposed to rely on it
- cblk->u.mStatic.mBufferPosition = (uint32_t) newPosition;
+ StaticAudioTrackPosLoop posLoop;
+ posLoop.mBufferPosition = mState.mPosition;
+ posLoop.mLoopCount = mState.mLoopCount;
+ mPosLoopMutator.push(posLoop);
if (setFlags != 0) {
(void) android_atomic_or(setFlags, &cblk->mFlags);
// this would be a good place to wake a futex
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 346a192..8e3b633 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -119,7 +119,7 @@
// haveSharedBuffer
if (sharedBuffer != 0) {
data.writeInt32(true);
- data.writeStrongBinder(sharedBuffer->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(sharedBuffer));
} else {
data.writeInt32(false);
}
@@ -419,7 +419,7 @@
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeStrongBinder(client->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(client));
remote()->transact(REGISTER_CLIENT, data, &reply);
}
@@ -716,7 +716,7 @@
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.write(pDesc, sizeof(effect_descriptor_t));
- data.writeStrongBinder(client->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(client));
data.writeInt32(priority);
data.writeInt32((int32_t) output);
data.writeInt32(sessionId);
@@ -939,7 +939,7 @@
reply->writeInt32(flags);
reply->writeInt32(sessionId);
reply->writeInt32(status);
- reply->writeStrongBinder(track->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(track));
return NO_ERROR;
} break;
case OPEN_RECORD: {
@@ -966,9 +966,9 @@
reply->writeInt32(sessionId);
reply->writeInt64(notificationFrames);
reply->writeInt32(status);
- reply->writeStrongBinder(record->asBinder());
- reply->writeStrongBinder(cblk->asBinder());
- reply->writeStrongBinder(buffers->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(record));
+ reply->writeStrongBinder(IInterface::asBinder(cblk));
+ reply->writeStrongBinder(IInterface::asBinder(buffers));
return NO_ERROR;
} break;
case SAMPLE_RATE: {
@@ -1254,7 +1254,7 @@
reply->writeInt32(status);
reply->writeInt32(id);
reply->writeInt32(enabled);
- reply->writeStrongBinder(effect->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(effect));
reply->write(&desc, sizeof(effect_descriptor_t));
return NO_ERROR;
} break;
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 70551c4..f2ff27b 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -73,6 +73,8 @@
REGISTER_POLICY_MIXES,
};
+#define MAX_ITEMS_PER_LIST 1024
+
class BpAudioPolicyService : public BpInterface<IAudioPolicyService>
{
public:
@@ -84,13 +86,15 @@
virtual status_t setDeviceConnectionState(
audio_devices_t device,
audio_policy_dev_state_t state,
- const char *device_address)
+ const char *device_address,
+ const char *device_name)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
data.writeInt32(static_cast <uint32_t>(device));
data.writeInt32(static_cast <uint32_t>(state));
data.writeCString(device_address);
+ data.writeCString(device_name);
remote()->transact(SET_DEVICE_CONNECTION_STATE, data, &reply);
return static_cast <status_t> (reply.readInt32());
}
@@ -628,7 +632,7 @@
{
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
- data.writeStrongBinder(client->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(client));
remote()->transact(REGISTER_CLIENT, data, &reply);
}
@@ -726,9 +730,11 @@
audio_policy_dev_state_t state =
static_cast <audio_policy_dev_state_t>(data.readInt32());
const char *device_address = data.readCString();
+ const char *device_name = data.readCString();
reply->writeInt32(static_cast<uint32_t> (setDeviceConnectionState(device,
state,
- device_address)));
+ device_address,
+ device_name)));
return NO_ERROR;
} break;
@@ -1054,10 +1060,18 @@
audio_port_role_t role = (audio_port_role_t)data.readInt32();
audio_port_type_t type = (audio_port_type_t)data.readInt32();
unsigned int numPortsReq = data.readInt32();
+ if (numPortsReq > MAX_ITEMS_PER_LIST) {
+ numPortsReq = MAX_ITEMS_PER_LIST;
+ }
unsigned int numPorts = numPortsReq;
- unsigned int generation;
struct audio_port *ports =
(struct audio_port *)calloc(numPortsReq, sizeof(struct audio_port));
+ if (ports == NULL) {
+ reply->writeInt32(NO_MEMORY);
+ reply->writeInt32(0);
+ return NO_ERROR;
+ }
+ unsigned int generation;
status_t status = listAudioPorts(role, type, &numPorts, ports, &generation);
reply->writeInt32(status);
reply->writeInt32(numPorts);
@@ -1111,11 +1125,19 @@
case LIST_AUDIO_PATCHES: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
unsigned int numPatchesReq = data.readInt32();
+ if (numPatchesReq > MAX_ITEMS_PER_LIST) {
+ numPatchesReq = MAX_ITEMS_PER_LIST;
+ }
unsigned int numPatches = numPatchesReq;
- unsigned int generation;
struct audio_patch *patches =
(struct audio_patch *)calloc(numPatchesReq,
sizeof(struct audio_patch));
+ if (patches == NULL) {
+ reply->writeInt32(NO_MEMORY);
+ reply->writeInt32(0);
+ return NO_ERROR;
+ }
+ unsigned int generation;
status_t status = listAudioPatches(&numPatches, patches, &generation);
reply->writeInt32(status);
reply->writeInt32(numPatches);
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index 265bb1b..df209fd 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -137,7 +137,7 @@
int64_t pts) {
Parcel data, reply;
data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
- data.writeStrongBinder(buffer->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(buffer));
data.writeInt64(pts);
status_t status = remote()->transact(QUEUE_TIMED_BUFFER,
data, &reply);
@@ -207,7 +207,7 @@
switch (code) {
case GET_CBLK: {
CHECK_INTERFACE(IAudioTrack, data, reply);
- reply->writeStrongBinder(getCblk()->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(getCblk()));
return NO_ERROR;
} break;
case START: {
@@ -241,7 +241,7 @@
status_t status = allocateTimedBuffer(data.readInt64(), &buffer);
reply->writeInt32(status);
if (status == NO_ERROR) {
- reply->writeStrongBinder(buffer->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(buffer));
}
return NO_ERROR;
} break;
diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp
index 7e74de9..b08fa82 100644
--- a/media/libmedia/IDrm.cpp
+++ b/media/libmedia/IDrm.cpp
@@ -450,7 +450,7 @@
virtual status_t setListener(const sp<IDrmClient>& listener) {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
- data.writeStrongBinder(listener->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(listener));
remote()->transact(SET_LISTENER, data, &reply);
return reply.readInt32();
}
diff --git a/media/libmedia/IEffect.cpp b/media/libmedia/IEffect.cpp
index b94012a..c2fff78 100644
--- a/media/libmedia/IEffect.cpp
+++ b/media/libmedia/IEffect.cpp
@@ -190,7 +190,7 @@
case GET_CBLK: {
CHECK_INTERFACE(IEffect, data, reply);
- reply->writeStrongBinder(getCblk()->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(getCblk()));
return NO_ERROR;
} break;
diff --git a/media/libmedia/IHDCP.cpp b/media/libmedia/IHDCP.cpp
index 1cf987a..9122f75 100644
--- a/media/libmedia/IHDCP.cpp
+++ b/media/libmedia/IHDCP.cpp
@@ -65,7 +65,7 @@
virtual status_t setObserver(const sp<IHDCPObserver> &observer) {
Parcel data, reply;
data.writeInterfaceToken(IHDCP::getInterfaceDescriptor());
- data.writeStrongBinder(observer->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(observer));
remote()->transact(HDCP_SET_OBSERVER, data, &reply);
return reply.readInt32();
}
diff --git a/media/libmedia/IMediaDeathNotifier.cpp b/media/libmedia/IMediaDeathNotifier.cpp
index 10b4934..38e9ca0 100644
--- a/media/libmedia/IMediaDeathNotifier.cpp
+++ b/media/libmedia/IMediaDeathNotifier.cpp
@@ -104,7 +104,7 @@
Mutex::Autolock _l(sServiceLock);
sObitRecipients.clear();
if (sMediaPlayerService != 0) {
- sMediaPlayerService->asBinder()->unlinkToDeath(this);
+ IInterface::asBinder(sMediaPlayerService)->unlinkToDeath(this);
}
}
diff --git a/media/libmedia/IMediaLogService.cpp b/media/libmedia/IMediaLogService.cpp
index 8a66c7c..a4af7b7 100644
--- a/media/libmedia/IMediaLogService.cpp
+++ b/media/libmedia/IMediaLogService.cpp
@@ -42,7 +42,7 @@
virtual void registerWriter(const sp<IMemory>& shared, size_t size, const char *name) {
Parcel data, reply;
data.writeInterfaceToken(IMediaLogService::getInterfaceDescriptor());
- data.writeStrongBinder(shared->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(shared));
data.writeInt64((int64_t) size);
data.writeCString(name);
status_t status = remote()->transact(REGISTER_WRITER, data, &reply);
@@ -52,7 +52,7 @@
virtual void unregisterWriter(const sp<IMemory>& shared) {
Parcel data, reply;
data.writeInterfaceToken(IMediaLogService::getInterfaceDescriptor());
- data.writeStrongBinder(shared->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(shared));
status_t status = remote()->transact(UNREGISTER_WRITER, data, &reply);
// FIXME ignores status
}
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index 38f717c..aa2665a 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -95,7 +95,7 @@
data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
data.writeInt32(httpService != NULL);
if (httpService != NULL) {
- data.writeStrongBinder(httpService->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(httpService));
}
data.writeCString(srcUrl);
@@ -246,7 +246,7 @@
sp<IMemory> bitmap = getFrameAtTime(timeUs, option);
if (bitmap != 0) { // Don't send NULL across the binder interface
reply->writeInt32(NO_ERROR);
- reply->writeStrongBinder(bitmap->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(bitmap));
} else {
reply->writeInt32(UNKNOWN_ERROR);
}
@@ -263,7 +263,7 @@
sp<IMemory> albumArt = extractAlbumArt();
if (albumArt != 0) { // Don't send NULL across the binder interface
reply->writeInt32(NO_ERROR);
- reply->writeStrongBinder(albumArt->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(albumArt));
} else {
reply->writeInt32(UNKNOWN_ERROR);
}
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index d778d05..dcd5670 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -39,6 +39,7 @@
START,
STOP,
IS_PLAYING,
+ SET_PLAYBACK_RATE,
PAUSE,
SEEK_TO,
GET_CURRENT_POSITION,
@@ -85,7 +86,7 @@
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
data.writeInt32(httpService != NULL);
if (httpService != NULL) {
- data.writeStrongBinder(httpService->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(httpService));
}
data.writeCString(url);
if (headers == NULL) {
@@ -115,7 +116,7 @@
status_t setDataSource(const sp<IStreamSource> &source) {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
- data.writeStrongBinder(source->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(source));
remote()->transact(SET_DATA_SOURCE_STREAM, data, &reply);
return reply.readInt32();
}
@@ -125,7 +126,7 @@
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
- sp<IBinder> b(bufferProducer->asBinder());
+ sp<IBinder> b(IInterface::asBinder(bufferProducer));
data.writeStrongBinder(b);
remote()->transact(SET_VIDEO_SURFACETEXTURE, data, &reply);
return reply.readInt32();
@@ -164,6 +165,15 @@
return reply.readInt32();
}
+ status_t setPlaybackRate(float rate)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ data.writeFloat(rate);
+ remote()->transact(SET_PLAYBACK_RATE, data, &reply);
+ return reply.readInt32();
+ }
+
status_t pause()
{
Parcel data, reply;
@@ -323,7 +333,7 @@
status_t setNextPlayer(const sp<IMediaPlayer>& player) {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
- sp<IBinder> b(player->asBinder());
+ sp<IBinder> b(IInterface::asBinder(player));
data.writeStrongBinder(b);
remote()->transact(SET_NEXT_PLAYER, data, &reply);
return reply.readInt32();
@@ -426,6 +436,11 @@
reply->writeInt32(ret);
return NO_ERROR;
} break;
+ case SET_PLAYBACK_RATE: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(setPlaybackRate(data.readFloat()));
+ return NO_ERROR;
+ } break;
case PAUSE: {
CHECK_INTERFACE(IMediaPlayer, data, reply);
reply->writeInt32(pause());
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 2e02d17..feea267 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -39,8 +39,6 @@
enum {
CREATE = IBinder::FIRST_CALL_TRANSACTION,
- DECODE_URL,
- DECODE_FD,
CREATE_MEDIA_RECORDER,
CREATE_METADATA_RETRIEVER,
GET_OMX,
@@ -73,7 +71,7 @@
const sp<IMediaPlayerClient>& client, int audioSessionId) {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
- data.writeStrongBinder(client->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(client));
data.writeInt32(audioSessionId);
remote()->transact(CREATE, data, &reply);
@@ -88,59 +86,6 @@
return interface_cast<IMediaRecorder>(reply.readStrongBinder());
}
- virtual status_t decode(
- const sp<IMediaHTTPService> &httpService,
- const char* url,
- uint32_t *pSampleRate,
- int* pNumChannels,
- audio_format_t* pFormat,
- const sp<IMemoryHeap>& heap,
- size_t *pSize)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
- data.writeInt32(httpService != NULL);
- if (httpService != NULL) {
- data.writeStrongBinder(httpService->asBinder());
- }
- data.writeCString(url);
- data.writeStrongBinder(heap->asBinder());
- status_t status = remote()->transact(DECODE_URL, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- if (status == NO_ERROR) {
- *pSampleRate = uint32_t(reply.readInt32());
- *pNumChannels = reply.readInt32();
- *pFormat = (audio_format_t)reply.readInt32();
- *pSize = (size_t)reply.readInt32();
- }
- }
- return status;
- }
-
- virtual status_t decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate,
- int* pNumChannels, audio_format_t* pFormat,
- const sp<IMemoryHeap>& heap, size_t *pSize)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
- data.writeFileDescriptor(fd);
- data.writeInt64(offset);
- data.writeInt64(length);
- data.writeStrongBinder(heap->asBinder());
- status_t status = remote()->transact(DECODE_FD, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- if (status == NO_ERROR) {
- *pSampleRate = uint32_t(reply.readInt32());
- *pNumChannels = reply.readInt32();
- *pFormat = (audio_format_t)reply.readInt32();
- *pSize = (size_t)reply.readInt32();
- }
- }
- return status;
- }
-
virtual sp<IOMX> getOMX() {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
@@ -188,7 +133,7 @@
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
- data.writeStrongBinder(client->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(client));
data.writeString8(iface);
remote()->transact(LISTEN_FOR_REMOTE_DISPLAY, data, &reply);
return interface_cast<IRemoteDisplay>(reply.readStrongBinder());
@@ -216,95 +161,44 @@
interface_cast<IMediaPlayerClient>(data.readStrongBinder());
int audioSessionId = data.readInt32();
sp<IMediaPlayer> player = create(client, audioSessionId);
- reply->writeStrongBinder(player->asBinder());
- return NO_ERROR;
- } break;
- case DECODE_URL: {
- CHECK_INTERFACE(IMediaPlayerService, data, reply);
- sp<IMediaHTTPService> httpService;
- if (data.readInt32()) {
- httpService =
- interface_cast<IMediaHTTPService>(data.readStrongBinder());
- }
- const char* url = data.readCString();
- sp<IMemoryHeap> heap = interface_cast<IMemoryHeap>(data.readStrongBinder());
- uint32_t sampleRate;
- int numChannels;
- audio_format_t format;
- size_t size;
- status_t status =
- decode(httpService,
- url,
- &sampleRate,
- &numChannels,
- &format,
- heap,
- &size);
- reply->writeInt32(status);
- if (status == NO_ERROR) {
- reply->writeInt32(sampleRate);
- reply->writeInt32(numChannels);
- reply->writeInt32((int32_t)format);
- reply->writeInt32((int32_t)size);
- }
- return NO_ERROR;
- } break;
- case DECODE_FD: {
- CHECK_INTERFACE(IMediaPlayerService, data, reply);
- int fd = dup(data.readFileDescriptor());
- int64_t offset = data.readInt64();
- int64_t length = data.readInt64();
- sp<IMemoryHeap> heap = interface_cast<IMemoryHeap>(data.readStrongBinder());
- uint32_t sampleRate;
- int numChannels;
- audio_format_t format;
- size_t size;
- status_t status = decode(fd, offset, length, &sampleRate, &numChannels, &format,
- heap, &size);
- reply->writeInt32(status);
- if (status == NO_ERROR) {
- reply->writeInt32(sampleRate);
- reply->writeInt32(numChannels);
- reply->writeInt32((int32_t)format);
- reply->writeInt32((int32_t)size);
- }
+ reply->writeStrongBinder(IInterface::asBinder(player));
return NO_ERROR;
} break;
case CREATE_MEDIA_RECORDER: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
sp<IMediaRecorder> recorder = createMediaRecorder();
- reply->writeStrongBinder(recorder->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(recorder));
return NO_ERROR;
} break;
case CREATE_METADATA_RETRIEVER: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
sp<IMediaMetadataRetriever> retriever = createMetadataRetriever();
- reply->writeStrongBinder(retriever->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(retriever));
return NO_ERROR;
} break;
case GET_OMX: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
sp<IOMX> omx = getOMX();
- reply->writeStrongBinder(omx->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(omx));
return NO_ERROR;
} break;
case MAKE_CRYPTO: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
sp<ICrypto> crypto = makeCrypto();
- reply->writeStrongBinder(crypto->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(crypto));
return NO_ERROR;
} break;
case MAKE_DRM: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
sp<IDrm> drm = makeDrm();
- reply->writeStrongBinder(drm->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(drm));
return NO_ERROR;
} break;
case MAKE_HDCP: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
bool createEncryptionModule = data.readInt32();
sp<IHDCP> hdcp = makeHDCP(createEncryptionModule);
- reply->writeStrongBinder(hdcp->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(hdcp));
return NO_ERROR;
} break;
case ADD_BATTERY_DATA: {
@@ -324,13 +218,13 @@
interface_cast<IRemoteDisplayClient>(data.readStrongBinder()));
String8 iface(data.readString8());
sp<IRemoteDisplay> display(listenForRemoteDisplay(client, iface));
- reply->writeStrongBinder(display->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(display));
return NO_ERROR;
} break;
case GET_CODEC_LIST: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
sp<IMediaCodecList> mcl = getCodecList();
- reply->writeStrongBinder(mcl->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(mcl));
return NO_ERROR;
} break;
default:
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 95af006..9181f86 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -46,7 +46,6 @@
SET_OUTPUT_FORMAT,
SET_VIDEO_ENCODER,
SET_AUDIO_ENCODER,
- SET_OUTPUT_FILE_PATH,
SET_OUTPUT_FILE_FD,
SET_VIDEO_SIZE,
SET_VIDEO_FRAMERATE,
@@ -70,8 +69,8 @@
ALOGV("setCamera(%p,%p)", camera.get(), proxy.get());
Parcel data, reply;
data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
- data.writeStrongBinder(camera->asBinder());
- data.writeStrongBinder(proxy->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(camera));
+ data.writeStrongBinder(IInterface::asBinder(proxy));
remote()->transact(SET_CAMERA, data, &reply);
return reply.readInt32();
}
@@ -94,7 +93,7 @@
ALOGV("setPreviewSurface(%p)", surface.get());
Parcel data, reply;
data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
- data.writeStrongBinder(surface->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(surface));
remote()->transact(SET_PREVIEW_SURFACE, data, &reply);
return reply.readInt32();
}
@@ -158,16 +157,6 @@
return reply.readInt32();
}
- status_t setOutputFile(const char* path)
- {
- ALOGV("setOutputFile(%s)", path);
- Parcel data, reply;
- data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
- data.writeCString(path);
- remote()->transact(SET_OUTPUT_FILE_PATH, data, &reply);
- return reply.readInt32();
- }
-
status_t setOutputFile(int fd, int64_t offset, int64_t length) {
ALOGV("setOutputFile(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
Parcel data, reply;
@@ -215,7 +204,7 @@
ALOGV("setListener(%p)", listener.get());
Parcel data, reply;
data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
- data.writeStrongBinder(listener->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(listener));
remote()->transact(SET_LISTENER, data, &reply);
return reply.readInt32();
}
@@ -300,7 +289,8 @@
// ----------------------------------------------------------------------
status_t BnMediaRecorder::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+ uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags)
{
switch (code) {
case RELEASE: {
@@ -390,13 +380,6 @@
return NO_ERROR;
} break;
- case SET_OUTPUT_FILE_PATH: {
- ALOGV("SET_OUTPUT_FILE_PATH");
- CHECK_INTERFACE(IMediaRecorder, data, reply);
- const char* path = data.readCString();
- reply->writeInt32(setOutputFile(path));
- return NO_ERROR;
- } break;
case SET_OUTPUT_FILE_FD: {
ALOGV("SET_OUTPUT_FILE_FD");
CHECK_INTERFACE(IMediaRecorder, data, reply);
@@ -445,7 +428,8 @@
case SET_PREVIEW_SURFACE: {
ALOGV("SET_PREVIEW_SURFACE");
CHECK_INTERFACE(IMediaRecorder, data, reply);
- sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
+ sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>(
+ data.readStrongBinder());
reply->writeInt32(setPreviewSurface(surface));
return NO_ERROR;
} break;
@@ -468,7 +452,7 @@
int returnedNull= (surfaceMediaSource == NULL) ? 1 : 0 ;
reply->writeInt32(returnedNull);
if (!returnedNull) {
- reply->writeStrongBinder(surfaceMediaSource->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(surfaceMediaSource));
}
return NO_ERROR;
} break;
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index c583d32..e208df9 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -100,7 +100,7 @@
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
data.writeCString(name);
- data.writeStrongBinder(observer->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(observer));
remote()->transact(ALLOCATE_NODE, data, &reply);
status_t err = reply.readInt32();
@@ -248,7 +248,7 @@
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
data.writeInt32((int32_t)node);
data.writeInt32(port_index);
- data.writeStrongBinder(params->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(params));
remote()->transact(USE_BUFFER, data, &reply);
status_t err = reply.readInt32();
@@ -418,7 +418,7 @@
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
data.writeInt32((int32_t)node);
data.writeInt32(port_index);
- data.writeStrongBinder(params->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(params));
remote()->transact(ALLOC_BUFFER_WITH_BACKUP, data, &reply);
status_t err = reply.readInt32();
@@ -775,7 +775,7 @@
reply->writeInt32(err);
if (err == OK) {
- reply->writeStrongBinder(bufferProducer->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(bufferProducer));
}
return NO_ERROR;
diff --git a/media/libmedia/IRemoteDisplayClient.cpp b/media/libmedia/IRemoteDisplayClient.cpp
index 7190879..9d63bc9 100644
--- a/media/libmedia/IRemoteDisplayClient.cpp
+++ b/media/libmedia/IRemoteDisplayClient.cpp
@@ -42,7 +42,7 @@
{
Parcel data, reply;
data.writeInterfaceToken(IRemoteDisplayClient::getInterfaceDescriptor());
- data.writeStrongBinder(bufferProducer->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(bufferProducer));
data.writeInt32(width);
data.writeInt32(height);
data.writeInt32(flags);
diff --git a/media/libmedia/IStreamSource.cpp b/media/libmedia/IStreamSource.cpp
index fe2cc61..d480aef 100644
--- a/media/libmedia/IStreamSource.cpp
+++ b/media/libmedia/IStreamSource.cpp
@@ -55,7 +55,7 @@
virtual void setListener(const sp<IStreamListener> &listener) {
Parcel data, reply;
data.writeInterfaceToken(IStreamSource::getInterfaceDescriptor());
- data.writeStrongBinder(listener->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(listener));
remote()->transact(SET_LISTENER, data, &reply);
}
@@ -64,7 +64,7 @@
data.writeInterfaceToken(IStreamSource::getInterfaceDescriptor());
data.writeInt64(static_cast<int64_t>(buffers.size()));
for (size_t i = 0; i < buffers.size(); ++i) {
- data.writeStrongBinder(buffers.itemAt(i)->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(buffers.itemAt(i)));
}
remote()->transact(SET_BUFFERS, data, &reply);
}
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index f0f1832..271be0c 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -36,7 +36,6 @@
mPaused(false),
mMaxTracks(maxTracks),
mEasData(NULL),
- mEasJetFileLoc(NULL),
mTrackBufferSize(trackBufferSize)
{
ALOGV("JetPlayer constructor");
@@ -133,10 +132,7 @@
JET_Shutdown(mEasData);
EAS_Shutdown(mEasData);
}
- if (mEasJetFileLoc) {
- free(mEasJetFileLoc);
- mEasJetFileLoc = NULL;
- }
+ mIoWrapper.clear();
if (mAudioTrack != 0) {
mAudioTrack->stop();
mAudioTrack->flush();
@@ -327,16 +323,9 @@
Mutex::Autolock lock(mMutex);
- mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
- strncpy(mJetFilePath, path, sizeof(mJetFilePath));
- mJetFilePath[sizeof(mJetFilePath) - 1] = '\0';
- mEasJetFileLoc->path = mJetFilePath;
+ mIoWrapper = new MidiIoWrapper(path);
- mEasJetFileLoc->fd = 0;
- mEasJetFileLoc->length = 0;
- mEasJetFileLoc->offset = 0;
-
- EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
+ EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
if (result != EAS_SUCCESS)
mState = EAS_STATE_ERROR;
else
@@ -352,13 +341,9 @@
Mutex::Autolock lock(mMutex);
- mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
- mEasJetFileLoc->fd = fd;
- mEasJetFileLoc->offset = offset;
- mEasJetFileLoc->length = length;
- mEasJetFileLoc->path = NULL;
+ mIoWrapper = new MidiIoWrapper(fd, offset, length);
- EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
+ EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
if (result != EAS_SUCCESS)
mState = EAS_STATE_ERROR;
else
@@ -423,7 +408,8 @@
ALOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d",
segmentNum, libNum, repeatCount, transpose);
Mutex::Autolock lock(mMutex);
- return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
+ return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags,
+ userID);
}
//-------------------------------------------------------------------------------------------------
@@ -459,13 +445,13 @@
//-------------------------------------------------------------------------------------------------
void JetPlayer::dump()
{
- ALOGE("JetPlayer dump: JET file=%s", mEasJetFileLoc->path);
}
void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
{
if (pJetStatus!=NULL)
- ALOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d paused=%d",
+ ALOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d "
+ "paused=%d",
pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
pJetStatus->numQueuedSegments, pJetStatus->paused);
else
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index e2e6042..47f9258 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -163,7 +163,8 @@
}
/*static*/ int
-MediaProfiles::findTagForName(const MediaProfiles::NameToTagMap *map, size_t nMappings, const char *name)
+MediaProfiles::findTagForName(const MediaProfiles::NameToTagMap *map, size_t nMappings,
+ const char *name)
{
int tag = -1;
for (size_t i = 0; i < nMappings; ++i) {
@@ -295,9 +296,8 @@
CHECK(codec != -1);
MediaProfiles::AudioEncoderCap *cap =
- new MediaProfiles::AudioEncoderCap(static_cast<audio_encoder>(codec), atoi(atts[5]), atoi(atts[7]),
- atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
- atoi(atts[15]));
+ new MediaProfiles::AudioEncoderCap(static_cast<audio_encoder>(codec), atoi(atts[5]),
+ atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]), atoi(atts[15]));
logAudioEncoderCap(*cap);
return cap;
}
@@ -330,7 +330,8 @@
!strcmp("fileFormat", atts[2]) &&
!strcmp("duration", atts[4]));
- const size_t nProfileMappings = sizeof(sCamcorderQualityNameMap)/sizeof(sCamcorderQualityNameMap[0]);
+ const size_t nProfileMappings = sizeof(sCamcorderQualityNameMap)/
+ sizeof(sCamcorderQualityNameMap[0]);
const int quality = findTagForName(sCamcorderQualityNameMap, nProfileMappings, atts[1]);
CHECK(quality != -1);
@@ -722,16 +723,20 @@
MediaProfiles::createDefaultCamcorderTimeLapseLowProfiles(
MediaProfiles::CamcorderProfile **lowTimeLapseProfile,
MediaProfiles::CamcorderProfile **lowSpecificTimeLapseProfile) {
- *lowTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(CAMCORDER_QUALITY_TIME_LAPSE_LOW);
- *lowSpecificTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(CAMCORDER_QUALITY_TIME_LAPSE_QCIF);
+ *lowTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(
+ CAMCORDER_QUALITY_TIME_LAPSE_LOW);
+ *lowSpecificTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(
+ CAMCORDER_QUALITY_TIME_LAPSE_QCIF);
}
/*static*/ void
MediaProfiles::createDefaultCamcorderTimeLapseHighProfiles(
MediaProfiles::CamcorderProfile **highTimeLapseProfile,
MediaProfiles::CamcorderProfile **highSpecificTimeLapseProfile) {
- *highTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(CAMCORDER_QUALITY_TIME_LAPSE_HIGH);
- *highSpecificTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(CAMCORDER_QUALITY_TIME_LAPSE_480P);
+ *highTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(
+ CAMCORDER_QUALITY_TIME_LAPSE_HIGH);
+ *highSpecificTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(
+ CAMCORDER_QUALITY_TIME_LAPSE_480P);
}
/*static*/ MediaProfiles::CamcorderProfile*
@@ -809,7 +814,8 @@
// high camcorder time lapse profiles.
MediaProfiles::CamcorderProfile *highTimeLapseProfile, *highSpecificTimeLapseProfile;
- createDefaultCamcorderTimeLapseHighProfiles(&highTimeLapseProfile, &highSpecificTimeLapseProfile);
+ createDefaultCamcorderTimeLapseHighProfiles(&highTimeLapseProfile,
+ &highSpecificTimeLapseProfile);
profiles->mCamcorderProfiles.add(highTimeLapseProfile);
profiles->mCamcorderProfiles.add(highSpecificTimeLapseProfile);
diff --git a/media/libmedia/MemoryLeakTrackUtil.cpp b/media/libmedia/MemoryLeakTrackUtil.cpp
index 66f7161..d31f721 100644
--- a/media/libmedia/MemoryLeakTrackUtil.cpp
+++ b/media/libmedia/MemoryLeakTrackUtil.cpp
@@ -18,6 +18,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/types.h>
#include <unistd.h>
diff --git a/media/libmedia/MidiIoWrapper.cpp b/media/libmedia/MidiIoWrapper.cpp
new file mode 100644
index 0000000..5197ce2
--- /dev/null
+++ b/media/libmedia/MidiIoWrapper.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MidiIoWrapper"
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "media/MidiIoWrapper.h"
+
+static int readAt(void *handle, void *buffer, int pos, int size) {
+ return ((android::MidiIoWrapper*)handle)->readAt(buffer, pos, size);
+}
+static int size(void *handle) {
+ return ((android::MidiIoWrapper*)handle)->size();
+}
+
+namespace android {
+
+MidiIoWrapper::MidiIoWrapper(const char *path) {
+ ALOGV("MidiIoWrapper(%s)", path);
+ mFd = open(path, O_RDONLY | O_LARGEFILE);
+ mBase = 0;
+ mLength = lseek(mFd, 0, SEEK_END);
+}
+
+MidiIoWrapper::MidiIoWrapper(int fd, off64_t offset, int64_t size) {
+ ALOGV("MidiIoWrapper(fd=%d)", fd);
+ mFd = dup(fd);
+ mBase = offset;
+ mLength = size;
+}
+
+MidiIoWrapper::MidiIoWrapper(const sp<DataSource> &source) {
+ ALOGV("MidiIoWrapper(DataSource)");
+ mFd = -1;
+ mDataSource = source;
+ off64_t l;
+ if (mDataSource->getSize(&l) == OK) {
+ mLength = l;
+ } else {
+ mLength = 0;
+ }
+}
+
+MidiIoWrapper::~MidiIoWrapper() {
+ ALOGV("~MidiIoWrapper");
+ close(mFd);
+}
+
+int MidiIoWrapper::readAt(void *buffer, int offset, int size) {
+ ALOGV("readAt(%p, %d, %d)", buffer, offset, size);
+
+ if (mDataSource != NULL) {
+ return mDataSource->readAt(offset, buffer, size);
+ }
+ lseek(mFd, mBase + offset, SEEK_SET);
+ if (offset + size > mLength) {
+ size = mLength - offset;
+ }
+ return read(mFd, buffer, size);
+}
+
+int MidiIoWrapper::size() {
+ ALOGV("size() = %d", int(mLength));
+ return mLength;
+}
+
+EAS_FILE_LOCATOR MidiIoWrapper::getLocator() {
+ mEasFile.handle = this;
+ mEasFile.readAt = ::readAt;
+ mEasFile.size = ::size;
+ return &mEasFile;
+}
+
+} // namespace android
diff --git a/media/libmedia/SingleStateQueue.cpp b/media/libmedia/SingleStateQueue.cpp
deleted file mode 100644
index 3503baa..0000000
--- a/media/libmedia/SingleStateQueue.cpp
+++ /dev/null
@@ -1,107 +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.
- */
-
-#include <new>
-#include <cutils/atomic.h>
-#include <cutils/atomic-inline.h> // for android_memory_barrier()
-#include <media/SingleStateQueue.h>
-
-namespace android {
-
-template<typename T> SingleStateQueue<T>::Mutator::Mutator(Shared *shared)
- : mSequence(0), mShared((Shared *) shared)
-{
- // exactly one of Mutator and Observer must initialize, currently it is Observer
- //shared->init();
-}
-
-template<typename T> int32_t SingleStateQueue<T>::Mutator::push(const T& value)
-{
- Shared *shared = mShared;
- int32_t sequence = mSequence;
- sequence++;
- android_atomic_acquire_store(sequence, &shared->mSequence);
- shared->mValue = value;
- sequence++;
- android_atomic_release_store(sequence, &shared->mSequence);
- mSequence = sequence;
- // consider signalling a futex here, if we know that observer is waiting
- return sequence;
-}
-
-template<typename T> bool SingleStateQueue<T>::Mutator::ack()
-{
- return mShared->mAck - mSequence == 0;
-}
-
-template<typename T> bool SingleStateQueue<T>::Mutator::ack(int32_t sequence)
-{
- // this relies on 2's complement rollover to detect an ancient sequence number
- return mShared->mAck - sequence >= 0;
-}
-
-template<typename T> SingleStateQueue<T>::Observer::Observer(Shared *shared)
- : mSequence(0), mSeed(1), mShared((Shared *) shared)
-{
- // exactly one of Mutator and Observer must initialize, currently it is Observer
- shared->init();
-}
-
-template<typename T> bool SingleStateQueue<T>::Observer::poll(T& value)
-{
- Shared *shared = mShared;
- int32_t before = shared->mSequence;
- if (before == mSequence) {
- return false;
- }
- for (int tries = 0; ; ) {
- const int MAX_TRIES = 5;
- if (before & 1) {
- if (++tries >= MAX_TRIES) {
- return false;
- }
- before = shared->mSequence;
- } else {
- android_memory_barrier();
- T temp = shared->mValue;
- int32_t after = android_atomic_release_load(&shared->mSequence);
- if (after == before) {
- value = temp;
- shared->mAck = before;
- mSequence = before;
- return true;
- }
- if (++tries >= MAX_TRIES) {
- return false;
- }
- before = after;
- }
- }
-}
-
-#if 0
-template<typename T> SingleStateQueue<T>::SingleStateQueue(void /*Shared*/ *shared)
-{
- ((Shared *) shared)->init();
-}
-#endif
-
-} // namespace android
-
-// hack for gcc
-#ifdef SINGLE_STATE_QUEUE_INSTANTIATIONS
-#include SINGLE_STATE_QUEUE_INSTANTIATIONS
-#endif
diff --git a/media/libmedia/SingleStateQueueInstantiations.cpp b/media/libmedia/SingleStateQueueInstantiations.cpp
deleted file mode 100644
index 0265c8c..0000000
--- a/media/libmedia/SingleStateQueueInstantiations.cpp
+++ /dev/null
@@ -1,28 +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.
- */
-
-#include <media/SingleStateQueue.h>
-#include <private/media/StaticAudioTrackState.h>
-#include <media/AudioTimestamp.h>
-
-// FIXME hack for gcc
-
-namespace android {
-
-template class SingleStateQueue<StaticAudioTrackState>; // typedef StaticAudioTrackSingleStateQueue
-template class SingleStateQueue<AudioTimestamp>; // typedef AudioTimestampSingleStateQueue
-
-}
diff --git a/media/libmedia/SoundPool.cpp b/media/libmedia/SoundPool.cpp
deleted file mode 100644
index d2e381b..0000000
--- a/media/libmedia/SoundPool.cpp
+++ /dev/null
@@ -1,921 +0,0 @@
-/*
- * Copyright (C) 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_NDEBUG 0
-#define LOG_TAG "SoundPool"
-
-#include <inttypes.h>
-
-#include <utils/Log.h>
-
-#define USE_SHARED_MEM_BUFFER
-
-#include <media/AudioTrack.h>
-#include <media/IMediaHTTPService.h>
-#include <media/mediaplayer.h>
-#include <media/SoundPool.h>
-#include "SoundPoolThread.h"
-#include <media/AudioPolicyHelper.h>
-
-namespace android
-{
-
-int kDefaultBufferCount = 4;
-uint32_t kMaxSampleRate = 48000;
-uint32_t kDefaultSampleRate = 44100;
-uint32_t kDefaultFrameCount = 1200;
-size_t kDefaultHeapSize = 1024 * 1024; // 1MB
-
-
-SoundPool::SoundPool(int maxChannels, const audio_attributes_t* pAttributes)
-{
- ALOGV("SoundPool constructor: maxChannels=%d, attr.usage=%d, attr.flags=0x%x, attr.tags=%s",
- maxChannels, pAttributes->usage, pAttributes->flags, pAttributes->tags);
-
- // check limits
- mMaxChannels = maxChannels;
- if (mMaxChannels < 1) {
- mMaxChannels = 1;
- }
- else if (mMaxChannels > 32) {
- mMaxChannels = 32;
- }
- ALOGW_IF(maxChannels != mMaxChannels, "App requested %d channels", maxChannels);
-
- mQuit = false;
- mDecodeThread = 0;
- memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t));
- mAllocated = 0;
- mNextSampleID = 0;
- mNextChannelID = 0;
-
- mCallback = 0;
- mUserData = 0;
-
- mChannelPool = new SoundChannel[mMaxChannels];
- for (int i = 0; i < mMaxChannels; ++i) {
- mChannelPool[i].init(this);
- mChannels.push_back(&mChannelPool[i]);
- }
-
- // start decode thread
- startThreads();
-}
-
-SoundPool::~SoundPool()
-{
- ALOGV("SoundPool destructor");
- mDecodeThread->quit();
- quit();
-
- Mutex::Autolock lock(&mLock);
-
- mChannels.clear();
- if (mChannelPool)
- delete [] mChannelPool;
- // clean up samples
- ALOGV("clear samples");
- mSamples.clear();
-
- if (mDecodeThread)
- delete mDecodeThread;
-}
-
-void SoundPool::addToRestartList(SoundChannel* channel)
-{
- Mutex::Autolock lock(&mRestartLock);
- if (!mQuit) {
- mRestart.push_back(channel);
- mCondition.signal();
- }
-}
-
-void SoundPool::addToStopList(SoundChannel* channel)
-{
- Mutex::Autolock lock(&mRestartLock);
- if (!mQuit) {
- mStop.push_back(channel);
- mCondition.signal();
- }
-}
-
-int SoundPool::beginThread(void* arg)
-{
- SoundPool* p = (SoundPool*)arg;
- return p->run();
-}
-
-int SoundPool::run()
-{
- mRestartLock.lock();
- while (!mQuit) {
- mCondition.wait(mRestartLock);
- ALOGV("awake");
- if (mQuit) break;
-
- while (!mStop.empty()) {
- SoundChannel* channel;
- ALOGV("Getting channel from stop list");
- List<SoundChannel* >::iterator iter = mStop.begin();
- channel = *iter;
- mStop.erase(iter);
- mRestartLock.unlock();
- if (channel != 0) {
- Mutex::Autolock lock(&mLock);
- channel->stop();
- }
- mRestartLock.lock();
- if (mQuit) break;
- }
-
- while (!mRestart.empty()) {
- SoundChannel* channel;
- ALOGV("Getting channel from list");
- List<SoundChannel*>::iterator iter = mRestart.begin();
- channel = *iter;
- mRestart.erase(iter);
- mRestartLock.unlock();
- if (channel != 0) {
- Mutex::Autolock lock(&mLock);
- channel->nextEvent();
- }
- mRestartLock.lock();
- if (mQuit) break;
- }
- }
-
- mStop.clear();
- mRestart.clear();
- mCondition.signal();
- mRestartLock.unlock();
- ALOGV("goodbye");
- return 0;
-}
-
-void SoundPool::quit()
-{
- mRestartLock.lock();
- mQuit = true;
- mCondition.signal();
- mCondition.wait(mRestartLock);
- ALOGV("return from quit");
- mRestartLock.unlock();
-}
-
-bool SoundPool::startThreads()
-{
- createThreadEtc(beginThread, this, "SoundPool");
- if (mDecodeThread == NULL)
- mDecodeThread = new SoundPoolThread(this);
- return mDecodeThread != NULL;
-}
-
-SoundChannel* SoundPool::findChannel(int channelID)
-{
- for (int i = 0; i < mMaxChannels; ++i) {
- if (mChannelPool[i].channelID() == channelID) {
- return &mChannelPool[i];
- }
- }
- return NULL;
-}
-
-SoundChannel* SoundPool::findNextChannel(int channelID)
-{
- for (int i = 0; i < mMaxChannels; ++i) {
- if (mChannelPool[i].nextChannelID() == channelID) {
- return &mChannelPool[i];
- }
- }
- return NULL;
-}
-
-int SoundPool::load(const char* path, int priority __unused)
-{
- ALOGV("load: path=%s, priority=%d", path, priority);
- Mutex::Autolock lock(&mLock);
- sp<Sample> sample = new Sample(++mNextSampleID, path);
- mSamples.add(sample->sampleID(), sample);
- doLoad(sample);
- return sample->sampleID();
-}
-
-int SoundPool::load(int fd, int64_t offset, int64_t length, int priority __unused)
-{
- ALOGV("load: fd=%d, offset=%" PRId64 ", length=%" PRId64 ", priority=%d",
- fd, offset, length, priority);
- Mutex::Autolock lock(&mLock);
- sp<Sample> sample = new Sample(++mNextSampleID, fd, offset, length);
- mSamples.add(sample->sampleID(), sample);
- doLoad(sample);
- return sample->sampleID();
-}
-
-void SoundPool::doLoad(sp<Sample>& sample)
-{
- ALOGV("doLoad: loading sample sampleID=%d", sample->sampleID());
- sample->startLoad();
- mDecodeThread->loadSample(sample->sampleID());
-}
-
-bool SoundPool::unload(int sampleID)
-{
- ALOGV("unload: sampleID=%d", sampleID);
- Mutex::Autolock lock(&mLock);
- return mSamples.removeItem(sampleID);
-}
-
-int SoundPool::play(int sampleID, float leftVolume, float rightVolume,
- int priority, int loop, float rate)
-{
- ALOGV("play sampleID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f",
- sampleID, leftVolume, rightVolume, priority, loop, rate);
- sp<Sample> sample;
- SoundChannel* channel;
- int channelID;
-
- Mutex::Autolock lock(&mLock);
-
- if (mQuit) {
- return 0;
- }
- // is sample ready?
- sample = findSample(sampleID);
- if ((sample == 0) || (sample->state() != Sample::READY)) {
- ALOGW(" sample %d not READY", sampleID);
- return 0;
- }
-
- dump();
-
- // allocate a channel
- channel = allocateChannel_l(priority);
-
- // no channel allocated - return 0
- if (!channel) {
- ALOGV("No channel allocated");
- return 0;
- }
-
- channelID = ++mNextChannelID;
-
- ALOGV("play channel %p state = %d", channel, channel->state());
- channel->play(sample, channelID, leftVolume, rightVolume, priority, loop, rate);
- return channelID;
-}
-
-SoundChannel* SoundPool::allocateChannel_l(int priority)
-{
- List<SoundChannel*>::iterator iter;
- SoundChannel* channel = NULL;
-
- // allocate a channel
- if (!mChannels.empty()) {
- iter = mChannels.begin();
- if (priority >= (*iter)->priority()) {
- channel = *iter;
- mChannels.erase(iter);
- ALOGV("Allocated active channel");
- }
- }
-
- // update priority and put it back in the list
- if (channel) {
- channel->setPriority(priority);
- for (iter = mChannels.begin(); iter != mChannels.end(); ++iter) {
- if (priority < (*iter)->priority()) {
- break;
- }
- }
- mChannels.insert(iter, channel);
- }
- return channel;
-}
-
-// move a channel from its current position to the front of the list
-void SoundPool::moveToFront_l(SoundChannel* channel)
-{
- for (List<SoundChannel*>::iterator iter = mChannels.begin(); iter != mChannels.end(); ++iter) {
- if (*iter == channel) {
- mChannels.erase(iter);
- mChannels.push_front(channel);
- break;
- }
- }
-}
-
-void SoundPool::pause(int channelID)
-{
- ALOGV("pause(%d)", channelID);
- Mutex::Autolock lock(&mLock);
- SoundChannel* channel = findChannel(channelID);
- if (channel) {
- channel->pause();
- }
-}
-
-void SoundPool::autoPause()
-{
- ALOGV("autoPause()");
- Mutex::Autolock lock(&mLock);
- for (int i = 0; i < mMaxChannels; ++i) {
- SoundChannel* channel = &mChannelPool[i];
- channel->autoPause();
- }
-}
-
-void SoundPool::resume(int channelID)
-{
- ALOGV("resume(%d)", channelID);
- Mutex::Autolock lock(&mLock);
- SoundChannel* channel = findChannel(channelID);
- if (channel) {
- channel->resume();
- }
-}
-
-void SoundPool::autoResume()
-{
- ALOGV("autoResume()");
- Mutex::Autolock lock(&mLock);
- for (int i = 0; i < mMaxChannels; ++i) {
- SoundChannel* channel = &mChannelPool[i];
- channel->autoResume();
- }
-}
-
-void SoundPool::stop(int channelID)
-{
- ALOGV("stop(%d)", channelID);
- Mutex::Autolock lock(&mLock);
- SoundChannel* channel = findChannel(channelID);
- if (channel) {
- channel->stop();
- } else {
- channel = findNextChannel(channelID);
- if (channel)
- channel->clearNextEvent();
- }
-}
-
-void SoundPool::setVolume(int channelID, float leftVolume, float rightVolume)
-{
- Mutex::Autolock lock(&mLock);
- SoundChannel* channel = findChannel(channelID);
- if (channel) {
- channel->setVolume(leftVolume, rightVolume);
- }
-}
-
-void SoundPool::setPriority(int channelID, int priority)
-{
- ALOGV("setPriority(%d, %d)", channelID, priority);
- Mutex::Autolock lock(&mLock);
- SoundChannel* channel = findChannel(channelID);
- if (channel) {
- channel->setPriority(priority);
- }
-}
-
-void SoundPool::setLoop(int channelID, int loop)
-{
- ALOGV("setLoop(%d, %d)", channelID, loop);
- Mutex::Autolock lock(&mLock);
- SoundChannel* channel = findChannel(channelID);
- if (channel) {
- channel->setLoop(loop);
- }
-}
-
-void SoundPool::setRate(int channelID, float rate)
-{
- ALOGV("setRate(%d, %f)", channelID, rate);
- Mutex::Autolock lock(&mLock);
- SoundChannel* channel = findChannel(channelID);
- if (channel) {
- channel->setRate(rate);
- }
-}
-
-// call with lock held
-void SoundPool::done_l(SoundChannel* channel)
-{
- ALOGV("done_l(%d)", channel->channelID());
- // if "stolen", play next event
- if (channel->nextChannelID() != 0) {
- ALOGV("add to restart list");
- addToRestartList(channel);
- }
-
- // return to idle state
- else {
- ALOGV("move to front");
- moveToFront_l(channel);
- }
-}
-
-void SoundPool::setCallback(SoundPoolCallback* callback, void* user)
-{
- Mutex::Autolock lock(&mCallbackLock);
- mCallback = callback;
- mUserData = user;
-}
-
-void SoundPool::notify(SoundPoolEvent event)
-{
- Mutex::Autolock lock(&mCallbackLock);
- if (mCallback != NULL) {
- mCallback(event, this, mUserData);
- }
-}
-
-void SoundPool::dump()
-{
- for (int i = 0; i < mMaxChannels; ++i) {
- mChannelPool[i].dump();
- }
-}
-
-
-Sample::Sample(int sampleID, const char* url)
-{
- init();
- mSampleID = sampleID;
- mUrl = strdup(url);
- ALOGV("create sampleID=%d, url=%s", mSampleID, mUrl);
-}
-
-Sample::Sample(int sampleID, int fd, int64_t offset, int64_t length)
-{
- init();
- mSampleID = sampleID;
- mFd = dup(fd);
- mOffset = offset;
- mLength = length;
- ALOGV("create sampleID=%d, fd=%d, offset=%" PRId64 " length=%" PRId64,
- mSampleID, mFd, mLength, mOffset);
-}
-
-void Sample::init()
-{
- mSize = 0;
- mRefCount = 0;
- mSampleID = 0;
- mState = UNLOADED;
- mFd = -1;
- mOffset = 0;
- mLength = 0;
- mUrl = 0;
-}
-
-Sample::~Sample()
-{
- ALOGV("Sample::destructor sampleID=%d, fd=%d", mSampleID, mFd);
- if (mFd > 0) {
- ALOGV("close(%d)", mFd);
- ::close(mFd);
- }
- free(mUrl);
-}
-
-status_t Sample::doLoad()
-{
- uint32_t sampleRate;
- int numChannels;
- audio_format_t format;
- status_t status;
- mHeap = new MemoryHeapBase(kDefaultHeapSize);
-
- ALOGV("Start decode");
- if (mUrl) {
- status = MediaPlayer::decode(
- NULL /* httpService */,
- mUrl,
- &sampleRate,
- &numChannels,
- &format,
- mHeap,
- &mSize);
- } else {
- status = MediaPlayer::decode(mFd, mOffset, mLength, &sampleRate, &numChannels, &format,
- mHeap, &mSize);
- ALOGV("close(%d)", mFd);
- ::close(mFd);
- mFd = -1;
- }
- if (status != NO_ERROR) {
- ALOGE("Unable to load sample: %s", mUrl);
- goto error;
- }
- ALOGV("pointer = %p, size = %zu, sampleRate = %u, numChannels = %d",
- mHeap->getBase(), mSize, sampleRate, numChannels);
-
- if (sampleRate > kMaxSampleRate) {
- ALOGE("Sample rate (%u) out of range", sampleRate);
- status = BAD_VALUE;
- goto error;
- }
-
- if ((numChannels < 1) || (numChannels > 2)) {
- ALOGE("Sample channel count (%d) out of range", numChannels);
- status = BAD_VALUE;
- goto error;
- }
-
- mData = new MemoryBase(mHeap, 0, mSize);
- mSampleRate = sampleRate;
- mNumChannels = numChannels;
- mFormat = format;
- mState = READY;
- return NO_ERROR;
-
-error:
- mHeap.clear();
- return status;
-}
-
-
-void SoundChannel::init(SoundPool* soundPool)
-{
- mSoundPool = soundPool;
-}
-
-// call with sound pool lock held
-void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftVolume,
- float rightVolume, int priority, int loop, float rate)
-{
- sp<AudioTrack> oldTrack;
- sp<AudioTrack> newTrack;
- status_t status;
-
- { // scope for the lock
- Mutex::Autolock lock(&mLock);
-
- ALOGV("SoundChannel::play %p: sampleID=%d, channelID=%d, leftVolume=%f, rightVolume=%f,"
- " priority=%d, loop=%d, rate=%f",
- this, sample->sampleID(), nextChannelID, leftVolume, rightVolume,
- priority, loop, rate);
-
- // if not idle, this voice is being stolen
- if (mState != IDLE) {
- ALOGV("channel %d stolen - event queued for channel %d", channelID(), nextChannelID);
- mNextEvent.set(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate);
- stop_l();
- return;
- }
-
- // initialize track
- size_t afFrameCount;
- uint32_t afSampleRate;
- audio_stream_type_t streamType = audio_attributes_to_stream_type(mSoundPool->attributes());
- if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
- afFrameCount = kDefaultFrameCount;
- }
- if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
- afSampleRate = kDefaultSampleRate;
- }
- int numChannels = sample->numChannels();
- uint32_t sampleRate = uint32_t(float(sample->sampleRate()) * rate + 0.5);
- uint32_t totalFrames = (kDefaultBufferCount * afFrameCount * sampleRate) / afSampleRate;
- uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount;
- size_t frameCount = 0;
-
- if (loop) {
- frameCount = sample->size()/numChannels/
- ((sample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t));
- }
-
-#ifndef USE_SHARED_MEM_BUFFER
- // Ensure minimum audio buffer size in case of short looped sample
- if(frameCount < totalFrames) {
- frameCount = totalFrames;
- }
-#endif
-
- // mToggle toggles each time a track is started on a given channel.
- // The toggle is concatenated with the SoundChannel address and passed to AudioTrack
- // as callback user data. This enables the detection of callbacks received from the old
- // audio track while the new one is being started and avoids processing them with
- // wrong audio audio buffer size (mAudioBufferSize)
- unsigned long toggle = mToggle ^ 1;
- void *userData = (void *)((unsigned long)this | toggle);
- audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(numChannels);
-
- // do not create a new audio track if current track is compatible with sample parameters
-#ifdef USE_SHARED_MEM_BUFFER
- newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
- channelMask, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData);
-#else
- newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
- channelMask, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData,
- bufferFrames);
-#endif
- oldTrack = mAudioTrack;
- status = newTrack->initCheck();
- if (status != NO_ERROR) {
- ALOGE("Error creating AudioTrack");
- goto exit;
- }
- ALOGV("setVolume %p", newTrack.get());
- newTrack->setVolume(leftVolume, rightVolume);
- newTrack->setLoop(0, frameCount, loop);
-
- // From now on, AudioTrack callbacks received with previous toggle value will be ignored.
- mToggle = toggle;
- mAudioTrack = newTrack;
- mPos = 0;
- mSample = sample;
- mChannelID = nextChannelID;
- mPriority = priority;
- mLoop = loop;
- mLeftVolume = leftVolume;
- mRightVolume = rightVolume;
- mNumChannels = numChannels;
- mRate = rate;
- clearNextEvent();
- mState = PLAYING;
- mAudioTrack->start();
- mAudioBufferSize = newTrack->frameCount()*newTrack->frameSize();
- }
-
-exit:
- ALOGV("delete oldTrack %p", oldTrack.get());
- if (status != NO_ERROR) {
- mAudioTrack.clear();
- }
-}
-
-void SoundChannel::nextEvent()
-{
- sp<Sample> sample;
- int nextChannelID;
- float leftVolume;
- float rightVolume;
- int priority;
- int loop;
- float rate;
-
- // check for valid event
- {
- Mutex::Autolock lock(&mLock);
- nextChannelID = mNextEvent.channelID();
- if (nextChannelID == 0) {
- ALOGV("stolen channel has no event");
- return;
- }
-
- sample = mNextEvent.sample();
- leftVolume = mNextEvent.leftVolume();
- rightVolume = mNextEvent.rightVolume();
- priority = mNextEvent.priority();
- loop = mNextEvent.loop();
- rate = mNextEvent.rate();
- }
-
- ALOGV("Starting stolen channel %d -> %d", channelID(), nextChannelID);
- play(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate);
-}
-
-void SoundChannel::callback(int event, void* user, void *info)
-{
- SoundChannel* channel = static_cast<SoundChannel*>((void *)((unsigned long)user & ~1));
-
- channel->process(event, info, (unsigned long)user & 1);
-}
-
-void SoundChannel::process(int event, void *info, unsigned long toggle)
-{
- //ALOGV("process(%d)", mChannelID);
-
- Mutex::Autolock lock(&mLock);
-
- AudioTrack::Buffer* b = NULL;
- if (event == AudioTrack::EVENT_MORE_DATA) {
- b = static_cast<AudioTrack::Buffer *>(info);
- }
-
- if (mToggle != toggle) {
- ALOGV("process wrong toggle %p channel %d", this, mChannelID);
- if (b != NULL) {
- b->size = 0;
- }
- return;
- }
-
- sp<Sample> sample = mSample;
-
-// ALOGV("SoundChannel::process event %d", event);
-
- if (event == AudioTrack::EVENT_MORE_DATA) {
-
- // check for stop state
- if (b->size == 0) return;
-
- if (mState == IDLE) {
- b->size = 0;
- return;
- }
-
- if (sample != 0) {
- // fill buffer
- uint8_t* q = (uint8_t*) b->i8;
- size_t count = 0;
-
- if (mPos < (int)sample->size()) {
- uint8_t* p = sample->data() + mPos;
- count = sample->size() - mPos;
- if (count > b->size) {
- count = b->size;
- }
- memcpy(q, p, count);
-// ALOGV("fill: q=%p, p=%p, mPos=%u, b->size=%u, count=%d", q, p, mPos, b->size,
-// count);
- } else if (mPos < mAudioBufferSize) {
- count = mAudioBufferSize - mPos;
- if (count > b->size) {
- count = b->size;
- }
- memset(q, 0, count);
-// ALOGV("fill extra: q=%p, mPos=%u, b->size=%u, count=%d", q, mPos, b->size, count);
- }
-
- mPos += count;
- b->size = count;
- //ALOGV("buffer=%p, [0]=%d", b->i16, b->i16[0]);
- }
- } else if (event == AudioTrack::EVENT_UNDERRUN || event == AudioTrack::EVENT_BUFFER_END ||
- event == AudioTrack::EVENT_NEW_IAUDIOTRACK) {
- ALOGV("process %p channel %d event %s",
- this, mChannelID, (event == AudioTrack::EVENT_UNDERRUN) ? "UNDERRUN" :
- (event == AudioTrack::EVENT_BUFFER_END) ? "BUFFER_END" : "NEW_IAUDIOTRACK");
- mSoundPool->addToStopList(this);
- } else if (event == AudioTrack::EVENT_LOOP_END) {
- ALOGV("End loop %p channel %d", this, mChannelID);
- } else {
- ALOGW("SoundChannel::process unexpected event %d", event);
- }
-}
-
-
-// call with lock held
-bool SoundChannel::doStop_l()
-{
- if (mState != IDLE) {
- setVolume_l(0, 0);
- ALOGV("stop");
- mAudioTrack->stop();
- mSample.clear();
- mState = IDLE;
- mPriority = IDLE_PRIORITY;
- return true;
- }
- return false;
-}
-
-// call with lock held and sound pool lock held
-void SoundChannel::stop_l()
-{
- if (doStop_l()) {
- mSoundPool->done_l(this);
- }
-}
-
-// call with sound pool lock held
-void SoundChannel::stop()
-{
- bool stopped;
- {
- Mutex::Autolock lock(&mLock);
- stopped = doStop_l();
- }
-
- if (stopped) {
- mSoundPool->done_l(this);
- }
-}
-
-//FIXME: Pause is a little broken right now
-void SoundChannel::pause()
-{
- Mutex::Autolock lock(&mLock);
- if (mState == PLAYING) {
- ALOGV("pause track");
- mState = PAUSED;
- mAudioTrack->pause();
- }
-}
-
-void SoundChannel::autoPause()
-{
- Mutex::Autolock lock(&mLock);
- if (mState == PLAYING) {
- ALOGV("pause track");
- mState = PAUSED;
- mAutoPaused = true;
- mAudioTrack->pause();
- }
-}
-
-void SoundChannel::resume()
-{
- Mutex::Autolock lock(&mLock);
- if (mState == PAUSED) {
- ALOGV("resume track");
- mState = PLAYING;
- mAutoPaused = false;
- mAudioTrack->start();
- }
-}
-
-void SoundChannel::autoResume()
-{
- Mutex::Autolock lock(&mLock);
- if (mAutoPaused && (mState == PAUSED)) {
- ALOGV("resume track");
- mState = PLAYING;
- mAutoPaused = false;
- mAudioTrack->start();
- }
-}
-
-void SoundChannel::setRate(float rate)
-{
- Mutex::Autolock lock(&mLock);
- if (mAudioTrack != NULL && mSample != 0) {
- uint32_t sampleRate = uint32_t(float(mSample->sampleRate()) * rate + 0.5);
- mAudioTrack->setSampleRate(sampleRate);
- mRate = rate;
- }
-}
-
-// call with lock held
-void SoundChannel::setVolume_l(float leftVolume, float rightVolume)
-{
- mLeftVolume = leftVolume;
- mRightVolume = rightVolume;
- if (mAudioTrack != NULL)
- mAudioTrack->setVolume(leftVolume, rightVolume);
-}
-
-void SoundChannel::setVolume(float leftVolume, float rightVolume)
-{
- Mutex::Autolock lock(&mLock);
- setVolume_l(leftVolume, rightVolume);
-}
-
-void SoundChannel::setLoop(int loop)
-{
- Mutex::Autolock lock(&mLock);
- if (mAudioTrack != NULL && mSample != 0) {
- uint32_t loopEnd = mSample->size()/mNumChannels/
- ((mSample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t));
- mAudioTrack->setLoop(0, loopEnd, loop);
- mLoop = loop;
- }
-}
-
-SoundChannel::~SoundChannel()
-{
- ALOGV("SoundChannel destructor %p", this);
- {
- Mutex::Autolock lock(&mLock);
- clearNextEvent();
- doStop_l();
- }
- // do not call AudioTrack destructor with mLock held as it will wait for the AudioTrack
- // callback thread to exit which may need to execute process() and acquire the mLock.
- mAudioTrack.clear();
-}
-
-void SoundChannel::dump()
-{
- ALOGV("mState = %d mChannelID=%d, mNumChannels=%d, mPos = %d, mPriority=%d, mLoop=%d",
- mState, mChannelID, mNumChannels, mPos, mPriority, mLoop);
-}
-
-void SoundEvent::set(const sp<Sample>& sample, int channelID, float leftVolume,
- float rightVolume, int priority, int loop, float rate)
-{
- mSample = sample;
- mChannelID = channelID;
- mLeftVolume = leftVolume;
- mRightVolume = rightVolume;
- mPriority = priority;
- mLoop = loop;
- mRate =rate;
-}
-
-} // end namespace android
diff --git a/media/libmedia/SoundPoolThread.cpp b/media/libmedia/SoundPoolThread.cpp
deleted file mode 100644
index ba3b482..0000000
--- a/media/libmedia/SoundPoolThread.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 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_NDEBUG 0
-#define LOG_TAG "SoundPoolThread"
-#include "utils/Log.h"
-
-#include "SoundPoolThread.h"
-
-namespace android {
-
-void SoundPoolThread::write(SoundPoolMsg msg) {
- Mutex::Autolock lock(&mLock);
- while (mMsgQueue.size() >= maxMessages) {
- mCondition.wait(mLock);
- }
-
- // if thread is quitting, don't add to queue
- if (mRunning) {
- mMsgQueue.push(msg);
- mCondition.signal();
- }
-}
-
-const SoundPoolMsg SoundPoolThread::read() {
- Mutex::Autolock lock(&mLock);
- while (mMsgQueue.size() == 0) {
- mCondition.wait(mLock);
- }
- SoundPoolMsg msg = mMsgQueue[0];
- mMsgQueue.removeAt(0);
- mCondition.signal();
- return msg;
-}
-
-void SoundPoolThread::quit() {
- Mutex::Autolock lock(&mLock);
- if (mRunning) {
- mRunning = false;
- mMsgQueue.clear();
- mMsgQueue.push(SoundPoolMsg(SoundPoolMsg::KILL, 0));
- mCondition.signal();
- mCondition.wait(mLock);
- }
- ALOGV("return from quit");
-}
-
-SoundPoolThread::SoundPoolThread(SoundPool* soundPool) :
- mSoundPool(soundPool)
-{
- mMsgQueue.setCapacity(maxMessages);
- if (createThreadEtc(beginThread, this, "SoundPoolThread")) {
- mRunning = true;
- }
-}
-
-SoundPoolThread::~SoundPoolThread()
-{
- quit();
-}
-
-int SoundPoolThread::beginThread(void* arg) {
- ALOGV("beginThread");
- SoundPoolThread* soundPoolThread = (SoundPoolThread*)arg;
- return soundPoolThread->run();
-}
-
-int SoundPoolThread::run() {
- ALOGV("run");
- for (;;) {
- SoundPoolMsg msg = read();
- ALOGV("Got message m=%d, mData=%d", msg.mMessageType, msg.mData);
- switch (msg.mMessageType) {
- case SoundPoolMsg::KILL:
- ALOGV("goodbye");
- return NO_ERROR;
- case SoundPoolMsg::LOAD_SAMPLE:
- doLoadSample(msg.mData);
- break;
- default:
- ALOGW("run: Unrecognized message %d\n",
- msg.mMessageType);
- break;
- }
- }
-}
-
-void SoundPoolThread::loadSample(int sampleID) {
- write(SoundPoolMsg(SoundPoolMsg::LOAD_SAMPLE, sampleID));
-}
-
-void SoundPoolThread::doLoadSample(int sampleID) {
- sp <Sample> sample = mSoundPool->findSample(sampleID);
- status_t status = -1;
- if (sample != 0) {
- status = sample->doLoad();
- }
- mSoundPool->notify(SoundPoolEvent(SoundPoolEvent::SAMPLE_LOADED, sampleID, status));
-}
-
-} // end namespace android
diff --git a/media/libmedia/SoundPoolThread.h b/media/libmedia/SoundPoolThread.h
deleted file mode 100644
index 7e96900..0000000
--- a/media/libmedia/SoundPoolThread.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef SOUNDPOOLTHREAD_H_
-#define SOUNDPOOLTHREAD_H_
-
-#include <utils/threads.h>
-#include <utils/Vector.h>
-#include <media/AudioTrack.h>
-
-#include <media/SoundPool.h>
-
-namespace android {
-
-class SoundPoolMsg {
-public:
- enum MessageType { INVALID, KILL, LOAD_SAMPLE };
- SoundPoolMsg() : mMessageType(INVALID), mData(0) {}
- SoundPoolMsg(MessageType MessageType, int data) :
- mMessageType(MessageType), mData(data) {}
- uint16_t mMessageType;
- uint16_t mData;
-};
-
-/*
- * This class handles background requests from the SoundPool
- */
-class SoundPoolThread {
-public:
- SoundPoolThread(SoundPool* SoundPool);
- ~SoundPoolThread();
- void loadSample(int sampleID);
- void quit();
- void write(SoundPoolMsg msg);
-
-private:
- static const size_t maxMessages = 5;
-
- static int beginThread(void* arg);
- int run();
- void doLoadSample(int sampleID);
- const SoundPoolMsg read();
-
- Mutex mLock;
- Condition mCondition;
- Vector<SoundPoolMsg> mMsgQueue;
- SoundPool* mSoundPool;
- bool mRunning;
-};
-
-} // end namespace android
-
-#endif /*SOUNDPOOLTHREAD_H_*/
diff --git a/media/libmedia/StringArray.cpp b/media/libmedia/StringArray.cpp
index 5f5b57a..477e3fd 100644
--- a/media/libmedia/StringArray.cpp
+++ b/media/libmedia/StringArray.cpp
@@ -16,7 +16,7 @@
//
// Sortable array of strings. STL-ish, but STL-free.
-//
+//
#include <stdlib.h>
#include <string.h>
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 61b6d36..2cc4685 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -28,718 +28,718 @@
// Descriptors for all available tones (See ToneGenerator::ToneDescriptor class declaration for details)
const ToneGenerator::ToneDescriptor ToneGenerator::sToneDescriptors[] = {
- { segments: {{ duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 941, 0 }, 0, 0},
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_DTMF_0
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 697, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_DTMF_1
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 697, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_DTMF_2
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 697, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_DTMF_3
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 770, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_DTMF_4
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 770, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_DTMF_5
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 770, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_DTMF_6
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 852, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_DTMF_7
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 852, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_DTMF_8
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 852, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_DTMF_9
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 941, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_DTMF_S
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 941, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_DTMF_P
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 697, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_DTMF_A
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 770, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_DTMF_B
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 852, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_DTMF_C
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 941, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_DTMF_D
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 425, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_SUP_DIAL
- { segments: { { duration: 500 , waveFreq: { 425, 0 }, 0, 0},
- { duration: 500, waveFreq: { 0 }, 0, 0},
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_SUP_BUSY
- { segments: { { duration: 200, waveFreq: { 425, 0 }, 0, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_SUP_CONGESTION
- { segments: { { duration: 200, waveFreq: { 425, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_SUP_RADIO_ACK
- { segments: { { duration: 200, waveFreq: { 425, 0 }, 0, 0},
- { duration: 200, waveFreq: { 0 }, 0, 0},
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: 2,
- repeatSegment: 0 }, // TONE_SUP_RADIO_NOTAVAIL
- { segments: { { duration: 330, waveFreq: { 950, 1400, 1800, 0 }, 0, 0},
- { duration: 1000, waveFreq: { 0 }, 0, 0},
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_SUP_ERROR
- { segments: { { duration: 200, waveFreq: { 425, 0 }, 0, 0 },
- { duration: 600, waveFreq: { 0 }, 0, 0 },
- { duration: 200, waveFreq: { 425, 0 }, 0, 0 },
- { duration: 3000, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_SUP_CALL_WAITING
- { segments: { { duration: 1000, waveFreq: { 425, 0 }, 0, 0 },
- { duration: 4000, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_SUP_RINGTONE
- { segments: { { duration: 40, waveFreq: { 400, 1200, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_PROP_BEEP
- { segments: { { duration: 100, waveFreq: { 1200, 0 }, 0, 0 },
- { duration: 100, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: 1,
- repeatSegment: 0 }, // TONE_PROP_ACK
- { segments: { { duration: 400, waveFreq: { 300, 400, 500, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_PROP_NACK
- { segments: { { duration: 200, waveFreq: { 400, 1200, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_PROP_PROMPT
- { segments: { { duration: 40, waveFreq: { 400, 1200, 0 }, 0, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 40, waveFreq: { 400, 1200, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_PROP_BEEP2
- { segments: { { duration: 250, waveFreq: { 440, 0 }, 0, 0 },
- { duration: 250, waveFreq: { 620, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_SUP_INTERCEPT
- { segments: { { duration: 250, waveFreq: { 440, 0 }, 0, 0 },
- { duration: 250, waveFreq: { 620, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: 7,
- repeatSegment: 0 }, // TONE_SUP_INTERCEPT_ABBREV
- { segments: { { duration: 250, waveFreq: { 480, 620, 0 }, 0, 0 },
- { duration: 250, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: 7,
- repeatSegment: 0 }, // TONE_SUP_CONGESTION_ABBREV
- { segments: { { duration: 100, waveFreq: { 350, 440, 0 }, 0, 0 },
- { duration: 100, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: 2,
- repeatSegment: 0 }, // TONE_SUP_CONFIRM
- { segments: { { duration: 100, waveFreq: { 480, 0 }, 0, 0 },
- { duration: 100, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: 3,
- repeatSegment: 0 }, // TONE_SUP_PIP
- { segments: {{ duration: ToneGenerator::TONEGEN_INF, waveFreq: { 425, 0 }, 0, 0},
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_DIAL_TONE_LITE
- { segments: { { duration: 2000, waveFreq: { 440, 480, 0 }, 0, 0 },
- { duration: 4000, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_NETWORK_USA_RINGBACK
- { segments: { { duration: 250, waveFreq: { 440, 0 }, 0, 0 },
- { duration: 250, waveFreq: { 620, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_INTERCEPT
- { segments: { { duration: 250, waveFreq: { 440, 0 }, 0, 0 },
- { duration: 250, waveFreq: { 620, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_ABBR_INTERCEPT
- { segments: { { duration: 250, waveFreq: { 480, 620, 0 }, 0, 0 },
- { duration: 250, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_REORDER
- { segments: { { duration: 250, waveFreq: { 480, 620, 0 }, 0, 0 },
- { duration: 250, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: 7,
- repeatSegment: 0 }, // TONE_CDMA_ABBR_REORDER
- { segments: { { duration: 500, waveFreq: { 480, 620, 0 }, 0, 0 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_NETWORK_BUSY
- { segments: { { duration: 100, waveFreq: { 350, 440, 0 }, 0, 0 },
- { duration: 100, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: 2,
- repeatSegment: 0 }, // TONE_CDMA_CONFIRM
- { segments: { { duration: 500, waveFreq: { 660, 1000, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_ANSWER
- { segments: { { duration: 300, waveFreq: { 440, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_NETWORK_CALLWAITING
- { segments: { { duration: 100, waveFreq: { 480, 0 }, 0, 0 },
- { duration: 100, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: 3,
- repeatSegment: 0 }, // TONE_CDMA_PIP
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1336, 941, 0 }, 0, 0},
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_DTMF_0
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1209, 697, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_DTMF_1
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1336, 697, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_DTMF_2
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1477, 697, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_DTMF_3
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1209, 770, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_DTMF_4
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1336, 770, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_DTMF_5
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1477, 770, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_DTMF_6
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1209, 852, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_DTMF_7
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1336, 852, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_DTMF_8
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1477, 852, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_DTMF_9
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1209, 941, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_DTMF_S
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1477, 941, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_DTMF_P
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1633, 697, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_DTMF_A
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1633, 770, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_DTMF_B
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1633, 852, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_DTMF_C
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1633, 941, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_DTMF_D
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 425, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_SUP_DIAL
+ { .segments = { { .duration = 500 , .waveFreq = { 425, 0 }, 0, 0},
+ { .duration = 500, .waveFreq = { 0 }, 0, 0},
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_SUP_BUSY
+ { .segments = { { .duration = 200, .waveFreq = { 425, 0 }, 0, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_SUP_CONGESTION
+ { .segments = { { .duration = 200, .waveFreq = { 425, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_SUP_RADIO_ACK
+ { .segments = { { .duration = 200, .waveFreq = { 425, 0 }, 0, 0},
+ { .duration = 200, .waveFreq = { 0 }, 0, 0},
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 2,
+ .repeatSegment = 0 }, // TONE_SUP_RADIO_NOTAVAIL
+ { .segments = { { .duration = 330, .waveFreq = { 950, 1400, 1800, 0 }, 0, 0},
+ { .duration = 1000, .waveFreq = { 0 }, 0, 0},
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_SUP_ERROR
+ { .segments = { { .duration = 200, .waveFreq = { 425, 0 }, 0, 0 },
+ { .duration = 600, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 200, .waveFreq = { 425, 0 }, 0, 0 },
+ { .duration = 3000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_SUP_CALL_WAITING
+ { .segments = { { .duration = 1000, .waveFreq = { 425, 0 }, 0, 0 },
+ { .duration = 4000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_SUP_RINGTONE
+ { .segments = { { .duration = 40, .waveFreq = { 400, 1200, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_PROP_BEEP
+ { .segments = { { .duration = 100, .waveFreq = { 1200, 0 }, 0, 0 },
+ { .duration = 100, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 1,
+ .repeatSegment = 0 }, // TONE_PROP_ACK
+ { .segments = { { .duration = 400, .waveFreq = { 300, 400, 500, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_PROP_NACK
+ { .segments = { { .duration = 200, .waveFreq = { 400, 1200, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_PROP_PROMPT
+ { .segments = { { .duration = 40, .waveFreq = { 400, 1200, 0 }, 0, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 40, .waveFreq = { 400, 1200, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_PROP_BEEP2
+ { .segments = { { .duration = 250, .waveFreq = { 440, 0 }, 0, 0 },
+ { .duration = 250, .waveFreq = { 620, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_SUP_INTERCEPT
+ { .segments = { { .duration = 250, .waveFreq = { 440, 0 }, 0, 0 },
+ { .duration = 250, .waveFreq = { 620, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 7,
+ .repeatSegment = 0 }, // TONE_SUP_INTERCEPT_ABBREV
+ { .segments = { { .duration = 250, .waveFreq = { 480, 620, 0 }, 0, 0 },
+ { .duration = 250, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 7,
+ .repeatSegment = 0 }, // TONE_SUP_CONGESTION_ABBREV
+ { .segments = { { .duration = 100, .waveFreq = { 350, 440, 0 }, 0, 0 },
+ { .duration = 100, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 2,
+ .repeatSegment = 0 }, // TONE_SUP_CONFIRM
+ { .segments = { { .duration = 100, .waveFreq = { 480, 0 }, 0, 0 },
+ { .duration = 100, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 3,
+ .repeatSegment = 0 }, // TONE_SUP_PIP
+ { .segments = {{ .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 425, 0 }, 0, 0},
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_DIAL_TONE_LITE
+ { .segments = { { .duration = 2000, .waveFreq = { 440, 480, 0 }, 0, 0 },
+ { .duration = 4000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_NETWORK_USA_RINGBACK
+ { .segments = { { .duration = 250, .waveFreq = { 440, 0 }, 0, 0 },
+ { .duration = 250, .waveFreq = { 620, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_INTERCEPT
+ { .segments = { { .duration = 250, .waveFreq = { 440, 0 }, 0, 0 },
+ { .duration = 250, .waveFreq = { 620, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_ABBR_INTERCEPT
+ { .segments = { { .duration = 250, .waveFreq = { 480, 620, 0 }, 0, 0 },
+ { .duration = 250, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_REORDER
+ { .segments = { { .duration = 250, .waveFreq = { 480, 620, 0 }, 0, 0 },
+ { .duration = 250, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 7,
+ .repeatSegment = 0 }, // TONE_CDMA_ABBR_REORDER
+ { .segments = { { .duration = 500, .waveFreq = { 480, 620, 0 }, 0, 0 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_NETWORK_BUSY
+ { .segments = { { .duration = 100, .waveFreq = { 350, 440, 0 }, 0, 0 },
+ { .duration = 100, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 2,
+ .repeatSegment = 0 }, // TONE_CDMA_CONFIRM
+ { .segments = { { .duration = 500, .waveFreq = { 660, 1000, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_ANSWER
+ { .segments = { { .duration = 300, .waveFreq = { 440, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_NETWORK_CALLWAITING
+ { .segments = { { .duration = 100, .waveFreq = { 480, 0 }, 0, 0 },
+ { .duration = 100, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 3,
+ .repeatSegment = 0 }, // TONE_CDMA_PIP
- { segments: { { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
- { duration: 64, waveFreq: { 2556, 0}, 19, 0},
- { duration: 32, waveFreq: { 2091, 0}, 0, 0},
- { duration: 48, waveFreq: { 2556, 0}, 0, 0},
- { duration: 4000, waveFreq: { 0 }, 0, 0},
- { duration: 0, waveFreq: { 0 }, 0, 0}},
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_NORMAL
- { segments: { { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
- { duration: 64, waveFreq: { 2556, 0}, 7, 0 },
- { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
- { duration: 400, waveFreq: { 0 }, 0, 0 },
- { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
- { duration: 64, waveFreq: { 2556, 0}, 7, 4 },
- { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
- { duration: 4000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 } },
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_INTERGROUP
- { segments: { { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
- { duration: 64, waveFreq: { 2556, 0}, 3, 0 },
- { duration: 16, waveFreq: { 2091, 0}, 0, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
- { duration: 64, waveFreq: { 2556, 0}, 3, 4 },
- { duration: 16, waveFreq: { 2091, 0}, 0, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 } },
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_SP_PRI
- { segments: { { duration: 0, waveFreq: { 0 }, 0, 0} },
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_PAT3
- { segments: { { duration: 32, waveFreq: { 2091, 0 }, 0, 0 },
- { duration: 64, waveFreq: { 2556, 0 }, 4, 0 },
- { duration: 20, waveFreq: { 2091, 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 } , 0, 0 } },
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_PING_RING
- { segments: { { duration: 0, waveFreq: { 0 }, 0, 0} },
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_PAT5
- { segments: { { duration: 0, waveFreq: { 0 }, 0, 0} },
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_PAT6
- { segments: { { duration: 0, waveFreq: { 0 }, 0, 0} },
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_PAT7
+ { .segments = { { .duration = 32, .waveFreq = { 2091, 0}, 0, 0 },
+ { .duration = 64, .waveFreq = { 2556, 0}, 19, 0},
+ { .duration = 32, .waveFreq = { 2091, 0}, 0, 0},
+ { .duration = 48, .waveFreq = { 2556, 0}, 0, 0},
+ { .duration = 4000, .waveFreq = { 0 }, 0, 0},
+ { .duration = 0, .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_NORMAL
+ { .segments = { { .duration = 32, .waveFreq = { 2091, 0}, 0, 0 },
+ { .duration = 64, .waveFreq = { 2556, 0}, 7, 0 },
+ { .duration = 32, .waveFreq = { 2091, 0}, 0, 0 },
+ { .duration = 400, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 32, .waveFreq = { 2091, 0}, 0, 0 },
+ { .duration = 64, .waveFreq = { 2556, 0}, 7, 4 },
+ { .duration = 32, .waveFreq = { 2091, 0}, 0, 0 },
+ { .duration = 4000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 } },
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_INTERGROUP
+ { .segments = { { .duration = 32, .waveFreq = { 2091, 0}, 0, 0 },
+ { .duration = 64, .waveFreq = { 2556, 0}, 3, 0 },
+ { .duration = 16, .waveFreq = { 2091, 0}, 0, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 32, .waveFreq = { 2091, 0}, 0, 0 },
+ { .duration = 64, .waveFreq = { 2556, 0}, 3, 4 },
+ { .duration = 16, .waveFreq = { 2091, 0}, 0, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 } },
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_SP_PRI
+ { .segments = { { .duration = 0, .waveFreq = { 0 }, 0, 0} },
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_PAT3
+ { .segments = { { .duration = 32, .waveFreq = { 2091, 0 }, 0, 0 },
+ { .duration = 64, .waveFreq = { 2556, 0 }, 4, 0 },
+ { .duration = 20, .waveFreq = { 2091, 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 } , 0, 0 } },
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_PING_RING
+ { .segments = { { .duration = 0, .waveFreq = { 0 }, 0, 0} },
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_PAT5
+ { .segments = { { .duration = 0, .waveFreq = { 0 }, 0, 0} },
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_PAT6
+ { .segments = { { .duration = 0, .waveFreq = { 0 }, 0, 0} },
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_PAT7
- { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 39, 0 },
- { duration: 4000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 } },
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_HIGH_L
- { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 39, 0 },
- { duration: 4000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 } },
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_MED_L
- { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 39, 0 },
- { duration: 4000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 } },
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_LOW_L
- { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 15, 0 },
- { duration: 400, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 } },
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_HIGH_SS
- { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 15, 0 },
- { duration: 400, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_MED_SS
- { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 15, 0 },
- { duration: 400, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_LOW_SS
- { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 7, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 7, 3 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 15, 6 },
- { duration: 4000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_HIGH_SSL
- { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 7, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 7, 3 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 15, 6 },
- { duration: 4000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_MED_SSL
- { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 7, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 7, 3 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 15, 6 },
- { duration: 4000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_LOW_SSL
- { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 19, 0 },
- { duration: 1000, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 19, 3 },
- { duration: 3000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_HIGH_SS_2
- { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 19, 0 },
- { duration: 1000, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 19, 3 },
- { duration: 3000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_MED_SS_2
- { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 19, 0 },
- { duration: 1000, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 19, 3 },
- { duration: 3000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_LOW_SS_2
- { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 9, 0 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 19, 3 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 9, 6 },
- { duration: 3000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_HIGH_SLS
- { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 9, 0 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 19, 3 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 9, 6 },
- { duration: 3000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_MED_SLS
- { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 9, 0 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 19, 3 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 9, 6 },
- { duration: 3000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_LOW_SLS
- { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 9, 0 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 9, 3 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 9, 6 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 9, 9 },
- { duration: 2500, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_HIGH_S_X4
- { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 9, 0 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 9, 3 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 9, 6 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 9, 9 },
- { duration: 2500, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_MED_S_X4
- { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 9, 0 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 9, 3 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 9, 6 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 9, 9 },
- { duration: 2500, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_LOW_S_X4
- { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 19, 0 },
- { duration: 2000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_HIGH_PBX_L
- { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 19, 0 },
- { duration: 2000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_MED_PBX_L
- { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 19, 0 },
- { duration: 2000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_LOW_PBX_L
- { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 7, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 7, 3 },
- { duration: 2000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_HIGH_PBX_SS
- { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 7, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 7, 3 },
- { duration: 2000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_MED_PBX_SS
- { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 7, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 7, 3 },
- { duration: 2000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_LOW_PBX_SS
- { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 7, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 7, 3 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 15, 6 },
- { duration: 1000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_HIGH_PBX_SSL
- { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 7, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 7, 3 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 15, 6 },
- { duration: 1000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_MED_PBX_SSL
- { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 7, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 7, 3 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 15, 6 },
- { duration: 1000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_LOW_PBX_SSL
- { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 7, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 15, 3 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 7, 6 },
- { duration: 1000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_HIGH_PBX_SLS
- { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 7, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 15, 3 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 7, 6 },
- { duration: 1000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_MED_PBX_SLS
- { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 7, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 15, 3 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 7, 6 },
- { duration: 1000, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_LOW_PBX_SLS
- { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 7, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 7, 3 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 7, 6 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 4000, 0 }, 7, 9 },
- { duration: 800, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_HIGH_PBX_S_X4
- { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 7, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 7, 3 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 7, 6 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 2900, 0 }, 7, 9 },
- { duration: 800, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_MED_PBX_S_X4
- { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 7, 0 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 7, 3 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 7, 6 },
- { duration: 200, waveFreq: { 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
- { duration: 25, waveFreq: { 1450, 0 }, 7, 9 },
- { duration: 800, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_LOW_PBX_S_X4
+ { .segments = { { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 39, 0 },
+ { .duration = 4000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 } },
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_HIGH_L
+ { .segments = { { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 39, 0 },
+ { .duration = 4000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 } },
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_MED_L
+ { .segments = { { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 39, 0 },
+ { .duration = 4000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 } },
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_LOW_L
+ { .segments = { { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 15, 0 },
+ { .duration = 400, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 } },
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_HIGH_SS
+ { .segments = { { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 15, 0 },
+ { .duration = 400, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_MED_SS
+ { .segments = { { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 15, 0 },
+ { .duration = 400, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_LOW_SS
+ { .segments = { { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 7, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 7, 3 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 15, 6 },
+ { .duration = 4000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_HIGH_SSL
+ { .segments = { { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 7, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 7, 3 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 15, 6 },
+ { .duration = 4000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_MED_SSL
+ { .segments = { { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 7, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 7, 3 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 15, 6 },
+ { .duration = 4000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_LOW_SSL
+ { .segments = { { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 19, 0 },
+ { .duration = 1000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 19, 3 },
+ { .duration = 3000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_HIGH_SS_2
+ { .segments = { { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 19, 0 },
+ { .duration = 1000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 19, 3 },
+ { .duration = 3000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_MED_SS_2
+ { .segments = { { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 19, 0 },
+ { .duration = 1000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 19, 3 },
+ { .duration = 3000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_LOW_SS_2
+ { .segments = { { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 9, 0 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 19, 3 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 9, 6 },
+ { .duration = 3000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_HIGH_SLS
+ { .segments = { { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 9, 0 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 19, 3 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 9, 6 },
+ { .duration = 3000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_MED_SLS
+ { .segments = { { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 9, 0 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 19, 3 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 9, 6 },
+ { .duration = 3000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_LOW_SLS
+ { .segments = { { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 9, 0 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 9, 3 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 9, 6 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 9, 9 },
+ { .duration = 2500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_HIGH_S_X4
+ { .segments = { { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 9, 0 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 9, 3 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 9, 6 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 9, 9 },
+ { .duration = 2500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_MED_S_X4
+ { .segments = { { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 9, 0 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 9, 3 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 9, 6 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 9, 9 },
+ { .duration = 2500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_LOW_S_X4
+ { .segments = { { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 19, 0 },
+ { .duration = 2000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_HIGH_PBX_L
+ { .segments = { { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 19, 0 },
+ { .duration = 2000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_MED_PBX_L
+ { .segments = { { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 19, 0 },
+ { .duration = 2000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_LOW_PBX_L
+ { .segments = { { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 7, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 7, 3 },
+ { .duration = 2000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_HIGH_PBX_SS
+ { .segments = { { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 7, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 7, 3 },
+ { .duration = 2000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_MED_PBX_SS
+ { .segments = { { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 7, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 7, 3 },
+ { .duration = 2000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_LOW_PBX_SS
+ { .segments = { { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 7, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 7, 3 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 15, 6 },
+ { .duration = 1000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_HIGH_PBX_SSL
+ { .segments = { { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 7, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 7, 3 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 15, 6 },
+ { .duration = 1000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_MED_PBX_SSL
+ { .segments = { { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 7, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 7, 3 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 15, 6 },
+ { .duration = 1000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_LOW_PBX_SSL
+ { .segments = { { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 7, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 15, 3 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 7, 6 },
+ { .duration = 1000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_HIGH_PBX_SLS
+ { .segments = { { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 7, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 15, 3 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 7, 6 },
+ { .duration = 1000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_MED_PBX_SLS
+ { .segments = { { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 7, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 15, 3 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 7, 6 },
+ { .duration = 1000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_LOW_PBX_SLS
+ { .segments = { { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 7, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 7, 3 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 7, 6 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 3700, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 4000, 0 }, 7, 9 },
+ { .duration = 800, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_HIGH_PBX_S_X4
+ { .segments = { { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 7, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 7, 3 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 7, 6 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2600, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 2900, 0 }, 7, 9 },
+ { .duration = 800, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_MED_PBX_S_X4
+ { .segments = { { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 7, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 7, 3 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 7, 6 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1300, 0 }, 0, 0 },
+ { .duration = 25, .waveFreq = { 1450, 0 }, 7, 9 },
+ { .duration = 800, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_LOW_PBX_S_X4
- { segments: { { duration: 62, waveFreq: { 1109, 0 }, 0, 0 },
- { duration: 62, waveFreq: { 784, 0 }, 0, 0 },
- { duration: 62, waveFreq: { 740, 0 }, 0, 0 },
- { duration: 62, waveFreq: { 622, 0 }, 0, 0 },
- { duration: 62, waveFreq: { 1109, 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 } },
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_ALERT_NETWORK_LITE
- { segments: { { duration: 62, waveFreq: { 1245, 0 }, 0, 0 },
- { duration: 62, waveFreq: { 659, 0 }, 2, 0 },
- { duration: 62, waveFreq: { 1245, 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 } },
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_ALERT_AUTOREDIAL_LITE
- { segments: { { duration: 400, waveFreq: { 1150, 770, 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 } },
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_ONE_MIN_BEEP
- { segments: { { duration: 120, waveFreq: { 941, 1477, 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 } },
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_KEYPAD_VOLUME_KEY_LITE
- { segments: { { duration: 375, waveFreq: { 587, 0 }, 0, 0 },
- { duration: 125, waveFreq: { 1175, 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 } },
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_PRESSHOLDKEY_LITE
- { segments: { { duration: 62, waveFreq: { 587, 0 }, 0, 0 },
- { duration: 62, waveFreq: { 784, 0 }, 0, 0 },
- { duration: 62, waveFreq: { 831, 0 }, 0, 0 },
- { duration: 62, waveFreq: { 784, 0 }, 0, 0 },
- { duration: 62, waveFreq: { 1109, 0 }, 0, 0 },
- { duration: 62, waveFreq: { 784, 0 }, 0, 0 },
- { duration: 62, waveFreq: { 831, 0 }, 0, 0 },
- { duration: 62, waveFreq: { 784, 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 } },
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_ALERT_INCALL_LITE
- { segments: { { duration: 125, waveFreq: { 941, 0 }, 0, 0 },
- { duration: 10, waveFreq: { 0 }, 2, 0 },
- { duration: 4990, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 } },
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_CDMA_EMERGENCY_RINGBACK
- { segments: { { duration: 125, waveFreq: { 1319, 0 }, 0, 0 },
- { duration: 125, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 } },
- repeatCnt: 2,
- repeatSegment: 0 }, // TONE_CDMA_ALERT_CALL_GUARD
- { segments: { { duration: 125, waveFreq: { 1047, 0 }, 0, 0 },
- { duration: 125, waveFreq: { 370, 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 } },
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_SOFT_ERROR_LITE
- { segments: { { duration: 125, waveFreq: { 1480, 0 }, 0, 0 },
- { duration: 125, waveFreq: { 1397, 0 }, 0, 0 },
- { duration: 125, waveFreq: { 784, 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 } },
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_CALLDROP_LITE
+ { .segments = { { .duration = 62, .waveFreq = { 1109, 0 }, 0, 0 },
+ { .duration = 62, .waveFreq = { 784, 0 }, 0, 0 },
+ { .duration = 62, .waveFreq = { 740, 0 }, 0, 0 },
+ { .duration = 62, .waveFreq = { 622, 0 }, 0, 0 },
+ { .duration = 62, .waveFreq = { 1109, 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 } },
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_ALERT_NETWORK_LITE
+ { .segments = { { .duration = 62, .waveFreq = { 1245, 0 }, 0, 0 },
+ { .duration = 62, .waveFreq = { 659, 0 }, 2, 0 },
+ { .duration = 62, .waveFreq = { 1245, 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 } },
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_ALERT_AUTOREDIAL_LITE
+ { .segments = { { .duration = 400, .waveFreq = { 1150, 770, 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 } },
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_ONE_MIN_BEEP
+ { .segments = { { .duration = 120, .waveFreq = { 941, 1477, 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 } },
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_KEYPAD_VOLUME_KEY_LITE
+ { .segments = { { .duration = 375, .waveFreq = { 587, 0 }, 0, 0 },
+ { .duration = 125, .waveFreq = { 1175, 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 } },
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_PRESSHOLDKEY_LITE
+ { .segments = { { .duration = 62, .waveFreq = { 587, 0 }, 0, 0 },
+ { .duration = 62, .waveFreq = { 784, 0 }, 0, 0 },
+ { .duration = 62, .waveFreq = { 831, 0 }, 0, 0 },
+ { .duration = 62, .waveFreq = { 784, 0 }, 0, 0 },
+ { .duration = 62, .waveFreq = { 1109, 0 }, 0, 0 },
+ { .duration = 62, .waveFreq = { 784, 0 }, 0, 0 },
+ { .duration = 62, .waveFreq = { 831, 0 }, 0, 0 },
+ { .duration = 62, .waveFreq = { 784, 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 } },
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_ALERT_INCALL_LITE
+ { .segments = { { .duration = 125, .waveFreq = { 941, 0 }, 0, 0 },
+ { .duration = 10, .waveFreq = { 0 }, 2, 0 },
+ { .duration = 4990, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 } },
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_CDMA_EMERGENCY_RINGBACK
+ { .segments = { { .duration = 125, .waveFreq = { 1319, 0 }, 0, 0 },
+ { .duration = 125, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 } },
+ .repeatCnt = 2,
+ .repeatSegment = 0 }, // TONE_CDMA_ALERT_CALL_GUARD
+ { .segments = { { .duration = 125, .waveFreq = { 1047, 0 }, 0, 0 },
+ { .duration = 125, .waveFreq = { 370, 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 } },
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_SOFT_ERROR_LITE
+ { .segments = { { .duration = 125, .waveFreq = { 1480, 0 }, 0, 0 },
+ { .duration = 125, .waveFreq = { 1397, 0 }, 0, 0 },
+ { .duration = 125, .waveFreq = { 784, 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 } },
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_CALLDROP_LITE
- { segments: { { duration: 500, waveFreq: { 425, 0 }, 0, 0 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_NETWORK_BUSY_ONE_SHOT
- { segments: { { duration: 400, waveFreq: { 1150, 770 }, 0, 0 },
- { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_ABBR_ALERT
- { segments: { { duration: 0, waveFreq: { 0 }, 0, 0 }},
- repeatCnt: 0,
- repeatSegment: 0 }, // TONE_CDMA_SIGNAL_OFF
+ { .segments = { { .duration = 500, .waveFreq = { 425, 0 }, 0, 0 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_NETWORK_BUSY_ONE_SHOT
+ { .segments = { { .duration = 400, .waveFreq = { 1150, 770 }, 0, 0 },
+ { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_ABBR_ALERT
+ { .segments = { { .duration = 0, .waveFreq = { 0 }, 0, 0 }},
+ .repeatCnt = 0,
+ .repeatSegment = 0 }, // TONE_CDMA_SIGNAL_OFF
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 350, 440, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_ANSI_DIAL
- { segments: { { duration: 500, waveFreq: { 480, 620, 0 }, 0, 0 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_ANSI_BUSY
- { segments: { { duration: 250, waveFreq: { 480, 620, 0 }, 0, 0 },
- { duration: 250, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_ANSI_CONGESTION
- { segments: { { duration: 300, waveFreq: { 440, 0 }, 0, 0 },
- { duration: 9700, waveFreq: { 0 }, 0, 0 },
- { duration: 100, waveFreq: { 440, 0 }, 0, 0 },
- { duration: 100, waveFreq: { 0 }, 0, 0 },
- { duration: 100, waveFreq: { 440, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 1 }, // TONE_ANSI_CALL_WAITING
- { segments: { { duration: 2000, waveFreq: { 440, 480, 0 }, 0, 0 },
- { duration: 4000, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_ANSI_RINGTONE
- { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 400, 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_JAPAN_DIAL
- { segments: { { duration: 500, waveFreq: { 400, 0 }, 0, 0 },
- { duration: 500, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_JAPAN_BUSY
- { segments: { { duration: 1000, waveFreq: { 400, 0 }, 0, 0 },
- { duration: 2000, waveFreq: { 0 }, 0, 0 },
- { duration: 0 , waveFreq: { 0 }, 0, 0}},
- repeatCnt: ToneGenerator::TONEGEN_INF,
- repeatSegment: 0 }, // TONE_JAPAN_RADIO_ACK
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 350, 440, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_ANSI_DIAL
+ { .segments = { { .duration = 500, .waveFreq = { 480, 620, 0 }, 0, 0 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_ANSI_BUSY
+ { .segments = { { .duration = 250, .waveFreq = { 480, 620, 0 }, 0, 0 },
+ { .duration = 250, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_ANSI_CONGESTION
+ { .segments = { { .duration = 300, .waveFreq = { 440, 0 }, 0, 0 },
+ { .duration = 9700, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 100, .waveFreq = { 440, 0 }, 0, 0 },
+ { .duration = 100, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 100, .waveFreq = { 440, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 1 }, // TONE_ANSI_CALL_WAITING
+ { .segments = { { .duration = 2000, .waveFreq = { 440, 480, 0 }, 0, 0 },
+ { .duration = 4000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_ANSI_RINGTONE
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 400, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_JAPAN_DIAL
+ { .segments = { { .duration = 500, .waveFreq = { 400, 0 }, 0, 0 },
+ { .duration = 500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_JAPAN_BUSY
+ { .segments = { { .duration = 1000, .waveFreq = { 400, 0 }, 0, 0 },
+ { .duration = 2000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_JAPAN_RADIO_ACK
diff --git a/media/libmedia/docs/Makefile b/media/libmedia/docs/Makefile
new file mode 100644
index 0000000..bddbc9b
--- /dev/null
+++ b/media/libmedia/docs/Makefile
@@ -0,0 +1,2 @@
+paused.png : paused.dot
+ dot -Tpng < $< > $@
diff --git a/media/libmedia/docs/paused.dot b/media/libmedia/docs/paused.dot
new file mode 100644
index 0000000..11e1777
--- /dev/null
+++ b/media/libmedia/docs/paused.dot
@@ -0,0 +1,85 @@
+digraph paused {
+initial [label="INITIAL\n\
+mIgnoreNextPausedInt = false\n\
+mPaused = false\n\
+mPausedInt = false"];
+
+resume_body [label="mIgnoreNextPausedInt = true\nif (mPaused || mPausedInt)"];
+resume_paused [label="mPaused = false\nmPausedInt = false\nsignal()"];
+resume_paused -> resume_merged;
+resume_merged [label="return"];
+
+Application -> ATstop;
+ATstop [label="AudioTrack::stop()"];
+ATstop -> pause;
+Application -> ATpause;
+ATpause [label="AudioTrack::pause()"];
+ATpause -> pause;
+ATstart -> resume;
+ATstart [label="AudioTrack::start()"];
+destructor [label="~AudioTrack()"];
+destructor -> requestExit;
+requestExit [label="AudioTrackThread::requestExit()"];
+requestExit -> resume;
+Application -> ATsetMarkerPosition
+ATsetMarkerPosition [label="AudioTrack::setMarkerPosition()\n[sets marker variables]"];
+ATsetMarkerPosition -> ATTwake
+Application -> ATsetPositionUpdatePeriod
+ATsetPositionUpdatePeriod [label="AudioTrack::setPositionUpdatePeriod()\n[sets update period variables]"];
+ATsetPositionUpdatePeriod -> ATTwake
+Application -> ATstart;
+
+resume [label="AudioTrackThread::resume()"];
+resume -> resume_body;
+
+resume_body -> resume_paused [label="true"];
+resume_body -> resume_merged [label="false"];
+
+ATTwake [label="AudioTrackThread::wake()\nif (!mPaused && mPausedInt && mPausedNs > 0)"];
+ATTwake-> ATTWake_wakeable [label="true"];
+ATTWake_wakeable [label="mIgnoreNextPausedInt = true\nmPausedInt = false\nsignal()"];
+ATTwake-> ATTWake_cannotwake [label="false"]
+ATTWake_cannotwake [label="ignore"];
+
+pause [label="mPaused = true"];
+pause -> return;
+
+threadLoop [label="AudioTrackThread::threadLoop()\nENTRY"];
+threadLoop -> threadLoop_1;
+threadLoop_1 [label="if (mPaused)"];
+threadLoop_1 -> threadLoop_1_true [label="true"];
+threadLoop_1 -> threadLoop_2 [label="false"];
+threadLoop_1_true [label="wait()\nreturn true"];
+threadLoop_2 [label="if (mIgnoreNextPausedInt)"];
+threadLoop_2 -> threadLoop_2_true [label="true"];
+threadLoop_2 -> threadLoop_3 [label="false"];
+threadLoop_2_true [label="mIgnoreNextPausedInt = false\nmPausedInt = false"];
+threadLoop_2_true -> threadLoop_3;
+threadLoop_3 [label="if (mPausedInt)"];
+threadLoop_3 -> threadLoop_3_true [label="true"];
+threadLoop_3 -> threadLoop_4 [label="false"];
+threadLoop_3_true [label="wait()\nmPausedInt = false\nreturn true"];
+threadLoop_4 [label="if (exitPending)"];
+threadLoop_4 -> threadLoop_4_true [label="true"];
+threadLoop_4 -> threadLoop_5 [label="false"];
+threadLoop_4_true [label="return false"];
+threadLoop_5 [label="ns = processAudioBuffer()"];
+threadLoop_5 -> threadLoop_6;
+threadLoop_6 [label="case ns"];
+threadLoop_6 -> threadLoop_6_0 [label="0"];
+threadLoop_6 -> threadLoop_6_NS_INACTIVE [label="NS_INACTIVE"];
+threadLoop_6 -> threadLoop_6_NS_NEVER [label="NS_NEVER"];
+threadLoop_6 -> threadLoop_6_NS_WHENEVER [label="NS_WHENEVER"];
+threadLoop_6 -> threadLoop_6_default [label="default"];
+threadLoop_6_default [label="if (ns < 0)"];
+threadLoop_6_default -> threadLoop_6_default_true [label="true"];
+threadLoop_6_default -> threadLoop_6_default_false [label="false"];
+threadLoop_6_default_true [label="FATAL"];
+threadLoop_6_default_false [label="pauseInternal(ns) [wake()-able]\nmPausedInternal = true\nmPausedNs = ns\nreturn true"];
+threadLoop_6_0 [label="return true"];
+threadLoop_6_NS_INACTIVE [label="pauseInternal()\nmPausedInternal = true\nmPausedNs = 0\nreturn true"];
+threadLoop_6_NS_NEVER [label="return false"];
+threadLoop_6_NS_WHENEVER [label="ns = 1s"];
+threadLoop_6_NS_WHENEVER -> threadLoop_6_default_false;
+
+}
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 39a239d..8e8a1ed 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -172,7 +172,7 @@
{
Mutex::Autolock lock(sServiceLock);
if (sService != 0) {
- sService->asBinder()->unlinkToDeath(this);
+ IInterface::asBinder(sService)->unlinkToDeath(this);
}
}
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 9611ac7..d1d51cc 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -59,6 +59,7 @@
mLoop = false;
mLeftVolume = mRightVolume = 1.0;
mVideoWidth = mVideoHeight = 0;
+ mPlaybackRate = 1.0;
mLockThreadId = 0;
mAudioSessionId = AudioSystem::newAudioUniqueId();
AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
@@ -240,7 +241,7 @@
// must call with lock held
status_t MediaPlayer::prepareAsync_l()
{
- if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
+ if ( (mPlayer != 0) && ( mCurrentState & (MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
mPlayer->setAudioStreamType(mStreamType);
if (mAudioAttributesParcel != NULL) {
mPlayer->setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, *mAudioAttributesParcel);
@@ -378,6 +379,24 @@
return false;
}
+status_t MediaPlayer::setPlaybackRate(float rate)
+{
+ ALOGV("setPlaybackRate: %f", rate);
+ if (rate <= 0.0) {
+ return BAD_VALUE;
+ }
+ Mutex::Autolock _l(mLock);
+ if (mPlayer != 0) {
+ if (mPlaybackRate == rate) {
+ return NO_ERROR;
+ }
+ mPlaybackRate = rate;
+ return mPlayer->setPlaybackRate(rate);
+ }
+ ALOGV("setPlaybackRate: no active player");
+ return INVALID_OPERATION;
+}
+
status_t MediaPlayer::getVideoWidth(int *w)
{
ALOGV("getVideoWidth");
@@ -414,7 +433,8 @@
status_t MediaPlayer::getDuration_l(int *msec)
{
ALOGV("getDuration_l");
- bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
+ bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
+ MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
if (mPlayer != 0 && isValidState) {
int durationMs;
status_t ret = mPlayer->getDuration(&durationMs);
@@ -443,7 +463,8 @@
status_t MediaPlayer::seekTo_l(int msec)
{
ALOGV("seekTo %d", msec);
- if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
+ if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
+ MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
if ( msec < 0 ) {
ALOGW("Attempt to seek to invalid position: %d", msec);
msec = 0;
@@ -477,7 +498,8 @@
return NO_ERROR;
}
}
- ALOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
+ ALOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(),
+ mCurrentState);
return INVALID_OPERATION;
}
@@ -835,53 +857,12 @@
}
}
-/*static*/ status_t MediaPlayer::decode(
- const sp<IMediaHTTPService> &httpService,
- const char* url,
- uint32_t *pSampleRate,
- int* pNumChannels,
- audio_format_t* pFormat,
- const sp<IMemoryHeap>& heap,
- size_t *pSize)
-{
- ALOGV("decode(%s)", url);
- status_t status;
- const sp<IMediaPlayerService>& service = getMediaPlayerService();
- if (service != 0) {
- status = service->decode(httpService, url, pSampleRate, pNumChannels, pFormat, heap, pSize);
- } else {
- ALOGE("Unable to locate media service");
- status = DEAD_OBJECT;
- }
- return status;
-
-}
-
void MediaPlayer::died()
{
ALOGV("died");
notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
}
-/*static*/ status_t MediaPlayer::decode(int fd, int64_t offset, int64_t length,
- uint32_t *pSampleRate, int* pNumChannels,
- audio_format_t* pFormat,
- const sp<IMemoryHeap>& heap, size_t *pSize)
-{
- ALOGV("decode(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
- status_t status;
- const sp<IMediaPlayerService>& service = getMediaPlayerService();
- if (service != 0) {
- status = service->decode(fd, offset, length, pSampleRate,
- pNumChannels, pFormat, heap, pSize);
- } else {
- ALOGE("Unable to locate media service");
- status = DEAD_OBJECT;
- }
- return status;
-
-}
-
status_t MediaPlayer::setNextMediaPlayer(const sp<MediaPlayer>& next) {
if (mPlayer == NULL) {
return NO_INIT;
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 1952b86..973e156 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -264,32 +264,6 @@
return ret;
}
-status_t MediaRecorder::setOutputFile(const char* path)
-{
- ALOGV("setOutputFile(%s)", path);
- if (mMediaRecorder == NULL) {
- ALOGE("media recorder is not initialized yet");
- return INVALID_OPERATION;
- }
- if (mIsOutputFileSet) {
- ALOGE("output file has already been set");
- return INVALID_OPERATION;
- }
- if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
- ALOGE("setOutputFile called in an invalid state(%d)", mCurrentState);
- return INVALID_OPERATION;
- }
-
- status_t ret = mMediaRecorder->setOutputFile(path);
- if (OK != ret) {
- ALOGV("setOutputFile failed: %d", ret);
- mCurrentState = MEDIA_RECORDER_ERROR;
- return ret;
- }
- mIsOutputFileSet = true;
- return ret;
-}
-
status_t MediaRecorder::setOutputFile(int fd, int64_t offset, int64_t length)
{
ALOGV("setOutputFile(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 2cf5710..4b31715 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -10,13 +10,12 @@
ActivityManager.cpp \
Crypto.cpp \
Drm.cpp \
+ DrmSessionManager.cpp \
HDCP.cpp \
MediaPlayerFactory.cpp \
MediaPlayerService.cpp \
MediaRecorderClient.cpp \
MetadataRetrieverClient.cpp \
- MidiFile.cpp \
- MidiMetadataRetriever.cpp \
RemoteDisplay.cpp \
SharedLibrary.cpp \
StagefrightPlayer.cpp \
diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp
index 81dad41..d4f6fab 100644
--- a/media/libmediaplayerservice/Drm.cpp
+++ b/media/libmediaplayerservice/Drm.cpp
@@ -23,6 +23,8 @@
#include "Drm.h"
+#include "DrmSessionClientInterface.h"
+#include "DrmSessionManager.h"
#include <media/drm/DrmAPI.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
@@ -33,6 +35,10 @@
namespace android {
+static inline int getCallingPid() {
+ return IPCThreadState::self()->getCallingPid();
+}
+
static bool checkPermission(const char* permissionString) {
#ifndef HAVE_ANDROID_OS
return true;
@@ -57,14 +63,41 @@
return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0;
}
+struct DrmSessionClient : public DrmSessionClientInterface {
+ DrmSessionClient(Drm* drm) : mDrm(drm) {}
+
+ virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
+ sp<Drm> drm = mDrm.promote();
+ if (drm == NULL) {
+ return true;
+ }
+ status_t err = drm->closeSession(sessionId);
+ if (err != OK) {
+ return false;
+ }
+ drm->sendEvent(DrmPlugin::kDrmPluginEventSessionReclaimed, 0, &sessionId, NULL);
+ return true;
+ }
+
+protected:
+ virtual ~DrmSessionClient() {}
+
+private:
+ wp<Drm> mDrm;
+
+ DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
+};
+
Drm::Drm()
: mInitCheck(NO_INIT),
+ mDrmSessionClient(new DrmSessionClient(this)),
mListener(NULL),
mFactory(NULL),
mPlugin(NULL) {
}
Drm::~Drm() {
+ DrmSessionManager::Instance()->removeDrm(mDrmSessionClient);
delete mPlugin;
mPlugin = NULL;
closeFactory();
@@ -84,10 +117,10 @@
{
Mutex::Autolock lock(mEventLock);
if (mListener != NULL){
- mListener->asBinder()->unlinkToDeath(this);
+ IInterface::asBinder(mListener)->unlinkToDeath(this);
}
if (listener != NULL) {
- listener->asBinder()->linkToDeath(this);
+ IInterface::asBinder(listener)->linkToDeath(this);
}
mListener = listener;
return NO_ERROR;
@@ -289,7 +322,18 @@
return -EINVAL;
}
- return mPlugin->openSession(sessionId);
+ status_t err = mPlugin->openSession(sessionId);
+ if (err == ERROR_DRM_RESOURCE_BUSY) {
+ bool retry = false;
+ retry = DrmSessionManager::Instance()->reclaimSession(getCallingPid());
+ if (retry) {
+ err = mPlugin->openSession(sessionId);
+ }
+ }
+ if (err == OK) {
+ DrmSessionManager::Instance()->addSession(getCallingPid(), mDrmSessionClient, sessionId);
+ }
+ return err;
}
status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
@@ -303,7 +347,11 @@
return -EINVAL;
}
- return mPlugin->closeSession(sessionId);
+ status_t err = mPlugin->closeSession(sessionId);
+ if (err == OK) {
+ DrmSessionManager::Instance()->removeSession(sessionId);
+ }
+ return err;
}
status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId,
@@ -321,6 +369,8 @@
return -EINVAL;
}
+ DrmSessionManager::Instance()->useSession(sessionId);
+
return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType,
optionalParameters, request, defaultUrl);
}
@@ -338,6 +388,8 @@
return -EINVAL;
}
+ DrmSessionManager::Instance()->useSession(sessionId);
+
return mPlugin->provideKeyResponse(sessionId, response, keySetId);
}
@@ -367,6 +419,8 @@
return -EINVAL;
}
+ DrmSessionManager::Instance()->useSession(sessionId);
+
return mPlugin->restoreKeys(sessionId, keySetId);
}
@@ -382,6 +436,8 @@
return -EINVAL;
}
+ DrmSessionManager::Instance()->useSession(sessionId);
+
return mPlugin->queryKeyStatus(sessionId, infoMap);
}
@@ -561,6 +617,8 @@
return -EINVAL;
}
+ DrmSessionManager::Instance()->useSession(sessionId);
+
return mPlugin->setCipherAlgorithm(sessionId, algorithm);
}
@@ -576,6 +634,8 @@
return -EINVAL;
}
+ DrmSessionManager::Instance()->useSession(sessionId);
+
return mPlugin->setMacAlgorithm(sessionId, algorithm);
}
@@ -594,6 +654,8 @@
return -EINVAL;
}
+ DrmSessionManager::Instance()->useSession(sessionId);
+
return mPlugin->encrypt(sessionId, keyId, input, iv, output);
}
@@ -612,6 +674,8 @@
return -EINVAL;
}
+ DrmSessionManager::Instance()->useSession(sessionId);
+
return mPlugin->decrypt(sessionId, keyId, input, iv, output);
}
@@ -629,6 +693,8 @@
return -EINVAL;
}
+ DrmSessionManager::Instance()->useSession(sessionId);
+
return mPlugin->sign(sessionId, keyId, message, signature);
}
@@ -647,6 +713,8 @@
return -EINVAL;
}
+ DrmSessionManager::Instance()->useSession(sessionId);
+
return mPlugin->verify(sessionId, keyId, message, signature, match);
}
@@ -669,6 +737,8 @@
return -EPERM;
}
+ DrmSessionManager::Instance()->useSession(sessionId);
+
return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature);
}
diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h
index 0e1eb2c..0cea639 100644
--- a/media/libmediaplayerservice/Drm.h
+++ b/media/libmediaplayerservice/Drm.h
@@ -28,6 +28,7 @@
struct DrmFactory;
struct DrmPlugin;
+struct DrmSessionClientInterface;
struct Drm : public BnDrm,
public IBinder::DeathRecipient,
@@ -138,6 +139,8 @@
status_t mInitCheck;
+ sp<DrmSessionClientInterface> mDrmSessionClient;
+
sp<IDrmClient> mListener;
mutable Mutex mEventLock;
mutable Mutex mNotifyLock;
diff --git a/media/libmediaplayerservice/DrmSessionClientInterface.h b/media/libmediaplayerservice/DrmSessionClientInterface.h
new file mode 100644
index 0000000..17faf08
--- /dev/null
+++ b/media/libmediaplayerservice/DrmSessionClientInterface.h
@@ -0,0 +1,34 @@
+/*
+ * 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 DRM_PROXY_INTERFACE_H_
+#define DRM_PROXY_INTERFACE_H_
+
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+struct DrmSessionClientInterface : public RefBase {
+ virtual bool reclaimSession(const Vector<uint8_t>& sessionId) = 0;
+
+protected:
+ virtual ~DrmSessionClientInterface() {}
+};
+
+} // namespace android
+
+#endif // DRM_PROXY_INTERFACE_H_
diff --git a/media/libmediaplayerservice/DrmSessionManager.cpp b/media/libmediaplayerservice/DrmSessionManager.cpp
new file mode 100644
index 0000000..6e17eb1
--- /dev/null
+++ b/media/libmediaplayerservice/DrmSessionManager.cpp
@@ -0,0 +1,271 @@
+/*
+ * 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"
+#include <utils/Log.h>
+
+#include "DrmSessionManager.h"
+
+#include "DrmSessionClientInterface.h"
+#include "ProcessInfoInterface.h"
+#include <binder/IPCThreadState.h>
+#include <binder/IProcessInfoService.h>
+#include <binder/IServiceManager.h>
+#include <unistd.h>
+#include <utils/String8.h>
+
+namespace android {
+
+static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) {
+ String8 sessionIdStr;
+ for (size_t i = 0; i < sessionId.size(); ++i) {
+ sessionIdStr.appendFormat("%u ", sessionId[i]);
+ }
+ return sessionIdStr;
+}
+
+struct ProcessInfo : public ProcessInfoInterface {
+ ProcessInfo() {}
+
+ virtual bool getPriority(int pid, int* priority) {
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("processinfo"));
+ sp<IProcessInfoService> service = interface_cast<IProcessInfoService>(binder);
+
+ size_t length = 1;
+ int32_t states;
+ status_t err = service->getProcessStatesFromPids(length, &pid, &states);
+ if (err != OK) {
+ ALOGE("getProcessStatesFromPids failed");
+ return false;
+ }
+ ALOGV("pid %d states %d", pid, states);
+ if (states < 0) {
+ return false;
+ }
+
+ // Use process state as the priority. Lower the value, higher the priority.
+ *priority = states;
+ return true;
+ }
+
+protected:
+ virtual ~ProcessInfo() {}
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(ProcessInfo);
+};
+
+bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2) {
+ if (sessionId1.size() != sessionId2.size()) {
+ return false;
+ }
+ for (size_t i = 0; i < sessionId1.size(); ++i) {
+ if (sessionId1[i] != sessionId2[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+sp<DrmSessionManager> DrmSessionManager::Instance() {
+ static sp<DrmSessionManager> drmSessionManager = new DrmSessionManager();
+ return drmSessionManager;
+}
+
+DrmSessionManager::DrmSessionManager()
+ : mProcessInfo(new ProcessInfo()),
+ mTime(0) {}
+
+DrmSessionManager::DrmSessionManager(sp<ProcessInfoInterface> processInfo)
+ : mProcessInfo(processInfo),
+ mTime(0) {}
+
+DrmSessionManager::~DrmSessionManager() {}
+
+void DrmSessionManager::addSession(
+ int pid, sp<DrmSessionClientInterface> drm, const Vector<uint8_t> &sessionId) {
+ ALOGV("addSession(pid %d, drm %p, sessionId %s)", pid, drm.get(),
+ GetSessionIdString(sessionId).string());
+
+ Mutex::Autolock lock(mLock);
+ SessionInfo info;
+ info.drm = drm;
+ info.sessionId = sessionId;
+ info.timeStamp = getTime_l();
+ ssize_t index = mSessionMap.indexOfKey(pid);
+ if (index < 0) {
+ // new pid
+ SessionInfos infosForPid;
+ infosForPid.push_back(info);
+ mSessionMap.add(pid, infosForPid);
+ } else {
+ mSessionMap.editValueAt(index).push_back(info);
+ }
+}
+
+void DrmSessionManager::useSession(const Vector<uint8_t> &sessionId) {
+ ALOGV("useSession(%s)", GetSessionIdString(sessionId).string());
+
+ Mutex::Autolock lock(mLock);
+ for (size_t i = 0; i < mSessionMap.size(); ++i) {
+ SessionInfos& infos = mSessionMap.editValueAt(i);
+ for (size_t j = 0; j < infos.size(); ++j) {
+ SessionInfo& info = infos.editItemAt(j);
+ if (isEqualSessionId(sessionId, info.sessionId)) {
+ info.timeStamp = getTime_l();
+ return;
+ }
+ }
+ }
+}
+
+void DrmSessionManager::removeSession(const Vector<uint8_t> &sessionId) {
+ ALOGV("removeSession(%s)", GetSessionIdString(sessionId).string());
+
+ Mutex::Autolock lock(mLock);
+ for (size_t i = 0; i < mSessionMap.size(); ++i) {
+ SessionInfos& infos = mSessionMap.editValueAt(i);
+ for (size_t j = 0; j < infos.size(); ++j) {
+ if (isEqualSessionId(sessionId, infos[j].sessionId)) {
+ infos.removeAt(j);
+ return;
+ }
+ }
+ }
+}
+
+void DrmSessionManager::removeDrm(sp<DrmSessionClientInterface> drm) {
+ ALOGV("removeDrm(%p)", drm.get());
+
+ Mutex::Autolock lock(mLock);
+ bool found = false;
+ for (size_t i = 0; i < mSessionMap.size(); ++i) {
+ SessionInfos& infos = mSessionMap.editValueAt(i);
+ for (size_t j = 0; j < infos.size();) {
+ if (infos[j].drm == drm) {
+ ALOGV("removed session (%s)", GetSessionIdString(infos[j].sessionId).string());
+ j = infos.removeAt(j);
+ found = true;
+ } else {
+ ++j;
+ }
+ }
+ if (found) {
+ break;
+ }
+ }
+}
+
+bool DrmSessionManager::reclaimSession(int callingPid) {
+ ALOGV("reclaimSession(%d)", callingPid);
+
+ sp<DrmSessionClientInterface> drm;
+ Vector<uint8_t> sessionId;
+ int lowestPriorityPid;
+ int lowestPriority;
+ {
+ Mutex::Autolock lock(mLock);
+ int callingPriority;
+ if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
+ return false;
+ }
+ if (!getLowestPriority_l(&lowestPriorityPid, &lowestPriority)) {
+ return false;
+ }
+ if (lowestPriority <= callingPriority) {
+ return false;
+ }
+
+ if (!getLeastUsedSession_l(lowestPriorityPid, &drm, &sessionId)) {
+ return false;
+ }
+ }
+
+ if (drm == NULL) {
+ return false;
+ }
+
+ ALOGV("reclaim session(%s) opened by pid %d",
+ GetSessionIdString(sessionId).string(), lowestPriorityPid);
+
+ return drm->reclaimSession(sessionId);
+}
+
+int64_t DrmSessionManager::getTime_l() {
+ return mTime++;
+}
+
+bool DrmSessionManager::getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority) {
+ int pid = -1;
+ int priority = -1;
+ for (size_t i = 0; i < mSessionMap.size(); ++i) {
+ if (mSessionMap.valueAt(i).size() == 0) {
+ // no opened session by this process.
+ continue;
+ }
+ int tempPid = mSessionMap.keyAt(i);
+ int tempPriority;
+ if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
+ // shouldn't happen.
+ return false;
+ }
+ if (pid == -1) {
+ pid = tempPid;
+ priority = tempPriority;
+ } else {
+ if (tempPriority > priority) {
+ pid = tempPid;
+ priority = tempPriority;
+ }
+ }
+ }
+ if (pid != -1) {
+ *lowestPriorityPid = pid;
+ *lowestPriority = priority;
+ }
+ return (pid != -1);
+}
+
+bool DrmSessionManager::getLeastUsedSession_l(
+ int pid, sp<DrmSessionClientInterface>* drm, Vector<uint8_t>* sessionId) {
+ ssize_t index = mSessionMap.indexOfKey(pid);
+ if (index < 0) {
+ return false;
+ }
+
+ int leastUsedIndex = -1;
+ int64_t minTs = LLONG_MAX;
+ const SessionInfos& infos = mSessionMap.valueAt(index);
+ for (size_t j = 0; j < infos.size(); ++j) {
+ if (leastUsedIndex == -1) {
+ leastUsedIndex = j;
+ minTs = infos[j].timeStamp;
+ } else {
+ if (infos[j].timeStamp < minTs) {
+ leastUsedIndex = j;
+ minTs = infos[j].timeStamp;
+ }
+ }
+ }
+ if (leastUsedIndex != -1) {
+ *drm = infos[leastUsedIndex].drm;
+ *sessionId = infos[leastUsedIndex].sessionId;
+ }
+ return (leastUsedIndex != -1);
+}
+
+} // namespace android
diff --git a/media/libmediaplayerservice/DrmSessionManager.h b/media/libmediaplayerservice/DrmSessionManager.h
new file mode 100644
index 0000000..ba5c268
--- /dev/null
+++ b/media/libmediaplayerservice/DrmSessionManager.h
@@ -0,0 +1,77 @@
+/*
+ * 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 DRM_SESSION_MANAGER_H_
+
+#define DRM_SESSION_MANAGER_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class DrmSessionManagerTest;
+struct DrmSessionClientInterface;
+struct ProcessInfoInterface;
+
+bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2);
+
+struct SessionInfo {
+ sp<DrmSessionClientInterface> drm;
+ Vector<uint8_t> sessionId;
+ int64_t timeStamp;
+};
+
+typedef Vector<SessionInfo > SessionInfos;
+typedef KeyedVector<int, SessionInfos > PidSessionInfosMap;
+
+struct DrmSessionManager : public RefBase {
+ static sp<DrmSessionManager> Instance();
+
+ DrmSessionManager();
+ DrmSessionManager(sp<ProcessInfoInterface> processInfo);
+
+ void addSession(int pid, sp<DrmSessionClientInterface> drm, const Vector<uint8_t>& sessionId);
+ void useSession(const Vector<uint8_t>& sessionId);
+ void removeSession(const Vector<uint8_t>& sessionId);
+ void removeDrm(sp<DrmSessionClientInterface> drm);
+ bool reclaimSession(int callingPid);
+
+protected:
+ virtual ~DrmSessionManager();
+
+private:
+ friend class DrmSessionManagerTest;
+
+ int64_t getTime_l();
+ bool getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority);
+ bool getLeastUsedSession_l(
+ int pid, sp<DrmSessionClientInterface>* drm, Vector<uint8_t>* sessionId);
+
+ sp<ProcessInfoInterface> mProcessInfo;
+ mutable Mutex mLock;
+ PidSessionInfosMap mSessionMap;
+ int64_t mTime;
+
+ DISALLOW_EVIL_CONSTRUCTORS(DrmSessionManager);
+};
+
+} // namespace android
+
+#endif // DRM_SESSION_MANAGER_H_
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index aeefb4c..48884b9 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -15,6 +15,7 @@
** limitations under the License.
*/
+//#define LOG_NDEBUG 0
#define LOG_TAG "MediaPlayerFactory"
#include <utils/Log.h>
@@ -29,7 +30,6 @@
#include "MediaPlayerFactory.h"
-#include "MidiFile.h"
#include "TestPlayerStub.h"
#include "StagefrightPlayer.h"
#include "nuplayer/NuPlayerDriver.h"
@@ -279,75 +279,6 @@
}
};
-class SonivoxPlayerFactory : public MediaPlayerFactory::IFactory {
- public:
- virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
- const char* url,
- float curScore) {
- static const float kOurScore = 0.4;
- static const char* const FILE_EXTS[] = { ".mid",
- ".midi",
- ".smf",
- ".xmf",
- ".mxmf",
- ".imy",
- ".rtttl",
- ".rtx",
- ".ota" };
- if (kOurScore <= curScore)
- return 0.0;
-
- // use MidiFile for MIDI extensions
- int lenURL = strlen(url);
- for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
- int len = strlen(FILE_EXTS[i]);
- int start = lenURL - len;
- if (start > 0) {
- if (!strncasecmp(url + start, FILE_EXTS[i], len)) {
- return kOurScore;
- }
- }
- }
-
- return 0.0;
- }
-
- virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
- int fd,
- int64_t offset,
- int64_t length,
- float curScore) {
- static const float kOurScore = 0.8;
-
- if (kOurScore <= curScore)
- return 0.0;
-
- // Some kind of MIDI?
- EAS_DATA_HANDLE easdata;
- if (EAS_Init(&easdata) == EAS_SUCCESS) {
- EAS_FILE locator;
- locator.path = NULL;
- locator.fd = fd;
- locator.offset = offset;
- locator.length = length;
- EAS_HANDLE eashandle;
- if (EAS_OpenFile(easdata, &locator, &eashandle) == EAS_SUCCESS) {
- EAS_CloseFile(easdata, eashandle);
- EAS_Shutdown(easdata);
- return kOurScore;
- }
- EAS_Shutdown(easdata);
- }
-
- return 0.0;
- }
-
- virtual sp<MediaPlayerBase> createPlayer() {
- ALOGV(" create MidiFile");
- return new MidiFile();
- }
-};
-
class TestPlayerFactory : public MediaPlayerFactory::IFactory {
public:
virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
@@ -374,7 +305,6 @@
registerFactory_l(new StagefrightPlayerFactory(), STAGEFRIGHT_PLAYER);
registerFactory_l(new NuPlayerFactory(), NU_PLAYER);
- registerFactory_l(new SonivoxPlayerFactory(), SONIVOX_PLAYER);
registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);
sInitComplete = true;
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index d461af3..f113e21 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -59,6 +59,7 @@
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooperRoster.h>
#include <system/audio.h>
@@ -70,7 +71,6 @@
#include "MetadataRetrieverClient.h"
#include "MediaPlayerFactory.h"
-#include "MidiFile.h"
#include "TestPlayerStub.h"
#include "StagefrightPlayer.h"
#include "nuplayer/NuPlayerDriver.h"
@@ -248,6 +248,9 @@
namespace android {
+extern ALooperRoster gLooperRoster;
+
+
static bool checkPermission(const char* permissionString) {
#ifndef HAVE_ANDROID_OS
return true;
@@ -287,8 +290,9 @@
const sp<IServiceManager> sm(defaultServiceManager());
if (sm != NULL) {
const String16 name("batterystats");
+ // use checkService() to avoid blocking if service is not up yet
sp<IBatteryStats> batteryStats =
- interface_cast<IBatteryStats>(sm->getService(name));
+ interface_cast<IBatteryStats>(sm->checkService(name));
if (batteryStats != NULL) {
batteryStats->noteResetVideo();
batteryStats->noteResetAudio();
@@ -385,28 +389,6 @@
return new RemoteDisplay(client, iface.string());
}
-status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& /*args*/) const
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- result.append(" AudioCache\n");
- if (mHeap != 0) {
- snprintf(buffer, 255, " heap base(%p), size(%zu), flags(%d)\n",
- mHeap->getBase(), mHeap->getSize(), mHeap->getFlags());
- result.append(buffer);
- }
- snprintf(buffer, 255, " msec per frame(%f), channel count(%d), format(%d), frame count(%zd)\n",
- mMsecsPerFrame, mChannelCount, mFormat, mFrameCount);
- result.append(buffer);
- snprintf(buffer, 255, " sample rate(%d), size(%d), error(%d), command complete(%s)\n",
- mSampleRate, mSize, mError, mCommandComplete?"true":"false");
- result.append(buffer);
- ::write(fd, result.string(), result.size());
- return NO_ERROR;
-}
-
status_t MediaPlayerService::AudioOutput::dump(int fd, const Vector<String16>& args) const
{
const size_t SIZE = 256;
@@ -451,11 +433,18 @@
return NO_ERROR;
}
+/**
+ * The only arguments this understands right now are -c, -von and -voff,
+ * which are parsed by ALooperRoster::dump()
+ */
status_t MediaPlayerService::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
+ SortedVector< sp<Client> > clients; //to serialise the mutex unlock & client destruction.
+ SortedVector< sp<MediaRecorderClient> > mediaRecorderClients;
+
if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
snprintf(buffer, SIZE, "Permission Denial: "
"can't dump MediaPlayerService from pid=%d, uid=%d\n",
@@ -467,6 +456,7 @@
for (int i = 0, n = mClients.size(); i < n; ++i) {
sp<Client> c = mClients[i].promote();
if (c != 0) c->dump(fd, args);
+ clients.add(c);
}
if (mMediaRecorderClients.size() == 0) {
result.append(" No media recorder client\n\n");
@@ -479,12 +469,13 @@
write(fd, result.string(), result.size());
result = "\n";
c->dump(fd, args);
+ mediaRecorderClients.add(c);
}
}
}
result.append(" Files opened and/or mapped:\n");
- snprintf(buffer, SIZE, "/proc/%d/maps", gettid());
+ snprintf(buffer, SIZE, "/proc/%d/maps", getpid());
FILE *f = fopen(buffer, "r");
if (f) {
while (!feof(f)) {
@@ -504,13 +495,13 @@
result.append("\n");
}
- snprintf(buffer, SIZE, "/proc/%d/fd", gettid());
+ snprintf(buffer, SIZE, "/proc/%d/fd", getpid());
DIR *d = opendir(buffer);
if (d) {
struct dirent *ent;
while((ent = readdir(d)) != NULL) {
if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
- snprintf(buffer, SIZE, "/proc/%d/fd/%s", gettid(), ent->d_name);
+ snprintf(buffer, SIZE, "/proc/%d/fd/%s", getpid(), ent->d_name);
struct stat s;
if (lstat(buffer, &s) == 0) {
if ((s.st_mode & S_IFMT) == S_IFLNK) {
@@ -551,6 +542,8 @@
result.append("\n");
}
+ gLooperRoster.dump(fd, args);
+
bool dumpMem = false;
for (size_t i = 0; i < args.size(); i++) {
if (args[i] == String16("-m")) {
@@ -817,8 +810,7 @@
sp<MediaPlayerBase> p = getPlayer();
if (p == 0) return UNKNOWN_ERROR;
- sp<IBinder> binder(bufferProducer == NULL ? NULL :
- bufferProducer->asBinder());
+ sp<IBinder> binder(IInterface::asBinder(bufferProducer));
if (mConnectedWindowBinder == binder) {
return OK;
}
@@ -975,6 +967,14 @@
return NO_ERROR;
}
+status_t MediaPlayerService::Client::setPlaybackRate(float rate)
+{
+ ALOGV("[%d] setPlaybackRate(%f)", mConnId, rate);
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == 0) return UNKNOWN_ERROR;
+ return p->setPlaybackRate(rate);
+}
+
status_t MediaPlayerService::Client::getCurrentPosition(int *msec)
{
ALOGV("getCurrentPosition");
@@ -1281,129 +1281,6 @@
}
#endif
-status_t MediaPlayerService::decode(
- const sp<IMediaHTTPService> &httpService,
- const char* url,
- uint32_t *pSampleRate,
- int* pNumChannels,
- audio_format_t* pFormat,
- const sp<IMemoryHeap>& heap,
- size_t *pSize)
-{
- ALOGV("decode(%s)", url);
- sp<MediaPlayerBase> player;
- status_t status = BAD_VALUE;
-
- // Protect our precious, precious DRMd ringtones by only allowing
- // decoding of http, but not filesystem paths or content Uris.
- // If the application wants to decode those, it should open a
- // filedescriptor for them and use that.
- if (url != NULL && strncmp(url, "http://", 7) != 0) {
- ALOGD("Can't decode %s by path, use filedescriptor instead", url);
- return BAD_VALUE;
- }
-
- player_type playerType =
- MediaPlayerFactory::getPlayerType(NULL /* client */, url);
- ALOGV("player type = %d", playerType);
-
- // create the right type of player
- sp<AudioCache> cache = new AudioCache(heap);
- player = MediaPlayerFactory::createPlayer(playerType, cache.get(), cache->notify);
- if (player == NULL) goto Exit;
- if (player->hardwareOutput()) goto Exit;
-
- static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache);
-
- // set data source
- if (player->setDataSource(httpService, url) != NO_ERROR) goto Exit;
-
- ALOGV("prepare");
- player->prepareAsync();
-
- ALOGV("wait for prepare");
- if (cache->wait() != NO_ERROR) goto Exit;
-
- ALOGV("start");
- player->start();
-
- ALOGV("wait for playback complete");
- cache->wait();
- // in case of error, return what was successfully decoded.
- if (cache->size() == 0) {
- goto Exit;
- }
-
- *pSize = cache->size();
- *pSampleRate = cache->sampleRate();
- *pNumChannels = cache->channelCount();
- *pFormat = cache->format();
- ALOGV("return size %d sampleRate=%u, channelCount = %d, format = %d",
- *pSize, *pSampleRate, *pNumChannels, *pFormat);
- status = NO_ERROR;
-
-Exit:
- if (player != 0) player->reset();
- return status;
-}
-
-status_t MediaPlayerService::decode(int fd, int64_t offset, int64_t length,
- uint32_t *pSampleRate, int* pNumChannels,
- audio_format_t* pFormat,
- const sp<IMemoryHeap>& heap, size_t *pSize)
-{
- ALOGV("decode(%d, %lld, %lld)", fd, offset, length);
- sp<MediaPlayerBase> player;
- status_t status = BAD_VALUE;
-
- player_type playerType = MediaPlayerFactory::getPlayerType(NULL /* client */,
- fd,
- offset,
- length);
- ALOGV("player type = %d", playerType);
-
- // create the right type of player
- sp<AudioCache> cache = new AudioCache(heap);
- player = MediaPlayerFactory::createPlayer(playerType, cache.get(), cache->notify);
- if (player == NULL) goto Exit;
- if (player->hardwareOutput()) goto Exit;
-
- static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache);
-
- // set data source
- if (player->setDataSource(fd, offset, length) != NO_ERROR) goto Exit;
-
- ALOGV("prepare");
- player->prepareAsync();
-
- ALOGV("wait for prepare");
- if (cache->wait() != NO_ERROR) goto Exit;
-
- ALOGV("start");
- player->start();
-
- ALOGV("wait for playback complete");
- cache->wait();
- // in case of error, return what was successfully decoded.
- if (cache->size() == 0) {
- goto Exit;
- }
-
- *pSize = cache->size();
- *pSampleRate = cache->sampleRate();
- *pNumChannels = cache->channelCount();
- *pFormat = cache->format();
- ALOGV("return size %d, sampleRate=%u, channelCount = %d, format = %d",
- *pSize, *pSampleRate, *pNumChannels, *pFormat);
- status = NO_ERROR;
-
-Exit:
- if (player != 0) player->reset();
- ::close(fd);
- return status;
-}
-
-
#undef LOG_TAG
#define LOG_TAG "AudioSink"
MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid,
@@ -1801,13 +1678,13 @@
}
}
-ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
+ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size, bool blocking)
{
LOG_ALWAYS_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
//ALOGV("write(%p, %u)", buffer, size);
if (mTrack != 0) {
- ssize_t ret = mTrack->write(buffer, size);
+ ssize_t ret = mTrack->write(buffer, size, blocking);
if (ret >= 0) {
mBytesWritten += ret;
}
@@ -1953,47 +1830,6 @@
return mTrack->getSampleRate();
}
-#undef LOG_TAG
-#define LOG_TAG "AudioCache"
-MediaPlayerService::AudioCache::AudioCache(const sp<IMemoryHeap>& heap) :
- mHeap(heap), mChannelCount(0), mFrameCount(1024), mSampleRate(0), mSize(0),
- mFrameSize(1), mError(NO_ERROR), mCommandComplete(false)
-{
-}
-
-uint32_t MediaPlayerService::AudioCache::latency () const
-{
- return 0;
-}
-
-float MediaPlayerService::AudioCache::msecsPerFrame() const
-{
- return mMsecsPerFrame;
-}
-
-status_t MediaPlayerService::AudioCache::getPosition(uint32_t *position) const
-{
- if (position == 0) return BAD_VALUE;
- *position = mSize / mFrameSize;
- return NO_ERROR;
-}
-
-status_t MediaPlayerService::AudioCache::getTimestamp(AudioTimestamp &ts) const
-{
- ts.mPosition = mSize / mFrameSize;
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- ts.mTime.tv_sec = now / 1000000000LL;
- ts.mTime.tv_nsec = now - (1000000000LL * ts.mTime.tv_sec);
- return NO_ERROR;
-}
-
-status_t MediaPlayerService::AudioCache::getFramesWritten(uint32_t *written) const
-{
- if (written == 0) return BAD_VALUE;
- *written = mSize / mFrameSize;
- return NO_ERROR;
-}
-
////////////////////////////////////////////////////////////////////////////////
struct CallbackThread : public Thread {
@@ -2061,139 +1897,6 @@
////////////////////////////////////////////////////////////////////////////////
-status_t MediaPlayerService::AudioCache::open(
- uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
- audio_format_t format, int bufferCount,
- AudioCallback cb, void *cookie, audio_output_flags_t /*flags*/,
- const audio_offload_info_t* /*offloadInfo*/)
-{
- ALOGV("open(%u, %d, 0x%x, %d, %d)", sampleRate, channelCount, channelMask, format, bufferCount);
- if (mHeap->getHeapID() < 0) {
- return NO_INIT;
- }
-
- mSampleRate = sampleRate;
- mChannelCount = (uint16_t)channelCount;
- mFormat = format;
- mMsecsPerFrame = 1.e3 / (float) sampleRate;
- mFrameSize = audio_is_linear_pcm(mFormat)
- ? mChannelCount * audio_bytes_per_sample(mFormat) : 1;
- mFrameCount = mHeap->getSize() / mFrameSize;
-
- if (cb != NULL) {
- mCallbackThread = new CallbackThread(this, cb, cookie);
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayerService::AudioCache::start() {
- if (mCallbackThread != NULL) {
- mCallbackThread->run("AudioCache callback");
- }
- return NO_ERROR;
-}
-
-void MediaPlayerService::AudioCache::stop() {
- if (mCallbackThread != NULL) {
- mCallbackThread->requestExitAndWait();
- }
-}
-
-ssize_t MediaPlayerService::AudioCache::write(const void* buffer, size_t size)
-{
- ALOGV("write(%p, %u)", buffer, size);
- if ((buffer == 0) || (size == 0)) return size;
-
- uint8_t* p = static_cast<uint8_t*>(mHeap->getBase());
- if (p == NULL) return NO_INIT;
- p += mSize;
- ALOGV("memcpy(%p, %p, %u)", p, buffer, size);
-
- bool overflow = mSize + size > mHeap->getSize();
- if (overflow) {
- ALOGE("Heap size overflow! req size: %d, max size: %d", (mSize + size), mHeap->getSize());
- size = mHeap->getSize() - mSize;
- }
- size -= size % mFrameSize; // consume only integral amounts of frame size
- memcpy(p, buffer, size);
- mSize += size;
-
- if (overflow) {
- // Signal heap filled here (last frame may be truncated).
- // After this point, no more data should be written as the
- // heap is filled and the AudioCache should be effectively
- // immutable with respect to future writes.
- //
- // It is thus safe for another thread to read the AudioCache.
- Mutex::Autolock lock(mLock);
- mCommandComplete = true;
- mSignal.signal();
- }
- return size;
-}
-
-// call with lock held
-status_t MediaPlayerService::AudioCache::wait()
-{
- Mutex::Autolock lock(mLock);
- while (!mCommandComplete) {
- mSignal.wait(mLock);
- }
- mCommandComplete = false;
-
- if (mError == NO_ERROR) {
- ALOGV("wait - success");
- } else {
- ALOGV("wait - error");
- }
- return mError;
-}
-
-void MediaPlayerService::AudioCache::notify(
- void* cookie, int msg, int ext1, int ext2, const Parcel* /*obj*/)
-{
- ALOGV("notify(%p, %d, %d, %d)", cookie, msg, ext1, ext2);
- AudioCache* p = static_cast<AudioCache*>(cookie);
-
- // ignore buffering messages
- switch (msg)
- {
- case MEDIA_ERROR:
- ALOGE("Error %d, %d occurred", ext1, ext2);
- break;
- case MEDIA_PREPARED:
- ALOGV("prepared");
- break;
- case MEDIA_PLAYBACK_COMPLETE:
- ALOGV("playback complete");
- break;
- default:
- ALOGV("ignored");
- return;
- }
-
- // wake up thread
- Mutex::Autolock lock(p->mLock);
- if (msg == MEDIA_ERROR) {
- p->mError = ext1;
- }
- p->mCommandComplete = true;
- p->mSignal.signal();
-}
-
-int MediaPlayerService::AudioCache::getSessionId() const
-{
- return 0;
-}
-
-uint32_t MediaPlayerService::AudioCache::getSampleRate() const
-{
- if (mMsecsPerFrame == 0) {
- return 0;
- }
- return (uint32_t)(1.e3 / mMsecsPerFrame);
-}
-
void MediaPlayerService::addBatteryData(uint32_t params)
{
Mutex::Autolock lock(mLock);
@@ -2237,7 +1940,7 @@
return;
}
- // an sudio stream is started
+ // an audio stream is started
if (params & kBatteryDataAudioFlingerStart) {
// record the start time only if currently no other audio
// is being played
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 3b96e88..4ce4b81 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -77,7 +77,6 @@
virtual ~AudioOutput();
virtual bool ready() const { return mTrack != 0; }
- virtual bool realtime() const { return true; }
virtual ssize_t bufferSize() const;
virtual ssize_t frameCount() const;
virtual ssize_t channelCount() const;
@@ -98,7 +97,7 @@
const audio_offload_info_t *offloadInfo = NULL);
virtual status_t start();
- virtual ssize_t write(const void* buffer, size_t size);
+ virtual ssize_t write(const void* buffer, size_t size, bool blocking = true);
virtual void stop();
virtual void flush();
virtual void pause();
@@ -184,75 +183,6 @@
}; // AudioOutput
- class AudioCache : public MediaPlayerBase::AudioSink
- {
- public:
- AudioCache(const sp<IMemoryHeap>& heap);
- virtual ~AudioCache() {}
-
- virtual bool ready() const { return (mChannelCount > 0) && (mHeap->getHeapID() > 0); }
- virtual bool realtime() const { return false; }
- virtual ssize_t bufferSize() const { return frameSize() * mFrameCount; }
- virtual ssize_t frameCount() const { return mFrameCount; }
- virtual ssize_t channelCount() const { return (ssize_t)mChannelCount; }
- virtual ssize_t frameSize() const { return (ssize_t)mFrameSize; }
- virtual uint32_t latency() const;
- virtual float msecsPerFrame() const;
- virtual status_t getPosition(uint32_t *position) const;
- virtual status_t getTimestamp(AudioTimestamp &ts) const;
- virtual status_t getFramesWritten(uint32_t *frameswritten) const;
- virtual int getSessionId() const;
- virtual uint32_t getSampleRate() const;
-
- virtual status_t open(
- uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
- audio_format_t format, int bufferCount = 1,
- AudioCallback cb = NULL, void *cookie = NULL,
- audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
- const audio_offload_info_t *offloadInfo = NULL);
-
- virtual status_t start();
- virtual ssize_t write(const void* buffer, size_t size);
- virtual void stop();
- virtual void flush() {}
- virtual void pause() {}
- virtual void close() {}
- void setAudioStreamType(audio_stream_type_t streamType __unused) {}
- // stream type is not used for AudioCache
- virtual audio_stream_type_t getAudioStreamType() const { return AUDIO_STREAM_DEFAULT; }
-
- void setVolume(float left __unused, float right __unused) {}
- virtual status_t setPlaybackRatePermille(int32_t ratePermille __unused) { return INVALID_OPERATION; }
- uint32_t sampleRate() const { return mSampleRate; }
- audio_format_t format() const { return mFormat; }
- size_t size() const { return mSize; }
- status_t wait();
-
- sp<IMemoryHeap> getHeap() const { return mHeap; }
-
- static void notify(void* cookie, int msg,
- int ext1, int ext2, const Parcel *obj);
- virtual status_t dump(int fd, const Vector<String16>& args) const;
-
- private:
- AudioCache();
-
- Mutex mLock;
- Condition mSignal;
- sp<IMemoryHeap> mHeap;
- float mMsecsPerFrame;
- uint16_t mChannelCount;
- audio_format_t mFormat;
- ssize_t mFrameCount;
- uint32_t mSampleRate;
- uint32_t mSize;
- size_t mFrameSize;
- int mError;
- bool mCommandComplete;
-
- sp<Thread> mCallbackThread;
- }; // AudioCache
-
public:
static void instantiate();
@@ -263,19 +193,6 @@
virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client, int audioSessionId);
- virtual status_t decode(
- const sp<IMediaHTTPService> &httpService,
- const char* url,
- uint32_t *pSampleRate,
- int* pNumChannels,
- audio_format_t* pFormat,
- const sp<IMemoryHeap>& heap,
- size_t *pSize);
-
- virtual status_t decode(int fd, int64_t offset, int64_t length,
- uint32_t *pSampleRate, int* pNumChannels,
- audio_format_t* pFormat,
- const sp<IMemoryHeap>& heap, size_t *pSize);
virtual sp<IMediaCodecList> getCodecList() const;
virtual sp<IOMX> getOMX();
virtual sp<ICrypto> makeCrypto();
@@ -344,6 +261,7 @@
virtual status_t stop();
virtual status_t pause();
virtual status_t isPlaying(bool* state);
+ virtual status_t setPlaybackRate(float rate);
virtual status_t seekTo(int msec);
virtual status_t getCurrentPosition(int* msec);
virtual status_t getDuration(int* msec);
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 194abbb..4d4de9b 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -154,17 +154,6 @@
return mRecorder->setAudioEncoder((audio_encoder)ae);
}
-status_t MediaRecorderClient::setOutputFile(const char* path)
-{
- ALOGV("setOutputFile(%s)", path);
- Mutex::Autolock lock(mLock);
- if (mRecorder == NULL) {
- ALOGE("recorder is not initialized");
- return NO_INIT;
- }
- return mRecorder->setOutputFile(path);
-}
-
status_t MediaRecorderClient::setOutputFile(int fd, int64_t offset, int64_t length)
{
ALOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length);
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index a65ec9f..a444b6c 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -38,7 +38,6 @@
virtual status_t setOutputFormat(int of);
virtual status_t setVideoEncoder(int ve);
virtual status_t setAudioEncoder(int ae);
- virtual status_t setOutputFile(const char* path);
virtual status_t setOutputFile(int fd, int64_t offset,
int64_t length);
virtual status_t setVideoSize(int width, int height);
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index fa28451..715cc0c 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -35,7 +35,6 @@
#include <media/MediaMetadataRetrieverInterface.h>
#include <media/MediaPlayerInterface.h>
#include <private/media/VideoFrame.h>
-#include "MidiMetadataRetriever.h"
#include "MetadataRetrieverClient.h"
#include "StagefrightMetadataRetriever.h"
#include "MediaPlayerFactory.h"
@@ -90,10 +89,6 @@
p = new StagefrightMetadataRetriever;
break;
}
- case SONIVOX_PLAYER:
- ALOGV("create midi metadata retriever");
- p = new MidiMetadataRetriever();
- break;
default:
// TODO:
// support for TEST_PLAYER
diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp
deleted file mode 100644
index 60cbd3c..0000000
--- a/media/libmediaplayerservice/MidiFile.cpp
+++ /dev/null
@@ -1,560 +0,0 @@
-/* MidiFile.cpp
-**
-** 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_NDEBUG 0
-#define LOG_TAG "MidiFile"
-#include "utils/Log.h"
-
-#include <stdio.h>
-#include <assert.h>
-#include <limits.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sched.h>
-#include <utils/threads.h>
-#include <libsonivox/eas_reverb.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <system/audio.h>
-
-#include "MidiFile.h"
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-// The midi engine buffers are a bit small (128 frames), so we batch them up
-static const int NUM_BUFFERS = 4;
-
-// TODO: Determine appropriate return codes
-static status_t ERROR_NOT_OPEN = -1;
-static status_t ERROR_OPEN_FAILED = -2;
-static status_t ERROR_EAS_FAILURE = -3;
-static status_t ERROR_ALLOCATE_FAILED = -4;
-
-static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
-
-MidiFile::MidiFile() :
- mEasData(NULL), mEasHandle(NULL), mAudioBuffer(NULL),
- mPlayTime(-1), mDuration(-1), mState(EAS_STATE_ERROR),
- mStreamType(AUDIO_STREAM_MUSIC), mLoop(false), mExit(false),
- mPaused(false), mRender(false), mTid(-1)
-{
- ALOGV("constructor");
-
- mFileLocator.path = NULL;
- mFileLocator.fd = -1;
- mFileLocator.offset = 0;
- mFileLocator.length = 0;
-
- // get the library configuration and do sanity check
- if (pLibConfig == NULL)
- pLibConfig = EAS_Config();
- if ((pLibConfig == NULL) || (LIB_VERSION != pLibConfig->libVersion)) {
- ALOGE("EAS library/header mismatch");
- goto Failed;
- }
-
- // initialize EAS library
- if (EAS_Init(&mEasData) != EAS_SUCCESS) {
- ALOGE("EAS_Init failed");
- goto Failed;
- }
-
- // select reverb preset and enable
- EAS_SetParameter(mEasData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_PRESET, EAS_PARAM_REVERB_CHAMBER);
- EAS_SetParameter(mEasData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_BYPASS, EAS_FALSE);
-
- // create playback thread
- {
- Mutex::Autolock l(mMutex);
- mThread = new MidiFileThread(this);
- mThread->run("midithread", ANDROID_PRIORITY_AUDIO);
- mCondition.wait(mMutex);
- ALOGV("thread started");
- }
-
- // indicate success
- if (mTid > 0) {
- ALOGV(" render thread(%d) started", mTid);
- mState = EAS_STATE_READY;
- }
-
-Failed:
- return;
-}
-
-status_t MidiFile::initCheck()
-{
- if (mState == EAS_STATE_ERROR) return ERROR_EAS_FAILURE;
- return NO_ERROR;
-}
-
-MidiFile::~MidiFile() {
- ALOGV("MidiFile destructor");
- release();
-}
-
-status_t MidiFile::setDataSource(
- const sp<IMediaHTTPService> & /*httpService*/,
- const char* path,
- const KeyedVector<String8, String8> *) {
- ALOGV("MidiFile::setDataSource url=%s", path);
- Mutex::Autolock lock(mMutex);
-
- // file still open?
- if (mEasHandle) {
- reset_nosync();
- }
-
- // open file and set paused state
- mFileLocator.path = strdup(path);
- mFileLocator.fd = -1;
- mFileLocator.offset = 0;
- mFileLocator.length = 0;
- EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle);
- if (result == EAS_SUCCESS) {
- updateState();
- }
-
- if (result != EAS_SUCCESS) {
- ALOGE("EAS_OpenFile failed: [%d]", (int)result);
- mState = EAS_STATE_ERROR;
- return ERROR_OPEN_FAILED;
- }
-
- mState = EAS_STATE_OPEN;
- mPlayTime = 0;
- return NO_ERROR;
-}
-
-status_t MidiFile::setDataSource(int fd, int64_t offset, int64_t length)
-{
- ALOGV("MidiFile::setDataSource fd=%d", fd);
- Mutex::Autolock lock(mMutex);
-
- // file still open?
- if (mEasHandle) {
- reset_nosync();
- }
-
- // open file and set paused state
- mFileLocator.fd = dup(fd);
- mFileLocator.offset = offset;
- mFileLocator.length = length;
- EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle);
- updateState();
-
- if (result != EAS_SUCCESS) {
- ALOGE("EAS_OpenFile failed: [%d]", (int)result);
- mState = EAS_STATE_ERROR;
- return ERROR_OPEN_FAILED;
- }
-
- mState = EAS_STATE_OPEN;
- mPlayTime = 0;
- return NO_ERROR;
-}
-
-status_t MidiFile::prepare()
-{
- ALOGV("MidiFile::prepare");
- Mutex::Autolock lock(mMutex);
- if (!mEasHandle) {
- return ERROR_NOT_OPEN;
- }
- EAS_RESULT result;
- if ((result = EAS_Prepare(mEasData, mEasHandle)) != EAS_SUCCESS) {
- ALOGE("EAS_Prepare failed: [%ld]", result);
- return ERROR_EAS_FAILURE;
- }
- updateState();
- return NO_ERROR;
-}
-
-status_t MidiFile::prepareAsync()
-{
- ALOGV("MidiFile::prepareAsync");
- status_t ret = prepare();
-
- // don't hold lock during callback
- if (ret == NO_ERROR) {
- sendEvent(MEDIA_PREPARED);
- } else {
- sendEvent(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ret);
- }
- return ret;
-}
-
-status_t MidiFile::start()
-{
- ALOGV("MidiFile::start");
- Mutex::Autolock lock(mMutex);
- if (!mEasHandle) {
- return ERROR_NOT_OPEN;
- }
-
- // resuming after pause?
- if (mPaused) {
- if (EAS_Resume(mEasData, mEasHandle) != EAS_SUCCESS) {
- return ERROR_EAS_FAILURE;
- }
- mPaused = false;
- updateState();
- }
-
- mRender = true;
- if (mState == EAS_STATE_PLAY) {
- sendEvent(MEDIA_STARTED);
- }
-
- // wake up render thread
- ALOGV(" wakeup render thread");
- mCondition.signal();
- return NO_ERROR;
-}
-
-status_t MidiFile::stop()
-{
- ALOGV("MidiFile::stop");
- Mutex::Autolock lock(mMutex);
- if (!mEasHandle) {
- return ERROR_NOT_OPEN;
- }
- if (!mPaused && (mState != EAS_STATE_STOPPED)) {
- EAS_RESULT result = EAS_Pause(mEasData, mEasHandle);
- if (result != EAS_SUCCESS) {
- ALOGE("EAS_Pause returned error %ld", result);
- return ERROR_EAS_FAILURE;
- }
- }
- mPaused = false;
- sendEvent(MEDIA_STOPPED);
- return NO_ERROR;
-}
-
-status_t MidiFile::seekTo(int position)
-{
- ALOGV("MidiFile::seekTo %d", position);
- // hold lock during EAS calls
- {
- Mutex::Autolock lock(mMutex);
- if (!mEasHandle) {
- return ERROR_NOT_OPEN;
- }
- EAS_RESULT result;
- if ((result = EAS_Locate(mEasData, mEasHandle, position, false))
- != EAS_SUCCESS)
- {
- ALOGE("EAS_Locate returned %ld", result);
- return ERROR_EAS_FAILURE;
- }
- EAS_GetLocation(mEasData, mEasHandle, &mPlayTime);
- }
- sendEvent(MEDIA_SEEK_COMPLETE);
- return NO_ERROR;
-}
-
-status_t MidiFile::pause()
-{
- ALOGV("MidiFile::pause");
- Mutex::Autolock lock(mMutex);
- if (!mEasHandle) {
- return ERROR_NOT_OPEN;
- }
- if ((mState == EAS_STATE_PAUSING) || (mState == EAS_STATE_PAUSED)) return NO_ERROR;
- if (EAS_Pause(mEasData, mEasHandle) != EAS_SUCCESS) {
- return ERROR_EAS_FAILURE;
- }
- mPaused = true;
- sendEvent(MEDIA_PAUSED);
- return NO_ERROR;
-}
-
-bool MidiFile::isPlaying()
-{
- ALOGV("MidiFile::isPlaying, mState=%d", int(mState));
- if (!mEasHandle || mPaused) return false;
- return (mState == EAS_STATE_PLAY || (mState == EAS_STATE_READY && mRender));
-}
-
-status_t MidiFile::getCurrentPosition(int* position)
-{
- ALOGV("MidiFile::getCurrentPosition");
- if (!mEasHandle) {
- ALOGE("getCurrentPosition(): file not open");
- return ERROR_NOT_OPEN;
- }
- if (mPlayTime < 0) {
- ALOGE("getCurrentPosition(): mPlayTime = %ld", mPlayTime);
- return ERROR_EAS_FAILURE;
- }
- *position = mPlayTime;
- return NO_ERROR;
-}
-
-status_t MidiFile::getDuration(int* duration)
-{
-
- ALOGV("MidiFile::getDuration");
- {
- Mutex::Autolock lock(mMutex);
- if (!mEasHandle) return ERROR_NOT_OPEN;
- *duration = mDuration;
- }
-
- // if no duration cached, get the duration
- // don't need a lock here because we spin up a new engine
- if (*duration < 0) {
- EAS_I32 temp;
- EAS_DATA_HANDLE easData = NULL;
- EAS_HANDLE easHandle = NULL;
- EAS_RESULT result = EAS_Init(&easData);
- if (result == EAS_SUCCESS) {
- result = EAS_OpenFile(easData, &mFileLocator, &easHandle);
- }
- if (result == EAS_SUCCESS) {
- result = EAS_Prepare(easData, easHandle);
- }
- if (result == EAS_SUCCESS) {
- result = EAS_ParseMetaData(easData, easHandle, &temp);
- }
- if (easHandle) {
- EAS_CloseFile(easData, easHandle);
- }
- if (easData) {
- EAS_Shutdown(easData);
- }
-
- if (result != EAS_SUCCESS) {
- return ERROR_EAS_FAILURE;
- }
-
- // cache successful result
- mDuration = *duration = int(temp);
- }
-
- return NO_ERROR;
-}
-
-status_t MidiFile::release()
-{
- ALOGV("MidiFile::release");
- Mutex::Autolock l(mMutex);
- reset_nosync();
-
- // wait for render thread to exit
- mExit = true;
- mCondition.signal();
-
- // wait for thread to exit
- if (mAudioBuffer) {
- mCondition.wait(mMutex);
- }
-
- // release resources
- if (mEasData) {
- EAS_Shutdown(mEasData);
- mEasData = NULL;
- }
- return NO_ERROR;
-}
-
-status_t MidiFile::reset()
-{
- ALOGV("MidiFile::reset");
- Mutex::Autolock lock(mMutex);
- return reset_nosync();
-}
-
-// call only with mutex held
-status_t MidiFile::reset_nosync()
-{
- ALOGV("MidiFile::reset_nosync");
- sendEvent(MEDIA_STOPPED);
- // close file
- if (mEasHandle) {
- EAS_CloseFile(mEasData, mEasHandle);
- mEasHandle = NULL;
- }
- if (mFileLocator.path) {
- free((void*)mFileLocator.path);
- mFileLocator.path = NULL;
- }
- if (mFileLocator.fd >= 0) {
- close(mFileLocator.fd);
- }
- mFileLocator.fd = -1;
- mFileLocator.offset = 0;
- mFileLocator.length = 0;
-
- mPlayTime = -1;
- mDuration = -1;
- mLoop = false;
- mPaused = false;
- mRender = false;
- return NO_ERROR;
-}
-
-status_t MidiFile::setLooping(int loop)
-{
- ALOGV("MidiFile::setLooping");
- Mutex::Autolock lock(mMutex);
- if (!mEasHandle) {
- return ERROR_NOT_OPEN;
- }
- loop = loop ? -1 : 0;
- if (EAS_SetRepeat(mEasData, mEasHandle, loop) != EAS_SUCCESS) {
- return ERROR_EAS_FAILURE;
- }
- return NO_ERROR;
-}
-
-status_t MidiFile::createOutputTrack() {
- if (mAudioSink->open(pLibConfig->sampleRate, pLibConfig->numChannels,
- CHANNEL_MASK_USE_CHANNEL_ORDER, AUDIO_FORMAT_PCM_16_BIT, 2 /*bufferCount*/) != NO_ERROR) {
- ALOGE("mAudioSink open failed");
- return ERROR_OPEN_FAILED;
- }
- return NO_ERROR;
-}
-
-int MidiFile::render() {
- EAS_RESULT result = EAS_FAILURE;
- EAS_I32 count;
- int temp;
- bool audioStarted = false;
-
- ALOGV("MidiFile::render");
-
- // allocate render buffer
- mAudioBuffer = new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * NUM_BUFFERS];
- if (!mAudioBuffer) {
- ALOGE("mAudioBuffer allocate failed");
- goto threadExit;
- }
-
- // signal main thread that we started
- {
- Mutex::Autolock l(mMutex);
- mTid = gettid();
- ALOGV("render thread(%d) signal", mTid);
- mCondition.signal();
- }
-
- while (1) {
- mMutex.lock();
-
- // nothing to render, wait for client thread to wake us up
- while (!mRender && !mExit)
- {
- ALOGV("MidiFile::render - signal wait");
- mCondition.wait(mMutex);
- ALOGV("MidiFile::render - signal rx'd");
- }
- if (mExit) {
- mMutex.unlock();
- break;
- }
-
- // render midi data into the input buffer
- //ALOGV("MidiFile::render - rendering audio");
- int num_output = 0;
- EAS_PCM* p = mAudioBuffer;
- for (int i = 0; i < NUM_BUFFERS; i++) {
- result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count);
- if (result != EAS_SUCCESS) {
- ALOGE("EAS_Render returned %ld", result);
- }
- p += count * pLibConfig->numChannels;
- num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM);
- }
-
- // update playback state and position
- // ALOGV("MidiFile::render - updating state");
- EAS_GetLocation(mEasData, mEasHandle, &mPlayTime);
- EAS_State(mEasData, mEasHandle, &mState);
- mMutex.unlock();
-
- // create audio output track if necessary
- if (!mAudioSink->ready()) {
- ALOGV("MidiFile::render - create output track");
- if (createOutputTrack() != NO_ERROR)
- goto threadExit;
- }
-
- // Write data to the audio hardware
- // ALOGV("MidiFile::render - writing to audio output");
- if ((temp = mAudioSink->write(mAudioBuffer, num_output)) < 0) {
- ALOGE("Error in writing:%d",temp);
- return temp;
- }
-
- // start audio output if necessary
- if (!audioStarted) {
- //ALOGV("MidiFile::render - starting audio");
- mAudioSink->start();
- audioStarted = true;
- }
-
- // still playing?
- if ((mState == EAS_STATE_STOPPED) || (mState == EAS_STATE_ERROR) ||
- (mState == EAS_STATE_PAUSED))
- {
- switch(mState) {
- case EAS_STATE_STOPPED:
- {
- ALOGV("MidiFile::render - stopped");
- sendEvent(MEDIA_PLAYBACK_COMPLETE);
- break;
- }
- case EAS_STATE_ERROR:
- {
- ALOGE("MidiFile::render - error");
- sendEvent(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN);
- break;
- }
- case EAS_STATE_PAUSED:
- ALOGV("MidiFile::render - paused");
- break;
- default:
- break;
- }
- mAudioSink->stop();
- audioStarted = false;
- mRender = false;
- }
- }
-
-threadExit:
- mAudioSink.clear();
- if (mAudioBuffer) {
- delete [] mAudioBuffer;
- mAudioBuffer = NULL;
- }
- mMutex.lock();
- mTid = -1;
- mCondition.signal();
- mMutex.unlock();
- return result;
-}
-
-} // end namespace android
diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h
deleted file mode 100644
index 82e4e88..0000000
--- a/media/libmediaplayerservice/MidiFile.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
-**
-** 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_MIDIFILE_H
-#define ANDROID_MIDIFILE_H
-
-#include <media/MediaPlayerInterface.h>
-#include <libsonivox/eas.h>
-
-namespace android {
-
-// Note that the name MidiFile is misleading; this actually represents a MIDI file player
-class MidiFile : public MediaPlayerInterface {
-public:
- MidiFile();
- ~MidiFile();
-
- virtual status_t initCheck();
-
- virtual status_t setDataSource(
- const sp<IMediaHTTPService> &httpService,
- const char* path,
- const KeyedVector<String8, String8> *headers);
-
- virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
- virtual status_t setVideoSurfaceTexture(
- const sp<IGraphicBufferProducer>& /*bufferProducer*/)
- { return UNKNOWN_ERROR; }
- virtual status_t prepare();
- virtual status_t prepareAsync();
- virtual status_t start();
- virtual status_t stop();
- virtual status_t seekTo(int msec);
- virtual status_t pause();
- virtual bool isPlaying();
- virtual status_t getCurrentPosition(int* msec);
- virtual status_t getDuration(int* msec);
- virtual status_t release();
- virtual status_t reset();
- virtual status_t setLooping(int loop);
- virtual player_type playerType() { return SONIVOX_PLAYER; }
- virtual status_t invoke(const Parcel& /*request*/, Parcel* /*reply*/) {
- return INVALID_OPERATION;
- }
- virtual status_t setParameter(int /*key*/, const Parcel &/*request*/) {
- return INVALID_OPERATION;
- }
- virtual status_t getParameter(int /*key*/, Parcel* /*reply*/) {
- return INVALID_OPERATION;
- }
-
-
-private:
- status_t createOutputTrack();
- status_t reset_nosync();
- int render();
- void updateState(){ EAS_State(mEasData, mEasHandle, &mState); }
-
- Mutex mMutex;
- Condition mCondition;
- EAS_DATA_HANDLE mEasData;
- EAS_HANDLE mEasHandle;
- EAS_PCM* mAudioBuffer;
- EAS_I32 mPlayTime;
- EAS_I32 mDuration;
- EAS_STATE mState;
- EAS_FILE mFileLocator;
- audio_stream_type_t mStreamType;
- bool mLoop;
- volatile bool mExit;
- bool mPaused;
- volatile bool mRender;
- pid_t mTid;
-
- class MidiFileThread : public Thread {
- public:
- MidiFileThread(MidiFile *midiPlayer) : mMidiFile(midiPlayer) {
- }
-
- protected:
- virtual ~MidiFileThread() {}
-
- private:
- MidiFile *mMidiFile;
-
- bool threadLoop() {
- int result;
- result = mMidiFile->render();
- return false;
- }
-
- MidiFileThread(const MidiFileThread &);
- MidiFileThread &operator=(const MidiFileThread &);
- };
-
- sp<MidiFileThread> mThread;
-};
-
-}; // namespace android
-
-#endif // ANDROID_MIDIFILE_H
diff --git a/media/libmediaplayerservice/MidiMetadataRetriever.cpp b/media/libmediaplayerservice/MidiMetadataRetriever.cpp
deleted file mode 100644
index f3cf6ef..0000000
--- a/media/libmediaplayerservice/MidiMetadataRetriever.cpp
+++ /dev/null
@@ -1,96 +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.
-*/
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MidiMetadataRetriever"
-#include <utils/Log.h>
-
-#include "MidiMetadataRetriever.h"
-#include <media/mediametadataretriever.h>
-
-#include <media/IMediaHTTPService.h>
-
-namespace android {
-
-static status_t ERROR_NOT_OPEN = -1;
-static status_t ERROR_OPEN_FAILED = -2;
-static status_t ERROR_EAS_FAILURE = -3;
-static status_t ERROR_ALLOCATE_FAILED = -4;
-
-void MidiMetadataRetriever::clearMetadataValues()
-{
- ALOGV("clearMetadataValues");
- mMetadataValues[0][0] = '\0';
-}
-
-status_t MidiMetadataRetriever::setDataSource(
- const sp<IMediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers)
-{
- ALOGV("setDataSource: %s", url? url: "NULL pointer");
- Mutex::Autolock lock(mLock);
- clearMetadataValues();
- if (mMidiPlayer == 0) {
- mMidiPlayer = new MidiFile();
- }
- return mMidiPlayer->setDataSource(httpService, url, headers);
-}
-
-status_t MidiMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
-{
- ALOGV("setDataSource: fd(%d), offset(%lld), and length(%lld)", fd, offset, length);
- Mutex::Autolock lock(mLock);
- clearMetadataValues();
- if (mMidiPlayer == 0) {
- mMidiPlayer = new MidiFile();
- }
- return mMidiPlayer->setDataSource(fd, offset, length);;
-}
-
-const char* MidiMetadataRetriever::extractMetadata(int keyCode)
-{
- ALOGV("extractMetdata: key(%d)", keyCode);
- Mutex::Autolock lock(mLock);
- if (mMidiPlayer == 0 || mMidiPlayer->initCheck() != NO_ERROR) {
- ALOGE("Midi player is not initialized yet");
- return NULL;
- }
- switch (keyCode) {
- case METADATA_KEY_DURATION:
- {
- if (mMetadataValues[0][0] == '\0') {
- int duration = -1;
- if (mMidiPlayer->getDuration(&duration) != NO_ERROR) {
- ALOGE("failed to get duration");
- return NULL;
- }
- snprintf(mMetadataValues[0], MAX_METADATA_STRING_LENGTH, "%d", duration);
- }
-
- ALOGV("duration: %s ms", mMetadataValues[0]);
- return mMetadataValues[0];
- }
- default:
- ALOGE("Unsupported key code (%d)", keyCode);
- return NULL;
- }
- return NULL;
-}
-
-};
-
diff --git a/media/libmediaplayerservice/MidiMetadataRetriever.h b/media/libmediaplayerservice/MidiMetadataRetriever.h
deleted file mode 100644
index b8214ee..0000000
--- a/media/libmediaplayerservice/MidiMetadataRetriever.h
+++ /dev/null
@@ -1,53 +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_MIDIMETADATARETRIEVER_H
-#define ANDROID_MIDIMETADATARETRIEVER_H
-
-#include <utils/threads.h>
-#include <utils/Errors.h>
-#include <media/MediaMetadataRetrieverInterface.h>
-
-#include "MidiFile.h"
-
-namespace android {
-
-class MidiMetadataRetriever : public MediaMetadataRetrieverInterface {
-public:
- MidiMetadataRetriever() {}
- ~MidiMetadataRetriever() {}
-
- 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 const char* extractMetadata(int keyCode);
-
-private:
- static const uint32_t MAX_METADATA_STRING_LENGTH = 128;
- void clearMetadataValues();
-
- Mutex mLock;
- sp<MidiFile> mMidiPlayer;
- char mMetadataValues[1][MAX_METADATA_STRING_LENGTH];
-};
-
-}; // namespace android
-
-#endif // ANDROID_MIDIMETADATARETRIEVER_H
diff --git a/services/audiopolicy/AudioPolicyFactory.cpp b/media/libmediaplayerservice/ProcessInfoInterface.h
similarity index 60%
copy from services/audiopolicy/AudioPolicyFactory.cpp
copy to media/libmediaplayerservice/ProcessInfoInterface.h
index 2ae7bc1..222f92d 100644
--- a/services/audiopolicy/AudioPolicyFactory.cpp
+++ b/media/libmediaplayerservice/ProcessInfoInterface.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 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,19 +14,20 @@
* limitations under the License.
*/
-#include "AudioPolicyManager.h"
+#ifndef PROCESS_INFO_INTERFACE_H_
+#define PROCESS_INFO_INTERFACE_H_
+
+#include <utils/RefBase.h>
namespace android {
-extern "C" AudioPolicyInterface* createAudioPolicyManager(
- AudioPolicyClientInterface *clientInterface)
-{
- return new AudioPolicyManager(clientInterface);
-}
+struct ProcessInfoInterface : public RefBase {
+ virtual bool getPriority(int pid, int* priority) = 0;
-extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface)
-{
- delete interface;
-}
+protected:
+ virtual ~ProcessInfoInterface() {}
+};
-}; // namespace android
+} // namespace android
+
+#endif // PROCESS_INFO_INTERFACE_H_
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 3d093fa..55763f0 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -75,6 +75,7 @@
mAudioSource(AUDIO_SOURCE_CNT),
mVideoSource(VIDEO_SOURCE_LIST_END),
mCaptureTimeLapse(false),
+ mCaptureFps(0.0f),
mStarted(false) {
ALOGV("Constructor");
@@ -206,7 +207,7 @@
status_t StagefrightRecorder::setVideoFrameRate(int frames_per_second) {
ALOGV("setVideoFrameRate: %d", frames_per_second);
if ((frames_per_second <= 0 && frames_per_second != -1) ||
- frames_per_second > 120) {
+ frames_per_second > kMaxHighSpeedFps) {
ALOGE("Invalid video frame rate: %d", frames_per_second);
return BAD_VALUE;
}
@@ -241,14 +242,6 @@
return OK;
}
-status_t StagefrightRecorder::setOutputFile(const char * /* path */) {
- ALOGE("setOutputFile(const char*) must not be called");
- // We don't actually support this at all, as the media_server process
- // no longer has permissions to create files.
-
- return -EPERM;
-}
-
status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
ALOGV("setOutputFile: %d, %lld, %lld", fd, offset, length);
// These don't make any sense, do they?
@@ -260,6 +253,9 @@
return -EBADF;
}
+ // start with a clean, empty file
+ ftruncate(fd, 0);
+
if (mOutputFd >= 0) {
::close(mOutputFd);
}
@@ -268,6 +264,31 @@
return OK;
}
+// Attempt to parse an float literal optionally surrounded by whitespace,
+// returns true on success, false otherwise.
+static bool safe_strtof(const char *s, float *val) {
+ char *end;
+
+ // It is lame, but according to man page, we have to set errno to 0
+ // before calling strtof().
+ errno = 0;
+ *val = strtof(s, &end);
+
+ if (end == s || errno == ERANGE) {
+ return false;
+ }
+
+ // Skip trailing whitespace
+ while (isspace(*end)) {
+ ++end;
+ }
+
+ // For a successful return, the string must contain nothing but a valid
+ // float literal optionally surrounded by whitespace.
+
+ return *end == '\0';
+}
+
// Attempt to parse an int64 literal optionally surrounded by whitespace,
// returns true on success, false otherwise.
static bool safe_strtoi64(const char *s, int64_t *val) {
@@ -551,8 +572,10 @@
return OK;
}
-status_t StagefrightRecorder::setParamTimeBetweenTimeLapseFrameCapture(int64_t timeUs) {
- ALOGV("setParamTimeBetweenTimeLapseFrameCapture: %lld us", timeUs);
+status_t StagefrightRecorder::setParamTimeLapseFps(float fps) {
+ ALOGV("setParamTimeLapseFps: %.2f", fps);
+
+ int64_t timeUs = (int64_t) (1000000.0 / fps + 0.5f);
// Not allowing time more than a day
if (timeUs <= 0 || timeUs > 86400*1E6) {
@@ -560,6 +583,7 @@
return BAD_VALUE;
}
+ mCaptureFps = fps;
mTimeBetweenTimeLapseFrameCaptureUs = timeUs;
return OK;
}
@@ -687,11 +711,10 @@
if (safe_strtoi32(value.string(), &timeLapseEnable)) {
return setParamTimeLapseEnable(timeLapseEnable);
}
- } else if (key == "time-between-time-lapse-frame-capture") {
- int64_t timeBetweenTimeLapseFrameCaptureUs;
- if (safe_strtoi64(value.string(), &timeBetweenTimeLapseFrameCaptureUs)) {
- return setParamTimeBetweenTimeLapseFrameCapture(
- timeBetweenTimeLapseFrameCaptureUs);
+ } else if (key == "time-lapse-fps") {
+ float fps;
+ if (safe_strtof(value.string(), &fps)) {
+ return setParamTimeLapseFps(fps);
}
} else {
ALOGE("setParameter: failed to find key %s", key.string());
@@ -1586,10 +1609,11 @@
status_t err = OK;
sp<MediaWriter> writer;
+ sp<MPEG4Writer> mp4writer;
if (mOutputFormat == OUTPUT_FORMAT_WEBM) {
writer = new WebmWriter(mOutputFd);
} else {
- writer = new MPEG4Writer(mOutputFd);
+ writer = mp4writer = new MPEG4Writer(mOutputFd);
}
if (mVideoSource < VIDEO_SOURCE_LIST_END) {
@@ -1622,13 +1646,15 @@
mTotalBitRate += mAudioBitRate;
}
+ if (mCaptureTimeLapse) {
+ mp4writer->setCaptureRate(mCaptureFps);
+ }
+
if (mInterleaveDurationUs > 0) {
- reinterpret_cast<MPEG4Writer *>(writer.get())->
- setInterleaveDuration(mInterleaveDurationUs);
+ mp4writer->setInterleaveDuration(mInterleaveDurationUs);
}
if (mLongitudex10000 > -3600000 && mLatitudex10000 > -3600000) {
- reinterpret_cast<MPEG4Writer *>(writer.get())->
- setGeoData(mLatitudex10000, mLongitudex10000);
+ mp4writer->setGeoData(mLatitudex10000, mLongitudex10000);
}
}
if (mMaxFileDurationUs != 0) {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 54c38d3..f34c229 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -53,7 +53,6 @@
virtual status_t setVideoFrameRate(int frames_per_second);
virtual status_t setCamera(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy);
virtual status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface);
- virtual status_t setOutputFile(const char *path);
virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
virtual status_t setParameters(const String8& params);
virtual status_t setListener(const sp<IMediaRecorderClient>& listener);
@@ -110,6 +109,7 @@
int32_t mTotalBitRate;
bool mCaptureTimeLapse;
+ float mCaptureFps;
int64_t mTimeBetweenTimeLapseFrameCaptureUs;
sp<CameraSourceTimeLapse> mCameraSourceTimeLapse;
@@ -127,6 +127,8 @@
sp<IGraphicBufferProducer> mGraphicBufferProducer;
sp<ALooper> mLooper;
+ static const int kMaxHighSpeedFps = 1000;
+
status_t prepareInternal();
status_t setupMPEG4orWEBMRecording();
void setupMPEG4orWEBMMetaData(sp<MetaData> *meta);
@@ -154,7 +156,7 @@
status_t setParamAudioSamplingRate(int32_t sampleRate);
status_t setParamAudioTimeScale(int32_t timeScale);
status_t setParamTimeLapseEnable(int32_t timeLapseEnable);
- status_t setParamTimeBetweenTimeLapseFrameCapture(int64_t timeUs);
+ status_t setParamTimeLapseFps(float fps);
status_t setParamVideoEncodingBitRate(int32_t bitRate);
status_t setParamVideoIFramesInterval(int32_t seconds);
status_t setParamVideoEncoderProfile(int32_t profile);
diff --git a/media/libmediaplayerservice/TestPlayerStub.cpp b/media/libmediaplayerservice/TestPlayerStub.cpp
index 5795773..c8bf6c5 100644
--- a/media/libmediaplayerservice/TestPlayerStub.cpp
+++ b/media/libmediaplayerservice/TestPlayerStub.cpp
@@ -45,7 +45,7 @@
{
char prop[PROPERTY_VALUE_MAX] = { '\0', };
- property_get(kBuildTypePropName, prop, '\0');
+ property_get(kBuildTypePropName, prop, "\0");
return strcmp(prop, kEngBuild) == 0 || strcmp(prop, kTestBuild) == 0;
}
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 9b446b8..a040343 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -65,12 +65,12 @@
mUID(uid),
mFd(-1),
mDrmManagerClient(NULL),
- mMetaDataSize(-1ll),
mBitrate(-1ll),
mPollBufferingGeneration(0),
mPendingReadBufferTypes(0),
mBuffering(false),
- mPrepareBuffering(false) {
+ mPrepareBuffering(false),
+ mPrevBufferPercentage(-1) {
resetDataSource();
DataSource::RegisterDefaultSniffers();
}
@@ -130,23 +130,34 @@
status_t NuPlayer::GenericSource::initFromDataSource() {
sp<MediaExtractor> extractor;
+ String8 mimeType;
+ float confidence;
+ sp<AMessage> dummy;
+ bool isWidevineStreaming = false;
CHECK(mDataSource != NULL);
if (mIsWidevine) {
- String8 mimeType;
- float confidence;
- sp<AMessage> dummy;
- bool success;
-
- success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy);
- if (!success
- || strcasecmp(
+ isWidevineStreaming = SniffWVM(
+ mDataSource, &mimeType, &confidence, &dummy);
+ if (!isWidevineStreaming ||
+ strcasecmp(
mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
ALOGE("unsupported widevine mime: %s", mimeType.string());
return UNKNOWN_ERROR;
}
+ } else if (mIsStreaming) {
+ if (!mDataSource->sniff(&mimeType, &confidence, &dummy)) {
+ return UNKNOWN_ERROR;
+ }
+ isWidevineStreaming = !strcasecmp(
+ mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM);
+ }
+ if (isWidevineStreaming) {
+ // we don't want cached source for widevine streaming.
+ mCachedSource.clear();
+ mDataSource = mHttpSource;
mWVMExtractor = new WVMExtractor(mDataSource);
mWVMExtractor->setAdaptiveStreamingMode(true);
if (mUIDValid) {
@@ -155,7 +166,7 @@
extractor = mWVMExtractor;
} else {
extractor = MediaExtractor::Create(mDataSource,
- mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str());
+ mimeType.isEmpty() ? NULL : mimeType.string());
}
if (extractor == NULL) {
@@ -181,14 +192,6 @@
if (mFileMeta->findCString(kKeyMIMEType, &fileMime)
&& !strncasecmp(fileMime, "video/wvm", 9)) {
mIsWidevine = true;
- if (!mUri.empty()) {
- // streaming, but the app forgot to specify widevine:// url
- mWVMExtractor = static_cast<WVMExtractor *>(extractor.get());
- mWVMExtractor->setAdaptiveStreamingMode(true);
- if (mUIDValid) {
- mWVMExtractor->setUID(mUID);
- }
- }
}
}
}
@@ -328,7 +331,7 @@
mLooper->registerHandler(this);
}
- sp<AMessage> msg = new AMessage(kWhatPrepareAsync, id());
+ sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
msg->post();
}
@@ -341,6 +344,7 @@
if (!mUri.empty()) {
const char* uri = mUri.c_str();
+ String8 contentType;
mIsWidevine = !strncasecmp(uri, "widevine://", 11);
if (!strncasecmp("http://", uri, 7)
@@ -355,7 +359,7 @@
}
mDataSource = DataSource::CreateFromURI(
- mHTTPService, uri, &mUriHeaders, &mContentType,
+ mHTTPService, uri, &mUriHeaders, &contentType,
static_cast<HTTPBase *>(mHttpSource.get()));
} else {
mIsWidevine = false;
@@ -383,20 +387,8 @@
mIsStreaming = (mIsWidevine || mCachedSource != NULL);
}
- // check initial caching status
- status_t err = prefillCacheIfNecessary();
- if (err != OK) {
- if (err == -EAGAIN) {
- (new AMessage(kWhatPrepareAsync, id()))->post(200000);
- } else {
- ALOGE("Failed to prefill data cache!");
- notifyPreparedAndCleanup(UNKNOWN_ERROR);
- }
- return;
- }
-
- // init extrator from data source
- err = initFromDataSource();
+ // init extractor from data source
+ status_t err = initFromDataSource();
if (err != OK) {
ALOGE("Failed to init from data source!");
@@ -435,9 +427,6 @@
void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
if (err != OK) {
- mMetaDataSize = -1ll;
- mContentType = "";
- mSniffedMIME = "";
mDataSource.clear();
mCachedSource.clear();
mHttpSource.clear();
@@ -447,76 +436,6 @@
notifyPrepared(err);
}
-status_t NuPlayer::GenericSource::prefillCacheIfNecessary() {
- CHECK(mDataSource != NULL);
-
- if (mCachedSource == NULL) {
- // no prefill if the data source is not cached
- return OK;
- }
-
- // 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.
- if (!strncasecmp(mContentType.string(), "audio/", 6)) {
- return OK;
- }
-
- // 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.
-
- // Initially make sure we have at least 192 KB for the sniff
- // to complete without blocking.
- static const size_t kMinBytesForSniffing = 192 * 1024;
- static const size_t kDefaultMetaSize = 200000;
-
- status_t finalStatus;
-
- size_t cachedDataRemaining =
- mCachedSource->approxDataRemaining(&finalStatus);
-
- if (finalStatus != OK || (mMetaDataSize >= 0
- && (off64_t)cachedDataRemaining >= mMetaDataSize)) {
- ALOGV("stop caching, status %d, "
- "metaDataSize %lld, cachedDataRemaining %zu",
- finalStatus, mMetaDataSize, cachedDataRemaining);
- return OK;
- }
-
- ALOGV("now cached %zu bytes of data", cachedDataRemaining);
-
- if (mMetaDataSize < 0
- && cachedDataRemaining >= kMinBytesForSniffing) {
- String8 tmp;
- float confidence;
- sp<AMessage> meta;
- if (!mCachedSource->sniff(&tmp, &confidence, &meta)) {
- 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()
- mSniffedMIME = tmp.string();
-
- if (meta == NULL
- || !meta->findInt64("meta-data-size",
- reinterpret_cast<int64_t*>(&mMetaDataSize))) {
- mMetaDataSize = kDefaultMetaSize;
- }
-
- if (mMetaDataSize < 0ll) {
- ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize);
- return UNKNOWN_ERROR;
- }
- }
-
- return -EAGAIN;
-}
-
void NuPlayer::GenericSource::start() {
ALOGI("start");
@@ -532,7 +451,7 @@
setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
mStarted = true;
- (new AMessage(kWhatStart, id()))->post();
+ (new AMessage(kWhatStart, this))->post();
}
void NuPlayer::GenericSource::stop() {
@@ -541,7 +460,7 @@
mStarted = false;
if (mIsWidevine || mIsSecure) {
// For widevine or secure sources we need to prevent any further reads.
- sp<AMessage> msg = new AMessage(kWhatStopWidevine, id());
+ sp<AMessage> msg = new AMessage(kWhatStopWidevine, this);
sp<AMessage> response;
(void) msg->postAndAwaitResponse(&response);
}
@@ -558,7 +477,7 @@
setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
mStarted = true;
- (new AMessage(kWhatResume, id()))->post();
+ (new AMessage(kWhatResume, this))->post();
}
void NuPlayer::GenericSource::disconnect() {
@@ -585,7 +504,7 @@
}
void NuPlayer::GenericSource::schedulePollBuffering() {
- sp<AMessage> msg = new AMessage(kWhatPollBuffering, id());
+ sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
msg->setInt32("generation", mPollBufferingGeneration);
msg->post(1000000ll);
}
@@ -593,6 +512,7 @@
void NuPlayer::GenericSource::cancelPollBuffering() {
mBuffering = false;
++mPollBufferingGeneration;
+ mPrevBufferPercentage = -1;
}
void NuPlayer::GenericSource::restartPollBuffering() {
@@ -602,7 +522,19 @@
}
}
-void NuPlayer::GenericSource::notifyBufferingUpdate(int percentage) {
+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();
@@ -656,10 +588,10 @@
int32_t kbps = 0;
status_t err = UNKNOWN_ERROR;
- if (mCachedSource != NULL) {
- err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
- } else if (mWVMExtractor != NULL) {
+ if (mWVMExtractor != NULL) {
err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
+ } else if (mCachedSource != NULL) {
+ err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
}
if (err == OK) {
@@ -681,7 +613,13 @@
int64_t cachedDurationUs = -1ll;
ssize_t cachedDataRemaining = -1;
- if (mCachedSource != NULL) {
+ 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);
@@ -697,9 +635,6 @@
cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
}
}
- } else if (mWVMExtractor != NULL) {
- cachedDurationUs
- = mWVMExtractor->getCachedDurationUs(&finalStatus);
}
if (finalStatus != OK) {
@@ -879,7 +814,7 @@
mVideoTrack.mPackets->clear();
}
sp<AMessage> response = new AMessage;
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
response->postReply(replyID);
break;
@@ -919,7 +854,7 @@
const int64_t oneSecUs = 1000000ll;
delayUs -= oneSecUs;
}
- sp<AMessage> msg2 = new AMessage(sendWhat, id());
+ sp<AMessage> msg2 = new AMessage(sendWhat, this);
msg2->setInt32("generation", msgGeneration);
msg2->post(delayUs < 0 ? 0 : delayUs);
}
@@ -959,7 +894,7 @@
}
sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
- sp<AMessage> msg = new AMessage(kWhatGetFormat, id());
+ sp<AMessage> msg = new AMessage(kWhatGetFormat, this);
msg->setInt32("audio", audio);
sp<AMessage> response;
@@ -981,7 +916,7 @@
sp<MetaData> format = doGetFormatMeta(audio);
response->setPointer("format", format.get());
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
response->postReply(replyID);
}
@@ -1048,7 +983,7 @@
if (mSubtitleTrack.mSource != NULL
&& !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
- sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
+ sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
msg->setInt64("timeUs", timeUs);
msg->setInt32("generation", mFetchSubtitleDataGeneration);
msg->post();
@@ -1056,7 +991,7 @@
if (mTimedTextTrack.mSource != NULL
&& !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
- sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
+ sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
msg->setInt64("timeUs", timeUs);
msg->setInt32("generation", mFetchTimedTextDataGeneration);
msg->post();
@@ -1121,7 +1056,7 @@
}
ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
- sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id());
+ sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, this);
msg->setInt32("type", type);
sp<AMessage> response;
@@ -1144,7 +1079,7 @@
ssize_t index = doGetSelectedTrack(type);
response->setInt32("index", index);
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
response->postReply(replyID);
}
@@ -1177,7 +1112,7 @@
status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
- sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
+ sp<AMessage> msg = new AMessage(kWhatSelectTrack, this);
msg->setInt32("trackIndex", trackIndex);
msg->setInt32("select", select);
msg->setInt64("timeUs", timeUs);
@@ -1202,7 +1137,7 @@
status_t err = doSelectTrack(trackIndex, select, timeUs);
response->setInt32("err", err);
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
response->postReply(replyID);
}
@@ -1263,7 +1198,7 @@
status_t eosResult; // ignored
if (mSubtitleTrack.mSource != NULL
&& !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
- sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
+ sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
msg->setInt64("timeUs", timeUs);
msg->setInt32("generation", mFetchSubtitleDataGeneration);
msg->post();
@@ -1271,7 +1206,7 @@
if (mTimedTextTrack.mSource != NULL
&& !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
- sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
+ sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
msg->setInt64("timeUs", timeUs);
msg->setInt32("generation", mFetchTimedTextDataGeneration);
msg->post();
@@ -1285,7 +1220,7 @@
return OK;
}
- sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id());
+ sp<AMessage> msg = new AMessage(kWhatChangeAVSource, this);
msg->setInt32("trackIndex", trackIndex);
msg->post();
return OK;
@@ -1295,7 +1230,7 @@
}
status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
- sp<AMessage> msg = new AMessage(kWhatSeek, id());
+ sp<AMessage> msg = new AMessage(kWhatSeek, this);
msg->setInt64("seekTimeUs", seekTimeUs);
sp<AMessage> response;
@@ -1315,7 +1250,7 @@
status_t err = doSeek(seekTimeUs);
response->setInt32("err", err);
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
response->postReply(replyID);
}
@@ -1435,7 +1370,7 @@
if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
mPendingReadBufferTypes |= (1 << trackType);
- sp<AMessage> msg = new AMessage(kWhatReadBuffer, id());
+ sp<AMessage> msg = new AMessage(kWhatReadBuffer, this);
msg->setInt32("trackType", trackType);
msg->post();
}
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 385d73a..5fc41ec 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -139,14 +139,13 @@
sp<DecryptHandle> mDecryptHandle;
bool mStarted;
bool mStopRead;
- String8 mContentType;
- AString mSniffedMIME;
- off64_t mMetaDataSize;
int64_t mBitrate;
int32_t mPollBufferingGeneration;
uint32_t mPendingReadBufferTypes;
bool mBuffering;
bool mPrepareBuffering;
+ int32_t mPrevBufferPercentage;
+
mutable Mutex mReadBufferLock;
sp<ALooper> mLooper;
@@ -158,8 +157,6 @@
int64_t getLastReadPosition();
void setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position);
- status_t prefillCacheIfNecessary();
-
void notifyPreparedAndCleanup(status_t err);
void onGetFormatMeta(sp<AMessage> msg) const;
@@ -200,7 +197,7 @@
void cancelPollBuffering();
void restartPollBuffering();
void onPollBuffering();
- void notifyBufferingUpdate(int percentage);
+ void notifyBufferingUpdate(int32_t percentage);
void startBufferingIfNecessary();
void stopBufferingIfNecessary();
void sendCacheStats();
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index a26ef9e..d01e83a 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -81,7 +81,7 @@
mLiveLooper->registerHandler(this);
}
- sp<AMessage> notify = new AMessage(kWhatSessionNotify, id());
+ sp<AMessage> notify = new AMessage(kWhatSessionNotify, this);
mLiveSession = new LiveSession(
notify,
@@ -153,7 +153,7 @@
if (err == OK) {
mFetchSubtitleDataGeneration++;
if (select) {
- sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
+ sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
msg->setInt32("generation", mFetchSubtitleDataGeneration);
msg->post();
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index fb8dbce..f4d3794 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -180,6 +180,7 @@
mFlushingVideo(NONE),
mResumePending(false),
mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
+ mPlaybackRate(1.0),
mStarted(false),
mPaused(false),
mPausedByClient(false) {
@@ -199,9 +200,9 @@
}
void NuPlayer::setDataSourceAsync(const sp<IStreamSource> &source) {
- sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
+ sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
- sp<AMessage> notify = new AMessage(kWhatSourceNotify, id());
+ sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
msg->setObject("source", new StreamingSource(notify, source));
msg->post();
@@ -229,10 +230,10 @@
const char *url,
const KeyedVector<String8, String8> *headers) {
- sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
+ sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
size_t len = strlen(url);
- sp<AMessage> notify = new AMessage(kWhatSourceNotify, id());
+ sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
sp<Source> source;
if (IsHTTPLiveURL(url)) {
@@ -266,9 +267,9 @@
}
void NuPlayer::setDataSourceAsync(int fd, int64_t offset, int64_t length) {
- sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
+ sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
- sp<AMessage> notify = new AMessage(kWhatSourceNotify, id());
+ sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
sp<GenericSource> source =
new GenericSource(notify, mUIDValid, mUID);
@@ -285,12 +286,12 @@
}
void NuPlayer::prepareAsync() {
- (new AMessage(kWhatPrepare, id()))->post();
+ (new AMessage(kWhatPrepare, this))->post();
}
void NuPlayer::setVideoSurfaceTextureAsync(
const sp<IGraphicBufferProducer> &bufferProducer) {
- sp<AMessage> msg = new AMessage(kWhatSetVideoNativeWindow, id());
+ sp<AMessage> msg = new AMessage(kWhatSetVideoNativeWindow, this);
if (bufferProducer == NULL) {
msg->setObject("native-window", NULL);
@@ -305,17 +306,23 @@
}
void NuPlayer::setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink) {
- sp<AMessage> msg = new AMessage(kWhatSetAudioSink, id());
+ sp<AMessage> msg = new AMessage(kWhatSetAudioSink, this);
msg->setObject("sink", sink);
msg->post();
}
void NuPlayer::start() {
- (new AMessage(kWhatStart, id()))->post();
+ (new AMessage(kWhatStart, this))->post();
+}
+
+void NuPlayer::setPlaybackRate(float rate) {
+ sp<AMessage> msg = new AMessage(kWhatSetRate, this);
+ msg->setFloat("rate", rate);
+ msg->post();
}
void NuPlayer::pause() {
- (new AMessage(kWhatPause, id()))->post();
+ (new AMessage(kWhatPause, this))->post();
}
void NuPlayer::resetAsync() {
@@ -329,11 +336,11 @@
mSource->disconnect();
}
- (new AMessage(kWhatReset, id()))->post();
+ (new AMessage(kWhatReset, this))->post();
}
void NuPlayer::seekToAsync(int64_t seekTimeUs, bool needNotify) {
- sp<AMessage> msg = new AMessage(kWhatSeek, id());
+ sp<AMessage> msg = new AMessage(kWhatSeek, this);
msg->setInt64("seekTimeUs", seekTimeUs);
msg->setInt32("needNotify", needNotify);
msg->post();
@@ -401,7 +408,7 @@
case kWhatGetTrackInfo:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
Parcel* reply;
@@ -454,7 +461,7 @@
sp<AMessage> response = new AMessage;
response->setInt32("err", err);
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
response->postReply(replyID);
break;
@@ -462,7 +469,7 @@
case kWhatSelectTrack:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
size_t trackIndex;
@@ -604,6 +611,16 @@
break;
}
+ case kWhatSetRate:
+ {
+ ALOGV("kWhatSetRate");
+ CHECK(msg->findFloat("rate", &mPlaybackRate));
+ if (mRenderer != NULL) {
+ mRenderer->setPlaybackRate(mPlaybackRate);
+ }
+ break;
+ }
+
case kWhatScanSources:
{
int32_t generation;
@@ -1044,15 +1061,17 @@
flags |= Renderer::FLAG_OFFLOAD_AUDIO;
}
- sp<AMessage> notify = new AMessage(kWhatRendererNotify, id());
+ sp<AMessage> notify = new AMessage(kWhatRendererNotify, this);
++mRendererGeneration;
notify->setInt32("generation", mRendererGeneration);
mRenderer = new Renderer(mAudioSink, notify, flags);
-
mRendererLooper = new ALooper;
mRendererLooper->setName("NuPlayerRenderer");
mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
mRendererLooper->registerHandler(mRenderer);
+ if (mPlaybackRate != 1.0) {
+ mRenderer->setPlaybackRate(mPlaybackRate);
+ }
sp<MetaData> meta = getFileMeta();
int32_t rate;
@@ -1158,7 +1177,7 @@
return;
}
- sp<AMessage> msg = new AMessage(kWhatScanSources, id());
+ sp<AMessage> msg = new AMessage(kWhatScanSources, this);
msg->setInt32("generation", mScanSourcesGeneration);
msg->post();
@@ -1200,7 +1219,7 @@
AString mime;
CHECK(format->findString("mime", &mime));
- sp<AMessage> ccNotify = new AMessage(kWhatClosedCaptionNotify, id());
+ sp<AMessage> ccNotify = new AMessage(kWhatClosedCaptionNotify, this);
if (mCCDecoder == NULL) {
mCCDecoder = new CCDecoder(ccNotify);
}
@@ -1215,7 +1234,7 @@
}
if (audio) {
- sp<AMessage> notify = new AMessage(kWhatAudioNotify, id());
+ sp<AMessage> notify = new AMessage(kWhatAudioNotify, this);
++mAudioDecoderGeneration;
notify->setInt32("generation", mAudioDecoderGeneration);
@@ -1225,7 +1244,7 @@
*decoder = new Decoder(notify, mSource, mRenderer);
}
} else {
- sp<AMessage> notify = new AMessage(kWhatVideoNotify, id());
+ sp<AMessage> notify = new AMessage(kWhatVideoNotify, this);
++mVideoDecoderGeneration;
notify->setInt32("generation", mVideoDecoderGeneration);
@@ -1416,7 +1435,7 @@
}
status_t NuPlayer::getTrackInfo(Parcel* reply) const {
- sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, id());
+ sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, this);
msg->setPointer("reply", reply);
sp<AMessage> response;
@@ -1425,7 +1444,7 @@
}
status_t NuPlayer::getSelectedTrack(int32_t type, Parcel* reply) const {
- sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id());
+ sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, this);
msg->setPointer("reply", reply);
msg->setInt32("type", type);
@@ -1438,7 +1457,7 @@
}
status_t NuPlayer::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
- sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
+ sp<AMessage> msg = new AMessage(kWhatSelectTrack, this);
msg->setSize("trackIndex", trackIndex);
msg->setInt32("select", select);
msg->setInt64("timeUs", timeUs);
@@ -1481,7 +1500,7 @@
}
void NuPlayer::schedulePollDuration() {
- sp<AMessage> msg = new AMessage(kWhatPollDuration, id());
+ sp<AMessage> msg = new AMessage(kWhatPollDuration, this);
msg->setInt32("generation", mPollDurationGeneration);
msg->post();
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index edc2bd3..a2cb53e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -26,7 +26,7 @@
struct ABuffer;
struct AMessage;
-struct MetaData;
+class MetaData;
struct NuPlayerDriver;
struct NuPlayer : public AHandler {
@@ -51,6 +51,7 @@
const sp<IGraphicBufferProducer> &bufferProducer);
void setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink);
+ void setPlaybackRate(float rate);
void start();
void pause();
@@ -104,6 +105,7 @@
kWhatSetVideoNativeWindow = '=NaW',
kWhatSetAudioSink = '=AuS',
kWhatMoreDataQueued = 'more',
+ kWhatSetRate = 'setR',
kWhatStart = 'strt',
kWhatScanSources = 'scan',
kWhatVideoNotify = 'vidN',
@@ -175,6 +177,7 @@
int32_t mVideoScalingMode;
+ float mPlaybackRate;
bool mStarted;
// Actual pause state, either as requested by client or due to buffering.
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
index 9229704..cf3e8ad 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
@@ -19,6 +19,7 @@
#include <utils/Log.h>
#include <inttypes.h>
+#include "avc_utils.h"
#include "NuPlayerCCDecoder.h"
#include <media/stagefright/foundation/ABitReader.h>
@@ -185,17 +186,38 @@
// returns true if a new CC track is found
bool NuPlayer::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) {
- int64_t timeUs;
- CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-
sp<ABuffer> sei;
if (!accessUnit->meta()->findBuffer("sei", &sei) || sei == NULL) {
return false;
}
+ int64_t timeUs;
+ CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
+
bool trackAdded = false;
- NALBitReader br(sei->data() + 1, sei->size() - 1);
+ const NALPosition *nal = (NALPosition *) sei->data();
+
+ for (size_t i = 0; i < sei->size() / sizeof(NALPosition); ++i, ++nal) {
+ trackAdded |= parseSEINalUnit(
+ timeUs, accessUnit->data() + nal->nalOffset, nal->nalSize);
+ }
+
+ return trackAdded;
+}
+
+// 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;
+
+ // the buffer should only have SEI in it
+ if (nalType != 6) {
+ return false;
+ }
+
+ bool trackAdded = false;
+ NALBitReader br(nalStart + 1, nalSize - 1);
// sei_message()
while (br.atLeastNumBitsLeft(16)) { // at least 16-bit for sei_message()
uint32_t payload_type = 0;
@@ -214,20 +236,25 @@
// sei_payload()
if (payload_type == 4) {
- // user_data_registered_itu_t_t35()
+ bool isCC = false;
+ if (payload_size > 1 + 2 + 4 + 1) {
+ // user_data_registered_itu_t_t35()
- // ATSC A/72: 6.4.2
- uint8_t itu_t_t35_country_code = br.getBits(8);
- uint16_t itu_t_t35_provider_code = br.getBits(16);
- uint32_t user_identifier = br.getBits(32);
- uint8_t user_data_type_code = br.getBits(8);
+ // ATSC A/72: 6.4.2
+ uint8_t itu_t_t35_country_code = br.getBits(8);
+ uint16_t itu_t_t35_provider_code = br.getBits(16);
+ uint32_t user_identifier = br.getBits(32);
+ uint8_t user_data_type_code = br.getBits(8);
- payload_size -= 1 + 2 + 4 + 1;
+ payload_size -= 1 + 2 + 4 + 1;
- if (itu_t_t35_country_code == 0xB5
- && itu_t_t35_provider_code == 0x0031
- && user_identifier == 'GA94'
- && user_data_type_code == 0x3) {
+ isCC = itu_t_t35_country_code == 0xB5
+ && itu_t_t35_provider_code == 0x0031
+ && user_identifier == 'GA94'
+ && user_data_type_code == 0x3;
+ }
+
+ if (isCC && payload_size > 2) {
// MPEG_cc_data()
// ATSC A/53 Part 4: 6.2.3.1
br.skipBits(1); //process_em_data_flag
@@ -243,7 +270,7 @@
sp<ABuffer> ccBuf = new ABuffer(cc_count * sizeof(CCData));
ccBuf->setRange(0, 0);
- for (size_t i = 0; i < cc_count; i++) {
+ for (size_t i = 0; i < cc_count && payload_size >= 3; i++) {
uint8_t marker = br.getBits(5);
CHECK_EQ(marker, 0x1f);
@@ -253,6 +280,8 @@
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);
@@ -269,7 +298,6 @@
}
}
}
- payload_size -= cc_count * 3;
mCCMap.add(timeUs, ccBuf);
break;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h
index 5e06f4e..77fb0fe 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h
@@ -49,6 +49,7 @@
bool isTrackValid(size_t index) const;
int32_t getTrackIndex(size_t channel) const;
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);
DISALLOW_EVIL_CONSTRUCTORS(CCDecoder);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 5d98d98..04ac699 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -56,6 +56,7 @@
mIsVideoAVC(false),
mIsSecure(false),
mFormatChangePending(false),
+ mTimeChangePending(false),
mPaused(true),
mResumePending(false),
mComponentName("decoder") {
@@ -121,6 +122,7 @@
CHECK(mCodec == NULL);
mFormatChangePending = false;
+ mTimeChangePending = false;
++mBufferGeneration;
@@ -235,7 +237,7 @@
}
}
-void NuPlayer::Decoder::onFlush(bool notifyComplete) {
+void NuPlayer::Decoder::doFlush(bool notifyComplete) {
if (mCCDecoder != NULL) {
mCCDecoder->flush();
}
@@ -259,13 +261,22 @@
// we attempt to release the buffers even if flush fails.
}
releaseAndResetMediaBuffers();
+}
- if (notifyComplete) {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatFlushCompleted);
- notify->post();
- mPaused = true;
+void NuPlayer::Decoder::onFlush() {
+ doFlush(true);
+
+ if (isDiscontinuityPending()) {
+ // This could happen if the client starts seeking/shutdown
+ // after we queued an EOS for discontinuities.
+ // We can consider discontinuity handled.
+ finishHandleDiscontinuity(false /* flushOnTimeChange */);
}
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kWhatFlushCompleted);
+ notify->post();
+ mPaused = true;
}
void NuPlayer::Decoder::onShutdown(bool notifyComplete) {
@@ -309,16 +320,17 @@
}
void NuPlayer::Decoder::doRequestBuffers() {
- if (mFormatChangePending) {
+ if (isDiscontinuityPending()) {
return;
}
status_t err = OK;
- while (!mDequeuedInputBuffers.empty()) {
+ while (err == OK && !mDequeuedInputBuffers.empty()) {
size_t bufferIx = *mDequeuedInputBuffers.begin();
sp<AMessage> msg = new AMessage();
msg->setSize("buffer-ix", bufferIx);
err = fetchInputData(msg);
- if (err != OK) {
+ if (err != OK && err != ERROR_END_OF_STREAM) {
+ // if EOS, need to queue EOS buffer
break;
}
mDequeuedInputBuffers.erase(mDequeuedInputBuffers.begin());
@@ -336,7 +348,7 @@
}
bool NuPlayer::Decoder::handleAnInputBuffer() {
- if (mFormatChangePending) {
+ if (isDiscontinuityPending()) {
return false;
}
size_t bufferIx = -1;
@@ -391,9 +403,6 @@
}
bool NuPlayer::Decoder::handleAnOutputBuffer() {
- if (mFormatChangePending) {
- return false;
- }
size_t bufferIx = -1;
size_t offset;
size_t size;
@@ -474,17 +483,20 @@
buffer->setRange(offset, size);
buffer->meta()->clear();
buffer->meta()->setInt64("timeUs", timeUs);
- if (flags & MediaCodec::BUFFER_FLAG_EOS) {
- buffer->meta()->setInt32("eos", true);
- notifyResumeCompleteIfNecessary();
- }
+
+ bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
// we do not expect CODECCONFIG or SYNCFRAME for decoder
- sp<AMessage> reply = new AMessage(kWhatRenderBuffer, id());
+ sp<AMessage> reply = new AMessage(kWhatRenderBuffer, this);
reply->setSize("buffer-ix", bufferIx);
reply->setInt32("generation", mBufferGeneration);
- if (mSkipRenderingUntilMediaTimeUs >= 0) {
+ if (eos) {
+ ALOGI("[%s] saw output EOS", mIsAudio ? "audio" : "video");
+
+ buffer->meta()->setInt32("eos", true);
+ reply->setInt32("eos", true);
+ } else if (mSkipRenderingUntilMediaTimeUs >= 0) {
if (timeUs < mSkipRenderingUntilMediaTimeUs) {
ALOGV("[%s] dropping buffer at time %lld as requested.",
mComponentName.c_str(), (long long)timeUs);
@@ -502,7 +514,7 @@
if (mRenderer != NULL) {
// send the buffer to renderer.
mRenderer->queueBuffer(mIsAudio, buffer, reply);
- if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+ if (eos && !isDiscontinuityPending()) {
mRenderer->queueEOS(mIsAudio, ERROR_END_OF_STREAM);
}
}
@@ -533,11 +545,8 @@
}
void NuPlayer::Decoder::requestCodecNotification() {
- if (mFormatChangePending) {
- return;
- }
if (mCodec != NULL) {
- sp<AMessage> reply = new AMessage(kWhatCodecNotify, id());
+ sp<AMessage> reply = new AMessage(kWhatCodecNotify, this);
reply->setInt32("generation", mBufferGeneration);
mCodec->requestActivityNotification(reply);
}
@@ -582,39 +591,31 @@
formatChange = !seamlessFormatChange;
}
- if (formatChange || timeChange) {
- sp<AMessage> msg = mNotify->dup();
- msg->setInt32("what", kWhatInputDiscontinuity);
- msg->setInt32("formatChange", formatChange);
- msg->post();
- }
-
+ // For format or time change, return EOS to queue EOS input,
+ // then wait for EOS on output.
if (formatChange /* not seamless */) {
- // must change decoder
- // return EOS and wait to be killed
mFormatChangePending = true;
- return ERROR_END_OF_STREAM;
+ err = ERROR_END_OF_STREAM;
} else if (timeChange) {
- // need to flush
- // TODO: Ideally we shouldn't need a flush upon time
- // discontinuity, flushing will cause loss of frames.
- // We probably should queue a time change marker to the
- // output queue, and handles it in renderer instead.
rememberCodecSpecificData(newFormat);
- onFlush(false /* notifyComplete */);
- err = OK;
+ mTimeChangePending = true;
+ err = ERROR_END_OF_STREAM;
} else if (seamlessFormatChange) {
// reuse existing decoder and don't flush
rememberCodecSpecificData(newFormat);
- err = OK;
+ continue;
} else {
// This stream is unaffected by the discontinuity
return -EWOULDBLOCK;
}
}
+ // reply should only be returned without a buffer set
+ // when there is an error (including EOS)
+ CHECK(err != OK);
+
reply->setInt32("err", err);
- return OK;
+ return ERROR_END_OF_STREAM;
}
if (!mIsAudio) {
@@ -636,7 +637,7 @@
#if 0
int64_t mediaTimeUs;
CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
- ALOGV("feeding %s input buffer at media time %.2f secs",
+ ALOGV("[%s] feeding input buffer at media time %" PRId64,
mIsAudio ? "audio" : "video",
mediaTimeUs / 1E6);
#endif
@@ -696,10 +697,7 @@
int32_t streamErr = ERROR_END_OF_STREAM;
CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
- if (streamErr == OK) {
- /* buffers are returned to hold on to */
- return true;
- }
+ CHECK(streamErr != OK);
// attempt to queue EOS
status_t err = mCodec->queueInputBuffer(
@@ -781,6 +779,7 @@
status_t err;
int32_t render;
size_t bufferIx;
+ int32_t eos;
CHECK(msg->findSize("buffer-ix", &bufferIx));
if (!mIsAudio) {
@@ -805,6 +804,42 @@
mComponentName.c_str(), err);
handleError(err);
}
+ if (msg->findInt32("eos", &eos) && eos
+ && isDiscontinuityPending()) {
+ finishHandleDiscontinuity(true /* flushOnTimeChange */);
+ }
+}
+
+bool NuPlayer::Decoder::isDiscontinuityPending() const {
+ return mFormatChangePending || mTimeChangePending;
+}
+
+void NuPlayer::Decoder::finishHandleDiscontinuity(bool flushOnTimeChange) {
+ ALOGV("finishHandleDiscontinuity: format %d, time %d, flush %d",
+ mFormatChangePending, mTimeChangePending, flushOnTimeChange);
+
+ // If we have format change, pause and wait to be killed;
+ // If we have time change only, flush and restart fetching.
+
+ if (mFormatChangePending) {
+ mPaused = true;
+ } else if (mTimeChangePending) {
+ if (flushOnTimeChange) {
+ doFlush(false /*notifyComplete*/);
+ }
+
+ // restart fetching input
+ scheduleRequestBuffers();
+ }
+
+ // Notify NuPlayer to either shutdown decoder, or rescan sources
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatInputDiscontinuity);
+ msg->setInt32("formatChange", mFormatChangePending);
+ msg->post();
+
+ mFormatChangePending = false;
+ mTimeChangePending = false;
}
bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index 1bfa94f..4aab2c6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -43,7 +43,7 @@
virtual void onSetRenderer(const sp<Renderer> &renderer);
virtual void onGetInputBuffers(Vector<sp<ABuffer> > *dstBuffers);
virtual void onResume(bool notifyComplete);
- virtual void onFlush(bool notifyComplete);
+ virtual void onFlush();
virtual void onShutdown(bool notifyComplete);
virtual void doRequestBuffers();
@@ -81,6 +81,7 @@
bool mIsVideoAVC;
bool mIsSecure;
bool mFormatChangePending;
+ bool mTimeChangePending;
bool mPaused;
bool mResumePending;
@@ -93,6 +94,7 @@
void requestCodecNotification();
bool isStaleReply(const sp<AMessage> &msg);
+ void doFlush(bool notifyComplete);
status_t fetchInputData(sp<AMessage> &reply);
bool onInputBufferFetched(const sp<AMessage> &msg);
void onRenderBuffer(const sp<AMessage> &msg);
@@ -100,6 +102,8 @@
bool supportsSeamlessFormatChange(const sp<AMessage> &to) const;
bool supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const;
void rememberCodecSpecificData(const sp<AMessage> &format);
+ bool isDiscontinuityPending() const;
+ void finishHandleDiscontinuity(bool flushOnTimeChange);
void notifyResumeCompleteIfNecessary();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
index d56fc4d..4636f0a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
@@ -61,7 +61,7 @@
}
void NuPlayer::DecoderBase::configure(const sp<AMessage> &format) {
- sp<AMessage> msg = new AMessage(kWhatConfigure, id());
+ sp<AMessage> msg = new AMessage(kWhatConfigure, this);
msg->setMessage("format", format);
msg->post();
}
@@ -71,13 +71,13 @@
}
void NuPlayer::DecoderBase::setRenderer(const sp<Renderer> &renderer) {
- sp<AMessage> msg = new AMessage(kWhatSetRenderer, id());
+ sp<AMessage> msg = new AMessage(kWhatSetRenderer, this);
msg->setObject("renderer", renderer);
msg->post();
}
status_t NuPlayer::DecoderBase::getInputBuffers(Vector<sp<ABuffer> > *buffers) const {
- sp<AMessage> msg = new AMessage(kWhatGetInputBuffers, id());
+ sp<AMessage> msg = new AMessage(kWhatGetInputBuffers, this);
msg->setPointer("buffers", buffers);
sp<AMessage> response;
@@ -85,17 +85,17 @@
}
void NuPlayer::DecoderBase::signalFlush() {
- (new AMessage(kWhatFlush, id()))->post();
+ (new AMessage(kWhatFlush, this))->post();
}
void NuPlayer::DecoderBase::signalResume(bool notifyComplete) {
- sp<AMessage> msg = new AMessage(kWhatResume, id());
+ sp<AMessage> msg = new AMessage(kWhatResume, this);
msg->setInt32("notifyComplete", notifyComplete);
msg->post();
}
void NuPlayer::DecoderBase::initiateShutdown() {
- (new AMessage(kWhatShutdown, id()))->post();
+ (new AMessage(kWhatShutdown, this))->post();
}
void NuPlayer::DecoderBase::onRequestInputBuffers() {
@@ -111,7 +111,7 @@
return;
}
mRequestInputBuffersPending = true;
- sp<AMessage> msg = new AMessage(kWhatRequestInputBuffers, id());
+ sp<AMessage> msg = new AMessage(kWhatRequestInputBuffers, this);
msg->post(10 * 1000ll);
}
@@ -136,7 +136,7 @@
case kWhatGetInputBuffers:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
Vector<sp<ABuffer> > *dstBuffers;
@@ -157,7 +157,7 @@
case kWhatFlush:
{
- onFlush(true);
+ onFlush();
break;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
index 6732ff4..97e9269 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
@@ -65,7 +65,7 @@
virtual void onSetRenderer(const sp<Renderer> &renderer) = 0;
virtual void onGetInputBuffers(Vector<sp<ABuffer> > *dstBuffers) = 0;
virtual void onResume(bool notifyComplete) = 0;
- virtual void onFlush(bool notifyComplete) = 0;
+ virtual void onFlush() = 0;
virtual void onShutdown(bool notifyComplete) = 0;
void onRequestInputBuffers();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index 9f7f09a..29b4c26 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -247,7 +247,7 @@
}
if (timeChange) {
- onFlush(false /* notifyComplete */);
+ doFlush(false /* notifyComplete */);
err = OK;
} else if (formatChange) {
// do seamless format change
@@ -333,7 +333,7 @@
return;
}
- sp<AMessage> reply = new AMessage(kWhatBufferConsumed, id());
+ sp<AMessage> reply = new AMessage(kWhatBufferConsumed, this);
reply->setInt32("generation", mBufferGeneration);
reply->setInt32("size", bufferSize);
@@ -364,7 +364,7 @@
}
}
-void NuPlayer::DecoderPassThrough::onFlush(bool notifyComplete) {
+void NuPlayer::DecoderPassThrough::doFlush(bool notifyComplete) {
++mBufferGeneration;
mSkipRenderingUntilMediaTimeUs = -1;
mPendingAudioAccessUnit.clear();
@@ -376,18 +376,21 @@
mRenderer->signalTimeDiscontinuity();
}
- if (notifyComplete) {
- mPaused = true;
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatFlushCompleted);
- notify->post();
- }
-
mPendingBuffersToDrain = 0;
mCachedBytes = 0;
mReachedEOS = false;
}
+void NuPlayer::DecoderPassThrough::onFlush() {
+ doFlush(true /* notifyComplete */);
+
+ mPaused = true;
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kWhatFlushCompleted);
+ notify->post();
+
+}
+
void NuPlayer::DecoderPassThrough::onShutdown(bool notifyComplete) {
++mBufferGeneration;
mSkipRenderingUntilMediaTimeUs = -1;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
index a6e1faf..173cfbd 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
@@ -43,7 +43,7 @@
virtual void onSetRenderer(const sp<Renderer> &renderer);
virtual void onGetInputBuffers(Vector<sp<ABuffer> > *dstBuffers);
virtual void onResume(bool notifyComplete);
- virtual void onFlush(bool notifyComplete);
+ virtual void onFlush();
virtual void onShutdown(bool notifyComplete);
virtual void doRequestBuffers();
@@ -77,6 +77,7 @@
status_t dequeueAccessUnit(sp<ABuffer> *accessUnit);
sp<ABuffer> aggregateBuffer(const sp<ABuffer> &accessUnit);
status_t fetchInputData(sp<AMessage> &reply);
+ void doFlush(bool notifyComplete);
void onInputBufferFetched(const sp<AMessage> &msg);
void onBufferConsumed(int32_t size);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index e7e1759..5887e50 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -341,6 +341,11 @@
return mState == STATE_RUNNING && !mAtEOS;
}
+status_t NuPlayerDriver::setPlaybackRate(float rate) {
+ mPlayer->setPlaybackRate(rate);
+ return OK;
+}
+
status_t NuPlayerDriver::seekTo(int msec) {
ALOGD("seekTo(%p) %d ms", this, msec);
Mutex::Autolock autoLock(mLock);
@@ -351,6 +356,14 @@
case STATE_PREPARED:
case STATE_STOPPED_AND_PREPARED:
{
+ int curpos = 0;
+ if (mPositionUs > 0) {
+ curpos = (mPositionUs + 500ll) / 1000;
+ }
+ if (curpos == msec) {
+ // nothing to do, and doing something anyway could result in deadlock (b/15323063)
+ break;
+ }
mStartupSeekTimeUs = seekTimeUs;
// pretend that the seek completed. It will actually happen when starting playback.
// TODO: actually perform the seek here, so the player is ready to go at the new
@@ -654,8 +667,7 @@
mAutoLoop = false;
}
}
- if (mLooping || (mAutoLoop
- && (mAudioSink == NULL || mAudioSink->realtime()))) {
+ if (mLooping || mAutoLoop) {
mPlayer->seekToAsync(0);
if (mAudioSink != NULL) {
// The renderer has stopped the sink at the end in order to play out
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 5cba7d9..e53abcd 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -47,6 +47,7 @@
virtual status_t stop();
virtual status_t pause();
virtual bool isPlaying();
+ virtual status_t setPlaybackRate(float rate);
virtual status_t seekTo(int msec);
virtual status_t getCurrentPosition(int *msec);
virtual status_t getDuration(int *msec);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 25225a8..4bccfa8 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -25,6 +25,7 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/foundation/AWakeLock.h>
+#include <media/stagefright/MediaClock.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
@@ -63,22 +64,19 @@
mDrainVideoQueuePending(false),
mAudioQueueGeneration(0),
mVideoQueueGeneration(0),
+ mAudioDrainGeneration(0),
+ mVideoDrainGeneration(0),
+ mPlaybackRate(1.0),
mAudioFirstAnchorTimeMediaUs(-1),
mAnchorTimeMediaUs(-1),
- mAnchorTimeRealUs(-1),
mAnchorNumFramesWritten(-1),
- mAnchorMaxMediaUs(-1),
mVideoLateByUs(0ll),
mHasAudio(false),
mHasVideo(false),
- mPauseStartedTimeRealUs(-1),
- mFlushingAudio(false),
- mFlushingVideo(false),
mNotifyCompleteAudio(false),
mNotifyCompleteVideo(false),
mSyncQueues(false),
mPaused(false),
- mPausePositionMediaTimeUs(-1),
mVideoSampleReceived(false),
mVideoRenderingStarted(false),
mVideoRenderingStartGeneration(0),
@@ -90,7 +88,7 @@
mTotalBuffersQueued(0),
mLastAudioBufferDrained(0),
mWakeLock(new AWakeLock()) {
-
+ mMediaClock = new MediaClock;
}
NuPlayer::Renderer::~Renderer() {
@@ -105,7 +103,8 @@
bool audio,
const sp<ABuffer> &buffer,
const sp<AMessage> ¬ifyConsumed) {
- sp<AMessage> msg = new AMessage(kWhatQueueBuffer, id());
+ sp<AMessage> msg = new AMessage(kWhatQueueBuffer, this);
+ msg->setInt32("queueGeneration", getQueueGeneration(audio));
msg->setInt32("audio", static_cast<int32_t>(audio));
msg->setBuffer("buffer", buffer);
msg->setMessage("notifyConsumed", notifyConsumed);
@@ -115,199 +114,108 @@
void NuPlayer::Renderer::queueEOS(bool audio, status_t finalResult) {
CHECK_NE(finalResult, (status_t)OK);
- sp<AMessage> msg = new AMessage(kWhatQueueEOS, id());
+ sp<AMessage> msg = new AMessage(kWhatQueueEOS, this);
+ msg->setInt32("queueGeneration", getQueueGeneration(audio));
msg->setInt32("audio", static_cast<int32_t>(audio));
msg->setInt32("finalResult", finalResult);
msg->post();
}
+void NuPlayer::Renderer::setPlaybackRate(float rate) {
+ sp<AMessage> msg = new AMessage(kWhatSetRate, this);
+ msg->setFloat("rate", rate);
+ msg->post();
+}
+
void NuPlayer::Renderer::flush(bool audio, bool notifyComplete) {
{
- Mutex::Autolock autoLock(mFlushLock);
+ Mutex::Autolock autoLock(mLock);
if (audio) {
mNotifyCompleteAudio |= notifyComplete;
- if (mFlushingAudio) {
- return;
- }
- mFlushingAudio = true;
+ ++mAudioQueueGeneration;
+ ++mAudioDrainGeneration;
} else {
mNotifyCompleteVideo |= notifyComplete;
- if (mFlushingVideo) {
- return;
- }
- mFlushingVideo = true;
+ ++mVideoQueueGeneration;
+ ++mVideoDrainGeneration;
}
+
+ clearAnchorTime_l();
+ clearAudioFirstAnchorTime_l();
+ mVideoLateByUs = 0;
+ mSyncQueues = false;
}
- sp<AMessage> msg = new AMessage(kWhatFlush, id());
+ sp<AMessage> msg = new AMessage(kWhatFlush, this);
msg->setInt32("audio", static_cast<int32_t>(audio));
msg->post();
}
void NuPlayer::Renderer::signalTimeDiscontinuity() {
- Mutex::Autolock autoLock(mLock);
- // CHECK(mAudioQueue.empty());
- // CHECK(mVideoQueue.empty());
- setAudioFirstAnchorTime(-1);
- setAnchorTime(-1, -1);
- setVideoLateByUs(0);
- mSyncQueues = false;
-}
-
-void NuPlayer::Renderer::signalAudioSinkChanged() {
- (new AMessage(kWhatAudioSinkChanged, id()))->post();
}
void NuPlayer::Renderer::signalDisableOffloadAudio() {
- (new AMessage(kWhatDisableOffloadAudio, id()))->post();
+ (new AMessage(kWhatDisableOffloadAudio, this))->post();
}
void NuPlayer::Renderer::signalEnableOffloadAudio() {
- (new AMessage(kWhatEnableOffloadAudio, id()))->post();
+ (new AMessage(kWhatEnableOffloadAudio, this))->post();
}
void NuPlayer::Renderer::pause() {
- (new AMessage(kWhatPause, id()))->post();
+ (new AMessage(kWhatPause, this))->post();
}
void NuPlayer::Renderer::resume() {
- (new AMessage(kWhatResume, id()))->post();
+ (new AMessage(kWhatResume, this))->post();
}
void NuPlayer::Renderer::setVideoFrameRate(float fps) {
- sp<AMessage> msg = new AMessage(kWhatSetVideoFrameRate, id());
+ sp<AMessage> msg = new AMessage(kWhatSetVideoFrameRate, this);
msg->setFloat("frame-rate", fps);
msg->post();
}
-// Called on any threads, except renderer's thread.
-status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs) {
- {
- Mutex::Autolock autoLock(mLock);
- int64_t currentPositionUs;
- if (getCurrentPositionIfPaused_l(¤tPositionUs)) {
- *mediaUs = currentPositionUs;
- return OK;
- }
- }
- return getCurrentPositionFromAnchor(mediaUs, ALooper::GetNowUs());
-}
-
-// Called on only renderer's thread.
-status_t NuPlayer::Renderer::getCurrentPositionOnLooper(int64_t *mediaUs) {
- return getCurrentPositionOnLooper(mediaUs, ALooper::GetNowUs());
-}
-
-// Called on only renderer's thread.
-// Since mPaused and mPausePositionMediaTimeUs are changed only on renderer's
-// thread, no need to acquire mLock.
-status_t NuPlayer::Renderer::getCurrentPositionOnLooper(
- int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo) {
- int64_t currentPositionUs;
- if (getCurrentPositionIfPaused_l(¤tPositionUs)) {
- *mediaUs = currentPositionUs;
- return OK;
- }
- return getCurrentPositionFromAnchor(mediaUs, nowUs, allowPastQueuedVideo);
-}
-
-// Called either with mLock acquired or on renderer's thread.
-bool NuPlayer::Renderer::getCurrentPositionIfPaused_l(int64_t *mediaUs) {
- if (!mPaused || mPausePositionMediaTimeUs < 0ll) {
- return false;
- }
- *mediaUs = mPausePositionMediaTimeUs;
- return true;
-}
-
// Called on any threads.
-status_t NuPlayer::Renderer::getCurrentPositionFromAnchor(
- int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo) {
- Mutex::Autolock autoLock(mTimeLock);
- if (!mHasAudio && !mHasVideo) {
- return NO_INIT;
- }
-
- if (mAnchorTimeMediaUs < 0) {
- return NO_INIT;
- }
-
- int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs;
-
- if (mPauseStartedTimeRealUs != -1) {
- positionUs -= (nowUs - mPauseStartedTimeRealUs);
- }
-
- // limit position to the last queued media time (for video only stream
- // position will be discrete as we don't know how long each frame lasts)
- if (mAnchorMaxMediaUs >= 0 && !allowPastQueuedVideo) {
- if (positionUs > mAnchorMaxMediaUs) {
- positionUs = mAnchorMaxMediaUs;
- }
- }
-
- if (positionUs < mAudioFirstAnchorTimeMediaUs) {
- positionUs = mAudioFirstAnchorTimeMediaUs;
- }
-
- *mediaUs = (positionUs <= 0) ? 0 : positionUs;
- return OK;
+status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs) {
+ return mMediaClock->getMediaTime(ALooper::GetNowUs(), mediaUs);
}
-void NuPlayer::Renderer::setHasMedia(bool audio) {
- Mutex::Autolock autoLock(mTimeLock);
- if (audio) {
- mHasAudio = true;
- } else {
- mHasVideo = true;
- }
+void NuPlayer::Renderer::clearAudioFirstAnchorTime_l() {
+ mAudioFirstAnchorTimeMediaUs = -1;
+ mMediaClock->setStartingTimeMedia(-1);
}
-void NuPlayer::Renderer::setAudioFirstAnchorTime(int64_t mediaUs) {
- Mutex::Autolock autoLock(mTimeLock);
- mAudioFirstAnchorTimeMediaUs = mediaUs;
-}
-
-void NuPlayer::Renderer::setAudioFirstAnchorTimeIfNeeded(int64_t mediaUs) {
- Mutex::Autolock autoLock(mTimeLock);
+void NuPlayer::Renderer::setAudioFirstAnchorTimeIfNeeded_l(int64_t mediaUs) {
if (mAudioFirstAnchorTimeMediaUs == -1) {
mAudioFirstAnchorTimeMediaUs = mediaUs;
+ mMediaClock->setStartingTimeMedia(mediaUs);
}
}
-void NuPlayer::Renderer::setAnchorTime(
- int64_t mediaUs, int64_t realUs, int64_t numFramesWritten, bool resume) {
- Mutex::Autolock autoLock(mTimeLock);
- mAnchorTimeMediaUs = mediaUs;
- mAnchorTimeRealUs = realUs;
- mAnchorNumFramesWritten = numFramesWritten;
- if (resume) {
- mPauseStartedTimeRealUs = -1;
- }
+void NuPlayer::Renderer::clearAnchorTime_l() {
+ mMediaClock->clearAnchor();
+ mAnchorTimeMediaUs = -1;
+ mAnchorNumFramesWritten = -1;
}
void NuPlayer::Renderer::setVideoLateByUs(int64_t lateUs) {
- Mutex::Autolock autoLock(mTimeLock);
+ Mutex::Autolock autoLock(mLock);
mVideoLateByUs = lateUs;
}
int64_t NuPlayer::Renderer::getVideoLateByUs() {
- Mutex::Autolock autoLock(mTimeLock);
+ Mutex::Autolock autoLock(mLock);
return mVideoLateByUs;
}
-void NuPlayer::Renderer::setPauseStartedTimeRealUs(int64_t realUs) {
- Mutex::Autolock autoLock(mTimeLock);
- mPauseStartedTimeRealUs = realUs;
-}
-
status_t NuPlayer::Renderer::openAudioSink(
const sp<AMessage> &format,
bool offloadOnly,
bool hasVideo,
uint32_t flags,
bool *isOffloaded) {
- sp<AMessage> msg = new AMessage(kWhatOpenAudioSink, id());
+ sp<AMessage> msg = new AMessage(kWhatOpenAudioSink, this);
msg->setMessage("format", format);
msg->setInt32("offload-only", offloadOnly);
msg->setInt32("has-video", hasVideo);
@@ -328,7 +236,7 @@
}
void NuPlayer::Renderer::closeAudioSink() {
- sp<AMessage> msg = new AMessage(kWhatCloseAudioSink, id());
+ sp<AMessage> msg = new AMessage(kWhatCloseAudioSink, this);
sp<AMessage> response;
msg->postAndAwaitResponse(&response);
@@ -356,7 +264,7 @@
response->setInt32("err", err);
response->setInt32("offload", offloadingAudio());
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
response->postReply(replyID);
@@ -365,7 +273,7 @@
case kWhatCloseAudioSink:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
onCloseAudioSink();
@@ -384,8 +292,8 @@
case kWhatDrainAudioQueue:
{
int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- if (generation != mAudioQueueGeneration) {
+ CHECK(msg->findInt32("drainGeneration", &generation));
+ if (generation != getDrainGeneration(true /* audio */)) {
break;
}
@@ -407,9 +315,7 @@
// Let's give it more data after about half that time
// has elapsed.
- // kWhatDrainAudioQueue is used for non-offloading mode,
- // and mLock is used only for offloading mode. Therefore,
- // no need to acquire mLock here.
+ Mutex::Autolock autoLock(mLock);
postDrainAudioQueue_l(delayUs / 2);
}
break;
@@ -418,8 +324,8 @@
case kWhatDrainVideoQueue:
{
int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- if (generation != mVideoQueueGeneration) {
+ CHECK(msg->findInt32("drainGeneration", &generation));
+ if (generation != getDrainGeneration(false /* audio */)) {
break;
}
@@ -427,22 +333,20 @@
onDrainVideoQueue();
- Mutex::Autolock autoLock(mLock);
- postDrainVideoQueue_l();
+ postDrainVideoQueue();
break;
}
case kWhatPostDrainVideoQueue:
{
int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- if (generation != mVideoQueueGeneration) {
+ CHECK(msg->findInt32("drainGeneration", &generation));
+ if (generation != getDrainGeneration(false /* audio */)) {
break;
}
mDrainVideoQueuePending = false;
- Mutex::Autolock autoLock(mLock);
- postDrainVideoQueue_l();
+ postDrainVideoQueue();
break;
}
@@ -458,15 +362,19 @@
break;
}
- case kWhatFlush:
+ case kWhatSetRate:
{
- onFlush(msg);
+ CHECK(msg->findFloat("rate", &mPlaybackRate));
+ int32_t ratePermille = (int32_t)(0.5f + 1000 * mPlaybackRate);
+ mPlaybackRate = ratePermille / 1000.0f;
+ mMediaClock->setPlaybackRate(mPlaybackRate);
+ mAudioSink->setPlaybackRatePermille(ratePermille);
break;
}
- case kWhatAudioSinkChanged:
+ case kWhatFlush:
{
- onAudioSinkChanged();
+ onFlush(msg);
break;
}
@@ -511,7 +419,7 @@
case kWhatAudioOffloadPauseTimeout:
{
int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
+ CHECK(msg->findInt32("drainGeneration", &generation));
if (generation != mAudioOffloadPauseTimeoutGeneration) {
break;
}
@@ -538,19 +446,19 @@
}
mDrainAudioQueuePending = true;
- sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, id());
- msg->setInt32("generation", mAudioQueueGeneration);
+ sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, this);
+ msg->setInt32("drainGeneration", mAudioDrainGeneration);
msg->post(delayUs);
}
-void NuPlayer::Renderer::prepareForMediaRenderingStart() {
- mAudioRenderingStartGeneration = mAudioQueueGeneration;
- mVideoRenderingStartGeneration = mVideoQueueGeneration;
+void NuPlayer::Renderer::prepareForMediaRenderingStart_l() {
+ mAudioRenderingStartGeneration = mAudioDrainGeneration;
+ mVideoRenderingStartGeneration = mVideoDrainGeneration;
}
-void NuPlayer::Renderer::notifyIfMediaRenderingStarted() {
- if (mVideoRenderingStartGeneration == mVideoQueueGeneration &&
- mAudioRenderingStartGeneration == mAudioQueueGeneration) {
+void NuPlayer::Renderer::notifyIfMediaRenderingStarted_l() {
+ if (mVideoRenderingStartGeneration == mVideoDrainGeneration &&
+ mAudioRenderingStartGeneration == mAudioDrainGeneration) {
mVideoRenderingStartGeneration = -1;
mAudioRenderingStartGeneration = -1;
@@ -618,7 +526,7 @@
int64_t mediaTimeUs;
CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
- setAudioFirstAnchorTimeIfNeeded(mediaTimeUs);
+ setAudioFirstAnchorTimeIfNeeded_l(mediaTimeUs);
}
size_t copy = entry->mBuffer->size() - entry->mOffset;
@@ -638,25 +546,27 @@
entry = NULL;
}
sizeCopied += copy;
- notifyIfMediaRenderingStarted();
+
+ notifyIfMediaRenderingStarted_l();
}
if (mAudioFirstAnchorTimeMediaUs >= 0) {
int64_t nowUs = ALooper::GetNowUs();
- setAnchorTime(mAudioFirstAnchorTimeMediaUs, nowUs - getPlayedOutAudioDurationUs(nowUs));
+ int64_t nowMediaUs =
+ mAudioFirstAnchorTimeMediaUs + getPlayedOutAudioDurationUs(nowUs);
+ // we don't know how much data we are queueing for offloaded tracks.
+ mMediaClock->updateAnchor(nowMediaUs, nowUs, INT64_MAX);
}
- // we don't know how much data we are queueing for offloaded tracks
- mAnchorMaxMediaUs = -1;
-
if (hasEOS) {
- (new AMessage(kWhatStopAudioSink, id()))->post();
+ (new AMessage(kWhatStopAudioSink, this))->post();
}
return sizeCopied;
}
bool NuPlayer::Renderer::onDrainAudioQueue() {
+#if 0
uint32_t numFramesPlayed;
if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
return false;
@@ -665,7 +575,6 @@
ssize_t numFramesAvailableToWrite =
mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
-#if 0
if (numFramesAvailableToWrite == mAudioSink->frameCount()) {
ALOGI("audio sink underrun");
} else {
@@ -674,10 +583,7 @@
}
#endif
- size_t numBytesAvailableToWrite =
- numFramesAvailableToWrite * mAudioSink->frameSize();
-
- while (numBytesAvailableToWrite > 0 && !mAudioQueue.empty()) {
+ while (!mAudioQueue.empty()) {
QueueEntry *entry = &*mAudioQueue.begin();
mLastAudioBufferDrained = entry->mBufferOrdinal;
@@ -710,14 +616,16 @@
}
size_t copy = entry->mBuffer->size() - entry->mOffset;
- if (copy > numBytesAvailableToWrite) {
- copy = numBytesAvailableToWrite;
- }
- ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset, copy);
+ ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset,
+ copy, false /* blocking */);
if (written < 0) {
// An error in AudioSink write. Perhaps the AudioSink was not properly opened.
- ALOGE("AudioSink write error(%zd) when writing %zu bytes", written, copy);
+ if (written == WOULD_BLOCK) {
+ ALOGW("AudioSink write would block when writing %zu bytes", copy);
+ } else {
+ ALOGE("AudioSink write error(%zd) when writing %zu bytes", written, copy);
+ }
break;
}
@@ -729,73 +637,92 @@
entry = NULL;
}
- numBytesAvailableToWrite -= written;
size_t copiedFrames = written / mAudioSink->frameSize();
mNumFramesWritten += copiedFrames;
- notifyIfMediaRenderingStarted();
+ {
+ Mutex::Autolock autoLock(mLock);
+ notifyIfMediaRenderingStarted_l();
+ }
if (written != (ssize_t)copy) {
// A short count was received from AudioSink::write()
//
- // AudioSink write should block until exactly the number of bytes are delivered.
- // But it may return with a short count (without an error) when:
+ // AudioSink write is called in non-blocking mode.
+ // It may return with a short count when:
//
// 1) Size to be copied is not a multiple of the frame size. We consider this fatal.
- // 2) AudioSink is an AudioCache for data retrieval, and the AudioCache is exceeded.
+ // 2) The data to be copied exceeds the available buffer in AudioSink.
+ // 3) An error occurs and data has been partially copied to the buffer in AudioSink.
+ // 4) AudioSink is an AudioCache for data retrieval, and the AudioCache is exceeded.
// (Case 1)
// Must be a multiple of the frame size. If it is not a multiple of a frame size, it
// needs to fail, as we should not carry over fractional frames between calls.
CHECK_EQ(copy % mAudioSink->frameSize(), 0);
- // (Case 2)
+ // (Case 2, 3, 4)
// Return early to the caller.
// Beware of calling immediately again as this may busy-loop if you are not careful.
- ALOGW("AudioSink write short frame count %zd < %zu", written, copy);
+ ALOGV("AudioSink write short frame count %zd < %zu", written, copy);
break;
}
}
- mAnchorMaxMediaUs =
- mAnchorTimeMediaUs +
- (int64_t)(max((long long)mNumFramesWritten - mAnchorNumFramesWritten, 0LL)
- * 1000LL * mAudioSink->msecsPerFrame());
+ int64_t maxTimeMedia;
+ {
+ Mutex::Autolock autoLock(mLock);
+ maxTimeMedia =
+ mAnchorTimeMediaUs +
+ (int64_t)(max((long long)mNumFramesWritten - mAnchorNumFramesWritten, 0LL)
+ * 1000LL * mAudioSink->msecsPerFrame());
+ }
+ mMediaClock->updateMaxTimeMedia(maxTimeMedia);
return !mAudioQueue.empty();
}
+int64_t NuPlayer::Renderer::getDurationUsIfPlayedAtSampleRate(uint32_t numFrames) {
+ int32_t sampleRate = offloadingAudio() ?
+ mCurrentOffloadInfo.sample_rate : mCurrentPcmInfo.mSampleRate;
+ // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
+ return (int64_t)((int32_t)numFrames * 1000000LL / sampleRate);
+}
+
+// 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 =
- mNumFramesWritten * 1000LL * mAudioSink->msecsPerFrame();
+ int64_t writtenAudioDurationUs = getDurationUsIfPlayedAtSampleRate(mNumFramesWritten);
return writtenAudioDurationUs - getPlayedOutAudioDurationUs(nowUs);
}
int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) {
- int64_t currentPositionUs;
- if (mPaused || getCurrentPositionOnLooper(
- ¤tPositionUs, nowUs, true /* allowPastQueuedVideo */) != OK) {
- // If failed to get current position, e.g. due to audio clock is not ready, then just
- // play out video immediately without delay.
+ int64_t realUs;
+ if (mMediaClock->getRealTimeFor(mediaTimeUs, &realUs) != OK) {
+ // If failed to get current position, e.g. due to audio clock is
+ // not ready, then just play out video immediately without delay.
return nowUs;
}
- return (mediaTimeUs - currentPositionUs) + nowUs;
+ return realUs;
}
void NuPlayer::Renderer::onNewAudioMediaTime(int64_t mediaTimeUs) {
+ Mutex::Autolock autoLock(mLock);
// TRICKY: vorbis decoder generates multiple frames with the same
// timestamp, so only update on the first frame with a given timestamp
if (mediaTimeUs == mAnchorTimeMediaUs) {
return;
}
- setAudioFirstAnchorTimeIfNeeded(mediaTimeUs);
+ setAudioFirstAnchorTimeIfNeeded_l(mediaTimeUs);
int64_t nowUs = ALooper::GetNowUs();
- setAnchorTime(
- mediaTimeUs, nowUs + getPendingAudioPlayoutDurationUs(nowUs), mNumFramesWritten);
+ int64_t nowMediaUs = mediaTimeUs - getPendingAudioPlayoutDurationUs(nowUs);
+ mMediaClock->updateAnchor(nowMediaUs, nowUs, mediaTimeUs);
+ mAnchorNumFramesWritten = mNumFramesWritten;
+ mAnchorTimeMediaUs = mediaTimeUs;
}
-void NuPlayer::Renderer::postDrainVideoQueue_l() {
+// Called without mLock acquired.
+void NuPlayer::Renderer::postDrainVideoQueue() {
if (mDrainVideoQueuePending
- || mSyncQueues
+ || getSyncQueues()
|| (mPaused && mVideoSampleReceived)) {
return;
}
@@ -806,8 +733,8 @@
QueueEntry &entry = *mVideoQueue.begin();
- sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, id());
- msg->setInt32("generation", mVideoQueueGeneration);
+ sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, this);
+ msg->setInt32("drainGeneration", getDrainGeneration(false /* audio */));
if (entry.mBuffer == NULL) {
// EOS doesn't carry a timestamp.
@@ -827,16 +754,19 @@
int64_t mediaTimeUs;
CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
- if (mAnchorTimeMediaUs < 0) {
- setAnchorTime(mediaTimeUs, nowUs);
- mPausePositionMediaTimeUs = mediaTimeUs;
- mAnchorMaxMediaUs = mediaTimeUs;
- realTimeUs = nowUs;
- } else {
- realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
+ {
+ Mutex::Autolock autoLock(mLock);
+ if (mAnchorTimeMediaUs < 0) {
+ mMediaClock->updateAnchor(mediaTimeUs, nowUs, mediaTimeUs);
+ mAnchorTimeMediaUs = mediaTimeUs;
+ realTimeUs = nowUs;
+ } else {
+ realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
+ }
}
if (!mHasAudio) {
- mAnchorMaxMediaUs = mediaTimeUs + 100000; // smooth out videos >= 10fps
+ // smooth out videos >= 10fps
+ mMediaClock->updateMaxTimeMedia(mediaTimeUs + 100000);
}
// Heuristics to handle situation when media time changed without a
@@ -915,16 +845,19 @@
ALOGV("video late by %lld us (%.2f secs)",
mVideoLateByUs, mVideoLateByUs / 1E6);
} else {
+ int64_t mediaUs = 0;
+ mMediaClock->getMediaTime(realTimeUs, &mediaUs);
ALOGV("rendering video at media time %.2f secs",
(mFlags & FLAG_REAL_TIME ? realTimeUs :
- (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6);
+ mediaUs) / 1E6);
}
} else {
setVideoLateByUs(0);
if (!mVideoSampleReceived && !mHasAudio) {
// This will ensure that the first frame after a flush won't be used as anchor
// when renderer is in paused state, because resume can happen any time after seek.
- setAnchorTime(-1, -1);
+ Mutex::Autolock autoLock(mLock);
+ clearAnchorTime_l();
}
}
@@ -941,7 +874,8 @@
mVideoRenderingStarted = true;
notifyVideoRenderingStart();
}
- notifyIfMediaRenderingStarted();
+ Mutex::Autolock autoLock(mLock);
+ notifyIfMediaRenderingStarted_l();
}
}
@@ -960,14 +894,22 @@
}
void NuPlayer::Renderer::notifyAudioOffloadTearDown() {
- (new AMessage(kWhatAudioOffloadTearDown, id()))->post();
+ (new AMessage(kWhatAudioOffloadTearDown, this))->post();
}
void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) {
int32_t audio;
CHECK(msg->findInt32("audio", &audio));
- setHasMedia(audio);
+ if (dropBufferIfStale(audio, msg)) {
+ return;
+ }
+
+ if (audio) {
+ mHasAudio = true;
+ } else {
+ mHasVideo = true;
+ }
if (mHasVideo) {
if (mVideoScheduler == NULL) {
@@ -976,10 +918,6 @@
}
}
- if (dropBufferWhileFlushing(audio, msg)) {
- return;
- }
-
sp<ABuffer> buffer;
CHECK(msg->findBuffer("buffer", &buffer));
@@ -993,15 +931,16 @@
entry.mFinalResult = OK;
entry.mBufferOrdinal = ++mTotalBuffersQueued;
- Mutex::Autolock autoLock(mLock);
if (audio) {
+ Mutex::Autolock autoLock(mLock);
mAudioQueue.push_back(entry);
postDrainAudioQueue_l();
} else {
mVideoQueue.push_back(entry);
- postDrainVideoQueue_l();
+ postDrainVideoQueue();
}
+ Mutex::Autolock autoLock(mLock);
if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) {
return;
}
@@ -1050,7 +989,9 @@
}
if (!mVideoQueue.empty()) {
- postDrainVideoQueue_l();
+ mLock.unlock();
+ postDrainVideoQueue();
+ mLock.lock();
}
}
@@ -1058,7 +999,7 @@
int32_t audio;
CHECK(msg->findInt32("audio", &audio));
- if (dropBufferWhileFlushing(audio, msg)) {
+ if (dropBufferIfStale(audio, msg)) {
return;
}
@@ -1069,19 +1010,20 @@
entry.mOffset = 0;
entry.mFinalResult = finalResult;
- Mutex::Autolock autoLock(mLock);
if (audio) {
+ Mutex::Autolock autoLock(mLock);
if (mAudioQueue.empty() && mSyncQueues) {
syncQueuesDone_l();
}
mAudioQueue.push_back(entry);
postDrainAudioQueue_l();
} else {
- if (mVideoQueue.empty() && mSyncQueues) {
+ if (mVideoQueue.empty() && getSyncQueues()) {
+ Mutex::Autolock autoLock(mLock);
syncQueuesDone_l();
}
mVideoQueue.push_back(entry);
- postDrainVideoQueue_l();
+ postDrainVideoQueue();
}
}
@@ -1090,31 +1032,25 @@
CHECK(msg->findInt32("audio", &audio));
{
- Mutex::Autolock autoLock(mFlushLock);
+ Mutex::Autolock autoLock(mLock);
if (audio) {
- mFlushingAudio = false;
notifyComplete = mNotifyCompleteAudio;
mNotifyCompleteAudio = false;
} else {
- mFlushingVideo = false;
notifyComplete = mNotifyCompleteVideo;
mNotifyCompleteVideo = false;
}
- }
- // If we're currently syncing the queues, i.e. dropping audio while
- // aligning the first audio/video buffer times and only one of the
- // two queues has data, we may starve that queue by not requesting
- // more buffers from the decoder. If the other source then encounters
- // a discontinuity that leads to flushing, we'll never find the
- // corresponding discontinuity on the other queue.
- // Therefore we'll stop syncing the queues if at least one of them
- // is flushed.
- {
- Mutex::Autolock autoLock(mLock);
- syncQueuesDone_l();
- setPauseStartedTimeRealUs(-1);
- setAnchorTime(-1, -1);
+ // If we're currently syncing the queues, i.e. dropping audio while
+ // aligning the first audio/video buffer times and only one of the
+ // two queues has data, we may starve that queue by not requesting
+ // more buffers from the decoder. If the other source then encounters
+ // a discontinuity that leads to flushing, we'll never find the
+ // corresponding discontinuity on the other queue.
+ // Therefore we'll stop syncing the queues if at least one of them
+ // is flushed.
+ syncQueuesDone_l();
+ clearAnchorTime_l();
}
ALOGV("flushing %s", audio ? "audio" : "video");
@@ -1123,11 +1059,11 @@
Mutex::Autolock autoLock(mLock);
flushQueue(&mAudioQueue);
- ++mAudioQueueGeneration;
- prepareForMediaRenderingStart();
+ ++mAudioDrainGeneration;
+ prepareForMediaRenderingStart_l();
if (offloadingAudio()) {
- setAudioFirstAnchorTime(-1);
+ clearAudioFirstAnchorTime_l();
}
}
@@ -1142,13 +1078,14 @@
flushQueue(&mVideoQueue);
mDrainVideoQueuePending = false;
- ++mVideoQueueGeneration;
if (mVideoScheduler != NULL) {
mVideoScheduler->restart();
}
- prepareForMediaRenderingStart();
+ Mutex::Autolock autoLock(mLock);
+ ++mVideoDrainGeneration;
+ prepareForMediaRenderingStart_l();
}
mVideoSampleReceived = false;
@@ -1178,20 +1115,12 @@
notify->post();
}
-bool NuPlayer::Renderer::dropBufferWhileFlushing(
+bool NuPlayer::Renderer::dropBufferIfStale(
bool audio, const sp<AMessage> &msg) {
- bool flushing = false;
+ int32_t queueGeneration;
+ CHECK(msg->findInt32("queueGeneration", &queueGeneration));
- {
- Mutex::Autolock autoLock(mFlushLock);
- if (audio) {
- flushing = mFlushingAudio;
- } else {
- flushing = mFlushingVideo;
- }
- }
-
- if (!flushing) {
+ if (queueGeneration == getQueueGeneration(audio)) {
return false;
}
@@ -1209,7 +1138,10 @@
}
CHECK(!mDrainAudioQueuePending);
mNumFramesWritten = 0;
- mAnchorNumFramesWritten = -1;
+ {
+ Mutex::Autolock autoLock(mLock);
+ mAnchorNumFramesWritten = -1;
+ }
uint32_t written;
if (mAudioSink->getFramesWritten(&written) == OK) {
mNumFramesWritten = written;
@@ -1219,13 +1151,13 @@
void NuPlayer::Renderer::onDisableOffloadAudio() {
Mutex::Autolock autoLock(mLock);
mFlags &= ~FLAG_OFFLOAD_AUDIO;
- ++mAudioQueueGeneration;
+ ++mAudioDrainGeneration;
}
void NuPlayer::Renderer::onEnableOffloadAudio() {
Mutex::Autolock autoLock(mLock);
mFlags |= FLAG_OFFLOAD_AUDIO;
- ++mAudioQueueGeneration;
+ ++mAudioDrainGeneration;
}
void NuPlayer::Renderer::onPause() {
@@ -1234,25 +1166,13 @@
return;
}
int64_t currentPositionUs;
- int64_t pausePositionMediaTimeUs;
- if (getCurrentPositionFromAnchor(
- ¤tPositionUs, ALooper::GetNowUs()) == OK) {
- pausePositionMediaTimeUs = currentPositionUs;
- } else {
- // Set paused position to -1 (unavailabe) if we don't have anchor time
- // This could happen if client does a seekTo() immediately followed by
- // pause(). Renderer will be flushed with anchor time cleared. We don't
- // want to leave stale value in mPausePositionMediaTimeUs.
- pausePositionMediaTimeUs = -1;
- }
{
Mutex::Autolock autoLock(mLock);
- mPausePositionMediaTimeUs = pausePositionMediaTimeUs;
- ++mAudioQueueGeneration;
- ++mVideoQueueGeneration;
- prepareForMediaRenderingStart();
+ ++mAudioDrainGeneration;
+ ++mVideoDrainGeneration;
+ prepareForMediaRenderingStart_l();
mPaused = true;
- setPauseStartedTimeRealUs(ALooper::GetNowUs());
+ mMediaClock->setPlaybackRate(0.0);
}
mDrainAudioQueuePending = false;
@@ -1277,21 +1197,18 @@
mAudioSink->start();
}
- Mutex::Autolock autoLock(mLock);
- mPaused = false;
- if (mPauseStartedTimeRealUs != -1) {
- int64_t newAnchorRealUs =
- mAnchorTimeRealUs + ALooper::GetNowUs() - mPauseStartedTimeRealUs;
- setAnchorTime(
- mAnchorTimeMediaUs, newAnchorRealUs, mAnchorNumFramesWritten, true /* resume */);
- }
+ {
+ Mutex::Autolock autoLock(mLock);
+ mPaused = false;
+ mMediaClock->setPlaybackRate(mPlaybackRate);
- if (!mAudioQueue.empty()) {
- postDrainAudioQueue_l();
+ if (!mAudioQueue.empty()) {
+ postDrainAudioQueue_l();
+ }
}
if (!mVideoQueue.empty()) {
- postDrainVideoQueue_l();
+ postDrainVideoQueue();
}
}
@@ -1302,6 +1219,21 @@
mVideoScheduler->init(fps);
}
+int32_t NuPlayer::Renderer::getQueueGeneration(bool audio) {
+ Mutex::Autolock autoLock(mLock);
+ return (audio ? mAudioQueueGeneration : mVideoQueueGeneration);
+}
+
+int32_t NuPlayer::Renderer::getDrainGeneration(bool audio) {
+ Mutex::Autolock autoLock(mLock);
+ return (audio ? mAudioDrainGeneration : mVideoDrainGeneration);
+}
+
+bool NuPlayer::Renderer::getSyncQueues() {
+ Mutex::Autolock autoLock(mLock);
+ return mSyncQueues;
+}
+
// TODO: Remove unnecessary calls to getPlayedOutAudioDurationUs()
// as it acquires locks and may query the audio driver.
//
@@ -1309,6 +1241,7 @@
// 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;
@@ -1346,9 +1279,8 @@
//ALOGD("getPosition: %d %lld", numFramesPlayed, numFramesPlayedAt);
}
- // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
//CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test
- int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000LL * mAudioSink->msecsPerFrame())
+ int64_t durationUs = getDurationUsIfPlayedAtSampleRate(numFramesPlayed)
+ nowUs - numFramesPlayedAt;
if (durationUs < 0) {
// Occurs when numFramesPlayed position is very small and the following:
@@ -1373,7 +1305,7 @@
mAudioOffloadTornDown = true;
int64_t currentPositionUs;
- if (getCurrentPositionOnLooper(¤tPositionUs) != OK) {
+ if (getCurrentPosition(¤tPositionUs) != OK) {
currentPositionUs = 0;
}
@@ -1390,8 +1322,8 @@
void NuPlayer::Renderer::startAudioOffloadPauseTimeout() {
if (offloadingAudio()) {
mWakeLock->acquire();
- sp<AMessage> msg = new AMessage(kWhatAudioOffloadPauseTimeout, id());
- msg->setInt32("generation", mAudioOffloadPauseTimeoutGeneration);
+ sp<AMessage> msg = new AMessage(kWhatAudioOffloadPauseTimeout, this);
+ msg->setInt32("drainGeneration", mAudioOffloadPauseTimeoutGeneration);
msg->post(kOffloadPauseMaxUs);
}
}
@@ -1487,6 +1419,10 @@
&offloadInfo);
if (err == OK) {
+ if (mPlaybackRate != 1.0) {
+ mAudioSink->setPlaybackRatePermille(
+ (int32_t)(mPlaybackRate * 1000 + 0.5f));
+ }
// If the playback is offloaded to h/w, we pass
// the HAL some metadata information.
// We don't want to do this for PCM because it
@@ -1542,6 +1478,10 @@
return err;
}
mCurrentPcmInfo = info;
+ if (mPlaybackRate != 1.0) {
+ mAudioSink->setPlaybackRatePermille(
+ (int32_t)(mPlaybackRate * 1000 + 0.5f));
+ }
mAudioSink->start();
}
if (audioSinkChanged) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 003d1d0..38843d5 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -24,6 +24,7 @@
struct ABuffer;
class AWakeLock;
+struct MediaClock;
struct VideoFrameScheduler;
struct NuPlayer::Renderer : public AHandler {
@@ -47,6 +48,8 @@
void queueEOS(bool audio, status_t finalResult);
+ void setPlaybackRate(float rate);
+
void flush(bool audio, bool notifyComplete);
void signalTimeDiscontinuity();
@@ -61,16 +64,8 @@
void setVideoFrameRate(float fps);
- // Following setters and getters are protected by mTimeLock.
status_t getCurrentPosition(int64_t *mediaUs);
- void setHasMedia(bool audio);
- void setAudioFirstAnchorTime(int64_t mediaUs);
- void setAudioFirstAnchorTimeIfNeeded(int64_t mediaUs);
- void setAnchorTime(
- int64_t mediaUs, int64_t realUs, int64_t numFramesWritten = -1, bool resume = false);
- void setVideoLateByUs(int64_t lateUs);
int64_t getVideoLateByUs();
- void setPauseStartedTimeRealUs(int64_t realUs);
status_t openAudioSink(
const sp<AMessage> &format,
@@ -107,8 +102,8 @@
kWhatPostDrainVideoQueue = 'pDVQ',
kWhatQueueBuffer = 'queB',
kWhatQueueEOS = 'qEOS',
+ kWhatSetRate = 'setR',
kWhatFlush = 'flus',
- kWhatAudioSinkChanged = 'auSC',
kWhatPause = 'paus',
kWhatResume = 'resm',
kWhatOpenAudioSink = 'opnA',
@@ -142,26 +137,18 @@
bool mDrainVideoQueuePending;
int32_t mAudioQueueGeneration;
int32_t mVideoQueueGeneration;
+ int32_t mAudioDrainGeneration;
+ int32_t mVideoDrainGeneration;
- Mutex mTimeLock;
- // |mTimeLock| protects the following 7 member vars that are related to time.
- // Note: those members are only written on Renderer thread, so reading on Renderer thread
- // doesn't need to be protected. Otherwise accessing those members must be protected by
- // |mTimeLock|.
- // TODO: move those members to a seperated media clock class.
+ sp<MediaClock> mMediaClock;
+ float mPlaybackRate;
int64_t mAudioFirstAnchorTimeMediaUs;
int64_t mAnchorTimeMediaUs;
- int64_t mAnchorTimeRealUs;
int64_t mAnchorNumFramesWritten;
- int64_t mAnchorMaxMediaUs;
int64_t mVideoLateByUs;
bool mHasAudio;
bool mHasVideo;
- int64_t mPauseStartedTimeRealUs;
- Mutex mFlushLock; // protects the following 2 member vars.
- bool mFlushingAudio;
- bool mFlushingVideo;
bool mNotifyCompleteAudio;
bool mNotifyCompleteVideo;
@@ -169,7 +156,6 @@
// modified on only renderer's thread.
bool mPaused;
- int64_t mPausePositionMediaTimeUs;
bool mVideoSampleReceived;
bool mVideoRenderingStarted;
@@ -211,14 +197,19 @@
int64_t getPlayedOutAudioDurationUs(int64_t nowUs);
void postDrainAudioQueue_l(int64_t delayUs = 0);
+ void clearAnchorTime_l();
+ void clearAudioFirstAnchorTime_l();
+ void setAudioFirstAnchorTimeIfNeeded_l(int64_t mediaUs);
+ void setVideoLateByUs(int64_t lateUs);
+
void onNewAudioMediaTime(int64_t mediaTimeUs);
int64_t getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs);
void onDrainVideoQueue();
- void postDrainVideoQueue_l();
+ void postDrainVideoQueue();
- void prepareForMediaRenderingStart();
- void notifyIfMediaRenderingStarted();
+ void prepareForMediaRenderingStart_l();
+ void notifyIfMediaRenderingStarted_l();
void onQueueBuffer(const sp<AMessage> &msg);
void onQueueEOS(const sp<AMessage> &msg);
@@ -229,6 +220,9 @@
void onPause();
void onResume();
void onSetVideoFrameRate(float fps);
+ int32_t getQueueGeneration(bool audio);
+ int32_t getDrainGeneration(bool audio);
+ bool getSyncQueues();
void onAudioOffloadTearDown(AudioOffloadTearDownReason reason);
status_t onOpenAudioSink(
const sp<AMessage> &format,
@@ -245,7 +239,7 @@
void notifyAudioOffloadTearDown();
void flushQueue(List<QueueEntry> *queue);
- bool dropBufferWhileFlushing(bool audio, const sp<AMessage> &msg);
+ bool dropBufferIfStale(bool audio, const sp<AMessage> &msg);
void syncQueuesDone_l();
bool offloadingAudio() const { return (mFlags & FLAG_OFFLOAD_AUDIO) != 0; }
@@ -253,6 +247,8 @@
void startAudioOffloadPauseTimeout();
void cancelAudioOffloadPauseTimeout();
+ int64_t getDurationUsIfPlayedAtSampleRate(uint32_t numFrames);
+
DISALLOW_EVIL_CONSTRUCTORS(Renderer);
};
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 8f18464..5a8beb1 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -28,7 +28,6 @@
namespace android {
struct ABuffer;
-struct MetaData;
struct MediaBuffer;
struct NuPlayer::Source : public AHandler {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp
index 885ebe4..f53afbd 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp
@@ -29,9 +29,9 @@
NuPlayer::NuPlayerStreamListener::NuPlayerStreamListener(
const sp<IStreamSource> &source,
- ALooper::handler_id id)
+ const sp<AHandler> &targetHandler)
: mSource(source),
- mTargetID(id),
+ mTargetHandler(targetHandler),
mEOS(false),
mSendDataNotification(true) {
mSource->setListener(this);
@@ -65,8 +65,8 @@
if (mSendDataNotification) {
mSendDataNotification = false;
- if (mTargetID != 0) {
- (new AMessage(kWhatMoreDataQueued, mTargetID))->post();
+ if (mTargetHandler != NULL) {
+ (new AMessage(kWhatMoreDataQueued, mTargetHandler))->post();
}
}
}
@@ -86,8 +86,8 @@
if (mSendDataNotification) {
mSendDataNotification = false;
- if (mTargetID != 0) {
- (new AMessage(kWhatMoreDataQueued, mTargetID))->post();
+ if (mTargetHandler != NULL) {
+ (new AMessage(kWhatMoreDataQueued, mTargetHandler))->post();
}
}
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h
index 1874d80..2de829b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h
@@ -29,7 +29,7 @@
struct NuPlayer::NuPlayerStreamListener : public BnStreamListener {
NuPlayerStreamListener(
const sp<IStreamSource> &source,
- ALooper::handler_id targetID);
+ const sp<AHandler> &targetHandler);
virtual void queueBuffer(size_t index, size_t size);
@@ -59,7 +59,7 @@
Mutex mLock;
sp<IStreamSource> mSource;
- ALooper::handler_id mTargetID;
+ sp<AHandler> mTargetHandler;
sp<MemoryDealer> mMemoryDealer;
Vector<sp<IMemory> > mBuffers;
List<QueueEntry> mQueue;
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 0282a9f..5210fc8 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -87,7 +87,7 @@
CHECK(mHandler == NULL);
CHECK(mSDPLoader == NULL);
- sp<AMessage> notify = new AMessage(kWhatNotify, id());
+ sp<AMessage> notify = new AMessage(kWhatNotify, this);
CHECK_EQ(mState, (int)DISCONNECTED);
mState = CONNECTING;
@@ -116,7 +116,7 @@
if (mLooper == NULL) {
return;
}
- sp<AMessage> msg = new AMessage(kWhatDisconnect, id());
+ sp<AMessage> msg = new AMessage(kWhatDisconnect, this);
sp<AMessage> dummy;
msg->postAndAwaitResponse(&dummy);
@@ -292,7 +292,7 @@
}
status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) {
- sp<AMessage> msg = new AMessage(kWhatPerformSeek, id());
+ sp<AMessage> msg = new AMessage(kWhatPerformSeek, this);
msg->setInt32("generation", ++mSeekGeneration);
msg->setInt64("timeUs", seekTimeUs);
msg->post(200000ll);
@@ -311,7 +311,7 @@
void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
if (msg->what() == kWhatDisconnect) {
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
mDisconnectReplyID = replyID;
@@ -600,7 +600,7 @@
ALOGE("Unable to find url in SDP");
err = UNKNOWN_ERROR;
} else {
- sp<AMessage> notify = new AMessage(kWhatNotify, id());
+ sp<AMessage> notify = new AMessage(kWhatNotify, this);
mHandler = new MyHandler(rtspUri.c_str(), notify, mUIDValid, mUID);
mLooper->registerHandler(mHandler);
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index ac3299a..5f2cf33 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -25,6 +25,7 @@
namespace android {
struct ALooper;
+struct AReplyToken;
struct AnotherPacketSource;
struct MyHandler;
struct SDPLoader;
@@ -96,7 +97,7 @@
bool mIsSDP;
State mState;
status_t mFinalResult;
- uint32_t mDisconnectReplyID;
+ sp<AReplyToken> mDisconnectReplyID;
Mutex mBufferingLock;
bool mBuffering;
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index b3f224d..0246b59 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -63,7 +63,7 @@
}
void NuPlayer::StreamingSource::start() {
- mStreamListener = new NuPlayerStreamListener(mSource, 0);
+ mStreamListener = new NuPlayerStreamListener(mSource, NULL);
uint32_t sourceFlags = mSource->flags();
@@ -163,7 +163,7 @@
mBuffering = true;
}
- (new AMessage(kWhatReadBuffer, id()))->post();
+ (new AMessage(kWhatReadBuffer, this))->post();
return OK;
}
diff --git a/media/libmediaplayerservice/tests/Android.mk b/media/libmediaplayerservice/tests/Android.mk
new file mode 100644
index 0000000..7bc78ff
--- /dev/null
+++ b/media/libmediaplayerservice/tests/Android.mk
@@ -0,0 +1,24 @@
+# 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_32_BIT_ONLY := true
+
+include $(BUILD_NATIVE_TEST)
+
diff --git a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
new file mode 100644
index 0000000..27b482b
--- /dev/null
+++ b/media/libmediaplayerservice/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 "ProcessInfoInterface.h"
+#include <media/stagefright/foundation/ADebug.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(2, map.size());
+ ssize_t index1 = map.indexOfKey(kTestPid1);
+ ASSERT_GE(index1, 0);
+ const SessionInfos& infos1 = map[index1];
+ EXPECT_EQ(1, 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(2, 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(2, map.size());
+ const SessionInfos& infos1 = map.valueFor(kTestPid1);
+ const SessionInfos& infos2 = map.valueFor(kTestPid2);
+ EXPECT_EQ(1, infos1.size());
+ EXPECT_EQ(1, 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(1, 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(1, 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(1, 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/media/libnbaio/Android.mk b/media/libnbaio/Android.mk
index 9707c4a..1353f28 100644
--- a/media/libnbaio/Android.mk
+++ b/media/libnbaio/Android.mk
@@ -11,7 +11,6 @@
MonoPipeReader.cpp \
Pipe.cpp \
PipeReader.cpp \
- roundup.c \
SourceAudioBufferProvider.cpp
LOCAL_SRC_FILES += NBLog.cpp
@@ -27,12 +26,13 @@
LOCAL_MODULE := libnbaio
LOCAL_SHARED_LIBRARIES := \
+ libaudioutils \
libbinder \
libcommon_time_client \
libcutils \
libutils \
liblog
-LOCAL_STATIC_LIBRARIES += libinstantssq
+LOCAL_C_INCLUDES := $(call include-path-for, audio-utils)
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libnbaio/MonoPipe.cpp b/media/libnbaio/MonoPipe.cpp
index 0b65861..129e9ef 100644
--- a/media/libnbaio/MonoPipe.cpp
+++ b/media/libnbaio/MonoPipe.cpp
@@ -27,7 +27,7 @@
#include <utils/Trace.h>
#include <media/AudioBufferProvider.h>
#include <media/nbaio/MonoPipe.h>
-#include <media/nbaio/roundup.h>
+#include <audio_utils/roundup.h>
namespace android {
diff --git a/media/libnbaio/MonoPipeReader.cpp b/media/libnbaio/MonoPipeReader.cpp
index de82229..e4d3ed8 100644
--- a/media/libnbaio/MonoPipeReader.cpp
+++ b/media/libnbaio/MonoPipeReader.cpp
@@ -39,7 +39,7 @@
return NEGOTIATE;
}
ssize_t ret = android_atomic_acquire_load(&mPipe->mRear) - mPipe->mFront;
- ALOG_ASSERT((0 <= ret) && (ret <= mMaxFrames));
+ ALOG_ASSERT((0 <= ret) && ((size_t) ret <= mPipe->mMaxFrames));
return ret;
}
diff --git a/media/libnbaio/Pipe.cpp b/media/libnbaio/Pipe.cpp
index 6e0ec8c..13f211d 100644
--- a/media/libnbaio/Pipe.cpp
+++ b/media/libnbaio/Pipe.cpp
@@ -21,7 +21,7 @@
#include <cutils/compiler.h>
#include <utils/Log.h>
#include <media/nbaio/Pipe.h>
-#include <media/nbaio/roundup.h>
+#include <audio_utils/roundup.h>
namespace android {
diff --git a/media/libnbaio/roundup.c b/media/libnbaio/roundup.c
deleted file mode 100644
index 1d552d1..0000000
--- a/media/libnbaio/roundup.c
+++ /dev/null
@@ -1,32 +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.
- */
-
-#include <media/nbaio/roundup.h>
-
-unsigned roundup(unsigned v)
-{
- // __builtin_clz is undefined for zero input
- if (v == 0) {
- v = 1;
- }
- int lz = __builtin_clz((int) v);
- unsigned rounded = ((unsigned) 0x80000000) >> lz;
- // 0x800000001 and higher are actually rounded _down_ to prevent overflow
- if (v > rounded && lz > 0) {
- rounded <<= 1;
- }
- return rounded;
-}
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index 7cc9430..9d90dbd 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -36,33 +36,19 @@
namespace android {
-AACWriter::AACWriter(const char *filename)
- : mFd(-1),
- mInitCheck(NO_INIT),
- mStarted(false),
- mPaused(false),
- mResumed(false),
- mChannelCount(-1),
- mSampleRate(-1),
- mAACProfile(OMX_AUDIO_AACObjectLC) {
-
- ALOGV("AACWriter Constructor");
-
- mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
- if (mFd >= 0) {
- mInitCheck = OK;
- }
-}
-
AACWriter::AACWriter(int fd)
: mFd(dup(fd)),
mInitCheck(mFd < 0? NO_INIT: OK),
mStarted(false),
mPaused(false),
mResumed(false),
+ mThread(0),
+ mEstimatedSizeBytes(0),
+ mEstimatedDurationUs(0),
mChannelCount(-1),
mSampleRate(-1),
- mAACProfile(OMX_AUDIO_AACObjectLC) {
+ mAACProfile(OMX_AUDIO_AACObjectLC),
+ mFrameDurationUs(0) {
}
AACWriter::~AACWriter() {
@@ -80,10 +66,6 @@
return mInitCheck;
}
-static int writeInt8(int fd, uint8_t x) {
- return ::write(fd, &x, 1);
-}
-
status_t AACWriter::addSource(const sp<MediaSource> &source) {
if (mInitCheck != OK) {
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index e015f1a..c75d4df 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -419,6 +419,7 @@
mMetaDataBuffersToSubmit(0),
mRepeatFrameDelayUs(-1ll),
mMaxPtsGapUs(-1ll),
+ mMaxFps(-1),
mTimePerFrameUs(-1ll),
mTimePerCaptureUs(-1ll),
mCreateInputBuffersSuspended(false),
@@ -451,61 +452,61 @@
void ACodec::initiateSetup(const sp<AMessage> &msg) {
msg->setWhat(kWhatSetup);
- msg->setTarget(id());
+ msg->setTarget(this);
msg->post();
}
void ACodec::signalSetParameters(const sp<AMessage> ¶ms) {
- sp<AMessage> msg = new AMessage(kWhatSetParameters, id());
+ sp<AMessage> msg = new AMessage(kWhatSetParameters, this);
msg->setMessage("params", params);
msg->post();
}
void ACodec::initiateAllocateComponent(const sp<AMessage> &msg) {
msg->setWhat(kWhatAllocateComponent);
- msg->setTarget(id());
+ msg->setTarget(this);
msg->post();
}
void ACodec::initiateConfigureComponent(const sp<AMessage> &msg) {
msg->setWhat(kWhatConfigureComponent);
- msg->setTarget(id());
+ msg->setTarget(this);
msg->post();
}
void ACodec::initiateCreateInputSurface() {
- (new AMessage(kWhatCreateInputSurface, id()))->post();
+ (new AMessage(kWhatCreateInputSurface, this))->post();
}
void ACodec::signalEndOfInputStream() {
- (new AMessage(kWhatSignalEndOfInputStream, id()))->post();
+ (new AMessage(kWhatSignalEndOfInputStream, this))->post();
}
void ACodec::initiateStart() {
- (new AMessage(kWhatStart, id()))->post();
+ (new AMessage(kWhatStart, this))->post();
}
void ACodec::signalFlush() {
ALOGV("[%s] signalFlush", mComponentName.c_str());
- (new AMessage(kWhatFlush, id()))->post();
+ (new AMessage(kWhatFlush, this))->post();
}
void ACodec::signalResume() {
- (new AMessage(kWhatResume, id()))->post();
+ (new AMessage(kWhatResume, this))->post();
}
void ACodec::initiateShutdown(bool keepComponentAllocated) {
- sp<AMessage> msg = new AMessage(kWhatShutdown, id());
+ sp<AMessage> msg = new AMessage(kWhatShutdown, this);
msg->setInt32("keepComponentAllocated", keepComponentAllocated);
msg->post();
if (!keepComponentAllocated) {
// ensure shutdown completes in 3 seconds
- (new AMessage(kWhatReleaseCodecInstance, id()))->post(3000000);
+ (new AMessage(kWhatReleaseCodecInstance, this))->post(3000000);
}
}
void ACodec::signalRequestIDRFrame() {
- (new AMessage(kWhatRequestIDRFrame, id()))->post();
+ (new AMessage(kWhatRequestIDRFrame, this))->post();
}
// *** NOTE: THE FOLLOWING WORKAROUND WILL BE REMOVED ***
@@ -516,7 +517,7 @@
void ACodec::signalSubmitOutputMetaDataBufferIfEOS_workaround() {
if (mPortEOS[kPortIndexInput] && !mPortEOS[kPortIndexOutput] &&
mMetaDataBuffersToSubmit > 0) {
- (new AMessage(kWhatSubmitOutputMetaDataBufferIfEOS, id()))->post();
+ (new AMessage(kWhatSubmitOutputMetaDataBufferIfEOS, this))->post();
}
}
@@ -935,7 +936,6 @@
ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() {
ANativeWindowBuffer *buf;
- int fenceFd = -1;
CHECK(mNativeWindow.get() != NULL);
if (mTunneled) {
@@ -1260,6 +1260,10 @@
mMaxPtsGapUs = -1ll;
}
+ if (!msg->findFloat("max-fps-to-encoder", &mMaxFps)) {
+ mMaxFps = -1;
+ }
+
if (!msg->findInt64("time-lapse", &mTimePerCaptureUs)) {
mTimePerCaptureUs = -1ll;
}
@@ -3255,7 +3259,6 @@
}
void ACodec::deferMessage(const sp<AMessage> &msg) {
- bool wasEmptyBefore = mDeferredQueue.empty();
mDeferredQueue.push_back(msg);
}
@@ -3963,7 +3966,6 @@
// on the screen and then been replaced, so an previous video frames are
// guaranteed NOT to be currently displayed.
for (int i = 0; i < numBufs + 1; i++) {
- int fenceFd = -1;
err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &anb);
if (err != NO_ERROR) {
ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
@@ -4296,7 +4298,7 @@
info->mData->meta()->clear();
notify->setBuffer("buffer", info->mData);
- sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, mCodec->id());
+ sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, mCodec);
reply->setInt32("buffer-id", info->mBufferID);
notify->setMessage("reply", reply);
@@ -4556,7 +4558,7 @@
}
sp<AMessage> reply =
- new AMessage(kWhatOutputBufferDrained, mCodec->id());
+ new AMessage(kWhatOutputBufferDrained, mCodec);
if (!mCodec->mSentFormat && rangeLength > 0) {
mCodec->sendFormatChange(reply);
@@ -4742,7 +4744,7 @@
ALOGV("Now uninitialized");
if (mDeathNotifier != NULL) {
- mCodec->mOMX->asBinder()->unlinkToDeath(mDeathNotifier);
+ IInterface::asBinder(mCodec->mOMX)->unlinkToDeath(mDeathNotifier);
mDeathNotifier.clear();
}
@@ -4832,10 +4834,10 @@
sp<IOMX> omx = client.interface();
- sp<AMessage> notify = new AMessage(kWhatOMXDied, mCodec->id());
+ sp<AMessage> notify = new AMessage(kWhatOMXDied, mCodec);
mDeathNotifier = new DeathNotifier(notify);
- if (omx->asBinder()->linkToDeath(mDeathNotifier) != OK) {
+ 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();
@@ -4880,7 +4882,7 @@
componentName = matchingCodecs.itemAt(matchIndex).mName.string();
quirks = matchingCodecs.itemAt(matchIndex).mQuirks;
- pid_t tid = androidGetTid();
+ pid_t tid = gettid();
int prevPriority = androidGetThreadPriority(tid);
androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);
status_t err = omx->allocateNode(componentName.c_str(), observer, &node);
@@ -4907,7 +4909,7 @@
return false;
}
- notify = new AMessage(kWhatOMXMessage, mCodec->id());
+ notify = new AMessage(kWhatOMXMessage, mCodec);
observer->setNotificationMessage(notify);
mCodec->mComponentName = componentName;
@@ -5113,6 +5115,21 @@
}
}
+ if (err == OK && mCodec->mMaxFps > 0) {
+ err = mCodec->mOMX->setInternalOption(
+ mCodec->mNode,
+ kPortIndexInput,
+ IOMX::INTERNAL_OPTION_MAX_FPS,
+ &mCodec->mMaxFps,
+ sizeof(mCodec->mMaxFps));
+
+ if (err != OK) {
+ ALOGE("[%s] Unable to configure max fps (err %d)",
+ mCodec->mComponentName.c_str(),
+ err);
+ }
+ }
+
if (err == OK && mCodec->mTimePerCaptureUs > 0ll
&& mCodec->mTimePerFrameUs > 0ll) {
int64_t timeLapse[2];
@@ -5667,6 +5684,7 @@
case kWhatFlush:
case kWhatShutdown:
case kWhatResume:
+ case kWhatSetParameters:
{
if (msg->what() == kWhatResume) {
ALOGV("[%s] Deferring resume", mCodec->mComponentName.c_str());
@@ -5982,7 +6000,7 @@
case OMX_EventPortSettingsChanged:
{
- sp<AMessage> msg = new AMessage(kWhatOMXMessage, mCodec->id());
+ sp<AMessage> msg = new AMessage(kWhatOMXMessage, mCodec);
msg->setInt32("type", omx_message::EVENT);
msg->setInt32("node", mCodec->mNode);
msg->setInt32("event", event);
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 9aa7d95..f53d7f0 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -31,19 +31,6 @@
namespace android {
-AMRWriter::AMRWriter(const char *filename)
- : mFd(-1),
- mInitCheck(NO_INIT),
- mStarted(false),
- mPaused(false),
- mResumed(false) {
-
- mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
- if (mFd >= 0) {
- mInitCheck = OK;
- }
-}
-
AMRWriter::AMRWriter(int fd)
: mFd(dup(fd)),
mInitCheck(mFd < 0? NO_INIT: OK),
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 193f8a7..38f2e34 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -31,11 +31,13 @@
MediaAdapter.cpp \
MediaBuffer.cpp \
MediaBufferGroup.cpp \
+ MediaClock.cpp \
MediaCodec.cpp \
MediaCodecList.cpp \
MediaCodecSource.cpp \
MediaDefs.cpp \
MediaExtractor.cpp \
+ MidiExtractor.cpp \
http/MediaHTTP.cpp \
MediaMuxer.cpp \
MediaSource.cpp \
@@ -68,11 +70,8 @@
$(TOP)/frameworks/native/include/media/openmax \
$(TOP)/external/flac/include \
$(TOP)/external/tremolo \
- $(TOP)/external/openssl/include \
$(TOP)/external/libvpx/libwebm \
$(TOP)/system/netd/include \
- $(TOP)/external/icu/icu4c/source/common \
- $(TOP)/external/icu/icu4c/source/i18n \
LOCAL_SHARED_LIBRARIES := \
libbinder \
@@ -103,6 +102,7 @@
libstagefright_color_conversion \
libstagefright_aacenc \
libstagefright_matroska \
+ libstagefright_mediafilter \
libstagefright_webm \
libstagefright_timedtext \
libvpx \
@@ -110,13 +110,14 @@
libstagefright_mpeg2ts \
libstagefright_id3 \
libFLAC \
- libmedia_helper
+ libmedia_helper \
LOCAL_SHARED_LIBRARIES += \
libstagefright_enc_common \
libstagefright_avc_common \
libstagefright_foundation \
- libdl
+ libdl \
+ libRScpp \
LOCAL_CFLAGS += -Wno-multichar
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 007c090..87eef1e 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -889,10 +889,7 @@
}
}
if ((mFlags & LOOPING)
- || ((mFlags & AUTO_LOOPING)
- && (mAudioSink == NULL || mAudioSink->realtime()))) {
- // Don't AUTO_LOOP if we're being recorded, since that cannot be
- // turned off and recording would go on indefinitely.
+ || (mFlags & AUTO_LOOPING)) {
seekTo_l(0);
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index c3a940a..ad12bdd 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -219,7 +219,7 @@
mCameraFlags |= FLAGS_HOT_CAMERA;
mDeathNotifier = new DeathNotifier();
// isBinderAlive needs linkToDeath to work.
- mCameraRecordingProxy->asBinder()->linkToDeath(mDeathNotifier);
+ IInterface::asBinder(mCameraRecordingProxy)->linkToDeath(mDeathNotifier);
}
mCamera->lock();
@@ -702,7 +702,7 @@
{
Mutex::Autolock autoLock(mLock);
if (mCameraRecordingProxy != 0) {
- mCameraRecordingProxy->asBinder()->unlinkToDeath(mDeathNotifier);
+ IInterface::asBinder(mCameraRecordingProxy)->unlinkToDeath(mDeathNotifier);
mCameraRecordingProxy.clear();
}
mCameraFlags = 0;
@@ -825,7 +825,7 @@
mFrameAvailableCondition.waitRelative(mLock,
mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) {
if (mCameraRecordingProxy != 0 &&
- !mCameraRecordingProxy->asBinder()->isBinderAlive()) {
+ !IInterface::asBinder(mCameraRecordingProxy)->isBinderAlive()) {
ALOGW("camera recording proxy is gone");
return ERROR_END_OF_STREAM;
}
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index c99db84..f7dcf35 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -22,6 +22,7 @@
#include "include/DRMExtractor.h"
#include "include/FLACExtractor.h"
#include "include/HTTPBase.h"
+#include "include/MidiExtractor.h"
#include "include/MP3Extractor.h"
#include "include/MPEG2PSExtractor.h"
#include "include/MPEG2TSExtractor.h"
@@ -172,6 +173,7 @@
RegisterSniffer_l(SniffAAC);
RegisterSniffer_l(SniffMPEG2PS);
RegisterSniffer_l(SniffWVM);
+ RegisterSniffer_l(SniffMidi);
char value[PROPERTY_VALUE_MAX];
if (property_get("drm.service.enabled", value, NULL)
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index a7ca3da..f0db76b 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FileSource"
+#include <utils/Log.h>
+
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/FileSource.h>
#include <sys/types.h>
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
index 0c2ff15..77a652a 100644
--- a/media/libstagefright/HTTPBase.cpp
+++ b/media/libstagefright/HTTPBase.cpp
@@ -75,7 +75,11 @@
bool HTTPBase::estimateBandwidth(int32_t *bandwidth_bps) {
Mutex::Autolock autoLock(mLock);
- if (mNumBandwidthHistoryItems < 2) {
+ // Do not do bandwidth estimation if we don't have enough samples, or
+ // total bytes download are too small (<64K).
+ // Bandwidth estimation from these samples can often shoot up and cause
+ // unwanted bw adaption behaviors.
+ if (mNumBandwidthHistoryItems < 2 || mTotalTransferBytes < 65536) {
return false;
}
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index 9856f92..ef07aa0 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -135,7 +135,7 @@
mNotify = notify;
- (new AMessage(kWhatStart, id()))->post();
+ (new AMessage(kWhatStart, this))->post();
}
void MPEG2TSWriter::SourceInfo::stop() {
@@ -361,7 +361,7 @@
}
void MPEG2TSWriter::SourceInfo::readMore() {
- (new AMessage(kWhatRead, id()))->post();
+ (new AMessage(kWhatRead, this))->post();
}
void MPEG2TSWriter::SourceInfo::onMessageReceived(const sp<AMessage> &msg) {
@@ -480,19 +480,6 @@
init();
}
-MPEG2TSWriter::MPEG2TSWriter(const char *filename)
- : mFile(fopen(filename, "wb")),
- mWriteCookie(NULL),
- mWriteFunc(NULL),
- mStarted(false),
- mNumSourcesDone(0),
- mNumTSPacketsWritten(0),
- mNumTSPacketsBeforeMeta(0),
- mPATContinuityCounter(0),
- mPMTContinuityCounter(0) {
- init();
-}
-
MPEG2TSWriter::MPEG2TSWriter(
void *cookie,
ssize_t (*write)(void *cookie, const void *data, size_t size))
@@ -565,7 +552,7 @@
for (size_t i = 0; i < mSources.size(); ++i) {
sp<AMessage> notify =
- new AMessage(kWhatSourceNotify, mReflector->id());
+ new AMessage(kWhatSourceNotify, mReflector);
notify->setInt32("source-index", i);
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index be3bc4a..d0f42cc 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -265,6 +265,8 @@
////////////////////////////////////////////////////////////////////////////////
+static const bool kUseHexDump = false;
+
static void hexdump(const void *_data, size_t size) {
const uint8_t *data = (const uint8_t *)_data;
size_t offset = 0;
@@ -352,6 +354,8 @@
MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source)
: mMoofOffset(0),
+ mMoofFound(false),
+ mMdatFound(false),
mDataSource(source),
mInitCheck(NO_INIT),
mHasVideo(false),
@@ -488,7 +492,9 @@
off64_t offset = 0;
status_t err;
- while (true) {
+ bool sawMoovOrSidx = false;
+
+ while (!(sawMoovOrSidx && (mMdatFound || mMoofFound))) {
off64_t orig_offset = offset;
err = parseChunk(&offset, 0);
@@ -500,23 +506,9 @@
ALOGE("did not advance: 0x%lld->0x%lld", orig_offset, offset);
err = ERROR_MALFORMED;
break;
- } else if (err == OK) {
- continue;
+ } else if (err == UNKNOWN_ERROR) {
+ sawMoovOrSidx = true;
}
-
- uint32_t hdr[2];
- if (mDataSource->readAt(offset, hdr, 8) < 8) {
- break;
- }
- uint32_t chunk_type = ntohl(hdr[1]);
- if (chunk_type == FOURCC('m', 'o', 'o', 'f')) {
- // store the offset of the first segment
- mMoofOffset = offset;
- } else if (chunk_type != FOURCC('m', 'd', 'a', 't')) {
- // keep parsing until we get to the data
- continue;
- }
- break;
}
if (mInitCheck == OK) {
@@ -607,7 +599,6 @@
if (size < 0) {
return ERROR_IO;
}
- int32_t classSize = size;
data_offset += numOfBytes;
while(size >= 11 ) {
@@ -668,7 +659,6 @@
if (size < 0) {
return ERROR_IO;
}
- classSize = size;
data_offset += numOfBytes;
while (size > 0) {
@@ -766,7 +756,7 @@
return ERROR_IO;
}
uint64_t chunk_size = ntohl(hdr[0]);
- uint32_t chunk_type = ntohl(hdr[1]);
+ int32_t chunk_type = ntohl(hdr[1]);
off64_t data_offset = *offset + 8;
if (chunk_size == 1) {
@@ -806,23 +796,23 @@
MakeFourCCString(chunk_type, chunk);
ALOGV("chunk: %s @ %lld, %d", chunk, *offset, depth);
-#if 0
- static const char kWhitespace[] = " ";
- const char *indent = &kWhitespace[sizeof(kWhitespace) - 1 - 2 * depth];
- printf("%sfound chunk '%s' of size %" PRIu64 "\n", indent, chunk, chunk_size);
+ if (kUseHexDump) {
+ static const char kWhitespace[] = " ";
+ const char *indent = &kWhitespace[sizeof(kWhitespace) - 1 - 2 * depth];
+ printf("%sfound chunk '%s' of size %" PRIu64 "\n", indent, chunk, chunk_size);
- char buffer[256];
- size_t n = chunk_size;
- if (n > sizeof(buffer)) {
- n = sizeof(buffer);
- }
- if (mDataSource->readAt(*offset, buffer, n)
- < (ssize_t)n) {
- return ERROR_IO;
- }
+ char buffer[256];
+ size_t n = chunk_size;
+ if (n > sizeof(buffer)) {
+ n = sizeof(buffer);
+ }
+ if (mDataSource->readAt(*offset, buffer, n)
+ < (ssize_t)n) {
+ return ERROR_IO;
+ }
- hexdump(buffer, n);
-#endif
+ hexdump(buffer, n);
+ }
PathAdder autoAdder(&mPath, chunk_type);
@@ -864,6 +854,12 @@
case FOURCC('s', 'c', 'h', 'i'):
case FOURCC('e', 'd', 't', 's'):
{
+ if (chunk_type == FOURCC('m', 'o', 'o', 'f') && !mMoofFound) {
+ // store the offset of the first segment
+ mMoofFound = true;
+ mMoofOffset = *offset;
+ }
+
if (chunk_type == FOURCC('s', 't', 'b', 'l')) {
ALOGV("sampleTable chunk is %" PRIu64 " bytes long.", chunk_size);
@@ -1301,7 +1297,7 @@
return ERROR_IO;
}
- uint16_t data_ref_index = U16_AT(&buffer[6]);
+ uint16_t data_ref_index __unused = U16_AT(&buffer[6]);
uint32_t num_channels = U16_AT(&buffer[16]);
uint16_t sample_size = U16_AT(&buffer[18]);
@@ -1354,7 +1350,7 @@
return ERROR_IO;
}
- uint16_t data_ref_index = U16_AT(&buffer[6]);
+ uint16_t data_ref_index __unused = U16_AT(&buffer[6]);
uint16_t width = U16_AT(&buffer[6 + 18]);
uint16_t height = U16_AT(&buffer[6 + 20]);
@@ -1536,13 +1532,13 @@
break;
}
- // @xyz
- case FOURCC('\xA9', 'x', 'y', 'z'):
+ // ©xyz
+ case FOURCC(0xA9, 'x', 'y', 'z'):
{
*offset += chunk_size;
- // Best case the total data length inside "@xyz" box
- // would be 8, for instance "@xyz" + "\x00\x04\x15\xc7" + "0+0/",
+ // Best case the total data length inside "©xyz" box
+ // would be 8, for instance "©xyz" + "\x00\x04\x15\xc7" + "0+0/",
// where "\x00\x04" is the text string length with value = 4,
// "\0x15\xc7" is the language code = en, and "0+0" is a
// location (string) value with longitude = 0 and latitude = 0.
@@ -1830,6 +1826,9 @@
case FOURCC('m', 'd', 'a', 't'):
{
ALOGV("mdat chunk, drm: %d", mIsDrm);
+
+ mMdatFound = true;
+
if (!mIsDrm) {
*offset += chunk_size;
break;
@@ -1870,7 +1869,6 @@
if (chunk_data_size < 24) {
return ERROR_IO;
}
- uint32_t duration;
Trex trex;
if (!mDataSource->getUInt32(data_offset + 4, &trex.track_ID) ||
!mDataSource->getUInt32(data_offset + 8, &trex.default_sample_description_index) ||
@@ -2142,7 +2140,7 @@
return ERROR_IO;
}
- uint64_t ctime, mtime, duration;
+ uint64_t ctime __unused, mtime __unused, duration __unused;
int32_t id;
if (version == 1) {
@@ -2164,12 +2162,13 @@
size_t matrixOffset = dynSize + 16;
int32_t a00 = U32_AT(&buffer[matrixOffset]);
int32_t a01 = U32_AT(&buffer[matrixOffset + 4]);
- int32_t dx = U32_AT(&buffer[matrixOffset + 8]);
int32_t a10 = U32_AT(&buffer[matrixOffset + 12]);
int32_t a11 = U32_AT(&buffer[matrixOffset + 16]);
- int32_t dy = U32_AT(&buffer[matrixOffset + 20]);
#if 0
+ int32_t dx = U32_AT(&buffer[matrixOffset + 8]);
+ int32_t dy = U32_AT(&buffer[matrixOffset + 20]);
+
ALOGI("x' = %.2f * x + %.2f * y + %.2f",
a00 / 65536.0f, a01 / 65536.0f, dx / 65536.0f);
ALOGI("y' = %.2f * x + %.2f * y + %.2f",
@@ -2230,7 +2229,7 @@
char chunk[5];
MakeFourCCString(mPath[4], chunk);
ALOGV("meta: %s @ %lld", chunk, offset);
- switch (mPath[4]) {
+ switch ((int32_t)mPath[4]) {
case FOURCC(0xa9, 'a', 'l', 'b'):
{
metadataKey = kKeyAlbum;
@@ -2721,10 +2720,10 @@
return ERROR_MALFORMED;
}
-#if 0
- printf("ESD of size %d\n", csd_size);
- hexdump(csd, csd_size);
-#endif
+ if (kUseHexDump) {
+ printf("ESD of size %d\n", csd_size);
+ hexdump(csd, csd_size);
+ }
if (csd_size == 0) {
// There's no further information, i.e. no codec specific data
@@ -2775,7 +2774,7 @@
if (objectType == AOT_SBR || objectType == AOT_PS) {//SBR specific config per 14496-3 table 1.13
uint32_t extFreqIndex = br.getBits(4);
- int32_t extSampleRate;
+ int32_t extSampleRate __unused;
if (extFreqIndex == 15) {
if (csd_size < 8) {
return ERROR_MALFORMED;
@@ -2825,12 +2824,12 @@
if (objectType == AOT_AAC_LC || objectType == AOT_ER_AAC_LC ||
objectType == AOT_ER_AAC_LD || objectType == AOT_ER_AAC_SCAL ||
objectType == AOT_ER_BSAC) {
- const int32_t frameLengthFlag = br.getBits(1);
+ const int32_t frameLengthFlag __unused = br.getBits(1);
const int32_t dependsOnCoreCoder = br.getBits(1);
if (dependsOnCoreCoder ) {
- const int32_t coreCoderDelay = br.getBits(14);
+ const int32_t coreCoderDelay __unused = br.getBits(14);
}
int32_t extensionFlag = -1;
@@ -2859,54 +2858,54 @@
if (numChannels == 0) {
int32_t channelsEffectiveNum = 0;
int32_t channelsNum = 0;
- const int32_t ElementInstanceTag = br.getBits(4);
- const int32_t Profile = br.getBits(2);
- const int32_t SamplingFrequencyIndex = br.getBits(4);
+ const int32_t ElementInstanceTag __unused = br.getBits(4);
+ const int32_t Profile __unused = br.getBits(2);
+ const int32_t SamplingFrequencyIndex __unused = br.getBits(4);
const int32_t NumFrontChannelElements = br.getBits(4);
const int32_t NumSideChannelElements = br.getBits(4);
const int32_t NumBackChannelElements = br.getBits(4);
const int32_t NumLfeChannelElements = br.getBits(2);
- const int32_t NumAssocDataElements = br.getBits(3);
- const int32_t NumValidCcElements = br.getBits(4);
+ const int32_t NumAssocDataElements __unused = br.getBits(3);
+ const int32_t NumValidCcElements __unused = br.getBits(4);
const int32_t MonoMixdownPresent = br.getBits(1);
if (MonoMixdownPresent != 0) {
- const int32_t MonoMixdownElementNumber = br.getBits(4);
+ const int32_t MonoMixdownElementNumber __unused = br.getBits(4);
}
const int32_t StereoMixdownPresent = br.getBits(1);
if (StereoMixdownPresent != 0) {
- const int32_t StereoMixdownElementNumber = br.getBits(4);
+ const int32_t StereoMixdownElementNumber __unused = br.getBits(4);
}
const int32_t MatrixMixdownIndexPresent = br.getBits(1);
if (MatrixMixdownIndexPresent != 0) {
- const int32_t MatrixMixdownIndex = br.getBits(2);
- const int32_t PseudoSurroundEnable = br.getBits(1);
+ const int32_t MatrixMixdownIndex __unused = br.getBits(2);
+ const int32_t PseudoSurroundEnable __unused = br.getBits(1);
}
int i;
for (i=0; i < NumFrontChannelElements; i++) {
const int32_t FrontElementIsCpe = br.getBits(1);
- const int32_t FrontElementTagSelect = br.getBits(4);
+ const int32_t FrontElementTagSelect __unused = br.getBits(4);
channelsNum += FrontElementIsCpe ? 2 : 1;
}
for (i=0; i < NumSideChannelElements; i++) {
const int32_t SideElementIsCpe = br.getBits(1);
- const int32_t SideElementTagSelect = br.getBits(4);
+ const int32_t SideElementTagSelect __unused = br.getBits(4);
channelsNum += SideElementIsCpe ? 2 : 1;
}
for (i=0; i < NumBackChannelElements; i++) {
const int32_t BackElementIsCpe = br.getBits(1);
- const int32_t BackElementTagSelect = br.getBits(4);
+ const int32_t BackElementTagSelect __unused = br.getBits(4);
channelsNum += BackElementIsCpe ? 2 : 1;
}
channelsEffectiveNum = channelsNum;
for (i=0; i < NumLfeChannelElements; i++) {
- const int32_t LfeElementTagSelect = br.getBits(4);
+ const int32_t LfeElementTagSelect __unused = br.getBits(4);
channelsNum += 1;
}
ALOGV("mpeg4 audio channelsNum = %d", channelsNum);
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 9f20b1d..6f6e362 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -29,6 +29,7 @@
#include <utils/Log.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
@@ -62,6 +63,14 @@
static const uint8_t kNalUnitTypePicParamSet = 0x08;
static const int64_t kInitialDelayTimeUs = 700000LL;
+static const char kMetaKey_Model[] = "com.android.model";
+static const char kMetaKey_Version[] = "com.android.version";
+static const char kMetaKey_Build[] = "com.android.build";
+static const char kMetaKey_CaptureFps[] = "com.android.capture.fps";
+
+/* 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);
@@ -345,31 +354,6 @@
Track &operator=(const Track &);
};
-MPEG4Writer::MPEG4Writer(const char *filename)
- : mFd(-1),
- mInitCheck(NO_INIT),
- mIsRealTimeRecording(true),
- mUse4ByteNalLength(true),
- mUse32BitOffset(true),
- mIsFileSizeLimitExplicitlyRequested(false),
- mPaused(false),
- mStarted(false),
- mWriterThreadStarted(false),
- mOffset(0),
- mMdatOffset(0),
- mEstimatedMoovBoxSize(0),
- mInterleaveDurationUs(1000000),
- mLatitudex10000(0),
- mLongitudex10000(0),
- mAreGeoTagsAvailable(false),
- mStartTimeOffsetMs(-1) {
-
- mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
- if (mFd >= 0) {
- mInitCheck = OK;
- }
-}
-
MPEG4Writer::MPEG4Writer(int fd)
: mFd(dup(fd)),
mInitCheck(mFd < 0? NO_INIT: OK),
@@ -383,11 +367,14 @@
mOffset(0),
mMdatOffset(0),
mEstimatedMoovBoxSize(0),
+ mMoovExtraSize(0),
mInterleaveDurationUs(1000000),
mLatitudex10000(0),
mLongitudex10000(0),
mAreGeoTagsAvailable(false),
+ mMetaKeys(new AMessage()),
mStartTimeOffsetMs(-1) {
+ addDeviceMeta();
}
MPEG4Writer::~MPEG4Writer() {
@@ -507,6 +494,34 @@
return OK;
}
+void MPEG4Writer::addDeviceMeta() {
+ // add device info and estimate space in 'moov'
+ char val[PROPERTY_VALUE_MAX];
+ size_t n;
+ // meta size is estimated by adding up the following:
+ // - meta header structures, which occur only once (total 66 bytes)
+ // - size for each key, which consists of a fixed header (32 bytes),
+ // plus key length and data length.
+ mMoovExtraSize += 66;
+ if (property_get("ro.build.version.release", val, NULL)
+ && (n = strlen(val)) > 0) {
+ mMetaKeys->setString(kMetaKey_Version, val, n + 1);
+ mMoovExtraSize += sizeof(kMetaKey_Version) + n + 32;
+ }
+#ifdef SHOW_MODEL_BUILD
+ if (property_get("ro.product.model", val, NULL)
+ && (n = strlen(val)) > 0) {
+ mMetaKeys->setString(kMetaKey_Model, val, n + 1);
+ mMoovExtraSize += sizeof(kMetaKey_Model) + n + 32;
+ }
+ if (property_get("ro.build.display.id", val, NULL)
+ && (n = strlen(val)) > 0) {
+ mMetaKeys->setString(kMetaKey_Build, val, n + 1);
+ mMoovExtraSize += sizeof(kMetaKey_Build) + n + 32;
+ }
+#endif
+}
+
int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) {
// This implementation is highly experimental/heurisitic.
//
@@ -560,6 +575,9 @@
size = MAX_MOOV_BOX_SIZE;
}
+ // Account for the extra stuff (Geo, meta keys, etc.)
+ size += mMoovExtraSize;
+
ALOGI("limits: %" PRId64 "/%" PRId64 " bytes/us, bit rate: %d bps and the"
" estimated moov size %" PRId64 " bytes",
mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
@@ -971,6 +989,7 @@
if (mAreGeoTagsAvailable) {
writeUdtaBox();
}
+ writeMetaBox();
int32_t id = 1;
for (List<Track *>::iterator it = mTracks.begin();
it != mTracks.end(); ++it, ++id) {
@@ -1140,6 +1159,14 @@
return bytes;
}
+void MPEG4Writer::beginBox(uint32_t id) {
+ mBoxes.push_back(mWriteMoovBoxToMemory?
+ mMoovBoxBufferOffset: mOffset);
+
+ writeInt32(0);
+ writeInt32(id);
+}
+
void MPEG4Writer::beginBox(const char *fourcc) {
CHECK_EQ(strlen(fourcc), 4);
@@ -1264,6 +1291,18 @@
mLatitudex10000 = latitudex10000;
mLongitudex10000 = longitudex10000;
mAreGeoTagsAvailable = true;
+ mMoovExtraSize += 30;
+ return OK;
+}
+
+status_t MPEG4Writer::setCaptureRate(float captureFps) {
+ if (captureFps <= 0.0f) {
+ return BAD_VALUE;
+ }
+
+ mMetaKeys->setFloat(kMetaKey_CaptureFps, captureFps);
+ mMoovExtraSize += sizeof(kMetaKey_CaptureFps) + 4 + 32;
+
return OK;
}
@@ -3095,6 +3134,103 @@
endBox();
}
+void MPEG4Writer::writeHdlr() {
+ beginBox("hdlr");
+ writeInt32(0); // Version, Flags
+ writeInt32(0); // Predefined
+ writeFourcc("mdta");
+ writeInt32(0); // Reserved[0]
+ writeInt32(0); // Reserved[1]
+ writeInt32(0); // Reserved[2]
+ writeInt8(0); // Name (empty)
+ endBox();
+}
+
+void MPEG4Writer::writeKeys() {
+ size_t count = mMetaKeys->countEntries();
+
+ beginBox("keys");
+ writeInt32(0); // Version, Flags
+ writeInt32(count); // Entry_count
+ for (size_t i = 0; i < count; i++) {
+ AMessage::Type type;
+ const char *key = mMetaKeys->getEntryNameAt(i, &type);
+ size_t n = strlen(key);
+ writeInt32(n + 8);
+ writeFourcc("mdta");
+ write(key, n); // write without the \0
+ }
+ endBox();
+}
+
+void MPEG4Writer::writeIlst() {
+ size_t count = mMetaKeys->countEntries();
+
+ beginBox("ilst");
+ for (size_t i = 0; i < count; i++) {
+ beginBox(i + 1); // key id (1-based)
+ beginBox("data");
+ AMessage::Type type;
+ const char *key = mMetaKeys->getEntryNameAt(i, &type);
+ switch (type) {
+ case AMessage::kTypeString:
+ {
+ AString val;
+ CHECK(mMetaKeys->findString(key, &val));
+ writeInt32(1); // type = UTF8
+ writeInt32(0); // default country/language
+ write(val.c_str(), strlen(val.c_str())); // write without \0
+ break;
+ }
+
+ case AMessage::kTypeFloat:
+ {
+ float val;
+ CHECK(mMetaKeys->findFloat(key, &val));
+ writeInt32(23); // type = float32
+ writeInt32(0); // default country/language
+ writeInt32(*reinterpret_cast<int32_t *>(&val));
+ break;
+ }
+
+ case AMessage::kTypeInt32:
+ {
+ int32_t val;
+ CHECK(mMetaKeys->findInt32(key, &val));
+ writeInt32(67); // type = signed int32
+ writeInt32(0); // default country/language
+ writeInt32(val);
+ break;
+ }
+
+ default:
+ {
+ ALOGW("Unsupported key type, writing 0 instead");
+ writeInt32(77); // type = unsigned int32
+ writeInt32(0); // default country/language
+ writeInt32(0);
+ break;
+ }
+ }
+ endBox(); // data
+ endBox(); // key id
+ }
+ endBox(); // ilst
+}
+
+void MPEG4Writer::writeMetaBox() {
+ size_t count = mMetaKeys->countEntries();
+ if (count == 0) {
+ return;
+ }
+
+ beginBox("meta");
+ writeHdlr();
+ writeKeys();
+ writeIlst();
+ endBox();
+}
+
/*
* Geodata is stored according to ISO-6709 standard.
*/
diff --git a/media/libstagefright/MediaClock.cpp b/media/libstagefright/MediaClock.cpp
new file mode 100644
index 0000000..38db5e4
--- /dev/null
+++ b/media/libstagefright/MediaClock.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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 "MediaClock"
+#include <utils/Log.h>
+
+#include <media/stagefright/MediaClock.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+
+namespace android {
+
+MediaClock::MediaClock()
+ : mAnchorTimeMediaUs(-1),
+ mAnchorTimeRealUs(-1),
+ mMaxTimeMediaUs(INT64_MAX),
+ mStartingTimeMediaUs(-1),
+ mPlaybackRate(1.0) {
+}
+
+MediaClock::~MediaClock() {
+}
+
+void MediaClock::setStartingTimeMedia(int64_t startingTimeMediaUs) {
+ Mutex::Autolock autoLock(mLock);
+ mStartingTimeMediaUs = startingTimeMediaUs;
+}
+
+void MediaClock::clearAnchor() {
+ Mutex::Autolock autoLock(mLock);
+ mAnchorTimeMediaUs = -1;
+ mAnchorTimeRealUs = -1;
+}
+
+void MediaClock::updateAnchor(
+ int64_t anchorTimeMediaUs,
+ int64_t anchorTimeRealUs,
+ int64_t maxTimeMediaUs) {
+ if (anchorTimeMediaUs < 0 || anchorTimeRealUs < 0) {
+ ALOGW("reject anchor time since it is negative.");
+ return;
+ }
+
+ Mutex::Autolock autoLock(mLock);
+ int64_t nowUs = ALooper::GetNowUs();
+ int64_t nowMediaUs =
+ anchorTimeMediaUs + (nowUs - anchorTimeRealUs) * (double)mPlaybackRate;
+ if (nowMediaUs < 0) {
+ ALOGW("reject anchor time since it leads to negative media time.");
+ return;
+ }
+ mAnchorTimeRealUs = nowUs;
+ mAnchorTimeMediaUs = nowMediaUs;
+ mMaxTimeMediaUs = maxTimeMediaUs;
+}
+
+void MediaClock::updateMaxTimeMedia(int64_t maxTimeMediaUs) {
+ Mutex::Autolock autoLock(mLock);
+ mMaxTimeMediaUs = maxTimeMediaUs;
+}
+
+void MediaClock::setPlaybackRate(float rate) {
+ CHECK_GE(rate, 0.0);
+ Mutex::Autolock autoLock(mLock);
+ if (mAnchorTimeRealUs == -1) {
+ mPlaybackRate = rate;
+ return;
+ }
+
+ int64_t nowUs = ALooper::GetNowUs();
+ mAnchorTimeMediaUs += (nowUs - mAnchorTimeRealUs) * (double)mPlaybackRate;
+ if (mAnchorTimeMediaUs < 0) {
+ ALOGW("setRate: anchor time should not be negative, set to 0.");
+ mAnchorTimeMediaUs = 0;
+ }
+ mAnchorTimeRealUs = nowUs;
+ mPlaybackRate = rate;
+}
+
+status_t MediaClock::getMediaTime(
+ int64_t realUs, int64_t *outMediaUs, bool allowPastMaxTime) {
+ Mutex::Autolock autoLock(mLock);
+ return getMediaTime_l(realUs, outMediaUs, allowPastMaxTime);
+}
+
+status_t MediaClock::getMediaTime_l(
+ int64_t realUs, int64_t *outMediaUs, bool allowPastMaxTime) {
+ if (mAnchorTimeRealUs == -1) {
+ return NO_INIT;
+ }
+
+ int64_t mediaUs = mAnchorTimeMediaUs
+ + (realUs - mAnchorTimeRealUs) * (double)mPlaybackRate;
+ if (mediaUs > mMaxTimeMediaUs && !allowPastMaxTime) {
+ mediaUs = mMaxTimeMediaUs;
+ }
+ if (mediaUs < mStartingTimeMediaUs) {
+ mediaUs = mStartingTimeMediaUs;
+ }
+ if (mediaUs < 0) {
+ mediaUs = 0;
+ }
+ *outMediaUs = mediaUs;
+ return OK;
+}
+
+status_t MediaClock::getRealTimeFor(int64_t targetMediaUs, int64_t *outRealUs) {
+ Mutex::Autolock autoLock(mLock);
+ if (mPlaybackRate == 0.0) {
+ return NO_INIT;
+ }
+
+ int64_t nowUs = ALooper::GetNowUs();
+ int64_t nowMediaUs;
+ status_t status =
+ getMediaTime_l(nowUs, &nowMediaUs, true /* allowPastMaxTime */);
+ if (status != OK) {
+ return status;
+ }
+ *outRealUs = (targetMediaUs - nowMediaUs) / (double)mPlaybackRate + nowUs;
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index a9c3a04..0597f1d 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -36,6 +36,7 @@
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaFilter.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/NativeWindowWrapper.h>
#include <private/android_filesystem_config.h>
@@ -173,7 +174,7 @@
}
// static
-void MediaCodec::PostReplyWithError(int32_t replyID, int32_t err) {
+void MediaCodec::PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err) {
sp<AMessage> response = new AMessage;
response->setInt32("err", err);
response->postReply(replyID);
@@ -189,7 +190,16 @@
// quickly, violating the OpenMAX specs, until that is remedied
// we need to invest in an extra looper to free the main event
// queue.
- mCodec = new ACodec;
+
+ 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 {
+ return NAME_NOT_FOUND;
+ }
+
bool needDedicatedLooper = false;
if (nameIsType && !strncasecmp(name.c_str(), "video/", 6)) {
needDedicatedLooper = true;
@@ -227,9 +237,9 @@
mLooper->registerHandler(this);
- mCodec->setNotificationMessage(new AMessage(kWhatCodecNotify, id()));
+ mCodec->setNotificationMessage(new AMessage(kWhatCodecNotify, this));
- sp<AMessage> msg = new AMessage(kWhatInit, id());
+ sp<AMessage> msg = new AMessage(kWhatInit, this);
msg->setString("name", name);
msg->setInt32("nameIsType", nameIsType);
@@ -242,7 +252,7 @@
}
status_t MediaCodec::setCallback(const sp<AMessage> &callback) {
- sp<AMessage> msg = new AMessage(kWhatSetCallback, id());
+ sp<AMessage> msg = new AMessage(kWhatSetCallback, this);
msg->setMessage("callback", callback);
sp<AMessage> response;
@@ -254,7 +264,7 @@
const sp<Surface> &nativeWindow,
const sp<ICrypto> &crypto,
uint32_t flags) {
- sp<AMessage> msg = new AMessage(kWhatConfigure, id());
+ sp<AMessage> msg = new AMessage(kWhatConfigure, this);
msg->setMessage("format", format);
msg->setInt32("flags", flags);
@@ -288,7 +298,7 @@
status_t MediaCodec::createInputSurface(
sp<IGraphicBufferProducer>* bufferProducer) {
- sp<AMessage> msg = new AMessage(kWhatCreateInputSurface, id());
+ sp<AMessage> msg = new AMessage(kWhatCreateInputSurface, this);
sp<AMessage> response;
status_t err = PostAndAwaitResponse(msg, &response);
@@ -307,21 +317,21 @@
}
status_t MediaCodec::start() {
- sp<AMessage> msg = new AMessage(kWhatStart, id());
+ sp<AMessage> msg = new AMessage(kWhatStart, this);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
status_t MediaCodec::stop() {
- sp<AMessage> msg = new AMessage(kWhatStop, id());
+ sp<AMessage> msg = new AMessage(kWhatStop, this);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
status_t MediaCodec::release() {
- sp<AMessage> msg = new AMessage(kWhatRelease, id());
+ sp<AMessage> msg = new AMessage(kWhatRelease, this);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
@@ -373,7 +383,7 @@
errorDetailMsg->clear();
}
- sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, id());
+ sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this);
msg->setSize("index", index);
msg->setSize("offset", offset);
msg->setSize("size", size);
@@ -400,7 +410,7 @@
errorDetailMsg->clear();
}
- sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, id());
+ sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this);
msg->setSize("index", index);
msg->setSize("offset", offset);
msg->setPointer("subSamples", (void *)subSamples);
@@ -419,7 +429,7 @@
}
status_t MediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
- sp<AMessage> msg = new AMessage(kWhatDequeueInputBuffer, id());
+ sp<AMessage> msg = new AMessage(kWhatDequeueInputBuffer, this);
msg->setInt64("timeoutUs", timeoutUs);
sp<AMessage> response;
@@ -440,7 +450,7 @@
int64_t *presentationTimeUs,
uint32_t *flags,
int64_t timeoutUs) {
- sp<AMessage> msg = new AMessage(kWhatDequeueOutputBuffer, id());
+ sp<AMessage> msg = new AMessage(kWhatDequeueOutputBuffer, this);
msg->setInt64("timeoutUs", timeoutUs);
sp<AMessage> response;
@@ -459,7 +469,7 @@
}
status_t MediaCodec::renderOutputBufferAndRelease(size_t index) {
- sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, id());
+ sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, this);
msg->setSize("index", index);
msg->setInt32("render", true);
@@ -468,7 +478,7 @@
}
status_t MediaCodec::renderOutputBufferAndRelease(size_t index, int64_t timestampNs) {
- sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, id());
+ sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, this);
msg->setSize("index", index);
msg->setInt32("render", true);
msg->setInt64("timestampNs", timestampNs);
@@ -478,7 +488,7 @@
}
status_t MediaCodec::releaseOutputBuffer(size_t index) {
- sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, id());
+ sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, this);
msg->setSize("index", index);
sp<AMessage> response;
@@ -486,14 +496,14 @@
}
status_t MediaCodec::signalEndOfInputStream() {
- sp<AMessage> msg = new AMessage(kWhatSignalEndOfInputStream, id());
+ sp<AMessage> msg = new AMessage(kWhatSignalEndOfInputStream, this);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
status_t MediaCodec::getOutputFormat(sp<AMessage> *format) const {
- sp<AMessage> msg = new AMessage(kWhatGetOutputFormat, id());
+ sp<AMessage> msg = new AMessage(kWhatGetOutputFormat, this);
sp<AMessage> response;
status_t err;
@@ -507,7 +517,7 @@
}
status_t MediaCodec::getInputFormat(sp<AMessage> *format) const {
- sp<AMessage> msg = new AMessage(kWhatGetInputFormat, id());
+ sp<AMessage> msg = new AMessage(kWhatGetInputFormat, this);
sp<AMessage> response;
status_t err;
@@ -521,7 +531,7 @@
}
status_t MediaCodec::getName(AString *name) const {
- sp<AMessage> msg = new AMessage(kWhatGetName, id());
+ sp<AMessage> msg = new AMessage(kWhatGetName, this);
sp<AMessage> response;
status_t err;
@@ -535,7 +545,7 @@
}
status_t MediaCodec::getInputBuffers(Vector<sp<ABuffer> > *buffers) const {
- sp<AMessage> msg = new AMessage(kWhatGetBuffers, id());
+ sp<AMessage> msg = new AMessage(kWhatGetBuffers, this);
msg->setInt32("portIndex", kPortIndexInput);
msg->setPointer("buffers", buffers);
@@ -544,7 +554,7 @@
}
status_t MediaCodec::getOutputBuffers(Vector<sp<ABuffer> > *buffers) const {
- sp<AMessage> msg = new AMessage(kWhatGetBuffers, id());
+ sp<AMessage> msg = new AMessage(kWhatGetBuffers, this);
msg->setInt32("portIndex", kPortIndexOutput);
msg->setPointer("buffers", buffers);
@@ -602,20 +612,20 @@
}
status_t MediaCodec::flush() {
- sp<AMessage> msg = new AMessage(kWhatFlush, id());
+ sp<AMessage> msg = new AMessage(kWhatFlush, this);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
status_t MediaCodec::requestIDRFrame() {
- (new AMessage(kWhatRequestIDRFrame, id()))->post();
+ (new AMessage(kWhatRequestIDRFrame, this))->post();
return OK;
}
void MediaCodec::requestActivityNotification(const sp<AMessage> ¬ify) {
- sp<AMessage> msg = new AMessage(kWhatRequestActivityNotification, id());
+ sp<AMessage> msg = new AMessage(kWhatRequestActivityNotification, this);
msg->setMessage("notify", notify);
msg->post();
}
@@ -640,7 +650,7 @@
}
}
-bool MediaCodec::handleDequeueInputBuffer(uint32_t replyID, bool newRequest) {
+bool MediaCodec::handleDequeueInputBuffer(const sp<AReplyToken> &replyID, bool newRequest) {
if (!isExecuting() || (mFlags & kFlagIsAsync)
|| (newRequest && (mFlags & kFlagDequeueInputPending))) {
PostReplyWithError(replyID, INVALID_OPERATION);
@@ -664,7 +674,7 @@
return true;
}
-bool MediaCodec::handleDequeueOutputBuffer(uint32_t replyID, bool newRequest) {
+bool MediaCodec::handleDequeueOutputBuffer(const sp<AReplyToken> &replyID, bool newRequest) {
sp<AMessage> response = new AMessage;
if (!isExecuting() || (mFlags & kFlagIsAsync)
@@ -1188,7 +1198,7 @@
case kWhatInit:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (mState != UNINITIALIZED) {
@@ -1224,7 +1234,7 @@
case kWhatSetCallback:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (mState == UNINITIALIZED
@@ -1256,7 +1266,7 @@
case kWhatConfigure:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (mState != INITIALIZED) {
@@ -1313,7 +1323,7 @@
case kWhatCreateInputSurface:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
// Must be configured, but can't have been started yet.
@@ -1329,7 +1339,7 @@
case kWhatStart:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (mState == FLUSHED) {
@@ -1355,7 +1365,7 @@
State targetState =
(msg->what() == kWhatStop) ? INITIALIZED : UNINITIALIZED;
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (!((mFlags & kFlagIsComponentAllocated) && targetState == UNINITIALIZED) // See 1
@@ -1403,7 +1413,7 @@
case kWhatDequeueInputBuffer:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (mFlags & kFlagIsAsync) {
@@ -1435,7 +1445,7 @@
if (timeoutUs > 0ll) {
sp<AMessage> timeoutMsg =
- new AMessage(kWhatDequeueInputTimedOut, id());
+ new AMessage(kWhatDequeueInputTimedOut, this);
timeoutMsg->setInt32(
"generation", ++mDequeueInputTimeoutGeneration);
timeoutMsg->post(timeoutUs);
@@ -1464,7 +1474,7 @@
case kWhatQueueInputBuffer:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (!isExecuting()) {
@@ -1483,7 +1493,7 @@
case kWhatDequeueOutputBuffer:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (mFlags & kFlagIsAsync) {
@@ -1509,7 +1519,7 @@
if (timeoutUs > 0ll) {
sp<AMessage> timeoutMsg =
- new AMessage(kWhatDequeueOutputTimedOut, id());
+ new AMessage(kWhatDequeueOutputTimedOut, this);
timeoutMsg->setInt32(
"generation", ++mDequeueOutputTimeoutGeneration);
timeoutMsg->post(timeoutUs);
@@ -1538,7 +1548,7 @@
case kWhatReleaseOutputBuffer:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (!isExecuting()) {
@@ -1557,7 +1567,7 @@
case kWhatSignalEndOfInputStream:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (!isExecuting()) {
@@ -1575,7 +1585,7 @@
case kWhatGetBuffers:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (!isExecuting() || (mFlags & kFlagIsAsync)) {
@@ -1609,7 +1619,7 @@
case kWhatFlush:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (!isExecuting()) {
@@ -1635,7 +1645,7 @@
sp<AMessage> format =
(msg->what() == kWhatGetOutputFormat ? mOutputFormat : mInputFormat);
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if ((mState != CONFIGURED && mState != STARTING &&
@@ -1672,7 +1682,7 @@
case kWhatGetName:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (mComponentName.empty()) {
@@ -1688,7 +1698,7 @@
case kWhatSetParameters:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
sp<AMessage> params;
@@ -1711,7 +1721,7 @@
size_t i = 0;
for (;;) {
sp<ABuffer> csd;
- if (!format->findBuffer(StringPrintf("csd-%u", i).c_str(), &csd)) {
+ if (!format->findBuffer(AStringPrintf("csd-%u", i).c_str(), &csd)) {
break;
}
@@ -1742,7 +1752,7 @@
AString errorDetailMsg;
- sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, id());
+ sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this);
msg->setSize("index", bufferIndex);
msg->setSize("offset", 0);
msg->setSize("size", csd->size());
@@ -2197,7 +2207,7 @@
}
status_t MediaCodec::setParameters(const sp<AMessage> ¶ms) {
- sp<AMessage> msg = new AMessage(kWhatSetParameters, id());
+ sp<AMessage> msg = new AMessage(kWhatSetParameters, this);
msg->setMessage("params", params);
sp<AMessage> response;
@@ -2234,7 +2244,7 @@
memcpy(csd->data() + 4, nalStart, nalSize);
mOutputFormat->setBuffer(
- StringPrintf("csd-%u", csdIndex).c_str(), csd);
+ AStringPrintf("csd-%u", csdIndex).c_str(), csd);
++csdIndex;
}
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index c26e909..b6fa810 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -121,7 +121,7 @@
mLooper->registerHandler(this);
mNotify = notify;
- sp<AMessage> msg = new AMessage(kWhatStart, id());
+ sp<AMessage> msg = new AMessage(kWhatStart, this);
msg->setObject("meta", meta);
return postSynchronouslyAndReturnError(msg);
}
@@ -137,19 +137,19 @@
mSource->stop();
ALOGV("source (%s) stopped", mIsAudio ? "audio" : "video");
- (new AMessage(kWhatStop, id()))->post();
+ (new AMessage(kWhatStop, this))->post();
}
void MediaCodecSource::Puller::pause() {
- (new AMessage(kWhatPause, id()))->post();
+ (new AMessage(kWhatPause, this))->post();
}
void MediaCodecSource::Puller::resume() {
- (new AMessage(kWhatResume, id()))->post();
+ (new AMessage(kWhatResume, this))->post();
}
void MediaCodecSource::Puller::schedulePull() {
- sp<AMessage> msg = new AMessage(kWhatPull, id());
+ sp<AMessage> msg = new AMessage(kWhatPull, this);
msg->setInt32("generation", mPullGeneration);
msg->post();
}
@@ -182,7 +182,7 @@
sp<AMessage> response = new AMessage;
response->setInt32("err", err);
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
response->postReply(replyID);
break;
@@ -269,13 +269,13 @@
}
status_t MediaCodecSource::start(MetaData* params) {
- sp<AMessage> msg = new AMessage(kWhatStart, mReflector->id());
+ sp<AMessage> msg = new AMessage(kWhatStart, mReflector);
msg->setObject("meta", params);
return postSynchronouslyAndReturnError(msg);
}
status_t MediaCodecSource::stop() {
- sp<AMessage> msg = new AMessage(kWhatStop, mReflector->id());
+ sp<AMessage> msg = new AMessage(kWhatStop, mReflector);
status_t err = postSynchronouslyAndReturnError(msg);
// mPuller->stop() needs to be done outside MediaCodecSource's looper,
@@ -294,7 +294,7 @@
}
status_t MediaCodecSource::pause() {
- (new AMessage(kWhatPause, mReflector->id()))->post();
+ (new AMessage(kWhatPause, mReflector))->post();
return OK;
}
@@ -422,8 +422,7 @@
}
}
- mEncoderActivityNotify = new AMessage(
- kWhatEncoderActivity, mReflector->id());
+ mEncoderActivityNotify = new AMessage(kWhatEncoderActivity, mReflector);
mEncoder->setCallback(mEncoderActivityNotify);
err = mEncoder->start();
@@ -492,7 +491,7 @@
if (mStopping && mEncoderReachedEOS) {
ALOGI("encoder (%s) stopped", mIsVideo ? "video" : "audio");
// posting reply to everyone that's waiting
- List<uint32_t>::iterator it;
+ List<sp<AReplyToken>>::iterator it;
for (it = mStopReplyIDQueue.begin();
it != mStopReplyIDQueue.end(); it++) {
(new AMessage)->postReply(*it);
@@ -620,8 +619,7 @@
resume(startTimeUs);
} else {
CHECK(mPuller != NULL);
- sp<AMessage> notify = new AMessage(
- kWhatPullerNotify, mReflector->id());
+ sp<AMessage> notify = new AMessage(kWhatPullerNotify, mReflector);
err = mPuller->start(params, notify);
if (err != OK) {
return err;
@@ -768,7 +766,7 @@
}
case kWhatStart:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
sp<RefBase> obj;
@@ -784,7 +782,7 @@
{
ALOGI("encoder (%s) stopping", mIsVideo ? "video" : "audio");
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (mEncoderReachedEOS) {
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index c5a6939..c48a5ae 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -34,6 +34,7 @@
const char *MEDIA_MIMETYPE_AUDIO_MPEG = "audio/mpeg";
const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I = "audio/mpeg-L1";
const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II = "audio/mpeg-L2";
+const char *MEDIA_MIMETYPE_AUDIO_MIDI = "audio/midi";
const char *MEDIA_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
const char *MEDIA_MIMETYPE_AUDIO_QCELP = "audio/qcelp";
const char *MEDIA_MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 9ab6611..e21fe6e 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -29,6 +29,7 @@
#include "include/WVMExtractor.h"
#include "include/FLACExtractor.h"
#include "include/AACExtractor.h"
+#include "include/MidiExtractor.h"
#include "matroska/MatroskaExtractor.h"
@@ -116,6 +117,8 @@
ret = new AACExtractor(source, meta);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
ret = new MPEG2PSExtractor(source);
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MIDI)) {
+ ret = new MidiExtractor(source);
}
if (ret != NULL) {
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index c7c6f34..b13877d 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -38,21 +38,6 @@
namespace android {
-MediaMuxer::MediaMuxer(const char *path, OutputFormat format)
- : mFormat(format),
- mState(UNINITIALIZED) {
- if (format == OUTPUT_FORMAT_MPEG_4) {
- mWriter = new MPEG4Writer(path);
- } else if (format == OUTPUT_FORMAT_WEBM) {
- mWriter = new WebmWriter(path);
- }
-
- if (mWriter != NULL) {
- mFileMeta = new MetaData;
- mState = INITIALIZED;
- }
-}
-
MediaMuxer::MediaMuxer(int fd, OutputFormat format)
: mFormat(format),
mState(UNINITIALIZED) {
diff --git a/media/libstagefright/MidiExtractor.cpp b/media/libstagefright/MidiExtractor.cpp
new file mode 100644
index 0000000..66fab77
--- /dev/null
+++ b/media/libstagefright/MidiExtractor.cpp
@@ -0,0 +1,325 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MidiExtractor"
+#include <utils/Log.h>
+
+#include "include/MidiExtractor.h"
+
+#include <media/MidiIoWrapper.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/MediaSource.h>
+#include <libsonivox/eas_reverb.h>
+
+namespace android {
+
+// how many Sonivox output buffers to aggregate into one MediaBuffer
+static const int NUM_COMBINE_BUFFERS = 4;
+
+class MidiSource : public MediaSource {
+
+public:
+ MidiSource(
+ const sp<MidiEngine> &engine,
+ const sp<MetaData> &trackMetadata);
+
+ virtual status_t start(MetaData *params);
+ virtual status_t stop();
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+protected:
+ virtual ~MidiSource();
+
+private:
+ sp<MidiEngine> mEngine;
+ sp<MetaData> mTrackMetadata;
+ bool mInitCheck;
+ bool mStarted;
+
+ status_t init();
+
+ // no copy constructor or assignment
+ MidiSource(const MidiSource &);
+ MidiSource &operator=(const MidiSource &);
+
+};
+
+
+// Midisource
+
+MidiSource::MidiSource(
+ const sp<MidiEngine> &engine,
+ const sp<MetaData> &trackMetadata)
+ : mEngine(engine),
+ mTrackMetadata(trackMetadata),
+ mInitCheck(false),
+ mStarted(false)
+{
+ ALOGV("MidiSource ctor");
+ mInitCheck = init();
+}
+
+MidiSource::~MidiSource()
+{
+ ALOGV("MidiSource dtor");
+ if (mStarted) {
+ stop();
+ }
+}
+
+status_t MidiSource::start(MetaData * /* params */)
+{
+ ALOGV("MidiSource::start");
+
+ CHECK(!mStarted);
+ mStarted = true;
+ mEngine->allocateBuffers();
+ return OK;
+}
+
+status_t MidiSource::stop()
+{
+ ALOGV("MidiSource::stop");
+
+ CHECK(mStarted);
+ mStarted = false;
+ mEngine->releaseBuffers();
+
+ return OK;
+}
+
+sp<MetaData> MidiSource::getFormat()
+{
+ return mTrackMetadata;
+}
+
+status_t MidiSource::read(
+ MediaBuffer **outBuffer, const ReadOptions *options)
+{
+ ALOGV("MidiSource::read");
+ MediaBuffer *buffer;
+ // process an optional seek request
+ int64_t seekTimeUs;
+ ReadOptions::SeekMode mode;
+ if ((NULL != options) && options->getSeekTo(&seekTimeUs, &mode)) {
+ if (seekTimeUs <= 0LL) {
+ seekTimeUs = 0LL;
+ }
+ mEngine->seekTo(seekTimeUs);
+ }
+ buffer = mEngine->readBuffer();
+ *outBuffer = buffer;
+ ALOGV("MidiSource::read %p done", this);
+ return buffer != NULL ? (status_t) OK : (status_t) ERROR_END_OF_STREAM;
+}
+
+status_t MidiSource::init()
+{
+ ALOGV("MidiSource::init");
+ return OK;
+}
+
+// MidiEngine
+
+MidiEngine::MidiEngine(const sp<DataSource> &dataSource,
+ const sp<MetaData> &fileMetadata,
+ const sp<MetaData> &trackMetadata) :
+ mGroup(NULL),
+ mEasData(NULL),
+ mEasHandle(NULL),
+ mEasConfig(NULL),
+ mIsInitialized(false) {
+ mIoWrapper = new MidiIoWrapper(dataSource);
+ // spin up a new EAS engine
+ EAS_I32 temp;
+ EAS_RESULT result = EAS_Init(&mEasData);
+
+ if (result == EAS_SUCCESS) {
+ result = EAS_OpenFile(mEasData, mIoWrapper->getLocator(), &mEasHandle);
+ }
+ if (result == EAS_SUCCESS) {
+ result = EAS_Prepare(mEasData, mEasHandle);
+ }
+ if (result == EAS_SUCCESS) {
+ result = EAS_ParseMetaData(mEasData, mEasHandle, &temp);
+ }
+
+ if (result != EAS_SUCCESS) {
+ return;
+ }
+
+ if (fileMetadata != NULL) {
+ fileMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MIDI);
+ }
+
+ if (trackMetadata != NULL) {
+ trackMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+ trackMetadata->setInt64(kKeyDuration, 1000ll * temp); // milli->micro
+ mEasConfig = EAS_Config();
+ trackMetadata->setInt32(kKeySampleRate, mEasConfig->sampleRate);
+ trackMetadata->setInt32(kKeyChannelCount, mEasConfig->numChannels);
+ }
+ mIsInitialized = true;
+}
+
+MidiEngine::~MidiEngine() {
+ if (mEasHandle) {
+ EAS_CloseFile(mEasData, mEasHandle);
+ }
+ if (mEasData) {
+ EAS_Shutdown(mEasData);
+ }
+ delete mGroup;
+
+}
+
+status_t MidiEngine::initCheck() {
+ return mIsInitialized ? OK : UNKNOWN_ERROR;
+}
+
+status_t MidiEngine::allocateBuffers() {
+ // select reverb preset and enable
+ EAS_SetParameter(mEasData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_PRESET, EAS_PARAM_REVERB_CHAMBER);
+ EAS_SetParameter(mEasData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_BYPASS, EAS_FALSE);
+
+ mGroup = new MediaBufferGroup;
+ int bufsize = sizeof(EAS_PCM)
+ * mEasConfig->mixBufferSize * mEasConfig->numChannels * NUM_COMBINE_BUFFERS;
+ ALOGV("using %d byte buffer", bufsize);
+ mGroup->add_buffer(new MediaBuffer(bufsize));
+ return OK;
+}
+
+status_t MidiEngine::releaseBuffers() {
+ delete mGroup;
+ mGroup = NULL;
+ return OK;
+}
+
+status_t MidiEngine::seekTo(int64_t positionUs) {
+ ALOGV("seekTo %lld", positionUs);
+ EAS_RESULT result = EAS_Locate(mEasData, mEasHandle, positionUs / 1000, false);
+ return result == EAS_SUCCESS ? OK : UNKNOWN_ERROR;
+}
+
+MediaBuffer* MidiEngine::readBuffer() {
+ EAS_STATE state;
+ EAS_State(mEasData, mEasHandle, &state);
+ if ((state == EAS_STATE_STOPPED) || (state == EAS_STATE_ERROR)) {
+ return NULL;
+ }
+ MediaBuffer *buffer;
+ status_t err = mGroup->acquire_buffer(&buffer);
+ if (err != OK) {
+ ALOGE("readBuffer: no buffer");
+ return NULL;
+ }
+ EAS_I32 timeMs;
+ EAS_GetLocation(mEasData, mEasHandle, &timeMs);
+ int64_t timeUs = 1000ll * timeMs;
+ buffer->meta_data()->setInt64(kKeyTime, timeUs);
+
+ EAS_PCM* p = (EAS_PCM*) buffer->data();
+ int numBytesOutput = 0;
+ for (int i = 0; i < NUM_COMBINE_BUFFERS; i++) {
+ EAS_I32 numRendered;
+ EAS_RESULT result = EAS_Render(mEasData, p, mEasConfig->mixBufferSize, &numRendered);
+ if (result != EAS_SUCCESS) {
+ ALOGE("EAS_Render returned %ld", result);
+ break;
+ }
+ p += numRendered * mEasConfig->numChannels;
+ numBytesOutput += numRendered * mEasConfig->numChannels * sizeof(EAS_PCM);
+ }
+ buffer->set_range(0, numBytesOutput);
+ ALOGV("readBuffer: returning %zd in buffer %p", buffer->range_length(), buffer);
+ return buffer;
+}
+
+
+// MidiExtractor
+
+MidiExtractor::MidiExtractor(
+ const sp<DataSource> &dataSource)
+ : mDataSource(dataSource),
+ mInitCheck(false)
+{
+ ALOGV("MidiExtractor ctor");
+ mFileMetadata = new MetaData;
+ mTrackMetadata = new MetaData;
+ mEngine = new MidiEngine(mDataSource, mFileMetadata, mTrackMetadata);
+ mInitCheck = mEngine->initCheck();
+}
+
+MidiExtractor::~MidiExtractor()
+{
+ ALOGV("MidiExtractor dtor");
+}
+
+size_t MidiExtractor::countTracks()
+{
+ return mInitCheck == OK ? 1 : 0;
+}
+
+sp<MediaSource> MidiExtractor::getTrack(size_t index)
+{
+ if (mInitCheck != OK || index > 0) {
+ return NULL;
+ }
+ return new MidiSource(mEngine, mTrackMetadata);
+}
+
+sp<MetaData> MidiExtractor::getTrackMetaData(
+ size_t index, uint32_t /* flags */) {
+ ALOGV("MidiExtractor::getTrackMetaData");
+ if (mInitCheck != OK || index > 0) {
+ return NULL;
+ }
+ return mTrackMetadata;
+}
+
+sp<MetaData> MidiExtractor::getMetaData()
+{
+ ALOGV("MidiExtractor::getMetaData");
+ return mFileMetadata;
+}
+
+// Sniffer
+
+bool SniffMidi(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *)
+{
+ sp<MidiEngine> p = new MidiEngine(source, NULL, NULL);
+ if (p->initCheck() == OK) {
+ *mimeType = MEDIA_MIMETYPE_AUDIO_MIDI;
+ *confidence = 0.8;
+ ALOGV("SniffMidi: yes");
+ return true;
+ }
+ ALOGV("SniffMidi: no");
+ return false;
+
+}
+
+} // namespace android
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index 7d7d631..8d70e50 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -226,7 +226,7 @@
mLooper->start(false /* runOnCallingThread */, true /* canCallJava */);
Mutex::Autolock autoLock(mLock);
- (new AMessage(kWhatFetchMore, mReflector->id()))->post();
+ (new AMessage(kWhatFetchMore, mReflector))->post();
}
NuCachedSource2::~NuCachedSource2() {
@@ -433,7 +433,7 @@
delayUs = 100000ll;
}
- (new AMessage(kWhatFetchMore, mReflector->id()))->post(delayUs);
+ (new AMessage(kWhatFetchMore, mReflector))->post(delayUs);
}
void NuCachedSource2::onRead(const sp<AMessage> &msg) {
@@ -522,7 +522,7 @@
return size;
}
- sp<AMessage> msg = new AMessage(kWhatRead, mReflector->id());
+ sp<AMessage> msg = new AMessage(kWhatRead, mReflector);
msg->setInt64("offset", offset);
msg->setPointer("data", data);
msg->setSize("size", size);
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index ca031aa..230c1f7 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -37,7 +37,7 @@
MuxOMX(const sp<IOMX> &remoteOMX);
virtual ~MuxOMX();
- virtual IBinder *onAsBinder() { return mRemoteOMX->asBinder().get(); }
+ virtual IBinder *onAsBinder() { return IInterface::asBinder(mRemoteOMX).get(); }
virtual bool livesLocally(node_id node, pid_t pid);
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 6da00e6..ea19ab2 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -101,10 +101,10 @@
#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__)
+#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() {
@@ -451,7 +451,7 @@
// assertion, let's be lenient for now...
// CHECK((ptr[4] >> 2) == 0x3f); // reserved
- size_t lengthSize = 1 + (ptr[4] & 3);
+ size_t lengthSize __unused = 1 + (ptr[4] & 3);
// commented out check below as H264_QVGA_500_NO_AUDIO.3gp
// violates it...
@@ -2006,7 +2006,6 @@
OMXCodec::BufferInfo* OMXCodec::dequeueBufferFromNativeWindow() {
// Dequeue the next buffer from the native window.
ANativeWindowBuffer* buf;
- int fenceFd = -1;
int err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf);
if (err != 0) {
CODEC_LOGE("dequeueBuffer failed w/ error 0x%08x", err);
@@ -2111,7 +2110,6 @@
// on the screen and then been replaced, so an previous video frames are
// guaranteed NOT to be currently displayed.
for (int i = 0; i < numBufs + 1; i++) {
- int fenceFd = -1;
err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &anb);
if (err != NO_ERROR) {
ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index b8868aa..6e32494 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -849,6 +849,7 @@
{ "TRACKNUMBER", kKeyCDTrackNumber },
{ "DISCNUMBER", kKeyDiscNumber },
{ "DATE", kKeyDate },
+ { "YEAR", kKeyYear },
{ "LYRICIST", kKeyWriter },
{ "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
{ "ANDROID_LOOP", kKeyAutoLoop },
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 4449d57..db33e83 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -28,9 +28,6 @@
#include <media/mediametadataretriever.h>
#include <private/media/VideoFrame.h>
-// Sonivox includes
-#include <libsonivox/eas.h>
-
namespace android {
StagefrightMediaScanner::StagefrightMediaScanner() {}
@@ -57,54 +54,6 @@
return false;
}
-static MediaScanResult HandleMIDI(
- const char *filename, MediaScannerClient *client) {
- // get the library configuration and do sanity check
- const S_EAS_LIB_CONFIG* pLibConfig = EAS_Config();
- if ((pLibConfig == NULL) || (LIB_VERSION != pLibConfig->libVersion)) {
- ALOGE("EAS library/header mismatch\n");
- return MEDIA_SCAN_RESULT_ERROR;
- }
- EAS_I32 temp;
-
- // spin up a new EAS engine
- EAS_DATA_HANDLE easData = NULL;
- EAS_HANDLE easHandle = NULL;
- EAS_RESULT result = EAS_Init(&easData);
- if (result == EAS_SUCCESS) {
- EAS_FILE file;
- file.path = filename;
- file.fd = 0;
- file.offset = 0;
- file.length = 0;
- result = EAS_OpenFile(easData, &file, &easHandle);
- }
- if (result == EAS_SUCCESS) {
- result = EAS_Prepare(easData, easHandle);
- }
- if (result == EAS_SUCCESS) {
- result = EAS_ParseMetaData(easData, easHandle, &temp);
- }
- if (easHandle) {
- EAS_CloseFile(easData, easHandle);
- }
- if (easData) {
- EAS_Shutdown(easData);
- }
-
- if (result != EAS_SUCCESS) {
- return MEDIA_SCAN_RESULT_SKIPPED;
- }
-
- char buffer[20];
- sprintf(buffer, "%ld", temp);
- status_t status = client->addStringTag("duration", buffer);
- if (status != OK) {
- return MEDIA_SCAN_RESULT_ERROR;
- }
- return MEDIA_SCAN_RESULT_OK;
-}
-
MediaScanResult StagefrightMediaScanner::processFile(
const char *path, const char *mimeType,
MediaScannerClient &client) {
@@ -130,18 +79,6 @@
return MEDIA_SCAN_RESULT_SKIPPED;
}
- if (!strcasecmp(extension, ".mid")
- || !strcasecmp(extension, ".smf")
- || !strcasecmp(extension, ".imy")
- || !strcasecmp(extension, ".midi")
- || !strcasecmp(extension, ".xmf")
- || !strcasecmp(extension, ".rtttl")
- || !strcasecmp(extension, ".rtx")
- || !strcasecmp(extension, ".ota")
- || !strcasecmp(extension, ".mxmf")) {
- return HandleMIDI(path, &client);
- }
-
sp<MediaMetadataRetriever> mRetriever(new MediaMetadataRetriever);
int fd = open(path, O_RDONLY | O_LARGEFILE);
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 1fdb244..7d15220 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -52,7 +52,7 @@
TimedEventQueue::~TimedEventQueue() {
stop();
if (mPowerManager != 0) {
- sp<IBinder> binder = mPowerManager->asBinder();
+ sp<IBinder> binder = IInterface::asBinder(mPowerManager);
binder->unlinkToDeath(mDeathRecipient);
}
}
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 25afc5b..c0be136 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -181,14 +181,14 @@
CHECK(size >= 7);
CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
- uint8_t profile = ptr[1];
- uint8_t level = ptr[3];
+ uint8_t profile __unused = ptr[1];
+ uint8_t level __unused = 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 = 1 + (ptr[4] & 3);
+ size_t lengthSize __unused = 1 + (ptr[4] & 3);
// commented out check below as H264_QVGA_500_NO_AUDIO.3gp
// violates it...
@@ -257,8 +257,8 @@
CHECK(size >= 7);
CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
- uint8_t profile = ptr[1] & 31;
- uint8_t level = ptr[12];
+ uint8_t profile __unused = ptr[1] & 31;
+ uint8_t level __unused = ptr[12];
ptr += 22;
size -= 22;
@@ -344,6 +344,28 @@
buffer->meta()->setInt32("csd", true);
buffer->meta()->setInt64("timeUs", 0);
msg->setBuffer("csd-0", buffer);
+
+ if (!meta->findData(kKeyOpusCodecDelay, &type, &data, &size)) {
+ return -EINVAL;
+ }
+
+ buffer = new ABuffer(size);
+ memcpy(buffer->data(), data, size);
+
+ buffer->meta()->setInt32("csd", true);
+ buffer->meta()->setInt64("timeUs", 0);
+ msg->setBuffer("csd-1", buffer);
+
+ if (!meta->findData(kKeyOpusSeekPreRoll, &type, &data, &size)) {
+ return -EINVAL;
+ }
+
+ buffer = new ABuffer(size);
+ memcpy(buffer->data(), data, size);
+
+ buffer->meta()->setInt32("csd", true);
+ buffer->meta()->setInt64("timeUs", 0);
+ msg->setBuffer("csd-2", buffer);
}
*format = msg;
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index cbdb816..8ef2dca 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -26,6 +26,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
+#include <utils/misc.h>
namespace android {
@@ -186,17 +187,31 @@
if (aspect_ratio_idc == 255 /* extendedSAR */) {
sar_width = br.getBits(16);
sar_height = br.getBits(16);
- } else if (aspect_ratio_idc > 0 && aspect_ratio_idc < 14) {
- static const int32_t kFixedSARWidth[] = {
- 1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160
+ } else {
+ static const struct { unsigned width, height; } kFixedSARs[] = {
+ { 0, 0 }, // Invalid
+ { 1, 1 },
+ { 12, 11 },
+ { 10, 11 },
+ { 16, 11 },
+ { 40, 33 },
+ { 24, 11 },
+ { 20, 11 },
+ { 32, 11 },
+ { 80, 33 },
+ { 18, 11 },
+ { 15, 11 },
+ { 64, 33 },
+ { 160, 99 },
+ { 4, 3 },
+ { 3, 2 },
+ { 2, 1 },
};
- static const int32_t kFixedSARHeight[] = {
- 1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99
- };
-
- sar_width = kFixedSARWidth[aspect_ratio_idc - 1];
- sar_height = kFixedSARHeight[aspect_ratio_idc - 1];
+ if (aspect_ratio_idc > 0 && aspect_ratio_idc < NELEM(kFixedSARs)) {
+ sar_width = kFixedSARs[aspect_ratio_idc].width;
+ sar_height = kFixedSARs[aspect_ratio_idc].height;
+ }
}
}
@@ -505,8 +520,8 @@
CHECK_NE(video_object_type_indication,
0x21u /* Fine Granularity Scalable */);
- unsigned video_object_layer_verid;
- unsigned video_object_layer_priority;
+ unsigned video_object_layer_verid __unused;
+ unsigned video_object_layer_priority __unused;
if (br.getBits(1)) {
video_object_layer_verid = br.getBits(4);
video_object_layer_priority = br.getBits(3);
@@ -568,7 +583,7 @@
unsigned video_object_layer_height = br.getBits(13);
CHECK(br.getBits(1)); // marker_bit
- unsigned interlaced = br.getBits(1);
+ unsigned interlaced __unused = br.getBits(1);
*width = video_object_layer_width;
*height = video_object_layer_height;
@@ -614,7 +629,7 @@
return false;
}
- unsigned protection = (header >> 16) & 1;
+ unsigned protection __unused = (header >> 16) & 1;
unsigned bitrate_index = (header >> 12) & 0x0f;
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 351ba1e..10937ec 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -623,7 +623,7 @@
} else {
int64_t currentTime = mBufferTimestamps.top();
currentTime += mStreamInfo->aacSamplesPerFrame *
- 1000000ll / mStreamInfo->sampleRate;
+ 1000000ll / mStreamInfo->aacSampleRate;
mBufferTimestamps.add(currentTime);
}
} else {
@@ -874,9 +874,9 @@
// adjust/interpolate next time stamp
*currentBufLeft -= decodedSize;
*nextTimeStamp += mStreamInfo->aacSamplesPerFrame *
- 1000000ll / mStreamInfo->sampleRate;
+ 1000000ll / mStreamInfo->aacSampleRate;
ALOGV("adjusted nextTimeStamp/size to %lld/%d",
- *nextTimeStamp, *currentBufLeft);
+ (long long) *nextTimeStamp, *currentBufLeft);
} else {
// move to next timestamp in list
if (mBufferTimestamps.size() > 0) {
@@ -885,7 +885,7 @@
mBufferSizes.removeAt(0);
currentBufLeft = &mBufferSizes.editItemAt(0);
ALOGV("moved to next time/size: %lld/%d",
- *nextTimeStamp, *currentBufLeft);
+ (long long) *nextTimeStamp, *currentBufLeft);
}
// try to limit output buffer size to match input buffers
// (e.g when an input buffer contained 4 "sub" frames, output
@@ -975,6 +975,7 @@
mBufferSizes.clear();
mDecodedSizes.clear();
mLastInHeader = NULL;
+ mEndOfInput = false;
} else {
int avail;
while ((avail = outputDelayRingBufferSamplesAvailable()) > 0) {
@@ -989,12 +990,11 @@
mOutputBufferCount++;
}
mOutputDelayRingBufferReadPos = mOutputDelayRingBufferWritePos;
+ mEndOfOutput = false;
}
}
void SoftAAC2::drainDecoder() {
- int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels;
-
// flush decoder until outputDelay is compensated
while (mOutputDelayCompensated > 0) {
// a buffer big enough for MAX_CHANNEL_COUNT channels of decoded HE-AAC
diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
index 8b5007e..bebb9dc 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -214,8 +214,6 @@
status_t AACEncoder::read(
MediaBuffer **out, const ReadOptions *options) {
- status_t err;
-
*out = NULL;
int64_t seekTimeUs;
diff --git a/media/libstagefright/codecs/aacenc/basic_op/basic_op.h b/media/libstagefright/codecs/aacenc/basic_op/basic_op.h
index 5cd7e5f..bbc753b 100644
--- a/media/libstagefright/codecs/aacenc/basic_op/basic_op.h
+++ b/media/libstagefright/codecs/aacenc/basic_op/basic_op.h
@@ -518,8 +518,6 @@
return ASM_L_shr( L_var1, -var2);
}
#else
- Word32 L_var_out = 0L;
-
if (var2 <= 0)
{
L_var1 = L_shr(L_var1, (Word16)-var2);
@@ -540,7 +538,6 @@
}
}
L_var1 <<= 1;
- L_var_out = L_var1;
}
}
return (L_var1);
diff --git a/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c b/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c
index 1d029fc..4fd16a1 100644
--- a/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c
+++ b/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c
@@ -245,10 +245,9 @@
Word32 rsqrt(Word32 value, /*!< Operand to square root (0.0 ... 1) */
Word32 accuracy) /*!< Number of valid bits that will be calculated */
{
- UNUSED(accuracy);
-
Word32 root = 0;
Word32 scale;
+ UNUSED(accuracy);
if(value < 0)
return 0;
@@ -351,12 +350,11 @@
UWord32 iPart;
UWord32 fPart;
Word32 res;
- Word32 tmp, tmp2;
- Word32 shift, shift2;
+ Word32 tmp;
- tmp2 = -x;
- iPart = tmp2 / y;
- fPart = tmp2 - iPart*y;
+ tmp = -x;
+ iPart = tmp / y;
+ fPart = tmp - iPart*y;
iPart = min(iPart,INT_BITS-1);
res = pow2Table[(POW2_TABLE_SIZE*fPart)/y] >> iPart;
diff --git a/media/libstagefright/codecs/aacenc/src/aacenc.c b/media/libstagefright/codecs/aacenc/src/aacenc.c
index 40db92c..df17787 100644
--- a/media/libstagefright/codecs/aacenc/src/aacenc.c
+++ b/media/libstagefright/codecs/aacenc/src/aacenc.c
@@ -39,18 +39,20 @@
VO_U32 VO_API voAACEncInit(VO_HANDLE * phCodec,VO_AUDIO_CODINGTYPE vType, VO_CODEC_INIT_USERDATA *pUserData)
{
AAC_ENCODER*hAacEnc;
- AACENC_CONFIG config;
int error;
#ifdef USE_DEAULT_MEM
VO_MEM_OPERATOR voMemoprator;
#endif
VO_MEM_OPERATOR *pMemOP;
+
+#ifdef USE_DEAULT_MEM
int interMem;
+ interMem = 0;
+#endif
UNUSED(vType);
- interMem = 0;
error = 0;
/* init the memory operator */
@@ -214,7 +216,7 @@
AAC_ENCODER* hAacEnc = (AAC_ENCODER*)hCodec;
Word16 numAncDataBytes=0;
Word32 inbuflen;
- int ret, length;
+ int length;
if(NULL == hAacEnc)
return VO_ERR_INVALID_ARG;
diff --git a/media/libstagefright/codecs/aacenc/src/aacenc_core.c b/media/libstagefright/codecs/aacenc/src/aacenc_core.c
index cecbc8f..de452d4 100644
--- a/media/libstagefright/codecs/aacenc/src/aacenc_core.c
+++ b/media/libstagefright/codecs/aacenc/src/aacenc_core.c
@@ -58,7 +58,6 @@
const AACENC_CONFIG config /* pre-initialized config struct */
)
{
- Word32 i;
Word32 error = 0;
Word16 profile = 1;
diff --git a/media/libstagefright/codecs/aacenc/src/adj_thr.c b/media/libstagefright/codecs/aacenc/src/adj_thr.c
index 471631c..8b8be0e 100644
--- a/media/libstagefright/codecs/aacenc/src/adj_thr.c
+++ b/media/libstagefright/codecs/aacenc/src/adj_thr.c
@@ -96,7 +96,7 @@
MINSNR_ADAPT_PARAM *msaParam,
const Word16 nChannels)
{
- Word16 ch, sfb, sfbOffs, shift;
+ Word16 ch, sfb, sfbOffs;
Word32 nSfb, avgEn;
Word16 log_avgEn = 0;
Word32 startRatio_x_avgEn = 0;
diff --git a/media/libstagefright/codecs/aacenc/src/bitbuffer.c b/media/libstagefright/codecs/aacenc/src/bitbuffer.c
index 0ce93d3..15eebd0 100644
--- a/media/libstagefright/codecs/aacenc/src/bitbuffer.c
+++ b/media/libstagefright/codecs/aacenc/src/bitbuffer.c
@@ -24,29 +24,6 @@
/*****************************************************************************
*
-* function name: updateBitBufWordPtr
-* description: update Bit Buffer pointer
-*
-*****************************************************************************/
-static void updateBitBufWordPtr(HANDLE_BIT_BUF hBitBuf,
- UWord8 **pBitBufWord,
- Word16 cnt)
-{
- *pBitBufWord += cnt;
-
-
- if(*pBitBufWord > hBitBuf->pBitBufEnd) {
- *pBitBufWord -= (hBitBuf->pBitBufEnd - hBitBuf->pBitBufBase + 1);
- }
-
- if(*pBitBufWord < hBitBuf->pBitBufBase) {
- *pBitBufWord += (hBitBuf->pBitBufEnd - hBitBuf->pBitBufBase + 1);
- }
-}
-
-
-/*****************************************************************************
-*
* function name: CreateBitBuffer
* description: create and init Bit Buffer Management
*
diff --git a/media/libstagefright/codecs/aacenc/src/bitenc.c b/media/libstagefright/codecs/aacenc/src/bitenc.c
index d1fd647..9c81204 100644
--- a/media/libstagefright/codecs/aacenc/src/bitenc.c
+++ b/media/libstagefright/codecs/aacenc/src/bitenc.c
@@ -547,7 +547,7 @@
totFillBits = totFillBits - (3+4);
- if ((cnt == (1<<4)-1)) {
+ if (cnt == (1<<4)-1) {
esc_count = min( ((totFillBits >> 3) - ((1<<4)-1)), (1<<8)-1);
WriteBits(hBitStream,esc_count,8);
diff --git a/media/libstagefright/codecs/aacenc/src/block_switch.c b/media/libstagefright/codecs/aacenc/src/block_switch.c
index c80538f..11bc7e7 100644
--- a/media/libstagefright/codecs/aacenc/src/block_switch.c
+++ b/media/libstagefright/codecs/aacenc/src/block_switch.c
@@ -30,9 +30,6 @@
#define ENERGY_SHIFT (8 - 1)
/**************** internal function prototypes ***********/
-static Word16
-IIRFilter(const Word16 in, const Word32 coeff[], Word32 states[]);
-
static Word32
SrchMaxWithIndex(const Word32 *in, Word16 *index, Word16 n);
@@ -280,7 +277,7 @@
Word16 chIncrement,
Word16 windowLen)
{
- Word32 w, i, wOffset, tidx, ch;
+ Word32 w, i, tidx;
Word32 accuUE, accuFE;
Word32 tempUnfiltered;
Word32 tempFiltered;
@@ -329,30 +326,6 @@
}
#endif
-/*****************************************************************************
-*
-* function name: IIRFilter
-* description: calculate the iir-filter for an array
-* returns: the result after iir-filter
-*
-**********************************************************************************/
-static Word16 IIRFilter(const Word16 in, const Word32 coeff[], Word32 states[])
-{
- Word32 accu1, accu2, accu3;
- Word32 out;
-
- accu1 = L_mpy_ls(coeff[1], in);
- accu3 = accu1 - states[0];
- accu2 = fixmul( coeff[0], states[1] );
- out = accu3 - accu2;
-
- states[0] = accu1;
- states[1] = out;
-
- return round16(out);
-}
-
-
static Word16 synchronizedBlockTypeTable[4][4] = {
/* LONG_WINDOW START_WINDOW SHORT_WINDOW STOP_WINDOW */
/* LONG_WINDOW */{LONG_WINDOW, START_WINDOW, SHORT_WINDOW, STOP_WINDOW},
diff --git a/media/libstagefright/codecs/aacenc/src/ms_stereo.c b/media/libstagefright/codecs/aacenc/src/ms_stereo.c
index 2e34f14..1e4b227 100644
--- a/media/libstagefright/codecs/aacenc/src/ms_stereo.c
+++ b/media/libstagefright/codecs/aacenc/src/ms_stereo.c
@@ -50,7 +50,6 @@
const Word16 sfbPerGroup,
const Word16 maxSfbPerGroup,
const Word16 *sfbOffset) {
- Word32 temp;
Word32 sfb,sfboffs, j;
Word32 msMaskTrueSomewhere = 0;
Word32 msMaskFalseSomewhere = 0;
diff --git a/media/libstagefright/codecs/aacenc/src/sf_estim.c b/media/libstagefright/codecs/aacenc/src/sf_estim.c
index bc320ec..78947e1 100644
--- a/media/libstagefright/codecs/aacenc/src/sf_estim.c
+++ b/media/libstagefright/codecs/aacenc/src/sf_estim.c
@@ -99,7 +99,7 @@
{
Word32 sfbw, sfbw1;
Word32 i, j;
- Word32 sfbOffs, sfb, shift;
+ Word32 sfbOffs, sfb;
sfbw = sfbw1 = 0;
for (sfbOffs=0; sfbOffs<psyOutChan->sfbCnt; sfbOffs+=psyOutChan->sfbPerGroup){
diff --git a/media/libstagefright/codecs/aacenc/src/tns.c b/media/libstagefright/codecs/aacenc/src/tns.c
index 5172612..27c3971 100644
--- a/media/libstagefright/codecs/aacenc/src/tns.c
+++ b/media/libstagefright/codecs/aacenc/src/tns.c
@@ -140,7 +140,7 @@
Word16 active) /*!< tns active flag */
{
- Word32 bitratePerChannel;
+ Word32 bitratePerChannel __unused;
tC->maxOrder = TNS_MAX_ORDER;
tC->tnsStartFreq = 1275;
tC->coefRes = 4;
@@ -206,7 +206,7 @@
PSY_CONFIGURATION_SHORT *pC, /*!< psy config struct */
Word16 active) /*!< tns active flag */
{
- Word32 bitratePerChannel;
+ Word32 bitratePerChannel __unused;
tC->maxOrder = TNS_MAX_ORDER_SHORT;
tC->tnsStartFreq = 2750;
tC->coefRes = 3;
@@ -497,36 +497,6 @@
/*****************************************************************************
*
-* function name: m_pow2_cordic
-* description: Iterative power function
-*
-* Calculates pow(2.0,x-1.0*(scale+1)) with INT_BITS bit precision
-* using modified cordic algorithm
-* returns: the result of pow2
-*
-*****************************************************************************/
-static Word32 m_pow2_cordic(Word32 x, Word16 scale)
-{
- Word32 k;
-
- Word32 accu_y = 0x40000000;
- accu_y = L_shr(accu_y,scale);
-
- for(k=1; k<INT_BITS; k++) {
- const Word32 z = m_log2_table[k];
-
- while(L_sub(x,z) >= 0) {
-
- x = L_sub(x, z);
- accu_y = L_add(accu_y, (accu_y >> k));
- }
- }
- return(accu_y);
-}
-
-
-/*****************************************************************************
-*
* function name: CalcWeightedSpectrum
* description: Calculate weighted spectrum for LPC calculation
*
diff --git a/media/libstagefright/codecs/aacenc/src/transform.c b/media/libstagefright/codecs/aacenc/src/transform.c
index a02336f..0080810 100644
--- a/media/libstagefright/codecs/aacenc/src/transform.c
+++ b/media/libstagefright/codecs/aacenc/src/transform.c
@@ -475,7 +475,6 @@
Word32 *winPtr;
Word32 delayBufferSf,timeSignalSf,minSf;
- Word32 headRoom=0;
switch(blockType){
diff --git a/media/libstagefright/codecs/amrnb/common/Android.mk b/media/libstagefright/codecs/amrnb/common/Android.mk
index a2b3c8f..5e632a6 100644
--- a/media/libstagefright/codecs/amrnb/common/Android.mk
+++ b/media/libstagefright/codecs/amrnb/common/Android.mk
@@ -67,7 +67,7 @@
$(LOCAL_PATH)/include
LOCAL_CFLAGS := \
- -DOSCL_UNUSED_ARG= -DOSCL_IMPORT_REF= -DOSCL_EXPORT_REF=
+ -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_IMPORT_REF= -DOSCL_EXPORT_REF=
LOCAL_CFLAGS += -Werror
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 35638e3..c4e4d4f 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,7 +115,7 @@
Returns:
L_sum = 32-bit sum of L_var1 and L_var2 (Word32)
*/
- static inline Word32 L_add(register Word32 L_var1, register Word32 L_var2, Flag *pOverflow)
+ static inline Word32 L_add(Word32 L_var1, Word32 L_var2, Flag *pOverflow)
{
Word32 L_sum;
@@ -154,8 +154,8 @@
Returns:
L_diff = 32-bit difference of L_var1 and L_var2 (Word32)
*/
- static inline Word32 L_sub(register Word32 L_var1, register Word32 L_var2,
- register Flag *pOverflow)
+ static inline Word32 L_sub(Word32 L_var1, Word32 L_var2,
+ Flag *pOverflow)
{
Word32 L_diff;
@@ -246,7 +246,7 @@
*/
static inline Word32 L_mult(Word16 var1, Word16 var2, Flag *pOverflow)
{
- register Word32 L_product;
+ Word32 L_product;
L_product = (Word32) var1 * var2;
@@ -452,7 +452,7 @@
*/
static inline Word16 mult(Word16 var1, Word16 var2, Flag *pOverflow)
{
- register Word32 product;
+ Word32 product;
product = ((Word32) var1 * var2) >> 15;
diff --git a/media/libstagefright/codecs/amrnb/common/src/az_lsp.cpp b/media/libstagefright/codecs/amrnb/common/src/az_lsp.cpp
index 4135f30..976b1a6 100644
--- a/media/libstagefright/codecs/amrnb/common/src/az_lsp.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/az_lsp.cpp
@@ -564,10 +564,10 @@
Flag *pOverflow /* (i/o): overflow flag */
)
{
- register Word16 i;
- register Word16 j;
- register Word16 nf;
- register Word16 ip;
+ Word16 i;
+ Word16 j;
+ Word16 nf;
+ Word16 ip;
Word16 xlow;
Word16 ylow;
Word16 xhigh;
diff --git a/media/libstagefright/codecs/amrnb/common/src/div_s.cpp b/media/libstagefright/codecs/amrnb/common/src/div_s.cpp
index f3bed7e..14d30c5 100644
--- a/media/libstagefright/codecs/amrnb/common/src/div_s.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/div_s.cpp
@@ -207,13 +207,13 @@
/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
-Word16 div_s(register Word16 var1, register Word16 var2)
+Word16 div_s(Word16 var1, Word16 var2)
{
/*----------------------------------------------------------------------------
; Define all local variables
----------------------------------------------------------------------------*/
Word16 var_out = 0;
- register Word16 iteration;
+ Word16 iteration;
Word32 L_num;
Word32 L_denom;
Word32 L_denom_by_2;
diff --git a/media/libstagefright/codecs/amrnb/common/src/gc_pred.cpp b/media/libstagefright/codecs/amrnb/common/src/gc_pred.cpp
index 3650f3c..1c8a700 100644
--- a/media/libstagefright/codecs/amrnb/common/src/gc_pred.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/gc_pred.cpp
@@ -477,9 +477,9 @@
Flag *pOverflow
)
{
- register Word16 i;
- register Word32 L_temp1, L_temp2;
- register Word32 L_tmp;
+ Word16 i;
+ Word32 L_temp1, L_temp2;
+ Word32 L_tmp;
Word32 ener_code;
Word32 ener;
Word16 exp, frac;
@@ -993,7 +993,7 @@
)
{
Word16 av_pred_en;
- register Word16 i;
+ Word16 i;
/* do average in MR122 mode (log2() domain) */
av_pred_en = 0;
diff --git a/media/libstagefright/codecs/amrnb/common/src/gmed_n.cpp b/media/libstagefright/codecs/amrnb/common/src/gmed_n.cpp
index be76241..2d3b9e4 100644
--- a/media/libstagefright/codecs/amrnb/common/src/gmed_n.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/gmed_n.cpp
@@ -185,9 +185,9 @@
Word16 n /* i : number of inputs */
)
{
- register Word16 i, j, ix = 0;
- register Word16 max;
- register Word16 medianIndex;
+ Word16 i, j, ix = 0;
+ Word16 max;
+ Word16 medianIndex;
Word16 tmp[NMAX];
Word16 tmp2[NMAX];
diff --git a/media/libstagefright/codecs/amrnb/common/src/lsp_az.cpp b/media/libstagefright/codecs/amrnb/common/src/lsp_az.cpp
index 6b7b471..495359f 100644
--- a/media/libstagefright/codecs/amrnb/common/src/lsp_az.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/lsp_az.cpp
@@ -254,8 +254,8 @@
Word32 *f,
Flag *pOverflow)
{
- register Word16 i;
- register Word16 j;
+ Word16 i;
+ Word16 j;
Word16 hi;
Word16 lo;
@@ -511,8 +511,8 @@
Flag *pOverflow /* (o) : overflow flag */
)
{
- register Word16 i;
- register Word16 j;
+ Word16 i;
+ Word16 j;
Word32 f1[6];
Word32 f2[6];
diff --git a/media/libstagefright/codecs/amrnb/common/src/mult_r.cpp b/media/libstagefright/codecs/amrnb/common/src/mult_r.cpp
index 0777e68..7112b3d 100644
--- a/media/libstagefright/codecs/amrnb/common/src/mult_r.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/mult_r.cpp
@@ -190,7 +190,7 @@
Word16 mult_r(Word16 var1, Word16 var2, Flag *pOverflow)
{
- register Word32 L_product_arr;
+ Word32 L_product_arr;
L_product_arr = ((Word32) var1) * var2; /* product */
L_product_arr += (Word32) 0x00004000L; /* round */
diff --git a/media/libstagefright/codecs/amrnb/common/src/norm_l.cpp b/media/libstagefright/codecs/amrnb/common/src/norm_l.cpp
index 132fed6..d8d1259 100644
--- a/media/libstagefright/codecs/amrnb/common/src/norm_l.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/norm_l.cpp
@@ -197,12 +197,12 @@
; FUNCTION CODE
----------------------------------------------------------------------------*/
#if !( defined(PV_ARM_V5) || defined(PV_ARM_GCC_V5) )
-Word16 norm_l(register Word32 L_var1)
+Word16 norm_l(Word32 L_var1)
{
/*----------------------------------------------------------------------------
; Define all local variables
----------------------------------------------------------------------------*/
- register Word16 var_out = 0;
+ Word16 var_out = 0;
/*----------------------------------------------------------------------------
; Function body here
diff --git a/media/libstagefright/codecs/amrnb/common/src/norm_s.cpp b/media/libstagefright/codecs/amrnb/common/src/norm_s.cpp
index 8cdcdb8..6468b67 100644
--- a/media/libstagefright/codecs/amrnb/common/src/norm_s.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/norm_s.cpp
@@ -194,13 +194,13 @@
----------------------------------------------------------------------------*/
#if !( defined(PV_ARM_V5) || defined(PV_ARM_GCC_V5) )
-Word16 norm_s(register Word16 var1)
+Word16 norm_s(Word16 var1)
{
/*----------------------------------------------------------------------------
; Define all local variables
----------------------------------------------------------------------------*/
- register Word16 var_out = 0;
+ Word16 var_out = 0;
/*----------------------------------------------------------------------------
; Function body here
diff --git a/media/libstagefright/codecs/amrnb/common/src/pred_lt.cpp b/media/libstagefright/codecs/amrnb/common/src/pred_lt.cpp
index 9163623..8a1aa9e 100644
--- a/media/libstagefright/codecs/amrnb/common/src/pred_lt.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/pred_lt.cpp
@@ -260,9 +260,9 @@
Flag *pOverflow /* output: if set, overflow occurred in this function */
)
{
- register Word16 i;
- register Word16 j;
- register Word16 k;
+ Word16 i;
+ Word16 j;
+ Word16 k;
Word16 *pX0;
Word16 *pX2;
diff --git a/media/libstagefright/codecs/amrnb/common/src/q_plsf_3.cpp b/media/libstagefright/codecs/amrnb/common/src/q_plsf_3.cpp
index 2b30bf4..c70847e 100644
--- a/media/libstagefright/codecs/amrnb/common/src/q_plsf_3.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/q_plsf_3.cpp
@@ -281,7 +281,7 @@
Flag *pOverflow /* o : Flag set when overflow occurs */
)
{
- register Word16 i;
+ Word16 i;
Word16 temp;
const Word16 *p_dico;
Word16 index = 0;
@@ -607,7 +607,7 @@
Flag use_half, /* i: use every second entry in codebook */
Flag *pOverflow) /* o : Flag set when overflow occurs */
{
- register Word16 i;
+ Word16 i;
Word16 temp;
const Word16 *p_dico;
@@ -1013,7 +1013,7 @@
Flag *pOverflow /* o : Flag set when overflow occurs */
)
{
- register Word16 i, j;
+ Word16 i, j;
Word16 lsf1[M];
Word16 wf1[M];
Word16 lsf_p[M];
diff --git a/media/libstagefright/codecs/amrnb/common/src/residu.cpp b/media/libstagefright/codecs/amrnb/common/src/residu.cpp
index b25d3be..2ad132f 100644
--- a/media/libstagefright/codecs/amrnb/common/src/residu.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/residu.cpp
@@ -202,7 +202,7 @@
{
- register Word16 i, j;
+ Word16 i, j;
Word32 s1;
Word32 s2;
Word32 s3;
diff --git a/media/libstagefright/codecs/amrnb/common/src/shr.cpp b/media/libstagefright/codecs/amrnb/common/src/shr.cpp
index 775dc69..1018d9c 100644
--- a/media/libstagefright/codecs/amrnb/common/src/shr.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/shr.cpp
@@ -202,10 +202,10 @@
/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
-Word16 shr(register Word16 var1, register Word16 var2, Flag *pOverflow)
+Word16 shr(Word16 var1, Word16 var2, Flag *pOverflow)
{
- register Word16 result;
- register Word32 temp_res;
+ Word16 result;
+ Word32 temp_res;
if (var2 != 0)
{
diff --git a/media/libstagefright/codecs/amrnb/common/src/weight_a.cpp b/media/libstagefright/codecs/amrnb/common/src/weight_a.cpp
index 2e2efc4..ee821ef 100644
--- a/media/libstagefright/codecs/amrnb/common/src/weight_a.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/weight_a.cpp
@@ -178,7 +178,7 @@
Word16 a_exp[] /* (o) : Spectral expanded LPC coefficients */
)
{
- register Word16 i;
+ Word16 i;
*(a_exp) = *(a);
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk
index b067456..3750e2e 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.mk
+++ b/media/libstagefright/codecs/amrnb/dec/Android.mk
@@ -45,7 +45,7 @@
$(LOCAL_PATH)/../common/include
LOCAL_CFLAGS := \
- -DOSCL_UNUSED_ARG= -DOSCL_IMPORT_REF=
+ -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_IMPORT_REF=
LOCAL_CFLAGS += -Werror
@@ -83,3 +83,24 @@
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
+
+################################################################################
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ test/amrnbdec_test.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/../common/include \
+ $(call include-path-for, audio-utils)
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_amrnbdec libsndfile
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright_amrnb_common libaudioutils
+
+LOCAL_MODULE := libstagefright_amrnbdec_test
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/amrnb/dec/src/d1035pf.cpp b/media/libstagefright/codecs/amrnb/dec/src/d1035pf.cpp
index 899daba..861b3e6 100644
--- a/media/libstagefright/codecs/amrnb/dec/src/d1035pf.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/src/d1035pf.cpp
@@ -209,7 +209,7 @@
Word16 cod[] /* (o) : algebraic (fixed) codebook excitation */
)
{
- register Word16 i, j, pos1, pos2;
+ Word16 i, j, pos1, pos2;
Word16 sign, tmp;
for (i = 0; i < L_CODE; i++)
diff --git a/media/libstagefright/codecs/amrnb/dec/src/d_plsf_5.cpp b/media/libstagefright/codecs/amrnb/dec/src/d_plsf_5.cpp
index 08b690d..7068c0a 100644
--- a/media/libstagefright/codecs/amrnb/dec/src/d_plsf_5.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/src/d_plsf_5.cpp
@@ -308,7 +308,7 @@
Flag *pOverflow /* o : Flag set when overflow occurs */
)
{
- register Word16 i;
+ Word16 i;
Word16 temp;
Word16 sign;
diff --git a/media/libstagefright/codecs/amrnb/dec/src/int_lsf.cpp b/media/libstagefright/codecs/amrnb/dec/src/int_lsf.cpp
index c5aefe4..2ca30de 100644
--- a/media/libstagefright/codecs/amrnb/dec/src/int_lsf.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/src/int_lsf.cpp
@@ -218,9 +218,9 @@
Flag *pOverflow /* o : flag set if overflow occurs */
)
{
- register Word16 i;
- register Word16 temp1;
- register Word16 temp2;
+ Word16 i;
+ Word16 temp1;
+ Word16 temp2;
if (i_subfr == 0)
{
diff --git a/media/libstagefright/codecs/amrnb/dec/src/ph_disp.cpp b/media/libstagefright/codecs/amrnb/dec/src/ph_disp.cpp
index da5445b..285465f 100644
--- a/media/libstagefright/codecs/amrnb/dec/src/ph_disp.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/src/ph_disp.cpp
@@ -207,7 +207,7 @@
Word16 ph_disp_reset(ph_dispState *state)
{
- register Word16 i;
+ Word16 i;
if (state == (ph_dispState *) NULL)
{
@@ -667,15 +667,15 @@
Flag *pOverflow /* i/o : oveflow indicator */
)
{
- register Word16 i, i1;
- register Word16 tmp1;
+ Word16 i, i1;
+ Word16 tmp1;
Word32 L_temp;
Word32 L_temp2;
Word16 impNr; /* indicator for amount of disp./filter used */
Word16 inno_sav[L_SUBFR];
Word16 ps_poss[L_SUBFR];
- register Word16 nze, nPulse;
+ Word16 nze, nPulse;
Word16 ppos;
const Word16 *ph_imp; /* Pointer to phase dispersion filter */
diff --git a/media/libstagefright/codecs/amrnb/dec/src/pstfilt.cpp b/media/libstagefright/codecs/amrnb/dec/src/pstfilt.cpp
index 0336990..39e01a2 100644
--- a/media/libstagefright/codecs/amrnb/dec/src/pstfilt.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/src/pstfilt.cpp
@@ -445,13 +445,13 @@
)
{
Word16 Ap3[MP1];
- Word16 Ap4[MP1]; /* bandwidth expanded LP parameters */
- Word16 *Az; /* pointer to Az_4: */
+ Word16 Ap4[MP1]; /* bandwidth expanded LP parameters */
+ Word16 *Az; /* pointer to Az_4: */
/* LPC parameters in each subframe */
- register Word16 i_subfr; /* index for beginning of subframe */
+ Word16 i_subfr; /* index for beginning of subframe */
Word16 h[L_H];
- register Word16 i;
+ Word16 i;
Word16 temp1;
Word16 temp2;
Word32 L_tmp;
diff --git a/media/libstagefright/codecs/amrnb/dec/test/amrnbdec_test.cpp b/media/libstagefright/codecs/amrnb/dec/test/amrnbdec_test.cpp
new file mode 100644
index 0000000..41a9e98
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/dec/test/amrnbdec_test.cpp
@@ -0,0 +1,150 @@
+/*
+ * 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 <malloc.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+
+#include "gsmamr_dec.h"
+#include <audio_utils/sndfile.h>
+
+// Constants for AMR-NB
+enum {
+ kInputBufferSize = 64,
+ kSamplesPerFrame = 160,
+ kBitsPerSample = 16,
+ kOutputBufferSize = kSamplesPerFrame * kBitsPerSample/8,
+ kSampleRate = 8000,
+ kChannels = 1,
+ kFileHeaderSize = 6
+};
+const uint32_t kFrameSizes[] = {12, 13, 15, 17, 19, 20, 26, 31};
+
+
+int main(int argc, char *argv[]) {
+
+ if(argc != 3) {
+ fprintf(stderr, "Usage %s <input file> <output file>\n", argv[0]);
+ return 1;
+ }
+
+ // Open the input file
+ FILE* fpInput = fopen(argv[1], "rb");
+ if (!fpInput) {
+ fprintf(stderr, "Could not open %s\n", argv[1]);
+ return 1;
+ }
+
+ // Validate the input AMR file
+ char header[kFileHeaderSize];
+ int bytesRead = fread(header, 1, kFileHeaderSize, fpInput);
+ if (bytesRead != kFileHeaderSize || memcmp(header, "#!AMR\n", kFileHeaderSize)) {
+ fprintf(stderr, "Invalid AMR-NB file\n");
+ return 1;
+ }
+
+ // 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){
+ fprintf(stderr, "Could not create %s\n", argv[2]);
+ return 1;
+ }
+
+ // Create AMR-NB decoder instance
+ void* amrHandle;
+ int err = GSMInitDecode(&amrHandle, (Word8*)"AMRNBDecoder");
+ if(err != 0){
+ fprintf(stderr, "Error creating AMR-NB decoder instance\n");
+ return 1;
+ }
+
+ //Allocate input buffer
+ void *inputBuf = malloc(kInputBufferSize);
+ assert(inputBuf != NULL);
+
+ //Allocate output buffer
+ void *outputBuf = malloc(kOutputBufferSize);
+ assert(outputBuf != NULL);
+
+
+ // Decode loop
+ uint32_t retVal = 0;
+ while (1) {
+ // Read mode
+ uint8_t mode;
+ bytesRead = fread(&mode, 1, 1, fpInput);
+ if (bytesRead != 1) break;
+
+ // Find frame type
+ Frame_Type_3GPP frameType = (Frame_Type_3GPP)((mode >> 3) & 0x0f);
+ if (frameType >= AMR_SID){
+ fprintf(stderr, "Frame type %d not supported\n",frameType);
+ retVal = 1;
+ break;
+ }
+
+ // Find frame type
+ int32_t frameSize = kFrameSizes[frameType];
+ bytesRead = fread(inputBuf, 1, frameSize, fpInput);
+ if (bytesRead != frameSize) break;
+
+ //Decode frame
+ int32_t decodeStatus;
+ decodeStatus = AMRDecode(amrHandle, frameType, (uint8_t*)inputBuf,
+ (int16_t*)outputBuf, MIME_IETF);
+ if(decodeStatus == -1) {
+ fprintf(stderr, "Decoder encountered error\n");
+ retVal = 1;
+ break;
+ }
+
+ //Write output to wav
+ sf_writef_short(handle, (int16_t*)outputBuf, kSamplesPerFrame);
+
+ }
+
+ // Close input and output file
+ fclose(fpInput);
+ sf_close(handle);
+
+ //Free allocated memory
+ free(inputBuf);
+ free(outputBuf);
+
+ // Close decoder instance
+ GSMDecodeFrameExit(&amrHandle);
+
+ return retVal;
+}
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.mk b/media/libstagefright/codecs/amrnb/enc/Android.mk
index afc0b89..bdba8a9 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.mk
+++ b/media/libstagefright/codecs/amrnb/enc/Android.mk
@@ -67,7 +67,7 @@
$(LOCAL_PATH)/../common/include
LOCAL_CFLAGS := \
- -DOSCL_UNUSED_ARG=
+ -D"OSCL_UNUSED_ARG(x)=(void)(x)"
LOCAL_CFLAGS += -Werror
diff --git a/media/libstagefright/codecs/amrnb/enc/src/autocorr.cpp b/media/libstagefright/codecs/amrnb/enc/src/autocorr.cpp
index 0d3acac..c71811d 100644
--- a/media/libstagefright/codecs/amrnb/enc/src/autocorr.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/src/autocorr.cpp
@@ -306,9 +306,9 @@
Flag *pOverflow /* (o) : indicates overflow */
)
{
- register Word16 i;
- register Word16 j;
- register Word16 norm;
+ Word16 i;
+ Word16 j;
+ Word16 norm;
Word16 y[L_WINDOW];
Word32 sum;
diff --git a/media/libstagefright/codecs/amrnb/enc/src/c2_9pf.cpp b/media/libstagefright/codecs/amrnb/enc/src/c2_9pf.cpp
index a33cdf74..b211032 100644
--- a/media/libstagefright/codecs/amrnb/enc/src/c2_9pf.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/src/c2_9pf.cpp
@@ -318,7 +318,7 @@
Word16 dn_sign[L_CODE];
Word16 rr[L_CODE][L_CODE];
- register Word16 i;
+ Word16 i;
Word16 index;
Word16 sharp;
@@ -592,10 +592,10 @@
Flag * pOverflow /* o : Flag set when overflow occurs */
)
{
- register Word16 i0;
- register Word16 i1;
+ Word16 i0;
+ Word16 i1;
Word16 ix = 0; /* initialization only needed to keep gcc silent */
- register Word16 track1;
+ Word16 track1;
Word16 ipos[NB_PULSE];
Word16 psk;
Word16 ps0;
@@ -608,7 +608,7 @@
Word32 s;
Word32 alp0;
Word32 alp1;
- register Word16 i;
+ Word16 i;
Word32 L_temp;
Word16 *p_codvec = &codvec[0];
@@ -993,13 +993,13 @@
Flag *pOverflow /* o : Flag set when overflow occurs */
)
{
- register Word16 i;
- register Word16 j;
- register Word16 k;
- register Word16 track;
- register Word16 first;
- register Word16 index;
- register Word16 rsign;
+ Word16 i;
+ Word16 j;
+ Word16 k;
+ Word16 track;
+ Word16 first;
+ Word16 index;
+ Word16 rsign;
Word16 indx;
Word16 _sign[NB_PULSE];
Word16 *p0;
diff --git a/media/libstagefright/codecs/amrnb/enc/src/cl_ltp.cpp b/media/libstagefright/codecs/amrnb/enc/src/cl_ltp.cpp
index 4a05327..525e57d 100644
--- a/media/libstagefright/codecs/amrnb/enc/src/cl_ltp.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/src/cl_ltp.cpp
@@ -638,7 +638,7 @@
Flag *pOverflow /* o : overflow indicator */
)
{
- register Word16 i;
+ Word16 i;
Word16 index;
Word32 L_temp; /* temporarily variable */
Word16 resu3; /* flag for upsample resolution */
diff --git a/media/libstagefright/codecs/amrnb/enc/src/convolve.cpp b/media/libstagefright/codecs/amrnb/enc/src/convolve.cpp
index e9ce7ba..5015a4a 100644
--- a/media/libstagefright/codecs/amrnb/enc/src/convolve.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/src/convolve.cpp
@@ -212,7 +212,7 @@
Word16 L /* (i) : vector size */
)
{
- register Word16 i, n;
+ Word16 i, n;
Word32 s1, s2;
diff --git a/media/libstagefright/codecs/amrnb/enc/src/cor_h.cpp b/media/libstagefright/codecs/amrnb/enc/src/cor_h.cpp
index e46d99f..20583c4 100644
--- a/media/libstagefright/codecs/amrnb/enc/src/cor_h.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/src/cor_h.cpp
@@ -272,8 +272,8 @@
Flag *pOverflow
)
{
- register Word16 i;
- register Word16 dec;
+ Word16 i;
+ Word16 dec;
Word16 h2[L_CODE];
Word32 s;
diff --git a/media/libstagefright/codecs/amrnb/enc/src/cor_h_x.cpp b/media/libstagefright/codecs/amrnb/enc/src/cor_h_x.cpp
index beb2aec..c25c026 100644
--- a/media/libstagefright/codecs/amrnb/enc/src/cor_h_x.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/src/cor_h_x.cpp
@@ -249,9 +249,9 @@
Flag *pOverflow /* (o): pointer to overflow flag */
)
{
- register Word16 i;
- register Word16 j;
- register Word16 k;
+ Word16 i;
+ Word16 j;
+ Word16 k;
Word32 s;
Word32 y32[L_CODE];
diff --git a/media/libstagefright/codecs/amrnb/enc/src/cor_h_x2.cpp b/media/libstagefright/codecs/amrnb/enc/src/cor_h_x2.cpp
index da60640..b4fd867 100644
--- a/media/libstagefright/codecs/amrnb/enc/src/cor_h_x2.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/src/cor_h_x2.cpp
@@ -236,9 +236,9 @@
Flag *pOverflow
)
{
- register Word16 i;
- register Word16 j;
- register Word16 k;
+ Word16 i;
+ Word16 j;
+ Word16 k;
Word32 s;
Word32 y32[L_CODE];
Word32 max;
diff --git a/media/libstagefright/codecs/amrnb/enc/src/dtx_enc.cpp b/media/libstagefright/codecs/amrnb/enc/src/dtx_enc.cpp
index 276e590..2ccb777 100644
--- a/media/libstagefright/codecs/amrnb/enc/src/dtx_enc.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/src/dtx_enc.cpp
@@ -130,7 +130,7 @@
; MACROS
; Define module specific macros here
----------------------------------------------------------------------------*/
-extern Word32 L_add(register Word32 L_var1, register Word32 L_var2, Flag *pOverflow);
+extern Word32 L_add(Word32 L_var1, Word32 L_var2, Flag *pOverflow);
/*----------------------------------------------------------------------------
; DEFINES
@@ -671,7 +671,7 @@
Flag *pOverflow /* i/o : overflow indicator */
)
{
- register Word16 i, j;
+ Word16 i, j;
Word16 temp;
Word16 log_en;
Word16 lsf[M];
@@ -943,7 +943,7 @@
)
{
- register Word16 i;
+ Word16 i;
Word32 L_frame_en;
Word32 L_temp;
Word16 log_en_e;
diff --git a/media/libstagefright/codecs/amrnb/enc/src/levinson.cpp b/media/libstagefright/codecs/amrnb/enc/src/levinson.cpp
index 001897b..29cdac6 100644
--- a/media/libstagefright/codecs/amrnb/enc/src/levinson.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/src/levinson.cpp
@@ -638,8 +638,8 @@
Flag *pOverflow
)
{
- register Word16 i;
- register Word16 j;
+ Word16 i;
+ Word16 j;
Word16 hi;
Word16 lo;
Word16 Kh; /* reflexion coefficient; hi and lo */
@@ -651,9 +651,9 @@
Word16 Al[M + 1];
Word16 Anh[M + 1]; /* LPC coef.for next iteration in */
Word16 Anl[M + 1]; /* double prec. */
- register Word32 t0; /* temporary variable */
- register Word32 t1; /* temporary variable */
- register Word32 t2; /* temporary variable */
+ Word32 t0; /* temporary variable */
+ Word32 t1; /* temporary variable */
+ Word32 t2; /* temporary variable */
Word16 *p_Rh;
Word16 *p_Rl;
diff --git a/media/libstagefright/codecs/amrnb/enc/src/pitch_ol.cpp b/media/libstagefright/codecs/amrnb/enc/src/pitch_ol.cpp
index d3a2ec0..c039bb0 100644
--- a/media/libstagefright/codecs/amrnb/enc/src/pitch_ol.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/src/pitch_ol.cpp
@@ -320,7 +320,7 @@
)
#endif
{
- register Word16 i;
+ Word16 i;
Word16 *p;
Word32 max;
Word32 t0;
diff --git a/media/libstagefright/codecs/amrnb/enc/src/pre_proc.cpp b/media/libstagefright/codecs/amrnb/enc/src/pre_proc.cpp
index fdc2440..042920e 100644
--- a/media/libstagefright/codecs/amrnb/enc/src/pre_proc.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/src/pre_proc.cpp
@@ -542,7 +542,7 @@
Word16 signal[], /* input/output signal */
Word16 lg) /* length of signal */
{
- register Word16 i;
+ Word16 i;
Word16 x_n_2;
Word16 x_n_1;
Word32 L_tmp;
diff --git a/media/libstagefright/codecs/amrnb/enc/src/set_sign.cpp b/media/libstagefright/codecs/amrnb/enc/src/set_sign.cpp
index d626de3..fa43f78 100644
--- a/media/libstagefright/codecs/amrnb/enc/src/set_sign.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/src/set_sign.cpp
@@ -248,7 +248,7 @@
Word16 n /* i : # of maximum correlations in dn2[] */
)
{
- register Word16 i, j, k;
+ Word16 i, j, k;
Word16 val, min;
Word16 pos = 0; /* initialization only needed to keep gcc silent */
diff --git a/media/libstagefright/codecs/amrwb/Android.mk b/media/libstagefright/codecs/amrwb/Android.mk
index efdf988..686f7a3 100644
--- a/media/libstagefright/codecs/amrwb/Android.mk
+++ b/media/libstagefright/codecs/amrwb/Android.mk
@@ -48,7 +48,7 @@
$(LOCAL_PATH)/include
LOCAL_CFLAGS := \
- -DOSCL_UNUSED_ARG= -DOSCL_IMPORT_REF=
+ -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_IMPORT_REF=
LOCAL_CFLAGS += -Werror
diff --git a/media/libstagefright/codecs/amrwb/src/pvamrwb_math_op.cpp b/media/libstagefright/codecs/amrwb/src/pvamrwb_math_op.cpp
index d1ec790..5872512 100644
--- a/media/libstagefright/codecs/amrwb/src/pvamrwb_math_op.cpp
+++ b/media/libstagefright/codecs/amrwb/src/pvamrwb_math_op.cpp
@@ -205,7 +205,7 @@
{
int16 var_out = 0;
- register int16 iteration;
+ int16 iteration;
int32 L_num;
int32 L_denom;
int32 L_denom_by_2;
diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk
index 64fe8d1..024a292 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/Android.mk
@@ -86,6 +86,9 @@
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
diff --git a/media/libstagefright/codecs/amrwbenc/src/q_pulse.c b/media/libstagefright/codecs/amrwbenc/src/q_pulse.c
index 80a0b73..d658602 100644
--- a/media/libstagefright/codecs/amrwbenc/src/q_pulse.c
+++ b/media/libstagefright/codecs/amrwbenc/src/q_pulse.c
@@ -188,7 +188,7 @@
Word16 pos[], /* (i) position of the pulse 1..4 */
Word16 N) /* (i) number of bits for position */
{
- Word16 nb_pos, mask, n_1, tmp;
+ Word16 nb_pos, mask __unused, n_1, tmp;
Word16 posA[4], posB[4];
Word32 i, j, k, index;
diff --git a/media/libstagefright/codecs/amrwbenc/src/wb_vad.c b/media/libstagefright/codecs/amrwbenc/src/wb_vad.c
index 13dd2aa..2beaefd 100644
--- a/media/libstagefright/codecs/amrwbenc/src/wb_vad.c
+++ b/media/libstagefright/codecs/amrwbenc/src/wb_vad.c
@@ -404,7 +404,7 @@
alpha_down = ALPHA_DOWN1;
} else
{
- if ((st->stat_count == 0))
+ if (st->stat_count == 0)
{
alpha_up = ALPHA_UP2;
alpha_down = ALPHA_DOWN2;
diff --git a/media/libstagefright/codecs/avc/common/src/deblock.cpp b/media/libstagefright/codecs/avc/common/src/deblock.cpp
index de2d2b6..5f8b693 100644
--- a/media/libstagefright/codecs/avc/common/src/deblock.cpp
+++ b/media/libstagefright/codecs/avc/common/src/deblock.cpp
@@ -1279,7 +1279,7 @@
int C0, c0, dif, AbsDelta, Strng, tmp, tmp1;
int L2 = 0, L1, L0, R0, R1, R2 = 0;
uint8 *ptr, *ptr1;
- register uint R_in, L_in;
+ uint R_in, L_in;
uint R_out, L_out;
diff --git a/media/libstagefright/codecs/avc/enc/Android.mk b/media/libstagefright/codecs/avc/enc/Android.mk
index 537ba42..2ceebc8 100644
--- a/media/libstagefright/codecs/avc/enc/Android.mk
+++ b/media/libstagefright/codecs/avc/enc/Android.mk
@@ -28,7 +28,7 @@
$(TOP)/frameworks/native/include/media/openmax
LOCAL_CFLAGS := \
- -DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF=
+ -DOSCL_IMPORT_REF= -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_EXPORT_REF=
LOCAL_CFLAGS += -Werror
@@ -51,7 +51,7 @@
$(LOCAL_PATH)/../common
LOCAL_CFLAGS := \
- -DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF=
+ -DOSCL_IMPORT_REF= -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_EXPORT_REF=
LOCAL_STATIC_LIBRARIES := \
diff --git a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp
index 24dfc29..928a74f 100644
--- a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp
+++ b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp
@@ -561,13 +561,6 @@
videoInput.coding_timestamp = (inHeader->nTimeStamp + 500) / 1000; // in ms
const uint8_t *inputData = NULL;
if (mInputDataIsMeta) {
- if (inHeader->nFilledLen != 8) {
- ALOGE("MetaData buffer is wrong size! "
- "(got %u bytes, expected 8)", inHeader->nFilledLen);
- mSignalledError = true;
- notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
- return;
- }
inputData =
extractGraphicBuffer(
mInputFrameData, (mWidth * mHeight * 3) >> 1,
diff --git a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.h b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.h
index f31c1f4..81de109 100644
--- a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.h
+++ b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.h
@@ -26,8 +26,6 @@
namespace android {
-struct MediaBuffer;
-
struct SoftAVCEncoder : public MediaBufferObserver,
public SoftVideoEncoderOMXComponent {
SoftAVCEncoder(
diff --git a/media/libstagefright/codecs/avc/enc/src/findhalfpel.cpp b/media/libstagefright/codecs/avc/enc/src/findhalfpel.cpp
index 38a2a15..0b8d9e2 100644
--- a/media/libstagefright/codecs/avc/enc/src/findhalfpel.cpp
+++ b/media/libstagefright/codecs/avc/enc/src/findhalfpel.cpp
@@ -151,8 +151,7 @@
uint8 tmp8;
int32 tmp32;
int16 tmp_horz[18*22], *dst_16, *src_16;
- register int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; // temp register
- int msk;
+ int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; // temp
int i, j;
/* first copy full-pel to the first array */
@@ -379,7 +378,6 @@
// one can just use the above code and change the for(i=2 to for(i=18
for (i = 16; i > 0; i -= 4)
{
- msk = 0;
for (j = 17; j > 0; j--)
{
a = *((uint32*)ref); /* load 4 bytes */
diff --git a/media/libstagefright/codecs/avc/enc/src/init.cpp b/media/libstagefright/codecs/avc/enc/src/init.cpp
index c258b57..6e1413a 100644
--- a/media/libstagefright/codecs/avc/enc/src/init.cpp
+++ b/media/libstagefright/codecs/avc/enc/src/init.cpp
@@ -177,10 +177,6 @@
seqParam->offset_for_non_ref_pic = extS->offset_for_non_ref_pic;
seqParam->offset_for_top_to_bottom_field = extS->offset_for_top_to_bottom_field;
seqParam->num_ref_frames_in_pic_order_cnt_cycle = extS->num_ref_frames_in_pic_order_cnt_cycle;
- if (extS->offset_for_ref_frame == NULL)
- {
- return AVCENC_ENCPARAM_MEM_FAIL;
- }
for (ii = 0; ii < (int) extS->num_ref_frames; ii++)
{
seqParam->offset_for_ref_frame[ii] = extS->offset_for_ref_frame[ii];
diff --git a/media/libstagefright/codecs/avc/enc/src/rate_control.cpp b/media/libstagefright/codecs/avc/enc/src/rate_control.cpp
index aa13873..09dcc28 100644
--- a/media/libstagefright/codecs/avc/enc/src/rate_control.cpp
+++ b/media/libstagefright/codecs/avc/enc/src/rate_control.cpp
@@ -171,7 +171,7 @@
AVCRateControl *rateCtrl = encvid->rateCtrl;
double L1, L2, L3, bpp;
int qp;
- int i, j;
+ int i;
rateCtrl->basicUnit = video->PicSizeInMbs;
diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
index 1301060..9edffd2 100644
--- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
+++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
@@ -421,7 +421,6 @@
}
FLAC__bool ok = true;
- FLAC__StreamEncoderInitStatus initStatus = FLAC__STREAM_ENCODER_INIT_STATUS_OK;
ok = ok && FLAC__stream_encoder_set_channels(mFlacStreamEncoder, mNumChannels);
ok = ok && FLAC__stream_encoder_set_sample_rate(mFlacStreamEncoder, mSampleRate);
ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, 16);
diff --git a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
index 4debc48..bd01a1a 100644
--- a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
+++ b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
@@ -34,6 +34,9 @@
params->nVersion.s.nStep = 0;
}
+// Microsoft WAV GSM encoding packs two GSM frames into 65 bytes.
+static const int kMSGSMFrameSize = 65;
+
SoftGSM::SoftGSM(
const char *name,
const OMX_CALLBACKTYPE *callbacks,
@@ -64,7 +67,7 @@
def.eDir = OMX_DirInput;
def.nBufferCountMin = kNumBuffers;
def.nBufferCountActual = def.nBufferCountMin;
- def.nBufferSize = sizeof(gsm_frame);
+ def.nBufferSize = 1024 / kMSGSMFrameSize * kMSGSMFrameSize;
def.bEnabled = OMX_TRUE;
def.bPopulated = OMX_FALSE;
def.eDomain = OMX_PortDomainAudio;
@@ -207,8 +210,8 @@
mSignalledError = true;
}
- if(((inHeader->nFilledLen / 65) * 65) != inHeader->nFilledLen) {
- ALOGE("input buffer not multiple of 65 (%d).", inHeader->nFilledLen);
+ if(((inHeader->nFilledLen / kMSGSMFrameSize) * kMSGSMFrameSize) != inHeader->nFilledLen) {
+ ALOGE("input buffer not multiple of %d (%d).", kMSGSMFrameSize, inHeader->nFilledLen);
notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
mSignalledError = true;
}
@@ -258,6 +261,25 @@
return ret;
}
+void SoftGSM::onPortFlushCompleted(OMX_U32 portIndex) {
+ if (portIndex == 0) {
+ gsm_destroy(mGsm);
+ mGsm = gsm_create();
+ int msopt = 1;
+ gsm_option(mGsm, GSM_OPT_WAV49, &msopt);
+ }
+}
+
+void SoftGSM::onReset() {
+ gsm_destroy(mGsm);
+ mGsm = gsm_create();
+ int msopt = 1;
+ gsm_option(mGsm, GSM_OPT_WAV49, &msopt);
+ mSignalledError = false;
+}
+
+
+
} // namespace android
diff --git a/media/libstagefright/codecs/gsm/dec/SoftGSM.h b/media/libstagefright/codecs/gsm/dec/SoftGSM.h
index 8ab6116..0303dea 100644
--- a/media/libstagefright/codecs/gsm/dec/SoftGSM.h
+++ b/media/libstagefright/codecs/gsm/dec/SoftGSM.h
@@ -43,6 +43,9 @@
virtual void onQueueFilled(OMX_U32 portIndex);
+ virtual void onPortFlushCompleted(OMX_U32 portIndex);
+ virtual void onReset();
+
private:
enum {
kNumBuffers = 4,
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/find_min_max.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/find_min_max.cpp
index a357ea6..1ac88a1 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/find_min_max.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/find_min_max.cpp
@@ -138,8 +138,8 @@
/*----------------------------------------------------------------------------
; Define all local variables
----------------------------------------------------------------------------*/
- register uint i, j;
- register int min, max;
+ uint i, j;
+ int min, max;
/*----------------------------------------------------------------------------
; Function body here
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.mk b/media/libstagefright/codecs/m4v_h263/enc/Android.mk
index c9006d9..7117692 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/Android.mk
+++ b/media/libstagefright/codecs/m4v_h263/enc/Android.mk
@@ -25,7 +25,7 @@
LOCAL_CFLAGS := \
-DBX_RC \
- -DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF=
+ -DOSCL_IMPORT_REF= -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_EXPORT_REF=
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/src \
@@ -55,7 +55,7 @@
LOCAL_CFLAGS := \
-DBX_RC \
- -DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF=
+ -DOSCL_IMPORT_REF= -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_EXPORT_REF=
LOCAL_STATIC_LIBRARIES := \
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
index fa3486c..8240f83 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
@@ -413,13 +413,6 @@
if (inHeader->nFilledLen > 0) {
const uint8_t *inputData = NULL;
if (mInputDataIsMeta) {
- if (inHeader->nFilledLen != 8) {
- ALOGE("MetaData buffer is wrong size! "
- "(got %u bytes, expected 8)", inHeader->nFilledLen);
- mSignalledError = true;
- notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
- return;
- }
inputData =
extractGraphicBuffer(
mInputFrameData, (mWidth * mHeight * 3) >> 1,
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
index 25ecdc9..3389c37 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
@@ -26,7 +26,6 @@
namespace android {
struct CodecProfileLevel;
-struct MediaBuffer;
struct SoftMPEG4Encoder : public SoftVideoEncoderOMXComponent {
SoftMPEG4Encoder(
diff --git a/media/libstagefright/codecs/m4v_h263/enc/src/dct.cpp b/media/libstagefright/codecs/m4v_h263/enc/src/dct.cpp
index fa4ae23..8d7d9f1 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/src/dct.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/src/dct.cpp
@@ -267,7 +267,7 @@
Void Block4x4DCT_AANwSub(Short *out, UChar *cur, UChar *pred, Int width)
{
Short *dst;
- register Int k0, k1, k2, k3, k4, k5, k6, k7;
+ Int k0, k1, k2, k3, k4, k5, k6, k7;
Int round;
Int k12 = 0x022A02D4;
Int k14 = 0x0188053A;
@@ -473,7 +473,7 @@
Void Block2x2DCT_AANwSub(Short *out, UChar *cur, UChar *pred, Int width)
{
Short *dst;
- register Int k0, k1, k2, k3, k4, k5, k6, k7;
+ Int k0, k1, k2, k3, k4, k5, k6, k7;
Int round;
Int k12 = 0x022A02D4;
Int k14 = 0x018803B2;
@@ -863,7 +863,7 @@
Void Block4x4DCT_AANIntra(Short *out, UChar *cur, UChar *dummy2, Int width)
{
Short *dst;
- register Int k0, k1, k2, k3, k4, k5, k6, k7;
+ Int k0, k1, k2, k3, k4, k5, k6, k7;
Int round;
Int k12 = 0x022A02D4;
Int k14 = 0x0188053A;
@@ -1050,7 +1050,7 @@
Void Block2x2DCT_AANIntra(Short *out, UChar *cur, UChar *dummy2, Int width)
{
Short *dst;
- register Int k0, k1, k2, k3, k4, k5, k6, k7;
+ Int k0, k1, k2, k3, k4, k5, k6, k7;
Int round;
Int k12 = 0x022A02D4;
Int k14 = 0x018803B2;
diff --git a/media/libstagefright/codecs/m4v_h263/enc/src/vlc_encode.cpp b/media/libstagefright/codecs/m4v_h263/enc/src/vlc_encode.cpp
index 7ea5dc4..2aec815 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/src/vlc_encode.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/src/vlc_encode.cpp
@@ -271,7 +271,7 @@
Int ind;
Int length;
- if ((intra == 0))
+ if (intra == 0)
cbpy = 15 - cbpy;
ind = cbpy;
diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk
index 8284490..948ae29 100644
--- a/media/libstagefright/codecs/mp3dec/Android.mk
+++ b/media/libstagefright/codecs/mp3dec/Android.mk
@@ -48,7 +48,7 @@
$(LOCAL_PATH)/include
LOCAL_CFLAGS := \
- -DOSCL_UNUSED_ARG=
+ -D"OSCL_UNUSED_ARG(x)=(void)(x)"
LOCAL_CFLAGS += -Werror
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
index 8a95643..6e6a78a 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
@@ -38,7 +38,10 @@
NULL /* profileLevels */, 0 /* numProfileLevels */,
320 /* width */, 240 /* height */, callbacks, appData, component),
mMode(codingType == OMX_VIDEO_CodingVP8 ? MODE_VP8 : MODE_VP9),
+ mEOSStatus(INPUT_DATA_AVAILABLE),
mCtx(NULL),
+ mFrameParallelMode(false),
+ mTimeStampIdx(0),
mImg(NULL) {
// arbitrary from avc/hevc as vpx does not specify a min compression ratio
const size_t kMinCompressionRatio = mMode == MODE_VP8 ? 2 : 4;
@@ -51,9 +54,7 @@
}
SoftVPX::~SoftVPX() {
- vpx_codec_destroy((vpx_codec_ctx_t *)mCtx);
- delete (vpx_codec_ctx_t *)mCtx;
- mCtx = NULL;
+ destroyDecoder();
}
static int GetCPUCoreCount() {
@@ -73,12 +74,19 @@
mCtx = new vpx_codec_ctx_t;
vpx_codec_err_t vpx_err;
vpx_codec_dec_cfg_t cfg;
+ vpx_codec_flags_t flags;
memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t));
+ memset(&flags, 0, sizeof(vpx_codec_flags_t));
cfg.threads = GetCPUCoreCount();
+
+ if (mFrameParallelMode) {
+ flags |= VPX_CODEC_USE_FRAME_THREADING;
+ }
+
if ((vpx_err = vpx_codec_dec_init(
(vpx_codec_ctx_t *)mCtx,
mMode == MODE_VP8 ? &vpx_codec_vp8_dx_algo : &vpx_codec_vp9_dx_algo,
- &cfg, 0))) {
+ &cfg, flags))) {
ALOGE("on2 decoder failed to initialize. (%d)", vpx_err);
return UNKNOWN_ERROR;
}
@@ -86,86 +94,155 @@
return OK;
}
+status_t SoftVPX::destroyDecoder() {
+ vpx_codec_destroy((vpx_codec_ctx_t *)mCtx);
+ delete (vpx_codec_ctx_t *)mCtx;
+ mCtx = NULL;
+ return OK;
+}
+
+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;
+ vpx_codec_iter_t iter = NULL;
+
+ if (flushDecoder && mFrameParallelMode) {
+ // Flush decoder by passing NULL data ptr and 0 size.
+ // Ideally, this should never fail.
+ if (vpx_codec_decode((vpx_codec_ctx_t *)mCtx, NULL, 0, NULL, 0)) {
+ ALOGE("Failed to flush on2 decoder.");
+ return false;
+ }
+ }
+
+ if (!display) {
+ if (!flushDecoder) {
+ ALOGE("Invalid operation.");
+ return false;
+ }
+ // Drop all the decoded frames in decoder.
+ while ((mImg = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter))) {
+ }
+ return true;
+ }
+
+ while (!outQueue.empty()) {
+ if (mImg == NULL) {
+ mImg = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter);
+ if (mImg == NULL) {
+ break;
+ }
+ }
+ uint32_t width = mImg->d_w;
+ uint32_t height = mImg->d_h;
+ outInfo = *outQueue.begin();
+ outHeader = outInfo->mHeader;
+ CHECK_EQ(mImg->fmt, IMG_FMT_I420);
+ handlePortSettingsChange(portWillReset, width, height);
+ if (*portWillReset) {
+ return true;
+ }
+
+ outHeader->nOffset = 0;
+ outHeader->nFilledLen = (width * height * 3) / 2;
+ outHeader->nFlags = 0;
+ outHeader->nTimeStamp = *(OMX_TICKS *)mImg->user_priv;
+
+ uint8_t *dst = outHeader->pBuffer;
+ const uint8_t *srcY = (const uint8_t *)mImg->planes[PLANE_Y];
+ const uint8_t *srcU = (const uint8_t *)mImg->planes[PLANE_U];
+ const uint8_t *srcV = (const uint8_t *)mImg->planes[PLANE_V];
+ size_t srcYStride = mImg->stride[PLANE_Y];
+ size_t srcUStride = mImg->stride[PLANE_U];
+ size_t srcVStride = mImg->stride[PLANE_V];
+ copyYV12FrameToOutputBuffer(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride);
+
+ mImg = NULL;
+ outInfo->mOwnedByUs = false;
+ outQueue.erase(outQueue.begin());
+ outInfo = NULL;
+ notifyFillBufferDone(outHeader);
+ outHeader = NULL;
+ }
+
+ if (!eos) {
+ return true;
+ }
+
+ if (!outQueue.empty()) {
+ outInfo = *outQueue.begin();
+ outQueue.erase(outQueue.begin());
+ outHeader = outInfo->mHeader;
+ outHeader->nTimeStamp = 0;
+ outHeader->nFilledLen = 0;
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+ mEOSStatus = OUTPUT_FRAMES_FLUSHED;
+ }
+ return true;
+}
+
void SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) {
- if (mOutputPortSettingsChange != NONE) {
+ if (mOutputPortSettingsChange != NONE || mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
return;
}
List<BufferInfo *> &inQueue = getPortQueue(0);
List<BufferInfo *> &outQueue = getPortQueue(1);
bool EOSseen = false;
+ vpx_codec_err_t err;
+ bool portWillReset = false;
- while (!inQueue.empty() && !outQueue.empty()) {
- BufferInfo *inInfo = *inQueue.begin();
- OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
-
- BufferInfo *outInfo = *outQueue.begin();
- OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
-
- if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
- EOSseen = true;
- if (inHeader->nFilledLen == 0) {
- inQueue.erase(inQueue.begin());
- inInfo->mOwnedByUs = false;
- notifyEmptyBufferDone(inHeader);
-
- outHeader->nFilledLen = 0;
- outHeader->nFlags = OMX_BUFFERFLAG_EOS;
-
- outQueue.erase(outQueue.begin());
- outInfo->mOwnedByUs = false;
- notifyFillBufferDone(outHeader);
- return;
- }
- }
-
- if (mImg == NULL) {
- if (vpx_codec_decode(
- (vpx_codec_ctx_t *)mCtx,
- inHeader->pBuffer + inHeader->nOffset,
- inHeader->nFilledLen,
- NULL,
- 0)) {
- ALOGE("on2 decoder failed to decode frame.");
-
+ while ((mEOSStatus == INPUT_EOS_SEEN || !inQueue.empty())
+ && !outQueue.empty()) {
+ // Output the pending frames that left from last port reset or decoder flush.
+ if (mEOSStatus == INPUT_EOS_SEEN || mImg != NULL) {
+ if (!outputBuffers(
+ mEOSStatus == INPUT_EOS_SEEN, true /* display */,
+ mEOSStatus == INPUT_EOS_SEEN, &portWillReset)) {
+ ALOGE("on2 decoder failed to output frame.");
notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
return;
}
- vpx_codec_iter_t iter = NULL;
- mImg = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter);
- }
-
- if (mImg != NULL) {
- CHECK_EQ(mImg->fmt, IMG_FMT_I420);
-
- uint32_t width = mImg->d_w;
- uint32_t height = mImg->d_h;
- bool portWillReset = false;
- handlePortSettingsChange(&portWillReset, width, height);
- if (portWillReset) {
+ if (portWillReset || mEOSStatus == OUTPUT_FRAMES_FLUSHED ||
+ mEOSStatus == INPUT_EOS_SEEN) {
return;
}
+ }
- outHeader->nOffset = 0;
- outHeader->nFilledLen = (width * height * 3) / 2;
- outHeader->nFlags = EOSseen ? OMX_BUFFERFLAG_EOS : 0;
- outHeader->nTimeStamp = inHeader->nTimeStamp;
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+ mTimeStamps[mTimeStampIdx] = inHeader->nTimeStamp;
- uint8_t *dst = outHeader->pBuffer;
- const uint8_t *srcY = (const uint8_t *)mImg->planes[PLANE_Y];
- const uint8_t *srcU = (const uint8_t *)mImg->planes[PLANE_U];
- const uint8_t *srcV = (const uint8_t *)mImg->planes[PLANE_V];
- size_t srcYStride = mImg->stride[PLANE_Y];
- size_t srcUStride = mImg->stride[PLANE_U];
- size_t srcVStride = mImg->stride[PLANE_V];
- copyYV12FrameToOutputBuffer(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride);
+ BufferInfo *outInfo = *outQueue.begin();
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ mEOSStatus = INPUT_EOS_SEEN;
+ EOSseen = true;
+ }
- mImg = NULL;
- outInfo->mOwnedByUs = false;
- outQueue.erase(outQueue.begin());
- outInfo = NULL;
- notifyFillBufferDone(outHeader);
- outHeader = NULL;
+ 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;
+ }
+ mTimeStampIdx = (mTimeStampIdx + 1) % kNumBuffers;
+
+ if (!outputBuffers(
+ EOSseen /* flushDecoder */, true /* display */, EOSseen, &portWillReset)) {
+ ALOGE("on2 decoder failed to output frame.");
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ return;
+ }
+ if (portWillReset) {
+ return;
}
inInfo->mOwnedByUs = false;
@@ -176,6 +253,30 @@
}
}
+void SoftVPX::onPortFlushCompleted(OMX_U32 portIndex) {
+ if (portIndex == kInputPortIndex) {
+ bool portWillReset = false;
+ if (!outputBuffers(
+ true /* flushDecoder */, false /* display */, false /* eos */, &portWillReset)) {
+ ALOGE("Failed to flush decoder.");
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ return;
+ }
+ mEOSStatus = INPUT_DATA_AVAILABLE;
+ }
+}
+
+void SoftVPX::onReset() {
+ bool portWillReset = false;
+ if (!outputBuffers(
+ true /* flushDecoder */, false /* display */, false /* eos */, &portWillReset)) {
+ ALOGW("Failed to flush decoder. Try to hard reset decoder");
+ destroyDecoder();
+ initDecoder();
+ }
+ mEOSStatus = INPUT_DATA_AVAILABLE;
+}
+
} // namespace android
android::SoftOMXComponent *createSoftOMXComponent(
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.h b/media/libstagefright/codecs/on2/dec/SoftVPX.h
index 8f68693..8ccbae2 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.h
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.h
@@ -38,6 +38,8 @@
virtual ~SoftVPX();
virtual void onQueueFilled(OMX_U32 portIndex);
+ virtual void onPortFlushCompleted(OMX_U32 portIndex);
+ virtual void onReset();
private:
enum {
@@ -49,11 +51,21 @@
MODE_VP9
} mMode;
- void *mCtx;
+ enum {
+ INPUT_DATA_AVAILABLE, // VPX component is ready to decode data.
+ INPUT_EOS_SEEN, // VPX component saw EOS and is flushing On2 decoder.
+ OUTPUT_FRAMES_FLUSHED // VPX component finished flushing On2 decoder.
+ } mEOSStatus;
+ void *mCtx;
+ bool mFrameParallelMode; // Frame parallel is only supported by VP9 decoder.
+ OMX_TICKS mTimeStamps[kNumBuffers];
+ uint8_t mTimeStampIdx;
vpx_image_t *mImg;
status_t initDecoder();
+ status_t destroyDecoder();
+ bool outputBuffers(bool flushDecoder, bool display, bool eos, bool *portWillReset);
DISALLOW_EVIL_CONSTRUCTORS(SoftVPX);
};
diff --git a/media/libstagefright/codecs/on2/enc/Android.mk b/media/libstagefright/codecs/on2/enc/Android.mk
index e265104..253fa04 100644
--- a/media/libstagefright/codecs/on2/enc/Android.mk
+++ b/media/libstagefright/codecs/on2/enc/Android.mk
@@ -6,7 +6,6 @@
LOCAL_C_INCLUDES := \
$(TOP)/external/libvpx/libvpx \
- $(TOP)/external/openssl/include \
$(TOP)/external/libvpx/libvpx/vpx_codec \
$(TOP)/external/libvpx/libvpx/vpx_ports \
frameworks/av/media/libstagefright/include \
diff --git a/media/libstagefright/codecs/on2/h264dec/Android.mk b/media/libstagefright/codecs/on2/h264dec/Android.mk
index bf03ad9..e63b6b1 100644
--- a/media/libstagefright/codecs/on2/h264dec/Android.mk
+++ b/media/libstagefright/codecs/on2/h264dec/Android.mk
@@ -94,6 +94,8 @@
LOCAL_C_INCLUDES += $(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
diff --git a/media/libstagefright/codecs/on2/h264dec/inc/H264SwDecApi.h b/media/libstagefright/codecs/on2/h264dec/inc/H264SwDecApi.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/inc/basetype.h b/media/libstagefright/codecs/on2/h264dec/inc/basetype.h
old mode 100755
new mode 100644
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
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM_BitDec_s.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM_BitDec_s.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM_Bitstream.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM_Bitstream.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM_IDCTTable.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM_IDCTTable.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM_IDCT_s.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM_IDCT_s.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM_MaskTable.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM_MaskTable.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM_Version.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM_Version.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM_s.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM_s.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armOMX.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armOMX.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/omxtypes.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/omxtypes.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/omxtypes_s.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/omxtypes_s.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/src/armCOMM.c b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/src/armCOMM.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/src/armCOMM_Bitstream.c b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/src/armCOMM_Bitstream.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/src/armCOMM_IDCTTable.c b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/src/armCOMM_IDCTTable.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/src/armCOMM_MaskTable.c b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/src/armCOMM_MaskTable.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/api/armVC.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/api/armVC.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/api/armVCCOMM_s.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/api/armVCCOMM_s.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/api/omxVC.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/api/omxVC.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/api/omxVC_s.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/api/omxVC_s.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/api/armVCM4P10_CAVLCTables.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/api/armVCM4P10_CAVLCTables.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src/armVCM4P10_CAVLCTables.c b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src/armVCM4P10_CAVLCTables.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DeblockChroma_I.c b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DeblockChroma_I.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DeblockLuma_I.c b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DeblockLuma_I.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DecodeChromaDcCoeffsToPairCAVLC.c b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DecodeChromaDcCoeffsToPairCAVLC.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DecodeCoeffsToPairCAVLC.c b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DecodeCoeffsToPairCAVLC.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_InterpolateChroma.c b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_InterpolateChroma.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p2/api/armVCM4P2_Huff_Tables_VLC.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p2/api/armVCM4P2_Huff_Tables_VLC.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p2/api/armVCM4P2_ZigZag_Tables.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p2/api/armVCM4P2_ZigZag_Tables.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p2/src/armVCM4P2_Huff_Tables_VLC.c b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p2/src/armVCM4P2_Huff_Tables_VLC.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p2/src/armVCM4P2_Lookup_Tables.c b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p2/src/armVCM4P2_Lookup_Tables.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p2/src/armVCM4P2_Zigzag_Tables.c b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p2/src/armVCM4P2_Zigzag_Tables.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p2/src/omxVCM4P2_DecodeBlockCoef_Inter.c b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p2/src/omxVCM4P2_DecodeBlockCoef_Inter.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p2/src/omxVCM4P2_DecodeBlockCoef_Intra.c b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p2/src/omxVCM4P2_DecodeBlockCoef_Intra.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/src/armVC_Version.c b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/src/armVC_Version.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/DecTestBench.c b/media/libstagefright/codecs/on2/h264dec/source/DecTestBench.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/EvaluationTestBench.c b/media/libstagefright/codecs/on2/h264dec/source/EvaluationTestBench.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/H264SwDecApi.c b/media/libstagefright/codecs/on2/h264dec/source/H264SwDecApi.c
index 524a3f0..a073dcb 100644
--- a/media/libstagefright/codecs/on2/h264dec/source/H264SwDecApi.c
+++ b/media/libstagefright/codecs/on2/h264dec/source/H264SwDecApi.c
@@ -36,6 +36,7 @@
1. Include headers
------------------------------------------------------------------------------*/
#include <stdlib.h>
+#include <string.h>
#include "basetype.h"
#include "h264bsd_container.h"
#include "H264SwDecApi.h"
diff --git a/media/libstagefright/codecs/on2/h264dec/source/TestBenchMultipleInstance.c b/media/libstagefright/codecs/on2/h264dec/source/TestBenchMultipleInstance.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_byte_stream.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_byte_stream.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_byte_stream.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_byte_stream.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_cavlc.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_cavlc.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_cavlc.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_cavlc.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_cfg.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_cfg.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_conceal.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_conceal.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_conceal.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_conceal.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_container.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_container.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_deblocking.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_deblocking.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_deblocking.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_deblocking.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_dpb.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_dpb.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_dpb.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_dpb.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_image.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_image.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_image.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_image.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_inter_prediction.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_inter_prediction.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_inter_prediction.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_inter_prediction.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_intra_prediction.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_intra_prediction.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_intra_prediction.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_intra_prediction.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_macroblock_layer.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_macroblock_layer.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_macroblock_layer.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_macroblock_layer.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_nal_unit.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_nal_unit.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_nal_unit.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_nal_unit.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_neighbour.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_neighbour.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_neighbour.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_neighbour.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_pic_order_cnt.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_pic_order_cnt.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_pic_order_cnt.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_pic_order_cnt.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_pic_param_set.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_pic_param_set.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_pic_param_set.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_pic_param_set.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_reconstruct.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_reconstruct.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_reconstruct.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_reconstruct.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_sei.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_sei.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_sei.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_sei.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_seq_param_set.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_seq_param_set.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_data.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_data.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_data.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_data.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_group_map.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_group_map.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_group_map.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_group_map.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_header.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_header.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_header.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_header.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_storage.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_storage.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_storage.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_storage.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_stream.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_stream.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_stream.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_stream.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_transform.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_transform.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_transform.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_transform.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_util.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_util.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_util.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_util.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_vlc.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_vlc.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_vlc.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_vlc.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_vui.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_vui.c
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_vui.h b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_vui.h
old mode 100755
new mode 100644
diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
index b8084ae..6322dc2 100644
--- a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
+++ b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
@@ -345,9 +345,15 @@
}
uint8_t channel_mapping[kMaxChannels] = {0};
- memcpy(&channel_mapping,
- kDefaultOpusChannelLayout,
- kMaxChannelsWithDefaultLayout);
+ if (mHeader->channels <= kMaxChannelsWithDefaultLayout) {
+ memcpy(&channel_mapping,
+ kDefaultOpusChannelLayout,
+ kMaxChannelsWithDefaultLayout);
+ } else {
+ memcpy(&channel_mapping,
+ mHeader->stream_map,
+ mHeader->channels);
+ }
int status = OPUS_INVALID_STATE;
mDecoder = opus_multistream_decoder_create(kRate,
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 4e75250..21da707 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -98,33 +98,49 @@
mCropWidth = mCropRight - mCropLeft + 1;
mCropHeight = mCropBottom - mCropTop + 1;
- int halFormat;
- size_t bufWidth, bufHeight;
+ // by default convert everything to RGB565
+ int halFormat = HAL_PIXEL_FORMAT_RGB_565;
+ size_t bufWidth = mCropWidth;
+ size_t bufHeight = mCropHeight;
- switch (mColorFormat) {
- case OMX_COLOR_FormatYUV420Planar:
- case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
- case OMX_COLOR_FormatYUV420SemiPlanar:
- {
- if (!runningInEmulator()) {
+ // hardware has YUV12 and RGBA8888 support, so convert known formats
+ if (!runningInEmulator()) {
+ switch (mColorFormat) {
+ case OMX_COLOR_FormatYUV420Planar:
+ case OMX_COLOR_FormatYUV420SemiPlanar:
+ case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
+ {
halFormat = HAL_PIXEL_FORMAT_YV12;
bufWidth = (mCropWidth + 1) & ~1;
bufHeight = (mCropHeight + 1) & ~1;
break;
}
-
- // fall through.
+ case OMX_COLOR_Format24bitRGB888:
+ {
+ halFormat = HAL_PIXEL_FORMAT_RGB_888;
+ bufWidth = (mCropWidth + 1) & ~1;
+ bufHeight = (mCropHeight + 1) & ~1;
+ break;
+ }
+ case OMX_COLOR_Format32bitARGB8888:
+ case OMX_COLOR_Format32BitRGBA8888:
+ {
+ halFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+ bufWidth = (mCropWidth + 1) & ~1;
+ bufHeight = (mCropHeight + 1) & ~1;
+ break;
+ }
+ default:
+ {
+ break;
+ }
}
+ }
- default:
- halFormat = HAL_PIXEL_FORMAT_RGB_565;
- bufWidth = mCropWidth;
- bufHeight = mCropHeight;
-
- mConverter = new ColorConverter(
- mColorFormat, OMX_COLOR_Format16bitRGB565);
- CHECK(mConverter->isValid());
- break;
+ if (halFormat == HAL_PIXEL_FORMAT_RGB_565) {
+ mConverter = new ColorConverter(
+ mColorFormat, OMX_COLOR_Format16bitRGB565);
+ CHECK(mConverter->isValid());
}
CHECK(mNativeWindow != NULL);
@@ -201,6 +217,8 @@
CHECK_EQ(0, mapper.lock(
buf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst));
+ // TODO move the other conversions also into ColorConverter, and
+ // fix cropping issues (when mCropLeft/Top != 0 or mWidth != mCropWidth)
if (mConverter) {
mConverter->convert(
data,
@@ -211,7 +229,8 @@
0, 0, mCropWidth - 1, mCropHeight - 1);
} else if (mColorFormat == OMX_COLOR_FormatYUV420Planar) {
const uint8_t *src_y = (const uint8_t *)data;
- const uint8_t *src_u = (const uint8_t *)data + mWidth * mHeight;
+ const uint8_t *src_u =
+ (const uint8_t *)data + mWidth * mHeight;
const uint8_t *src_v = src_u + (mWidth / 2 * mHeight / 2);
uint8_t *dst_y = (uint8_t *)dst;
@@ -239,11 +258,9 @@
}
} else if (mColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar
|| mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
- const uint8_t *src_y =
- (const uint8_t *)data;
-
- const uint8_t *src_uv =
- (const uint8_t *)data + mWidth * (mHeight - mCropTop / 2);
+ const uint8_t *src_y = (const uint8_t *)data;
+ const uint8_t *src_uv = (const uint8_t *)data
+ + mWidth * (mHeight - mCropTop / 2);
uint8_t *dst_y = (uint8_t *)dst;
@@ -271,6 +288,38 @@
dst_u += dst_c_stride;
dst_v += dst_c_stride;
}
+ } else if (mColorFormat == OMX_COLOR_Format24bitRGB888) {
+ uint8_t* srcPtr = (uint8_t*)data;
+ uint8_t* dstPtr = (uint8_t*)dst;
+
+ for (size_t y = 0; y < (size_t)mCropHeight; ++y) {
+ memcpy(dstPtr, srcPtr, mCropWidth * 3);
+ srcPtr += mWidth * 3;
+ dstPtr += buf->stride * 3;
+ }
+ } else if (mColorFormat == OMX_COLOR_Format32bitARGB8888) {
+ uint8_t *srcPtr, *dstPtr;
+
+ for (size_t y = 0; y < (size_t)mCropHeight; ++y) {
+ srcPtr = (uint8_t*)data + mWidth * 4 * y;
+ dstPtr = (uint8_t*)dst + buf->stride * 4 * y;
+ for (size_t x = 0; x < (size_t)mCropWidth; ++x) {
+ uint8_t a = *srcPtr++;
+ for (size_t i = 0; i < 3; ++i) { // copy RGB
+ *dstPtr++ = *srcPtr++;
+ }
+ *dstPtr++ = a; // alpha last (ARGB to RGBA)
+ }
+ }
+ } else if (mColorFormat == OMX_COLOR_Format32BitRGBA8888) {
+ uint8_t* srcPtr = (uint8_t*)data;
+ uint8_t* dstPtr = (uint8_t*)dst;
+
+ for (size_t y = 0; y < (size_t)mCropHeight; ++y) {
+ memcpy(dstPtr, srcPtr, mCropWidth * 4);
+ srcPtr += mWidth * 4;
+ dstPtr += buf->stride * 4;
+ }
} else {
LOG_ALWAYS_FATAL("bad color format %#x", mColorFormat);
}
diff --git a/media/libstagefright/filters/Android.mk b/media/libstagefright/filters/Android.mk
new file mode 100644
index 0000000..36ab444
--- /dev/null
+++ b/media/libstagefright/filters/Android.mk
@@ -0,0 +1,27 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ ColorConvert.cpp \
+ GraphicBufferListener.cpp \
+ IntrinsicBlurFilter.cpp \
+ MediaFilter.cpp \
+ RSFilter.cpp \
+ SaturationFilter.cpp \
+ saturationARGB.rs \
+ SimpleFilter.cpp \
+ ZeroFilter.cpp
+
+LOCAL_C_INCLUDES := \
+ $(TOP)/frameworks/native/include/media/openmax \
+ $(TOP)/frameworks/rs/cpp \
+ $(TOP)/frameworks/rs \
+
+intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
+LOCAL_C_INCLUDES += $(intermediates)
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE:= libstagefright_mediafilter
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/filters/ColorConvert.cpp b/media/libstagefright/filters/ColorConvert.cpp
new file mode 100644
index 0000000..a5039f9
--- /dev/null
+++ b/media/libstagefright/filters/ColorConvert.cpp
@@ -0,0 +1,111 @@
+/*
+ * 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 "ColorConvert.h"
+
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+namespace android {
+
+void YUVToRGB(
+ int32_t y, int32_t u, int32_t v,
+ int32_t* r, int32_t* g, int32_t* b) {
+ y -= 16;
+ u -= 128;
+ v -= 128;
+
+ *b = 1192 * y + 2066 * u;
+ *g = 1192 * y - 833 * v - 400 * u;
+ *r = 1192 * y + 1634 * v;
+
+ *r = min(262143, max(0, *r));
+ *g = min(262143, max(0, *g));
+ *b = min(262143, max(0, *b));
+
+ *r >>= 10;
+ *g >>= 10;
+ *b >>= 10;
+}
+
+void convertYUV420spToARGB(
+ uint8_t *pY, uint8_t *pUV, int32_t width, int32_t height,
+ uint8_t *dest) {
+ const int32_t bytes_per_pixel = 2;
+
+ for (int32_t i = 0; i < height; i++) {
+ for (int32_t j = 0; j < width; j++) {
+ int32_t y = *(pY + i * width + j);
+ int32_t u = *(pUV + (i/2) * width + bytes_per_pixel * (j/2));
+ int32_t v = *(pUV + (i/2) * width + bytes_per_pixel * (j/2) + 1);
+
+ int32_t r, g, b;
+ YUVToRGB(y, u, v, &r, &g, &b);
+
+ *dest++ = 0xFF;
+ *dest++ = r;
+ *dest++ = g;
+ *dest++ = b;
+ }
+ }
+}
+
+void convertYUV420spToRGB888(
+ uint8_t *pY, uint8_t *pUV, int32_t width, int32_t height,
+ uint8_t *dest) {
+ const int32_t bytes_per_pixel = 2;
+
+ for (int32_t i = 0; i < height; i++) {
+ for (int32_t j = 0; j < width; j++) {
+ int32_t y = *(pY + i * width + j);
+ int32_t u = *(pUV + (i/2) * width + bytes_per_pixel * (j/2));
+ int32_t v = *(pUV + (i/2) * width + bytes_per_pixel * (j/2) + 1);
+
+ int32_t r, g, b;
+ YUVToRGB(y, u, v, &r, &g, &b);
+
+ *dest++ = r;
+ *dest++ = g;
+ *dest++ = b;
+ }
+ }
+}
+
+// HACK - not even slightly optimized
+// TODO: remove when RGBA support is added to SoftwareRenderer
+void convertRGBAToARGB(
+ uint8_t *src, int32_t width, int32_t height, uint32_t stride,
+ uint8_t *dest) {
+ for (size_t i = 0; i < height; ++i) {
+ for (size_t j = 0; j < width; ++j) {
+ uint8_t r = *src++;
+ uint8_t g = *src++;
+ uint8_t b = *src++;
+ uint8_t a = *src++;
+ *dest++ = a;
+ *dest++ = r;
+ *dest++ = g;
+ *dest++ = b;
+ }
+ src += (stride - width) * 4;
+ }
+}
+
+} // namespace android
diff --git a/media/libstagefright/filters/ColorConvert.h b/media/libstagefright/filters/ColorConvert.h
new file mode 100644
index 0000000..13faa02
--- /dev/null
+++ b/media/libstagefright/filters/ColorConvert.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#ifndef COLOR_CONVERT_H_
+#define COLOR_CONVERT_H_
+
+#include <inttypes.h>
+
+namespace android {
+
+void YUVToRGB(
+ int32_t y, int32_t u, int32_t v,
+ int32_t* r, int32_t* g, int32_t* b);
+
+void convertYUV420spToARGB(
+ uint8_t *pY, uint8_t *pUV, int32_t width, int32_t height,
+ uint8_t *dest);
+
+void convertYUV420spToRGB888(
+ uint8_t *pY, uint8_t *pUV, int32_t width, int32_t height,
+ uint8_t *dest);
+
+// TODO: remove when RGBA support is added to SoftwareRenderer
+void convertRGBAToARGB(
+ uint8_t *src, int32_t width, int32_t height, uint32_t stride,
+ uint8_t *dest);
+
+} // namespace android
+
+#endif // COLOR_CONVERT_H_
diff --git a/media/libstagefright/filters/GraphicBufferListener.cpp b/media/libstagefright/filters/GraphicBufferListener.cpp
new file mode 100644
index 0000000..fa38192
--- /dev/null
+++ b/media/libstagefright/filters/GraphicBufferListener.cpp
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "GraphicBufferListener"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaErrors.h>
+
+#include "GraphicBufferListener.h"
+
+namespace android {
+
+status_t GraphicBufferListener::init(
+ const sp<AMessage> ¬ify,
+ size_t bufferWidth, size_t bufferHeight, size_t bufferCount) {
+ mNotify = notify;
+
+ String8 name("GraphicBufferListener");
+ BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+ mConsumer->setConsumerName(name);
+ mConsumer->setDefaultBufferSize(bufferWidth, bufferHeight);
+ mConsumer->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN);
+
+ status_t err = mConsumer->setMaxAcquiredBufferCount(bufferCount);
+ if (err != NO_ERROR) {
+ ALOGE("Unable to set BQ max acquired buffer count to %u: %d",
+ bufferCount, err);
+ return err;
+ }
+
+ wp<BufferQueue::ConsumerListener> listener =
+ static_cast<BufferQueue::ConsumerListener*>(this);
+ sp<BufferQueue::ProxyConsumerListener> proxy =
+ new BufferQueue::ProxyConsumerListener(listener);
+
+ err = mConsumer->consumerConnect(proxy, false);
+ if (err != NO_ERROR) {
+ ALOGE("Error connecting to BufferQueue: %s (%d)",
+ strerror(-err), err);
+ return err;
+ }
+
+ ALOGV("init() successful.");
+
+ return OK;
+}
+
+void GraphicBufferListener::onFrameAvailable(const BufferItem& /* item */) {
+ ALOGV("onFrameAvailable() called");
+
+ {
+ Mutex::Autolock autoLock(mMutex);
+ mNumFramesAvailable++;
+ }
+
+ sp<AMessage> notify = mNotify->dup();
+ mNotify->setWhat(kWhatFrameAvailable);
+ mNotify->post();
+}
+
+void GraphicBufferListener::onBuffersReleased() {
+ ALOGV("onBuffersReleased() called");
+ // nothing to do
+}
+
+void GraphicBufferListener::onSidebandStreamChanged() {
+ ALOGW("GraphicBufferListener cannot consume sideband streams.");
+ // nothing to do
+}
+
+BufferQueue::BufferItem GraphicBufferListener::getBufferItem() {
+ BufferQueue::BufferItem item;
+
+ {
+ Mutex::Autolock autoLock(mMutex);
+ if (mNumFramesAvailable <= 0) {
+ ALOGE("getBuffer() called with no frames available");
+ return item;
+ }
+ mNumFramesAvailable--;
+ }
+
+ status_t err = mConsumer->acquireBuffer(&item, 0);
+ if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+ // shouldn't happen, since we track num frames available
+ ALOGE("frame was not available");
+ item.mBuf = -1;
+ return item;
+ } else if (err != OK) {
+ ALOGE("acquireBuffer returned err=%d", err);
+ item.mBuf = -1;
+ return item;
+ }
+
+ // Wait for it to become available.
+ err = item.mFence->waitForever("GraphicBufferListener::getBufferItem");
+ if (err != OK) {
+ ALOGW("failed to wait for buffer fence: %d", err);
+ // keep going
+ }
+
+ // 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;
+ }
+
+ return item;
+}
+
+sp<GraphicBuffer> GraphicBufferListener::getBuffer(
+ BufferQueue::BufferItem item) {
+ sp<GraphicBuffer> buf;
+ if (item.mBuf < 0 || item.mBuf >= BufferQueue::NUM_BUFFER_SLOTS) {
+ ALOGE("getBuffer() received invalid BufferItem: mBuf==%d", item.mBuf);
+ return buf;
+ }
+
+ buf = mBufferSlot[item.mBuf];
+ CHECK(buf.get() != NULL);
+
+ return buf;
+}
+
+status_t GraphicBufferListener::releaseBuffer(
+ BufferQueue::BufferItem item) {
+ if (item.mBuf < 0 || item.mBuf >= BufferQueue::NUM_BUFFER_SLOTS) {
+ ALOGE("getBuffer() received invalid BufferItem: mBuf==%d", item.mBuf);
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber,
+ EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
+
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libstagefright/filters/GraphicBufferListener.h b/media/libstagefright/filters/GraphicBufferListener.h
new file mode 100644
index 0000000..b3e0ee3
--- /dev/null
+++ b/media/libstagefright/filters/GraphicBufferListener.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#ifndef GRAPHIC_BUFFER_LISTENER_H_
+#define GRAPHIC_BUFFER_LISTENER_H_
+
+#include <gui/BufferQueue.h>
+
+namespace android {
+
+struct AMessage;
+
+struct GraphicBufferListener : public BufferQueue::ConsumerListener {
+public:
+ GraphicBufferListener() {};
+
+ status_t init(
+ const sp<AMessage> ¬ify,
+ size_t bufferWidth, size_t bufferHeight, size_t bufferCount);
+
+ virtual void onFrameAvailable(const BufferItem& item);
+ virtual void onBuffersReleased();
+ virtual void onSidebandStreamChanged();
+
+ // Returns the handle to the producer side of the BufferQueue. Buffers
+ // queued on this will be received by GraphicBufferListener.
+ sp<IGraphicBufferProducer> getIGraphicBufferProducer() const {
+ return mProducer;
+ }
+
+ BufferQueue::BufferItem getBufferItem();
+ sp<GraphicBuffer> getBuffer(BufferQueue::BufferItem item);
+ status_t releaseBuffer(BufferQueue::BufferItem item);
+
+ enum {
+ kWhatFrameAvailable = 'frav',
+ };
+
+private:
+ sp<AMessage> mNotify;
+ size_t mNumFramesAvailable;
+
+ mutable Mutex mMutex;
+
+ // Our BufferQueue interfaces. mProducer is passed to the producer through
+ // getIGraphicBufferProducer, and mConsumer is used internally to retrieve
+ // the buffers queued by the producer.
+ sp<IGraphicBufferProducer> mProducer;
+ sp<IGraphicBufferConsumer> mConsumer;
+
+ // Cache of GraphicBuffers from the buffer queue.
+ sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
+};
+
+} // namespace android
+
+#endif // GRAPHIC_BUFFER_LISTENER_H
diff --git a/media/libstagefright/filters/IntrinsicBlurFilter.cpp b/media/libstagefright/filters/IntrinsicBlurFilter.cpp
new file mode 100644
index 0000000..cbcf699
--- /dev/null
+++ b/media/libstagefright/filters/IntrinsicBlurFilter.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "IntrinsicBlurFilter"
+
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include "IntrinsicBlurFilter.h"
+
+namespace android {
+
+status_t IntrinsicBlurFilter::configure(const sp<AMessage> &msg) {
+ status_t err = SimpleFilter::configure(msg);
+ if (err != OK) {
+ return err;
+ }
+
+ if (!msg->findString("cacheDir", &mCacheDir)) {
+ ALOGE("Failed to find cache directory in config message.");
+ return NAME_NOT_FOUND;
+ }
+
+ return OK;
+}
+
+status_t IntrinsicBlurFilter::start() {
+ // TODO: use a single RS context object for entire application
+ mRS = new RSC::RS();
+
+ if (!mRS->init(mCacheDir.c_str())) {
+ ALOGE("Failed to initialize RenderScript context.");
+ return NO_INIT;
+ }
+
+ // 32-bit elements for ARGB8888
+ RSC::sp<const RSC::Element> e = RSC::Element::U8_4(mRS);
+
+ RSC::Type::Builder tb(mRS, e);
+ tb.setX(mWidth);
+ tb.setY(mHeight);
+ RSC::sp<const RSC::Type> t = tb.create();
+
+ mAllocIn = RSC::Allocation::createTyped(mRS, t);
+ mAllocOut = RSC::Allocation::createTyped(mRS, t);
+
+ mBlur = RSC::ScriptIntrinsicBlur::create(mRS, e);
+ mBlur->setRadius(mBlurRadius);
+ mBlur->setInput(mAllocIn);
+
+ return OK;
+}
+
+void IntrinsicBlurFilter::reset() {
+ mBlur.clear();
+ mAllocOut.clear();
+ mAllocIn.clear();
+ mRS.clear();
+}
+
+status_t IntrinsicBlurFilter::setParameters(const sp<AMessage> &msg) {
+ sp<AMessage> params;
+ CHECK(msg->findMessage("params", ¶ms));
+
+ float blurRadius;
+ if (params->findFloat("blur-radius", &blurRadius)) {
+ mBlurRadius = blurRadius;
+ }
+
+ return OK;
+}
+
+status_t IntrinsicBlurFilter::processBuffers(
+ const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer) {
+ mAllocIn->copy1DRangeFrom(0, mWidth * mHeight, srcBuffer->data());
+ mBlur->forEach(mAllocOut);
+ mAllocOut->copy1DRangeTo(0, mWidth * mHeight, outBuffer->data());
+
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libstagefright/filters/IntrinsicBlurFilter.h b/media/libstagefright/filters/IntrinsicBlurFilter.h
new file mode 100644
index 0000000..4707ab7
--- /dev/null
+++ b/media/libstagefright/filters/IntrinsicBlurFilter.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifndef INTRINSIC_BLUR_FILTER_H_
+#define INTRINSIC_BLUR_FILTER_H_
+
+#include "RenderScript.h"
+#include "SimpleFilter.h"
+
+namespace android {
+
+struct IntrinsicBlurFilter : public SimpleFilter {
+public:
+ IntrinsicBlurFilter() : mBlurRadius(1.f) {};
+
+ virtual status_t configure(const sp<AMessage> &msg);
+ virtual status_t start();
+ virtual void reset();
+ virtual status_t setParameters(const sp<AMessage> &msg);
+ virtual status_t processBuffers(
+ const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer);
+
+protected:
+ virtual ~IntrinsicBlurFilter() {};
+
+private:
+ AString mCacheDir;
+ RSC::sp<RSC::RS> mRS;
+ RSC::sp<RSC::Allocation> mAllocIn;
+ RSC::sp<RSC::Allocation> mAllocOut;
+ RSC::sp<RSC::ScriptIntrinsicBlur> mBlur;
+ float mBlurRadius;
+};
+
+} // namespace android
+
+#endif // INTRINSIC_BLUR_FILTER_H_
diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp
new file mode 100644
index 0000000..d2f662d
--- /dev/null
+++ b/media/libstagefright/filters/MediaFilter.cpp
@@ -0,0 +1,816 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaFilter"
+
+#include <inttypes.h>
+#include <utils/Trace.h>
+
+#include <binder/MemoryDealer.h>
+
+#include <media/stagefright/BufferProducerWrapper.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaFilter.h>
+
+#include "ColorConvert.h"
+#include "GraphicBufferListener.h"
+#include "IntrinsicBlurFilter.h"
+#include "RSFilter.h"
+#include "SaturationFilter.h"
+#include "ZeroFilter.h"
+
+namespace android {
+
+// parameter: number of input and output buffers
+static const size_t kBufferCountActual = 4;
+
+MediaFilter::MediaFilter()
+ : mState(UNINITIALIZED),
+ mGeneration(0),
+ mGraphicBufferListener(NULL) {
+}
+
+MediaFilter::~MediaFilter() {
+}
+
+//////////////////// PUBLIC FUNCTIONS //////////////////////////////////////////
+
+void MediaFilter::setNotificationMessage(const sp<AMessage> &msg) {
+ mNotify = msg;
+}
+
+void MediaFilter::initiateAllocateComponent(const sp<AMessage> &msg) {
+ msg->setWhat(kWhatAllocateComponent);
+ msg->setTarget(this);
+ msg->post();
+}
+
+void MediaFilter::initiateConfigureComponent(const sp<AMessage> &msg) {
+ msg->setWhat(kWhatConfigureComponent);
+ msg->setTarget(this);
+ msg->post();
+}
+
+void MediaFilter::initiateCreateInputSurface() {
+ (new AMessage(kWhatCreateInputSurface, this))->post();
+}
+
+void MediaFilter::initiateStart() {
+ (new AMessage(kWhatStart, this))->post();
+}
+
+void MediaFilter::initiateShutdown(bool keepComponentAllocated) {
+ sp<AMessage> msg = new AMessage(kWhatShutdown, this);
+ msg->setInt32("keepComponentAllocated", keepComponentAllocated);
+ msg->post();
+}
+
+void MediaFilter::signalFlush() {
+ (new AMessage(kWhatFlush, this))->post();
+}
+
+void MediaFilter::signalResume() {
+ (new AMessage(kWhatResume, this))->post();
+}
+
+// nothing to do
+void MediaFilter::signalRequestIDRFrame() {
+ return;
+}
+
+void MediaFilter::signalSetParameters(const sp<AMessage> ¶ms) {
+ sp<AMessage> msg = new AMessage(kWhatSetParameters, this);
+ msg->setMessage("params", params);
+ msg->post();
+}
+
+void MediaFilter::signalEndOfInputStream() {
+ (new AMessage(kWhatSignalEndOfInputStream, this))->post();
+}
+
+void MediaFilter::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatAllocateComponent:
+ {
+ onAllocateComponent(msg);
+ break;
+ }
+ case kWhatConfigureComponent:
+ {
+ onConfigureComponent(msg);
+ break;
+ }
+ case kWhatStart:
+ {
+ onStart();
+ break;
+ }
+ case kWhatProcessBuffers:
+ {
+ processBuffers();
+ break;
+ }
+ case kWhatInputBufferFilled:
+ {
+ onInputBufferFilled(msg);
+ break;
+ }
+ case kWhatOutputBufferDrained:
+ {
+ onOutputBufferDrained(msg);
+ break;
+ }
+ case kWhatShutdown:
+ {
+ onShutdown(msg);
+ break;
+ }
+ case kWhatFlush:
+ {
+ onFlush();
+ break;
+ }
+ case kWhatResume:
+ {
+ // nothing to do
+ break;
+ }
+ case kWhatSetParameters:
+ {
+ onSetParameters(msg);
+ break;
+ }
+ case kWhatCreateInputSurface:
+ {
+ onCreateInputSurface();
+ break;
+ }
+ case GraphicBufferListener::kWhatFrameAvailable:
+ {
+ onInputFrameAvailable();
+ break;
+ }
+ case kWhatSignalEndOfInputStream:
+ {
+ onSignalEndOfInputStream();
+ break;
+ }
+ default:
+ {
+ ALOGE("Message not handled:\n%s", msg->debugString().c_str());
+ break;
+ }
+ }
+}
+
+//////////////////// PORT DESCRIPTION //////////////////////////////////////////
+
+MediaFilter::PortDescription::PortDescription() {
+}
+
+void MediaFilter::PortDescription::addBuffer(
+ IOMX::buffer_id id, const sp<ABuffer> &buffer) {
+ mBufferIDs.push_back(id);
+ mBuffers.push_back(buffer);
+}
+
+size_t MediaFilter::PortDescription::countBuffers() {
+ return mBufferIDs.size();
+}
+
+IOMX::buffer_id MediaFilter::PortDescription::bufferIDAt(size_t index) const {
+ return mBufferIDs.itemAt(index);
+}
+
+sp<ABuffer> MediaFilter::PortDescription::bufferAt(size_t index) const {
+ return mBuffers.itemAt(index);
+}
+
+//////////////////// HELPER FUNCTIONS //////////////////////////////////////////
+
+void MediaFilter::signalProcessBuffers() {
+ (new AMessage(kWhatProcessBuffers, this))->post();
+}
+
+void MediaFilter::signalError(status_t error) {
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", CodecBase::kWhatError);
+ notify->setInt32("err", error);
+ notify->post();
+}
+
+status_t MediaFilter::allocateBuffersOnPort(OMX_U32 portIndex) {
+ CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
+ const bool isInput = portIndex == kPortIndexInput;
+ const size_t bufferSize = isInput ? mMaxInputSize : mMaxOutputSize;
+
+ CHECK(mDealer[portIndex] == NULL);
+ CHECK(mBuffers[portIndex].isEmpty());
+
+ ALOGV("Allocating %zu buffers of size %zu on %s port",
+ kBufferCountActual, bufferSize,
+ isInput ? "input" : "output");
+
+ size_t totalSize = kBufferCountActual * bufferSize;
+
+ mDealer[portIndex] = new MemoryDealer(totalSize, "MediaFilter");
+
+ for (size_t i = 0; i < kBufferCountActual; ++i) {
+ sp<IMemory> mem = mDealer[portIndex]->allocate(bufferSize);
+ CHECK(mem.get() != NULL);
+
+ BufferInfo info;
+ info.mStatus = BufferInfo::OWNED_BY_US;
+ info.mBufferID = i;
+ info.mGeneration = mGeneration;
+ info.mOutputFlags = 0;
+ info.mData = new ABuffer(mem->pointer(), bufferSize);
+ info.mData->meta()->setInt64("timeUs", 0);
+
+ mBuffers[portIndex].push_back(info);
+
+ if (!isInput) {
+ mAvailableOutputBuffers.push(
+ &mBuffers[portIndex].editItemAt(i));
+ }
+ }
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", CodecBase::kWhatBuffersAllocated);
+
+ notify->setInt32("portIndex", portIndex);
+
+ sp<PortDescription> desc = new PortDescription;
+
+ for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
+ const BufferInfo &info = mBuffers[portIndex][i];
+
+ desc->addBuffer(info.mBufferID, info.mData);
+ }
+
+ notify->setObject("portDesc", desc);
+ notify->post();
+
+ return OK;
+}
+
+MediaFilter::BufferInfo* MediaFilter::findBufferByID(
+ uint32_t portIndex, IOMX::buffer_id bufferID,
+ ssize_t *index) {
+ for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
+ BufferInfo *info = &mBuffers[portIndex].editItemAt(i);
+
+ if (info->mBufferID == bufferID) {
+ if (index != NULL) {
+ *index = i;
+ }
+ return info;
+ }
+ }
+
+ TRESPASS();
+
+ return NULL;
+}
+
+void MediaFilter::postFillThisBuffer(BufferInfo *info) {
+ ALOGV("postFillThisBuffer on buffer %d", info->mBufferID);
+ if (mPortEOS[kPortIndexInput]) {
+ return;
+ }
+
+ CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
+
+ info->mGeneration = mGeneration;
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", CodecBase::kWhatFillThisBuffer);
+ notify->setInt32("buffer-id", info->mBufferID);
+
+ info->mData->meta()->clear();
+ notify->setBuffer("buffer", info->mData);
+
+ sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, this);
+ reply->setInt32("buffer-id", info->mBufferID);
+
+ notify->setMessage("reply", reply);
+
+ info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
+ notify->post();
+}
+
+void MediaFilter::postDrainThisBuffer(BufferInfo *info) {
+ CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
+
+ info->mGeneration = mGeneration;
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", CodecBase::kWhatDrainThisBuffer);
+ notify->setInt32("buffer-id", info->mBufferID);
+ notify->setInt32("flags", info->mOutputFlags);
+ notify->setBuffer("buffer", info->mData);
+
+ sp<AMessage> reply = new AMessage(kWhatOutputBufferDrained, this);
+ reply->setInt32("buffer-id", info->mBufferID);
+
+ notify->setMessage("reply", reply);
+
+ notify->post();
+
+ info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
+}
+
+void MediaFilter::postEOS() {
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", CodecBase::kWhatEOS);
+ notify->setInt32("err", ERROR_END_OF_STREAM);
+ notify->post();
+
+ ALOGV("Sent kWhatEOS.");
+}
+
+void MediaFilter::sendFormatChange() {
+ sp<AMessage> notify = mNotify->dup();
+
+ notify->setInt32("what", kWhatOutputFormatChanged);
+
+ AString mime;
+ CHECK(mOutputFormat->findString("mime", &mime));
+ notify->setString("mime", mime.c_str());
+
+ notify->setInt32("stride", mStride);
+ notify->setInt32("slice-height", mSliceHeight);
+ notify->setInt32("color-format", mColorFormatOut);
+ notify->setRect("crop", 0, 0, mStride - 1, mSliceHeight - 1);
+ notify->setInt32("width", mWidth);
+ notify->setInt32("height", mHeight);
+
+ notify->post();
+}
+
+void MediaFilter::requestFillEmptyInput() {
+ if (mPortEOS[kPortIndexInput]) {
+ return;
+ }
+
+ for (size_t i = 0; i < mBuffers[kPortIndexInput].size(); ++i) {
+ BufferInfo *info = &mBuffers[kPortIndexInput].editItemAt(i);
+
+ if (info->mStatus == BufferInfo::OWNED_BY_US) {
+ postFillThisBuffer(info);
+ }
+ }
+}
+
+void MediaFilter::processBuffers() {
+ if (mAvailableInputBuffers.empty() || mAvailableOutputBuffers.empty()) {
+ ALOGV("Skipping process (buffers unavailable)");
+ return;
+ }
+
+ if (mPortEOS[kPortIndexOutput]) {
+ // TODO notify caller of queueInput error when it is supported
+ // in MediaCodec
+ ALOGW("Tried to process a buffer after EOS.");
+ return;
+ }
+
+ BufferInfo *inputInfo = mAvailableInputBuffers[0];
+ mAvailableInputBuffers.removeAt(0);
+ BufferInfo *outputInfo = mAvailableOutputBuffers[0];
+ mAvailableOutputBuffers.removeAt(0);
+
+ status_t err;
+ err = mFilter->processBuffers(inputInfo->mData, outputInfo->mData);
+ if (err != (status_t)OK) {
+ outputInfo->mData->meta()->setInt32("err", err);
+ }
+
+ int64_t timeUs;
+ CHECK(inputInfo->mData->meta()->findInt64("timeUs", &timeUs));
+ outputInfo->mData->meta()->setInt64("timeUs", timeUs);
+ outputInfo->mOutputFlags = 0;
+ int32_t eos = 0;
+ if (inputInfo->mData->meta()->findInt32("eos", &eos) && eos != 0) {
+ outputInfo->mOutputFlags |= OMX_BUFFERFLAG_EOS;
+ mPortEOS[kPortIndexOutput] = true;
+ outputInfo->mData->meta()->setInt32("eos", eos);
+ postEOS();
+ ALOGV("Output stream saw EOS.");
+ }
+
+ ALOGV("Processed input buffer %u [%zu], output buffer %u [%zu]",
+ inputInfo->mBufferID, inputInfo->mData->size(),
+ outputInfo->mBufferID, outputInfo->mData->size());
+
+ if (mGraphicBufferListener != NULL) {
+ delete inputInfo;
+ } else {
+ postFillThisBuffer(inputInfo);
+ }
+ postDrainThisBuffer(outputInfo);
+
+ // prevent any corner case where buffers could get stuck in queue
+ signalProcessBuffers();
+}
+
+void MediaFilter::onAllocateComponent(const sp<AMessage> &msg) {
+ CHECK_EQ(mState, UNINITIALIZED);
+
+ CHECK(msg->findString("componentName", &mComponentName));
+ const char* name = mComponentName.c_str();
+ if (!strcasecmp(name, "android.filter.zerofilter")) {
+ mFilter = new ZeroFilter;
+ } else if (!strcasecmp(name, "android.filter.saturation")) {
+ mFilter = new SaturationFilter;
+ } else if (!strcasecmp(name, "android.filter.intrinsicblur")) {
+ mFilter = new IntrinsicBlurFilter;
+ } else if (!strcasecmp(name, "android.filter.RenderScript")) {
+ mFilter = new RSFilter;
+ } else {
+ ALOGE("Unrecognized filter name: %s", name);
+ signalError(NAME_NOT_FOUND);
+ return;
+ }
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kWhatComponentAllocated);
+ // HACK - need "OMX.google" to use MediaCodec's software renderer
+ notify->setString("componentName", "OMX.google.MediaFilter");
+ notify->post();
+ mState = INITIALIZED;
+ ALOGV("Handled kWhatAllocateComponent.");
+}
+
+void MediaFilter::onConfigureComponent(const sp<AMessage> &msg) {
+ // TODO: generalize to allow audio filters as well as video
+
+ CHECK_EQ(mState, INITIALIZED);
+
+ // get params - at least mime, width & height
+ AString mime;
+ CHECK(msg->findString("mime", &mime));
+ if (strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_RAW)) {
+ ALOGE("Bad mime: %s", mime.c_str());
+ signalError(BAD_VALUE);
+ return;
+ }
+
+ CHECK(msg->findInt32("width", &mWidth));
+ CHECK(msg->findInt32("height", &mHeight));
+ if (!msg->findInt32("stride", &mStride)) {
+ mStride = mWidth;
+ }
+ if (!msg->findInt32("slice-height", &mSliceHeight)) {
+ mSliceHeight = mHeight;
+ }
+
+ mMaxInputSize = mWidth * mHeight * 4; // room for ARGB8888
+ int32_t maxInputSize;
+ if (msg->findInt32("max-input-size", &maxInputSize)
+ && (size_t)maxInputSize > mMaxInputSize) {
+ mMaxInputSize = maxInputSize;
+ }
+
+ if (!msg->findInt32("color-format", &mColorFormatIn)) {
+ // default to OMX_COLOR_Format32bitARGB8888
+ mColorFormatIn = OMX_COLOR_Format32bitARGB8888;
+ msg->setInt32("color-format", mColorFormatIn);
+ }
+ mColorFormatOut = mColorFormatIn;
+
+ mMaxOutputSize = mWidth * mHeight * 4; // room for ARGB8888
+
+ AString cacheDir;
+ if (!msg->findString("cacheDir", &cacheDir)) {
+ ALOGE("Failed to find cache directory in config message.");
+ signalError(NAME_NOT_FOUND);
+ return;
+ }
+
+ status_t err;
+ err = mFilter->configure(msg);
+ if (err != (status_t)OK) {
+ ALOGE("Failed to configure filter component, err %d", err);
+ signalError(err);
+ return;
+ }
+
+ mInputFormat = new AMessage();
+ mInputFormat->setString("mime", mime.c_str());
+ mInputFormat->setInt32("stride", mStride);
+ mInputFormat->setInt32("slice-height", mSliceHeight);
+ mInputFormat->setInt32("color-format", mColorFormatIn);
+ mInputFormat->setRect("crop", 0, 0, mStride, mSliceHeight);
+ mInputFormat->setInt32("width", mWidth);
+ mInputFormat->setInt32("height", mHeight);
+
+ mOutputFormat = new AMessage();
+ mOutputFormat->setString("mime", mime.c_str());
+ mOutputFormat->setInt32("stride", mStride);
+ mOutputFormat->setInt32("slice-height", mSliceHeight);
+ mOutputFormat->setInt32("color-format", mColorFormatOut);
+ mOutputFormat->setRect("crop", 0, 0, mStride, mSliceHeight);
+ mOutputFormat->setInt32("width", mWidth);
+ mOutputFormat->setInt32("height", mHeight);
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kWhatComponentConfigured);
+ notify->setString("componentName", "MediaFilter");
+ notify->setMessage("input-format", mInputFormat);
+ notify->setMessage("output-format", mOutputFormat);
+ notify->post();
+ mState = CONFIGURED;
+ ALOGV("Handled kWhatConfigureComponent.");
+
+ sendFormatChange();
+}
+
+void MediaFilter::onStart() {
+ CHECK_EQ(mState, CONFIGURED);
+
+ allocateBuffersOnPort(kPortIndexInput);
+
+ allocateBuffersOnPort(kPortIndexOutput);
+
+ status_t err = mFilter->start();
+ if (err != (status_t)OK) {
+ ALOGE("Failed to start filter component, err %d", err);
+ signalError(err);
+ return;
+ }
+
+ mPortEOS[kPortIndexInput] = false;
+ mPortEOS[kPortIndexOutput] = false;
+ mInputEOSResult = OK;
+ mState = STARTED;
+
+ requestFillEmptyInput();
+ ALOGV("Handled kWhatStart.");
+}
+
+void MediaFilter::onInputBufferFilled(const sp<AMessage> &msg) {
+ IOMX::buffer_id bufferID;
+ CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
+ BufferInfo *info = findBufferByID(kPortIndexInput, bufferID);
+
+ if (mState != STARTED) {
+ // we're not running, so we'll just keep that buffer...
+ info->mStatus = BufferInfo::OWNED_BY_US;
+ return;
+ }
+
+ if (info->mGeneration != mGeneration) {
+ ALOGV("Caught a stale input buffer [ID %d]", bufferID);
+ // buffer is stale (taken before a flush/shutdown) - repost it
+ CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_US);
+ postFillThisBuffer(info);
+ return;
+ }
+
+ CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_UPSTREAM);
+ info->mStatus = BufferInfo::OWNED_BY_US;
+
+ sp<ABuffer> buffer;
+ int32_t err = OK;
+ bool eos = false;
+
+ if (!msg->findBuffer("buffer", &buffer)) {
+ // these are unfilled buffers returned by client
+ CHECK(msg->findInt32("err", &err));
+
+ if (err == OK) {
+ // buffers with no errors are returned on MediaCodec.flush
+ ALOGV("saw unfilled buffer (MediaCodec.flush)");
+ postFillThisBuffer(info);
+ return;
+ } else {
+ ALOGV("saw error %d instead of an input buffer", err);
+ eos = true;
+ }
+
+ buffer.clear();
+ }
+
+ int32_t isCSD;
+ if (buffer != NULL && buffer->meta()->findInt32("csd", &isCSD)
+ && isCSD != 0) {
+ // ignore codec-specific data buffers
+ ALOGW("MediaFilter received a codec-specific data buffer");
+ postFillThisBuffer(info);
+ return;
+ }
+
+ int32_t tmp;
+ if (buffer != NULL && buffer->meta()->findInt32("eos", &tmp) && tmp) {
+ eos = true;
+ err = ERROR_END_OF_STREAM;
+ }
+
+ mAvailableInputBuffers.push_back(info);
+ processBuffers();
+
+ if (eos) {
+ mPortEOS[kPortIndexInput] = true;
+ mInputEOSResult = err;
+ }
+
+ ALOGV("Handled kWhatInputBufferFilled. [ID %u]", bufferID);
+}
+
+void MediaFilter::onOutputBufferDrained(const sp<AMessage> &msg) {
+ IOMX::buffer_id bufferID;
+ CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
+ BufferInfo *info = findBufferByID(kPortIndexOutput, bufferID);
+
+ if (mState != STARTED) {
+ // we're not running, so we'll just keep that buffer...
+ info->mStatus = BufferInfo::OWNED_BY_US;
+ return;
+ }
+
+ if (info->mGeneration != mGeneration) {
+ ALOGV("Caught a stale output buffer [ID %d]", bufferID);
+ // buffer is stale (taken before a flush/shutdown) - keep it
+ CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_US);
+ return;
+ }
+
+ CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_UPSTREAM);
+ info->mStatus = BufferInfo::OWNED_BY_US;
+
+ mAvailableOutputBuffers.push_back(info);
+
+ processBuffers();
+
+ ALOGV("Handled kWhatOutputBufferDrained. [ID %u]",
+ bufferID);
+}
+
+void MediaFilter::onShutdown(const sp<AMessage> &msg) {
+ mGeneration++;
+
+ if (mState != UNINITIALIZED) {
+ mFilter->reset();
+ }
+
+ int32_t keepComponentAllocated;
+ CHECK(msg->findInt32("keepComponentAllocated", &keepComponentAllocated));
+ if (!keepComponentAllocated || mState == UNINITIALIZED) {
+ mState = UNINITIALIZED;
+ } else {
+ mState = INITIALIZED;
+ }
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", CodecBase::kWhatShutdownCompleted);
+ notify->post();
+}
+
+void MediaFilter::onFlush() {
+ mGeneration++;
+
+ mAvailableInputBuffers.clear();
+ for (size_t i = 0; i < mBuffers[kPortIndexInput].size(); ++i) {
+ BufferInfo *info = &mBuffers[kPortIndexInput].editItemAt(i);
+ info->mStatus = BufferInfo::OWNED_BY_US;
+ }
+ mAvailableOutputBuffers.clear();
+ for (size_t i = 0; i < mBuffers[kPortIndexOutput].size(); ++i) {
+ BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i);
+ info->mStatus = BufferInfo::OWNED_BY_US;
+ mAvailableOutputBuffers.push_back(info);
+ }
+
+ mPortEOS[kPortIndexInput] = false;
+ mPortEOS[kPortIndexOutput] = false;
+ mInputEOSResult = OK;
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", CodecBase::kWhatFlushCompleted);
+ notify->post();
+ ALOGV("Posted kWhatFlushCompleted");
+
+ // MediaCodec returns all input buffers after flush, so in
+ // onInputBufferFilled we call postFillThisBuffer on them
+}
+
+void MediaFilter::onSetParameters(const sp<AMessage> &msg) {
+ CHECK(mState != STARTED);
+
+ status_t err = mFilter->setParameters(msg);
+ if (err != (status_t)OK) {
+ ALOGE("setParameters returned err %d", err);
+ }
+}
+
+void MediaFilter::onCreateInputSurface() {
+ CHECK(mState == CONFIGURED);
+
+ mGraphicBufferListener = new GraphicBufferListener;
+
+ sp<AMessage> notify = new AMessage();
+ notify->setTarget(this);
+ status_t err = mGraphicBufferListener->init(
+ notify, mStride, mSliceHeight, kBufferCountActual);
+
+ if (err != OK) {
+ ALOGE("Failed to init mGraphicBufferListener: %d", err);
+ signalError(err);
+ return;
+ }
+
+ sp<AMessage> reply = mNotify->dup();
+ reply->setInt32("what", CodecBase::kWhatInputSurfaceCreated);
+ reply->setObject(
+ "input-surface",
+ new BufferProducerWrapper(
+ mGraphicBufferListener->getIGraphicBufferProducer()));
+ reply->post();
+}
+
+void MediaFilter::onInputFrameAvailable() {
+ BufferQueue::BufferItem item = mGraphicBufferListener->getBufferItem();
+ sp<GraphicBuffer> buf = mGraphicBufferListener->getBuffer(item);
+
+ // get pointer to graphic buffer
+ void* bufPtr;
+ buf->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &bufPtr);
+
+ // HACK - there is no OMX_COLOR_FORMATTYPE value for RGBA, so the format
+ // conversion is hardcoded until we add this.
+ // TODO: check input format and convert only if necessary
+ // copy RGBA graphic buffer into temporary ARGB input buffer
+ BufferInfo *inputInfo = new BufferInfo;
+ inputInfo->mData = new ABuffer(buf->getWidth() * buf->getHeight() * 4);
+ ALOGV("Copying surface data into temp buffer.");
+ convertRGBAToARGB(
+ (uint8_t*)bufPtr, buf->getWidth(), buf->getHeight(),
+ buf->getStride(), inputInfo->mData->data());
+ inputInfo->mBufferID = item.mBuf;
+ inputInfo->mGeneration = mGeneration;
+ inputInfo->mOutputFlags = 0;
+ inputInfo->mStatus = BufferInfo::OWNED_BY_US;
+ inputInfo->mData->meta()->setInt64("timeUs", item.mTimestamp / 1000);
+
+ mAvailableInputBuffers.push_back(inputInfo);
+
+ mGraphicBufferListener->releaseBuffer(item);
+
+ signalProcessBuffers();
+}
+
+void MediaFilter::onSignalEndOfInputStream() {
+ // if using input surface, need to send an EOS output buffer
+ if (mGraphicBufferListener != NULL) {
+ Vector<BufferInfo> *outputBufs = &mBuffers[kPortIndexOutput];
+ BufferInfo* eosBuf;
+ bool foundBuf = false;
+ for (size_t i = 0; i < kBufferCountActual; i++) {
+ eosBuf = &outputBufs->editItemAt(i);
+ if (eosBuf->mStatus == BufferInfo::OWNED_BY_US) {
+ foundBuf = true;
+ break;
+ }
+ }
+
+ if (!foundBuf) {
+ ALOGE("onSignalEndOfInputStream failed to find an output buffer");
+ return;
+ }
+
+ eosBuf->mOutputFlags = OMX_BUFFERFLAG_EOS;
+ eosBuf->mGeneration = mGeneration;
+ eosBuf->mData->setRange(0, 0);
+ postDrainThisBuffer(eosBuf);
+ ALOGV("Posted EOS on output buffer %zu", eosBuf->mBufferID);
+ }
+
+ mPortEOS[kPortIndexOutput] = true;
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", CodecBase::kWhatSignaledInputEOS);
+ notify->post();
+
+ ALOGV("Output stream saw EOS.");
+}
+
+} // namespace android
diff --git a/media/libstagefright/filters/RSFilter.cpp b/media/libstagefright/filters/RSFilter.cpp
new file mode 100644
index 0000000..b569945
--- /dev/null
+++ b/media/libstagefright/filters/RSFilter.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "RSFilter"
+
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include "RSFilter.h"
+
+namespace android {
+
+RSFilter::RSFilter() {
+
+}
+
+RSFilter::~RSFilter() {
+
+}
+
+status_t RSFilter::configure(const sp<AMessage> &msg) {
+ status_t err = SimpleFilter::configure(msg);
+ if (err != OK) {
+ return err;
+ }
+
+ if (!msg->findString("cacheDir", &mCacheDir)) {
+ ALOGE("Failed to find cache directory in config message.");
+ return NAME_NOT_FOUND;
+ }
+
+ sp<RenderScriptWrapper> wrapper;
+ if (!msg->findObject("rs-wrapper", (sp<RefBase>*)&wrapper)) {
+ ALOGE("Failed to find RenderScriptWrapper in config message.");
+ return NAME_NOT_FOUND;
+ }
+
+ mRS = wrapper->mContext;
+ mCallback = wrapper->mCallback;
+
+ return OK;
+}
+
+status_t RSFilter::start() {
+ // 32-bit elements for ARGB8888
+ RSC::sp<const RSC::Element> e = RSC::Element::U8_4(mRS);
+
+ RSC::Type::Builder tb(mRS, e);
+ tb.setX(mWidth);
+ tb.setY(mHeight);
+ RSC::sp<const RSC::Type> t = tb.create();
+
+ mAllocIn = RSC::Allocation::createTyped(mRS, t);
+ mAllocOut = RSC::Allocation::createTyped(mRS, t);
+
+ return OK;
+}
+
+void RSFilter::reset() {
+ mCallback.clear();
+ mAllocOut.clear();
+ mAllocIn.clear();
+ mRS.clear();
+}
+
+status_t RSFilter::setParameters(const sp<AMessage> &msg) {
+ return mCallback->handleSetParameters(msg);
+}
+
+status_t RSFilter::processBuffers(
+ const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer) {
+ mAllocIn->copy1DRangeFrom(0, mWidth * mHeight, srcBuffer->data());
+ mCallback->processBuffers(mAllocIn.get(), mAllocOut.get());
+ mAllocOut->copy1DRangeTo(0, mWidth * mHeight, outBuffer->data());
+
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libstagefright/filters/RSFilter.h b/media/libstagefright/filters/RSFilter.h
new file mode 100644
index 0000000..c5b5074
--- /dev/null
+++ b/media/libstagefright/filters/RSFilter.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef RS_FILTER_H_
+#define RS_FILTER_H_
+
+#include <media/stagefright/RenderScriptWrapper.h>
+#include <RenderScript.h>
+
+#include "SimpleFilter.h"
+
+namespace android {
+
+struct AString;
+
+struct RSFilter : public SimpleFilter {
+public:
+ RSFilter();
+
+ virtual status_t configure(const sp<AMessage> &msg);
+ virtual status_t start();
+ virtual void reset();
+ virtual status_t setParameters(const sp<AMessage> &msg);
+ virtual status_t processBuffers(
+ const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer);
+
+protected:
+ virtual ~RSFilter();
+
+private:
+ AString mCacheDir;
+ sp<RenderScriptWrapper::RSFilterCallback> mCallback;
+ RSC::sp<RSC::RS> mRS;
+ RSC::sp<RSC::Allocation> mAllocIn;
+ RSC::sp<RSC::Allocation> mAllocOut;
+};
+
+} // namespace android
+
+#endif // RS_FILTER_H_
diff --git a/media/libstagefright/filters/SaturationFilter.cpp b/media/libstagefright/filters/SaturationFilter.cpp
new file mode 100644
index 0000000..ba5f75a
--- /dev/null
+++ b/media/libstagefright/filters/SaturationFilter.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SaturationFilter"
+
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include "SaturationFilter.h"
+
+namespace android {
+
+status_t SaturationFilter::configure(const sp<AMessage> &msg) {
+ status_t err = SimpleFilter::configure(msg);
+ if (err != OK) {
+ return err;
+ }
+
+ if (!msg->findString("cacheDir", &mCacheDir)) {
+ ALOGE("Failed to find cache directory in config message.");
+ return NAME_NOT_FOUND;
+ }
+
+ return OK;
+}
+
+status_t SaturationFilter::start() {
+ // TODO: use a single RS context object for entire application
+ mRS = new RSC::RS();
+
+ if (!mRS->init(mCacheDir.c_str())) {
+ ALOGE("Failed to initialize RenderScript context.");
+ return NO_INIT;
+ }
+
+ // 32-bit elements for ARGB8888
+ RSC::sp<const RSC::Element> e = RSC::Element::U8_4(mRS);
+
+ RSC::Type::Builder tb(mRS, e);
+ tb.setX(mWidth);
+ tb.setY(mHeight);
+ RSC::sp<const RSC::Type> t = tb.create();
+
+ mAllocIn = RSC::Allocation::createTyped(mRS, t);
+ mAllocOut = RSC::Allocation::createTyped(mRS, t);
+
+ mScript = new ScriptC_saturationARGB(mRS);
+
+ mScript->set_gSaturation(mSaturation);
+
+ return OK;
+}
+
+void SaturationFilter::reset() {
+ mScript.clear();
+ mAllocOut.clear();
+ mAllocIn.clear();
+ mRS.clear();
+}
+
+status_t SaturationFilter::setParameters(const sp<AMessage> &msg) {
+ sp<AMessage> params;
+ CHECK(msg->findMessage("params", ¶ms));
+
+ float saturation;
+ if (params->findFloat("saturation", &saturation)) {
+ mSaturation = saturation;
+ }
+
+ return OK;
+}
+
+status_t SaturationFilter::processBuffers(
+ const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer) {
+ mAllocIn->copy1DRangeFrom(0, mWidth * mHeight, srcBuffer->data());
+ mScript->forEach_root(mAllocIn, mAllocOut);
+ mAllocOut->copy1DRangeTo(0, mWidth * mHeight, outBuffer->data());
+
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libstagefright/filters/SaturationFilter.h b/media/libstagefright/filters/SaturationFilter.h
new file mode 100644
index 0000000..0545021
--- /dev/null
+++ b/media/libstagefright/filters/SaturationFilter.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef SATURATION_FILTER_H_
+#define SATURATION_FILTER_H_
+
+#include <RenderScript.h>
+
+#include "ScriptC_saturationARGB.h"
+#include "SimpleFilter.h"
+
+namespace android {
+
+struct SaturationFilter : public SimpleFilter {
+public:
+ SaturationFilter() : mSaturation(1.f) {};
+
+ virtual status_t configure(const sp<AMessage> &msg);
+ virtual status_t start();
+ virtual void reset();
+ virtual status_t setParameters(const sp<AMessage> &msg);
+ virtual status_t processBuffers(
+ const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer);
+
+protected:
+ virtual ~SaturationFilter() {};
+
+private:
+ AString mCacheDir;
+ RSC::sp<RSC::RS> mRS;
+ RSC::sp<RSC::Allocation> mAllocIn;
+ RSC::sp<RSC::Allocation> mAllocOut;
+ RSC::sp<ScriptC_saturationARGB> mScript;
+ float mSaturation;
+};
+
+} // namespace android
+
+#endif // SATURATION_FILTER_H_
diff --git a/media/libstagefright/filters/SimpleFilter.cpp b/media/libstagefright/filters/SimpleFilter.cpp
new file mode 100644
index 0000000..6c1ca2c
--- /dev/null
+++ b/media/libstagefright/filters/SimpleFilter.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include "SimpleFilter.h"
+
+namespace android {
+
+status_t SimpleFilter::configure(const sp<AMessage> &msg) {
+ CHECK(msg->findInt32("width", &mWidth));
+ CHECK(msg->findInt32("height", &mHeight));
+ if (!msg->findInt32("stride", &mStride)) {
+ mStride = mWidth;
+ }
+ if (!msg->findInt32("slice-height", &mSliceHeight)) {
+ mSliceHeight = mHeight;
+ }
+ CHECK(msg->findInt32("color-format", &mColorFormatIn));
+ mColorFormatOut = mColorFormatIn;
+
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libstagefright/filters/SimpleFilter.h b/media/libstagefright/filters/SimpleFilter.h
new file mode 100644
index 0000000..4cd37ef
--- /dev/null
+++ b/media/libstagefright/filters/SimpleFilter.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef SIMPLE_FILTER_H_
+#define SIMPLE_FILTER_H_
+
+#include <stdint.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+struct ABuffer;
+struct AMessage;
+
+namespace android {
+
+struct SimpleFilter : public RefBase {
+public:
+ SimpleFilter() : mWidth(0), mHeight(0), mStride(0), mSliceHeight(0),
+ mColorFormatIn(0), mColorFormatOut(0) {};
+
+ virtual status_t configure(const sp<AMessage> &msg);
+
+ virtual status_t start() = 0;
+ virtual void reset() = 0;
+ virtual status_t setParameters(const sp<AMessage> &msg) = 0;
+ virtual status_t processBuffers(
+ const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer) = 0;
+
+protected:
+ int32_t mWidth, mHeight;
+ int32_t mStride, mSliceHeight;
+ int32_t mColorFormatIn, mColorFormatOut;
+
+ virtual ~SimpleFilter() {};
+};
+
+} // namespace android
+
+#endif // SIMPLE_FILTER_H_
diff --git a/media/libstagefright/filters/ZeroFilter.cpp b/media/libstagefright/filters/ZeroFilter.cpp
new file mode 100644
index 0000000..3f1243c
--- /dev/null
+++ b/media/libstagefright/filters/ZeroFilter.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ZeroFilter"
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include "ZeroFilter.h"
+
+namespace android {
+
+status_t ZeroFilter::setParameters(const sp<AMessage> &msg) {
+ sp<AMessage> params;
+ CHECK(msg->findMessage("params", ¶ms));
+
+ int32_t invert;
+ if (params->findInt32("invert", &invert)) {
+ mInvertData = (invert != 0);
+ }
+
+ return OK;
+}
+
+status_t ZeroFilter::processBuffers(
+ const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer) {
+ // assuming identical input & output buffers, since we're a copy filter
+ if (mInvertData) {
+ uint32_t* src = (uint32_t*)srcBuffer->data();
+ uint32_t* dest = (uint32_t*)outBuffer->data();
+ for (size_t i = 0; i < srcBuffer->size() / 4; ++i) {
+ *(dest++) = *(src++) ^ 0xFFFFFFFF;
+ }
+ } else {
+ memcpy(outBuffer->data(), srcBuffer->data(), srcBuffer->size());
+ }
+ outBuffer->setRange(0, srcBuffer->size());
+
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libstagefright/filters/ZeroFilter.h b/media/libstagefright/filters/ZeroFilter.h
new file mode 100644
index 0000000..bd34dfb
--- /dev/null
+++ b/media/libstagefright/filters/ZeroFilter.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#ifndef ZERO_FILTER_H_
+#define ZERO_FILTER_H_
+
+#include "SimpleFilter.h"
+
+namespace android {
+
+struct ZeroFilter : public SimpleFilter {
+public:
+ ZeroFilter() : mInvertData(false) {};
+
+ virtual status_t start() { return OK; };
+ virtual void reset() {};
+ virtual status_t setParameters(const sp<AMessage> &msg);
+ virtual status_t processBuffers(
+ const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer);
+
+protected:
+ virtual ~ZeroFilter() {};
+
+private:
+ bool mInvertData;
+};
+
+} // namespace android
+
+#endif // ZERO_FILTER_H_
diff --git a/media/libstagefright/filters/saturation.rs b/media/libstagefright/filters/saturation.rs
new file mode 100644
index 0000000..2c867ac
--- /dev/null
+++ b/media/libstagefright/filters/saturation.rs
@@ -0,0 +1,40 @@
+// Sample script for RGB888 support (compare to saturationARGB.rs)
+/*
+ * 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.cppbasic)
+#pragma rs_fp_relaxed
+
+const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
+
+// global variables (parameters accessible to application code)
+float gSaturation = 1.0f;
+
+void root(const uchar3 *v_in, uchar3 *v_out) {
+ // scale 0-255 uchar to 0-1.0 float
+ float3 in = {v_in->r * 0.003921569f, v_in->g * 0.003921569f,
+ v_in->b * 0.003921569f};
+
+ // apply saturation filter
+ float3 result = dot(in, gMonoMult);
+ result = mix(result, in, gSaturation);
+
+ // convert to uchar, copied from rsPackColorTo8888
+ v_out->x = (uchar)clamp((result.r * 255.f + 0.5f), 0.f, 255.f);
+ v_out->y = (uchar)clamp((result.g * 255.f + 0.5f), 0.f, 255.f);
+ v_out->z = (uchar)clamp((result.b * 255.f + 0.5f), 0.f, 255.f);
+}
diff --git a/media/libstagefright/filters/saturationARGB.rs b/media/libstagefright/filters/saturationARGB.rs
new file mode 100644
index 0000000..1de9dd8
--- /dev/null
+++ b/media/libstagefright/filters/saturationARGB.rs
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.cppbasic)
+#pragma rs_fp_relaxed
+
+const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
+
+// global variables (parameters accessible to application code)
+float gSaturation = 1.0f;
+
+void root(const uchar4 *v_in, uchar4 *v_out) {
+ v_out->x = v_in->x; // don't modify A
+
+ // get RGB, scale 0-255 uchar to 0-1.0 float
+ float3 rgb = {v_in->y * 0.003921569f, v_in->z * 0.003921569f,
+ v_in->w * 0.003921569f};
+
+ // apply saturation filter
+ float3 result = dot(rgb, gMonoMult);
+ result = mix(result, rgb, gSaturation);
+
+ v_out->y = (uchar)clamp((result.r * 255.f + 0.5f), 0.f, 255.f);
+ v_out->z = (uchar)clamp((result.g * 255.f + 0.5f), 0.f, 255.f);
+ v_out->w = (uchar)clamp((result.b * 255.f + 0.5f), 0.f, 255.f);
+}
diff --git a/media/libstagefright/foundation/AHandler.cpp b/media/libstagefright/foundation/AHandler.cpp
index bd5f7e9..7dbbe54 100644
--- a/media/libstagefright/foundation/AHandler.cpp
+++ b/media/libstagefright/foundation/AHandler.cpp
@@ -19,15 +19,23 @@
#include <utils/Log.h>
#include <media/stagefright/foundation/AHandler.h>
-
-#include <media/stagefright/foundation/ALooperRoster.h>
+#include <media/stagefright/foundation/AMessage.h>
namespace android {
-sp<ALooper> AHandler::looper() {
- extern ALooperRoster gLooperRoster;
+void AHandler::deliverMessage(const sp<AMessage> &msg) {
+ onMessageReceived(msg);
+ mMessageCounter++;
- return gLooperRoster.findLooper(id());
+ if (mVerboseStats) {
+ uint32_t what = msg->what();
+ ssize_t idx = mMessages.indexOfKey(what);
+ if (idx < 0) {
+ mMessages.add(what, 1);
+ } else {
+ mMessages.editValueAt(idx)++;
+ }
+ }
}
} // namespace android
diff --git a/media/libstagefright/foundation/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp
index 88b1c92..90b5f68 100644
--- a/media/libstagefright/foundation/ALooper.cpp
+++ b/media/libstagefright/foundation/ALooper.cpp
@@ -16,6 +16,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "ALooper"
+
+#include <media/stagefright/foundation/ADebug.h>
+
#include <utils/Log.h>
#include <sys/time.h>
@@ -210,7 +213,7 @@
mEventQueue.erase(mEventQueue.begin());
}
- gLooperRoster.deliverMessage(event.mMessage);
+ event.mMessage->deliver();
// NOTE: It's important to note that at this point our "ALooper" object
// may no longer exist (its final reference may have gone away while
@@ -220,4 +223,29 @@
return true;
}
+// to be called by AMessage::postAndAwaitResponse only
+sp<AReplyToken> ALooper::createReplyToken() {
+ return new AReplyToken(this);
+}
+
+// to be called by AMessage::postAndAwaitResponse only
+status_t ALooper::awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response) {
+ // return status in case we want to handle an interrupted wait
+ Mutex::Autolock autoLock(mRepliesLock);
+ CHECK(replyToken != NULL);
+ while (!replyToken->retrieveReply(response)) {
+ mRepliesCondition.wait(mRepliesLock);
+ }
+ return OK;
+}
+
+status_t ALooper::postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &reply) {
+ Mutex::Autolock autoLock(mRepliesLock);
+ status_t err = replyToken->setReply(reply);
+ if (err == OK) {
+ mRepliesCondition.broadcast();
+ }
+ return err;
+}
+
} // namespace android
diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp
index e0dc768..473ce1b 100644
--- a/media/libstagefright/foundation/ALooperRoster.cpp
+++ b/media/libstagefright/foundation/ALooperRoster.cpp
@@ -17,6 +17,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "ALooperRoster"
#include <utils/Log.h>
+#include <utils/String8.h>
#include "ALooperRoster.h"
@@ -26,9 +27,10 @@
namespace android {
+static bool verboseStats = false;
+
ALooperRoster::ALooperRoster()
- : mNextHandlerID(1),
- mNextReplyID(1) {
+ : mNextHandlerID(1) {
}
ALooper::handler_id ALooperRoster::registerHandler(
@@ -46,7 +48,7 @@
ALooper::handler_id handlerID = mNextHandlerID++;
mHandlers.add(handlerID, info);
- handler->setID(handlerID);
+ handler->setID(handlerID, looper);
return handlerID;
}
@@ -65,7 +67,7 @@
sp<AHandler> handler = info.mHandler.promote();
if (handler != NULL) {
- handler->setID(0);
+ handler->setID(0, NULL);
}
mHandlers.removeItemsAt(index);
@@ -97,103 +99,73 @@
}
}
-status_t ALooperRoster::postMessage(
- const sp<AMessage> &msg, int64_t delayUs) {
-
- sp<ALooper> looper = findLooper(msg->target());
-
- if (looper == NULL) {
- return -ENOENT;
+static void makeFourCC(uint32_t fourcc, char *s) {
+ s[0] = (fourcc >> 24) & 0xff;
+ if (s[0]) {
+ s[1] = (fourcc >> 16) & 0xff;
+ s[2] = (fourcc >> 8) & 0xff;
+ s[3] = fourcc & 0xff;
+ s[4] = 0;
+ } else {
+ sprintf(s, "%u", fourcc);
}
- looper->post(msg, delayUs);
- return OK;
}
-void ALooperRoster::deliverMessage(const sp<AMessage> &msg) {
- sp<AHandler> handler;
-
- {
- Mutex::Autolock autoLock(mLock);
-
- ssize_t index = mHandlers.indexOfKey(msg->target());
-
- if (index < 0) {
- ALOGW("failed to deliver message. Target handler not registered.");
- return;
- }
-
- const HandlerInfo &info = mHandlers.valueAt(index);
- handler = info.mHandler.promote();
-
- if (handler == NULL) {
- ALOGW("failed to deliver message. "
- "Target handler %d registered, but object gone.",
- msg->target());
-
- mHandlers.removeItemsAt(index);
- return;
+void ALooperRoster::dump(int fd, const Vector<String16>& args) {
+ bool clear = false;
+ bool oldVerbose = verboseStats;
+ for (size_t i = 0; i < args.size(); i++) {
+ if (args[i] == String16("-c")) {
+ clear = true;
+ } else if (args[i] == String16("-von")) {
+ verboseStats = true;
+ } else if (args[i] == String16("-voff")) {
+ verboseStats = false;
}
}
-
- handler->onMessageReceived(msg);
-}
-
-sp<ALooper> ALooperRoster::findLooper(ALooper::handler_id handlerID) {
- Mutex::Autolock autoLock(mLock);
-
- ssize_t index = mHandlers.indexOfKey(handlerID);
-
- if (index < 0) {
- return NULL;
- }
-
- sp<ALooper> looper = mHandlers.valueAt(index).mLooper.promote();
-
- if (looper == NULL) {
- mHandlers.removeItemsAt(index);
- return NULL;
- }
-
- return looper;
-}
-
-status_t ALooperRoster::postAndAwaitResponse(
- const sp<AMessage> &msg, sp<AMessage> *response) {
- sp<ALooper> looper = findLooper(msg->target());
-
- if (looper == NULL) {
- ALOGW("failed to post message. "
- "Target handler %d still registered, but object gone.",
- msg->target());
- response->clear();
- return -ENOENT;
+ String8 s;
+ if (verboseStats && !oldVerbose) {
+ s.append("(verbose stats collection enabled, stats will be cleared)\n");
}
Mutex::Autolock autoLock(mLock);
+ size_t n = mHandlers.size();
+ s.appendFormat(" %zu registered handlers:\n", n);
- uint32_t replyID = mNextReplyID++;
-
- msg->setInt32("replyID", replyID);
-
- looper->post(msg, 0 /* delayUs */);
-
- ssize_t index;
- while ((index = mReplies.indexOfKey(replyID)) < 0) {
- mRepliesCondition.wait(mLock);
+ for (size_t i = 0; i < n; i++) {
+ s.appendFormat(" %d: ", mHandlers.keyAt(i));
+ HandlerInfo &info = mHandlers.editValueAt(i);
+ sp<ALooper> looper = info.mLooper.promote();
+ if (looper != NULL) {
+ s.append(looper->getName());
+ sp<AHandler> handler = info.mHandler.promote();
+ if (handler != NULL) {
+ handler->mVerboseStats = verboseStats;
+ s.appendFormat(": %u messages processed", handler->mMessageCounter);
+ if (verboseStats) {
+ for (size_t j = 0; j < handler->mMessages.size(); j++) {
+ char fourcc[15];
+ makeFourCC(handler->mMessages.keyAt(j), fourcc);
+ s.appendFormat("\n %s: %u",
+ fourcc,
+ handler->mMessages.valueAt(j));
+ }
+ } else {
+ handler->mMessages.clear();
+ }
+ if (clear || (verboseStats && !oldVerbose)) {
+ handler->mMessageCounter = 0;
+ handler->mMessages.clear();
+ }
+ } else {
+ s.append(": <stale handler>");
+ }
+ } else {
+ s.append("<stale>");
+ }
+ s.append("\n");
}
-
- *response = mReplies.valueAt(index);
- mReplies.removeItemsAt(index);
-
- return OK;
-}
-
-void ALooperRoster::postReply(uint32_t replyID, const sp<AMessage> &reply) {
- Mutex::Autolock autoLock(mLock);
-
- CHECK(mReplies.indexOfKey(replyID) < 0);
- mReplies.add(replyID, reply);
- mRepliesCondition.broadcast();
+ write(fd, s.string(), s.size());
}
} // namespace android
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index 795e8a6..e549ff6 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -27,6 +27,7 @@
#include "ABuffer.h"
#include "ADebug.h"
#include "ALooperRoster.h"
+#include "AHandler.h"
#include "AString.h"
#include <binder/Parcel.h>
@@ -36,12 +37,29 @@
extern ALooperRoster gLooperRoster;
-AMessage::AMessage(uint32_t what, ALooper::handler_id target)
- : mWhat(what),
- mTarget(target),
+status_t AReplyToken::setReply(const sp<AMessage> &reply) {
+ if (mReplied) {
+ ALOGE("trying to post a duplicate reply");
+ return -EBUSY;
+ }
+ CHECK(mReply == NULL);
+ mReply = reply;
+ mReplied = true;
+ return OK;
+}
+
+AMessage::AMessage(void)
+ : mWhat(0),
+ mTarget(0),
mNumItems(0) {
}
+AMessage::AMessage(uint32_t what, const sp<const AHandler> &handler)
+ : mWhat(what),
+ mNumItems(0) {
+ setTarget(handler);
+}
+
AMessage::~AMessage() {
clear();
}
@@ -54,12 +72,16 @@
return mWhat;
}
-void AMessage::setTarget(ALooper::handler_id handlerID) {
- mTarget = handlerID;
-}
-
-ALooper::handler_id AMessage::target() const {
- return mTarget;
+void AMessage::setTarget(const sp<const AHandler> &handler) {
+ if (handler == NULL) {
+ mTarget = 0;
+ mHandler.clear();
+ mLooper.clear();
+ } else {
+ mTarget = handler->id();
+ mHandler = handler->getHandler();
+ mLooper = handler->getLooper();
+ }
}
void AMessage::clear() {
@@ -322,33 +344,76 @@
return true;
}
-void AMessage::post(int64_t delayUs) {
- gLooperRoster.postMessage(this, delayUs);
+void AMessage::deliver() {
+ sp<AHandler> handler = mHandler.promote();
+ if (handler == NULL) {
+ ALOGW("failed to deliver message as target handler %d is gone.", mTarget);
+ return;
+ }
+
+ handler->deliverMessage(this);
+}
+
+status_t AMessage::post(int64_t delayUs) {
+ sp<ALooper> looper = mLooper.promote();
+ if (looper == NULL) {
+ ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
+ return -ENOENT;
+ }
+
+ looper->post(this, delayUs);
+ return OK;
}
status_t AMessage::postAndAwaitResponse(sp<AMessage> *response) {
- return gLooperRoster.postAndAwaitResponse(this, response);
+ sp<ALooper> looper = mLooper.promote();
+ if (looper == NULL) {
+ ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
+ return -ENOENT;
+ }
+
+ sp<AReplyToken> token = looper->createReplyToken();
+ if (token == NULL) {
+ ALOGE("failed to create reply token");
+ return -ENOMEM;
+ }
+ setObject("replyID", token);
+
+ looper->post(this, 0 /* delayUs */);
+ return looper->awaitResponse(token, response);
}
-void AMessage::postReply(uint32_t replyID) {
- gLooperRoster.postReply(replyID, this);
+status_t AMessage::postReply(const sp<AReplyToken> &replyToken) {
+ if (replyToken == NULL) {
+ ALOGW("failed to post reply to a NULL token");
+ return -ENOENT;
+ }
+ sp<ALooper> looper = replyToken->getLooper();
+ if (looper == NULL) {
+ ALOGW("failed to post reply as target looper is gone.");
+ return -ENOENT;
+ }
+ return looper->postReply(replyToken, this);
}
-bool AMessage::senderAwaitsResponse(uint32_t *replyID) const {
- int32_t tmp;
- bool found = findInt32("replyID", &tmp);
+bool AMessage::senderAwaitsResponse(sp<AReplyToken> *replyToken) {
+ sp<RefBase> tmp;
+ bool found = findObject("replyID", &tmp);
if (!found) {
return false;
}
- *replyID = static_cast<uint32_t>(tmp);
+ *replyToken = static_cast<AReplyToken *>(tmp.get());
+ tmp.clear();
+ setObject("replyID", tmp);
+ // TODO: delete Object instead of setting it to NULL
- return true;
+ return *replyToken != NULL;
}
sp<AMessage> AMessage::dup() const {
- sp<AMessage> msg = new AMessage(mWhat, mTarget);
+ sp<AMessage> msg = new AMessage(mWhat, mHandler.promote());
msg->mNumItems = mNumItems;
#ifdef DUMP_STATS
@@ -426,19 +491,19 @@
AString tmp;
if (isFourcc(mWhat)) {
- tmp = StringPrintf(
+ tmp = AStringPrintf(
"'%c%c%c%c'",
(char)(mWhat >> 24),
(char)((mWhat >> 16) & 0xff),
(char)((mWhat >> 8) & 0xff),
(char)(mWhat & 0xff));
} else {
- tmp = StringPrintf("0x%08x", mWhat);
+ tmp = AStringPrintf("0x%08x", mWhat);
}
s.append(tmp);
if (mTarget != 0) {
- tmp = StringPrintf(", target = %d", mTarget);
+ tmp = AStringPrintf(", target = %d", mTarget);
s.append(tmp);
}
s.append(") = {\n");
@@ -448,37 +513,37 @@
switch (item.mType) {
case kTypeInt32:
- tmp = StringPrintf(
+ tmp = AStringPrintf(
"int32_t %s = %d", item.mName, item.u.int32Value);
break;
case kTypeInt64:
- tmp = StringPrintf(
+ tmp = AStringPrintf(
"int64_t %s = %lld", item.mName, item.u.int64Value);
break;
case kTypeSize:
- tmp = StringPrintf(
+ tmp = AStringPrintf(
"size_t %s = %d", item.mName, item.u.sizeValue);
break;
case kTypeFloat:
- tmp = StringPrintf(
+ tmp = AStringPrintf(
"float %s = %f", item.mName, item.u.floatValue);
break;
case kTypeDouble:
- tmp = StringPrintf(
+ tmp = AStringPrintf(
"double %s = %f", item.mName, item.u.doubleValue);
break;
case kTypePointer:
- tmp = StringPrintf(
+ tmp = AStringPrintf(
"void *%s = %p", item.mName, item.u.ptrValue);
break;
case kTypeString:
- tmp = StringPrintf(
+ tmp = AStringPrintf(
"string %s = \"%s\"",
item.mName,
item.u.stringValue->c_str());
break;
case kTypeObject:
- tmp = StringPrintf(
+ tmp = AStringPrintf(
"RefBase *%s = %p", item.mName, item.u.refValue);
break;
case kTypeBuffer:
@@ -486,18 +551,18 @@
sp<ABuffer> buffer = static_cast<ABuffer *>(item.u.refValue);
if (buffer != NULL && buffer->data() != NULL && buffer->size() <= 64) {
- tmp = StringPrintf("Buffer %s = {\n", item.mName);
+ tmp = AStringPrintf("Buffer %s = {\n", item.mName);
hexdump(buffer->data(), buffer->size(), indent + 4, &tmp);
appendIndent(&tmp, indent + 2);
tmp.append("}");
} else {
- tmp = StringPrintf(
+ tmp = AStringPrintf(
"Buffer *%s = %p", item.mName, buffer.get());
}
break;
}
case kTypeMessage:
- tmp = StringPrintf(
+ tmp = AStringPrintf(
"AMessage %s = %s",
item.mName,
static_cast<AMessage *>(
@@ -505,7 +570,7 @@
indent + strlen(item.mName) + 14).c_str());
break;
case kTypeRect:
- tmp = StringPrintf(
+ tmp = AStringPrintf(
"Rect %s(%d, %d, %d, %d)",
item.mName,
item.u.rectValue.mLeft,
@@ -532,7 +597,8 @@
// static
sp<AMessage> AMessage::FromParcel(const Parcel &parcel) {
int32_t what = parcel.readInt32();
- sp<AMessage> msg = new AMessage(what);
+ sp<AMessage> msg = new AMessage();
+ msg->setWhat(what);
msg->mNumItems = static_cast<size_t>(parcel.readInt32());
for (size_t i = 0; i < msg->mNumItems; ++i) {
diff --git a/media/libstagefright/foundation/ANetworkSession.cpp b/media/libstagefright/foundation/ANetworkSession.cpp
index 4504c2b..b230400 100644
--- a/media/libstagefright/foundation/ANetworkSession.cpp
+++ b/media/libstagefright/foundation/ANetworkSession.cpp
@@ -187,7 +187,7 @@
CHECK_GE(res, 0);
in_addr_t addr = ntohl(localAddr.sin_addr.s_addr);
- AString localAddrString = StringPrintf(
+ AString localAddrString = AStringPrintf(
"%d.%d.%d.%d",
(addr >> 24),
(addr >> 16) & 0xff,
@@ -195,7 +195,7 @@
addr & 0xff);
addr = ntohl(remoteAddr.sin_addr.s_addr);
- AString remoteAddrString = StringPrintf(
+ AString remoteAddrString = AStringPrintf(
"%d.%d.%d.%d",
(addr >> 24),
(addr >> 16) & 0xff,
@@ -301,7 +301,7 @@
uint32_t ip = ntohl(remoteAddr.sin_addr.s_addr);
notify->setString(
"fromAddr",
- StringPrintf(
+ AStringPrintf(
"%u.%u.%u.%u",
ip >> 24,
(ip >> 16) & 0xff,
diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp
index 9835ca3..b167543 100644
--- a/media/libstagefright/foundation/AString.cpp
+++ b/media/libstagefright/foundation/AString.cpp
@@ -366,7 +366,7 @@
return err;
}
-AString StringPrintf(const char *format, ...) {
+AString AStringPrintf(const char *format, ...) {
va_list ap;
va_start(ap, format);
diff --git a/media/libstagefright/foundation/AWakeLock.cpp b/media/libstagefright/foundation/AWakeLock.cpp
index 88c4f6e..d9277ac 100644
--- a/media/libstagefright/foundation/AWakeLock.cpp
+++ b/media/libstagefright/foundation/AWakeLock.cpp
@@ -36,7 +36,7 @@
AWakeLock::~AWakeLock() {
if (mPowerManager != NULL) {
- sp<IBinder> binder = mPowerManager->asBinder();
+ sp<IBinder> binder = IInterface::asBinder(mPowerManager);
binder->unlinkToDeath(mDeathRecipient);
}
clearPowerManager();
diff --git a/media/libstagefright/http/MediaHTTP.cpp b/media/libstagefright/http/MediaHTTP.cpp
index 2d29913..bb89567 100644
--- a/media/libstagefright/http/MediaHTTP.cpp
+++ b/media/libstagefright/http/MediaHTTP.cpp
@@ -129,7 +129,7 @@
*size = mCachedSize;
- return *size < 0 ? *size : OK;
+ return *size < 0 ? *size : static_cast<status_t>(OK);
}
uint32_t MediaHTTP::flags() {
diff --git a/media/libstagefright/httplive/Android.mk b/media/libstagefright/httplive/Android.mk
index e8d558c..93b7935 100644
--- a/media/libstagefright/httplive/Android.mk
+++ b/media/libstagefright/httplive/Android.mk
@@ -10,8 +10,7 @@
LOCAL_C_INCLUDES:= \
$(TOP)/frameworks/av/media/libstagefright \
- $(TOP)/frameworks/native/include/media/openmax \
- $(TOP)/external/openssl/include
+ $(TOP)/frameworks/native/include/media/openmax
LOCAL_CFLAGS += -Werror
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 4355a3c..a8f60a8 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -49,8 +49,13 @@
namespace android {
+// static
// Number of recently-read bytes to use for bandwidth estimation
const size_t LiveSession::kBandwidthHistoryBytes = 200 * 1024;
+// High water mark to start up switch or report prepared)
+const int64_t LiveSession::kHighWaterMark = 8000000ll;
+const int64_t LiveSession::kMidWaterMark = 5000000ll;
+const int64_t LiveSession::kLowWaterMark = 3000000ll;
LiveSession::LiveSession(
const sp<AMessage> ¬ify, uint32_t flags,
@@ -75,14 +80,14 @@
mSeekReplyID(0),
mFirstTimeUsValid(false),
mFirstTimeUs(0),
- mLastSeekTimeUs(0) {
+ mLastSeekTimeUs(0),
+ mPollBufferingGeneration(0) {
mStreams[kAudioIndex] = StreamItem("audio");
mStreams[kVideoIndex] = StreamItem("video");
mStreams[kSubtitleIndex] = StreamItem("subtitles");
for (size_t i = 0; i < kMaxStreams; ++i) {
- mDiscontinuities.add(indexToType(i), new AnotherPacketSource(NULL /* meta */));
mPacketSources.add(indexToType(i), new AnotherPacketSource(NULL /* meta */));
mPacketSources2.add(indexToType(i), new AnotherPacketSource(NULL /* meta */));
mBuffering[i] = false;
@@ -97,6 +102,9 @@
}
LiveSession::~LiveSession() {
+ if (mFetcherLooper != NULL) {
+ mFetcherLooper->stop();
+ }
}
sp<ABuffer> LiveSession::createFormatChangeBuffer(bool swap) {
@@ -125,24 +133,7 @@
return -EWOULDBLOCK;
}
- status_t finalResult;
- sp<AnotherPacketSource> discontinuityQueue = mDiscontinuities.valueFor(stream);
- if (discontinuityQueue->hasBufferAvailable(&finalResult)) {
- discontinuityQueue->dequeueAccessUnit(accessUnit);
- // seeking, track switching
- sp<AMessage> extra;
- int64_t timeUs;
- if ((*accessUnit)->meta()->findMessage("extra", &extra)
- && extra != NULL
- && extra->findInt64("timeUs", &timeUs)) {
- // seeking only
- mLastSeekTimeUs = timeUs;
- mDiscontinuityOffsetTimesUs.clear();
- mDiscontinuityAbsStartTimesUs.clear();
- }
- return INFO_DISCONTINUITY;
- }
-
+ status_t finalResult = OK;
sp<AnotherPacketSource> packetSource = mPacketSources.valueFor(stream);
ssize_t idx = typeToIndex(stream);
@@ -172,7 +163,7 @@
if (mBuffering[idx]) {
if (mSwitchInProgress
|| packetSource->isFinished(0)
- || packetSource->getEstimatedDurationUs() > targetDurationUs) {
+ || packetSource->hasBufferAvailable(&finalResult)) {
mBuffering[idx] = false;
}
}
@@ -244,7 +235,7 @@
Mutex::Autolock lock(mSwapMutex);
if (switchGeneration == mSwitchGeneration) {
swapPacketSource(stream);
- sp<AMessage> msg = new AMessage(kWhatSwapped, id());
+ sp<AMessage> msg = new AMessage(kWhatSwapped, this);
msg->setInt32("stream", stream);
msg->setInt32("switchGeneration", switchGeneration);
msg->post();
@@ -349,7 +340,7 @@
void LiveSession::connectAsync(
const char *url, const KeyedVector<String8, String8> *headers) {
- sp<AMessage> msg = new AMessage(kWhatConnect, id());
+ sp<AMessage> msg = new AMessage(kWhatConnect, this);
msg->setString("url", url);
if (headers != NULL) {
@@ -362,7 +353,7 @@
}
status_t LiveSession::disconnect() {
- sp<AMessage> msg = new AMessage(kWhatDisconnect, id());
+ sp<AMessage> msg = new AMessage(kWhatDisconnect, this);
sp<AMessage> response;
status_t err = msg->postAndAwaitResponse(&response);
@@ -371,7 +362,7 @@
}
status_t LiveSession::seekTo(int64_t timeUs) {
- sp<AMessage> msg = new AMessage(kWhatSeek, id());
+ sp<AMessage> msg = new AMessage(kWhatSeek, this);
msg->setInt64("timeUs", timeUs);
sp<AMessage> response;
@@ -402,7 +393,7 @@
case kWhatSeek:
{
- uint32_t seekReplyID;
+ sp<AReplyToken> seekReplyID;
CHECK(msg->senderAwaitsResponse(&seekReplyID));
mSeekReplyID = seekReplyID;
mSeekReply = new AMessage;
@@ -429,11 +420,16 @@
if (what == PlaylistFetcher::kWhatStopped) {
AString uri;
CHECK(msg->findString("uri", &uri));
- if (mFetcherInfos.removeItem(uri) < 0) {
+ ssize_t index = mFetcherInfos.indexOfKey(uri);
+ if (index < 0) {
// ignore duplicated kWhatStopped messages.
break;
}
+ mFetcherLooper->unregisterHandler(
+ mFetcherInfos[index].mFetcher->id());
+ mFetcherInfos.removeItemsAt(index);
+
if (mSwitchInProgress) {
tryToFinishBandwidthSwitch();
}
@@ -443,14 +439,6 @@
CHECK_GT(mContinuationCounter, 0);
if (--mContinuationCounter == 0) {
mContinuation->post();
-
- if (mSeekReplyID != 0) {
- CHECK(mSeekReply != NULL);
- mSeekReply->setInt32("err", OK);
- mSeekReply->postReply(mSeekReplyID);
- mSeekReplyID = 0;
- mSeekReply.clear();
- }
}
}
break;
@@ -464,8 +452,11 @@
int64_t durationUs;
CHECK(msg->findInt64("durationUs", &durationUs));
- FetcherInfo *info = &mFetcherInfos.editValueFor(uri);
- info->mDurationUs = durationUs;
+ ssize_t index = mFetcherInfos.indexOfKey(uri);
+ if (index >= 0) {
+ FetcherInfo *info = &mFetcherInfos.editValueFor(uri);
+ info->mDurationUs = durationUs;
+ }
break;
}
@@ -513,34 +504,6 @@
break;
}
- case PlaylistFetcher::kWhatTemporarilyDoneFetching:
- {
- AString uri;
- CHECK(msg->findString("uri", &uri));
-
- if (mFetcherInfos.indexOfKey(uri) < 0) {
- ALOGE("couldn't find uri");
- break;
- }
- FetcherInfo *info = &mFetcherInfos.editValueFor(uri);
- info->mIsPrepared = true;
-
- if (mInPreparationPhase) {
- bool allFetchersPrepared = true;
- for (size_t i = 0; i < mFetcherInfos.size(); ++i) {
- if (!mFetcherInfos.valueAt(i).mIsPrepared) {
- allFetchersPrepared = false;
- break;
- }
- }
-
- if (allFetchersPrepared) {
- postPrepared(OK);
- }
- }
- break;
- }
-
case PlaylistFetcher::kWhatStartedAt:
{
int32_t switchGeneration;
@@ -569,19 +532,6 @@
break;
}
- case kWhatCheckBandwidth:
- {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
-
- if (generation != mCheckBandwidthGeneration) {
- break;
- }
-
- onCheckBandwidth(msg);
- break;
- }
-
case kWhatChangeConfiguration:
{
onChangeConfiguration(msg);
@@ -612,15 +562,13 @@
break;
}
- case kWhatCheckSwitchDown:
+ case kWhatPollBuffering:
{
- onCheckSwitchDown();
- break;
- }
-
- case kWhatSwitchDown:
- {
- onSwitchDown();
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+ if (generation == mPollBufferingGeneration) {
+ onPollBuffering();
+ }
break;
}
@@ -691,6 +639,14 @@
return;
}
+ // create looper for fetchers
+ if (mFetcherLooper == NULL) {
+ mFetcherLooper = new ALooper();
+
+ mFetcherLooper->setName("Fetcher");
+ mFetcherLooper->start(false, false);
+ }
+
// We trust the content provider to make a reasonable choice of preferred
// initial bandwidth by listing it first in the variant playlist.
// At startup we really don't have a good estimate on the available
@@ -709,7 +665,6 @@
AString uri;
mPlaylist->itemAt(i, &uri, &meta);
- unsigned long bandwidth;
CHECK(meta->findInt32("bandwidth", (int32_t *)&item.mBandwidth));
if (initialBandwidth == 0) {
@@ -740,25 +695,26 @@
mPlaylist->pickRandomMediaItems();
changeConfiguration(
0ll /* timeUs */, initialBandwidthIndex, false /* pickTrack */);
+
+ schedulePollBuffering();
}
void LiveSession::finishDisconnect() {
// No reconfiguration is currently pending, make sure none will trigger
// during disconnection either.
- cancelCheckBandwidthEvent();
// Protect mPacketSources from a swapPacketSource race condition through disconnect.
// (finishDisconnect, onFinishDisconnect2)
cancelBandwidthSwitch();
- // cancel switch down monitor
- mSwitchDownMonitor.clear();
+ // cancel buffer polling
+ cancelPollBuffering();
for (size_t i = 0; i < mFetcherInfos.size(); ++i) {
mFetcherInfos.valueAt(i).mFetcher->stopAsync();
}
- sp<AMessage> msg = new AMessage(kWhatFinishDisconnect2, id());
+ sp<AMessage> msg = new AMessage(kWhatFinishDisconnect2, this);
mContinuationCounter = mFetcherInfos.size();
mContinuation = msg;
@@ -791,7 +747,7 @@
return NULL;
}
- sp<AMessage> notify = new AMessage(kWhatFetcherNotify, id());
+ sp<AMessage> notify = new AMessage(kWhatFetcherNotify, this);
notify->setString("uri", uri);
notify->setInt32("switchGeneration", mSwitchGeneration);
@@ -800,7 +756,7 @@
info.mDurationUs = -1ll;
info.mIsPrepared = false;
info.mToBeRemoved = false;
- looper()->registerHandler(info.mFetcher);
+ mFetcherLooper->registerHandler(info.mFetcher);
mFetcherInfos.add(uri, info);
@@ -847,11 +803,11 @@
headers.add(
String8("Range"),
String8(
- StringPrintf(
+ AStringPrintf(
"bytes=%lld-%s",
range_offset,
range_length < 0
- ? "" : StringPrintf("%lld",
+ ? "" : AStringPrintf("%lld",
range_offset + range_length - 1).c_str()).c_str()));
}
status_t err = mHTTPDataSource->connect(url, &headers);
@@ -990,9 +946,11 @@
return playlist;
}
+#if 0
static double uniformRand() {
return (double)rand() / RAND_MAX;
}
+#endif
size_t LiveSession::getBandwidthIndex() {
if (mBandwidthItems.size() == 0) {
@@ -1184,7 +1142,7 @@
++mSubtitleGeneration;
status_t err = mPlaylist->selectTrack(index, select);
if (err == OK) {
- sp<AMessage> msg = new AMessage(kWhatChangeConfiguration, id());
+ sp<AMessage> msg = new AMessage(kWhatChangeConfiguration, this);
msg->setInt32("bandwidthIndex", mCurBandwidthIndex);
msg->setInt32("pickTrack", select);
msg->post();
@@ -1200,19 +1158,6 @@
}
}
-bool LiveSession::canSwitchUp() {
- // Allow upwards bandwidth switch when a stream has buffered at least 10 seconds.
- status_t err = OK;
- for (size_t i = 0; i < mPacketSources.size(); ++i) {
- sp<AnotherPacketSource> source = mPacketSources.valueAt(i);
- int64_t dur = source->getBufferedDurationUs(&err);
- if (err == OK && dur > 10000000) {
- return true;
- }
- }
- return false;
-}
-
void LiveSession::changeConfiguration(
int64_t timeUs, size_t bandwidthIndex, bool pickTrack) {
// Protect mPacketSources from a swapPacketSource race condition through reconfiguration.
@@ -1272,9 +1217,9 @@
sp<AMessage> msg;
if (timeUs < 0ll) {
// skip onChangeConfiguration2 (decoder destruction) if not seeking.
- msg = new AMessage(kWhatChangeConfiguration3, id());
+ msg = new AMessage(kWhatChangeConfiguration3, this);
} else {
- msg = new AMessage(kWhatChangeConfiguration2, id());
+ msg = new AMessage(kWhatChangeConfiguration2, this);
}
msg->setInt32("streamMask", streamMask);
msg->setInt32("resumeMask", resumeMask);
@@ -1295,14 +1240,6 @@
if (mContinuationCounter == 0) {
msg->post();
-
- if (mSeekReplyID != 0) {
- CHECK(mSeekReply != NULL);
- mSeekReply->setInt32("err", OK);
- mSeekReply->postReply(mSeekReplyID);
- mSeekReplyID = 0;
- mSeekReply.clear();
- }
}
}
@@ -1322,6 +1259,30 @@
// All fetchers are either suspended or have been removed now.
+ // If we're seeking, clear all packet sources before we report
+ // seek complete, to prevent decoder from pulling stale data.
+ int64_t timeUs;
+ CHECK(msg->findInt64("timeUs", &timeUs));
+
+ if (timeUs >= 0) {
+ mLastSeekTimeUs = timeUs;
+
+ for (size_t i = 0; i < mPacketSources.size(); i++) {
+ mPacketSources.editValueAt(i)->clear();
+ }
+
+ mDiscontinuityOffsetTimesUs.clear();
+ mDiscontinuityAbsStartTimesUs.clear();
+
+ if (mSeekReplyID != 0) {
+ CHECK(mSeekReply != NULL);
+ mSeekReply->setInt32("err", OK);
+ mSeekReply->postReply(mSeekReplyID);
+ mSeekReplyID = 0;
+ mSeekReply.clear();
+ }
+ }
+
uint32_t streamMask, resumeMask;
CHECK(msg->findInt32("streamMask", (int32_t *)&streamMask));
CHECK(msg->findInt32("resumeMask", (int32_t *)&resumeMask));
@@ -1371,7 +1332,7 @@
notify->setInt32("changedMask", changedMask);
msg->setWhat(kWhatChangeConfiguration3);
- msg->setTarget(id());
+ msg->setTarget(this);
notify->setMessage("reply", msg);
notify->post();
@@ -1427,19 +1388,8 @@
for (size_t j = 0; j < kMaxStreams; ++j) {
if ((resumeMask & indexToType(j)) && uri == mStreams[j].mUri) {
sources[j] = mPacketSources.valueFor(indexToType(j));
-
- if (j != kSubtitleIndex) {
- ALOGV("queueing dummy discontinuity for stream type %d", indexToType(j));
- sp<AnotherPacketSource> discontinuityQueue;
- discontinuityQueue = mDiscontinuities.valueFor(indexToType(j));
- discontinuityQueue->queueDiscontinuity(
- ATSParser::DISCONTINUITY_NONE,
- NULL,
- true);
- }
}
}
-
FetcherInfo &info = mFetcherInfos.editValueAt(i);
if (sources[kAudioIndex] != NULL || sources[kVideoIndex] != NULL
|| sources[kSubtitleIndex] != NULL) {
@@ -1469,7 +1419,6 @@
sp<PlaylistFetcher> fetcher = addFetcher(uri.c_str());
CHECK(fetcher != NULL);
- int32_t latestSeq = -1;
int64_t startTimeUs = -1;
int64_t segmentStartTimeUs = -1ll;
int32_t discontinuitySeq = -1;
@@ -1486,18 +1435,9 @@
sources[j] = mPacketSources.valueFor(indexToType(j));
if (timeUs >= 0) {
- sources[j]->clear();
startTimeUs = timeUs;
-
- sp<AnotherPacketSource> discontinuityQueue;
- sp<AMessage> extra = new AMessage;
- extra->setInt64("timeUs", timeUs);
- discontinuityQueue = mDiscontinuities.valueFor(indexToType(j));
- discontinuityQueue->queueDiscontinuity(
- ATSParser::DISCONTINUITY_TIME, extra, true);
} else {
int32_t type;
- int64_t srcSegmentStartTimeUs;
sp<AMessage> meta;
if (pickTrack) {
// selecting
@@ -1533,9 +1473,10 @@
if (j == kSubtitleIndex) {
break;
}
- sp<AnotherPacketSource> discontinuityQueue;
- discontinuityQueue = mDiscontinuities.valueFor(indexToType(j));
- discontinuityQueue->queueDiscontinuity(
+
+ ALOGV("stream[%d]: queue format change", j);
+
+ sources[j]->queueDiscontinuity(
ATSParser::DISCONTINUITY_FORMATCHANGE, NULL, true);
} else {
// adapting, queue discontinuities after resume
@@ -1565,9 +1506,6 @@
// All fetchers have now been started, the configuration change
// has completed.
- cancelCheckBandwidthEvent();
- scheduleCheckBandwidthEvent();
-
ALOGV("XXX configuration change completed.");
mReconfigurationInProgress = false;
if (switching) {
@@ -1624,47 +1562,35 @@
tryToFinishBandwidthSwitch();
}
-void LiveSession::onCheckSwitchDown() {
- if (mSwitchDownMonitor == NULL) {
- return;
- }
+void LiveSession::schedulePollBuffering() {
+ sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
+ msg->setInt32("generation", mPollBufferingGeneration);
+ msg->post(1000000ll);
+}
- if (mSwitchInProgress || mReconfigurationInProgress) {
- ALOGV("Switch/Reconfig in progress, defer switch down");
- mSwitchDownMonitor->post(1000000ll);
- return;
- }
+void LiveSession::cancelPollBuffering() {
+ ++mPollBufferingGeneration;
+}
- for (size_t i = 0; i < kMaxStreams; ++i) {
- int32_t targetDuration;
- sp<AnotherPacketSource> packetSource = mPacketSources.valueFor(indexToType(i));
- sp<AMessage> meta = packetSource->getLatestDequeuedMeta();
+void LiveSession::onPollBuffering() {
+ ALOGV("onPollBuffering: mSwitchInProgress %d, mReconfigurationInProgress %d, "
+ "mInPreparationPhase %d, mStreamMask 0x%x",
+ mSwitchInProgress, mReconfigurationInProgress,
+ mInPreparationPhase, mStreamMask);
- if (meta != NULL && meta->findInt32("targetDuration", &targetDuration) ) {
- int64_t bufferedDurationUs = packetSource->getEstimatedDurationUs();
- int64_t targetDurationUs = targetDuration * 1000000ll;
+ bool low, mid, high;
+ if (checkBuffering(low, mid, high)) {
+ if (mInPreparationPhase && mid) {
+ postPrepared(OK);
+ }
- if (bufferedDurationUs < targetDurationUs / 3) {
- (new AMessage(kWhatSwitchDown, id()))->post();
- break;
- }
+ // don't switch before we report prepared
+ if (!mInPreparationPhase && (low || high)) {
+ switchBandwidthIfNeeded(high);
}
}
- mSwitchDownMonitor->post(1000000ll);
-}
-
-void LiveSession::onSwitchDown() {
- if (mReconfigurationInProgress || mSwitchInProgress || mCurBandwidthIndex == 0) {
- return;
- }
-
- ssize_t bandwidthIndex = getBandwidthIndex();
- if (bandwidthIndex < mCurBandwidthIndex) {
- changeConfiguration(-1, bandwidthIndex, false);
- return;
- }
-
+ schedulePollBuffering();
}
// Mark switch done when:
@@ -1689,16 +1615,6 @@
}
}
-void LiveSession::scheduleCheckBandwidthEvent() {
- sp<AMessage> msg = new AMessage(kWhatCheckBandwidth, id());
- msg->setInt32("generation", mCheckBandwidthGeneration);
- msg->post(10000000ll);
-}
-
-void LiveSession::cancelCheckBandwidthEvent() {
- ++mCheckBandwidthGeneration;
-}
-
void LiveSession::cancelBandwidthSwitch() {
Mutex::Autolock lock(mSwapMutex);
mSwitchGeneration++;
@@ -1728,33 +1644,69 @@
}
}
-bool LiveSession::canSwitchBandwidthTo(size_t bandwidthIndex) {
- if (mReconfigurationInProgress || mSwitchInProgress) {
+bool LiveSession::checkBuffering(bool &low, bool &mid, bool &high) {
+ low = mid = high = false;
+
+ if (mSwitchInProgress || mReconfigurationInProgress) {
+ ALOGV("Switch/Reconfig in progress, defer buffer polling");
return false;
}
- if (mCurBandwidthIndex < 0) {
+ // TODO: Fine tune low/high mark.
+ // We also need to pause playback if buffering is too low.
+ // Currently during underflow, we depend on decoder to starve
+ // to pause, but A/V could have different buffering left,
+ // they're not paused together.
+ // TODO: Report buffering level to NuPlayer for BUFFERING_UPDATE
+
+ // Switch down if any of the fetchers are below low mark;
+ // Switch up if all of the fetchers are over high mark.
+ size_t activeCount, lowCount, midCount, highCount;
+ activeCount = lowCount = midCount = highCount = 0;
+ for (size_t i = 0; i < mPacketSources.size(); ++i) {
+ // we don't check subtitles for buffering level
+ if (!(mStreamMask & mPacketSources.keyAt(i)
+ & (STREAMTYPE_AUDIO | STREAMTYPE_VIDEO))) {
+ continue;
+ }
+ // ignore streams that never had any packet queued.
+ // (it's possible that the variant only has audio or video)
+ sp<AMessage> meta = mPacketSources[i]->getLatestEnqueuedMeta();
+ if (meta == NULL) {
+ continue;
+ }
+
+ ++activeCount;
+ int64_t bufferedDurationUs =
+ mPacketSources[i]->getEstimatedDurationUs();
+ ALOGV("source[%d]: buffered %lld us", i, bufferedDurationUs);
+ if (bufferedDurationUs < kLowWaterMark) {
+ ++lowCount;
+ break;
+ } else if (bufferedDurationUs > kHighWaterMark) {
+ ++midCount;
+ ++highCount;
+ } else if (bufferedDurationUs > kMidWaterMark) {
+ ++midCount;
+ }
+ }
+
+ if (activeCount > 0) {
+ high = (highCount == activeCount);
+ mid = (midCount == activeCount);
+ low = (lowCount > 0);
return true;
}
- if (bandwidthIndex == (size_t)mCurBandwidthIndex) {
- return false;
- } else if (bandwidthIndex > (size_t)mCurBandwidthIndex) {
- return canSwitchUp();
- } else {
- return true;
- }
+ return false;
}
-void LiveSession::onCheckBandwidth(const sp<AMessage> &msg) {
- size_t bandwidthIndex = getBandwidthIndex();
- if (canSwitchBandwidthTo(bandwidthIndex)) {
- changeConfiguration(-1ll /* timeUs */, bandwidthIndex);
- } else {
- // Come back and check again 10 seconds later in case there is nothing to do now.
- // If we DO change configuration, once that completes it'll schedule a new
- // check bandwidth event with an incremented mCheckBandwidthGeneration.
- msg->post(10000000ll);
+void LiveSession::switchBandwidthIfNeeded(bool canSwitchUp) {
+ ssize_t bandwidthIndex = getBandwidthIndex();
+
+ if ((canSwitchUp && bandwidthIndex > mCurBandwidthIndex)
+ || (!canSwitchUp && bandwidthIndex < mCurBandwidthIndex)) {
+ changeConfiguration(-1, bandwidthIndex, false);
}
}
@@ -1772,10 +1724,8 @@
notify->post();
mInPreparationPhase = false;
-
- mSwitchDownMonitor = new AMessage(kWhatCheckSwitchDown, id());
- mSwitchDownMonitor->post();
}
+
} // namespace android
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index dfb5e59..3b0a9a4 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -26,6 +26,7 @@
namespace android {
struct ABuffer;
+struct AReplyToken;
struct AnotherPacketSource;
struct DataSource;
struct HTTPBase;
@@ -33,17 +34,12 @@
struct LiveDataSource;
struct M3UParser;
struct PlaylistFetcher;
-struct Parcel;
struct LiveSession : public AHandler {
enum Flags {
// Don't log any URLs.
kFlagIncognito = 1,
};
- LiveSession(
- const sp<AMessage> ¬ify,
- uint32_t flags,
- const sp<IMediaHTTPService> &httpService);
enum StreamIndex {
kAudioIndex = 0,
@@ -57,6 +53,12 @@
STREAMTYPE_VIDEO = 1 << kVideoIndex,
STREAMTYPE_SUBTITLES = 1 << kSubtitleIndex,
};
+
+ LiveSession(
+ const sp<AMessage> ¬ify,
+ uint32_t flags,
+ const sp<IMediaHTTPService> &httpService);
+
status_t dequeueAccessUnit(StreamType stream, sp<ABuffer> *accessUnit);
status_t getStreamFormat(StreamType stream, sp<AMessage> *format);
@@ -110,11 +112,13 @@
kWhatChangeConfiguration3 = 'chC3',
kWhatFinishDisconnect2 = 'fin2',
kWhatSwapped = 'swap',
- kWhatCheckSwitchDown = 'ckSD',
- kWhatSwitchDown = 'sDwn',
+ kWhatPollBuffering = 'poll',
};
static const size_t kBandwidthHistoryBytes;
+ static const int64_t kHighWaterMark;
+ static const int64_t kMidWaterMark;
+ static const int64_t kLowWaterMark;
struct BandwidthItem {
size_t mPlaylistIndex;
@@ -169,6 +173,7 @@
sp<M3UParser> mPlaylist;
+ sp<ALooper> mFetcherLooper;
KeyedVector<AString, FetcherInfo> mFetcherInfos;
uint32_t mStreamMask;
@@ -181,7 +186,6 @@
// we use this to track reconfiguration progress.
uint32_t mSwapMask;
- KeyedVector<StreamType, sp<AnotherPacketSource> > mDiscontinuities;
KeyedVector<StreamType, sp<AnotherPacketSource> > mPacketSources;
// A second set of packet sources that buffer content for the variant we're switching to.
KeyedVector<StreamType, sp<AnotherPacketSource> > mPacketSources2;
@@ -204,16 +208,17 @@
bool mReconfigurationInProgress;
bool mSwitchInProgress;
- uint32_t mDisconnectReplyID;
- uint32_t mSeekReplyID;
+ sp<AReplyToken> mDisconnectReplyID;
+ sp<AReplyToken> mSeekReplyID;
bool mFirstTimeUsValid;
int64_t mFirstTimeUs;
int64_t mLastSeekTimeUs;
- sp<AMessage> mSwitchDownMonitor;
KeyedVector<size_t, int64_t> mDiscontinuityAbsStartTimesUs;
KeyedVector<size_t, int64_t> mDiscontinuityOffsetTimesUs;
+ int32_t mPollBufferingGeneration;
+
sp<PlaylistFetcher> addFetcher(const char *uri);
void onConnect(const sp<AMessage> &msg);
@@ -257,27 +262,24 @@
void onChangeConfiguration2(const sp<AMessage> &msg);
void onChangeConfiguration3(const sp<AMessage> &msg);
void onSwapped(const sp<AMessage> &msg);
- void onCheckSwitchDown();
- void onSwitchDown();
void tryToFinishBandwidthSwitch();
- void scheduleCheckBandwidthEvent();
- void cancelCheckBandwidthEvent();
-
// cancelBandwidthSwitch is atomic wrt swapPacketSource; call it to prevent packet sources
// from being swapped out on stale discontinuities while manipulating
// mPacketSources/mPacketSources2.
void cancelBandwidthSwitch();
- bool canSwitchBandwidthTo(size_t bandwidthIndex);
- void onCheckBandwidth(const sp<AMessage> &msg);
+ void schedulePollBuffering();
+ void cancelPollBuffering();
+ void onPollBuffering();
+ bool checkBuffering(bool &low, bool &mid, bool &high);
+ void switchBandwidthIfNeeded(bool canSwitchUp);
void finishDisconnect();
void postPrepared(status_t err);
void swapPacketSource(StreamType stream);
- bool canSwitchUp();
DISALLOW_EVIL_CONSTRUCTORS(LiveSession);
};
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 00e52ee..3710686 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -49,6 +49,7 @@
// static
const int64_t PlaylistFetcher::kMinBufferedDurationUs = 10000000ll;
const int64_t PlaylistFetcher::kMaxMonitorDelayUs = 3000000ll;
+const int64_t PlaylistFetcher::kFetcherResumeThreshold = 100000ll;
// LCM of 188 (size of a TS packet) & 1k works well
const int32_t PlaylistFetcher::kDownloadBlockSize = 47 * 1024;
const int32_t PlaylistFetcher::kNumSkipFrames = 5;
@@ -291,7 +292,6 @@
}
status_t PlaylistFetcher::checkDecryptPadding(const sp<ABuffer> &buffer) {
- status_t err;
AString method;
CHECK(buffer->meta()->findString("cipher-method", &method));
if (method == "NONE") {
@@ -326,7 +326,7 @@
ALOGV("Need to refresh playlist in %" PRId64 , maxDelayUs);
delayUs = maxDelayUs;
}
- sp<AMessage> msg = new AMessage(kWhatMonitorQueue, id());
+ sp<AMessage> msg = new AMessage(kWhatMonitorQueue, this);
msg->setInt32("generation", mMonitorQueueGeneration);
msg->post(delayUs);
}
@@ -343,7 +343,7 @@
int64_t segmentStartTimeUs,
int32_t startDiscontinuitySeq,
bool adaptive) {
- sp<AMessage> msg = new AMessage(kWhatStart, id());
+ sp<AMessage> msg = new AMessage(kWhatStart, this);
uint32_t streamTypeMask = 0ul;
@@ -371,17 +371,17 @@
}
void PlaylistFetcher::pauseAsync() {
- (new AMessage(kWhatPause, id()))->post();
+ (new AMessage(kWhatPause, this))->post();
}
void PlaylistFetcher::stopAsync(bool clear) {
- sp<AMessage> msg = new AMessage(kWhatStop, id());
+ sp<AMessage> msg = new AMessage(kWhatStop, this);
msg->setInt32("clear", clear);
msg->post();
}
void PlaylistFetcher::resumeUntilAsync(const sp<AMessage> ¶ms) {
- AMessage* msg = new AMessage(kWhatResumeUntil, id());
+ AMessage* msg = new AMessage(kWhatResumeUntil, this);
msg->setMessage("params", params);
msg->post();
}
@@ -536,12 +536,19 @@
sp<AMessage> params;
CHECK(msg->findMessage("params", ¶ms));
- bool stop = false;
+ size_t stopCount = 0;
for (size_t i = 0; i < mPacketSources.size(); i++) {
sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
const char *stopKey;
int streamType = mPacketSources.keyAt(i);
+
+ if (streamType == LiveSession::STREAMTYPE_SUBTITLES) {
+ // the subtitle track can always be stopped
+ ++stopCount;
+ continue;
+ }
+
switch (streamType) {
case LiveSession::STREAMTYPE_VIDEO:
stopKey = "timeUsVideo";
@@ -551,15 +558,11 @@
stopKey = "timeUsAudio";
break;
- case LiveSession::STREAMTYPE_SUBTITLES:
- stopKey = "timeUsSubtitle";
- break;
-
default:
TRESPASS();
}
- // Don't resume if we would stop within a resume threshold.
+ // check if this stream has too little data left to be resumed
int32_t discontinuitySeq;
int64_t latestTimeUs = 0, stopTimeUs = 0;
sp<AMessage> latestMeta = packetSource->getLatestEnqueuedMeta();
@@ -568,12 +571,13 @@
&& discontinuitySeq == mDiscontinuitySeq
&& latestMeta->findInt64("timeUs", &latestTimeUs)
&& params->findInt64(stopKey, &stopTimeUs)
- && stopTimeUs - latestTimeUs < resumeThreshold(latestMeta)) {
- stop = true;
+ && stopTimeUs - latestTimeUs < kFetcherResumeThreshold) {
+ ++stopCount;
}
}
- if (stop) {
+ // Don't resume if all streams are within a resume threshold
+ if (stopCount == mPacketSources.size()) {
for (size_t i = 0; i < mPacketSources.size(); i++) {
mPacketSources.valueAt(i)->queueAccessUnit(mSession->createFormatChangeBuffer());
}
@@ -582,7 +586,7 @@
}
mStopParams = params;
- postMonitorQueue();
+ onDownloadNext();
return OK;
}
@@ -661,9 +665,6 @@
ALOGV("prepared, buffered=%" PRId64 " > %" PRId64 "",
bufferedDurationUs, targetDurationUs);
- sp<AMessage> msg = mNotify->dup();
- msg->setInt32("what", kWhatTemporarilyDoneFetching);
- msg->post();
}
if (finalResult == OK && downloadMore) {
@@ -672,16 +673,11 @@
// delay the next download slightly; hopefully this gives other concurrent fetchers
// a better chance to run.
// onDownloadNext();
- sp<AMessage> msg = new AMessage(kWhatDownloadNext, id());
+ sp<AMessage> msg = new AMessage(kWhatDownloadNext, this);
msg->setInt32("generation", mMonitorQueueGeneration);
msg->post(1000l);
} else {
// Nothing to do yet, try again in a second.
-
- sp<AMessage> msg = mNotify->dup();
- msg->setInt32("what", kWhatTemporarilyDoneFetching);
- msg->post();
-
int64_t delayUs = mPrepared ? kMaxMonitorDelayUs : targetDurationUs / 2;
ALOGV("pausing for %" PRId64 ", buffered=%" PRId64 " > %" PRId64 "",
delayUs, bufferedDurationUs, durationToBufferUs);
@@ -1547,7 +1543,7 @@
CHECK_EQ(bits.getBits(12), 0xfffu);
bits.skipBits(3); // ID, layer
- bool protection_absent = bits.getBits(1) != 0;
+ bool protection_absent __unused = bits.getBits(1) != 0;
unsigned profile = bits.getBits(2);
CHECK_NE(profile, 3u);
@@ -1688,33 +1684,4 @@
msg->post();
}
-int64_t PlaylistFetcher::resumeThreshold(const sp<AMessage> &msg) {
- int64_t durationUs, threshold;
- if (msg->findInt64("durationUs", &durationUs) && durationUs > 0) {
- return kNumSkipFrames * durationUs;
- }
-
- sp<RefBase> obj;
- msg->findObject("format", &obj);
- MetaData *format = static_cast<MetaData *>(obj.get());
-
- const char *mime;
- CHECK(format->findCString(kKeyMIMEType, &mime));
- bool audio = !strncasecmp(mime, "audio/", 6);
- if (audio) {
- // Assumes 1000 samples per frame.
- int32_t sampleRate;
- CHECK(format->findInt32(kKeySampleRate, &sampleRate));
- return kNumSkipFrames /* frames */ * 1000 /* samples */
- * (1000000 / sampleRate) /* sample duration (us) */;
- } else {
- int32_t frameRate;
- if (format->findInt32(kKeyFrameRate, &frameRate) && frameRate > 0) {
- return kNumSkipFrames * (1000000 / frameRate);
- }
- }
-
- return 500000ll;
-}
-
} // namespace android
diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h
index 67161a9..2f11949 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.h
+++ b/media/libstagefright/httplive/PlaylistFetcher.h
@@ -31,11 +31,12 @@
struct HTTPBase;
struct LiveDataSource;
struct M3UParser;
-struct String8;
+class String8;
struct PlaylistFetcher : public AHandler {
static const int64_t kMinBufferedDurationUs;
static const int32_t kDownloadBlockSize;
+ static const int64_t kFetcherResumeThreshold;
enum {
kWhatStarted,
@@ -43,7 +44,6 @@
kWhatStopped,
kWhatError,
kWhatDurationUpdate,
- kWhatTemporarilyDoneFetching,
kWhatPrepared,
kWhatPreparationFailed,
kWhatStartedAt,
@@ -212,10 +212,6 @@
void updateDuration();
- // Before resuming a fetcher in onResume, check the remaining duration is longer than that
- // returned by resumeThreshold.
- int64_t resumeThreshold(const sp<AMessage> &msg);
-
DISALLOW_EVIL_CONSTRUCTORS(PlaylistFetcher);
};
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 7f221a0..d9491d6 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -630,7 +630,10 @@
| (mParent.mData[mOffset + 4] << 8)
| mParent.mData[mOffset + 5];
- mFrameSize += 6;
+ if (mFrameSize == 0) {
+ return;
+ }
+ mFrameSize += 6; // add tag id and size field
if (mOffset + mFrameSize > mParent.mSize) {
ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)",
@@ -671,7 +674,11 @@
baseSize = U32_AT(&mParent.mData[mOffset + 4]);
}
- mFrameSize = 10 + baseSize;
+ if (baseSize == 0) {
+ return;
+ }
+
+ mFrameSize = 10 + baseSize; // add tag id, size field and flags
if (mOffset + mFrameSize > mParent.mSize) {
ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)",
@@ -793,8 +800,8 @@
mime->setTo((const char *)&data[1]);
size_t mimeLen = strlen((const char *)&data[1]) + 1;
- uint8_t picType = data[1 + mimeLen];
#if 0
+ uint8_t picType = data[1 + mimeLen];
if (picType != 0x03) {
// Front Cover Art
it.next();
diff --git a/media/libstagefright/include/AACEncoder.h b/media/libstagefright/include/AACEncoder.h
index 3d5fc60..52beb0e 100644
--- a/media/libstagefright/include/AACEncoder.h
+++ b/media/libstagefright/include/AACEncoder.h
@@ -25,7 +25,7 @@
namespace android {
-struct MediaBufferGroup;
+class MediaBufferGroup;
class AACEncoder: public MediaSource {
public:
diff --git a/media/libstagefright/include/ID3.h b/media/libstagefright/include/ID3.h
index e83f3ef..c2c4a6d 100644
--- a/media/libstagefright/include/ID3.h
+++ b/media/libstagefright/include/ID3.h
@@ -22,8 +22,8 @@
namespace android {
-struct DataSource;
-struct String8;
+class DataSource;
+class String8;
struct ID3 {
enum Version {
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/libstagefright/include/MPEG2TSExtractor.h
index c5e86a6..db1187d 100644
--- a/media/libstagefright/include/MPEG2TSExtractor.h
+++ b/media/libstagefright/include/MPEG2TSExtractor.h
@@ -28,7 +28,7 @@
struct AMessage;
struct AnotherPacketSource;
struct ATSParser;
-struct DataSource;
+class DataSource;
struct MPEG2TSSource;
struct String8;
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index 1fe6fcf..8c16251 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -83,6 +83,8 @@
Vector<SidxEntry> mSidxEntries;
off64_t mMoofOffset;
+ bool mMoofFound;
+ bool mMdatFound;
Vector<PsshInfo> mPssh;
diff --git a/media/libstagefright/include/MidiExtractor.h b/media/libstagefright/include/MidiExtractor.h
new file mode 100644
index 0000000..9a2abc0
--- /dev/null
+++ b/media/libstagefright/include/MidiExtractor.h
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#ifndef MIDI_EXTRACTOR_H_
+#define MIDI_EXTRACTOR_H_
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/MidiIoWrapper.h>
+#include <utils/String8.h>
+#include <libsonivox/eas.h>
+
+namespace android {
+
+class MidiEngine : public RefBase {
+public:
+ MidiEngine(const sp<DataSource> &dataSource,
+ const sp<MetaData> &fileMetadata,
+ const sp<MetaData> &trackMetadata);
+ ~MidiEngine();
+
+ status_t initCheck();
+
+ status_t allocateBuffers();
+ status_t releaseBuffers();
+ status_t seekTo(int64_t positionUs);
+ MediaBuffer* readBuffer();
+private:
+ sp<MidiIoWrapper> mIoWrapper;
+ MediaBufferGroup *mGroup;
+ EAS_DATA_HANDLE mEasData;
+ EAS_HANDLE mEasHandle;
+ const S_EAS_LIB_CONFIG* mEasConfig;
+ bool mIsInitialized;
+};
+
+class MidiExtractor : public MediaExtractor {
+
+public:
+ // Extractor assumes ownership of source
+ MidiExtractor(const sp<DataSource> &source);
+
+ virtual size_t countTracks();
+ virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
+
+ virtual sp<MetaData> getMetaData();
+
+protected:
+ virtual ~MidiExtractor();
+
+private:
+ sp<DataSource> mDataSource;
+ status_t mInitCheck;
+ sp<MetaData> mFileMetadata;
+
+ // There is only one track
+ sp<MetaData> mTrackMetadata;
+
+ sp<MidiEngine> mEngine;
+
+ EAS_DATA_HANDLE mEasData;
+ EAS_HANDLE mEasHandle;
+ EAS_PCM* mAudioBuffer;
+ EAS_I32 mPlayTime;
+ EAS_I32 mDuration;
+ EAS_STATE mState;
+ EAS_FILE mFileLocator;
+
+ MidiExtractor(const MidiExtractor &);
+ MidiExtractor &operator=(const MidiExtractor &);
+
+};
+
+bool SniffMidi(const sp<DataSource> &source, String8 *mimeType,
+ float *confidence, sp<AMessage> *);
+
+} // namespace android
+
+#endif // MIDI_EXTRACTOR_H_
diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/include/avc_utils.h
index d517320..dafa07e 100644
--- a/media/libstagefright/include/avc_utils.h
+++ b/media/libstagefright/include/avc_utils.h
@@ -23,7 +23,7 @@
namespace android {
-struct ABitReader;
+class ABitReader;
enum {
kAVCProfileBaseline = 0x42,
@@ -36,6 +36,11 @@
kAVCProfileCAVLC444Intra = 0x2c
};
+struct NALPosition {
+ size_t nalOffset;
+ size_t nalSize;
+};
+
// Optionally returns sample aspect ratio as well.
void FindAVCDimensions(
const sp<ABuffer> &seqParamSet,
@@ -49,7 +54,7 @@
const uint8_t **nalStart, size_t *nalSize,
bool startCodeFollows = false);
-struct MetaData;
+class MetaData;
sp<MetaData> MakeAVCCodecSpecificData(const sp<ABuffer> &accessUnit);
bool IsIDR(const sp<ABuffer> &accessUnit);
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 4f0862c..0712bf0 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -500,17 +500,6 @@
return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
}
-static size_t clz(uint8_t x) {
- size_t numLeadingZeroes = 0;
-
- while (!(x & 0x80)) {
- ++numLeadingZeroes;
- x = x << 1;
- }
-
- return numLeadingZeroes;
-}
-
void MatroskaSource::clearPendingFrames() {
while (!mPendingFrames.empty()) {
MediaBuffer *frame = *mPendingFrames.begin();
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 482ccff..6786506 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -35,6 +35,7 @@
#include <media/stagefright/Utils.h>
#include <media/IStreamSource.h>
#include <utils/KeyedVector.h>
+#include <utils/Vector.h>
#include <inttypes.h>
@@ -86,14 +87,22 @@
}
private:
+ struct StreamInfo {
+ unsigned mType;
+ unsigned mPID;
+ };
+
ATSParser *mParser;
unsigned mProgramNumber;
unsigned mProgramMapPID;
KeyedVector<unsigned, sp<Stream> > mStreams;
bool mFirstPTSValid;
uint64_t mFirstPTS;
+ int64_t mLastRecoveredPTS;
status_t parseProgramMap(ABitReader *br);
+ int64_t recoverPTS(uint64_t PTS_33bit);
+ bool switchPIDs(const Vector<StreamInfo> &infos);
DISALLOW_EVIL_CONSTRUCTORS(Program);
};
@@ -182,7 +191,8 @@
mProgramNumber(programNumber),
mProgramMapPID(programMapPID),
mFirstPTSValid(false),
- mFirstPTS(0) {
+ mFirstPTS(0),
+ mLastRecoveredPTS(-1ll) {
ALOGV("new program number %u", programNumber);
}
@@ -237,10 +247,71 @@
}
}
-struct StreamInfo {
- unsigned mType;
- unsigned mPID;
-};
+bool ATSParser::Program::switchPIDs(const Vector<StreamInfo> &infos) {
+ bool success = false;
+
+ if (mStreams.size() == infos.size()) {
+ // build type->PIDs map for old and new mapping
+ size_t i;
+ KeyedVector<int32_t, Vector<int32_t> > oldType2PIDs, newType2PIDs;
+ for (i = 0; i < mStreams.size(); ++i) {
+ ssize_t index = oldType2PIDs.indexOfKey(mStreams[i]->type());
+ if (index < 0) {
+ oldType2PIDs.add(mStreams[i]->type(), Vector<int32_t>());
+ }
+ oldType2PIDs.editValueFor(mStreams[i]->type()).push_back(mStreams[i]->pid());
+ }
+ for (i = 0; i < infos.size(); ++i) {
+ ssize_t index = newType2PIDs.indexOfKey(infos[i].mType);
+ if (index < 0) {
+ newType2PIDs.add(infos[i].mType, Vector<int32_t>());
+ }
+ newType2PIDs.editValueFor(infos[i].mType).push_back(infos[i].mPID);
+ }
+
+ // we can recover if the number of streams for each type hasn't changed
+ if (oldType2PIDs.size() == newType2PIDs.size()) {
+ success = true;
+ for (i = 0; i < oldType2PIDs.size(); ++i) {
+ // KeyedVector is sorted, we just compare key and size of each index
+ if (oldType2PIDs.keyAt(i) != newType2PIDs.keyAt(i)
+ || oldType2PIDs[i].size() != newType2PIDs[i].size()) {
+ success = false;
+ break;
+ }
+ }
+ }
+
+ if (success) {
+ // save current streams to temp
+ KeyedVector<int32_t, sp<Stream> > temp;
+ for (i = 0; i < mStreams.size(); ++i) {
+ temp.add(mStreams.keyAt(i), mStreams.editValueAt(i));
+ }
+
+ mStreams.clear();
+ for (i = 0; i < temp.size(); ++i) {
+ // The two checks below shouldn't happen,
+ // we already checked above the stream count matches
+ ssize_t index = newType2PIDs.indexOfKey(temp[i]->type());
+ CHECK(index >= 0);
+ Vector<int32_t> &newPIDs = newType2PIDs.editValueAt(index);
+ CHECK(newPIDs.size() > 0);
+
+ // get the next PID for temp[i]->type() in the new PID map
+ Vector<int32_t>::iterator it = newPIDs.begin();
+
+ // change the PID of the stream, and add it back
+ temp.editValueAt(i)->setPID(*it);
+ mStreams.add(temp[i]->pid(), temp.editValueAt(i));
+
+ // removed the used PID
+ newPIDs.erase(it);
+ }
+ }
+ }
+ return success;
+}
status_t ATSParser::Program::parseProgramMap(ABitReader *br) {
unsigned table_id = br->getBits(8);
@@ -369,39 +440,8 @@
}
#endif
- // The only case we can recover from is if we have two streams
- // and they switched PIDs.
-
- bool success = false;
-
- if (mStreams.size() == 2 && infos.size() == 2) {
- const StreamInfo &info1 = infos.itemAt(0);
- const StreamInfo &info2 = infos.itemAt(1);
-
- sp<Stream> s1 = mStreams.editValueAt(0);
- sp<Stream> s2 = mStreams.editValueAt(1);
-
- bool caseA =
- info1.mPID == s1->pid() && info1.mType == s2->type()
- && info2.mPID == s2->pid() && info2.mType == s1->type();
-
- bool caseB =
- info1.mPID == s2->pid() && info1.mType == s1->type()
- && info2.mPID == s1->pid() && info2.mType == s2->type();
-
- if (caseA || caseB) {
- unsigned pid1 = s1->pid();
- unsigned pid2 = s2->pid();
- s1->setPID(pid2);
- s2->setPID(pid1);
-
- mStreams.clear();
- mStreams.add(s1->pid(), s1);
- mStreams.add(s2->pid(), s2);
-
- success = true;
- }
- }
+ // we can recover if number of streams for each type remain the same
+ bool success = switchPIDs(infos);
if (!success) {
ALOGI("Stream PIDs changed and we cannot recover.");
@@ -425,6 +465,32 @@
return OK;
}
+int64_t ATSParser::Program::recoverPTS(uint64_t PTS_33bit) {
+ // We only have the lower 33-bit of the PTS. It could overflow within a
+ // reasonable amount of time. To handle the wrap-around, use fancy math
+ // to get an extended PTS that is within [-0xffffffff, 0xffffffff]
+ // of the latest recovered PTS.
+ if (mLastRecoveredPTS < 0ll) {
+ // Use the original 33bit number for 1st frame, the reason is that
+ // if 1st frame wraps to negative that's far away from 0, we could
+ // never start. Only start wrapping around from 2nd frame.
+ mLastRecoveredPTS = static_cast<int64_t>(PTS_33bit);
+ } else {
+ mLastRecoveredPTS = static_cast<int64_t>(
+ ((mLastRecoveredPTS - 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.
+ // (eg. video is read first and starts at 0, but audio starts at 0xfffffff0)
+ if (mLastRecoveredPTS < 0ll) {
+ ALOGI("Clamping negative recovered PTS (%" PRId64 ") to 0", mLastRecoveredPTS);
+ mLastRecoveredPTS = 0ll;
+ }
+ }
+
+ return mLastRecoveredPTS;
+}
+
sp<MediaSource> ATSParser::Program::getSource(SourceType type) {
size_t index = (type == AUDIO) ? 0 : 0;
@@ -455,6 +521,8 @@
}
int64_t ATSParser::Program::convertPTSToTimestamp(uint64_t PTS) {
+ PTS = recoverPTS(PTS);
+
if (!(mParser->mFlags & TS_TIMESTAMPS_ARE_ABSOLUTE)) {
if (!mFirstPTSValid) {
mFirstPTSValid = true;
@@ -1098,7 +1166,8 @@
if (payload_unit_start_indicator) {
if (!section->isEmpty()) {
- return ERROR_UNSUPPORTED;
+ ALOGW("parsePID encounters payload_unit_start_indicator when section is not empty");
+ section->clear();
}
unsigned skip = br->getBits(8);
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 5d76cbd..75d76dc 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -28,7 +28,7 @@
namespace android {
-struct ABitReader;
+class ABitReader;
struct ABuffer;
struct MediaSource;
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index f266fe7..bb05417 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -91,13 +91,11 @@
while (it != mBuffers.end()) {
sp<ABuffer> buffer = *it;
int32_t discontinuity;
- if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
- break;
- }
-
- sp<RefBase> object;
- if (buffer->meta()->findObject("format", &object)) {
- return mFormat = static_cast<MetaData*>(object.get());
+ if (!buffer->meta()->findInt32("discontinuity", &discontinuity)) {
+ sp<RefBase> object;
+ if (buffer->meta()->findObject("format", &object)) {
+ return mFormat = static_cast<MetaData*>(object.get());
+ }
}
++it;
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 2ed3ccc..88da275 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -63,8 +63,6 @@
const uint8_t *ptr, size_t size, sp<MetaData> *metaData) {
static const unsigned channelCountTable[] = {2, 1, 2, 3, 3, 4, 4, 5};
static const unsigned samplingRateTable[] = {48000, 44100, 32000};
- static const unsigned rates[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256,
- 320, 384, 448, 512, 576, 640};
static const unsigned frameSizeTable[19][3] = {
{ 64, 69, 96 },
@@ -89,7 +87,6 @@
};
ABitReader bits(ptr, size);
- unsigned syncStartPos = 0; // in bytes
if (bits.numBitsLeft() < 16) {
return 0;
}
@@ -121,11 +118,11 @@
return 0;
}
- unsigned bsmod = bits.getBits(3);
+ unsigned bsmod __unused = bits.getBits(3);
unsigned acmod = bits.getBits(3);
- unsigned cmixlev = 0;
- unsigned surmixlev = 0;
- unsigned dsurmod = 0;
+ unsigned cmixlev __unused = 0;
+ unsigned surmixlev __unused = 0;
+ unsigned dsurmod __unused = 0;
if ((acmod & 1) > 0 && acmod != 1) {
if (bits.numBitsLeft() < 2) {
@@ -556,7 +553,7 @@
CHECK_EQ(bits.getBits(8), 0xa0);
unsigned numAUs = bits.getBits(8);
bits.skipBits(8);
- unsigned quantization_word_length = bits.getBits(2);
+ unsigned quantization_word_length __unused = bits.getBits(2);
unsigned audio_sampling_frequency = bits.getBits(3);
unsigned num_channels = bits.getBits(3);
@@ -620,8 +617,6 @@
// having to interpolate.
// The final AAC frame may well extend into the next RangeInfo but
// that's ok.
- // TODO: the logic commented above is skipped because codec cannot take
- // arbitrary sized input buffers;
size_t offset = 0;
while (offset < info.mLength) {
if (offset + 7 > mBuffer->size()) {
@@ -634,7 +629,7 @@
CHECK_EQ(bits.getBits(12), 0xfffu);
bits.skipBits(3); // ID, layer
- bool protection_absent = bits.getBits(1) != 0;
+ bool protection_absent __unused = bits.getBits(1) != 0;
if (mFormat == NULL) {
unsigned profile = bits.getBits(2);
@@ -683,15 +678,12 @@
return NULL;
}
- size_t headerSize = protection_absent ? 7 : 9;
+ size_t headerSize __unused = protection_absent ? 7 : 9;
offset += aac_frame_length;
- // TODO: move back to concatenation when codec can support arbitrary input buffers.
- // For now only queue a single buffer
- break;
}
- int64_t timeUs = fetchTimestampAAC(offset);
+ int64_t timeUs = fetchTimestamp(offset);
sp<ABuffer> accessUnit = new ABuffer(offset);
memcpy(accessUnit->data(), mBuffer->data(), offset);
@@ -738,50 +730,6 @@
return timeUs;
}
-// TODO: avoid interpolating timestamps once codec supports arbitrary sized input buffers
-int64_t ElementaryStreamQueue::fetchTimestampAAC(size_t size) {
- int64_t timeUs = -1;
- bool first = true;
-
- size_t samplesize = size;
- while (size > 0) {
- CHECK(!mRangeInfos.empty());
-
- RangeInfo *info = &*mRangeInfos.begin();
-
- if (first) {
- timeUs = info->mTimestampUs;
- first = false;
- }
-
- if (info->mLength > size) {
- int32_t sampleRate;
- CHECK(mFormat->findInt32(kKeySampleRate, &sampleRate));
- info->mLength -= size;
- size_t numSamples = 1024 * size / samplesize;
- info->mTimestampUs += numSamples * 1000000ll / sampleRate;
- size = 0;
- } else {
- size -= info->mLength;
-
- mRangeInfos.erase(mRangeInfos.begin());
- info = NULL;
- }
-
- }
-
- if (timeUs == 0ll) {
- ALOGV("Returning 0 timestamp");
- }
-
- return timeUs;
-}
-
-struct NALPosition {
- size_t nalOffset;
- size_t nalSize;
-};
-
sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() {
const uint8_t *data = mBuffer->data();
@@ -789,6 +737,7 @@
Vector<NALPosition> nals;
size_t totalSize = 0;
+ size_t seiCount = 0;
status_t err;
const uint8_t *nalStart;
@@ -818,6 +767,9 @@
// next frame.
flush = true;
+ } else if (nalType == 6 && nalSize > 0) {
+ // found non-zero sized SEI
+ ++seiCount;
}
if (flush) {
@@ -826,21 +778,29 @@
size_t auSize = 4 * nals.size() + totalSize;
sp<ABuffer> accessUnit = new ABuffer(auSize);
+ sp<ABuffer> sei;
+
+ if (seiCount > 0) {
+ sei = new ABuffer(seiCount * sizeof(NALPosition));
+ accessUnit->meta()->setBuffer("sei", sei);
+ }
#if !LOG_NDEBUG
AString out;
#endif
size_t dstOffset = 0;
+ size_t seiIndex = 0;
for (size_t i = 0; i < nals.size(); ++i) {
const NALPosition &pos = nals.itemAt(i);
unsigned nalType = mBuffer->data()[pos.nalOffset] & 0x1f;
- if (nalType == 6) {
- sp<ABuffer> sei = new ABuffer(pos.nalSize);
- memcpy(sei->data(), mBuffer->data() + pos.nalOffset, pos.nalSize);
- accessUnit->meta()->setBuffer("sei", sei);
+ if (nalType == 6 && pos.nalSize > 0) {
+ CHECK_LT(seiIndex, sei->size() / sizeof(NALPosition));
+ NALPosition &seiPos = ((NALPosition *)sei->data())[seiIndex++];
+ seiPos.nalOffset = dstOffset + 4;
+ seiPos.nalSize = pos.nalSize;
}
#if !LOG_NDEBUG
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index 7c81ff0..45b4624 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -26,7 +26,7 @@
namespace android {
struct ABuffer;
-struct MetaData;
+class MetaData;
struct ElementaryStreamQueue {
enum Mode {
@@ -77,7 +77,6 @@
// consume a logical (compressed) access unit of size "size",
// returns its timestamp in us (or -1 if no time information).
int64_t fetchTimestamp(size_t size);
- int64_t fetchTimestampAAC(size_t size);
DISALLOW_EVIL_CONSTRUCTORS(ElementaryStreamQueue);
};
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index 35ca118..1f43d6d 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -159,7 +159,6 @@
int numPacketsParsed = 0;
while (feedMore() == OK) {
- ATSParser::SourceType type;
if (haveAudio && haveVideo) {
break;
}
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index aaa8334..07ea605 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -1,11 +1,8 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-ifeq ($(TARGET_DEVICE), manta)
- LOCAL_CFLAGS += -DSURFACE_IS_BGR32
-endif
-
LOCAL_SRC_FILES:= \
+ FrameDropper.cpp \
GraphicBufferSource.cpp \
OMX.cpp \
OMXMaster.cpp \
diff --git a/media/libstagefright/omx/FrameDropper.cpp b/media/libstagefright/omx/FrameDropper.cpp
new file mode 100644
index 0000000..9fba0b7
--- /dev/null
+++ b/media/libstagefright/omx/FrameDropper.cpp
@@ -0,0 +1,70 @@
+/*
+ * 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 "FrameDropper"
+#include <utils/Log.h>
+
+#include "FrameDropper.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+static const int64_t kMaxJitterUs = 2000;
+
+FrameDropper::FrameDropper()
+ : mDesiredMinTimeUs(-1),
+ mMinIntervalUs(0) {
+}
+
+FrameDropper::~FrameDropper() {
+}
+
+status_t FrameDropper::setMaxFrameRate(float maxFrameRate) {
+ if (maxFrameRate <= 0) {
+ ALOGE("framerate should be positive but got %f.", maxFrameRate);
+ return BAD_VALUE;
+ }
+ mMinIntervalUs = (int64_t) (1000000.0f / maxFrameRate);
+ return OK;
+}
+
+bool FrameDropper::shouldDrop(int64_t timeUs) {
+ if (mMinIntervalUs <= 0) {
+ return false;
+ }
+
+ if (mDesiredMinTimeUs < 0) {
+ mDesiredMinTimeUs = timeUs + mMinIntervalUs;
+ ALOGV("first frame %lld, next desired frame %lld", timeUs, mDesiredMinTimeUs);
+ return false;
+ }
+
+ if (timeUs < (mDesiredMinTimeUs - kMaxJitterUs)) {
+ ALOGV("drop frame %lld, desired frame %lld, diff %lld",
+ timeUs, mDesiredMinTimeUs, mDesiredMinTimeUs - timeUs);
+ return true;
+ }
+
+ int64_t n = (timeUs - mDesiredMinTimeUs + kMaxJitterUs) / mMinIntervalUs;
+ mDesiredMinTimeUs += (n + 1) * mMinIntervalUs;
+ ALOGV("keep frame %lld, next desired frame %lld, diff %lld",
+ timeUs, mDesiredMinTimeUs, mDesiredMinTimeUs - timeUs);
+ return false;
+}
+
+} // namespace android
diff --git a/media/libstagefright/omx/FrameDropper.h b/media/libstagefright/omx/FrameDropper.h
new file mode 100644
index 0000000..c5a6d4b
--- /dev/null
+++ b/media/libstagefright/omx/FrameDropper.h
@@ -0,0 +1,50 @@
+/*
+ * 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 FRAME_DROPPER_H_
+
+#define FRAME_DROPPER_H_
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+struct FrameDropper : public RefBase {
+ // No frames will be dropped until a valid max frame rate is set.
+ FrameDropper();
+
+ // maxFrameRate required to be positive.
+ status_t setMaxFrameRate(float maxFrameRate);
+
+ // Returns false if max frame rate has not been set via setMaxFrameRate.
+ bool shouldDrop(int64_t timeUs);
+
+protected:
+ virtual ~FrameDropper();
+
+private:
+ int64_t mDesiredMinTimeUs;
+ int64_t mMinIntervalUs;
+
+ DISALLOW_EVIL_CONSTRUCTORS(FrameDropper);
+};
+
+} // namespace android
+
+#endif // FRAME_DROPPER_H_
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 44c7edc..d81da3f 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -30,6 +30,7 @@
#include <ui/GraphicBuffer.h>
#include <inttypes.h>
+#include "FrameDropper.h"
namespace android {
@@ -53,9 +54,9 @@
mRepeatAfterUs(-1ll),
mRepeatLastFrameGeneration(0),
mRepeatLastFrameTimestamp(-1ll),
- mLatestSubmittedBufferId(-1),
- mLatestSubmittedBufferFrameNum(0),
- mLatestSubmittedBufferUseCount(0),
+ mLatestBufferId(-1),
+ mLatestBufferFrameNum(0),
+ mLatestBufferUseCount(0),
mRepeatBufferDeferred(false),
mTimePerCaptureUs(-1ll),
mTimePerFrameUs(-1ll),
@@ -152,9 +153,9 @@
mLooper->registerHandler(mReflector);
mLooper->start();
- if (mLatestSubmittedBufferId >= 0) {
+ if (mLatestBufferId >= 0) {
sp<AMessage> msg =
- new AMessage(kWhatRepeatLastFrame, mReflector->id());
+ new AMessage(kWhatRepeatLastFrame, mReflector);
msg->setInt32("generation", ++mRepeatLastFrameGeneration);
msg->post(mRepeatAfterUs);
@@ -287,8 +288,8 @@
ALOGV("cbi %d matches bq slot %d, handle=%p",
cbi, id, mBufferSlot[id]->handle);
- if (id == mLatestSubmittedBufferId) {
- CHECK_GT(mLatestSubmittedBufferUseCount--, 0);
+ if (id == mLatestBufferId) {
+ CHECK_GT(mLatestBufferUseCount--, 0);
} else {
mConsumer->releaseBuffer(id, codecBuffer.mFrameNumber,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
@@ -313,11 +314,11 @@
ALOGV("buffer freed, EOS pending");
submitEndOfInputStream_l();
} else if (mRepeatBufferDeferred) {
- bool success = repeatLatestSubmittedBuffer_l();
+ bool success = repeatLatestBuffer_l();
if (success) {
- ALOGV("deferred repeatLatestSubmittedBuffer_l SUCCESS");
+ ALOGV("deferred repeatLatestBuffer_l SUCCESS");
} else {
- ALOGV("deferred repeatLatestSubmittedBuffer_l FAILURE");
+ ALOGV("deferred repeatLatestBuffer_l FAILURE");
}
mRepeatBufferDeferred = false;
}
@@ -382,12 +383,12 @@
mSuspended = false;
if (mExecuting && mNumFramesAvailable == 0 && mRepeatBufferDeferred) {
- if (repeatLatestSubmittedBuffer_l()) {
- ALOGV("suspend/deferred repeatLatestSubmittedBuffer_l SUCCESS");
+ if (repeatLatestBuffer_l()) {
+ ALOGV("suspend/deferred repeatLatestBuffer_l SUCCESS");
mRepeatBufferDeferred = false;
} else {
- ALOGV("suspend/deferred repeatLatestSubmittedBuffer_l FAILURE");
+ ALOGV("suspend/deferred repeatLatestBuffer_l FAILURE");
}
}
}
@@ -441,12 +442,22 @@
// only submit sample if start time is unspecified, or sample
// is queued after the specified start time
+ bool dropped = false;
if (mSkipFramesBeforeNs < 0ll || item.mTimestamp >= mSkipFramesBeforeNs) {
// if start time is set, offset time stamp by start time
if (mSkipFramesBeforeNs > 0) {
item.mTimestamp -= mSkipFramesBeforeNs;
}
- err = submitBuffer_l(item, cbi);
+
+ int64_t timeUs = item.mTimestamp / 1000;
+ if (mFrameDropper != NULL && mFrameDropper->shouldDrop(timeUs)) {
+ ALOGV("skipping frame (%lld) to meet max framerate", static_cast<long long>(timeUs));
+ // set err to OK so that the skipped frame can still be saved as the lastest frame
+ err = OK;
+ dropped = true;
+ } else {
+ err = submitBuffer_l(item, cbi);
+ }
}
if (err != OK) {
@@ -455,46 +466,46 @@
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
} else {
ALOGV("buffer submitted (bq %d, cbi %d)", item.mBuf, cbi);
- setLatestSubmittedBuffer_l(item);
+ setLatestBuffer_l(item, dropped);
}
return true;
}
-bool GraphicBufferSource::repeatLatestSubmittedBuffer_l() {
+bool GraphicBufferSource::repeatLatestBuffer_l() {
CHECK(mExecuting && mNumFramesAvailable == 0);
- if (mLatestSubmittedBufferId < 0 || mSuspended) {
+ if (mLatestBufferId < 0 || mSuspended) {
return false;
}
- if (mBufferSlot[mLatestSubmittedBufferId] == NULL) {
+ if (mBufferSlot[mLatestBufferId] == NULL) {
// This can happen if the remote side disconnects, causing
// onBuffersReleased() to NULL out our copy of the slots. The
// buffer is gone, so we have nothing to show.
//
// To be on the safe side we try to release the buffer.
- ALOGD("repeatLatestSubmittedBuffer_l: slot was NULL");
+ ALOGD("repeatLatestBuffer_l: slot was NULL");
mConsumer->releaseBuffer(
- mLatestSubmittedBufferId,
- mLatestSubmittedBufferFrameNum,
+ mLatestBufferId,
+ mLatestBufferFrameNum,
EGL_NO_DISPLAY,
EGL_NO_SYNC_KHR,
Fence::NO_FENCE);
- mLatestSubmittedBufferId = -1;
- mLatestSubmittedBufferFrameNum = 0;
+ mLatestBufferId = -1;
+ mLatestBufferFrameNum = 0;
return false;
}
int cbi = findAvailableCodecBuffer_l();
if (cbi < 0) {
// No buffers available, bail.
- ALOGV("repeatLatestSubmittedBuffer_l: no codec buffers.");
+ ALOGV("repeatLatestBuffer_l: no codec buffers.");
return false;
}
BufferQueue::BufferItem item;
- item.mBuf = mLatestSubmittedBufferId;
- item.mFrameNumber = mLatestSubmittedBufferFrameNum;
+ item.mBuf = mLatestBufferId;
+ item.mFrameNumber = mLatestBufferFrameNum;
item.mTimestamp = mRepeatLastFrameTimestamp;
status_t err = submitBuffer_l(item, cbi);
@@ -503,7 +514,7 @@
return false;
}
- ++mLatestSubmittedBufferUseCount;
+ ++mLatestBufferUseCount;
/* repeat last frame up to kRepeatLastFrameCount times.
* in case of static scene, a single repeat might not get rid of encoder
@@ -513,7 +524,7 @@
mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
if (mReflector != NULL) {
- sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector->id());
+ sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector);
msg->setInt32("generation", ++mRepeatLastFrameGeneration);
msg->post(mRepeatAfterUs);
}
@@ -522,31 +533,31 @@
return true;
}
-void GraphicBufferSource::setLatestSubmittedBuffer_l(
- const BufferQueue::BufferItem &item) {
- ALOGV("setLatestSubmittedBuffer_l");
+void GraphicBufferSource::setLatestBuffer_l(
+ const BufferQueue::BufferItem &item, bool dropped) {
+ ALOGV("setLatestBuffer_l");
- if (mLatestSubmittedBufferId >= 0) {
- if (mLatestSubmittedBufferUseCount == 0) {
+ if (mLatestBufferId >= 0) {
+ if (mLatestBufferUseCount == 0) {
mConsumer->releaseBuffer(
- mLatestSubmittedBufferId,
- mLatestSubmittedBufferFrameNum,
+ mLatestBufferId,
+ mLatestBufferFrameNum,
EGL_NO_DISPLAY,
EGL_NO_SYNC_KHR,
Fence::NO_FENCE);
}
}
- mLatestSubmittedBufferId = item.mBuf;
- mLatestSubmittedBufferFrameNum = item.mFrameNumber;
+ mLatestBufferId = item.mBuf;
+ mLatestBufferFrameNum = item.mFrameNumber;
mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
- mLatestSubmittedBufferUseCount = 1;
+ mLatestBufferUseCount = dropped ? 0 : 1;
mRepeatBufferDeferred = false;
mRepeatLastFrameCount = kRepeatLastFrameCount;
if (mReflector != NULL) {
- sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector->id());
+ sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector);
msg->setInt32("generation", ++mRepeatLastFrameGeneration);
msg->post(mRepeatAfterUs);
}
@@ -841,6 +852,23 @@
return OK;
}
+status_t GraphicBufferSource::setMaxFps(float maxFps) {
+ Mutex::Autolock autoLock(mMutex);
+
+ if (mExecuting) {
+ return INVALID_OPERATION;
+ }
+
+ mFrameDropper = new FrameDropper();
+ status_t err = mFrameDropper->setMaxFrameRate(maxFps);
+ if (err != OK) {
+ mFrameDropper.clear();
+ return err;
+ }
+
+ return OK;
+}
+
void GraphicBufferSource::setSkipFramesBeforeUs(int64_t skipFramesBeforeUs) {
Mutex::Autolock autoLock(mMutex);
@@ -879,12 +907,12 @@
break;
}
- bool success = repeatLatestSubmittedBuffer_l();
+ bool success = repeatLatestBuffer_l();
if (success) {
- ALOGV("repeatLatestSubmittedBuffer_l SUCCESS");
+ ALOGV("repeatLatestBuffer_l SUCCESS");
} else {
- ALOGV("repeatLatestSubmittedBuffer_l FAILURE");
+ ALOGV("repeatLatestBuffer_l FAILURE");
mRepeatBufferDeferred = true;
}
break;
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index c8e3775..ce3881e 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -30,6 +30,8 @@
namespace android {
+class FrameDropper;
+
/*
* This class is used to feed OMX codecs from a Surface via BufferQueue.
*
@@ -119,6 +121,9 @@
// of suspension on input.
status_t setMaxTimestampGapUs(int64_t maxGapUs);
+ // When set, the max frame rate fed to the encoder will be capped at maxFps.
+ status_t setMaxFps(float maxFps);
+
// Sets the time lapse (or slow motion) parameters.
// data[0] is the time (us) between two frames for playback
// data[1] is the time (us) between two frames for capture
@@ -193,8 +198,8 @@
// doing anything if we don't have a codec buffer available.
void submitEndOfInputStream_l();
- void setLatestSubmittedBuffer_l(const BufferQueue::BufferItem &item);
- bool repeatLatestSubmittedBuffer_l();
+ void setLatestBuffer_l(const BufferQueue::BufferItem &item, bool dropped);
+ bool repeatLatestBuffer_l();
int64_t getTimestamp(const BufferQueue::BufferItem &item);
// Lock, covers all member variables.
@@ -250,6 +255,8 @@
int64_t mPrevModifiedTimeUs;
int64_t mSkipFramesBeforeNs;
+ sp<FrameDropper> mFrameDropper;
+
sp<ALooper> mLooper;
sp<AHandlerReflector<GraphicBufferSource> > mReflector;
@@ -258,11 +265,11 @@
int64_t mRepeatLastFrameTimestamp;
int32_t mRepeatLastFrameCount;
- int mLatestSubmittedBufferId;
- uint64_t mLatestSubmittedBufferFrameNum;
- int32_t mLatestSubmittedBufferUseCount;
+ int mLatestBufferId;
+ uint64_t mLatestBufferFrameNum;
+ int32_t mLatestBufferUseCount;
- // The previously submitted buffer should've been repeated but
+ // The previous buffer should've been repeated but
// no codec buffer was available at the time.
bool mRepeatBufferDeferred;
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 6d46eee..f8d38ff 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -245,8 +245,8 @@
instance->setHandle(*node, handle);
- mLiveNodes.add(observer->asBinder(), instance);
- observer->asBinder()->linkToDeath(this);
+ mLiveNodes.add(IInterface::asBinder(observer), instance);
+ IInterface::asBinder(observer)->linkToDeath(this);
return OK;
}
@@ -256,7 +256,7 @@
{
Mutex::Autolock autoLock(mLock);
- ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
+ ssize_t index = mLiveNodes.indexOfKey(IInterface::asBinder(instance->observer()));
if (index < 0) {
// This could conceivably happen if the observer dies at roughly the
// same time that a client attempts to free the node explicitly.
@@ -265,7 +265,7 @@
mLiveNodes.removeItemsAt(index);
}
- instance->observer()->asBinder()->unlinkToDeath(this);
+ IInterface::asBinder(instance->observer())->unlinkToDeath(this);
status_t err = instance->freeNode(mMaster);
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index c04d95f..4779d6a 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -158,7 +158,7 @@
switch (portIndex) {
case kPortIndexInput: return "Input";
case kPortIndexOutput: return "Output";
- case ~0: return "All";
+ case ~0U: return "All";
default: return "port";
}
}
@@ -1075,6 +1075,7 @@
case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY:
return "REPEAT_PREVIOUS_FRAME_DELAY";
case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP: return "MAX_TIMESTAMP_GAP";
+ case IOMX::INTERNAL_OPTION_MAX_FPS: return "MAX_FPS";
case IOMX::INTERNAL_OPTION_START_TIME: return "START_TIME";
case IOMX::INTERNAL_OPTION_TIME_LAPSE: return "TIME_LAPSE";
default: return def;
@@ -1092,6 +1093,7 @@
case IOMX::INTERNAL_OPTION_SUSPEND:
case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY:
case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP:
+ case IOMX::INTERNAL_OPTION_MAX_FPS:
case IOMX::INTERNAL_OPTION_START_TIME:
case IOMX::INTERNAL_OPTION_TIME_LAPSE:
{
@@ -1129,6 +1131,14 @@
int64_t maxGapUs = *(int64_t *)data;
CLOG_CONFIG(setInternalOption, "gapUs=%lld", (long long)maxGapUs);
return bufferSource->setMaxTimestampGapUs(maxGapUs);
+ } else if (type == IOMX::INTERNAL_OPTION_MAX_FPS) {
+ if (size != sizeof(float)) {
+ return INVALID_OPERATION;
+ }
+
+ float maxFps = *(float *)data;
+ CLOG_CONFIG(setInternalOption, "maxFps=%f", maxFps);
+ return bufferSource->setMaxFps(maxFps);
} else if (type == IOMX::INTERNAL_OPTION_START_TIME) {
if (size != sizeof(int64_t)) {
return INVALID_OPERATION;
diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
index 7f99dcd..801a1bd 100644
--- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
@@ -58,7 +58,7 @@
OMX_COMMANDTYPE cmd, OMX_U32 param, OMX_PTR data) {
CHECK(data == NULL);
- sp<AMessage> msg = new AMessage(kWhatSendCommand, mHandler->id());
+ sp<AMessage> msg = new AMessage(kWhatSendCommand, mHandler);
msg->setInt32("cmd", cmd);
msg->setInt32("param", param);
msg->post();
@@ -307,7 +307,7 @@
OMX_ERRORTYPE SimpleSoftOMXComponent::emptyThisBuffer(
OMX_BUFFERHEADERTYPE *buffer) {
- sp<AMessage> msg = new AMessage(kWhatEmptyThisBuffer, mHandler->id());
+ sp<AMessage> msg = new AMessage(kWhatEmptyThisBuffer, mHandler);
msg->setPointer("header", buffer);
msg->post();
@@ -316,7 +316,7 @@
OMX_ERRORTYPE SimpleSoftOMXComponent::fillThisBuffer(
OMX_BUFFERHEADERTYPE *buffer) {
- sp<AMessage> msg = new AMessage(kWhatFillThisBuffer, mHandler->id());
+ sp<AMessage> msg = new AMessage(kWhatFillThisBuffer, mHandler);
msg->setPointer("header", buffer);
msg->post();
diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
index b2d3623..d4d6217 100644
--- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
@@ -500,12 +500,12 @@
size_t srcStride;
size_t srcVStride;
if (usingGraphicBuffer) {
- if (srcSize < 4 + sizeof(GraphicBuffer *)) {
- ALOGE("Metadata is too small (%zu vs %zu)", srcSize, 4 + sizeof(GraphicBuffer *));
+ if (srcSize < sizeof(OMX_U32) + sizeof(GraphicBuffer *)) {
+ ALOGE("Metadata is too small (%zu vs %zu)", srcSize, sizeof(OMX_U32) + sizeof(GraphicBuffer *));
return NULL;
}
- GraphicBuffer *buffer = *(GraphicBuffer **)(src + 4);
+ GraphicBuffer *buffer = *(GraphicBuffer **)(src + sizeof(OMX_U32));
handle = buffer->handle;
format = buffer->format;
srcStride = buffer->stride;
@@ -519,12 +519,12 @@
} else {
// TODO: remove this part. Check if anyone uses this.
- if (srcSize < 4 + sizeof(buffer_handle_t)) {
- ALOGE("Metadata is too small (%zu vs %zu)", srcSize, 4 + sizeof(buffer_handle_t));
+ if (srcSize < sizeof(OMX_U32) + sizeof(buffer_handle_t)) {
+ ALOGE("Metadata is too small (%zu vs %zu)", srcSize, sizeof(OMX_U32) + sizeof(buffer_handle_t));
return NULL;
}
- handle = *(buffer_handle_t *)(src + 4);
+ handle = *(buffer_handle_t *)(src + sizeof(OMX_U32));
// assume HAL_PIXEL_FORMAT_RGBA_8888
// there is no way to get the src stride without the graphic buffer
format = HAL_PIXEL_FORMAT_RGBA_8888;
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index 447b29e..9be637a 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -20,3 +20,21 @@
LOCAL_32_BIT_ONLY := true
include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := FrameDropper_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+ FrameDropper_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright_omx \
+ libutils \
+
+LOCAL_C_INCLUDES := \
+ frameworks/av/media/libstagefright/omx \
+
+include $(BUILD_NATIVE_TEST)
diff --git a/media/libstagefright/omx/tests/FrameDropper_test.cpp b/media/libstagefright/omx/tests/FrameDropper_test.cpp
new file mode 100644
index 0000000..4ac72c4
--- /dev/null
+++ b/media/libstagefright/omx/tests/FrameDropper_test.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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 "FrameDropper_test"
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+
+#include "FrameDropper.h"
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+struct TestFrame {
+ int64_t timeUs;
+ bool shouldDrop;
+};
+
+static const TestFrame testFrames20Fps[] = {
+ {1000000, false}, {1050000, false}, {1100000, false}, {1150000, false},
+ {1200000, false}, {1250000, false}, {1300000, false}, {1350000, false},
+ {1400000, false}, {1450000, false}, {1500000, false}, {1550000, false},
+ {1600000, false}, {1650000, false}, {1700000, false}, {1750000, false},
+ {1800000, false}, {1850000, false}, {1900000, false}, {1950000, false},
+};
+
+static const TestFrame testFrames30Fps[] = {
+ {1000000, false}, {1033333, false}, {1066667, false}, {1100000, false},
+ {1133333, false}, {1166667, false}, {1200000, false}, {1233333, false},
+ {1266667, false}, {1300000, false}, {1333333, false}, {1366667, false},
+ {1400000, false}, {1433333, false}, {1466667, false}, {1500000, false},
+ {1533333, false}, {1566667, false}, {1600000, false}, {1633333, false},
+};
+
+static const TestFrame testFrames40Fps[] = {
+ {1000000, false}, {1025000, true}, {1050000, false}, {1075000, false},
+ {1100000, false}, {1125000, true}, {1150000, false}, {1175000, false},
+ {1200000, false}, {1225000, true}, {1250000, false}, {1275000, false},
+ {1300000, false}, {1325000, true}, {1350000, false}, {1375000, false},
+ {1400000, false}, {1425000, true}, {1450000, false}, {1475000, false},
+};
+
+static const TestFrame testFrames60Fps[] = {
+ {1000000, false}, {1016667, true}, {1033333, false}, {1050000, true},
+ {1066667, false}, {1083333, true}, {1100000, false}, {1116667, true},
+ {1133333, false}, {1150000, true}, {1166667, false}, {1183333, true},
+ {1200000, false}, {1216667, true}, {1233333, false}, {1250000, true},
+ {1266667, false}, {1283333, true}, {1300000, false}, {1316667, true},
+};
+
+static const TestFrame testFramesVariableFps[] = {
+ // 40fps
+ {1000000, false}, {1025000, true}, {1050000, false}, {1075000, false},
+ {1100000, false}, {1125000, true}, {1150000, false}, {1175000, false},
+ {1200000, false}, {1225000, true}, {1250000, false}, {1275000, false},
+ {1300000, false}, {1325000, true}, {1350000, false}, {1375000, false},
+ {1400000, false}, {1425000, true}, {1450000, false}, {1475000, false},
+ // a timestamp jump plus switch to 20fps
+ {2000000, false}, {2050000, false}, {2100000, false}, {2150000, false},
+ {2200000, false}, {2250000, false}, {2300000, false}, {2350000, false},
+ {2400000, false}, {2450000, false}, {2500000, false}, {2550000, false},
+ {2600000, false}, {2650000, false}, {2700000, false}, {2750000, false},
+ {2800000, false}, {2850000, false}, {2900000, false}, {2950000, false},
+ // 60fps
+ {2966667, false}, {2983333, true}, {3000000, false}, {3016667, true},
+ {3033333, false}, {3050000, true}, {3066667, false}, {3083333, true},
+ {3100000, false}, {3116667, true}, {3133333, false}, {3150000, true},
+ {3166667, false}, {3183333, true}, {3200000, false}, {3216667, true},
+ {3233333, false}, {3250000, true}, {3266667, false}, {3283333, true},
+};
+
+static const int kMaxTestJitterUs = 2000;
+// return one of 1000, 0, -1000 as jitter.
+static int GetJitter(size_t i) {
+ return (1 - (i % 3)) * (kMaxTestJitterUs / 2);
+}
+
+class FrameDropperTest : public ::testing::Test {
+public:
+ FrameDropperTest() : mFrameDropper(new FrameDropper()) {
+ EXPECT_EQ(OK, mFrameDropper->setMaxFrameRate(30.0));
+ }
+
+protected:
+ void RunTest(const TestFrame* frames, size_t size) {
+ for (size_t i = 0; i < size; ++i) {
+ int jitter = GetJitter(i);
+ int64_t testTimeUs = frames[i].timeUs + jitter;
+ printf("time %lld, testTime %lld, jitter %d\n", frames[i].timeUs, testTimeUs, jitter);
+ EXPECT_EQ(frames[i].shouldDrop, mFrameDropper->shouldDrop(testTimeUs));
+ }
+ }
+
+ sp<FrameDropper> mFrameDropper;
+};
+
+TEST_F(FrameDropperTest, TestInvalidMaxFrameRate) {
+ EXPECT_NE(OK, mFrameDropper->setMaxFrameRate(-1.0));
+ EXPECT_NE(OK, mFrameDropper->setMaxFrameRate(0));
+}
+
+TEST_F(FrameDropperTest, Test20Fps) {
+ RunTest(testFrames20Fps, ARRAY_SIZE(testFrames20Fps));
+}
+
+TEST_F(FrameDropperTest, Test30Fps) {
+ RunTest(testFrames30Fps, ARRAY_SIZE(testFrames30Fps));
+}
+
+TEST_F(FrameDropperTest, Test40Fps) {
+ RunTest(testFrames40Fps, ARRAY_SIZE(testFrames40Fps));
+}
+
+TEST_F(FrameDropperTest, Test60Fps) {
+ RunTest(testFrames60Fps, ARRAY_SIZE(testFrames60Fps));
+}
+
+TEST_F(FrameDropperTest, TestVariableFps) {
+ RunTest(testFramesVariableFps, ARRAY_SIZE(testFramesVariableFps));
+}
+
+} // namespace android
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index f4dfd6b..67ff145 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -253,29 +253,6 @@
return MediaExtractor::Create(source);
}
-static sp<MediaSource> MakeSource(
- const char *uri,
- const char *mimeType) {
- sp<MediaExtractor> extractor = CreateExtractorFromURI(uri);
-
- if (extractor == NULL) {
- return NULL;
- }
-
- for (size_t i = 0; i < extractor->countTracks(); ++i) {
- sp<MetaData> meta = extractor->getTrackMetaData(i);
-
- const char *trackMIME;
- CHECK(meta->findCString(kKeyMIMEType, &trackMIME));
-
- if (!strcasecmp(trackMIME, mimeType)) {
- return extractor->getTrack(i);
- }
- }
-
- return NULL;
-}
-
status_t Harness::testStateTransitions(
const char *componentName, const char *componentRole) {
if (strncmp(componentName, "OMX.", 4)) {
diff --git a/media/libstagefright/rtsp/AAMRAssembler.cpp b/media/libstagefright/rtsp/AAMRAssembler.cpp
index 9e8725a..bb2a238 100644
--- a/media/libstagefright/rtsp/AAMRAssembler.cpp
+++ b/media/libstagefright/rtsp/AAMRAssembler.cpp
@@ -143,8 +143,8 @@
return MALFORMED_PACKET;
}
- unsigned payloadHeader = buffer->data()[0];
- unsigned CMR = payloadHeader >> 4;
+ unsigned payloadHeader __unused = buffer->data()[0];
+ unsigned CMR __unused = payloadHeader >> 4;
Vector<uint8_t> tableOfContents;
diff --git a/media/libstagefright/rtsp/AMPEG2TSAssembler.h b/media/libstagefright/rtsp/AMPEG2TSAssembler.h
index 712e18e..f39c2b5 100644
--- a/media/libstagefright/rtsp/AMPEG2TSAssembler.h
+++ b/media/libstagefright/rtsp/AMPEG2TSAssembler.h
@@ -24,7 +24,7 @@
struct AMessage;
struct AString;
-struct MetaData;
+class MetaData;
struct AMPEG2TSAssembler : public ARTPAssembler {
AMPEG2TSAssembler(
diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
index aa8ffc6..1f76068 100644
--- a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
@@ -108,7 +108,7 @@
static status_t parseGASpecificConfig(
ABitReader *bits,
unsigned audioObjectType, unsigned channelConfiguration) {
- unsigned frameLengthFlag = bits->getBits(1);
+ unsigned frameLengthFlag __unused = bits->getBits(1);
unsigned dependsOnCoreCoder = bits->getBits(1);
if (dependsOnCoreCoder) {
/* unsigned coreCoderDelay = */bits->getBits(1);
@@ -217,7 +217,7 @@
// Apparently an extension is always considered an even
// multiple of 8 bits long.
- ALOGI("Skipping %d bits after sync extension",
+ ALOGI("Skipping %zu bits after sync extension",
8 - (numBitsInExtension & 7));
bits->skipBits(8 - (numBitsInExtension & 7));
@@ -422,7 +422,7 @@
}
if (offset < buffer->size()) {
- ALOGI("ignoring %d bytes of trailing data", buffer->size() - offset);
+ ALOGI("ignoring %zu bytes of trailing data", buffer->size() - offset);
}
CHECK_LE(offset, buffer->size());
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
index 7eb6542..156004c 100644
--- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
@@ -360,7 +360,7 @@
}
if (offset != buffer->size()) {
- ALOGW("potentially malformed packet (offset %d, size %d)",
+ ALOGW("potentially malformed packet (offset %zu, size %zu)",
offset, buffer->size());
}
}
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 09f52bc..cfafaa7 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -279,8 +279,6 @@
// be encoded.
CHECK_LT(20 + config->size(), 128u);
- const uint8_t *data = config->data();
-
static const uint8_t kStaticESDS[] = {
0x03, 22,
0x00, 0x00, // ES_ID
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index 372fbe9..a86ab74 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -82,7 +82,7 @@
size_t index,
const sp<AMessage> ¬ify,
bool injected) {
- sp<AMessage> msg = new AMessage(kWhatAddStream, id());
+ sp<AMessage> msg = new AMessage(kWhatAddStream, this);
msg->setInt32("rtp-socket", rtpSocket);
msg->setInt32("rtcp-socket", rtcpSocket);
msg->setObject("session-desc", sessionDesc);
@@ -93,7 +93,7 @@
}
void ARTPConnection::removeStream(int rtpSocket, int rtcpSocket) {
- sp<AMessage> msg = new AMessage(kWhatRemoveStream, id());
+ sp<AMessage> msg = new AMessage(kWhatRemoveStream, this);
msg->setInt32("rtp-socket", rtpSocket);
msg->setInt32("rtcp-socket", rtcpSocket);
msg->post();
@@ -233,7 +233,7 @@
return;
}
- sp<AMessage> msg = new AMessage(kWhatPollStreams, id());
+ sp<AMessage> msg = new AMessage(kWhatPollStreams, this);
msg->post();
mPollEventPending = true;
@@ -639,7 +639,7 @@
}
void ARTPConnection::injectPacket(int index, const sp<ABuffer> &buffer) {
- sp<AMessage> msg = new AMessage(kWhatInjectPacket, id());
+ sp<AMessage> msg = new AMessage(kWhatInjectPacket, this);
msg->setInt32("index", index);
msg->setBuffer("buffer", buffer);
msg->post();
@@ -664,11 +664,10 @@
StreamInfo *s = &*it;
- status_t err;
if (it->mRTPSocket == index) {
- err = parseRTP(s, buffer);
+ parseRTP(s, buffer);
} else {
- err = parseRTCP(s, buffer);
+ parseRTCP(s, buffer);
}
}
diff --git a/media/libstagefright/rtsp/ARTPSession.cpp b/media/libstagefright/rtsp/ARTPSession.cpp
index ba4e33c..e5acb06 100644
--- a/media/libstagefright/rtsp/ARTPSession.cpp
+++ b/media/libstagefright/rtsp/ARTPSession.cpp
@@ -82,7 +82,7 @@
info->mRTPSocket = rtpSocket;
info->mRTCPSocket = rtcpSocket;
- sp<AMessage> notify = new AMessage(kWhatAccessUnitComplete, id());
+ sp<AMessage> notify = new AMessage(kWhatAccessUnitComplete, this);
notify->setSize("track-index", mTracks.size() - 1);
mRTPConn->addStream(
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 793d116..56c4aa6 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -146,7 +146,7 @@
TRESPASS();
}
- (new AMessage(kWhatStart, mReflector->id()))->post();
+ (new AMessage(kWhatStart, mReflector))->post();
while (!(mFlags & kFlagStarted)) {
mCondition.wait(mLock);
@@ -161,7 +161,7 @@
return OK;
}
- (new AMessage(kWhatStop, mReflector->id()))->post();
+ (new AMessage(kWhatStop, mReflector))->post();
while (mFlags & kFlagStarted) {
mCondition.wait(mLock);
@@ -213,8 +213,8 @@
mCondition.signal();
}
- (new AMessage(kWhatRead, mReflector->id()))->post();
- (new AMessage(kWhatSendSR, mReflector->id()))->post();
+ (new AMessage(kWhatRead, mReflector))->post();
+ (new AMessage(kWhatSendSR, mReflector))->post();
break;
}
@@ -461,7 +461,7 @@
sdp.append("m=audio ");
}
- sdp.append(StringPrintf("%d", ntohs(mRTPAddr.sin_port)));
+ sdp.append(AStringPrintf("%d", ntohs(mRTPAddr.sin_port)));
sdp.append(
" RTP/AVP " PT_STR "\r\n"
"b=AS 320000\r\n"
@@ -480,7 +480,7 @@
CHECK_EQ(sampleRate, (mMode == AMR_NB) ? 8000 : 16000);
sdp.append(mMode == AMR_NB ? "AMR" : "AMR-WB");
- sdp.append(StringPrintf("/%d/%d", sampleRate, numChannels));
+ sdp.append(AStringPrintf("/%d/%d", sampleRate, numChannels));
} else {
TRESPASS();
}
@@ -543,7 +543,7 @@
CHECK_EQ((unsigned)data[0], 0x67u);
mProfileLevel =
- StringPrintf("%02X%02X%02X", data[1], data[2], data[3]);
+ AStringPrintf("%02X%02X%02X", data[1], data[2], data[3]);
encodeBase64(data, startCodePos, &mSeqParamSet);
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index f25539c..855ffdc 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -42,7 +42,7 @@
// static
const AString ARTSPConnection::sUserAgent =
- StringPrintf("User-Agent: %s\r\n", MakeUserAgent().c_str());
+ AStringPrintf("User-Agent: %s\r\n", MakeUserAgent().c_str());
ARTSPConnection::ARTSPConnection(bool uidValid, uid_t uid)
: mUIDValid(uidValid),
@@ -68,28 +68,28 @@
}
void ARTSPConnection::connect(const char *url, const sp<AMessage> &reply) {
- sp<AMessage> msg = new AMessage(kWhatConnect, id());
+ sp<AMessage> msg = new AMessage(kWhatConnect, this);
msg->setString("url", url);
msg->setMessage("reply", reply);
msg->post();
}
void ARTSPConnection::disconnect(const sp<AMessage> &reply) {
- sp<AMessage> msg = new AMessage(kWhatDisconnect, id());
+ sp<AMessage> msg = new AMessage(kWhatDisconnect, this);
msg->setMessage("reply", reply);
msg->post();
}
void ARTSPConnection::sendRequest(
const char *request, const sp<AMessage> &reply) {
- sp<AMessage> msg = new AMessage(kWhatSendRequest, id());
+ sp<AMessage> msg = new AMessage(kWhatSendRequest, this);
msg->setString("request", request);
msg->setMessage("reply", reply);
msg->post();
}
void ARTSPConnection::observeBinaryData(const sp<AMessage> &reply) {
- sp<AMessage> msg = new AMessage(kWhatObserveBinaryData, id());
+ sp<AMessage> msg = new AMessage(kWhatObserveBinaryData, this);
msg->setMessage("reply", reply);
msg->post();
}
@@ -286,7 +286,7 @@
if (err < 0) {
if (errno == EINPROGRESS) {
- sp<AMessage> msg = new AMessage(kWhatCompleteConnection, id());
+ sp<AMessage> msg = new AMessage(kWhatCompleteConnection, this);
msg->setMessage("reply", reply);
msg->setInt32("connection-id", mConnectionID);
msg->post();
@@ -523,7 +523,7 @@
return;
}
- sp<AMessage> msg = new AMessage(kWhatReceiveResponse, id());
+ sp<AMessage> msg = new AMessage(kWhatReceiveResponse, this);
msg->post();
mReceiveResponseEventPending = true;
@@ -746,7 +746,7 @@
AString request;
CHECK(reply->findString("original-request", &request));
- sp<AMessage> msg = new AMessage(kWhatSendRequest, id());
+ sp<AMessage> msg = new AMessage(kWhatSendRequest, this);
msg->setMessage("reply", reply);
msg->setString("request", request.c_str(), request.size());
diff --git a/media/libstagefright/rtsp/ARawAudioAssembler.h b/media/libstagefright/rtsp/ARawAudioAssembler.h
index ed7af08..bc1dea6 100644
--- a/media/libstagefright/rtsp/ARawAudioAssembler.h
+++ b/media/libstagefright/rtsp/ARawAudioAssembler.h
@@ -24,7 +24,7 @@
struct AMessage;
struct AString;
-struct MetaData;
+class MetaData;
struct ARawAudioAssembler : public ARTPAssembler {
ARawAudioAssembler(
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index d60dc2f..9fedb71 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -19,10 +19,11 @@
ASessionDescription.cpp \
SDPLoader.cpp \
+LOCAL_SHARED_LIBRARIES += libcrypto
+
LOCAL_C_INCLUDES:= \
$(TOP)/frameworks/av/media/libstagefright \
- $(TOP)/frameworks/native/include/media/openmax \
- $(TOP)/external/openssl/include
+ $(TOP)/frameworks/native/include/media/openmax
LOCAL_MODULE:= libstagefright_rtsp
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 423a420..0642343 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -156,7 +156,7 @@
mSessionURL.append("rtsp://");
mSessionURL.append(host);
mSessionURL.append(":");
- mSessionURL.append(StringPrintf("%u", port));
+ mSessionURL.append(AStringPrintf("%u", port));
mSessionURL.append(path);
ALOGV("rewritten session url: '%s'", mSessionURL.c_str());
@@ -169,10 +169,10 @@
looper()->registerHandler(mConn);
(1 ? mNetLooper : looper())->registerHandler(mRTPConn);
- sp<AMessage> notify = new AMessage('biny', id());
+ sp<AMessage> notify = new AMessage('biny', this);
mConn->observeBinaryData(notify);
- sp<AMessage> reply = new AMessage('conn', id());
+ sp<AMessage> reply = new AMessage('conn', this);
mConn->connect(mOriginalSessionURL.c_str(), reply);
}
@@ -180,10 +180,10 @@
looper()->registerHandler(mConn);
(1 ? mNetLooper : looper())->registerHandler(mRTPConn);
- sp<AMessage> notify = new AMessage('biny', id());
+ sp<AMessage> notify = new AMessage('biny', this);
mConn->observeBinaryData(notify);
- sp<AMessage> reply = new AMessage('sdpl', id());
+ sp<AMessage> reply = new AMessage('sdpl', this);
reply->setObject("description", desc);
mConn->connect(mOriginalSessionURL.c_str(), reply);
}
@@ -210,11 +210,11 @@
}
void disconnect() {
- (new AMessage('abor', id()))->post();
+ (new AMessage('abor', this))->post();
}
void seek(int64_t timeUs) {
- sp<AMessage> msg = new AMessage('seek', id());
+ sp<AMessage> msg = new AMessage('seek', this);
msg->setInt64("time", timeUs);
mPauseGeneration++;
msg->post();
@@ -225,14 +225,14 @@
}
void pause() {
- sp<AMessage> msg = new AMessage('paus', id());
+ sp<AMessage> msg = new AMessage('paus', this);
mPauseGeneration++;
msg->setInt32("pausecheck", mPauseGeneration);
msg->post(kPauseDelayUs);
}
void resume() {
- sp<AMessage> msg = new AMessage('resu', id());
+ sp<AMessage> msg = new AMessage('resu', this);
mPauseGeneration++;
msg->post();
}
@@ -454,10 +454,10 @@
request.append("Accept: application/sdp\r\n");
request.append("\r\n");
- sp<AMessage> reply = new AMessage('desc', id());
+ sp<AMessage> reply = new AMessage('desc', this);
mConn->sendRequest(request.c_str(), reply);
} else {
- (new AMessage('disc', id()))->post();
+ (new AMessage('disc', this))->post();
}
break;
}
@@ -468,10 +468,10 @@
int32_t reconnect;
if (msg->findInt32("reconnect", &reconnect) && reconnect) {
- sp<AMessage> reply = new AMessage('conn', id());
+ sp<AMessage> reply = new AMessage('conn', this);
mConn->connect(mOriginalSessionURL.c_str(), reply);
} else {
- (new AMessage('quit', id()))->post();
+ (new AMessage('quit', this))->post();
}
break;
}
@@ -508,13 +508,13 @@
mSessionURL.append("rtsp://");
mSessionURL.append(host);
mSessionURL.append(":");
- mSessionURL.append(StringPrintf("%u", port));
+ mSessionURL.append(AStringPrintf("%u", port));
mSessionURL.append(path);
ALOGI("rewritten session url: '%s'", mSessionURL.c_str());
}
- sp<AMessage> reply = new AMessage('conn', id());
+ sp<AMessage> reply = new AMessage('conn', this);
mConn->connect(mOriginalSessionURL.c_str(), reply);
break;
}
@@ -586,7 +586,7 @@
}
if (result != OK) {
- sp<AMessage> reply = new AMessage('disc', id());
+ sp<AMessage> reply = new AMessage('disc', this);
mConn->disconnect(reply);
}
break;
@@ -631,7 +631,7 @@
}
if (result != OK) {
- sp<AMessage> reply = new AMessage('disc', id());
+ sp<AMessage> reply = new AMessage('disc', this);
mConn->disconnect(reply);
}
break;
@@ -703,7 +703,7 @@
mSessionID.erase(i, mSessionID.size() - i);
}
- sp<AMessage> notify = new AMessage('accu', id());
+ sp<AMessage> notify = new AMessage('accu', this);
notify->setSize("track-index", trackIndex);
i = response->mHeaders.indexOfKey("transport");
@@ -769,10 +769,10 @@
request.append("\r\n");
- sp<AMessage> reply = new AMessage('play', id());
+ sp<AMessage> reply = new AMessage('play', this);
mConn->sendRequest(request.c_str(), reply);
} else {
- sp<AMessage> reply = new AMessage('disc', id());
+ sp<AMessage> reply = new AMessage('disc', this);
mConn->disconnect(reply);
}
break;
@@ -797,7 +797,7 @@
} else {
parsePlayResponse(response);
- sp<AMessage> timeout = new AMessage('tiou', id());
+ sp<AMessage> timeout = new AMessage('tiou', this);
mCheckTimeoutGeneration++;
timeout->setInt32("tioucheck", mCheckTimeoutGeneration);
timeout->post(kStartupTimeoutUs);
@@ -805,7 +805,7 @@
}
if (result != OK) {
- sp<AMessage> reply = new AMessage('disc', id());
+ sp<AMessage> reply = new AMessage('disc', this);
mConn->disconnect(reply);
}
@@ -831,7 +831,7 @@
request.append("\r\n");
request.append("\r\n");
- sp<AMessage> reply = new AMessage('opts', id());
+ sp<AMessage> reply = new AMessage('opts', this);
reply->setInt32("generation", mKeepAliveGeneration);
mConn->sendRequest(request.c_str(), reply);
break;
@@ -894,7 +894,7 @@
mPausing = false;
mSeekable = true;
- sp<AMessage> reply = new AMessage('tear', id());
+ sp<AMessage> reply = new AMessage('tear', this);
int32_t reconnect;
if (msg->findInt32("reconnect", &reconnect) && reconnect) {
@@ -926,7 +926,7 @@
ALOGI("TEARDOWN completed with result %d (%s)",
result, strerror(-result));
- sp<AMessage> reply = new AMessage('disc', id());
+ sp<AMessage> reply = new AMessage('disc', this);
int32_t reconnect;
if (msg->findInt32("reconnect", &reconnect) && reconnect) {
@@ -958,7 +958,7 @@
if (mNumAccessUnitsReceived == 0) {
#if 1
ALOGI("stream ended? aborting.");
- (new AMessage('abor', id()))->post();
+ (new AMessage('abor', this))->post();
break;
#else
ALOGI("haven't seen an AU in a looong time.");
@@ -1077,7 +1077,7 @@
request.append("\r\n");
- sp<AMessage> reply = new AMessage('pau2', id());
+ sp<AMessage> reply = new AMessage('pau2', this);
mConn->sendRequest(request.c_str(), reply);
break;
}
@@ -1114,7 +1114,7 @@
request.append("\r\n");
- sp<AMessage> reply = new AMessage('res2', id());
+ sp<AMessage> reply = new AMessage('res2', this);
mConn->sendRequest(request.c_str(), reply);
break;
}
@@ -1143,7 +1143,7 @@
// Post new timeout in order to make sure to use
// fake timestamps if no new Sender Reports arrive
- sp<AMessage> timeout = new AMessage('tiou', id());
+ sp<AMessage> timeout = new AMessage('tiou', this);
mCheckTimeoutGeneration++;
timeout->setInt32("tioucheck", mCheckTimeoutGeneration);
timeout->post(kStartupTimeoutUs);
@@ -1152,7 +1152,7 @@
if (result != OK) {
ALOGE("resume failed, aborting.");
- (new AMessage('abor', id()))->post();
+ (new AMessage('abor', this))->post();
}
mPausing = false;
@@ -1180,7 +1180,7 @@
mCheckPending = true;
++mCheckGeneration;
- sp<AMessage> reply = new AMessage('see1', id());
+ sp<AMessage> reply = new AMessage('see1', this);
reply->setInt64("time", timeUs);
if (mPausing) {
@@ -1221,7 +1221,7 @@
// Start new timeoutgeneration to avoid getting timeout
// before PLAY response arrive
- sp<AMessage> timeout = new AMessage('tiou', id());
+ sp<AMessage> timeout = new AMessage('tiou', this);
mCheckTimeoutGeneration++;
timeout->setInt32("tioucheck", mCheckTimeoutGeneration);
timeout->post(kStartupTimeoutUs);
@@ -1238,12 +1238,12 @@
request.append("\r\n");
request.append(
- StringPrintf(
+ AStringPrintf(
"Range: npt=%lld-\r\n", timeUs / 1000000ll));
request.append("\r\n");
- sp<AMessage> reply = new AMessage('see2', id());
+ sp<AMessage> reply = new AMessage('see2', this);
mConn->sendRequest(request.c_str(), reply);
break;
}
@@ -1277,7 +1277,7 @@
// Post new timeout in order to make sure to use
// fake timestamps if no new Sender Reports arrive
- sp<AMessage> timeout = new AMessage('tiou', id());
+ sp<AMessage> timeout = new AMessage('tiou', this);
mCheckTimeoutGeneration++;
timeout->setInt32("tioucheck", mCheckTimeoutGeneration);
timeout->post(kStartupTimeoutUs);
@@ -1293,7 +1293,7 @@
if (result != OK) {
ALOGE("seek failed, aborting.");
- (new AMessage('abor', id()))->post();
+ (new AMessage('abor', this))->post();
}
mPausing = false;
@@ -1343,12 +1343,12 @@
mTryTCPInterleaving = true;
- sp<AMessage> msg = new AMessage('abor', id());
+ sp<AMessage> msg = new AMessage('abor', this);
msg->setInt32("reconnect", true);
msg->post();
} else {
ALOGW("Never received any data, disconnecting.");
- (new AMessage('abor', id()))->post();
+ (new AMessage('abor', this))->post();
}
} else {
if (!mAllTracksHaveTime) {
@@ -1369,7 +1369,7 @@
}
void postKeepAlive() {
- sp<AMessage> msg = new AMessage('aliv', id());
+ sp<AMessage> msg = new AMessage('aliv', this);
msg->setInt32("generation", mKeepAliveGeneration);
msg->post((mKeepAliveTimeoutUs * 9) / 10);
}
@@ -1380,7 +1380,7 @@
}
mCheckPending = true;
- sp<AMessage> check = new AMessage('chek', id());
+ sp<AMessage> check = new AMessage('chek', this);
check->setInt32("generation", mCheckGeneration);
check->post(kAccessUnitTimeoutUs);
}
@@ -1566,7 +1566,7 @@
if (source->initCheck() != OK) {
ALOGW("Unsupported format. Ignoring track #%d.", index);
- sp<AMessage> reply = new AMessage('setu', id());
+ sp<AMessage> reply = new AMessage('setu', this);
reply->setSize("index", index);
reply->setInt32("result", ERROR_UNSUPPORTED);
reply->post();
@@ -1652,7 +1652,7 @@
request.append("\r\n");
- sp<AMessage> reply = new AMessage('setu', id());
+ sp<AMessage> reply = new AMessage('setu', this);
reply->setSize("index", index);
reply->setSize("track-index", mTracks.size() - 1);
mConn->sendRequest(request.c_str(), reply);
diff --git a/media/libstagefright/rtsp/MyTransmitter.h b/media/libstagefright/rtsp/MyTransmitter.h
index 009a3b1..369f276 100644
--- a/media/libstagefright/rtsp/MyTransmitter.h
+++ b/media/libstagefright/rtsp/MyTransmitter.h
@@ -100,7 +100,7 @@
mLooper->registerHandler(this);
mLooper->registerHandler(mConn);
- sp<AMessage> reply = new AMessage('conn', id());
+ sp<AMessage> reply = new AMessage('conn', this);
mConn->connect(mServerURL.c_str(), reply);
#ifdef ANDROID
@@ -229,7 +229,7 @@
request.append("\r\n");
request.append(sdp);
- sp<AMessage> reply = new AMessage('anno', id());
+ sp<AMessage> reply = new AMessage('anno', this);
mConn->sendRequest(request.c_str(), reply);
}
@@ -350,7 +350,7 @@
<< result << " (" << strerror(-result) << ")";
if (result != OK) {
- (new AMessage('quit', id()))->post();
+ (new AMessage('quit', this))->post();
break;
}
@@ -381,7 +381,7 @@
if (response->mStatusCode == 401) {
if (mAuthType != NONE) {
LOG(INFO) << "FAILED to authenticate";
- (new AMessage('quit', id()))->post();
+ (new AMessage('quit', this))->post();
break;
}
@@ -391,14 +391,14 @@
}
if (result != OK || response->mStatusCode != 200) {
- (new AMessage('quit', id()))->post();
+ (new AMessage('quit', this))->post();
break;
}
unsigned rtpPort;
ARTPConnection::MakePortPair(&mRTPSocket, &mRTCPSocket, &rtpPort);
- // (new AMessage('poll', id()))->post();
+ // (new AMessage('poll', this))->post();
AString request;
request.append("SETUP ");
@@ -414,7 +414,7 @@
request.append(";mode=record\r\n");
request.append("\r\n");
- sp<AMessage> reply = new AMessage('setu', id());
+ sp<AMessage> reply = new AMessage('setu', this);
mConn->sendRequest(request.c_str(), reply);
break;
}
@@ -468,7 +468,7 @@
}
if (result != OK || response->mStatusCode != 200) {
- (new AMessage('quit', id()))->post();
+ (new AMessage('quit', this))->post();
break;
}
@@ -535,7 +535,7 @@
request.append("\r\n");
request.append("\r\n");
- sp<AMessage> reply = new AMessage('reco', id());
+ sp<AMessage> reply = new AMessage('reco', this);
mConn->sendRequest(request.c_str(), reply);
break;
}
@@ -558,13 +558,13 @@
}
if (result != OK) {
- (new AMessage('quit', id()))->post();
+ (new AMessage('quit', this))->post();
break;
}
- (new AMessage('more', id()))->post();
- (new AMessage('sr ', id()))->post();
- (new AMessage('aliv', id()))->post(30000000ll);
+ (new AMessage('more', this))->post();
+ (new AMessage('sr ', this))->post();
+ (new AMessage('aliv', this))->post(30000000ll);
break;
}
@@ -586,7 +586,7 @@
request.append("\r\n");
request.append("\r\n");
- sp<AMessage> reply = new AMessage('opts', id());
+ sp<AMessage> reply = new AMessage('opts', this);
mConn->sendRequest(request.c_str(), reply);
break;
}
@@ -603,7 +603,7 @@
break;
}
- (new AMessage('aliv', id()))->post(30000000ll);
+ (new AMessage('aliv', this))->post(30000000ll);
break;
}
@@ -702,7 +702,7 @@
request.append("\r\n");
request.append("\r\n");
- sp<AMessage> reply = new AMessage('paus', id());
+ sp<AMessage> reply = new AMessage('paus', this);
mConn->sendRequest(request.c_str(), reply);
}
break;
@@ -753,7 +753,7 @@
request.append("\r\n");
request.append("\r\n");
- sp<AMessage> reply = new AMessage('tear', id());
+ sp<AMessage> reply = new AMessage('tear', this);
mConn->sendRequest(request.c_str(), reply);
break;
}
@@ -775,7 +775,7 @@
CHECK(response != NULL);
}
- (new AMessage('quit', id()))->post();
+ (new AMessage('quit', this))->post();
break;
}
@@ -784,14 +784,14 @@
LOG(INFO) << "disconnect completed";
mConnected = false;
- (new AMessage('quit', id()))->post();
+ (new AMessage('quit', this))->post();
break;
}
case 'quit':
{
if (mConnected) {
- mConn->disconnect(new AMessage('disc', id()));
+ mConn->disconnect(new AMessage('disc', this));
break;
}
diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp
index 424badf..0f46c83 100644
--- a/media/libstagefright/rtsp/SDPLoader.cpp
+++ b/media/libstagefright/rtsp/SDPLoader.cpp
@@ -51,7 +51,7 @@
void SDPLoader::load(const char *url, const KeyedVector<String8, String8> *headers) {
mNetLooper->registerHandler(this);
- sp<AMessage> msg = new AMessage(kWhatLoad, id());
+ sp<AMessage> msg = new AMessage(kWhatLoad, this);
msg->setString("url", url);
if (headers != NULL) {
@@ -105,7 +105,7 @@
headers = NULL;
}
- off64_t sdpSize;
+ off64_t sdpSize = 0;
if (err == OK && !mCancelled) {
err = mHTTPDataSource->getSize(&sdpSize);
diff --git a/media/libstagefright/rtsp/UDPPusher.cpp b/media/libstagefright/rtsp/UDPPusher.cpp
index 47ea6f1..5c685a1 100644
--- a/media/libstagefright/rtsp/UDPPusher.cpp
+++ b/media/libstagefright/rtsp/UDPPusher.cpp
@@ -65,7 +65,7 @@
mFirstTimeMs = fromlel(timeMs);
mFirstTimeUs = ALooper::GetNowUs();
- (new AMessage(kWhatPush, id()))->post();
+ (new AMessage(kWhatPush, this))->post();
}
bool UDPPusher::onPush() {
@@ -103,7 +103,7 @@
timeMs -= mFirstTimeMs;
int64_t whenUs = mFirstTimeUs + timeMs * 1000ll;
int64_t nowUs = ALooper::GetNowUs();
- (new AMessage(kWhatPush, id()))->post(whenUs - nowUs);
+ (new AMessage(kWhatPush, this))->post(whenUs - nowUs);
return true;
}
diff --git a/media/libstagefright/tests/Android.mk b/media/libstagefright/tests/Android.mk
index 99b480ad..8d6ff5b 100644
--- a/media/libstagefright/tests/Android.mk
+++ b/media/libstagefright/tests/Android.mk
@@ -1,8 +1,7 @@
# Build the unit tests.
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-
-ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE := SurfaceMediaSource_test
@@ -22,33 +21,23 @@
libstagefright \
libstagefright_foundation \
libstagefright_omx \
- libstlport \
libsync \
libui \
libutils \
liblog
-LOCAL_STATIC_LIBRARIES := \
- libgtest \
- libgtest_main \
-
LOCAL_C_INCLUDES := \
- bionic \
- bionic/libstdc++/include \
- external/gtest/include \
- external/stlport/stlport \
frameworks/av/media/libstagefright \
frameworks/av/media/libstagefright/include \
$(TOP)/frameworks/native/include/media/openmax \
LOCAL_32_BIT_ONLY := true
-include $(BUILD_EXECUTABLE)
-
-endif
+include $(BUILD_NATIVE_TEST)
include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE := Utils_test
@@ -64,23 +53,14 @@
libstagefright \
libstagefright_foundation \
libstagefright_omx \
- libstlport \
-
-LOCAL_STATIC_LIBRARIES := \
- libgtest \
- libgtest_main \
LOCAL_C_INCLUDES := \
- bionic \
- bionic/libstdc++/include \
- external/gtest/include \
- external/stlport/stlport \
frameworks/av/include \
frameworks/av/media/libstagefright \
frameworks/av/media/libstagefright/include \
$(TOP)/frameworks/native/include/media/openmax \
-include $(BUILD_EXECUTABLE)
+include $(BUILD_NATIVE_TEST)
# Include subdirectory makefiles
# ============================================================
diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp
index 71aa21e..55a9803 100644
--- a/media/libstagefright/timedtext/TimedTextDriver.cpp
+++ b/media/libstagefright/timedtext/TimedTextDriver.cpp
@@ -133,7 +133,7 @@
}
mPlayer->start();
break;
- defaut:
+ default:
TRESPASS();
}
return ret;
@@ -181,7 +181,7 @@
case PLAYING:
mPlayer->seekToAsync(timeUs);
return OK;
- defaut:
+ default:
TRESPASS();
}
return UNKNOWN_ERROR;
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp
index a070487..aecf666 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.cpp
+++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp
@@ -56,25 +56,25 @@
}
void TimedTextPlayer::start() {
- (new AMessage(kWhatStart, id()))->post();
+ (new AMessage(kWhatStart, this))->post();
}
void TimedTextPlayer::pause() {
- (new AMessage(kWhatPause, id()))->post();
+ (new AMessage(kWhatPause, this))->post();
}
void TimedTextPlayer::resume() {
- (new AMessage(kWhatResume, id()))->post();
+ (new AMessage(kWhatResume, this))->post();
}
void TimedTextPlayer::seekToAsync(int64_t timeUs) {
- sp<AMessage> msg = new AMessage(kWhatSeek, id());
+ 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, id());
+ sp<AMessage> msg = new AMessage(kWhatSetSource, this);
msg->setObject("source", source);
msg->post();
}
@@ -231,7 +231,7 @@
status_t err = mSource->read(&startTimeUs, &endTimeUs,
&(parcelEvent->parcel), options);
if (err == WOULD_BLOCK) {
- sp<AMessage> msg = new AMessage(kWhatRetryRead, id());
+ sp<AMessage> msg = new AMessage(kWhatRetryRead, this);
if (options != NULL) {
int64_t seekTimeUs = kInvalidTimeUs;
MediaSource::ReadOptions::SeekMode seekMode =
@@ -259,7 +259,7 @@
void TimedTextPlayer::postTextEvent(const sp<ParcelEvent>& parcel, int64_t timeUs) {
int64_t delayUs = delayUsFromCurrentTime(timeUs);
- sp<AMessage> msg = new AMessage(kWhatSendSubtitle, id());
+ sp<AMessage> msg = new AMessage(kWhatSendSubtitle, this);
msg->setInt32("generation", mSendSubtitleGeneration);
if (parcel != NULL) {
msg->setObject("subtitle", parcel);
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.h b/media/libstagefright/timedtext/TimedTextPlayer.h
index ec8ed25..9cb49ec 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.h
+++ b/media/libstagefright/timedtext/TimedTextPlayer.h
@@ -27,7 +27,7 @@
namespace android {
-class AMessage;
+struct AMessage;
class MediaPlayerBase;
class TimedTextDriver;
class TimedTextSource;
diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.h b/media/libstagefright/timedtext/TimedTextSRTSource.h
index 598c200..232675e 100644
--- a/media/libstagefright/timedtext/TimedTextSRTSource.h
+++ b/media/libstagefright/timedtext/TimedTextSRTSource.h
@@ -25,7 +25,7 @@
namespace android {
-class AString;
+struct AString;
class DataSource;
class MediaBuffer;
class Parcel;
diff --git a/media/libstagefright/timedtext/test/TimedTextSRTSource_test.cpp b/media/libstagefright/timedtext/test/TimedTextSRTSource_test.cpp
index 40e93c7..3a06d61 100644
--- a/media/libstagefright/timedtext/test/TimedTextSRTSource_test.cpp
+++ b/media/libstagefright/timedtext/test/TimedTextSRTSource_test.cpp
@@ -120,26 +120,26 @@
err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
EXPECT_EQ(OK, err);
CheckStartTimeMs(parcel, i * kSecToMsec);
- subtitle = StringPrintf("%d\n\n", i);
+ 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 = StringPrintf("6\n\n");
+ subtitle = AStringPrintf("6\n\n");
CheckDataEquals(parcel, subtitle.c_str());
err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
EXPECT_EQ(OK, err);
CheckStartTimeMs(parcel, 5800);
- subtitle = StringPrintf("7\n\n");
+ subtitle = AStringPrintf("7\n\n");
CheckDataEquals(parcel, subtitle.c_str());
err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
EXPECT_EQ(OK, err);
CheckStartTimeMs(parcel, 6000);
- subtitle = StringPrintf("8\n\n");
+ subtitle = AStringPrintf("8\n\n");
CheckDataEquals(parcel, subtitle.c_str());
err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
@@ -202,21 +202,21 @@
err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
EXPECT_EQ(OK, err);
EXPECT_EQ(5500 * kMsecToUsec, startTimeUs);
- subtitle = StringPrintf("6\n\n");
+ 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 = StringPrintf("7\n\n");
+ 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 = StringPrintf("8\n\n");
+ subtitle = AStringPrintf("8\n\n");
CheckDataEquals(parcel, subtitle.c_str());
}
diff --git a/media/libstagefright/webm/WebmWriter.cpp b/media/libstagefright/webm/WebmWriter.cpp
index 03cf92a..737f144 100644
--- a/media/libstagefright/webm/WebmWriter.cpp
+++ b/media/libstagefright/webm/WebmWriter.cpp
@@ -80,38 +80,6 @@
mCuePoints);
}
-WebmWriter::WebmWriter(const char *filename)
- : mInitCheck(NO_INIT),
- mTimeCodeScale(1000000),
- mStartTimestampUs(0),
- mStartTimeOffsetMs(0),
- mSegmentOffset(0),
- mSegmentDataStart(0),
- mInfoOffset(0),
- mInfoSize(0),
- mTracksOffset(0),
- mCuesOffset(0),
- mPaused(false),
- mStarted(false),
- mIsFileSizeLimitExplicitlyRequested(false),
- mIsRealTimeRecording(false),
- mStreamableFile(true),
- mEstimatedCuesSize(0) {
- mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
- if (mFd >= 0) {
- ALOGV("fd %d; flags: %o", mFd, fcntl(mFd, F_GETFL, 0));
- mInitCheck = OK;
- }
- mStreams[kAudioIndex] = WebmStream(kAudioType, "Audio", &WebmWriter::audioTrack);
- mStreams[kVideoIndex] = WebmStream(kVideoType, "Video", &WebmWriter::videoTrack);
- mSinkThread = new WebmFrameSinkThread(
- mFd,
- mSegmentDataStart,
- mStreams[kVideoIndex].mSink,
- mStreams[kAudioIndex].mSink,
- mCuePoints);
-}
-
// static
sp<WebmElement> WebmWriter::videoTrack(const sp<MetaData>& md) {
int32_t width, height;
@@ -333,7 +301,6 @@
serializeCodedUnsigned(segmentSizeCoded, bary);
::write(mFd, bary, sizeOf(kMkvUnknownLength));
- uint64_t size;
uint64_t durationOffset = mInfoOffset + sizeOf(kMkvInfo) + sizeOf(mInfoSize)
+ sizeOf(kMkvSegmentDuration) + sizeOf(sizeof(double));
sp<WebmElement> duration = new WebmFloat(
diff --git a/media/libstagefright/webm/WebmWriter.h b/media/libstagefright/webm/WebmWriter.h
index 36b6965..4ad770e 100644
--- a/media/libstagefright/webm/WebmWriter.h
+++ b/media/libstagefright/webm/WebmWriter.h
@@ -37,7 +37,6 @@
class WebmWriter : public MediaWriter {
public:
WebmWriter(int fd);
- WebmWriter(const char *filename);
~WebmWriter() { reset(); }
diff --git a/media/libstagefright/wifi-display/MediaSender.cpp b/media/libstagefright/wifi-display/MediaSender.cpp
index b1cdec0..6f0087f 100644
--- a/media/libstagefright/wifi-display/MediaSender.cpp
+++ b/media/libstagefright/wifi-display/MediaSender.cpp
@@ -121,7 +121,7 @@
}
if (err == OK) {
- sp<AMessage> notify = new AMessage(kWhatSenderNotify, id());
+ sp<AMessage> notify = new AMessage(kWhatSenderNotify, this);
notify->setInt32("generation", mGeneration);
mTSSender = new RTPSender(mNetSession, notify);
looper()->registerHandler(mTSSender);
@@ -170,7 +170,7 @@
return INVALID_OPERATION;
}
- sp<AMessage> notify = new AMessage(kWhatSenderNotify, id());
+ sp<AMessage> notify = new AMessage(kWhatSenderNotify, this);
notify->setInt32("generation", mGeneration);
notify->setSize("trackIndex", trackIndex);
diff --git a/media/libstagefright/wifi-display/VideoFormats.cpp b/media/libstagefright/wifi-display/VideoFormats.cpp
index 04e02c1..2f4af5b 100644
--- a/media/libstagefright/wifi-display/VideoFormats.cpp
+++ b/media/libstagefright/wifi-display/VideoFormats.cpp
@@ -435,7 +435,7 @@
// max-hres (none or 2 byte)
// max-vres (none or 2 byte)
- return StringPrintf(
+ return AStringPrintf(
"%02x 00 %02x %02x %08x %08x %08x 00 0000 0000 00 none none",
forM4Message ? 0x00 : ((mNativeIndex << 3) | mNativeType),
mConfigs[mNativeType][mNativeIndex].profile,
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.cpp b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
index e88a3bd..4e72533 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.cpp
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
@@ -95,11 +95,11 @@
return INVALID_OPERATION;
}
- sp<AMessage> rtpNotify = new AMessage(kWhatRTPNotify, id());
+ sp<AMessage> rtpNotify = new AMessage(kWhatRTPNotify, this);
sp<AMessage> rtcpNotify;
if (remoteRTCPPort >= 0) {
- rtcpNotify = new AMessage(kWhatRTCPNotify, id());
+ rtcpNotify = new AMessage(kWhatRTCPNotify, this);
}
CHECK_EQ(mRTPSessionID, 0);
diff --git a/media/libstagefright/wifi-display/source/Converter.cpp b/media/libstagefright/wifi-display/source/Converter.cpp
index 2834a66..8368945 100644
--- a/media/libstagefright/wifi-display/source/Converter.cpp
+++ b/media/libstagefright/wifi-display/source/Converter.cpp
@@ -93,7 +93,7 @@
void Converter::shutdownAsync() {
ALOGV("shutdown");
- (new AMessage(kWhatShutdown, id()))->post();
+ (new AMessage(kWhatShutdown, this))->post();
}
status_t Converter::init() {
@@ -482,11 +482,11 @@
#if 1
if (mEncoderActivityNotify == NULL) {
- mEncoderActivityNotify = new AMessage(kWhatEncoderActivity, id());
+ mEncoderActivityNotify = new AMessage(kWhatEncoderActivity, this);
}
mEncoder->requestActivityNotification(mEncoderActivityNotify->dup());
#else
- sp<AMessage> notify = new AMessage(kWhatEncoderActivity, id());
+ sp<AMessage> notify = new AMessage(kWhatEncoderActivity, this);
notify->setInt64("whenUs", ALooper::GetNowUs());
mEncoder->requestActivityNotification(notify);
#endif
@@ -731,8 +731,7 @@
// MediaSender will post the following message when HDCP
// is done, to release the output buffer back to encoder.
- sp<AMessage> notify(new AMessage(
- kWhatReleaseOutputBuffer, id()));
+ sp<AMessage> notify(new AMessage(kWhatReleaseOutputBuffer, this));
notify->setInt32("bufferIndex", bufferIndex);
buffer = new ABuffer(
@@ -787,18 +786,18 @@
}
void Converter::requestIDRFrame() {
- (new AMessage(kWhatRequestIDRFrame, id()))->post();
+ (new AMessage(kWhatRequestIDRFrame, this))->post();
}
void Converter::dropAFrame() {
// Unsupported in surface input mode.
CHECK(!(mFlags & FLAG_USE_SURFACE_INPUT));
- (new AMessage(kWhatDropAFrame, id()))->post();
+ (new AMessage(kWhatDropAFrame, this))->post();
}
void Converter::suspendEncoding(bool suspend) {
- sp<AMessage> msg = new AMessage(kWhatSuspendEncoding, id());
+ sp<AMessage> msg = new AMessage(kWhatSuspendEncoding, this);
msg->setInt32("suspend", suspend);
msg->post();
}
diff --git a/media/libstagefright/wifi-display/source/MediaPuller.cpp b/media/libstagefright/wifi-display/source/MediaPuller.cpp
index 86b918f..ce07a4e 100644
--- a/media/libstagefright/wifi-display/source/MediaPuller.cpp
+++ b/media/libstagefright/wifi-display/source/MediaPuller.cpp
@@ -63,21 +63,21 @@
}
status_t MediaPuller::start() {
- return postSynchronouslyAndReturnError(new AMessage(kWhatStart, id()));
+ return postSynchronouslyAndReturnError(new AMessage(kWhatStart, this));
}
void MediaPuller::stopAsync(const sp<AMessage> ¬ify) {
- sp<AMessage> msg = new AMessage(kWhatStop, id());
+ sp<AMessage> msg = new AMessage(kWhatStop, this);
msg->setMessage("notify", notify);
msg->post();
}
void MediaPuller::pause() {
- (new AMessage(kWhatPause, id()))->post();
+ (new AMessage(kWhatPause, this))->post();
}
void MediaPuller::resume() {
- (new AMessage(kWhatResume, id()))->post();
+ (new AMessage(kWhatResume, this))->post();
}
void MediaPuller::onMessageReceived(const sp<AMessage> &msg) {
@@ -105,7 +105,7 @@
sp<AMessage> response = new AMessage;
response->setInt32("err", err);
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
response->postReply(replyID);
break;
@@ -215,7 +215,7 @@
}
void MediaPuller::schedulePull() {
- sp<AMessage> msg = new AMessage(kWhatPull, id());
+ sp<AMessage> msg = new AMessage(kWhatPull, this);
msg->setInt32("generation", mPullGeneration);
msg->post();
}
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index 2cb4786..6080943 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -214,7 +214,7 @@
mConverter->shutdownAsync();
}
- sp<AMessage> msg = new AMessage(kWhatMediaPullerStopped, id());
+ sp<AMessage> msg = new AMessage(kWhatMediaPullerStopped, this);
if (mStarted && mMediaPuller != NULL) {
if (mRepeaterSource != NULL) {
@@ -382,7 +382,7 @@
size_t videoResolutionIndex,
VideoFormats::ProfileType videoProfileType,
VideoFormats::LevelType videoLevelType) {
- sp<AMessage> notify = new AMessage(kWhatMediaSenderNotify, id());
+ sp<AMessage> notify = new AMessage(kWhatMediaSenderNotify, this);
mMediaSender = new MediaSender(mNetSession, notify);
looper()->registerHandler(mMediaSender);
@@ -440,7 +440,7 @@
status_t WifiDisplaySource::PlaybackSession::play() {
updateLiveness();
- (new AMessage(kWhatResume, id()))->post();
+ (new AMessage(kWhatResume, this))->post();
return OK;
}
@@ -460,7 +460,7 @@
status_t WifiDisplaySource::PlaybackSession::pause() {
updateLiveness();
- (new AMessage(kWhatPause, id()))->post();
+ (new AMessage(kWhatPause, this))->post();
return OK;
}
@@ -786,7 +786,7 @@
size_t trackIndex = mTracks.size();
- sp<AMessage> notify = new AMessage(kWhatTrackNotify, id());
+ sp<AMessage> notify = new AMessage(kWhatTrackNotify, this);
notify->setSize("trackIndex", trackIndex);
sp<Track> track = new Track(notify, format);
@@ -833,7 +833,7 @@
int64_t whenUs = sampleTimeUs - mFirstSampleTimeUs + mFirstSampleTimeRealUs;
- sp<AMessage> msg = new AMessage(kWhatPullExtractorSample, id());
+ sp<AMessage> msg = new AMessage(kWhatPullExtractorSample, this);
msg->setInt32("generation", mPullExtractorGeneration);
msg->post(whenUs - nowUs);
@@ -857,7 +857,7 @@
size_t trackIndex;
CHECK_EQ((status_t)OK, mExtractor->getSampleTrackIndex(&trackIndex));
- sp<AMessage> msg = new AMessage(kWhatConverterNotify, id());
+ sp<AMessage> msg = new AMessage(kWhatConverterNotify, this);
msg->setSize(
"trackIndex", mExtractorTrackToInternalTrack.valueFor(trackIndex));
@@ -955,7 +955,7 @@
? MEDIA_MIMETYPE_AUDIO_RAW : MEDIA_MIMETYPE_AUDIO_AAC);
}
- notify = new AMessage(kWhatConverterNotify, id());
+ notify = new AMessage(kWhatConverterNotify, this);
notify->setSize("trackIndex", trackIndex);
sp<Converter> converter = new Converter(notify, codecLooper, format);
@@ -970,7 +970,7 @@
return err;
}
- notify = new AMessage(Converter::kWhatMediaPullerNotify, converter->id());
+ notify = new AMessage(Converter::kWhatMediaPullerNotify, converter);
notify->setSize("trackIndex", trackIndex);
sp<MediaPuller> puller = new MediaPuller(source, notify);
@@ -980,7 +980,7 @@
*numInputBuffers = converter->getInputBufferCount();
}
- notify = new AMessage(kWhatTrackNotify, id());
+ notify = new AMessage(kWhatTrackNotify, this);
notify->setSize("trackIndex", trackIndex);
sp<Track> track = new Track(
diff --git a/media/libstagefright/wifi-display/source/RepeaterSource.cpp b/media/libstagefright/wifi-display/source/RepeaterSource.cpp
index 59d7e6e..af6b663 100644
--- a/media/libstagefright/wifi-display/source/RepeaterSource.cpp
+++ b/media/libstagefright/wifi-display/source/RepeaterSource.cpp
@@ -173,7 +173,7 @@
}
void RepeaterSource::postRead() {
- (new AMessage(kWhatRead, mReflector->id()))->post();
+ (new AMessage(kWhatRead, mReflector))->post();
}
void RepeaterSource::onMessageReceived(const sp<AMessage> &msg) {
diff --git a/media/libstagefright/wifi-display/source/TSPacketizer.cpp b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
index 50d317a..4c5ad17 100644
--- a/media/libstagefright/wifi-display/source/TSPacketizer.cpp
+++ b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
@@ -106,7 +106,7 @@
|| !strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
for (size_t i = 0;; ++i) {
sp<ABuffer> csd;
- if (!mFormat->findBuffer(StringPrintf("csd-%d", i).c_str(), &csd)) {
+ if (!mFormat->findBuffer(AStringPrintf("csd-%d", i).c_str(), &csd)) {
break;
}
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index da405e2..14d0951 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -43,6 +43,10 @@
namespace android {
// static
+const int64_t WifiDisplaySource::kReaperIntervalUs;
+const int64_t WifiDisplaySource::kTeardownTriggerTimeouSecs;
+const int64_t WifiDisplaySource::kPlaybackSessionTimeoutSecs;
+const int64_t WifiDisplaySource::kPlaybackSessionTimeoutUs;
const AString WifiDisplaySource::sUserAgent = MakeUserAgent();
WifiDisplaySource::WifiDisplaySource(
@@ -53,7 +57,7 @@
mNetSession(netSession),
mClient(client),
mSessionID(0),
- mStopReplyID(0),
+ mStopReplyID(NULL),
mChosenRTPPort(-1),
mUsingPCMAudio(false),
mClientSessionID(0),
@@ -102,7 +106,7 @@
status_t WifiDisplaySource::start(const char *iface) {
CHECK_EQ(mState, INITIALIZED);
- sp<AMessage> msg = new AMessage(kWhatStart, id());
+ sp<AMessage> msg = new AMessage(kWhatStart, this);
msg->setString("iface", iface);
sp<AMessage> response;
@@ -110,21 +114,21 @@
}
status_t WifiDisplaySource::stop() {
- sp<AMessage> msg = new AMessage(kWhatStop, id());
+ sp<AMessage> msg = new AMessage(kWhatStop, this);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
status_t WifiDisplaySource::pause() {
- sp<AMessage> msg = new AMessage(kWhatPause, id());
+ sp<AMessage> msg = new AMessage(kWhatPause, this);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
status_t WifiDisplaySource::resume() {
- sp<AMessage> msg = new AMessage(kWhatResume, id());
+ sp<AMessage> msg = new AMessage(kWhatResume, this);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
@@ -134,7 +138,7 @@
switch (msg->what()) {
case kWhatStart:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
AString iface;
@@ -163,7 +167,7 @@
if (err == OK) {
if (inet_aton(iface.c_str(), &mInterfaceAddr) != 0) {
- sp<AMessage> notify = new AMessage(kWhatRTSPNotify, id());
+ sp<AMessage> notify = new AMessage(kWhatRTSPNotify, this);
err = mNetSession->createRTSPServer(
mInterfaceAddr, port, notify, &mSessionID);
@@ -306,7 +310,7 @@
if (err == OK) {
mState = AWAITING_CLIENT_TEARDOWN;
- (new AMessage(kWhatTeardownTriggerTimedOut, id()))->post(
+ (new AMessage(kWhatTeardownTriggerTimedOut, this))->post(
kTeardownTriggerTimeouSecs * 1000000ll);
break;
@@ -321,7 +325,7 @@
case kWhatPause:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
status_t err = OK;
@@ -341,7 +345,7 @@
case kWhatResume:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
status_t err = OK;
@@ -488,7 +492,7 @@
if (mState == AWAITING_CLIENT_TEARDOWN) {
ALOGI("TEARDOWN trigger timed out, forcing disconnection.");
- CHECK_NE(mStopReplyID, 0);
+ CHECK(mStopReplyID != NULL);
finishStop();
break;
}
@@ -525,7 +529,7 @@
// HDCPObserver::notify is completely handled before
// we clear the HDCP instance and unload the shared
// library :(
- (new AMessage(kWhatFinishStop2, id()))->post(300000ll);
+ (new AMessage(kWhatFinishStop2, this))->post(300000ll);
break;
}
@@ -594,7 +598,7 @@
AppendCommonResponse(&request, mNextCSeq);
request.append("Content-Type: text/parameters\r\n");
- request.append(StringPrintf("Content-Length: %d\r\n", body.size()));
+ request.append(AStringPrintf("Content-Length: %d\r\n", body.size()));
request.append("\r\n");
request.append(body);
@@ -635,26 +639,26 @@
if (mSinkSupportsAudio) {
body.append(
- StringPrintf("wfd_audio_codecs: %s\r\n",
+ AStringPrintf("wfd_audio_codecs: %s\r\n",
(mUsingPCMAudio
? "LPCM 00000002 00" // 2 ch PCM 48kHz
: "AAC 00000001 00"))); // 2 ch AAC 48kHz
}
body.append(
- StringPrintf(
+ AStringPrintf(
"wfd_presentation_URL: rtsp://%s/wfd1.0/streamid=0 none\r\n",
mClientInfo.mLocalIP.c_str()));
body.append(
- StringPrintf(
+ AStringPrintf(
"wfd_client_rtp_ports: %s\r\n", mWfdClientRtpPorts.c_str()));
AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
AppendCommonResponse(&request, mNextCSeq);
request.append("Content-Type: text/parameters\r\n");
- request.append(StringPrintf("Content-Length: %d\r\n", body.size()));
+ request.append(AStringPrintf("Content-Length: %d\r\n", body.size()));
request.append("\r\n");
request.append(body);
@@ -700,7 +704,7 @@
AppendCommonResponse(&request, mNextCSeq);
request.append("Content-Type: text/parameters\r\n");
- request.append(StringPrintf("Content-Length: %d\r\n", body.size()));
+ request.append(AStringPrintf("Content-Length: %d\r\n", body.size()));
request.append("\r\n");
request.append(body);
@@ -725,7 +729,7 @@
CHECK_EQ(sessionID, mClientSessionID);
request.append(
- StringPrintf("Session: %d\r\n", mClientInfo.mPlaybackSessionID));
+ AStringPrintf("Session: %d\r\n", mClientInfo.mPlaybackSessionID));
request.append("\r\n"); // Empty body
status_t err =
@@ -1023,7 +1027,7 @@
}
mReaperPending = true;
- (new AMessage(kWhatReapDeadClients, id()))->post(kReaperIntervalUs);
+ (new AMessage(kWhatReapDeadClients, this))->post(kReaperIntervalUs);
}
void WifiDisplaySource::scheduleKeepAlive(int32_t sessionID) {
@@ -1031,7 +1035,7 @@
// expire, make sure the timeout is greater than 5 secs to begin with.
CHECK_GT(kPlaybackSessionTimeoutUs, 5000000ll);
- sp<AMessage> msg = new AMessage(kWhatKeepAlive, id());
+ sp<AMessage> msg = new AMessage(kWhatKeepAlive, this);
msg->setInt32("sessionID", sessionID);
msg->post(kPlaybackSessionTimeoutUs - 5000000ll);
}
@@ -1235,7 +1239,7 @@
int32_t playbackSessionID = makeUniquePlaybackSessionID();
- sp<AMessage> notify = new AMessage(kWhatPlaybackSessionNotify, id());
+ sp<AMessage> notify = new AMessage(kWhatPlaybackSessionNotify, this);
notify->setInt32("playbackSessionID", playbackSessionID);
notify->setInt32("sessionID", sessionID);
@@ -1301,7 +1305,7 @@
if (rtpMode == RTPSender::TRANSPORT_TCP_INTERLEAVED) {
response.append(
- StringPrintf(
+ AStringPrintf(
"Transport: RTP/AVP/TCP;interleaved=%d-%d;",
clientRtp, clientRtcp));
} else {
@@ -1314,14 +1318,14 @@
if (clientRtcp >= 0) {
response.append(
- StringPrintf(
+ AStringPrintf(
"Transport: RTP/AVP/%s;unicast;client_port=%d-%d;"
"server_port=%d-%d\r\n",
transportString.c_str(),
clientRtp, clientRtcp, serverRtp, serverRtp + 1));
} else {
response.append(
- StringPrintf(
+ AStringPrintf(
"Transport: RTP/AVP/%s;unicast;client_port=%d;"
"server_port=%d\r\n",
transportString.c_str(),
@@ -1466,7 +1470,7 @@
mNetSession->sendRequest(sessionID, response.c_str());
if (mState == AWAITING_CLIENT_TEARDOWN) {
- CHECK_NE(mStopReplyID, 0);
+ CHECK(mStopReplyID != NULL);
finishStop();
} else {
mClient->onDisplayError(IRemoteDisplayClient::kDisplayErrorUnknown);
@@ -1581,15 +1585,15 @@
response->append(buf);
response->append("\r\n");
- response->append(StringPrintf("Server: %s\r\n", sUserAgent.c_str()));
+ response->append(AStringPrintf("Server: %s\r\n", sUserAgent.c_str()));
if (cseq >= 0) {
- response->append(StringPrintf("CSeq: %d\r\n", cseq));
+ response->append(AStringPrintf("CSeq: %d\r\n", cseq));
}
if (playbackSessionID >= 0ll) {
response->append(
- StringPrintf(
+ AStringPrintf(
"Session: %d;timeout=%lld\r\n",
playbackSessionID, kPlaybackSessionTimeoutSecs));
}
@@ -1703,7 +1707,7 @@
return ERROR_UNSUPPORTED;
}
- sp<AMessage> notify = new AMessage(kWhatHDCPNotify, id());
+ sp<AMessage> notify = new AMessage(kWhatHDCPNotify, this);
mHDCPObserver = new HDCPObserver(notify);
status_t err = mHDCP->setObserver(mHDCPObserver);
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.h b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
index 750265f..0f779e4 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.h
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
@@ -27,6 +27,7 @@
namespace android {
+struct AReplyToken;
struct IHDCP;
struct IRemoteDisplayClient;
struct ParsedMessage;
@@ -121,7 +122,7 @@
struct in_addr mInterfaceAddr;
int32_t mSessionID;
- uint32_t mStopReplyID;
+ sp<AReplyToken> mStopReplyID;
AString mWfdClientRtpPorts;
int32_t mChosenRTPPort; // extracted from "wfd_client_rtp_ports"
diff --git a/media/libstagefright/yuv/YUVImage.cpp b/media/libstagefright/yuv/YUVImage.cpp
index bb3e2fd..c098135 100644
--- a/media/libstagefright/yuv/YUVImage.cpp
+++ b/media/libstagefright/yuv/YUVImage.cpp
@@ -374,13 +374,13 @@
void YUVImage::yuv2rgb(uint8_t yValue, uint8_t uValue, uint8_t vValue,
uint8_t *r, uint8_t *g, uint8_t *b) const {
- *r = yValue + (1.370705 * (vValue-128));
- *g = yValue - (0.698001 * (vValue-128)) - (0.337633 * (uValue-128));
- *b = yValue + (1.732446 * (uValue-128));
+ int rTmp = yValue + (1.370705 * (vValue-128));
+ int gTmp = yValue - (0.698001 * (vValue-128)) - (0.337633 * (uValue-128));
+ int bTmp = yValue + (1.732446 * (uValue-128));
- *r = clamp(*r, 0, 255);
- *g = clamp(*g, 0, 255);
- *b = clamp(*b, 0, 255);
+ *r = clamp(rTmp, 0, 255);
+ *g = clamp(gTmp, 0, 255);
+ *b = clamp(bTmp, 0, 255);
}
bool YUVImage::writeToPPM(const char *filename) const {
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index 3a280f0..f1b84ad 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -11,7 +11,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- main_mediaserver.cpp
+ main_mediaserver.cpp
LOCAL_SHARED_LIBRARIES := \
libaudioflinger \
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index af1c9e6..263dd32 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -33,7 +33,7 @@
#include "CameraService.h"
#include "MediaLogService.h"
#include "MediaPlayerService.h"
-#include "AudioPolicyService.h"
+#include "service/AudioPolicyService.h"
#include "SoundTriggerHwService.h"
using namespace android;
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index e0d679d..3eafd6f 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -131,13 +131,22 @@
struct usb_endpoint_descriptor *ep_in_desc = NULL;
struct usb_endpoint_descriptor *ep_out_desc = NULL;
struct usb_endpoint_descriptor *ep_intr_desc = NULL;
+ //USB3 add USB_DT_SS_ENDPOINT_COMP as companion descriptor;
+ struct usb_ss_ep_comp_descriptor *ep_ss_ep_comp_desc = NULL;
for (int i = 0; i < 3; i++) {
ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
+ if (ep && ep->bDescriptorType == USB_DT_SS_ENDPOINT_COMP) {
+ ALOGD("Descriptor type is USB_DT_SS_ENDPOINT_COMP for USB3 \n");
+ ep_ss_ep_comp_desc = (usb_ss_ep_comp_descriptor*)ep;
+ ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
+ }
+
if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) {
ALOGE("endpoints not found\n");
usb_device_close(device);
return NULL;
}
+
if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
ep_in_desc = ep;
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index ed00b72..80c1c2f 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -116,7 +116,7 @@
case kWhatStopActivityNotifications:
{
- uint32_t replyID;
+ sp<AReplyToken> replyID;
msg->senderAwaitsResponse(&replyID);
mCodec->mGeneration++;
@@ -136,7 +136,7 @@
static void requestActivityNotification(AMediaCodec *codec) {
- (new AMessage(kWhatRequestActivityNotifications, codec->mHandler->id()))->post();
+ (new AMessage(kWhatRequestActivityNotifications, codec->mHandler))->post();
}
extern "C" {
@@ -219,7 +219,7 @@
if (ret != OK) {
return translate_error(ret);
}
- mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler->id());
+ mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler);
mData->mActivityNotification->setInt32("generation", mData->mGeneration);
requestActivityNotification(mData);
return AMEDIA_OK;
@@ -229,7 +229,7 @@
media_status_t AMediaCodec_stop(AMediaCodec *mData) {
media_status_t ret = translate_error(mData->mCodec->stop());
- sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler->id());
+ sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler);
sp<AMessage> response;
msg->postAndAwaitResponse(&response);
mData->mActivityNotification.clear();
@@ -352,7 +352,8 @@
}
//EXPORT
-media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) {
+media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback,
+ void *userdata) {
mData->mCallback = callback;
mData->mCallbackUserData = userdata;
return AMEDIA_OK;
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index db57d0b..0ecd64f 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -70,7 +70,8 @@
}
EXPORT
-media_status_t AMediaExtractor_setDataSourceFd(AMediaExtractor *mData, int fd, off64_t offset, off64_t length) {
+media_status_t AMediaExtractor_setDataSourceFd(AMediaExtractor *mData, int fd, off64_t offset,
+ off64_t length) {
ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
return translate_error(mData->mImpl->setDataSource(fd, offset, length));
}
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index f0196c6..642ff82 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -29,6 +29,12 @@
include $(CLEAR_VARS)
+# Clang++ aborts on AudioMixer.cpp,
+# b/18373866, "do not know how to split this operator."
+ifeq ($(filter $(TARGET_ARCH),arm arm64),$(TARGET_ARCH))
+ LOCAL_CLANG := false
+endif
+
LOCAL_SRC_FILES:= \
AudioFlinger.cpp \
Threads.cpp \
@@ -68,19 +74,20 @@
LOCAL_MODULE:= libaudioflinger
LOCAL_32_BIT_ONLY := true
-LOCAL_SRC_FILES += FastMixer.cpp FastMixerState.cpp AudioWatchdog.cpp
-LOCAL_SRC_FILES += FastThread.cpp FastThreadState.cpp
-LOCAL_SRC_FILES += FastCapture.cpp FastCaptureState.cpp
+LOCAL_SRC_FILES += \
+ AudioWatchdog.cpp \
+ FastCapture.cpp \
+ FastCaptureDumpState.cpp \
+ FastCaptureState.cpp \
+ FastMixer.cpp \
+ FastMixerDumpState.cpp \
+ FastMixerState.cpp \
+ FastThread.cpp \
+ FastThreadDumpState.cpp \
+ FastThreadState.cpp
LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"'
-# Define ANDROID_SMP appropriately. Used to get inline tracing fast-path.
-ifeq ($(TARGET_CPU_SMP),true)
- LOCAL_CFLAGS += -DANDROID_SMP=1
-else
- LOCAL_CFLAGS += -DANDROID_SMP=0
-endif
-
LOCAL_CFLAGS += -fvisibility=hidden
include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index ccc05a1..461b5d3 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -185,7 +185,8 @@
char value[PROPERTY_VALUE_MAX];
bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
if (doLog) {
- mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters", MemoryHeapBase::READ_ONLY);
+ mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters",
+ MemoryHeapBase::READ_ONLY);
}
#ifdef TEE_SINK
@@ -401,6 +402,9 @@
String8 result(kClientLockedString);
write(fd, result.string(), result.size());
}
+
+ EffectDumpEffects(fd);
+
dumpClients(fd, args);
if (clientLocked) {
mClientLock.unlock();
@@ -822,14 +826,20 @@
if (ret != NO_ERROR) {
return false;
}
-
+ bool mute = true;
bool state = AUDIO_MODE_INVALID;
AutoMutex lock(mHardwareLock);
- audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
- dev->get_mic_mute(dev, &state);
+ for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+ audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
+ status_t result = dev->get_mic_mute(dev, &state);
+ if (result == NO_ERROR) {
+ mute = mute && state;
+ }
+ }
mHardwareStatus = AUDIO_HW_IDLE;
- return state;
+
+ return mute;
}
status_t AudioFlinger::setMasterMute(bool muted)
@@ -1211,7 +1221,7 @@
mNotificationClients.add(pid, notificationClient);
- sp<IBinder> binder = client->asBinder();
+ sp<IBinder> binder = IInterface::asBinder(client);
binder->linkToDeath(notificationClient);
clientAdded = true;
}
@@ -1947,18 +1957,18 @@
status_t AudioFlinger::openInput(audio_module_handle_t module,
audio_io_handle_t *input,
audio_config_t *config,
- audio_devices_t *device,
+ audio_devices_t *devices,
const String8& address,
audio_source_t source,
audio_input_flags_t flags)
{
Mutex::Autolock _l(mLock);
- if (*device == AUDIO_DEVICE_NONE) {
+ if (*devices == AUDIO_DEVICE_NONE) {
return BAD_VALUE;
}
- sp<RecordThread> thread = openInput_l(module, input, config, *device, address, source, flags);
+ sp<RecordThread> thread = openInput_l(module, input, config, *devices, address, source, flags);
if (thread != 0) {
// notify client processes of the new input creation
@@ -1971,12 +1981,12 @@
sp<AudioFlinger::RecordThread> AudioFlinger::openInput_l(audio_module_handle_t module,
audio_io_handle_t *input,
audio_config_t *config,
- audio_devices_t device,
+ audio_devices_t devices,
const String8& address,
audio_source_t source,
audio_input_flags_t flags)
{
- AudioHwDevice *inHwDev = findSuitableHwDev_l(module, device);
+ AudioHwDevice *inHwDev = findSuitableHwDev_l(module, devices);
if (inHwDev == NULL) {
*input = AUDIO_IO_HANDLE_NONE;
return 0;
@@ -1989,7 +1999,7 @@
audio_config_t halconfig = *config;
audio_hw_device_t *inHwHal = inHwDev->hwDevice();
audio_stream_in_t *inStream = NULL;
- status_t status = inHwHal->open_input_stream(inHwHal, *input, device, &halconfig,
+ status_t status = inHwHal->open_input_stream(inHwHal, *input, devices, &halconfig,
&inStream, flags, address.string(), source);
ALOGV("openInput_l() openInputStream returned input %p, SamplingRate %d"
", Format %#x, Channels %x, flags %#x, status %d addr %s",
@@ -2011,7 +2021,7 @@
// FIXME describe the change proposed by HAL (save old values so we can log them here)
ALOGV("openInput_l() reopening with proposed sampling rate and channel mask");
inStream = NULL;
- status = inHwHal->open_input_stream(inHwHal, *input, device, &halconfig,
+ status = inHwHal->open_input_stream(inHwHal, *input, devices, &halconfig,
&inStream, flags, address.string(), source);
// FIXME log this new status; HAL should not propose any further changes
}
@@ -2076,7 +2086,7 @@
inputStream,
*input,
primaryOutputDevice_l(),
- device
+ devices
#ifdef TEE_SINK
, teeSink
#endif
@@ -2799,13 +2809,13 @@
struct Entry {
-#define MAX_NAME 32 // %Y%m%d%H%M%S_%d.wav
- char mName[MAX_NAME];
+#define TEE_MAX_FILENAME 32 // %Y%m%d%H%M%S_%d.wav = 4+2+2+2+2+2+1+1+4+1 = 21
+ char mFileName[TEE_MAX_FILENAME];
};
int comparEntry(const void *p1, const void *p2)
{
- return strcmp(((const Entry *) p1)->mName, ((const Entry *) p2)->mName);
+ return strcmp(((const Entry *) p1)->mFileName, ((const Entry *) p2)->mFileName);
}
#ifdef TEE_SINK
@@ -2824,11 +2834,11 @@
DIR *dir = opendir(teePath);
teePath[teePathLen++] = '/';
if (dir != NULL) {
-#define MAX_SORT 20 // number of entries to sort
-#define MAX_KEEP 10 // number of entries to keep
- struct Entry entries[MAX_SORT];
+#define TEE_MAX_SORT 20 // number of entries to sort
+#define TEE_MAX_KEEP 10 // number of entries to keep
+ struct Entry entries[TEE_MAX_SORT];
size_t entryCount = 0;
- while (entryCount < MAX_SORT) {
+ while (entryCount < TEE_MAX_SORT) {
struct dirent de;
struct dirent *result = NULL;
int rc = readdir_r(dir, &de, &result);
@@ -2845,17 +2855,17 @@
}
// ignore non .wav file entries
size_t nameLen = strlen(de.d_name);
- if (nameLen <= 4 || nameLen >= MAX_NAME ||
+ if (nameLen <= 4 || nameLen >= TEE_MAX_FILENAME ||
strcmp(&de.d_name[nameLen - 4], ".wav")) {
continue;
}
- strcpy(entries[entryCount++].mName, de.d_name);
+ strcpy(entries[entryCount++].mFileName, de.d_name);
}
(void) closedir(dir);
- if (entryCount > MAX_KEEP) {
+ if (entryCount > TEE_MAX_KEEP) {
qsort(entries, entryCount, sizeof(Entry), comparEntry);
- for (size_t i = 0; i < entryCount - MAX_KEEP; ++i) {
- strcpy(&teePath[teePathLen], entries[i].mName);
+ for (size_t i = 0; i < entryCount - TEE_MAX_KEEP; ++i) {
+ strcpy(&teePath[teePathLen], entries[i].mFileName);
(void) unlink(teePath);
}
}
@@ -2939,4 +2949,4 @@
return BnAudioFlinger::onTransact(code, data, reply, flags);
}
-}; // namespace android
+} // namespace android
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index aa0af1f..7b76185 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -796,9 +796,13 @@
#undef INCLUDING_FROM_AUDIOFLINGER_H
const char *formatToString(audio_format_t format);
+String8 inputFlagsToString(audio_input_flags_t flags);
+String8 outputFlagsToString(audio_output_flags_t flags);
+String8 devicesToString(audio_devices_t devices);
+const char *sourceToString(audio_source_t source);
// ----------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
#endif // ANDROID_AUDIO_FLINGER_H
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index fd28ea1..93d821a 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -341,11 +341,46 @@
ALOGV("RemixBufferProvider(%p)(%#x, %#x, %#x) %zu %zu",
this, format, inputChannelMask, outputChannelMask,
mInputChannels, mOutputChannels);
- // TODO: consider channel representation in index array formulation
- // We ignore channel representation, and just use the bits.
- memcpy_by_index_array_initialization(mIdxAry, ARRAY_SIZE(mIdxAry),
- audio_channel_mask_get_bits(outputChannelMask),
- audio_channel_mask_get_bits(inputChannelMask));
+
+ const audio_channel_representation_t inputRepresentation =
+ audio_channel_mask_get_representation(inputChannelMask);
+ const audio_channel_representation_t outputRepresentation =
+ audio_channel_mask_get_representation(outputChannelMask);
+ const uint32_t inputBits = audio_channel_mask_get_bits(inputChannelMask);
+ const uint32_t outputBits = audio_channel_mask_get_bits(outputChannelMask);
+
+ switch (inputRepresentation) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ switch (outputRepresentation) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ memcpy_by_index_array_initialization(mIdxAry, ARRAY_SIZE(mIdxAry),
+ outputBits, inputBits);
+ return;
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ // TODO: output channel index mask not currently allowed
+ // fall through
+ default:
+ break;
+ }
+ break;
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ switch (outputRepresentation) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ memcpy_by_index_array_initialization_src_index(mIdxAry, ARRAY_SIZE(mIdxAry),
+ outputBits, inputBits);
+ return;
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ // TODO: output channel index mask not currently allowed
+ // fall through
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ LOG_ALWAYS_FATAL("invalid channel mask conversion from %#x to %#x",
+ inputChannelMask, outputChannelMask);
}
void AudioMixer::RemixBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
@@ -430,6 +465,10 @@
mState.mLog = log;
}
+static inline audio_format_t selectMixerInFormat(audio_format_t inputFormat __unused) {
+ return kUseFloat && kUseNewMixer ? AUDIO_FORMAT_PCM_FLOAT : AUDIO_FORMAT_PCM_16_BIT;
+}
+
int AudioMixer::getTrackName(audio_channel_mask_t channelMask,
audio_format_t format, int sessionId)
{
@@ -492,24 +531,23 @@
t->mInputBufferProvider = NULL;
t->mReformatBufferProvider = NULL;
t->downmixerBufferProvider = NULL;
+ t->mPostDownmixReformatBufferProvider = NULL;
t->mMixerFormat = AUDIO_FORMAT_PCM_16_BIT;
t->mFormat = format;
- t->mMixerInFormat = kUseFloat && kUseNewMixer
- ? AUDIO_FORMAT_PCM_FLOAT : AUDIO_FORMAT_PCM_16_BIT;
+ t->mMixerInFormat = selectMixerInFormat(format);
+ t->mDownmixRequiresFormat = AUDIO_FORMAT_INVALID; // no format required
t->mMixerChannelMask = audio_channel_mask_from_representation_and_bits(
AUDIO_CHANNEL_REPRESENTATION_POSITION, AUDIO_CHANNEL_OUT_STEREO);
t->mMixerChannelCount = audio_channel_count_from_out_mask(t->mMixerChannelMask);
// Check the downmixing (or upmixing) requirements.
- status_t status = initTrackDownmix(t, n);
+ status_t status = t->prepareForDownmix();
if (status != OK) {
ALOGE("AudioMixer::getTrackName invalid channelMask (%#x)", channelMask);
return -1;
}
- // initTrackDownmix() may change the input format requirement.
- // If you desire floating point input to the mixer, it may change
- // to integer because the downmixer requires integer to process.
+ // prepareForDownmix() may change mDownmixRequiresFormat
ALOGVV("mMixerFormat:%#x mMixerInFormat:%#x\n", t->mMixerFormat, t->mMixerInFormat);
- prepareTrackForReformat(t, n);
+ t->prepareForReformat();
mTrackNames |= 1 << n;
return TRACK0 + n;
}
@@ -526,7 +564,7 @@
}
// Called when channel masks have changed for a track name
-// TODO: Fix Downmixbufferprofider not to (possibly) change mixer input format,
+// TODO: Fix DownmixerBufferProvider not to (possibly) change mixer input format,
// which will simplify this logic.
bool AudioMixer::setChannelMasks(int name,
audio_channel_mask_t trackChannelMask, audio_channel_mask_t mixerChannelMask) {
@@ -551,21 +589,18 @@
// channel masks have changed, does this track need a downmixer?
// update to try using our desired format (if we aren't already using it)
- const audio_format_t prevMixerInFormat = track.mMixerInFormat;
- track.mMixerInFormat = kUseFloat && kUseNewMixer
- ? AUDIO_FORMAT_PCM_FLOAT : AUDIO_FORMAT_PCM_16_BIT;
- const status_t status = initTrackDownmix(&mState.tracks[name], name);
+ const audio_format_t prevDownmixerFormat = track.mDownmixRequiresFormat;
+ const status_t status = mState.tracks[name].prepareForDownmix();
ALOGE_IF(status != OK,
- "initTrackDownmix error %d, track channel mask %#x, mixer channel mask %#x",
+ "prepareForDownmix error %d, track channel mask %#x, mixer channel mask %#x",
status, track.channelMask, track.mMixerChannelMask);
- const bool mixerInFormatChanged = prevMixerInFormat != track.mMixerInFormat;
- if (mixerInFormatChanged) {
- prepareTrackForReformat(&track, name); // because of downmixer, track format may change!
+ if (prevDownmixerFormat != track.mDownmixRequiresFormat) {
+ track.prepareForReformat(); // because of downmixer, track format may change!
}
- if (track.resampler && (mixerInFormatChanged || mixerChannelCountChanged)) {
- // resampler input format or channels may have changed.
+ if (track.resampler && mixerChannelCountChanged) {
+ // resampler channels may have changed.
const uint32_t resetToSampleRate = track.sampleRate;
delete track.resampler;
track.resampler = NULL;
@@ -576,99 +611,125 @@
return true;
}
-status_t AudioMixer::initTrackDownmix(track_t* pTrack, int trackName)
-{
- // Only remix (upmix or downmix) if the track and mixer/device channel masks
- // are not the same and not handled internally, as mono -> stereo currently is.
- if (pTrack->channelMask != pTrack->mMixerChannelMask
- && !(pTrack->channelMask == AUDIO_CHANNEL_OUT_MONO
- && pTrack->mMixerChannelMask == AUDIO_CHANNEL_OUT_STEREO)) {
- return prepareTrackForDownmix(pTrack, trackName);
- }
- // no remix necessary
- unprepareTrackForDownmix(pTrack, trackName);
- return NO_ERROR;
-}
+void AudioMixer::track_t::unprepareForDownmix() {
+ ALOGV("AudioMixer::unprepareForDownmix(%p)", this);
-void AudioMixer::unprepareTrackForDownmix(track_t* pTrack, int trackName __unused) {
- ALOGV("AudioMixer::unprepareTrackForDownmix(%d)", trackName);
-
- if (pTrack->downmixerBufferProvider != NULL) {
+ mDownmixRequiresFormat = AUDIO_FORMAT_INVALID;
+ if (downmixerBufferProvider != NULL) {
// this track had previously been configured with a downmixer, delete it
ALOGV(" deleting old downmixer");
- delete pTrack->downmixerBufferProvider;
- pTrack->downmixerBufferProvider = NULL;
- reconfigureBufferProviders(pTrack);
+ delete downmixerBufferProvider;
+ downmixerBufferProvider = NULL;
+ reconfigureBufferProviders();
} else {
ALOGV(" nothing to do, no downmixer to delete");
}
}
-status_t AudioMixer::prepareTrackForDownmix(track_t* pTrack, int trackName)
+status_t AudioMixer::track_t::prepareForDownmix()
{
- ALOGV("AudioMixer::prepareTrackForDownmix(%d) with mask 0x%x", trackName, pTrack->channelMask);
+ ALOGV("AudioMixer::prepareForDownmix(%p) with mask 0x%x",
+ this, channelMask);
// discard the previous downmixer if there was one
- unprepareTrackForDownmix(pTrack, trackName);
- if (DownmixerBufferProvider::isMultichannelCapable()) {
- DownmixerBufferProvider* pDbp = new DownmixerBufferProvider(pTrack->channelMask,
- pTrack->mMixerChannelMask,
- AUDIO_FORMAT_PCM_16_BIT /* TODO: use pTrack->mMixerInFormat, now only PCM 16 */,
- pTrack->sampleRate, pTrack->sessionId, kCopyBufferFrameCount);
+ unprepareForDownmix();
+ // Only remix (upmix or downmix) if the track and mixer/device channel masks
+ // are not the same and not handled internally, as mono -> stereo currently is.
+ if (channelMask == mMixerChannelMask
+ || (channelMask == AUDIO_CHANNEL_OUT_MONO
+ && mMixerChannelMask == AUDIO_CHANNEL_OUT_STEREO)) {
+ return NO_ERROR;
+ }
+ // DownmixerBufferProvider is only used for position masks.
+ if (audio_channel_mask_get_representation(channelMask)
+ == AUDIO_CHANNEL_REPRESENTATION_POSITION
+ && DownmixerBufferProvider::isMultichannelCapable()) {
+ DownmixerBufferProvider* pDbp = new DownmixerBufferProvider(channelMask,
+ mMixerChannelMask,
+ AUDIO_FORMAT_PCM_16_BIT /* TODO: use mMixerInFormat, now only PCM 16 */,
+ sampleRate, sessionId, kCopyBufferFrameCount);
if (pDbp->isValid()) { // if constructor completed properly
- pTrack->mMixerInFormat = AUDIO_FORMAT_PCM_16_BIT; // PCM 16 bit required for downmix
- pTrack->downmixerBufferProvider = pDbp;
- reconfigureBufferProviders(pTrack);
+ mDownmixRequiresFormat = AUDIO_FORMAT_PCM_16_BIT; // PCM 16 bit required for downmix
+ downmixerBufferProvider = pDbp;
+ reconfigureBufferProviders();
return NO_ERROR;
}
delete pDbp;
}
// Effect downmixer does not accept the channel conversion. Let's use our remixer.
- RemixBufferProvider* pRbp = new RemixBufferProvider(pTrack->channelMask,
- pTrack->mMixerChannelMask, pTrack->mMixerInFormat, kCopyBufferFrameCount);
+ RemixBufferProvider* pRbp = new RemixBufferProvider(channelMask,
+ mMixerChannelMask, mMixerInFormat, kCopyBufferFrameCount);
// Remix always finds a conversion whereas Downmixer effect above may fail.
- pTrack->downmixerBufferProvider = pRbp;
- reconfigureBufferProviders(pTrack);
+ downmixerBufferProvider = pRbp;
+ reconfigureBufferProviders();
return NO_ERROR;
}
-void AudioMixer::unprepareTrackForReformat(track_t* pTrack, int trackName __unused) {
- ALOGV("AudioMixer::unprepareTrackForReformat(%d)", trackName);
- if (pTrack->mReformatBufferProvider != NULL) {
- delete pTrack->mReformatBufferProvider;
- pTrack->mReformatBufferProvider = NULL;
- reconfigureBufferProviders(pTrack);
+void AudioMixer::track_t::unprepareForReformat() {
+ ALOGV("AudioMixer::unprepareForReformat(%p)", this);
+ bool requiresReconfigure = false;
+ if (mReformatBufferProvider != NULL) {
+ delete mReformatBufferProvider;
+ mReformatBufferProvider = NULL;
+ requiresReconfigure = true;
+ }
+ if (mPostDownmixReformatBufferProvider != NULL) {
+ delete mPostDownmixReformatBufferProvider;
+ mPostDownmixReformatBufferProvider = NULL;
+ requiresReconfigure = true;
+ }
+ if (requiresReconfigure) {
+ reconfigureBufferProviders();
}
}
-status_t AudioMixer::prepareTrackForReformat(track_t* pTrack, int trackName)
+status_t AudioMixer::track_t::prepareForReformat()
{
- ALOGV("AudioMixer::prepareTrackForReformat(%d) with format %#x", trackName, pTrack->mFormat);
- // discard the previous reformatter if there was one
- unprepareTrackForReformat(pTrack, trackName);
- // only configure reformatter if needed
- if (pTrack->mFormat != pTrack->mMixerInFormat) {
- pTrack->mReformatBufferProvider = new ReformatBufferProvider(
- audio_channel_count_from_out_mask(pTrack->channelMask),
- pTrack->mFormat, pTrack->mMixerInFormat,
+ ALOGV("AudioMixer::prepareForReformat(%p) with format %#x", this, mFormat);
+ // discard previous reformatters
+ unprepareForReformat();
+ // only configure reformatters as needed
+ const audio_format_t targetFormat = mDownmixRequiresFormat != AUDIO_FORMAT_INVALID
+ ? mDownmixRequiresFormat : mMixerInFormat;
+ bool requiresReconfigure = false;
+ if (mFormat != targetFormat) {
+ mReformatBufferProvider = new ReformatBufferProvider(
+ audio_channel_count_from_out_mask(channelMask),
+ mFormat,
+ targetFormat,
kCopyBufferFrameCount);
- reconfigureBufferProviders(pTrack);
+ requiresReconfigure = true;
+ }
+ if (targetFormat != mMixerInFormat) {
+ mPostDownmixReformatBufferProvider = new ReformatBufferProvider(
+ audio_channel_count_from_out_mask(mMixerChannelMask),
+ targetFormat,
+ mMixerInFormat,
+ kCopyBufferFrameCount);
+ requiresReconfigure = true;
+ }
+ if (requiresReconfigure) {
+ reconfigureBufferProviders();
}
return NO_ERROR;
}
-void AudioMixer::reconfigureBufferProviders(track_t* pTrack)
+void AudioMixer::track_t::reconfigureBufferProviders()
{
- pTrack->bufferProvider = pTrack->mInputBufferProvider;
- if (pTrack->mReformatBufferProvider) {
- pTrack->mReformatBufferProvider->setBufferProvider(pTrack->bufferProvider);
- pTrack->bufferProvider = pTrack->mReformatBufferProvider;
+ bufferProvider = mInputBufferProvider;
+ if (mReformatBufferProvider) {
+ mReformatBufferProvider->setBufferProvider(bufferProvider);
+ bufferProvider = mReformatBufferProvider;
}
- if (pTrack->downmixerBufferProvider) {
- pTrack->downmixerBufferProvider->setBufferProvider(pTrack->bufferProvider);
- pTrack->bufferProvider = pTrack->downmixerBufferProvider;
+ if (downmixerBufferProvider) {
+ downmixerBufferProvider->setBufferProvider(bufferProvider);
+ bufferProvider = downmixerBufferProvider;
+ }
+ if (mPostDownmixReformatBufferProvider) {
+ mPostDownmixReformatBufferProvider->setBufferProvider(bufferProvider);
+ bufferProvider = mPostDownmixReformatBufferProvider;
}
}
@@ -687,9 +748,9 @@
delete track.resampler;
track.resampler = NULL;
// delete the downmixer
- unprepareTrackForDownmix(&mState.tracks[name], name);
+ mState.tracks[name].unprepareForDownmix();
// delete the reformatter
- unprepareTrackForReformat(&mState.tracks[name], name);
+ mState.tracks[name].unprepareForReformat();
mTrackNames &= ~(1<<name);
}
@@ -828,7 +889,7 @@
ALOG_ASSERT(audio_is_linear_pcm(format), "Invalid format %#x", format);
track.mFormat = format;
ALOGV("setParameter(TRACK, FORMAT, %#x)", format);
- prepareTrackForReformat(&track, name);
+ track.prepareForReformat();
invalidateState(1 << name);
}
} break;
@@ -1032,10 +1093,13 @@
if (mState.tracks[name].mReformatBufferProvider != NULL) {
mState.tracks[name].mReformatBufferProvider->reset();
} else if (mState.tracks[name].downmixerBufferProvider != NULL) {
+ mState.tracks[name].downmixerBufferProvider->reset();
+ } else if (mState.tracks[name].mPostDownmixReformatBufferProvider != NULL) {
+ mState.tracks[name].mPostDownmixReformatBufferProvider->reset();
}
mState.tracks[name].mInputBufferProvider = bufferProvider;
- reconfigureBufferProviders(&mState.tracks[name]);
+ mState.tracks[name].reconfigureBufferProviders();
}
@@ -2236,4 +2300,4 @@
}
// ----------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 3b972bb..381036b 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -21,15 +21,15 @@
#include <stdint.h>
#include <sys/types.h>
+#include <hardware/audio_effect.h>
+#include <media/AudioBufferProvider.h>
+#include <media/nbaio/NBLog.h>
+#include <system/audio.h>
+#include <utils/Compat.h>
#include <utils/threads.h>
-#include <media/AudioBufferProvider.h>
#include "AudioResampler.h"
-#include <hardware/audio_effect.h>
-#include <system/audio.h>
-#include <media/nbaio/NBLog.h>
-
// FIXME This is actually unity gain, which might not be max in future, expressed in U.12
#define MAX_GAIN_INT AudioMixer::UNITY_GAIN_INT
@@ -58,7 +58,7 @@
static const uint32_t MAX_NUM_CHANNELS_TO_DOWNMIX = AUDIO_CHANNEL_COUNT_MAX;
static const uint16_t UNITY_GAIN_INT = 0x1000;
- static const float UNITY_GAIN_FLOAT = 1.0f;
+ static const CONSTEXPR float UNITY_GAIN_FLOAT = 1.0f;
enum { // names
@@ -127,10 +127,16 @@
size_t getUnreleasedFrames(int name) const;
static inline bool isValidPcmTrackFormat(audio_format_t format) {
- return format == AUDIO_FORMAT_PCM_16_BIT ||
- format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
- format == AUDIO_FORMAT_PCM_32_BIT ||
- format == AUDIO_FORMAT_PCM_FLOAT;
+ switch (format) {
+ case AUDIO_FORMAT_PCM_8_BIT:
+ case AUDIO_FORMAT_PCM_16_BIT:
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ case AUDIO_FORMAT_PCM_32_BIT:
+ case AUDIO_FORMAT_PCM_FLOAT:
+ return true;
+ default:
+ return false;
+ }
}
private:
@@ -205,17 +211,34 @@
int32_t* auxBuffer;
// 16-byte boundary
+
+ /* Buffer providers are constructed to translate the track input data as needed.
+ *
+ * 1) mInputBufferProvider: The AudioTrack buffer provider.
+ * 2) mReformatBufferProvider: If not NULL, performs the audio reformat to
+ * match either mMixerInFormat or mDownmixRequiresFormat, if the downmixer
+ * requires reformat. For example, it may convert floating point input to
+ * PCM_16_bit if that's required by the downmixer.
+ * 3) downmixerBufferProvider: If not NULL, performs the channel remixing to match
+ * the number of channels required by the mixer sink.
+ * 4) mPostDownmixReformatBufferProvider: If not NULL, performs reformatting from
+ * the downmixer requirements to the mixer engine input requirements.
+ */
AudioBufferProvider* mInputBufferProvider; // externally provided buffer provider.
CopyBufferProvider* mReformatBufferProvider; // provider wrapper for reformatting.
CopyBufferProvider* downmixerBufferProvider; // wrapper for channel conversion.
-
- int32_t sessionId;
+ CopyBufferProvider* mPostDownmixReformatBufferProvider;
// 16-byte boundary
+ int32_t sessionId;
+
audio_format_t mMixerFormat; // output mix format: AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
audio_format_t mFormat; // input track format
audio_format_t mMixerInFormat; // mix internal format AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
// each track must be converted to this format.
+ audio_format_t mDownmixRequiresFormat; // required downmixer format
+ // AUDIO_FORMAT_PCM_16_BIT if 16 bit necessary
+ // AUDIO_FORMAT_INVALID if no required format
float mVolume[MAX_NUM_VOLUMES]; // floating point set volume
float mPrevVolume[MAX_NUM_VOLUMES]; // floating point previous volume
@@ -225,7 +248,6 @@
float mPrevAuxLevel; // floating point prev aux level
float mAuxInc; // floating point aux increment
- // 16-byte boundary
audio_channel_mask_t mMixerChannelMask;
uint32_t mMixerChannelCount;
@@ -236,6 +258,12 @@
void adjustVolumeRamp(bool aux, bool useFloat = false);
size_t getUnreleasedFrames() const { return resampler != NULL ?
resampler->getUnreleasedFrames() : 0; };
+
+ status_t prepareForDownmix();
+ void unprepareForDownmix();
+ status_t prepareForReformat();
+ void unprepareForReformat();
+ void reconfigureBufferProviders();
};
typedef void (*process_hook_t)(state_t* state, int64_t pts);
@@ -382,14 +410,6 @@
bool setChannelMasks(int name,
audio_channel_mask_t trackChannelMask, audio_channel_mask_t mixerChannelMask);
- // TODO: remove unused trackName/trackNum from functions below.
- static status_t initTrackDownmix(track_t* pTrack, int trackName);
- static status_t prepareTrackForDownmix(track_t* pTrack, int trackNum);
- static void unprepareTrackForDownmix(track_t* pTrack, int trackName);
- static status_t prepareTrackForReformat(track_t* pTrack, int trackNum);
- static void unprepareTrackForReformat(track_t* pTrack, int trackName);
- static void reconfigureBufferProviders(track_t* pTrack);
-
static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp,
int32_t* aux);
static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
@@ -465,6 +485,6 @@
};
// ----------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
#endif // ANDROID_AUDIO_MIXER_H
diff --git a/services/audioflinger/AudioMixerOps.h b/services/audioflinger/AudioMixerOps.h
index f7376a8..2678857 100644
--- a/services/audioflinger/AudioMixerOps.h
+++ b/services/audioflinger/AudioMixerOps.h
@@ -52,15 +52,12 @@
*
* For high precision audio, only the <TO, TI, TV> = <float, float, float>
* needs to be accelerated. This is perhaps the easiest form to do quickly as well.
+ *
+ * A generic version is NOT defined to catch any mistake of using it.
*/
template <typename TO, typename TI, typename TV>
-inline TO MixMul(TI value, TV volume) {
- COMPILE_TIME_ASSERT_FUNCTION_SCOPE(false);
- // should not be here :-).
- // To avoid mistakes, this template is always specialized.
- return value * volume;
-}
+TO MixMul(TI value, TV volume);
template <>
inline int32_t MixMul<int32_t, int16_t, int16_t>(int16_t value, int16_t volume) {
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index 1f7a613..46e3d6c 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -29,14 +29,11 @@
#include "AudioResamplerDyn.h"
#ifdef __arm__
-#include <machine/cpu-features.h>
+ #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
#endif
namespace android {
-#ifdef __ARM_HAVE_HALFWORD_MULTIPLY // optimized asm option
- #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
-#endif // __ARM_HAVE_HALFWORD_MULTIPLY
// ----------------------------------------------------------------------------
class AudioResamplerOrder1 : public AudioResampler {
diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h
index cdc6d92..863614a 100644
--- a/services/audioflinger/AudioResampler.h
+++ b/services/audioflinger/AudioResampler.h
@@ -19,7 +19,9 @@
#include <stdint.h>
#include <sys/types.h>
+
#include <cutils/compiler.h>
+#include <utils/Compat.h>
#include <media/AudioBufferProvider.h>
#include <system/audio.h>
@@ -47,7 +49,7 @@
DYN_HIGH_QUALITY=7,
};
- static const float UNITY_GAIN_FLOAT = 1.0f;
+ static const CONSTEXPR float UNITY_GAIN_FLOAT = 1.0f;
static AudioResampler* create(audio_format_t format, int inChannelCount,
int32_t sampleRate, src_quality quality=DEFAULT_QUALITY);
@@ -168,7 +170,6 @@
};
// ----------------------------------------------------------------------------
-}
-; // namespace android
+} // namespace android
#endif // ANDROID_AUDIO_RESAMPLER_H
diff --git a/services/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp
index 8f14ff9..d3cbd1c 100644
--- a/services/audioflinger/AudioResamplerCubic.cpp
+++ b/services/audioflinger/AudioResamplerCubic.cpp
@@ -185,5 +185,4 @@
}
// ----------------------------------------------------------------------------
-}
-; // namespace android
+} // namespace android
diff --git a/services/audioflinger/AudioResamplerCubic.h b/services/audioflinger/AudioResamplerCubic.h
index b315da5..1ddc5f9 100644
--- a/services/audioflinger/AudioResamplerCubic.h
+++ b/services/audioflinger/AudioResamplerCubic.h
@@ -63,6 +63,6 @@
};
// ----------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
#endif /*ANDROID_AUDIO_RESAMPLER_CUBIC_H*/
diff --git a/services/audioflinger/AudioResamplerDyn.cpp b/services/audioflinger/AudioResamplerDyn.cpp
index 0eeb201..c21d4ca 100644
--- a/services/audioflinger/AudioResamplerDyn.cpp
+++ b/services/audioflinger/AudioResamplerDyn.cpp
@@ -618,4 +618,4 @@
template class AudioResamplerDyn<int32_t, int16_t, int32_t>;
// ----------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
diff --git a/services/audioflinger/AudioResamplerDyn.h b/services/audioflinger/AudioResamplerDyn.h
index e886a68..238b163 100644
--- a/services/audioflinger/AudioResamplerDyn.h
+++ b/services/audioflinger/AudioResamplerDyn.h
@@ -127,6 +127,6 @@
void* mCoefBuffer; // if a filter is created, this is not null
};
-}; // namespace android
+} // namespace android
#endif /*ANDROID_AUDIO_RESAMPLER_DYN_H*/
diff --git a/services/audioflinger/AudioResamplerFirGen.h b/services/audioflinger/AudioResamplerFirGen.h
index d024b2f..ad18965 100644
--- a/services/audioflinger/AudioResamplerFirGen.h
+++ b/services/audioflinger/AudioResamplerFirGen.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_AUDIO_RESAMPLER_FIR_GEN_H
#define ANDROID_AUDIO_RESAMPLER_FIR_GEN_H
+#include "utils/Compat.h"
+
namespace android {
/*
@@ -187,22 +189,23 @@
template <int N>
struct I0Term {
- static const double value = I0Term<N-1>::value / (4. * N * N);
+ static const CONSTEXPR double value = I0Term<N-1>::value / (4. * N * N);
};
template <>
struct I0Term<0> {
- static const double value = 1.;
+ static const CONSTEXPR double value = 1.;
};
template <int N>
struct I0ATerm {
- static const double value = I0ATerm<N-1>::value * (2.*N-1.) * (2.*N-1.) / (8. * N);
+ static const CONSTEXPR double value = I0ATerm<N-1>::value * (2.*N-1.) * (2.*N-1.) / (8. * N);
};
template <>
struct I0ATerm<0> { // 1/sqrt(2*PI);
- static const double value = 0.398942280401432677939946059934381868475858631164934657665925;
+ static const CONSTEXPR double value =
+ 0.398942280401432677939946059934381868475858631164934657665925;
};
#if USE_HORNERS_METHOD
@@ -704,6 +707,6 @@
}
}
-}; // namespace android
+} // namespace android
#endif /*ANDROID_AUDIO_RESAMPLER_FIR_GEN_H*/
diff --git a/services/audioflinger/AudioResamplerFirOps.h b/services/audioflinger/AudioResamplerFirOps.h
index bf2163f..658285d 100644
--- a/services/audioflinger/AudioResamplerFirOps.h
+++ b/services/audioflinger/AudioResamplerFirOps.h
@@ -25,7 +25,7 @@
#define USE_INLINE_ASSEMBLY (false)
#endif
-#if USE_INLINE_ASSEMBLY && defined(__ARM_NEON__)
+#if defined(__aarch64__) || defined(__ARM_NEON__)
#define USE_NEON (true)
#include <arm_neon.h>
#else
@@ -158,6 +158,6 @@
#endif
}
-}; // namespace android
+} // namespace android
#endif /*ANDROID_AUDIO_RESAMPLER_FIR_OPS_H*/
diff --git a/services/audioflinger/AudioResamplerFirProcess.h b/services/audioflinger/AudioResamplerFirProcess.h
index efc8055..176202e 100644
--- a/services/audioflinger/AudioResamplerFirProcess.h
+++ b/services/audioflinger/AudioResamplerFirProcess.h
@@ -174,7 +174,8 @@
* Process() calls ProcessBase() with TFUNC = InterpCompute, for interpolated phase.
*/
-template <int CHANNELS, int STRIDE, typename TFUNC, typename TC, typename TI, typename TO, typename TINTERP>
+template <int CHANNELS, int STRIDE, typename TFUNC, typename TC, typename TI, typename TO,
+ typename TINTERP>
static inline
void ProcessBase(TO* const out,
size_t count,
@@ -242,6 +243,9 @@
}
}
+/* Calculates a single output frame from a polyphase resampling filter.
+ * See Process() for parameter details.
+ */
template <int CHANNELS, int STRIDE, typename TC, typename TI, typename TO>
static inline
void ProcessL(TO* const out,
@@ -255,6 +259,39 @@
ProcessBase<CHANNELS, STRIDE, InterpNull>(out, count, coefsP, coefsN, sP, sN, 0, volumeLR);
}
+/*
+ * Calculates a single output frame from a polyphase resampling filter,
+ * with filter phase interpolation.
+ *
+ * @param out should point to the output buffer with space for at least one output frame.
+ *
+ * @param count should be half the size of the total filter length (halfNumCoefs), as we
+ * use symmetry in filter coefficients to evaluate two dot products.
+ *
+ * @param coefsP is one phase of the polyphase filter bank of size halfNumCoefs, corresponding
+ * to the positive sP.
+ *
+ * @param coefsN is one phase of the polyphase filter bank of size halfNumCoefs, corresponding
+ * to the negative sN.
+ *
+ * @param coefsP1 is the next phase of coefsP (used for interpolation).
+ *
+ * @param coefsN1 is the next phase of coefsN (used for interpolation).
+ *
+ * @param sP is the positive half of the coefficients (as viewed by a convolution),
+ * starting at the original samples pointer and decrementing (by CHANNELS).
+ *
+ * @param sN is the negative half of the samples (as viewed by a convolution),
+ * starting at the original samples pointer + CHANNELS and incrementing (by CHANNELS).
+ *
+ * @param lerpP The fractional siting between the polyphase indices is given by the bits
+ * below coefShift. See fir() for details.
+ *
+ * @param volumeLR is a pointer to an array of two 32 bit volume values, one per stereo channel,
+ * expressed as a S32 integer or float. A negative value inverts the channel 180 degrees.
+ * The pointer volumeLR should be aligned to a minimum of 8 bytes.
+ * A typical value for volume is 0x1000 to align to a unity gain output of 20.12.
+ */
template <int CHANNELS, int STRIDE, typename TC, typename TI, typename TO, typename TINTERP>
static inline
void Process(TO* const out,
@@ -268,11 +305,12 @@
TINTERP lerpP,
const TO* const volumeLR)
{
- ProcessBase<CHANNELS, STRIDE, InterpCompute>(out, count, coefsP, coefsN, sP, sN, lerpP, volumeLR);
+ ProcessBase<CHANNELS, STRIDE, InterpCompute>(out, count, coefsP, coefsN, sP, sN, lerpP,
+ volumeLR);
}
/*
- * Calculates a single output frame (two samples) from input sample pointer.
+ * Calculates a single output frame from input sample pointer.
*
* This sets up the params for the accelerated Process() and ProcessL()
* functions to do the appropriate dot products.
@@ -307,7 +345,7 @@
* the positive half of the filter is dot product from samples to samples-halfNumCoefs+1.
*
* @param volumeLR is a pointer to an array of two 32 bit volume values, one per stereo channel,
- * expressed as a S32 integer. A negative value inverts the channel 180 degrees.
+ * expressed as a S32 integer or float. A negative value inverts the channel 180 degrees.
* The pointer volumeLR should be aligned to a minimum of 8 bytes.
* A typical value for volume is 0x1000 to align to a unity gain output of 20.12.
*
@@ -396,6 +434,6 @@
}
}
-}; // namespace android
+} // namespace android
#endif /*ANDROID_AUDIO_RESAMPLER_FIR_PROCESS_H*/
diff --git a/services/audioflinger/AudioResamplerFirProcessNeon.h b/services/audioflinger/AudioResamplerFirProcessNeon.h
index f311cef..3de9edd 100644
--- a/services/audioflinger/AudioResamplerFirProcessNeon.h
+++ b/services/audioflinger/AudioResamplerFirProcessNeon.h
@@ -22,14 +22,35 @@
// depends on AudioResamplerFirOps.h, AudioResamplerFirProcess.h
#if USE_NEON
+
+// use intrinsics if inline arm32 assembly is not possible
+#if !USE_INLINE_ASSEMBLY
+#define USE_INTRINSIC
+#endif
+
+// following intrinsics available only on ARM 64 bit ACLE
+#ifndef __aarch64__
+#undef vld1q_f32_x2
+#undef vld1q_s32_x2
+#endif
+
+#define TO_STRING2(x) #x
+#define TO_STRING(x) TO_STRING2(x)
+// uncomment to print GCC version, may be relevant for intrinsic optimizations
+/* #pragma message ("GCC version: " TO_STRING(__GNUC__) \
+ "." TO_STRING(__GNUC_MINOR__) \
+ "." TO_STRING(__GNUC_PATCHLEVEL__)) */
+
//
-// NEON specializations are enabled for Process() and ProcessL()
+// NEON specializations are enabled for Process() and ProcessL() in AudioResamplerFirProcess.h
//
-// TODO: Stride 16 and Stride 8 can be combined with one pass stride 8 (if necessary)
-// and looping stride 16 (or vice versa). This has some polyphase coef data alignment
-// issues with S16 coefs. Consider this later.
+// Two variants are presented here:
+// ARM NEON inline assembly which appears up to 10-15% faster than intrinsics (gcc 4.9) for arm32.
+// ARM NEON intrinsics which can also be used by arm64 and x86/64 with NEON header.
+//
// Macros to save a mono/stereo accumulator sample in q0 (and q4) as stereo out.
+// These are only used for inline assembly.
#define ASSEMBLY_ACCUMULATE_MONO \
"vld1.s32 {d2}, [%[vLR]:64] \n"/* (1) load volumes */\
"vld1.s32 {d3}, %[out] \n"/* (2) unaligned load the output */\
@@ -49,6 +70,458 @@
"vqadd.s32 d3, d3, d0 \n"/* (1+4d) accumulate result (saturating)*/\
"vst1.s32 {d3}, %[out] \n"/* (2+2d)store result*/
+template <int CHANNELS, int STRIDE, bool FIXED>
+static inline void ProcessNeonIntrinsic(int32_t* out,
+ int count,
+ const int16_t* coefsP,
+ const int16_t* coefsN,
+ const int16_t* sP,
+ const int16_t* sN,
+ const int32_t* volumeLR,
+ uint32_t lerpP,
+ const int16_t* coefsP1,
+ const int16_t* coefsN1)
+{
+ ALOG_ASSERT(count > 0 && (count & 7) == 0); // multiple of 8
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CHANNELS == 1 || CHANNELS == 2);
+
+ sP -= CHANNELS*((STRIDE>>1)-1);
+ coefsP = (const int16_t*)__builtin_assume_aligned(coefsP, 16);
+ coefsN = (const int16_t*)__builtin_assume_aligned(coefsN, 16);
+
+ int16x4_t interp;
+ if (!FIXED) {
+ interp = vdup_n_s16(lerpP);
+ //interp = (int16x4_t)vset_lane_s32 ((int32x2_t)lerpP, interp, 0);
+ coefsP1 = (const int16_t*)__builtin_assume_aligned(coefsP1, 16);
+ coefsN1 = (const int16_t*)__builtin_assume_aligned(coefsN1, 16);
+ }
+ int32x4_t accum, accum2;
+ // warning uninitialized if we use veorq_s32
+ // (alternative to below) accum = veorq_s32(accum, accum);
+ accum = vdupq_n_s32(0);
+ if (CHANNELS == 2) {
+ // (alternative to below) accum2 = veorq_s32(accum2, accum2);
+ accum2 = vdupq_n_s32(0);
+ }
+ do {
+ int16x8_t posCoef = vld1q_s16(coefsP);
+ coefsP += 8;
+ int16x8_t negCoef = vld1q_s16(coefsN);
+ coefsN += 8;
+ if (!FIXED) { // interpolate
+ int16x8_t posCoef1 = vld1q_s16(coefsP1);
+ coefsP1 += 8;
+ int16x8_t negCoef1 = vld1q_s16(coefsN1);
+ coefsN1 += 8;
+
+ posCoef1 = vsubq_s16(posCoef1, posCoef);
+ negCoef = vsubq_s16(negCoef, negCoef1);
+
+ posCoef1 = vqrdmulhq_lane_s16(posCoef1, interp, 0);
+ negCoef = vqrdmulhq_lane_s16(negCoef, interp, 0);
+
+ posCoef = vaddq_s16(posCoef, posCoef1);
+ negCoef = vaddq_s16(negCoef, negCoef1);
+ }
+ switch (CHANNELS) {
+ case 1: {
+ int16x8_t posSamp = vld1q_s16(sP);
+ int16x8_t negSamp = vld1q_s16(sN);
+ sN += 8;
+ posSamp = vrev64q_s16(posSamp);
+
+ // dot product
+ accum = vmlal_s16(accum, vget_low_s16(posSamp), vget_high_s16(posCoef)); // reversed
+ accum = vmlal_s16(accum, vget_high_s16(posSamp), vget_low_s16(posCoef)); // reversed
+ accum = vmlal_s16(accum, vget_low_s16(negSamp), vget_low_s16(negCoef));
+ accum = vmlal_s16(accum, vget_high_s16(negSamp), vget_high_s16(negCoef));
+ sP -= 8;
+ } break;
+ case 2: {
+ int16x8x2_t posSamp = vld2q_s16(sP);
+ int16x8x2_t negSamp = vld2q_s16(sN);
+ sN += 16;
+ posSamp.val[0] = vrev64q_s16(posSamp.val[0]);
+ posSamp.val[1] = vrev64q_s16(posSamp.val[1]);
+
+ // dot product
+ accum = vmlal_s16(accum, vget_low_s16(posSamp.val[0]), vget_high_s16(posCoef)); // r
+ accum = vmlal_s16(accum, vget_high_s16(posSamp.val[0]), vget_low_s16(posCoef)); // r
+ accum2 = vmlal_s16(accum2, vget_low_s16(posSamp.val[1]), vget_high_s16(posCoef)); // r
+ accum2 = vmlal_s16(accum2, vget_high_s16(posSamp.val[1]), vget_low_s16(posCoef)); // r
+ accum = vmlal_s16(accum, vget_low_s16(negSamp.val[0]), vget_low_s16(negCoef));
+ accum = vmlal_s16(accum, vget_high_s16(negSamp.val[0]), vget_high_s16(negCoef));
+ accum2 = vmlal_s16(accum2, vget_low_s16(negSamp.val[1]), vget_low_s16(negCoef));
+ accum2 = vmlal_s16(accum2, vget_high_s16(negSamp.val[1]), vget_high_s16(negCoef));
+ sP -= 16;
+ }
+ } break;
+ } while (count -= 8);
+
+ // multiply by volume and save
+ volumeLR = (const int32_t*)__builtin_assume_aligned(volumeLR, 8);
+ int32x2_t vLR = vld1_s32(volumeLR);
+ int32x2_t outSamp = vld1_s32(out);
+ // combine and funnel down accumulator
+ int32x2_t outAccum = vpadd_s32(vget_low_s32(accum), vget_high_s32(accum));
+ if (CHANNELS == 1) {
+ // duplicate accum to both L and R
+ outAccum = vpadd_s32(outAccum, outAccum);
+ } else if (CHANNELS == 2) {
+ // accum2 contains R, fold in
+ int32x2_t outAccum2 = vpadd_s32(vget_low_s32(accum2), vget_high_s32(accum2));
+ outAccum = vpadd_s32(outAccum, outAccum2);
+ }
+ outAccum = vqrdmulh_s32(outAccum, vLR);
+ outSamp = vqadd_s32(outSamp, outAccum);
+ vst1_s32(out, outSamp);
+}
+
+template <int CHANNELS, int STRIDE, bool FIXED>
+static inline void ProcessNeonIntrinsic(int32_t* out,
+ int count,
+ const int32_t* coefsP,
+ const int32_t* coefsN,
+ const int16_t* sP,
+ const int16_t* sN,
+ const int32_t* volumeLR,
+ uint32_t lerpP,
+ const int32_t* coefsP1,
+ const int32_t* coefsN1)
+{
+ ALOG_ASSERT(count > 0 && (count & 7) == 0); // multiple of 8
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CHANNELS == 1 || CHANNELS == 2);
+
+ sP -= CHANNELS*((STRIDE>>1)-1);
+ coefsP = (const int32_t*)__builtin_assume_aligned(coefsP, 16);
+ coefsN = (const int32_t*)__builtin_assume_aligned(coefsN, 16);
+
+ int32x2_t interp;
+ if (!FIXED) {
+ interp = vdup_n_s32(lerpP);
+ coefsP1 = (const int32_t*)__builtin_assume_aligned(coefsP1, 16);
+ coefsN1 = (const int32_t*)__builtin_assume_aligned(coefsN1, 16);
+ }
+ int32x4_t accum, accum2;
+ // warning uninitialized if we use veorq_s32
+ // (alternative to below) accum = veorq_s32(accum, accum);
+ accum = vdupq_n_s32(0);
+ if (CHANNELS == 2) {
+ // (alternative to below) accum2 = veorq_s32(accum2, accum2);
+ accum2 = vdupq_n_s32(0);
+ }
+ do {
+#ifdef vld1q_s32_x2
+ int32x4x2_t posCoef = vld1q_s32_x2(coefsP);
+ coefsP += 8;
+ int32x4x2_t negCoef = vld1q_s32_x2(coefsN);
+ coefsN += 8;
+#else
+ int32x4x2_t posCoef;
+ posCoef.val[0] = vld1q_s32(coefsP);
+ coefsP += 4;
+ posCoef.val[1] = vld1q_s32(coefsP);
+ coefsP += 4;
+ int32x4x2_t negCoef;
+ negCoef.val[0] = vld1q_s32(coefsN);
+ coefsN += 4;
+ negCoef.val[1] = vld1q_s32(coefsN);
+ coefsN += 4;
+#endif
+ if (!FIXED) { // interpolate
+#ifdef vld1q_s32_x2
+ int32x4x2_t posCoef1 = vld1q_s32_x2(coefsP1);
+ coefsP1 += 8;
+ int32x4x2_t negCoef1 = vld1q_s32_x2(coefsN1);
+ coefsN1 += 8;
+#else
+ int32x4x2_t posCoef1;
+ posCoef1.val[0] = vld1q_s32(coefsP1);
+ coefsP1 += 4;
+ posCoef1.val[1] = vld1q_s32(coefsP1);
+ coefsP1 += 4;
+ int32x4x2_t negCoef1;
+ negCoef1.val[0] = vld1q_s32(coefsN1);
+ coefsN1 += 4;
+ negCoef1.val[1] = vld1q_s32(coefsN1);
+ coefsN1 += 4;
+#endif
+
+ posCoef1.val[0] = vsubq_s32(posCoef1.val[0], posCoef.val[0]);
+ posCoef1.val[1] = vsubq_s32(posCoef1.val[1], posCoef.val[1]);
+ negCoef.val[0] = vsubq_s32(negCoef.val[0], negCoef1.val[0]);
+ negCoef.val[1] = vsubq_s32(negCoef.val[1], negCoef1.val[1]);
+
+ posCoef1.val[0] = vqrdmulhq_lane_s32(posCoef1.val[0], interp, 0);
+ posCoef1.val[1] = vqrdmulhq_lane_s32(posCoef1.val[1], interp, 0);
+ negCoef.val[0] = vqrdmulhq_lane_s32(negCoef.val[0], interp, 0);
+ negCoef.val[1] = vqrdmulhq_lane_s32(negCoef.val[1], interp, 0);
+
+ posCoef.val[0] = vaddq_s32(posCoef.val[0], posCoef1.val[0]);
+ posCoef.val[1] = vaddq_s32(posCoef.val[1], posCoef1.val[1]);
+ negCoef.val[0] = vaddq_s32(negCoef.val[0], negCoef1.val[0]);
+ negCoef.val[1] = vaddq_s32(negCoef.val[1], negCoef1.val[1]);
+ }
+ switch (CHANNELS) {
+ case 1: {
+ int16x8_t posSamp = vld1q_s16(sP);
+ int16x8_t negSamp = vld1q_s16(sN);
+ sN += 8;
+ posSamp = vrev64q_s16(posSamp);
+
+ int32x4_t posSamp0 = vshll_n_s16(vget_low_s16(posSamp), 15);
+ int32x4_t posSamp1 = vshll_n_s16(vget_high_s16(posSamp), 15);
+ int32x4_t negSamp0 = vshll_n_s16(vget_low_s16(negSamp), 15);
+ int32x4_t negSamp1 = vshll_n_s16(vget_high_s16(negSamp), 15);
+
+ // dot product
+ posSamp0 = vqrdmulhq_s32(posSamp0, posCoef.val[1]); // reversed
+ posSamp1 = vqrdmulhq_s32(posSamp1, posCoef.val[0]); // reversed
+ negSamp0 = vqrdmulhq_s32(negSamp0, negCoef.val[0]);
+ negSamp1 = vqrdmulhq_s32(negSamp1, negCoef.val[1]);
+
+ accum = vaddq_s32(accum, posSamp0);
+ negSamp0 = vaddq_s32(negSamp0, negSamp1);
+ accum = vaddq_s32(accum, posSamp1);
+ accum = vaddq_s32(accum, negSamp0);
+
+ sP -= 8;
+ } break;
+ case 2: {
+ int16x8x2_t posSamp = vld2q_s16(sP);
+ int16x8x2_t negSamp = vld2q_s16(sN);
+ sN += 16;
+ posSamp.val[0] = vrev64q_s16(posSamp.val[0]);
+ posSamp.val[1] = vrev64q_s16(posSamp.val[1]);
+
+ // left
+ int32x4_t posSamp0 = vshll_n_s16(vget_low_s16(posSamp.val[0]), 15);
+ int32x4_t posSamp1 = vshll_n_s16(vget_high_s16(posSamp.val[0]), 15);
+ int32x4_t negSamp0 = vshll_n_s16(vget_low_s16(negSamp.val[0]), 15);
+ int32x4_t negSamp1 = vshll_n_s16(vget_high_s16(negSamp.val[0]), 15);
+
+ // dot product
+ posSamp0 = vqrdmulhq_s32(posSamp0, posCoef.val[1]); // reversed
+ posSamp1 = vqrdmulhq_s32(posSamp1, posCoef.val[0]); // reversed
+ negSamp0 = vqrdmulhq_s32(negSamp0, negCoef.val[0]);
+ negSamp1 = vqrdmulhq_s32(negSamp1, negCoef.val[1]);
+
+ accum = vaddq_s32(accum, posSamp0);
+ negSamp0 = vaddq_s32(negSamp0, negSamp1);
+ accum = vaddq_s32(accum, posSamp1);
+ accum = vaddq_s32(accum, negSamp0);
+
+ // right
+ posSamp0 = vshll_n_s16(vget_low_s16(posSamp.val[1]), 15);
+ posSamp1 = vshll_n_s16(vget_high_s16(posSamp.val[1]), 15);
+ negSamp0 = vshll_n_s16(vget_low_s16(negSamp.val[1]), 15);
+ negSamp1 = vshll_n_s16(vget_high_s16(negSamp.val[1]), 15);
+
+ // dot product
+ posSamp0 = vqrdmulhq_s32(posSamp0, posCoef.val[1]); // reversed
+ posSamp1 = vqrdmulhq_s32(posSamp1, posCoef.val[0]); // reversed
+ negSamp0 = vqrdmulhq_s32(negSamp0, negCoef.val[0]);
+ negSamp1 = vqrdmulhq_s32(negSamp1, negCoef.val[1]);
+
+ accum2 = vaddq_s32(accum2, posSamp0);
+ negSamp0 = vaddq_s32(negSamp0, negSamp1);
+ accum2 = vaddq_s32(accum2, posSamp1);
+ accum2 = vaddq_s32(accum2, negSamp0);
+
+ sP -= 16;
+ } break;
+ }
+ } while (count -= 8);
+
+ // multiply by volume and save
+ volumeLR = (const int32_t*)__builtin_assume_aligned(volumeLR, 8);
+ int32x2_t vLR = vld1_s32(volumeLR);
+ int32x2_t outSamp = vld1_s32(out);
+ // combine and funnel down accumulator
+ int32x2_t outAccum = vpadd_s32(vget_low_s32(accum), vget_high_s32(accum));
+ if (CHANNELS == 1) {
+ // duplicate accum to both L and R
+ outAccum = vpadd_s32(outAccum, outAccum);
+ } else if (CHANNELS == 2) {
+ // accum2 contains R, fold in
+ int32x2_t outAccum2 = vpadd_s32(vget_low_s32(accum2), vget_high_s32(accum2));
+ outAccum = vpadd_s32(outAccum, outAccum2);
+ }
+ outAccum = vqrdmulh_s32(outAccum, vLR);
+ outSamp = vqadd_s32(outSamp, outAccum);
+ vst1_s32(out, outSamp);
+}
+
+template <int CHANNELS, int STRIDE, bool FIXED>
+static inline void ProcessNeonIntrinsic(float* out,
+ int count,
+ const float* coefsP,
+ const float* coefsN,
+ const float* sP,
+ const float* sN,
+ const float* volumeLR,
+ float lerpP,
+ const float* coefsP1,
+ const float* coefsN1)
+{
+ ALOG_ASSERT(count > 0 && (count & 7) == 0); // multiple of 8
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CHANNELS == 1 || CHANNELS == 2);
+
+ sP -= CHANNELS*((STRIDE>>1)-1);
+ coefsP = (const float*)__builtin_assume_aligned(coefsP, 16);
+ coefsN = (const float*)__builtin_assume_aligned(coefsN, 16);
+
+ float32x2_t interp;
+ if (!FIXED) {
+ interp = vdup_n_f32(lerpP);
+ coefsP1 = (const float*)__builtin_assume_aligned(coefsP1, 16);
+ coefsN1 = (const float*)__builtin_assume_aligned(coefsN1, 16);
+ }
+ float32x4_t accum, accum2;
+ // warning uninitialized if we use veorq_s32
+ // (alternative to below) accum = veorq_s32(accum, accum);
+ accum = vdupq_n_f32(0);
+ if (CHANNELS == 2) {
+ // (alternative to below) accum2 = veorq_s32(accum2, accum2);
+ accum2 = vdupq_n_f32(0);
+ }
+ do {
+#ifdef vld1q_f32_x2
+ float32x4x2_t posCoef = vld1q_f32_x2(coefsP);
+ coefsP += 8;
+ float32x4x2_t negCoef = vld1q_f32_x2(coefsN);
+ coefsN += 8;
+#else
+ float32x4x2_t posCoef;
+ posCoef.val[0] = vld1q_f32(coefsP);
+ coefsP += 4;
+ posCoef.val[1] = vld1q_f32(coefsP);
+ coefsP += 4;
+ float32x4x2_t negCoef;
+ negCoef.val[0] = vld1q_f32(coefsN);
+ coefsN += 4;
+ negCoef.val[1] = vld1q_f32(coefsN);
+ coefsN += 4;
+#endif
+ if (!FIXED) { // interpolate
+#ifdef vld1q_f32_x2
+ float32x4x2_t posCoef1 = vld1q_f32_x2(coefsP1);
+ coefsP1 += 8;
+ float32x4x2_t negCoef1 = vld1q_f32_x2(coefsN1);
+ coefsN1 += 8;
+#else
+ float32x4x2_t posCoef1;
+ posCoef1.val[0] = vld1q_f32(coefsP1);
+ coefsP1 += 4;
+ posCoef1.val[1] = vld1q_f32(coefsP1);
+ coefsP1 += 4;
+ float32x4x2_t negCoef1;
+ negCoef1.val[0] = vld1q_f32(coefsN1);
+ coefsN1 += 4;
+ negCoef1.val[1] = vld1q_f32(coefsN1);
+ coefsN1 += 4;
+#endif
+ posCoef1.val[0] = vsubq_f32(posCoef1.val[0], posCoef.val[0]);
+ posCoef1.val[1] = vsubq_f32(posCoef1.val[1], posCoef.val[1]);
+ negCoef.val[0] = vsubq_f32(negCoef.val[0], negCoef1.val[0]);
+ negCoef.val[1] = vsubq_f32(negCoef.val[1], negCoef1.val[1]);
+
+ posCoef.val[0] = vmlaq_lane_f32(posCoef.val[0], posCoef1.val[0], interp, 0);
+ posCoef.val[1] = vmlaq_lane_f32(posCoef.val[1], posCoef1.val[1], interp, 0);
+ negCoef.val[0] = vmlaq_lane_f32(negCoef1.val[0], negCoef.val[0], interp, 0); // rev
+ negCoef.val[1] = vmlaq_lane_f32(negCoef1.val[1], negCoef.val[1], interp, 0); // rev
+ }
+ switch (CHANNELS) {
+ case 1: {
+#ifdef vld1q_f32_x2
+ float32x4x2_t posSamp = vld1q_f32_x2(sP);
+ float32x4x2_t negSamp = vld1q_f32_x2(sN);
+ sN += 8;
+ sP -= 8;
+#else
+ float32x4x2_t posSamp;
+ posSamp.val[0] = vld1q_f32(sP);
+ sP += 4;
+ posSamp.val[1] = vld1q_f32(sP);
+ sP -= 12;
+ float32x4x2_t negSamp;
+ negSamp.val[0] = vld1q_f32(sN);
+ sN += 4;
+ negSamp.val[1] = vld1q_f32(sN);
+ sN += 4;
+#endif
+ // effectively we want a vrev128q_f32()
+ posSamp.val[0] = vrev64q_f32(posSamp.val[0]);
+ posSamp.val[1] = vrev64q_f32(posSamp.val[1]);
+ posSamp.val[0] = vcombine_f32(
+ vget_high_f32(posSamp.val[0]), vget_low_f32(posSamp.val[0]));
+ posSamp.val[1] = vcombine_f32(
+ vget_high_f32(posSamp.val[1]), vget_low_f32(posSamp.val[1]));
+
+ accum = vmlaq_f32(accum, posSamp.val[0], posCoef.val[1]);
+ accum = vmlaq_f32(accum, posSamp.val[1], posCoef.val[0]);
+ accum = vmlaq_f32(accum, negSamp.val[0], negCoef.val[0]);
+ accum = vmlaq_f32(accum, negSamp.val[1], negCoef.val[1]);
+ } break;
+ case 2: {
+ float32x4x2_t posSamp0 = vld2q_f32(sP);
+ sP += 8;
+ float32x4x2_t negSamp0 = vld2q_f32(sN);
+ sN += 8;
+ posSamp0.val[0] = vrev64q_f32(posSamp0.val[0]);
+ posSamp0.val[1] = vrev64q_f32(posSamp0.val[1]);
+ posSamp0.val[0] = vcombine_f32(
+ vget_high_f32(posSamp0.val[0]), vget_low_f32(posSamp0.val[0]));
+ posSamp0.val[1] = vcombine_f32(
+ vget_high_f32(posSamp0.val[1]), vget_low_f32(posSamp0.val[1]));
+
+ float32x4x2_t posSamp1 = vld2q_f32(sP);
+ sP -= 24;
+ float32x4x2_t negSamp1 = vld2q_f32(sN);
+ sN += 8;
+ posSamp1.val[0] = vrev64q_f32(posSamp1.val[0]);
+ posSamp1.val[1] = vrev64q_f32(posSamp1.val[1]);
+ posSamp1.val[0] = vcombine_f32(
+ vget_high_f32(posSamp1.val[0]), vget_low_f32(posSamp1.val[0]));
+ posSamp1.val[1] = vcombine_f32(
+ vget_high_f32(posSamp1.val[1]), vget_low_f32(posSamp1.val[1]));
+
+ // Note: speed is affected by accumulation order.
+ // Also, speed appears slower using vmul/vadd instead of vmla for
+ // stereo case, comparable for mono.
+
+ accum = vmlaq_f32(accum, negSamp0.val[0], negCoef.val[0]);
+ accum = vmlaq_f32(accum, negSamp1.val[0], negCoef.val[1]);
+ accum2 = vmlaq_f32(accum2, negSamp0.val[1], negCoef.val[0]);
+ accum2 = vmlaq_f32(accum2, negSamp1.val[1], negCoef.val[1]);
+
+ accum = vmlaq_f32(accum, posSamp0.val[0], posCoef.val[1]); // reversed
+ accum = vmlaq_f32(accum, posSamp1.val[0], posCoef.val[0]); // reversed
+ accum2 = vmlaq_f32(accum2, posSamp0.val[1], posCoef.val[1]); // reversed
+ accum2 = vmlaq_f32(accum2, posSamp1.val[1], posCoef.val[0]); // reversed
+ } break;
+ }
+ } while (count -= 8);
+
+ // multiply by volume and save
+ volumeLR = (const float*)__builtin_assume_aligned(volumeLR, 8);
+ float32x2_t vLR = vld1_f32(volumeLR);
+ float32x2_t outSamp = vld1_f32(out);
+ // combine and funnel down accumulator
+ float32x2_t outAccum = vpadd_f32(vget_low_f32(accum), vget_high_f32(accum));
+ if (CHANNELS == 1) {
+ // duplicate accum to both L and R
+ outAccum = vpadd_f32(outAccum, outAccum);
+ } else if (CHANNELS == 2) {
+ // accum2 contains R, fold in
+ float32x2_t outAccum2 = vpadd_f32(vget_low_f32(accum2), vget_high_f32(accum2));
+ outAccum = vpadd_f32(outAccum, outAccum2);
+ }
+ outSamp = vmla_f32(outSamp, outAccum, vLR);
+ vst1_f32(out, outSamp);
+}
+
template <>
inline void ProcessL<1, 16>(int32_t* const out,
int count,
@@ -58,6 +531,10 @@
const int16_t* sN,
const int32_t* const volumeLR)
{
+#ifdef USE_INTRINSIC
+ ProcessNeonIntrinsic<1, 16, true>(out, count, coefsP, coefsN, sP, sN, volumeLR,
+ 0 /*lerpP*/, NULL /*coefsP1*/, NULL /*coefsN1*/);
+#else
const int CHANNELS = 1; // template specialization does not preserve params
const int STRIDE = 16;
sP -= CHANNELS*((STRIDE>>1)-1);
@@ -99,6 +576,7 @@
"q0", "q1", "q2", "q3",
"q8", "q10"
);
+#endif
}
template <>
@@ -110,6 +588,10 @@
const int16_t* sN,
const int32_t* const volumeLR)
{
+#ifdef USE_INTRINSIC
+ ProcessNeonIntrinsic<2, 16, true>(out, count, coefsP, coefsN, sP, sN, volumeLR,
+ 0 /*lerpP*/, NULL /*coefsP1*/, NULL /*coefsN1*/);
+#else
const int CHANNELS = 2; // template specialization does not preserve params
const int STRIDE = 16;
sP -= CHANNELS*((STRIDE>>1)-1);
@@ -119,13 +601,13 @@
"1: \n"
- "vld2.16 {q2, q3}, [%[sP]] \n"// (3+0d) load 8 16-bits stereo samples
- "vld2.16 {q5, q6}, [%[sN]]! \n"// (3) load 8 16-bits stereo samples
+ "vld2.16 {q2, q3}, [%[sP]] \n"// (3+0d) load 8 16-bits stereo frames
+ "vld2.16 {q5, q6}, [%[sN]]! \n"// (3) load 8 16-bits stereo frames
"vld1.16 {q8}, [%[coefsP0]:128]! \n"// (1) load 8 16-bits coefs
"vld1.16 {q10}, [%[coefsN0]:128]! \n"// (1) load 8 16-bits coefs
- "vrev64.16 q2, q2 \n"// (1) reverse 8 frames of the left positive
- "vrev64.16 q3, q3 \n"// (0 combines+) reverse right positive
+ "vrev64.16 q2, q2 \n"// (1) reverse 8 samples of positive left
+ "vrev64.16 q3, q3 \n"// (0 combines+) reverse positive right
"vmlal.s16 q0, d4, d17 \n"// (1) multiply (reversed) samples left
"vmlal.s16 q0, d5, d16 \n"// (1) multiply (reversed) samples left
@@ -157,6 +639,7 @@
"q4", "q5", "q6",
"q8", "q10"
);
+#endif
}
template <>
@@ -171,6 +654,11 @@
uint32_t lerpP,
const int32_t* const volumeLR)
{
+#ifdef USE_INTRINSIC
+ ProcessNeonIntrinsic<1, 16, false>(out, count, coefsP, coefsN, sP, sN, volumeLR,
+ lerpP, coefsP1, coefsN1);
+#else
+
const int CHANNELS = 1; // template specialization does not preserve params
const int STRIDE = 16;
sP -= CHANNELS*((STRIDE>>1)-1);
@@ -227,6 +715,7 @@
"q0", "q1", "q2", "q3",
"q8", "q9", "q10", "q11"
);
+#endif
}
template <>
@@ -241,6 +730,10 @@
uint32_t lerpP,
const int32_t* const volumeLR)
{
+#ifdef USE_INTRINSIC
+ ProcessNeonIntrinsic<2, 16, false>(out, count, coefsP, coefsN, sP, sN, volumeLR,
+ lerpP, coefsP1, coefsN1);
+#else
const int CHANNELS = 2; // template specialization does not preserve params
const int STRIDE = 16;
sP -= CHANNELS*((STRIDE>>1)-1);
@@ -251,8 +744,8 @@
"1: \n"
- "vld2.16 {q2, q3}, [%[sP]] \n"// (3+0d) load 8 16-bits stereo samples
- "vld2.16 {q5, q6}, [%[sN]]! \n"// (3) load 8 16-bits stereo samples
+ "vld2.16 {q2, q3}, [%[sP]] \n"// (3+0d) load 8 16-bits stereo frames
+ "vld2.16 {q5, q6}, [%[sN]]! \n"// (3) load 8 16-bits stereo frames
"vld1.16 {q8}, [%[coefsP0]:128]! \n"// (1) load 8 16-bits coefs
"vld1.16 {q9}, [%[coefsP1]:128]! \n"// (1) load 8 16-bits coefs for interpolation
"vld1.16 {q10}, [%[coefsN1]:128]! \n"// (1) load 8 16-bits coefs
@@ -264,8 +757,8 @@
"vqrdmulh.s16 q9, q9, d2[0] \n"// (2) interpolate (step2) 1st set of coefs
"vqrdmulh.s16 q11, q11, d2[0] \n"// (2) interpolate (step2) 2nd set of coefs
- "vrev64.16 q2, q2 \n"// (1) reverse 8 frames of the left positive
- "vrev64.16 q3, q3 \n"// (1) reverse 8 frames of the right positive
+ "vrev64.16 q2, q2 \n"// (1) reverse 8 samples of positive left
+ "vrev64.16 q3, q3 \n"// (1) reverse 8 samples of positive right
"vadd.s16 q8, q8, q9 \n"// (1+1d) interpolate (step3) 1st set
"vadd.s16 q10, q10, q11 \n"// (1+1d) interpolate (step3) 2nd set
@@ -303,6 +796,7 @@
"q4", "q5", "q6",
"q8", "q9", "q10", "q11"
);
+#endif
}
template <>
@@ -314,6 +808,10 @@
const int16_t* sN,
const int32_t* const volumeLR)
{
+#ifdef USE_INTRINSIC
+ ProcessNeonIntrinsic<1, 16, true>(out, count, coefsP, coefsN, sP, sN, volumeLR,
+ 0 /*lerpP*/, NULL /*coefsP1*/, NULL /*coefsN1*/);
+#else
const int CHANNELS = 1; // template specialization does not preserve params
const int STRIDE = 16;
sP -= CHANNELS*((STRIDE>>1)-1);
@@ -327,7 +825,7 @@
"vld1.32 {q8, q9}, [%[coefsP0]:128]! \n"// load 8 32-bits coefs
"vld1.32 {q10, q11}, [%[coefsN0]:128]! \n"// load 8 32-bits coefs
- "vrev64.16 q2, q2 \n"// reverse 8 frames of the positive side
+ "vrev64.16 q2, q2 \n"// reverse 8 samples of the positive side
"vshll.s16 q12, d4, #15 \n"// extend samples to 31 bits
"vshll.s16 q13, d5, #15 \n"// extend samples to 31 bits
@@ -335,10 +833,10 @@
"vshll.s16 q14, d6, #15 \n"// extend samples to 31 bits
"vshll.s16 q15, d7, #15 \n"// extend samples to 31 bits
- "vqrdmulh.s32 q12, q12, q9 \n"// multiply samples by interpolated coef
- "vqrdmulh.s32 q13, q13, q8 \n"// multiply samples by interpolated coef
- "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by interpolated coef
- "vqrdmulh.s32 q15, q15, q11 \n"// multiply samples by interpolated coef
+ "vqrdmulh.s32 q12, q12, q9 \n"// multiply samples
+ "vqrdmulh.s32 q13, q13, q8 \n"// multiply samples
+ "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples
+ "vqrdmulh.s32 q15, q15, q11 \n"// multiply samples
"vadd.s32 q0, q0, q12 \n"// accumulate result
"vadd.s32 q13, q13, q14 \n"// accumulate result
@@ -364,6 +862,7 @@
"q8", "q9", "q10", "q11",
"q12", "q13", "q14", "q15"
);
+#endif
}
template <>
@@ -375,6 +874,10 @@
const int16_t* sN,
const int32_t* const volumeLR)
{
+#ifdef USE_INTRINSIC
+ ProcessNeonIntrinsic<2, 16, true>(out, count, coefsP, coefsN, sP, sN, volumeLR,
+ 0 /*lerpP*/, NULL /*coefsP1*/, NULL /*coefsN1*/);
+#else
const int CHANNELS = 2; // template specialization does not preserve params
const int STRIDE = 16;
sP -= CHANNELS*((STRIDE>>1)-1);
@@ -384,13 +887,13 @@
"1: \n"
- "vld2.16 {q2, q3}, [%[sP]] \n"// load 4 16-bits stereo samples
- "vld2.16 {q5, q6}, [%[sN]]! \n"// load 4 16-bits stereo samples
- "vld1.32 {q8, q9}, [%[coefsP0]:128]! \n"// load 4 32-bits coefs
- "vld1.32 {q10, q11}, [%[coefsN0]:128]! \n"// load 4 32-bits coefs
+ "vld2.16 {q2, q3}, [%[sP]] \n"// load 8 16-bits stereo frames
+ "vld2.16 {q5, q6}, [%[sN]]! \n"// load 8 16-bits stereo frames
+ "vld1.32 {q8, q9}, [%[coefsP0]:128]! \n"// load 8 32-bits coefs
+ "vld1.32 {q10, q11}, [%[coefsN0]:128]! \n"// load 8 32-bits coefs
- "vrev64.16 q2, q2 \n"// reverse 8 frames of the positive side
- "vrev64.16 q3, q3 \n"// reverse 8 frames of the positive side
+ "vrev64.16 q2, q2 \n"// reverse 8 samples of positive left
+ "vrev64.16 q3, q3 \n"// reverse 8 samples of positive right
"vshll.s16 q12, d4, #15 \n"// extend samples to 31 bits
"vshll.s16 q13, d5, #15 \n"// extend samples to 31 bits
@@ -398,15 +901,15 @@
"vshll.s16 q14, d10, #15 \n"// extend samples to 31 bits
"vshll.s16 q15, d11, #15 \n"// extend samples to 31 bits
- "vqrdmulh.s32 q12, q12, q9 \n"// multiply samples by interpolated coef
- "vqrdmulh.s32 q13, q13, q8 \n"// multiply samples by interpolated coef
- "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by interpolated coef
- "vqrdmulh.s32 q15, q15, q11 \n"// multiply samples by interpolated coef
+ "vqrdmulh.s32 q12, q12, q9 \n"// multiply samples by coef
+ "vqrdmulh.s32 q13, q13, q8 \n"// multiply samples by coef
+ "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by coef
+ "vqrdmulh.s32 q15, q15, q11 \n"// multiply samples by coef
"vadd.s32 q0, q0, q12 \n"// accumulate result
"vadd.s32 q13, q13, q14 \n"// accumulate result
- "vadd.s32 q0, q0, q15 \n"// (+1) accumulate result
- "vadd.s32 q0, q0, q13 \n"// (+1) accumulate result
+ "vadd.s32 q0, q0, q15 \n"// accumulate result
+ "vadd.s32 q0, q0, q13 \n"// accumulate result
"vshll.s16 q12, d6, #15 \n"// extend samples to 31 bits
"vshll.s16 q13, d7, #15 \n"// extend samples to 31 bits
@@ -414,15 +917,15 @@
"vshll.s16 q14, d12, #15 \n"// extend samples to 31 bits
"vshll.s16 q15, d13, #15 \n"// extend samples to 31 bits
- "vqrdmulh.s32 q12, q12, q9 \n"// multiply samples by interpolated coef
- "vqrdmulh.s32 q13, q13, q8 \n"// multiply samples by interpolated coef
- "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by interpolated coef
- "vqrdmulh.s32 q15, q15, q11 \n"// multiply samples by interpolated coef
+ "vqrdmulh.s32 q12, q12, q9 \n"// multiply samples by coef
+ "vqrdmulh.s32 q13, q13, q8 \n"// multiply samples by coef
+ "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by coef
+ "vqrdmulh.s32 q15, q15, q11 \n"// multiply samples by coef
"vadd.s32 q4, q4, q12 \n"// accumulate result
"vadd.s32 q13, q13, q14 \n"// accumulate result
- "vadd.s32 q4, q4, q15 \n"// (+1) accumulate result
- "vadd.s32 q4, q4, q13 \n"// (+1) accumulate result
+ "vadd.s32 q4, q4, q15 \n"// accumulate result
+ "vadd.s32 q4, q4, q13 \n"// accumulate result
"subs %[count], %[count], #8 \n"// update loop counter
"sub %[sP], %[sP], #32 \n"// move pointer to next set of samples
@@ -444,6 +947,7 @@
"q8", "q9", "q10", "q11",
"q12", "q13", "q14", "q15"
);
+#endif
}
template <>
@@ -458,6 +962,10 @@
uint32_t lerpP,
const int32_t* const volumeLR)
{
+#ifdef USE_INTRINSIC
+ ProcessNeonIntrinsic<1, 16, false>(out, count, coefsP, coefsN, sP, sN, volumeLR,
+ lerpP, coefsP1, coefsN1);
+#else
const int CHANNELS = 1; // template specialization does not preserve params
const int STRIDE = 16;
sP -= CHANNELS*((STRIDE>>1)-1);
@@ -489,7 +997,7 @@
"vadd.s32 q10, q10, q14 \n"// interpolate (step3)
"vadd.s32 q11, q11, q15 \n"// interpolate (step3)
- "vrev64.16 q2, q2 \n"// reverse 8 frames of the positive side
+ "vrev64.16 q2, q2 \n"// reverse 8 samples of the positive side
"vshll.s16 q12, d4, #15 \n"// extend samples to 31 bits
"vshll.s16 q13, d5, #15 \n"// extend samples to 31 bits
@@ -529,6 +1037,7 @@
"q8", "q9", "q10", "q11",
"q12", "q13", "q14", "q15"
);
+#endif
}
template <>
@@ -543,6 +1052,10 @@
uint32_t lerpP,
const int32_t* const volumeLR)
{
+#ifdef USE_INTRINSIC
+ ProcessNeonIntrinsic<2, 16, false>(out, count, coefsP, coefsN, sP, sN, volumeLR,
+ lerpP, coefsP1, coefsN1);
+#else
const int CHANNELS = 2; // template specialization does not preserve params
const int STRIDE = 16;
sP -= CHANNELS*((STRIDE>>1)-1);
@@ -553,8 +1066,8 @@
"1: \n"
- "vld2.16 {q2, q3}, [%[sP]] \n"// load 4 16-bits stereo samples
- "vld2.16 {q5, q6}, [%[sN]]! \n"// load 4 16-bits stereo samples
+ "vld2.16 {q2, q3}, [%[sP]] \n"// load 8 16-bits stereo frames
+ "vld2.16 {q5, q6}, [%[sN]]! \n"// load 8 16-bits stereo frames
"vld1.32 {q8, q9}, [%[coefsP0]:128]! \n"// load 8 32-bits coefs
"vld1.32 {q12, q13}, [%[coefsP1]:128]! \n"// load 8 32-bits coefs
"vld1.32 {q10, q11}, [%[coefsN1]:128]! \n"// load 8 32-bits coefs
@@ -575,8 +1088,8 @@
"vadd.s32 q10, q10, q14 \n"// interpolate (step3)
"vadd.s32 q11, q11, q15 \n"// interpolate (step3)
- "vrev64.16 q2, q2 \n"// reverse 8 frames of the positive side
- "vrev64.16 q3, q3 \n"// reverse 8 frames of the positive side
+ "vrev64.16 q2, q2 \n"// reverse 8 samples of positive left
+ "vrev64.16 q3, q3 \n"// reverse 8 samples of positive right
"vshll.s16 q12, d4, #15 \n"// extend samples to 31 bits
"vshll.s16 q13, d5, #15 \n"// extend samples to 31 bits
@@ -591,8 +1104,8 @@
"vadd.s32 q0, q0, q12 \n"// accumulate result
"vadd.s32 q13, q13, q14 \n"// accumulate result
- "vadd.s32 q0, q0, q15 \n"// (+1) accumulate result
- "vadd.s32 q0, q0, q13 \n"// (+1) accumulate result
+ "vadd.s32 q0, q0, q15 \n"// accumulate result
+ "vadd.s32 q0, q0, q13 \n"// accumulate result
"vshll.s16 q12, d6, #15 \n"// extend samples to 31 bits
"vshll.s16 q13, d7, #15 \n"// extend samples to 31 bits
@@ -607,8 +1120,8 @@
"vadd.s32 q4, q4, q12 \n"// accumulate result
"vadd.s32 q13, q13, q14 \n"// accumulate result
- "vadd.s32 q4, q4, q15 \n"// (+1) accumulate result
- "vadd.s32 q4, q4, q13 \n"// (+1) accumulate result
+ "vadd.s32 q4, q4, q15 \n"// accumulate result
+ "vadd.s32 q4, q4, q13 \n"// accumulate result
"subs %[count], %[count], #8 \n"// update loop counter
"sub %[sP], %[sP], #32 \n"// move pointer to next set of samples
@@ -633,517 +1146,69 @@
"q8", "q9", "q10", "q11",
"q12", "q13", "q14", "q15"
);
+#endif
}
-template <>
-inline void ProcessL<1, 8>(int32_t* const out,
+template<>
+inline void ProcessL<1, 16>(float* const out,
int count,
- const int16_t* coefsP,
- const int16_t* coefsN,
- const int16_t* sP,
- const int16_t* sN,
- const int32_t* const volumeLR)
+ const float* coefsP,
+ const float* coefsN,
+ const float* sP,
+ const float* sN,
+ const float* const volumeLR)
{
- const int CHANNELS = 1; // template specialization does not preserve params
- const int STRIDE = 8;
- sP -= CHANNELS*((STRIDE>>1)-1);
- asm (
- "veor q0, q0, q0 \n"// (0 - combines+) accumulator = 0
-
- "1: \n"
-
- "vld1.16 {d4}, [%[sP]] \n"// (2+0d) load 4 16-bits mono samples
- "vld1.16 {d6}, [%[sN]]! \n"// (2) load 4 16-bits mono samples
- "vld1.16 {d16}, [%[coefsP0]:64]! \n"// (1) load 4 16-bits coefs
- "vld1.16 {d20}, [%[coefsN0]:64]! \n"// (1) load 4 16-bits coefs
-
- "vrev64.16 d4, d4 \n"// (1) reversed s3, s2, s1, s0, s7, s6, s5, s4
-
- // reordering the vmal to do d6, d7 before d4, d5 is slower(?)
- "vmlal.s16 q0, d4, d16 \n"// (1) multiply (reversed)samples by coef
- "vmlal.s16 q0, d6, d20 \n"// (1) multiply neg samples
-
- // moving these ARM instructions before neon above seems to be slower
- "subs %[count], %[count], #4 \n"// (1) update loop counter
- "sub %[sP], %[sP], #8 \n"// (0) move pointer to next set of samples
-
- // sP used after branch (warning)
- "bne 1b \n"// loop
-
- ASSEMBLY_ACCUMULATE_MONO
-
- : [out] "=Uv" (out[0]),
- [count] "+r" (count),
- [coefsP0] "+r" (coefsP),
- [coefsN0] "+r" (coefsN),
- [sP] "+r" (sP),
- [sN] "+r" (sN)
- : [vLR] "r" (volumeLR)
- : "cc", "memory",
- "q0", "q1", "q2", "q3",
- "q8", "q10"
- );
+ ProcessNeonIntrinsic<1, 16, true>(out, count, coefsP, coefsN, sP, sN, volumeLR,
+ 0 /*lerpP*/, NULL /*coefsP1*/, NULL /*coefsN1*/);
}
-template <>
-inline void ProcessL<2, 8>(int32_t* const out,
+template<>
+inline void ProcessL<2, 16>(float* const out,
int count,
- const int16_t* coefsP,
- const int16_t* coefsN,
- const int16_t* sP,
- const int16_t* sN,
- const int32_t* const volumeLR)
+ const float* coefsP,
+ const float* coefsN,
+ const float* sP,
+ const float* sN,
+ const float* const volumeLR)
{
- const int CHANNELS = 2; // template specialization does not preserve params
- const int STRIDE = 8;
- sP -= CHANNELS*((STRIDE>>1)-1);
- asm (
- "veor q0, q0, q0 \n"// (1) acc_L = 0
- "veor q4, q4, q4 \n"// (0 combines+) acc_R = 0
-
- "1: \n"
-
- "vld2.16 {d4, d5}, [%[sP]] \n"// (2+0d) load 8 16-bits stereo samples
- "vld2.16 {d6, d7}, [%[sN]]! \n"// (2) load 8 16-bits stereo samples
- "vld1.16 {d16}, [%[coefsP0]:64]! \n"// (1) load 8 16-bits coefs
- "vld1.16 {d20}, [%[coefsN0]:64]! \n"// (1) load 8 16-bits coefs
-
- "vrev64.16 q2, q2 \n"// (1) reverse 8 frames of the left positive
-
- "vmlal.s16 q0, d4, d16 \n"// (1) multiply (reversed) samples left
- "vmlal.s16 q4, d5, d16 \n"// (1) multiply (reversed) samples right
- "vmlal.s16 q0, d6, d20 \n"// (1) multiply samples left
- "vmlal.s16 q4, d7, d20 \n"// (1) multiply samples right
-
- // moving these ARM before neon seems to be slower
- "subs %[count], %[count], #4 \n"// (1) update loop counter
- "sub %[sP], %[sP], #16 \n"// (0) move pointer to next set of samples
-
- // sP used after branch (warning)
- "bne 1b \n"// loop
-
- ASSEMBLY_ACCUMULATE_STEREO
-
- : [out] "=Uv" (out[0]),
- [count] "+r" (count),
- [coefsP0] "+r" (coefsP),
- [coefsN0] "+r" (coefsN),
- [sP] "+r" (sP),
- [sN] "+r" (sN)
- : [vLR] "r" (volumeLR)
- : "cc", "memory",
- "q0", "q1", "q2", "q3",
- "q4", "q5", "q6",
- "q8", "q10"
- );
+ ProcessNeonIntrinsic<2, 16, true>(out, count, coefsP, coefsN, sP, sN, volumeLR,
+ 0 /*lerpP*/, NULL /*coefsP1*/, NULL /*coefsN1*/);
}
-template <>
-inline void Process<1, 8>(int32_t* const out,
+template<>
+inline void Process<1, 16>(float* const out,
int count,
- const int16_t* coefsP,
- const int16_t* coefsN,
- const int16_t* coefsP1,
- const int16_t* coefsN1,
- const int16_t* sP,
- const int16_t* sN,
- uint32_t lerpP,
- const int32_t* const volumeLR)
+ const float* coefsP,
+ const float* coefsN,
+ const float* coefsP1,
+ const float* coefsN1,
+ const float* sP,
+ const float* sN,
+ float lerpP,
+ const float* const volumeLR)
{
- const int CHANNELS = 1; // template specialization does not preserve params
- const int STRIDE = 8;
- sP -= CHANNELS*((STRIDE>>1)-1);
- asm (
- "vmov.32 d2[0], %[lerpP] \n"// load the positive phase S32 Q15
- "veor q0, q0, q0 \n"// (0 - combines+) accumulator = 0
-
- "1: \n"
-
- "vld1.16 {d4}, [%[sP]] \n"// (2+0d) load 4 16-bits mono samples
- "vld1.16 {d6}, [%[sN]]! \n"// (2) load 4 16-bits mono samples
- "vld1.16 {d16}, [%[coefsP0]:64]! \n"// (1) load 4 16-bits coefs
- "vld1.16 {d17}, [%[coefsP1]:64]! \n"// (1) load 4 16-bits coefs for interpolation
- "vld1.16 {d20}, [%[coefsN1]:64]! \n"// (1) load 4 16-bits coefs
- "vld1.16 {d21}, [%[coefsN0]:64]! \n"// (1) load 4 16-bits coefs for interpolation
-
- "vsub.s16 d17, d17, d16 \n"// (1) interpolate (step1) 1st set of coefs
- "vsub.s16 d21, d21, d20 \n"// (1) interpolate (step1) 2nd set of coets
-
- "vqrdmulh.s16 d17, d17, d2[0] \n"// (2) interpolate (step2) 1st set of coefs
- "vqrdmulh.s16 d21, d21, d2[0] \n"// (2) interpolate (step2) 2nd set of coefs
-
- "vrev64.16 d4, d4 \n"// (1) reverse s3, s2, s1, s0, s7, s6, s5, s4
-
- "vadd.s16 d16, d16, d17 \n"// (1+2d) interpolate (step3) 1st set
- "vadd.s16 d20, d20, d21 \n"// (1+1d) interpolate (step3) 2nd set
-
- // reordering the vmal to do d6, d7 before d4, d5 is slower(?)
- "vmlal.s16 q0, d4, d16 \n"// (1+0d) multiply (reversed)by coef
- "vmlal.s16 q0, d6, d20 \n"// (1) multiply neg samples
-
- // moving these ARM instructions before neon above seems to be slower
- "subs %[count], %[count], #4 \n"// (1) update loop counter
- "sub %[sP], %[sP], #8 \n"// move pointer to next set of samples
-
- // sP used after branch (warning)
- "bne 1b \n"// loop
-
- ASSEMBLY_ACCUMULATE_MONO
-
- : [out] "=Uv" (out[0]),
- [count] "+r" (count),
- [coefsP0] "+r" (coefsP),
- [coefsN0] "+r" (coefsN),
- [coefsP1] "+r" (coefsP1),
- [coefsN1] "+r" (coefsN1),
- [sP] "+r" (sP),
- [sN] "+r" (sN)
- : [lerpP] "r" (lerpP),
- [vLR] "r" (volumeLR)
- : "cc", "memory",
- "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11"
- );
+ ProcessNeonIntrinsic<1, 16, false>(out, count, coefsP, coefsN, sP, sN, volumeLR,
+ lerpP, coefsP1, coefsN1);
}
-template <>
-inline void Process<2, 8>(int32_t* const out,
+template<>
+inline void Process<2, 16>(float* const out,
int count,
- const int16_t* coefsP,
- const int16_t* coefsN,
- const int16_t* coefsP1,
- const int16_t* coefsN1,
- const int16_t* sP,
- const int16_t* sN,
- uint32_t lerpP,
- const int32_t* const volumeLR)
+ const float* coefsP,
+ const float* coefsN,
+ const float* coefsP1,
+ const float* coefsN1,
+ const float* sP,
+ const float* sN,
+ float lerpP,
+ const float* const volumeLR)
{
- const int CHANNELS = 2; // template specialization does not preserve params
- const int STRIDE = 8;
- sP -= CHANNELS*((STRIDE>>1)-1);
- asm (
- "vmov.32 d2[0], %[lerpP] \n"// load the positive phase
- "veor q0, q0, q0 \n"// (1) acc_L = 0
- "veor q4, q4, q4 \n"// (0 combines+) acc_R = 0
-
- "1: \n"
-
- "vld2.16 {d4, d5}, [%[sP]] \n"// (3+0d) load 8 16-bits stereo samples
- "vld2.16 {d6, d7}, [%[sN]]! \n"// (3) load 8 16-bits stereo samples
- "vld1.16 {d16}, [%[coefsP0]:64]! \n"// (1) load 8 16-bits coefs
- "vld1.16 {d17}, [%[coefsP1]:64]! \n"// (1) load 8 16-bits coefs for interpolation
- "vld1.16 {d20}, [%[coefsN1]:64]! \n"// (1) load 8 16-bits coefs
- "vld1.16 {d21}, [%[coefsN0]:64]! \n"// (1) load 8 16-bits coefs for interpolation
-
- "vsub.s16 d17, d17, d16 \n"// (1) interpolate (step1) 1st set of coefs
- "vsub.s16 d21, d21, d20 \n"// (1) interpolate (step1) 2nd set of coets
-
- "vqrdmulh.s16 d17, d17, d2[0] \n"// (2) interpolate (step2) 1st set of coefs
- "vqrdmulh.s16 d21, d21, d2[0] \n"// (2) interpolate (step2) 2nd set of coefs
-
- "vrev64.16 q2, q2 \n"// (1) reverse 8 frames of the left positive
-
- "vadd.s16 d16, d16, d17 \n"// (1+1d) interpolate (step3) 1st set
- "vadd.s16 d20, d20, d21 \n"// (1+1d) interpolate (step3) 2nd set
-
- "vmlal.s16 q0, d4, d16 \n"// (1) multiply (reversed) samples left
- "vmlal.s16 q4, d5, d16 \n"// (1) multiply (reversed) samples right
- "vmlal.s16 q0, d6, d20 \n"// (1) multiply samples left
- "vmlal.s16 q4, d7, d20 \n"// (1) multiply samples right
-
- // moving these ARM before neon seems to be slower
- "subs %[count], %[count], #4 \n"// (1) update loop counter
- "sub %[sP], %[sP], #16 \n"// move pointer to next set of samples
-
- // sP used after branch (warning)
- "bne 1b \n"// loop
-
- ASSEMBLY_ACCUMULATE_STEREO
-
- : [out] "=Uv" (out[0]),
- [count] "+r" (count),
- [coefsP0] "+r" (coefsP),
- [coefsN0] "+r" (coefsN),
- [coefsP1] "+r" (coefsP1),
- [coefsN1] "+r" (coefsN1),
- [sP] "+r" (sP),
- [sN] "+r" (sN)
- : [lerpP] "r" (lerpP),
- [vLR] "r" (volumeLR)
- : "cc", "memory",
- "q0", "q1", "q2", "q3",
- "q4", "q5", "q6",
- "q8", "q9", "q10", "q11"
- );
-}
-
-template <>
-inline void ProcessL<1, 8>(int32_t* const out,
- int count,
- const int32_t* coefsP,
- const int32_t* coefsN,
- const int16_t* sP,
- const int16_t* sN,
- const int32_t* const volumeLR)
-{
- const int CHANNELS = 1; // template specialization does not preserve params
- const int STRIDE = 8;
- sP -= CHANNELS*((STRIDE>>1)-1);
- asm (
- "veor q0, q0, q0 \n"// result, initialize to 0
-
- "1: \n"
-
- "vld1.16 {d4}, [%[sP]] \n"// load 4 16-bits mono samples
- "vld1.16 {d6}, [%[sN]]! \n"// load 4 16-bits mono samples
- "vld1.32 {q8}, [%[coefsP0]:128]! \n"// load 4 32-bits coefs
- "vld1.32 {q10}, [%[coefsN0]:128]! \n"// load 4 32-bits coefs
-
- "vrev64.16 d4, d4 \n"// reverse 2 frames of the positive side
-
- "vshll.s16 q12, d4, #15 \n"// (stall) extend samples to 31 bits
- "vshll.s16 q14, d6, #15 \n"// extend samples to 31 bits
-
- "vqrdmulh.s32 q12, q12, q8 \n"// multiply samples by interpolated coef
- "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by interpolated coef
-
- "vadd.s32 q0, q0, q12 \n"// accumulate result
- "vadd.s32 q0, q0, q14 \n"// (stall) accumulate result
-
- "subs %[count], %[count], #4 \n"// update loop counter
- "sub %[sP], %[sP], #8 \n"// move pointer to next set of samples
-
- "bne 1b \n"// loop
-
- ASSEMBLY_ACCUMULATE_MONO
-
- : [out] "=Uv" (out[0]),
- [count] "+r" (count),
- [coefsP0] "+r" (coefsP),
- [coefsN0] "+r" (coefsN),
- [sP] "+r" (sP),
- [sN] "+r" (sN)
- : [vLR] "r" (volumeLR)
- : "cc", "memory",
- "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11",
- "q12", "q14"
- );
-}
-
-template <>
-inline void ProcessL<2, 8>(int32_t* const out,
- int count,
- const int32_t* coefsP,
- const int32_t* coefsN,
- const int16_t* sP,
- const int16_t* sN,
- const int32_t* const volumeLR)
-{
- const int CHANNELS = 2; // template specialization does not preserve params
- const int STRIDE = 8;
- sP -= CHANNELS*((STRIDE>>1)-1);
- asm (
- "veor q0, q0, q0 \n"// result, initialize to 0
- "veor q4, q4, q4 \n"// result, initialize to 0
-
- "1: \n"
-
- "vld2.16 {d4, d5}, [%[sP]] \n"// load 4 16-bits stereo samples
- "vld2.16 {d6, d7}, [%[sN]]! \n"// load 4 16-bits stereo samples
- "vld1.32 {q8}, [%[coefsP0]:128]! \n"// load 4 32-bits coefs
- "vld1.32 {q10}, [%[coefsN0]:128]! \n"// load 4 32-bits coefs
-
- "vrev64.16 q2, q2 \n"// reverse 2 frames of the positive side
-
- "vshll.s16 q12, d4, #15 \n"// extend samples to 31 bits
- "vshll.s16 q13, d5, #15 \n"// extend samples to 31 bits
-
- "vshll.s16 q14, d6, #15 \n"// extend samples to 31 bits
- "vshll.s16 q15, d7, #15 \n"// extend samples to 31 bits
-
- "vqrdmulh.s32 q12, q12, q8 \n"// multiply samples by coef
- "vqrdmulh.s32 q13, q13, q8 \n"// multiply samples by coef
- "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by coef
- "vqrdmulh.s32 q15, q15, q10 \n"// multiply samples by coef
-
- "vadd.s32 q0, q0, q12 \n"// accumulate result
- "vadd.s32 q4, q4, q13 \n"// accumulate result
- "vadd.s32 q0, q0, q14 \n"// accumulate result
- "vadd.s32 q4, q4, q15 \n"// accumulate result
-
- "subs %[count], %[count], #4 \n"// update loop counter
- "sub %[sP], %[sP], #16 \n"// move pointer to next set of samples
-
- "bne 1b \n"// loop
-
- ASSEMBLY_ACCUMULATE_STEREO
-
- : [out] "=Uv" (out[0]),
- [count] "+r" (count),
- [coefsP0] "+r" (coefsP),
- [coefsN0] "+r" (coefsN),
- [sP] "+r" (sP),
- [sN] "+r" (sN)
- : [vLR] "r" (volumeLR)
- : "cc", "memory",
- "q0", "q1", "q2", "q3", "q4",
- "q8", "q9", "q10", "q11",
- "q12", "q13", "q14", "q15"
- );
-}
-
-template <>
-inline void Process<1, 8>(int32_t* const out,
- int count,
- const int32_t* coefsP,
- const int32_t* coefsN,
- const int32_t* coefsP1,
- const int32_t* coefsN1,
- const int16_t* sP,
- const int16_t* sN,
- uint32_t lerpP,
- const int32_t* const volumeLR)
-{
- const int CHANNELS = 1; // template specialization does not preserve params
- const int STRIDE = 8;
- sP -= CHANNELS*((STRIDE>>1)-1);
- asm (
- "vmov.32 d2[0], %[lerpP] \n"// load the positive phase
- "veor q0, q0, q0 \n"// result, initialize to 0
-
- "1: \n"
-
- "vld1.16 {d4}, [%[sP]] \n"// load 4 16-bits mono samples
- "vld1.16 {d6}, [%[sN]]! \n"// load 4 16-bits mono samples
- "vld1.32 {q8}, [%[coefsP0]:128]! \n"// load 4 32-bits coefs
- "vld1.32 {q9}, [%[coefsP1]:128]! \n"// load 4 32-bits coefs for interpolation
- "vld1.32 {q10}, [%[coefsN1]:128]! \n"// load 4 32-bits coefs
- "vld1.32 {q11}, [%[coefsN0]:128]! \n"// load 4 32-bits coefs for interpolation
-
- "vrev64.16 d4, d4 \n"// reverse 2 frames of the positive side
-
- "vsub.s32 q9, q9, q8 \n"// interpolate (step1) 1st set of coefs
- "vsub.s32 q11, q11, q10 \n"// interpolate (step1) 2nd set of coets
- "vshll.s16 q12, d4, #15 \n"// extend samples to 31 bits
-
- "vqrdmulh.s32 q9, q9, d2[0] \n"// interpolate (step2) 1st set of coefs
- "vqrdmulh.s32 q11, q11, d2[0] \n"// interpolate (step2) 2nd set of coefs
- "vshll.s16 q14, d6, #15 \n"// extend samples to 31 bits
-
- "vadd.s32 q8, q8, q9 \n"// interpolate (step3) 1st set
- "vadd.s32 q10, q10, q11 \n"// interpolate (step4) 2nd set
-
- "vqrdmulh.s32 q12, q12, q8 \n"// multiply samples by interpolated coef
- "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by interpolated coef
-
- "vadd.s32 q0, q0, q12 \n"// accumulate result
- "vadd.s32 q0, q0, q14 \n"// accumulate result
-
- "subs %[count], %[count], #4 \n"// update loop counter
- "sub %[sP], %[sP], #8 \n"// move pointer to next set of samples
-
- "bne 1b \n"// loop
-
- ASSEMBLY_ACCUMULATE_MONO
-
- : [out] "=Uv" (out[0]),
- [count] "+r" (count),
- [coefsP0] "+r" (coefsP),
- [coefsP1] "+r" (coefsP1),
- [coefsN0] "+r" (coefsN),
- [coefsN1] "+r" (coefsN1),
- [sP] "+r" (sP),
- [sN] "+r" (sN)
- : [lerpP] "r" (lerpP),
- [vLR] "r" (volumeLR)
- : "cc", "memory",
- "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11",
- "q12", "q14"
- );
-}
-
-template <>
-inline
-void Process<2, 8>(int32_t* const out,
- int count,
- const int32_t* coefsP,
- const int32_t* coefsN,
- const int32_t* coefsP1,
- const int32_t* coefsN1,
- const int16_t* sP,
- const int16_t* sN,
- uint32_t lerpP,
- const int32_t* const volumeLR)
-{
- const int CHANNELS = 2; // template specialization does not preserve params
- const int STRIDE = 8;
- sP -= CHANNELS*((STRIDE>>1)-1);
- asm (
- "vmov.32 d2[0], %[lerpP] \n"// load the positive phase
- "veor q0, q0, q0 \n"// result, initialize to 0
- "veor q4, q4, q4 \n"// result, initialize to 0
-
- "1: \n"
- "vld2.16 {d4, d5}, [%[sP]] \n"// load 4 16-bits stereo samples
- "vld2.16 {d6, d7}, [%[sN]]! \n"// load 4 16-bits stereo samples
- "vld1.32 {q8}, [%[coefsP0]:128]! \n"// load 4 32-bits coefs
- "vld1.32 {q9}, [%[coefsP1]:128]! \n"// load 4 32-bits coefs for interpolation
- "vld1.32 {q10}, [%[coefsN1]:128]! \n"// load 4 32-bits coefs
- "vld1.32 {q11}, [%[coefsN0]:128]! \n"// load 4 32-bits coefs for interpolation
-
- "vrev64.16 q2, q2 \n"// (reversed) 2 frames of the positive side
-
- "vsub.s32 q9, q9, q8 \n"// interpolate (step1) 1st set of coefs
- "vsub.s32 q11, q11, q10 \n"// interpolate (step1) 2nd set of coets
- "vshll.s16 q12, d4, #15 \n"// extend samples to 31 bits
- "vshll.s16 q13, d5, #15 \n"// extend samples to 31 bits
-
- "vqrdmulh.s32 q9, q9, d2[0] \n"// interpolate (step2) 1st set of coefs
- "vqrdmulh.s32 q11, q11, d2[1] \n"// interpolate (step3) 2nd set of coefs
- "vshll.s16 q14, d6, #15 \n"// extend samples to 31 bits
- "vshll.s16 q15, d7, #15 \n"// extend samples to 31 bits
-
- "vadd.s32 q8, q8, q9 \n"// interpolate (step3) 1st set
- "vadd.s32 q10, q10, q11 \n"// interpolate (step4) 2nd set
-
- "vqrdmulh.s32 q12, q12, q8 \n"// multiply samples by interpolated coef
- "vqrdmulh.s32 q13, q13, q8 \n"// multiply samples by interpolated coef
- "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by interpolated coef
- "vqrdmulh.s32 q15, q15, q10 \n"// multiply samples by interpolated coef
-
- "vadd.s32 q0, q0, q12 \n"// accumulate result
- "vadd.s32 q4, q4, q13 \n"// accumulate result
- "vadd.s32 q0, q0, q14 \n"// accumulate result
- "vadd.s32 q4, q4, q15 \n"// accumulate result
-
- "subs %[count], %[count], #4 \n"// update loop counter
- "sub %[sP], %[sP], #16 \n"// move pointer to next set of samples
-
- "bne 1b \n"// loop
-
- ASSEMBLY_ACCUMULATE_STEREO
-
- : [out] "=Uv" (out[0]),
- [count] "+r" (count),
- [coefsP0] "+r" (coefsP),
- [coefsP1] "+r" (coefsP1),
- [coefsN0] "+r" (coefsN),
- [coefsN1] "+r" (coefsN1),
- [sP] "+r" (sP),
- [sN] "+r" (sN)
- : [lerpP] "r" (lerpP),
- [vLR] "r" (volumeLR)
- : "cc", "memory",
- "q0", "q1", "q2", "q3", "q4",
- "q8", "q9", "q10", "q11",
- "q12", "q13", "q14", "q15"
- );
+ ProcessNeonIntrinsic<2, 16, false>(out, count, coefsP, coefsN, sP, sN, volumeLR,
+ lerpP, coefsP1, coefsN1);
}
#endif //USE_NEON
-}; // namespace android
+} // namespace android
#endif /*ANDROID_AUDIO_RESAMPLER_FIR_PROCESS_NEON_H*/
diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp
index d03e578..ba9a356 100644
--- a/services/audioflinger/AudioResamplerSinc.cpp
+++ b/services/audioflinger/AudioResamplerSinc.cpp
@@ -31,7 +31,10 @@
#include "AudioResamplerSinc.h"
-
+#if defined(__clang__) && !__has_builtin(__builtin_assume_aligned)
+#define __builtin_assume_aligned(p, a) \
+ (((uintptr_t(p) % (a)) == 0) ? (p) : (__builtin_unreachable(), (p)))
+#endif
#if defined(__arm__) && !defined(__thumb__)
#define USE_INLINE_ASSEMBLY (true)
@@ -58,135 +61,7 @@
* cmd-line: fir -l 7 -s 48000 -c 20478
*/
const uint32_t AudioResamplerSinc::mFirCoefsUp[] __attribute__ ((aligned (32))) = {
- 0x6d374bc7, 0x111c6ba0, 0xf3240e61, 0x07d14a38, 0xfc509e64, 0x0139cee9, 0xffc8c866, 0xfffcc300,
- 0x6d35278a, 0x103e8192, 0xf36b9dfd, 0x07bdfaa5, 0xfc5102d0, 0x013d618d, 0xffc663b9, 0xfffd9592,
- 0x6d2ebafe, 0x0f62811a, 0xf3b3d8ac, 0x07a9f399, 0xfc51d9a6, 0x0140bea5, 0xffc41212, 0xfffe631e,
- 0x6d24069d, 0x0e8875ad, 0xf3fcb43e, 0x07953976, 0xfc53216f, 0x0143e67c, 0xffc1d373, 0xffff2b9f,
- 0x6d150b35, 0x0db06a89, 0xf4462690, 0x077fd0ac, 0xfc54d8ae, 0x0146d965, 0xffbfa7d9, 0xffffef10,
- 0x6d01c9e3, 0x0cda6ab5, 0xf4902587, 0x0769bdaf, 0xfc56fdda, 0x014997bb, 0xffbd8f40, 0x0000ad6e,
- 0x6cea4418, 0x0c0680fe, 0xf4daa718, 0x07530501, 0xfc598f60, 0x014c21db, 0xffbb89a1, 0x000166b6,
- 0x6cce7b97, 0x0b34b7f5, 0xf525a143, 0x073bab28, 0xfc5c8ba5, 0x014e782a, 0xffb996f3, 0x00021ae5,
- 0x6cae7272, 0x0a6519f4, 0xf5710a17, 0x0723b4b4, 0xfc5ff105, 0x01509b14, 0xffb7b728, 0x0002c9fd,
- 0x6c8a2b0f, 0x0997b116, 0xf5bcd7b1, 0x070b2639, 0xfc63bdd3, 0x01528b08, 0xffb5ea31, 0x000373fb,
- 0x6c61a823, 0x08cc873c, 0xf609003f, 0x06f20453, 0xfc67f05a, 0x0154487b, 0xffb42ffc, 0x000418e2,
- 0x6c34ecb5, 0x0803a60a, 0xf6557a00, 0x06d853a2, 0xfc6c86dd, 0x0155d3e8, 0xffb28876, 0x0004b8b3,
- 0x6c03fc1c, 0x073d16e7, 0xf6a23b44, 0x06be18cd, 0xfc717f97, 0x01572dcf, 0xffb0f388, 0x00055371,
- 0x6bced9ff, 0x0678e2fc, 0xf6ef3a6e, 0x06a3587e, 0xfc76d8bc, 0x015856b6, 0xffaf7118, 0x0005e921,
- 0x6b958a54, 0x05b71332, 0xf73c6df4, 0x06881761, 0xfc7c9079, 0x01594f25, 0xffae010b, 0x000679c5,
- 0x6b581163, 0x04f7b037, 0xf789cc61, 0x066c5a27, 0xfc82a4f4, 0x015a17ab, 0xffaca344, 0x00070564,
- 0x6b1673c1, 0x043ac276, 0xf7d74c53, 0x06502583, 0xfc89144d, 0x015ab0db, 0xffab57a1, 0x00078c04,
- 0x6ad0b652, 0x0380521c, 0xf824e480, 0x06337e2a, 0xfc8fdc9f, 0x015b1b4e, 0xffaa1e02, 0x00080dab,
- 0x6a86de48, 0x02c86715, 0xf8728bb3, 0x061668d2, 0xfc96fbfc, 0x015b579e, 0xffa8f641, 0x00088a62,
- 0x6a38f123, 0x0213090c, 0xf8c038d0, 0x05f8ea30, 0xfc9e7074, 0x015b666c, 0xffa7e039, 0x00090230,
- 0x69e6f4b1, 0x01603f6e, 0xf90de2d1, 0x05db06fc, 0xfca63810, 0x015b485b, 0xffa6dbc0, 0x0009751e,
- 0x6990ef0b, 0x00b01162, 0xf95b80cb, 0x05bcc3ed, 0xfcae50d6, 0x015afe14, 0xffa5e8ad, 0x0009e337,
- 0x6936e697, 0x000285d0, 0xf9a909ea, 0x059e25b5, 0xfcb6b8c4, 0x015a8843, 0xffa506d2, 0x000a4c85,
- 0x68d8e206, 0xff57a35e, 0xf9f67577, 0x057f310a, 0xfcbf6dd8, 0x0159e796, 0xffa43603, 0x000ab112,
- 0x6876e855, 0xfeaf706f, 0xfa43bad2, 0x055fea9d, 0xfcc86e09, 0x01591cc0, 0xffa3760e, 0x000b10ec,
- 0x681100c9, 0xfe09f323, 0xfa90d17b, 0x0540571a, 0xfcd1b74c, 0x01582878, 0xffa2c6c2, 0x000b6c1d,
- 0x67a732f4, 0xfd673159, 0xfaddb10c, 0x05207b2f, 0xfcdb4793, 0x01570b77, 0xffa227ec, 0x000bc2b3,
- 0x673986ac, 0xfcc730aa, 0xfb2a513b, 0x05005b82, 0xfce51ccb, 0x0155c678, 0xffa19957, 0x000c14bb,
- 0x66c80413, 0xfc29f670, 0xfb76a9dd, 0x04dffcb6, 0xfcef34e1, 0x01545a3c, 0xffa11acb, 0x000c6244,
- 0x6652b392, 0xfb8f87bd, 0xfbc2b2e4, 0x04bf6369, 0xfcf98dbe, 0x0152c783, 0xffa0ac11, 0x000cab5c,
- 0x65d99dd5, 0xfaf7e963, 0xfc0e6461, 0x049e9433, 0xfd04254a, 0x01510f13, 0xffa04cf0, 0x000cf012,
- 0x655ccbd3, 0xfa631fef, 0xfc59b685, 0x047d93a8, 0xfd0ef969, 0x014f31b2, 0xff9ffd2c, 0x000d3075,
- 0x64dc46c3, 0xf9d12fab, 0xfca4a19f, 0x045c6654, 0xfd1a0801, 0x014d3029, 0xff9fbc89, 0x000d6c97,
- 0x64581823, 0xf9421c9d, 0xfcef1e20, 0x043b10bd, 0xfd254ef4, 0x014b0b45, 0xff9f8ac9, 0x000da486,
- 0x63d049b4, 0xf8b5ea87, 0xfd392498, 0x04199760, 0xfd30cc24, 0x0148c3d2, 0xff9f67ae, 0x000dd854,
- 0x6344e578, 0xf82c9ce7, 0xfd82adba, 0x03f7feb4, 0xfd3c7d73, 0x01465a9f, 0xff9f52f7, 0x000e0812,
- 0x62b5f5b2, 0xf7a636fa, 0xfdcbb25a, 0x03d64b27, 0xfd4860c2, 0x0143d07f, 0xff9f4c65, 0x000e33d3,
- 0x622384e8, 0xf722bbb5, 0xfe142b6e, 0x03b4811d, 0xfd5473f3, 0x01412643, 0xff9f53b4, 0x000e5ba7,
- 0x618d9ddc, 0xf6a22dcf, 0xfe5c120f, 0x0392a4f4, 0xfd60b4e7, 0x013e5cc0, 0xff9f68a1, 0x000e7fa1,
- 0x60f44b91, 0xf6248fb6, 0xfea35f79, 0x0370bafc, 0xfd6d2180, 0x013b74ca, 0xff9f8ae9, 0x000e9fd5,
- 0x60579947, 0xf5a9e398, 0xfeea0d0c, 0x034ec77f, 0xfd79b7a1, 0x01386f3a, 0xff9fba47, 0x000ebc54,
- 0x5fb79278, 0xf5322b61, 0xff30144a, 0x032ccebb, 0xfd86752e, 0x01354ce7, 0xff9ff674, 0x000ed533,
- 0x5f1442dc, 0xf4bd68b6, 0xff756edc, 0x030ad4e1, 0xfd93580d, 0x01320ea9, 0xffa03f2b, 0x000eea84,
- 0x5e6db665, 0xf44b9cfe, 0xffba168d, 0x02e8de19, 0xfda05e23, 0x012eb55a, 0xffa09425, 0x000efc5c,
- 0x5dc3f93c, 0xf3dcc959, 0xfffe054e, 0x02c6ee7f, 0xfdad855b, 0x012b41d3, 0xffa0f519, 0x000f0ace,
- 0x5d1717c4, 0xf370eea9, 0x00413536, 0x02a50a22, 0xfdbacb9e, 0x0127b4f1, 0xffa161bf, 0x000f15ef,
- 0x5c671e96, 0xf3080d8c, 0x0083a081, 0x02833506, 0xfdc82edb, 0x01240f8e, 0xffa1d9cf, 0x000f1dd2,
- 0x5bb41a80, 0xf2a2265e, 0x00c54190, 0x02617321, 0xfdd5ad01, 0x01205285, 0xffa25cfe, 0x000f228d,
- 0x5afe1886, 0xf23f393b, 0x010612eb, 0x023fc85c, 0xfde34403, 0x011c7eb2, 0xffa2eb04, 0x000f2434,
- 0x5a4525df, 0xf1df45fd, 0x01460f41, 0x021e3891, 0xfdf0f1d6, 0x011894f0, 0xffa38395, 0x000f22dc,
- 0x59894ff3, 0xf1824c3e, 0x01853165, 0x01fcc78f, 0xfdfeb475, 0x0114961b, 0xffa42668, 0x000f1e99,
- 0x58caa45b, 0xf1284b58, 0x01c37452, 0x01db7914, 0xfe0c89db, 0x0110830f, 0xffa4d332, 0x000f1781,
- 0x580930e1, 0xf0d14267, 0x0200d32c, 0x01ba50d2, 0xfe1a7009, 0x010c5ca6, 0xffa589a6, 0x000f0da8,
- 0x5745037c, 0xf07d3043, 0x023d493c, 0x0199526b, 0xfe286505, 0x010823ba, 0xffa6497c, 0x000f0125,
- 0x567e2a51, 0xf02c138a, 0x0278d1f2, 0x01788170, 0xfe3666d5, 0x0103d927, 0xffa71266, 0x000ef20b,
- 0x55b4b3af, 0xefddea9a, 0x02b368e6, 0x0157e166, 0xfe447389, 0x00ff7dc4, 0xffa7e41a, 0x000ee070,
- 0x54e8ae13, 0xef92b393, 0x02ed09d7, 0x013775bf, 0xfe528931, 0x00fb126b, 0xffa8be4c, 0x000ecc69,
- 0x541a281e, 0xef4a6c58, 0x0325b0ad, 0x011741df, 0xfe60a5e5, 0x00f697f3, 0xffa9a0b1, 0x000eb60b,
- 0x5349309e, 0xef051290, 0x035d5977, 0x00f7491a, 0xfe6ec7c0, 0x00f20f32, 0xffaa8afe, 0x000e9d6b,
- 0x5275d684, 0xeec2a3a3, 0x0394006a, 0x00d78eb3, 0xfe7cece2, 0x00ed78ff, 0xffab7ce7, 0x000e829e,
- 0x51a028e8, 0xee831cc3, 0x03c9a1e5, 0x00b815da, 0xfe8b1373, 0x00e8d62d, 0xffac7621, 0x000e65ba,
- 0x50c83704, 0xee467ae1, 0x03fe3a6f, 0x0098e1b3, 0xfe99399f, 0x00e4278f, 0xffad7662, 0x000e46d3,
- 0x4fee1037, 0xee0cbab9, 0x0431c6b5, 0x0079f54c, 0xfea75d97, 0x00df6df7, 0xffae7d5f, 0x000e25fd,
- 0x4f11c3fe, 0xedd5d8ca, 0x0464438c, 0x005b53a4, 0xfeb57d92, 0x00daaa34, 0xffaf8acd, 0x000e034f,
- 0x4e3361f7, 0xeda1d15c, 0x0495adf2, 0x003cffa9, 0xfec397cf, 0x00d5dd16, 0xffb09e63, 0x000ddedb,
- 0x4d52f9df, 0xed70a07d, 0x04c6030d, 0x001efc35, 0xfed1aa92, 0x00d10769, 0xffb1b7d8, 0x000db8b7,
- 0x4c709b8e, 0xed424205, 0x04f54029, 0x00014c12, 0xfedfb425, 0x00cc29f7, 0xffb2d6e1, 0x000d90f6,
- 0x4b8c56f8, 0xed16b196, 0x052362ba, 0xffe3f1f7, 0xfeedb2da, 0x00c7458a, 0xffb3fb37, 0x000d67ae,
- 0x4aa63c2c, 0xecedea99, 0x0550685d, 0xffc6f08a, 0xfefba508, 0x00c25ae8, 0xffb52490, 0x000d3cf1,
- 0x49be5b50, 0xecc7e845, 0x057c4ed4, 0xffaa4a5d, 0xff09890f, 0x00bd6ad7, 0xffb652a7, 0x000d10d5,
- 0x48d4c4a2, 0xeca4a59b, 0x05a7140b, 0xff8e01f1, 0xff175d53, 0x00b87619, 0xffb78533, 0x000ce36b,
- 0x47e98874, 0xec841d68, 0x05d0b612, 0xff7219b3, 0xff252042, 0x00b37d70, 0xffb8bbed, 0x000cb4c8,
- 0x46fcb72d, 0xec664a48, 0x05f93324, 0xff5693fe, 0xff32d04f, 0x00ae8198, 0xffb9f691, 0x000c84ff,
- 0x460e6148, 0xec4b26a2, 0x0620899e, 0xff3b731b, 0xff406bf8, 0x00a9834e, 0xffbb34d8, 0x000c5422,
- 0x451e9750, 0xec32acb0, 0x0646b808, 0xff20b93e, 0xff4df1be, 0x00a4834c, 0xffbc767f, 0x000c2245,
- 0x442d69de, 0xec1cd677, 0x066bbd0d, 0xff066889, 0xff5b602c, 0x009f8249, 0xffbdbb42, 0x000bef79,
- 0x433ae99c, 0xec099dcf, 0x068f9781, 0xfeec830d, 0xff68b5d5, 0x009a80f8, 0xffbf02dd, 0x000bbbd2,
- 0x4247273f, 0xebf8fc64, 0x06b2465b, 0xfed30ac5, 0xff75f153, 0x0095800c, 0xffc04d0f, 0x000b8760,
- 0x41523389, 0xebeaebaf, 0x06d3c8bb, 0xfeba0199, 0xff831148, 0x00908034, 0xffc19996, 0x000b5235,
- 0x405c1f43, 0xebdf6500, 0x06f41de3, 0xfea16960, 0xff90145e, 0x008b821b, 0xffc2e832, 0x000b1c64,
- 0x3f64fb40, 0xebd6617b, 0x0713453d, 0xfe8943dc, 0xff9cf947, 0x0086866b, 0xffc438a3, 0x000ae5fc,
- 0x3e6cd85b, 0xebcfda19, 0x07313e56, 0xfe7192bd, 0xffa9bebe, 0x00818dcb, 0xffc58aaa, 0x000aaf0f,
- 0x3d73c772, 0xebcbc7a7, 0x074e08e0, 0xfe5a579d, 0xffb66386, 0x007c98de, 0xffc6de09, 0x000a77ac,
- 0x3c79d968, 0xebca22cc, 0x0769a4b2, 0xfe439407, 0xffc2e669, 0x0077a845, 0xffc83285, 0x000a3fe5,
- 0x3b7f1f23, 0xebcae405, 0x078411c7, 0xfe2d496f, 0xffcf463a, 0x0072bc9d, 0xffc987e0, 0x000a07c9,
- 0x3a83a989, 0xebce03aa, 0x079d503b, 0xfe177937, 0xffdb81d6, 0x006dd680, 0xffcadde1, 0x0009cf67,
- 0x3987897f, 0xebd379eb, 0x07b56051, 0xfe0224b0, 0xffe79820, 0x0068f687, 0xffcc344c, 0x000996ce,
- 0x388acfe9, 0xebdb3ed5, 0x07cc426c, 0xfded4d13, 0xfff38806, 0x00641d44, 0xffcd8aeb, 0x00095e0e,
- 0x378d8da8, 0xebe54a4f, 0x07e1f712, 0xfdd8f38b, 0xffff507b, 0x005f4b4a, 0xffcee183, 0x00092535,
- 0x368fd397, 0xebf1941f, 0x07f67eec, 0xfdc5192d, 0x000af07f, 0x005a8125, 0xffd037e0, 0x0008ec50,
- 0x3591b28b, 0xec0013e8, 0x0809dac3, 0xfdb1befc, 0x00166718, 0x0055bf60, 0xffd18dcc, 0x0008b36e,
- 0x34933b50, 0xec10c12c, 0x081c0b84, 0xfd9ee5e7, 0x0021b355, 0x00510682, 0xffd2e311, 0x00087a9c,
- 0x33947eab, 0xec23934f, 0x082d1239, 0xfd8c8ecc, 0x002cd44d, 0x004c570f, 0xffd4377d, 0x000841e8,
- 0x32958d55, 0xec388194, 0x083cf010, 0xfd7aba74, 0x0037c922, 0x0047b186, 0xffd58ade, 0x0008095d,
- 0x319677fa, 0xec4f8322, 0x084ba654, 0xfd696998, 0x004290fc, 0x00431666, 0xffd6dd02, 0x0007d108,
- 0x30974f3b, 0xec688f02, 0x08593671, 0xfd589cdc, 0x004d2b0e, 0x003e8628, 0xffd82dba, 0x000798f5,
- 0x2f9823a8, 0xec839c22, 0x0865a1f1, 0xfd4854d3, 0x00579691, 0x003a0141, 0xffd97cd6, 0x00076130,
- 0x2e9905c1, 0xeca0a156, 0x0870ea7e, 0xfd3891fd, 0x0061d2ca, 0x00358824, 0xffdaca2a, 0x000729c4,
- 0x2d9a05f4, 0xecbf9558, 0x087b11de, 0xfd2954c8, 0x006bdf05, 0x00311b41, 0xffdc1588, 0x0006f2bb,
- 0x2c9b349e, 0xece06ecb, 0x088419f6, 0xfd1a9d91, 0x0075ba95, 0x002cbb03, 0xffdd5ec6, 0x0006bc21,
- 0x2b9ca203, 0xed032439, 0x088c04c8, 0xfd0c6ca2, 0x007f64da, 0x002867d2, 0xffdea5bb, 0x000685ff,
- 0x2a9e5e57, 0xed27ac16, 0x0892d470, 0xfcfec233, 0x0088dd38, 0x00242213, 0xffdfea3c, 0x0006505f,
- 0x29a079b2, 0xed4dfcc2, 0x08988b2a, 0xfcf19e6b, 0x0092231e, 0x001fea27, 0xffe12c22, 0x00061b4b,
- 0x28a30416, 0xed760c88, 0x089d2b4a, 0xfce50161, 0x009b3605, 0x001bc06b, 0xffe26b48, 0x0005e6cb,
- 0x27a60d6a, 0xed9fd1a2, 0x08a0b740, 0xfcd8eb17, 0x00a4156b, 0x0017a53b, 0xffe3a788, 0x0005b2e8,
- 0x26a9a57b, 0xedcb4237, 0x08a33196, 0xfccd5b82, 0x00acc0da, 0x001398ec, 0xffe4e0bf, 0x00057faa,
- 0x25addbf9, 0xedf8545b, 0x08a49cf0, 0xfcc25285, 0x00b537e1, 0x000f9bd2, 0xffe616c8, 0x00054d1a,
- 0x24b2c075, 0xee26fe17, 0x08a4fc0d, 0xfcb7cff0, 0x00bd7a1c, 0x000bae3c, 0xffe74984, 0x00051b3e,
- 0x23b86263, 0xee573562, 0x08a451c0, 0xfcadd386, 0x00c5872a, 0x0007d075, 0xffe878d3, 0x0004ea1d,
- 0x22bed116, 0xee88f026, 0x08a2a0f8, 0xfca45cf7, 0x00cd5eb7, 0x000402c8, 0xffe9a494, 0x0004b9c0,
- 0x21c61bc0, 0xeebc2444, 0x089fecbb, 0xfc9b6be5, 0x00d50075, 0x00004579, 0xffeaccaa, 0x00048a2b,
- 0x20ce516f, 0xeef0c78d, 0x089c3824, 0xfc92ffe1, 0x00dc6c1e, 0xfffc98c9, 0xffebf0fa, 0x00045b65,
- 0x1fd7810f, 0xef26cfca, 0x08978666, 0xfc8b186d, 0x00e3a175, 0xfff8fcf7, 0xffed1166, 0x00042d74,
- 0x1ee1b965, 0xef5e32bd, 0x0891dac8, 0xfc83b4fc, 0x00eaa045, 0xfff5723d, 0xffee2dd7, 0x0004005e,
- 0x1ded0911, 0xef96e61c, 0x088b38a9, 0xfc7cd4f0, 0x00f16861, 0xfff1f8d2, 0xffef4632, 0x0003d426,
- 0x1cf97e8b, 0xefd0df9a, 0x0883a378, 0xfc76779e, 0x00f7f9a3, 0xffee90eb, 0xfff05a60, 0x0003a8d2,
- 0x1c072823, 0xf00c14e1, 0x087b1ebc, 0xfc709c4d, 0x00fe53ef, 0xffeb3ab8, 0xfff16a4a, 0x00037e65,
- 0x1b1613ff, 0xf0487b98, 0x0871ae0d, 0xfc6b4233, 0x0104772e, 0xffe7f666, 0xfff275db, 0x000354e5,
- 0x1a26501b, 0xf0860962, 0x08675516, 0xfc66687a, 0x010a6353, 0xffe4c41e, 0xfff37d00, 0x00032c54,
- 0x1937ea47, 0xf0c4b3e0, 0x085c1794, 0xfc620e3d, 0x01101858, 0xffe1a408, 0xfff47fa5, 0x000304b7,
- 0x184af025, 0xf10470b0, 0x084ff957, 0xfc5e328c, 0x0115963d, 0xffde9646, 0xfff57db8, 0x0002de0e,
- 0x175f6f2b, 0xf1453571, 0x0842fe3d, 0xfc5ad465, 0x011add0b, 0xffdb9af8, 0xfff67729, 0x0002b85f,
- 0x1675749e, 0xf186f7c0, 0x08352a35, 0xfc57f2be, 0x011fecd3, 0xffd8b23b, 0xfff76be9, 0x000293aa,
- 0x158d0d95, 0xf1c9ad40, 0x0826813e, 0xfc558c7c, 0x0124c5ab, 0xffd5dc28, 0xfff85be8, 0x00026ff2,
- 0x14a646f6, 0xf20d4b92, 0x08170767, 0xfc53a07b, 0x012967b1, 0xffd318d6, 0xfff9471b, 0x00024d39,
- 0x13c12d73, 0xf251c85d, 0x0806c0cb, 0xfc522d88, 0x012dd30a, 0xffd06858, 0xfffa2d74, 0x00022b7f,
- 0x12ddcd8f, 0xf297194d, 0x07f5b193, 0xfc513266, 0x013207e4, 0xffcdcabe, 0xfffb0ee9, 0x00020ac7,
- 0x11fc3395, 0xf2dd3411, 0x07e3ddf7, 0xfc50adcc, 0x01360670, 0xffcb4014, 0xfffbeb70, 0x0001eb10,
- 0x111c6ba0, 0xf3240e61, 0x07d14a38, 0xfc509e64, 0x0139cee9, 0xffc8c866, 0xfffcc300, 0x0001cc5c,
+#include "AudioResamplerSincUp.h"
};
/*
@@ -194,135 +69,7 @@
* cmd-line: fir -l 7 -s 48000 -c 17189
*/
const uint32_t AudioResamplerSinc::mFirCoefsDown[] __attribute__ ((aligned (32))) = {
- 0x5bacb6f4, 0x1ded1a1d, 0xf0398d56, 0x0394f674, 0x0193a5f9, 0xfe66dbeb, 0x00791043, 0xfffe6631,
- 0x5bab6c81, 0x1d3ddccd, 0xf0421d2c, 0x03af9995, 0x01818dc9, 0xfe6bb63e, 0x0079812a, 0xfffdc37d,
- 0x5ba78d37, 0x1c8f2cf9, 0xf04beb1d, 0x03c9a04a, 0x016f8aca, 0xfe70a511, 0x0079e34d, 0xfffd2545,
- 0x5ba1194f, 0x1be11231, 0xf056f2c7, 0x03e309fe, 0x015d9e64, 0xfe75a79f, 0x007a36e2, 0xfffc8b86,
- 0x5b981122, 0x1b3393f8, 0xf0632fb7, 0x03fbd625, 0x014bc9fa, 0xfe7abd23, 0x007a7c20, 0xfffbf639,
- 0x5b8c7530, 0x1a86b9bf, 0xf0709d74, 0x04140449, 0x013a0ee9, 0xfe7fe4db, 0x007ab33d, 0xfffb655b,
- 0x5b7e461a, 0x19da8ae5, 0xf07f3776, 0x042b93fd, 0x01286e86, 0xfe851e05, 0x007adc72, 0xfffad8e4,
- 0x5b6d84a8, 0x192f0eb7, 0xf08ef92d, 0x044284e6, 0x0116ea22, 0xfe8a67dd, 0x007af7f6, 0xfffa50ce,
- 0x5b5a31c6, 0x18844c70, 0xf09fddfe, 0x0458d6b7, 0x01058306, 0xfe8fc1a5, 0x007b0603, 0xfff9cd12,
- 0x5b444e81, 0x17da4b37, 0xf0b1e143, 0x046e8933, 0x00f43a74, 0xfe952a9b, 0x007b06d4, 0xfff94da9,
- 0x5b2bdc0e, 0x17311222, 0xf0c4fe50, 0x04839c29, 0x00e311a9, 0xfe9aa201, 0x007afaa1, 0xfff8d28c,
- 0x5b10dbc2, 0x1688a832, 0xf0d9306d, 0x04980f79, 0x00d209db, 0xfea02719, 0x007ae1a7, 0xfff85bb1,
- 0x5af34f18, 0x15e11453, 0xf0ee72db, 0x04abe310, 0x00c12439, 0xfea5b926, 0x007abc20, 0xfff7e910,
- 0x5ad337af, 0x153a5d5e, 0xf104c0d2, 0x04bf16e9, 0x00b061eb, 0xfeab576d, 0x007a8a49, 0xfff77a9f,
- 0x5ab09748, 0x14948a16, 0xf11c1583, 0x04d1ab0d, 0x009fc413, 0xfeb10134, 0x007a4c5d, 0xfff71057,
- 0x5a8b6fc7, 0x13efa12c, 0xf1346c17, 0x04e39f93, 0x008f4bcb, 0xfeb6b5c0, 0x007a029a, 0xfff6aa2b,
- 0x5a63c336, 0x134ba937, 0xf14dbfb1, 0x04f4f4a2, 0x007efa29, 0xfebc745c, 0x0079ad3d, 0xfff64812,
- 0x5a3993c0, 0x12a8a8bb, 0xf1680b6e, 0x0505aa6a, 0x006ed038, 0xfec23c50, 0x00794c82, 0xfff5ea02,
- 0x5a0ce3b2, 0x1206a625, 0xf1834a63, 0x0515c12d, 0x005ecf01, 0xfec80ce8, 0x0078e0a9, 0xfff58ff0,
- 0x59ddb57f, 0x1165a7cc, 0xf19f77a0, 0x05253938, 0x004ef782, 0xfecde571, 0x007869ee, 0xfff539cf,
- 0x59ac0bba, 0x10c5b3ef, 0xf1bc8e31, 0x053412e4, 0x003f4ab4, 0xfed3c538, 0x0077e891, 0xfff4e794,
- 0x5977e919, 0x1026d0b8, 0xf1da891b, 0x05424e9b, 0x002fc98a, 0xfed9ab8f, 0x00775ccf, 0xfff49934,
- 0x59415075, 0x0f890437, 0xf1f96360, 0x054feccf, 0x002074ed, 0xfedf97c6, 0x0076c6e8, 0xfff44ea3,
- 0x590844c9, 0x0eec5465, 0xf21917ff, 0x055cee03, 0x00114dc3, 0xfee58932, 0x00762719, 0xfff407d2,
- 0x58ccc930, 0x0e50c723, 0xf239a1ef, 0x056952c3, 0x000254e8, 0xfeeb7f27, 0x00757da3, 0xfff3c4b7,
- 0x588ee0ea, 0x0db6623b, 0xf25afc29, 0x05751baa, 0xfff38b32, 0xfef178fc, 0x0074cac4, 0xfff38542,
- 0x584e8f56, 0x0d1d2b5d, 0xf27d219f, 0x0580495c, 0xffe4f171, 0xfef7760c, 0x00740ebb, 0xfff34968,
- 0x580bd7f4, 0x0c85281f, 0xf2a00d43, 0x058adc8d, 0xffd6886d, 0xfefd75af, 0x007349c7, 0xfff3111b,
- 0x57c6be67, 0x0bee5dff, 0xf2c3ba04, 0x0594d5fa, 0xffc850e6, 0xff037744, 0x00727c27, 0xfff2dc4c,
- 0x577f4670, 0x0b58d262, 0xf2e822ce, 0x059e366c, 0xffba4b98, 0xff097a29, 0x0071a61b, 0xfff2aaef,
- 0x573573f2, 0x0ac48a92, 0xf30d428e, 0x05a6feb9, 0xffac7936, 0xff0f7dbf, 0x0070c7e1, 0xfff27cf3,
- 0x56e94af1, 0x0a318bc1, 0xf333142f, 0x05af2fbf, 0xff9eda6d, 0xff15816a, 0x006fe1b8, 0xfff2524c,
- 0x569acf90, 0x099fdb04, 0xf359929a, 0x05b6ca6b, 0xff916fe1, 0xff1b848e, 0x006ef3df, 0xfff22aea,
- 0x564a0610, 0x090f7d57, 0xf380b8ba, 0x05bdcfb2, 0xff843a32, 0xff218692, 0x006dfe94, 0xfff206bf,
- 0x55f6f2d3, 0x0880779d, 0xf3a88179, 0x05c44095, 0xff7739f7, 0xff2786e1, 0x006d0217, 0xfff1e5bb,
- 0x55a19a5c, 0x07f2ce9b, 0xf3d0e7c2, 0x05ca1e1f, 0xff6a6fc1, 0xff2d84e5, 0x006bfea4, 0xfff1c7d0,
- 0x554a0148, 0x076686fc, 0xf3f9e680, 0x05cf6965, 0xff5ddc1a, 0xff33800e, 0x006af47b, 0xfff1acef,
- 0x54f02c56, 0x06dba551, 0xf42378a0, 0x05d42387, 0xff517f86, 0xff3977cb, 0x0069e3d9, 0xfff19508,
- 0x54942061, 0x06522e0f, 0xf44d9912, 0x05d84daf, 0xff455a80, 0xff3f6b8f, 0x0068ccfa, 0xfff1800b,
- 0x5435e263, 0x05ca258f, 0xf47842c5, 0x05dbe90f, 0xff396d7f, 0xff455acf, 0x0067b01e, 0xfff16de9,
- 0x53d57774, 0x0543900d, 0xf4a370ad, 0x05def6e4, 0xff2db8f2, 0xff4b4503, 0x00668d80, 0xfff15e93,
- 0x5372e4c6, 0x04be71ab, 0xf4cf1dbf, 0x05e17873, 0xff223d40, 0xff5129a3, 0x0065655d, 0xfff151f9,
- 0x530e2fac, 0x043ace6e, 0xf4fb44f4, 0x05e36f0d, 0xff16faca, 0xff57082e, 0x006437f1, 0xfff1480b,
- 0x52a75d90, 0x03b8aa40, 0xf527e149, 0x05e4dc08, 0xff0bf1ed, 0xff5ce021, 0x00630577, 0xfff140b9,
- 0x523e73fd, 0x033808eb, 0xf554edbd, 0x05e5c0c6, 0xff0122fc, 0xff62b0fd, 0x0061ce2c, 0xfff13bf3,
- 0x51d37897, 0x02b8ee22, 0xf5826555, 0x05e61eae, 0xfef68e45, 0xff687a47, 0x00609249, 0xfff139aa,
- 0x5166711c, 0x023b5d76, 0xf5b0431a, 0x05e5f733, 0xfeec340f, 0xff6e3b84, 0x005f520a, 0xfff139cd,
- 0x50f76368, 0x01bf5a5e, 0xf5de8218, 0x05e54bcd, 0xfee2149b, 0xff73f43d, 0x005e0da8, 0xfff13c4c,
- 0x5086556f, 0x0144e834, 0xf60d1d63, 0x05e41dfe, 0xfed83023, 0xff79a3fe, 0x005cc55c, 0xfff14119,
- 0x50134d3e, 0x00cc0a36, 0xf63c1012, 0x05e26f4e, 0xfece86db, 0xff7f4a54, 0x005b7961, 0xfff14821,
- 0x4f9e50ff, 0x0054c382, 0xf66b5544, 0x05e0414d, 0xfec518f1, 0xff84e6d0, 0x005a29ed, 0xfff15156,
- 0x4f2766f2, 0xffdf171b, 0xf69ae81d, 0x05dd9593, 0xfebbe68c, 0xff8a7905, 0x0058d738, 0xfff15ca8,
- 0x4eae9571, 0xff6b07e7, 0xf6cac3c7, 0x05da6dbe, 0xfeb2efcd, 0xff900089, 0x0057817b, 0xfff16a07,
- 0x4e33e2ee, 0xfef898ae, 0xf6fae373, 0x05d6cb72, 0xfeaa34d0, 0xff957cf4, 0x005628ec, 0xfff17962,
- 0x4db755f3, 0xfe87cc1b, 0xf72b425b, 0x05d2b05c, 0xfea1b5a9, 0xff9aede0, 0x0054cdc0, 0xfff18aab,
- 0x4d38f520, 0xfe18a4bc, 0xf75bdbbd, 0x05ce1e2d, 0xfe997268, 0xffa052ec, 0x0053702d, 0xfff19dd1,
- 0x4cb8c72e, 0xfdab2501, 0xf78caae0, 0x05c9169d, 0xfe916b15, 0xffa5abb8, 0x00521068, 0xfff1b2c5,
- 0x4c36d2eb, 0xfd3f4f3d, 0xf7bdab16, 0x05c39b6a, 0xfe899fb2, 0xffaaf7e6, 0x0050aea5, 0xfff1c976,
- 0x4bb31f3c, 0xfcd525a5, 0xf7eed7b4, 0x05bdae57, 0xfe82103f, 0xffb0371c, 0x004f4b17, 0xfff1e1d6,
- 0x4b2db31a, 0xfc6caa53, 0xf8202c1c, 0x05b7512e, 0xfe7abcb1, 0xffb56902, 0x004de5f1, 0xfff1fbd5,
- 0x4aa69594, 0xfc05df40, 0xf851a3b6, 0x05b085bc, 0xfe73a4fb, 0xffba8d44, 0x004c7f66, 0xfff21764,
- 0x4a1dcdce, 0xfba0c64b, 0xf88339f5, 0x05a94dd5, 0xfe6cc909, 0xffbfa38d, 0x004b17a6, 0xfff23473,
- 0x499362ff, 0xfb3d6133, 0xf8b4ea55, 0x05a1ab52, 0xfe6628c1, 0xffc4ab8f, 0x0049aee3, 0xfff252f3,
- 0x49075c72, 0xfadbb19a, 0xf8e6b059, 0x0599a00e, 0xfe5fc405, 0xffc9a4fc, 0x0048454b, 0xfff272d6,
- 0x4879c185, 0xfa7bb908, 0xf9188793, 0x05912dea, 0xfe599aaf, 0xffce8f8a, 0x0046db0f, 0xfff2940b,
- 0x47ea99a9, 0xfa1d78e3, 0xf94a6b9b, 0x058856cd, 0xfe53ac97, 0xffd36af1, 0x0045705c, 0xfff2b686,
- 0x4759ec60, 0xf9c0f276, 0xf97c5815, 0x057f1c9e, 0xfe4df98e, 0xffd836eb, 0x00440561, 0xfff2da36,
- 0x46c7c140, 0xf96626f0, 0xf9ae48af, 0x0575814c, 0xfe48815e, 0xffdcf336, 0x00429a4a, 0xfff2ff0d,
- 0x46341fed, 0xf90d1761, 0xf9e03924, 0x056b86c6, 0xfe4343d0, 0xffe19f91, 0x00412f43, 0xfff324fd,
- 0x459f101d, 0xf8b5c4be, 0xfa122537, 0x05612f00, 0xfe3e40a6, 0xffe63bc0, 0x003fc478, 0xfff34bf9,
- 0x45089996, 0xf8602fdc, 0xfa4408ba, 0x05567bf1, 0xfe39779a, 0xffeac787, 0x003e5a12, 0xfff373f0,
- 0x4470c42d, 0xf80c5977, 0xfa75df87, 0x054b6f92, 0xfe34e867, 0xffef42af, 0x003cf03d, 0xfff39cd7,
- 0x43d797c7, 0xf7ba422b, 0xfaa7a586, 0x05400be1, 0xfe3092bf, 0xfff3ad01, 0x003b871f, 0xfff3c69f,
- 0x433d1c56, 0xf769ea78, 0xfad956ab, 0x053452dc, 0xfe2c7650, 0xfff8064b, 0x003a1ee3, 0xfff3f13a,
- 0x42a159dc, 0xf71b52c4, 0xfb0aeef6, 0x05284685, 0xfe2892c5, 0xfffc4e5c, 0x0038b7ae, 0xfff41c9c,
- 0x42045865, 0xf6ce7b57, 0xfb3c6a73, 0x051be8dd, 0xfe24e7c3, 0x00008507, 0x003751a7, 0xfff448b7,
- 0x4166200e, 0xf683645a, 0xfb6dc53c, 0x050f3bec, 0xfe2174ec, 0x0004aa1f, 0x0035ecf4, 0xfff4757e,
- 0x40c6b8fd, 0xf63a0ddf, 0xfb9efb77, 0x050241b6, 0xfe1e39da, 0x0008bd7c, 0x003489b9, 0xfff4a2e5,
- 0x40262b65, 0xf5f277d9, 0xfbd00956, 0x04f4fc46, 0xfe1b3628, 0x000cbef7, 0x0033281a, 0xfff4d0de,
- 0x3f847f83, 0xf5aca21f, 0xfc00eb1b, 0x04e76da3, 0xfe18696a, 0x0010ae6e, 0x0031c83a, 0xfff4ff5d,
- 0x3ee1bda2, 0xf5688c6d, 0xfc319d13, 0x04d997d8, 0xfe15d32f, 0x00148bbd, 0x00306a3b, 0xfff52e57,
- 0x3e3dee13, 0xf5263665, 0xfc621b9a, 0x04cb7cf2, 0xfe137304, 0x001856c7, 0x002f0e3f, 0xfff55dbf,
- 0x3d991932, 0xf4e59f8a, 0xfc926319, 0x04bd1efb, 0xfe114872, 0x001c0f6e, 0x002db466, 0xfff58d89,
- 0x3cf34766, 0xf4a6c748, 0xfcc27008, 0x04ae8000, 0xfe0f52fc, 0x001fb599, 0x002c5cd0, 0xfff5bdaa,
- 0x3c4c811c, 0xf469aced, 0xfcf23eec, 0x049fa20f, 0xfe0d9224, 0x0023492f, 0x002b079a, 0xfff5ee17,
- 0x3ba4cec9, 0xf42e4faf, 0xfd21cc59, 0x04908733, 0xfe0c0567, 0x0026ca1c, 0x0029b4e4, 0xfff61ec5,
- 0x3afc38eb, 0xf3f4aea6, 0xfd5114f0, 0x0481317a, 0xfe0aac3f, 0x002a384c, 0x002864c9, 0xfff64fa8,
- 0x3a52c805, 0xf3bcc8d3, 0xfd801564, 0x0471a2ef, 0xfe098622, 0x002d93ae, 0x00271766, 0xfff680b5,
- 0x39a884a1, 0xf3869d1a, 0xfdaeca73, 0x0461dda0, 0xfe089283, 0x0030dc34, 0x0025ccd7, 0xfff6b1e4,
- 0x38fd774e, 0xf3522a49, 0xfddd30eb, 0x0451e396, 0xfe07d0d3, 0x003411d2, 0x00248535, 0xfff6e329,
- 0x3851a8a2, 0xf31f6f0f, 0xfe0b45aa, 0x0441b6dd, 0xfe07407d, 0x0037347d, 0x0023409a, 0xfff7147a,
- 0x37a52135, 0xf2ee6a07, 0xfe39059b, 0x0431597d, 0xfe06e0eb, 0x003a442e, 0x0021ff1f, 0xfff745cd,
- 0x36f7e9a4, 0xf2bf19ae, 0xfe666dbc, 0x0420cd80, 0xfe06b184, 0x003d40e0, 0x0020c0dc, 0xfff7771a,
- 0x364a0a90, 0xf2917c6d, 0xfe937b15, 0x041014eb, 0xfe06b1ac, 0x00402a8e, 0x001f85e6, 0xfff7a857,
- 0x359b8c9d, 0xf265908f, 0xfec02ac2, 0x03ff31c3, 0xfe06e0c4, 0x00430137, 0x001e4e56, 0xfff7d97a,
- 0x34ec786f, 0xf23b544b, 0xfeec79ec, 0x03ee260d, 0xfe073e2a, 0x0045c4dd, 0x001d1a3f, 0xfff80a7c,
- 0x343cd6af, 0xf212c5be, 0xff1865cd, 0x03dcf3ca, 0xfe07c93a, 0x00487582, 0x001be9b7, 0xfff83b52,
- 0x338cb004, 0xf1ebe2ec, 0xff43ebac, 0x03cb9cf9, 0xfe08814e, 0x004b132b, 0x001abcd0, 0xfff86bf6,
- 0x32dc0d17, 0xf1c6a9c3, 0xff6f08e4, 0x03ba2398, 0xfe0965bc, 0x004d9dde, 0x0019939d, 0xfff89c60,
- 0x322af693, 0xf1a3181a, 0xff99badb, 0x03a889a1, 0xfe0a75da, 0x005015a5, 0x00186e31, 0xfff8cc86,
- 0x3179751f, 0xf1812bb0, 0xffc3ff0c, 0x0396d10c, 0xfe0bb0f9, 0x00527a8a, 0x00174c9c, 0xfff8fc62,
- 0x30c79163, 0xf160e22d, 0xffedd2fd, 0x0384fbd1, 0xfe0d166b, 0x0054cc9a, 0x00162eef, 0xfff92bec,
- 0x30155404, 0xf1423924, 0x00173447, 0x03730be0, 0xfe0ea57e, 0x00570be4, 0x00151538, 0xfff95b1e,
- 0x2f62c5a7, 0xf1252e0f, 0x00402092, 0x0361032a, 0xfe105d7e, 0x00593877, 0x0013ff88, 0xfff989ef,
- 0x2eafeeed, 0xf109be56, 0x00689598, 0x034ee39b, 0xfe123db6, 0x005b5267, 0x0012edea, 0xfff9b85b,
- 0x2dfcd873, 0xf0efe748, 0x0090911f, 0x033caf1d, 0xfe144570, 0x005d59c6, 0x0011e06d, 0xfff9e65a,
- 0x2d498ad3, 0xf0d7a622, 0x00b81102, 0x032a6796, 0xfe1673f2, 0x005f4eac, 0x0010d71d, 0xfffa13e5,
- 0x2c960ea3, 0xf0c0f808, 0x00df1328, 0x03180ee7, 0xfe18c884, 0x0061312e, 0x000fd205, 0xfffa40f8,
- 0x2be26c73, 0xf0abda0e, 0x0105958c, 0x0305a6f0, 0xfe1b4268, 0x00630167, 0x000ed130, 0xfffa6d8d,
- 0x2b2eaccf, 0xf0984931, 0x012b9635, 0x02f3318a, 0xfe1de0e2, 0x0064bf71, 0x000dd4a7, 0xfffa999d,
- 0x2a7ad83c, 0xf086425a, 0x0151133e, 0x02e0b08d, 0xfe20a335, 0x00666b68, 0x000cdc74, 0xfffac525,
- 0x29c6f738, 0xf075c260, 0x01760ad1, 0x02ce25ca, 0xfe2388a1, 0x0068056b, 0x000be89f, 0xfffaf01e,
- 0x2913123c, 0xf066c606, 0x019a7b27, 0x02bb9310, 0xfe269065, 0x00698d98, 0x000af931, 0xfffb1a84,
- 0x285f31b7, 0xf05949fb, 0x01be628c, 0x02a8fa2a, 0xfe29b9c1, 0x006b0411, 0x000a0e2f, 0xfffb4453,
- 0x27ab5e12, 0xf04d4ade, 0x01e1bf58, 0x02965cdb, 0xfe2d03f2, 0x006c68f8, 0x000927a0, 0xfffb6d86,
- 0x26f79fab, 0xf042c539, 0x02048ff8, 0x0283bce6, 0xfe306e35, 0x006dbc71, 0x00084589, 0xfffb961a,
- 0x2643feda, 0xf039b587, 0x0226d2e6, 0x02711c05, 0xfe33f7c7, 0x006efea0, 0x000767f0, 0xfffbbe09,
- 0x259083eb, 0xf032182f, 0x024886ad, 0x025e7bf0, 0xfe379fe3, 0x00702fae, 0x00068ed8, 0xfffbe552,
- 0x24dd3721, 0xf02be98a, 0x0269a9e9, 0x024bde5a, 0xfe3b65c4, 0x00714fc0, 0x0005ba46, 0xfffc0bef,
- 0x242a20b3, 0xf02725dc, 0x028a3b44, 0x023944ee, 0xfe3f48a5, 0x00725f02, 0x0004ea3a, 0xfffc31df,
- 0x237748cf, 0xf023c95d, 0x02aa397b, 0x0226b156, 0xfe4347c0, 0x00735d9c, 0x00041eb9, 0xfffc571e,
- 0x22c4b795, 0xf021d031, 0x02c9a359, 0x02142533, 0xfe476250, 0x00744bba, 0x000357c2, 0xfffc7ba9,
- 0x2212751a, 0xf0213671, 0x02e877b9, 0x0201a223, 0xfe4b978e, 0x0075298a, 0x00029558, 0xfffc9f7e,
- 0x21608968, 0xf021f823, 0x0306b586, 0x01ef29be, 0xfe4fe6b3, 0x0075f739, 0x0001d779, 0xfffcc29a,
- 0x20aefc79, 0xf0241140, 0x03245bbc, 0x01dcbd96, 0xfe544efb, 0x0076b4f5, 0x00011e26, 0xfffce4fc,
- 0x1ffdd63b, 0xf0277db1, 0x03416966, 0x01ca5f37, 0xfe58cf9d, 0x007762f0, 0x0000695e, 0xfffd06a1,
- 0x1f4d1e8e, 0xf02c3953, 0x035ddd9e, 0x01b81028, 0xfe5d67d4, 0x0078015a, 0xffffb91f, 0xfffd2787,
- 0x1e9cdd43, 0xf0323ff5, 0x0379b790, 0x01a5d1ea, 0xfe6216db, 0x00789065, 0xffff0d66, 0xfffd47ae,
- 0x1ded1a1d, 0xf0398d56, 0x0394f674, 0x0193a5f9, 0xfe66dbeb, 0x00791043, 0xfffe6631, 0xfffd6713,
+#include "AudioResamplerSincDown.h"
};
// we use 15 bits to interpolate between these samples
@@ -518,7 +265,8 @@
if (mConstants == &veryHighQualityConstants && readResampleCoefficients) {
mFirCoefs = readResampleCoefficients( mInSampleRate <= mSampleRate );
} else {
- mFirCoefs = (const int32_t *) ((mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown);
+ mFirCoefs = (const int32_t *)
+ ((mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown);
}
// select the appropriate resampler
@@ -853,4 +601,4 @@
}
}
// ----------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
diff --git a/services/audioflinger/AudioResamplerSinc.h b/services/audioflinger/AudioResamplerSinc.h
index 4691d0a..6d8e85d 100644
--- a/services/audioflinger/AudioResamplerSinc.h
+++ b/services/audioflinger/AudioResamplerSinc.h
@@ -95,6 +95,6 @@
};
// ----------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
#endif /*ANDROID_AUDIO_RESAMPLER_SINC_H*/
diff --git a/services/audioflinger/AudioResamplerSincDown.h b/services/audioflinger/AudioResamplerSincDown.h
new file mode 100644
index 0000000..2d0fb86
--- /dev/null
+++ b/services/audioflinger/AudioResamplerSincDown.h
@@ -0,0 +1,131 @@
+// cmd-line: fir -l 7 -s48000 -c 17189
+
+ 0x5bacb6f4, 0x1ded1a1d, 0xf0398d56, 0x0394f674, 0x0193a5f9, 0xfe66dbeb, 0x00791043, 0xfffe6631,
+ 0x5bab6c81, 0x1d3ddccd, 0xf0421d2c, 0x03af9995, 0x01818dc9, 0xfe6bb63e, 0x0079812a, 0xfffdc37d,
+ 0x5ba78d37, 0x1c8f2cf9, 0xf04beb1d, 0x03c9a04a, 0x016f8aca, 0xfe70a511, 0x0079e34d, 0xfffd2545,
+ 0x5ba1194f, 0x1be11231, 0xf056f2c7, 0x03e309fe, 0x015d9e64, 0xfe75a79f, 0x007a36e2, 0xfffc8b86,
+ 0x5b981122, 0x1b3393f8, 0xf0632fb7, 0x03fbd625, 0x014bc9fa, 0xfe7abd23, 0x007a7c20, 0xfffbf639,
+ 0x5b8c7530, 0x1a86b9bf, 0xf0709d74, 0x04140449, 0x013a0ee9, 0xfe7fe4db, 0x007ab33d, 0xfffb655b,
+ 0x5b7e461a, 0x19da8ae5, 0xf07f3776, 0x042b93fd, 0x01286e86, 0xfe851e05, 0x007adc72, 0xfffad8e4,
+ 0x5b6d84a8, 0x192f0eb7, 0xf08ef92d, 0x044284e6, 0x0116ea22, 0xfe8a67dd, 0x007af7f6, 0xfffa50ce,
+ 0x5b5a31c6, 0x18844c70, 0xf09fddfe, 0x0458d6b7, 0x01058306, 0xfe8fc1a5, 0x007b0603, 0xfff9cd12,
+ 0x5b444e81, 0x17da4b37, 0xf0b1e143, 0x046e8933, 0x00f43a74, 0xfe952a9b, 0x007b06d4, 0xfff94da9,
+ 0x5b2bdc0e, 0x17311222, 0xf0c4fe50, 0x04839c29, 0x00e311a9, 0xfe9aa201, 0x007afaa1, 0xfff8d28c,
+ 0x5b10dbc2, 0x1688a832, 0xf0d9306d, 0x04980f79, 0x00d209db, 0xfea02719, 0x007ae1a7, 0xfff85bb1,
+ 0x5af34f18, 0x15e11453, 0xf0ee72db, 0x04abe310, 0x00c12439, 0xfea5b926, 0x007abc20, 0xfff7e910,
+ 0x5ad337af, 0x153a5d5e, 0xf104c0d2, 0x04bf16e9, 0x00b061eb, 0xfeab576d, 0x007a8a49, 0xfff77a9f,
+ 0x5ab09748, 0x14948a16, 0xf11c1583, 0x04d1ab0d, 0x009fc413, 0xfeb10134, 0x007a4c5d, 0xfff71057,
+ 0x5a8b6fc7, 0x13efa12c, 0xf1346c17, 0x04e39f93, 0x008f4bcb, 0xfeb6b5c0, 0x007a029a, 0xfff6aa2b,
+ 0x5a63c336, 0x134ba937, 0xf14dbfb1, 0x04f4f4a2, 0x007efa29, 0xfebc745c, 0x0079ad3d, 0xfff64812,
+ 0x5a3993c0, 0x12a8a8bb, 0xf1680b6e, 0x0505aa6a, 0x006ed038, 0xfec23c50, 0x00794c82, 0xfff5ea02,
+ 0x5a0ce3b2, 0x1206a625, 0xf1834a63, 0x0515c12d, 0x005ecf01, 0xfec80ce8, 0x0078e0a9, 0xfff58ff0,
+ 0x59ddb57f, 0x1165a7cc, 0xf19f77a0, 0x05253938, 0x004ef782, 0xfecde571, 0x007869ee, 0xfff539cf,
+ 0x59ac0bba, 0x10c5b3ef, 0xf1bc8e31, 0x053412e4, 0x003f4ab4, 0xfed3c538, 0x0077e891, 0xfff4e794,
+ 0x5977e919, 0x1026d0b8, 0xf1da891b, 0x05424e9b, 0x002fc98a, 0xfed9ab8f, 0x00775ccf, 0xfff49934,
+ 0x59415075, 0x0f890437, 0xf1f96360, 0x054feccf, 0x002074ed, 0xfedf97c6, 0x0076c6e8, 0xfff44ea3,
+ 0x590844c9, 0x0eec5465, 0xf21917ff, 0x055cee03, 0x00114dc3, 0xfee58932, 0x00762719, 0xfff407d2,
+ 0x58ccc930, 0x0e50c723, 0xf239a1ef, 0x056952c3, 0x000254e8, 0xfeeb7f27, 0x00757da3, 0xfff3c4b7,
+ 0x588ee0ea, 0x0db6623b, 0xf25afc29, 0x05751baa, 0xfff38b32, 0xfef178fc, 0x0074cac4, 0xfff38542,
+ 0x584e8f56, 0x0d1d2b5d, 0xf27d219f, 0x0580495c, 0xffe4f171, 0xfef7760c, 0x00740ebb, 0xfff34968,
+ 0x580bd7f4, 0x0c85281f, 0xf2a00d43, 0x058adc8d, 0xffd6886d, 0xfefd75af, 0x007349c7, 0xfff3111b,
+ 0x57c6be67, 0x0bee5dff, 0xf2c3ba04, 0x0594d5fa, 0xffc850e6, 0xff037744, 0x00727c27, 0xfff2dc4c,
+ 0x577f4670, 0x0b58d262, 0xf2e822ce, 0x059e366c, 0xffba4b98, 0xff097a29, 0x0071a61b, 0xfff2aaef,
+ 0x573573f2, 0x0ac48a92, 0xf30d428e, 0x05a6feb9, 0xffac7936, 0xff0f7dbf, 0x0070c7e1, 0xfff27cf3,
+ 0x56e94af1, 0x0a318bc1, 0xf333142f, 0x05af2fbf, 0xff9eda6d, 0xff15816a, 0x006fe1b8, 0xfff2524c,
+ 0x569acf90, 0x099fdb04, 0xf359929a, 0x05b6ca6b, 0xff916fe1, 0xff1b848e, 0x006ef3df, 0xfff22aea,
+ 0x564a0610, 0x090f7d57, 0xf380b8ba, 0x05bdcfb2, 0xff843a32, 0xff218692, 0x006dfe94, 0xfff206bf,
+ 0x55f6f2d3, 0x0880779d, 0xf3a88179, 0x05c44095, 0xff7739f7, 0xff2786e1, 0x006d0217, 0xfff1e5bb,
+ 0x55a19a5c, 0x07f2ce9b, 0xf3d0e7c2, 0x05ca1e1f, 0xff6a6fc1, 0xff2d84e5, 0x006bfea4, 0xfff1c7d0,
+ 0x554a0148, 0x076686fc, 0xf3f9e680, 0x05cf6965, 0xff5ddc1a, 0xff33800e, 0x006af47b, 0xfff1acef,
+ 0x54f02c56, 0x06dba551, 0xf42378a0, 0x05d42387, 0xff517f86, 0xff3977cb, 0x0069e3d9, 0xfff19508,
+ 0x54942061, 0x06522e0f, 0xf44d9912, 0x05d84daf, 0xff455a80, 0xff3f6b8f, 0x0068ccfa, 0xfff1800b,
+ 0x5435e263, 0x05ca258f, 0xf47842c5, 0x05dbe90f, 0xff396d7f, 0xff455acf, 0x0067b01e, 0xfff16de9,
+ 0x53d57774, 0x0543900d, 0xf4a370ad, 0x05def6e4, 0xff2db8f2, 0xff4b4503, 0x00668d80, 0xfff15e93,
+ 0x5372e4c6, 0x04be71ab, 0xf4cf1dbf, 0x05e17873, 0xff223d40, 0xff5129a3, 0x0065655d, 0xfff151f9,
+ 0x530e2fac, 0x043ace6e, 0xf4fb44f4, 0x05e36f0d, 0xff16faca, 0xff57082e, 0x006437f1, 0xfff1480b,
+ 0x52a75d90, 0x03b8aa40, 0xf527e149, 0x05e4dc08, 0xff0bf1ed, 0xff5ce021, 0x00630577, 0xfff140b9,
+ 0x523e73fd, 0x033808eb, 0xf554edbd, 0x05e5c0c6, 0xff0122fc, 0xff62b0fd, 0x0061ce2c, 0xfff13bf3,
+ 0x51d37897, 0x02b8ee22, 0xf5826555, 0x05e61eae, 0xfef68e45, 0xff687a47, 0x00609249, 0xfff139aa,
+ 0x5166711c, 0x023b5d76, 0xf5b0431a, 0x05e5f733, 0xfeec340f, 0xff6e3b84, 0x005f520a, 0xfff139cd,
+ 0x50f76368, 0x01bf5a5e, 0xf5de8218, 0x05e54bcd, 0xfee2149b, 0xff73f43d, 0x005e0da8, 0xfff13c4c,
+ 0x5086556f, 0x0144e834, 0xf60d1d63, 0x05e41dfe, 0xfed83023, 0xff79a3fe, 0x005cc55c, 0xfff14119,
+ 0x50134d3e, 0x00cc0a36, 0xf63c1012, 0x05e26f4e, 0xfece86db, 0xff7f4a54, 0x005b7961, 0xfff14821,
+ 0x4f9e50ff, 0x0054c382, 0xf66b5544, 0x05e0414d, 0xfec518f1, 0xff84e6d0, 0x005a29ed, 0xfff15156,
+ 0x4f2766f2, 0xffdf171b, 0xf69ae81d, 0x05dd9593, 0xfebbe68c, 0xff8a7905, 0x0058d738, 0xfff15ca8,
+ 0x4eae9571, 0xff6b07e7, 0xf6cac3c7, 0x05da6dbe, 0xfeb2efcd, 0xff900089, 0x0057817b, 0xfff16a07,
+ 0x4e33e2ee, 0xfef898ae, 0xf6fae373, 0x05d6cb72, 0xfeaa34d0, 0xff957cf4, 0x005628ec, 0xfff17962,
+ 0x4db755f3, 0xfe87cc1b, 0xf72b425b, 0x05d2b05c, 0xfea1b5a9, 0xff9aede0, 0x0054cdc0, 0xfff18aab,
+ 0x4d38f520, 0xfe18a4bc, 0xf75bdbbd, 0x05ce1e2d, 0xfe997268, 0xffa052ec, 0x0053702d, 0xfff19dd1,
+ 0x4cb8c72e, 0xfdab2501, 0xf78caae0, 0x05c9169d, 0xfe916b15, 0xffa5abb8, 0x00521068, 0xfff1b2c5,
+ 0x4c36d2eb, 0xfd3f4f3d, 0xf7bdab16, 0x05c39b6a, 0xfe899fb2, 0xffaaf7e6, 0x0050aea5, 0xfff1c976,
+ 0x4bb31f3c, 0xfcd525a5, 0xf7eed7b4, 0x05bdae57, 0xfe82103f, 0xffb0371c, 0x004f4b17, 0xfff1e1d6,
+ 0x4b2db31a, 0xfc6caa53, 0xf8202c1c, 0x05b7512e, 0xfe7abcb1, 0xffb56902, 0x004de5f1, 0xfff1fbd5,
+ 0x4aa69594, 0xfc05df40, 0xf851a3b6, 0x05b085bc, 0xfe73a4fb, 0xffba8d44, 0x004c7f66, 0xfff21764,
+ 0x4a1dcdce, 0xfba0c64b, 0xf88339f5, 0x05a94dd5, 0xfe6cc909, 0xffbfa38d, 0x004b17a6, 0xfff23473,
+ 0x499362ff, 0xfb3d6133, 0xf8b4ea55, 0x05a1ab52, 0xfe6628c1, 0xffc4ab8f, 0x0049aee3, 0xfff252f3,
+ 0x49075c72, 0xfadbb19a, 0xf8e6b059, 0x0599a00e, 0xfe5fc405, 0xffc9a4fc, 0x0048454b, 0xfff272d6,
+ 0x4879c185, 0xfa7bb908, 0xf9188793, 0x05912dea, 0xfe599aaf, 0xffce8f8a, 0x0046db0f, 0xfff2940b,
+ 0x47ea99a9, 0xfa1d78e3, 0xf94a6b9b, 0x058856cd, 0xfe53ac97, 0xffd36af1, 0x0045705c, 0xfff2b686,
+ 0x4759ec60, 0xf9c0f276, 0xf97c5815, 0x057f1c9e, 0xfe4df98e, 0xffd836eb, 0x00440561, 0xfff2da36,
+ 0x46c7c140, 0xf96626f0, 0xf9ae48af, 0x0575814c, 0xfe48815e, 0xffdcf336, 0x00429a4a, 0xfff2ff0d,
+ 0x46341fed, 0xf90d1761, 0xf9e03924, 0x056b86c6, 0xfe4343d0, 0xffe19f91, 0x00412f43, 0xfff324fd,
+ 0x459f101d, 0xf8b5c4be, 0xfa122537, 0x05612f00, 0xfe3e40a6, 0xffe63bc0, 0x003fc478, 0xfff34bf9,
+ 0x45089996, 0xf8602fdc, 0xfa4408ba, 0x05567bf1, 0xfe39779a, 0xffeac787, 0x003e5a12, 0xfff373f0,
+ 0x4470c42d, 0xf80c5977, 0xfa75df87, 0x054b6f92, 0xfe34e867, 0xffef42af, 0x003cf03d, 0xfff39cd7,
+ 0x43d797c7, 0xf7ba422b, 0xfaa7a586, 0x05400be1, 0xfe3092bf, 0xfff3ad01, 0x003b871f, 0xfff3c69f,
+ 0x433d1c56, 0xf769ea78, 0xfad956ab, 0x053452dc, 0xfe2c7650, 0xfff8064b, 0x003a1ee3, 0xfff3f13a,
+ 0x42a159dc, 0xf71b52c4, 0xfb0aeef6, 0x05284685, 0xfe2892c5, 0xfffc4e5c, 0x0038b7ae, 0xfff41c9c,
+ 0x42045865, 0xf6ce7b57, 0xfb3c6a73, 0x051be8dd, 0xfe24e7c3, 0x00008507, 0x003751a7, 0xfff448b7,
+ 0x4166200e, 0xf683645a, 0xfb6dc53c, 0x050f3bec, 0xfe2174ec, 0x0004aa1f, 0x0035ecf4, 0xfff4757e,
+ 0x40c6b8fd, 0xf63a0ddf, 0xfb9efb77, 0x050241b6, 0xfe1e39da, 0x0008bd7c, 0x003489b9, 0xfff4a2e5,
+ 0x40262b65, 0xf5f277d9, 0xfbd00956, 0x04f4fc46, 0xfe1b3628, 0x000cbef7, 0x0033281a, 0xfff4d0de,
+ 0x3f847f83, 0xf5aca21f, 0xfc00eb1b, 0x04e76da3, 0xfe18696a, 0x0010ae6e, 0x0031c83a, 0xfff4ff5d,
+ 0x3ee1bda2, 0xf5688c6d, 0xfc319d13, 0x04d997d8, 0xfe15d32f, 0x00148bbd, 0x00306a3b, 0xfff52e57,
+ 0x3e3dee13, 0xf5263665, 0xfc621b9a, 0x04cb7cf2, 0xfe137304, 0x001856c7, 0x002f0e3f, 0xfff55dbf,
+ 0x3d991932, 0xf4e59f8a, 0xfc926319, 0x04bd1efb, 0xfe114872, 0x001c0f6e, 0x002db466, 0xfff58d89,
+ 0x3cf34766, 0xf4a6c748, 0xfcc27008, 0x04ae8000, 0xfe0f52fc, 0x001fb599, 0x002c5cd0, 0xfff5bdaa,
+ 0x3c4c811c, 0xf469aced, 0xfcf23eec, 0x049fa20f, 0xfe0d9224, 0x0023492f, 0x002b079a, 0xfff5ee17,
+ 0x3ba4cec9, 0xf42e4faf, 0xfd21cc59, 0x04908733, 0xfe0c0567, 0x0026ca1c, 0x0029b4e4, 0xfff61ec5,
+ 0x3afc38eb, 0xf3f4aea6, 0xfd5114f0, 0x0481317a, 0xfe0aac3f, 0x002a384c, 0x002864c9, 0xfff64fa8,
+ 0x3a52c805, 0xf3bcc8d3, 0xfd801564, 0x0471a2ef, 0xfe098622, 0x002d93ae, 0x00271766, 0xfff680b5,
+ 0x39a884a1, 0xf3869d1a, 0xfdaeca73, 0x0461dda0, 0xfe089283, 0x0030dc34, 0x0025ccd7, 0xfff6b1e4,
+ 0x38fd774e, 0xf3522a49, 0xfddd30eb, 0x0451e396, 0xfe07d0d3, 0x003411d2, 0x00248535, 0xfff6e329,
+ 0x3851a8a2, 0xf31f6f0f, 0xfe0b45aa, 0x0441b6dd, 0xfe07407d, 0x0037347d, 0x0023409a, 0xfff7147a,
+ 0x37a52135, 0xf2ee6a07, 0xfe39059b, 0x0431597d, 0xfe06e0eb, 0x003a442e, 0x0021ff1f, 0xfff745cd,
+ 0x36f7e9a4, 0xf2bf19ae, 0xfe666dbc, 0x0420cd80, 0xfe06b184, 0x003d40e0, 0x0020c0dc, 0xfff7771a,
+ 0x364a0a90, 0xf2917c6d, 0xfe937b15, 0x041014eb, 0xfe06b1ac, 0x00402a8e, 0x001f85e6, 0xfff7a857,
+ 0x359b8c9d, 0xf265908f, 0xfec02ac2, 0x03ff31c3, 0xfe06e0c4, 0x00430137, 0x001e4e56, 0xfff7d97a,
+ 0x34ec786f, 0xf23b544b, 0xfeec79ec, 0x03ee260d, 0xfe073e2a, 0x0045c4dd, 0x001d1a3f, 0xfff80a7c,
+ 0x343cd6af, 0xf212c5be, 0xff1865cd, 0x03dcf3ca, 0xfe07c93a, 0x00487582, 0x001be9b7, 0xfff83b52,
+ 0x338cb004, 0xf1ebe2ec, 0xff43ebac, 0x03cb9cf9, 0xfe08814e, 0x004b132b, 0x001abcd0, 0xfff86bf6,
+ 0x32dc0d17, 0xf1c6a9c3, 0xff6f08e4, 0x03ba2398, 0xfe0965bc, 0x004d9dde, 0x0019939d, 0xfff89c60,
+ 0x322af693, 0xf1a3181a, 0xff99badb, 0x03a889a1, 0xfe0a75da, 0x005015a5, 0x00186e31, 0xfff8cc86,
+ 0x3179751f, 0xf1812bb0, 0xffc3ff0c, 0x0396d10c, 0xfe0bb0f9, 0x00527a8a, 0x00174c9c, 0xfff8fc62,
+ 0x30c79163, 0xf160e22d, 0xffedd2fd, 0x0384fbd1, 0xfe0d166b, 0x0054cc9a, 0x00162eef, 0xfff92bec,
+ 0x30155404, 0xf1423924, 0x00173447, 0x03730be0, 0xfe0ea57e, 0x00570be4, 0x00151538, 0xfff95b1e,
+ 0x2f62c5a7, 0xf1252e0f, 0x00402092, 0x0361032a, 0xfe105d7e, 0x00593877, 0x0013ff88, 0xfff989ef,
+ 0x2eafeeed, 0xf109be56, 0x00689598, 0x034ee39b, 0xfe123db6, 0x005b5267, 0x0012edea, 0xfff9b85b,
+ 0x2dfcd873, 0xf0efe748, 0x0090911f, 0x033caf1d, 0xfe144570, 0x005d59c6, 0x0011e06d, 0xfff9e65a,
+ 0x2d498ad3, 0xf0d7a622, 0x00b81102, 0x032a6796, 0xfe1673f2, 0x005f4eac, 0x0010d71d, 0xfffa13e5,
+ 0x2c960ea3, 0xf0c0f808, 0x00df1328, 0x03180ee7, 0xfe18c884, 0x0061312e, 0x000fd205, 0xfffa40f8,
+ 0x2be26c73, 0xf0abda0e, 0x0105958c, 0x0305a6f0, 0xfe1b4268, 0x00630167, 0x000ed130, 0xfffa6d8d,
+ 0x2b2eaccf, 0xf0984931, 0x012b9635, 0x02f3318a, 0xfe1de0e2, 0x0064bf71, 0x000dd4a7, 0xfffa999d,
+ 0x2a7ad83c, 0xf086425a, 0x0151133e, 0x02e0b08d, 0xfe20a335, 0x00666b68, 0x000cdc74, 0xfffac525,
+ 0x29c6f738, 0xf075c260, 0x01760ad1, 0x02ce25ca, 0xfe2388a1, 0x0068056b, 0x000be89f, 0xfffaf01e,
+ 0x2913123c, 0xf066c606, 0x019a7b27, 0x02bb9310, 0xfe269065, 0x00698d98, 0x000af931, 0xfffb1a84,
+ 0x285f31b7, 0xf05949fb, 0x01be628c, 0x02a8fa2a, 0xfe29b9c1, 0x006b0411, 0x000a0e2f, 0xfffb4453,
+ 0x27ab5e12, 0xf04d4ade, 0x01e1bf58, 0x02965cdb, 0xfe2d03f2, 0x006c68f8, 0x000927a0, 0xfffb6d86,
+ 0x26f79fab, 0xf042c539, 0x02048ff8, 0x0283bce6, 0xfe306e35, 0x006dbc71, 0x00084589, 0xfffb961a,
+ 0x2643feda, 0xf039b587, 0x0226d2e6, 0x02711c05, 0xfe33f7c7, 0x006efea0, 0x000767f0, 0xfffbbe09,
+ 0x259083eb, 0xf032182f, 0x024886ad, 0x025e7bf0, 0xfe379fe3, 0x00702fae, 0x00068ed8, 0xfffbe552,
+ 0x24dd3721, 0xf02be98a, 0x0269a9e9, 0x024bde5a, 0xfe3b65c4, 0x00714fc0, 0x0005ba46, 0xfffc0bef,
+ 0x242a20b3, 0xf02725dc, 0x028a3b44, 0x023944ee, 0xfe3f48a5, 0x00725f02, 0x0004ea3a, 0xfffc31df,
+ 0x237748cf, 0xf023c95d, 0x02aa397b, 0x0226b156, 0xfe4347c0, 0x00735d9c, 0x00041eb9, 0xfffc571e,
+ 0x22c4b795, 0xf021d031, 0x02c9a359, 0x02142533, 0xfe476250, 0x00744bba, 0x000357c2, 0xfffc7ba9,
+ 0x2212751a, 0xf0213671, 0x02e877b9, 0x0201a223, 0xfe4b978e, 0x0075298a, 0x00029558, 0xfffc9f7e,
+ 0x21608968, 0xf021f823, 0x0306b586, 0x01ef29be, 0xfe4fe6b3, 0x0075f739, 0x0001d779, 0xfffcc29a,
+ 0x20aefc79, 0xf0241140, 0x03245bbc, 0x01dcbd96, 0xfe544efb, 0x0076b4f5, 0x00011e26, 0xfffce4fc,
+ 0x1ffdd63b, 0xf0277db1, 0x03416966, 0x01ca5f37, 0xfe58cf9d, 0x007762f0, 0x0000695e, 0xfffd06a1,
+ 0x1f4d1e8e, 0xf02c3953, 0x035ddd9e, 0x01b81028, 0xfe5d67d4, 0x0078015a, 0xffffb91f, 0xfffd2787,
+ 0x1e9cdd43, 0xf0323ff5, 0x0379b790, 0x01a5d1ea, 0xfe6216db, 0x00789065, 0xffff0d66, 0xfffd47ae,
+ 0x1ded1a1d, 0xf0398d56, 0x0394f674, 0x0193a5f9, 0xfe66dbeb, 0x00791043, 0xfffe6631, 0xfffd6713,
diff --git a/services/audioflinger/AudioResamplerSincUp.h b/services/audioflinger/AudioResamplerSincUp.h
new file mode 100644
index 0000000..fd5367e
--- /dev/null
+++ b/services/audioflinger/AudioResamplerSincUp.h
@@ -0,0 +1,131 @@
+// cmd-line: fir -l 7 -s48000 -c 20478
+
+ 0x6d374bc7, 0x111c6ba0, 0xf3240e61, 0x07d14a38, 0xfc509e64, 0x0139cee9, 0xffc8c866, 0xfffcc300,
+ 0x6d35278a, 0x103e8192, 0xf36b9dfd, 0x07bdfaa5, 0xfc5102d0, 0x013d618d, 0xffc663b9, 0xfffd9592,
+ 0x6d2ebafe, 0x0f62811a, 0xf3b3d8ac, 0x07a9f399, 0xfc51d9a6, 0x0140bea5, 0xffc41212, 0xfffe631e,
+ 0x6d24069d, 0x0e8875ad, 0xf3fcb43e, 0x07953976, 0xfc53216f, 0x0143e67c, 0xffc1d373, 0xffff2b9f,
+ 0x6d150b35, 0x0db06a89, 0xf4462690, 0x077fd0ac, 0xfc54d8ae, 0x0146d965, 0xffbfa7d9, 0xffffef10,
+ 0x6d01c9e3, 0x0cda6ab5, 0xf4902587, 0x0769bdaf, 0xfc56fdda, 0x014997bb, 0xffbd8f40, 0x0000ad6e,
+ 0x6cea4418, 0x0c0680fe, 0xf4daa718, 0x07530501, 0xfc598f60, 0x014c21db, 0xffbb89a1, 0x000166b6,
+ 0x6cce7b97, 0x0b34b7f5, 0xf525a143, 0x073bab28, 0xfc5c8ba5, 0x014e782a, 0xffb996f3, 0x00021ae5,
+ 0x6cae7272, 0x0a6519f4, 0xf5710a17, 0x0723b4b4, 0xfc5ff105, 0x01509b14, 0xffb7b728, 0x0002c9fd,
+ 0x6c8a2b0f, 0x0997b116, 0xf5bcd7b1, 0x070b2639, 0xfc63bdd3, 0x01528b08, 0xffb5ea31, 0x000373fb,
+ 0x6c61a823, 0x08cc873c, 0xf609003f, 0x06f20453, 0xfc67f05a, 0x0154487b, 0xffb42ffc, 0x000418e2,
+ 0x6c34ecb5, 0x0803a60a, 0xf6557a00, 0x06d853a2, 0xfc6c86dd, 0x0155d3e8, 0xffb28876, 0x0004b8b3,
+ 0x6c03fc1c, 0x073d16e7, 0xf6a23b44, 0x06be18cd, 0xfc717f97, 0x01572dcf, 0xffb0f388, 0x00055371,
+ 0x6bced9ff, 0x0678e2fc, 0xf6ef3a6e, 0x06a3587e, 0xfc76d8bc, 0x015856b6, 0xffaf7118, 0x0005e921,
+ 0x6b958a54, 0x05b71332, 0xf73c6df4, 0x06881761, 0xfc7c9079, 0x01594f25, 0xffae010b, 0x000679c5,
+ 0x6b581163, 0x04f7b037, 0xf789cc61, 0x066c5a27, 0xfc82a4f4, 0x015a17ab, 0xffaca344, 0x00070564,
+ 0x6b1673c1, 0x043ac276, 0xf7d74c53, 0x06502583, 0xfc89144d, 0x015ab0db, 0xffab57a1, 0x00078c04,
+ 0x6ad0b652, 0x0380521c, 0xf824e480, 0x06337e2a, 0xfc8fdc9f, 0x015b1b4e, 0xffaa1e02, 0x00080dab,
+ 0x6a86de48, 0x02c86715, 0xf8728bb3, 0x061668d2, 0xfc96fbfc, 0x015b579e, 0xffa8f641, 0x00088a62,
+ 0x6a38f123, 0x0213090c, 0xf8c038d0, 0x05f8ea30, 0xfc9e7074, 0x015b666c, 0xffa7e039, 0x00090230,
+ 0x69e6f4b1, 0x01603f6e, 0xf90de2d1, 0x05db06fc, 0xfca63810, 0x015b485b, 0xffa6dbc0, 0x0009751e,
+ 0x6990ef0b, 0x00b01162, 0xf95b80cb, 0x05bcc3ed, 0xfcae50d6, 0x015afe14, 0xffa5e8ad, 0x0009e337,
+ 0x6936e697, 0x000285d0, 0xf9a909ea, 0x059e25b5, 0xfcb6b8c4, 0x015a8843, 0xffa506d2, 0x000a4c85,
+ 0x68d8e206, 0xff57a35e, 0xf9f67577, 0x057f310a, 0xfcbf6dd8, 0x0159e796, 0xffa43603, 0x000ab112,
+ 0x6876e855, 0xfeaf706f, 0xfa43bad2, 0x055fea9d, 0xfcc86e09, 0x01591cc0, 0xffa3760e, 0x000b10ec,
+ 0x681100c9, 0xfe09f323, 0xfa90d17b, 0x0540571a, 0xfcd1b74c, 0x01582878, 0xffa2c6c2, 0x000b6c1d,
+ 0x67a732f4, 0xfd673159, 0xfaddb10c, 0x05207b2f, 0xfcdb4793, 0x01570b77, 0xffa227ec, 0x000bc2b3,
+ 0x673986ac, 0xfcc730aa, 0xfb2a513b, 0x05005b82, 0xfce51ccb, 0x0155c678, 0xffa19957, 0x000c14bb,
+ 0x66c80413, 0xfc29f670, 0xfb76a9dd, 0x04dffcb6, 0xfcef34e1, 0x01545a3c, 0xffa11acb, 0x000c6244,
+ 0x6652b392, 0xfb8f87bd, 0xfbc2b2e4, 0x04bf6369, 0xfcf98dbe, 0x0152c783, 0xffa0ac11, 0x000cab5c,
+ 0x65d99dd5, 0xfaf7e963, 0xfc0e6461, 0x049e9433, 0xfd04254a, 0x01510f13, 0xffa04cf0, 0x000cf012,
+ 0x655ccbd3, 0xfa631fef, 0xfc59b685, 0x047d93a8, 0xfd0ef969, 0x014f31b2, 0xff9ffd2c, 0x000d3075,
+ 0x64dc46c3, 0xf9d12fab, 0xfca4a19f, 0x045c6654, 0xfd1a0801, 0x014d3029, 0xff9fbc89, 0x000d6c97,
+ 0x64581823, 0xf9421c9d, 0xfcef1e20, 0x043b10bd, 0xfd254ef4, 0x014b0b45, 0xff9f8ac9, 0x000da486,
+ 0x63d049b4, 0xf8b5ea87, 0xfd392498, 0x04199760, 0xfd30cc24, 0x0148c3d2, 0xff9f67ae, 0x000dd854,
+ 0x6344e578, 0xf82c9ce7, 0xfd82adba, 0x03f7feb4, 0xfd3c7d73, 0x01465a9f, 0xff9f52f7, 0x000e0812,
+ 0x62b5f5b2, 0xf7a636fa, 0xfdcbb25a, 0x03d64b27, 0xfd4860c2, 0x0143d07f, 0xff9f4c65, 0x000e33d3,
+ 0x622384e8, 0xf722bbb5, 0xfe142b6e, 0x03b4811d, 0xfd5473f3, 0x01412643, 0xff9f53b4, 0x000e5ba7,
+ 0x618d9ddc, 0xf6a22dcf, 0xfe5c120f, 0x0392a4f4, 0xfd60b4e7, 0x013e5cc0, 0xff9f68a1, 0x000e7fa1,
+ 0x60f44b91, 0xf6248fb6, 0xfea35f79, 0x0370bafc, 0xfd6d2180, 0x013b74ca, 0xff9f8ae9, 0x000e9fd5,
+ 0x60579947, 0xf5a9e398, 0xfeea0d0c, 0x034ec77f, 0xfd79b7a1, 0x01386f3a, 0xff9fba47, 0x000ebc54,
+ 0x5fb79278, 0xf5322b61, 0xff30144a, 0x032ccebb, 0xfd86752e, 0x01354ce7, 0xff9ff674, 0x000ed533,
+ 0x5f1442dc, 0xf4bd68b6, 0xff756edc, 0x030ad4e1, 0xfd93580d, 0x01320ea9, 0xffa03f2b, 0x000eea84,
+ 0x5e6db665, 0xf44b9cfe, 0xffba168d, 0x02e8de19, 0xfda05e23, 0x012eb55a, 0xffa09425, 0x000efc5c,
+ 0x5dc3f93c, 0xf3dcc959, 0xfffe054e, 0x02c6ee7f, 0xfdad855b, 0x012b41d3, 0xffa0f519, 0x000f0ace,
+ 0x5d1717c4, 0xf370eea9, 0x00413536, 0x02a50a22, 0xfdbacb9e, 0x0127b4f1, 0xffa161bf, 0x000f15ef,
+ 0x5c671e96, 0xf3080d8c, 0x0083a081, 0x02833506, 0xfdc82edb, 0x01240f8e, 0xffa1d9cf, 0x000f1dd2,
+ 0x5bb41a80, 0xf2a2265e, 0x00c54190, 0x02617321, 0xfdd5ad01, 0x01205285, 0xffa25cfe, 0x000f228d,
+ 0x5afe1886, 0xf23f393b, 0x010612eb, 0x023fc85c, 0xfde34403, 0x011c7eb2, 0xffa2eb04, 0x000f2434,
+ 0x5a4525df, 0xf1df45fd, 0x01460f41, 0x021e3891, 0xfdf0f1d6, 0x011894f0, 0xffa38395, 0x000f22dc,
+ 0x59894ff3, 0xf1824c3e, 0x01853165, 0x01fcc78f, 0xfdfeb475, 0x0114961b, 0xffa42668, 0x000f1e99,
+ 0x58caa45b, 0xf1284b58, 0x01c37452, 0x01db7914, 0xfe0c89db, 0x0110830f, 0xffa4d332, 0x000f1781,
+ 0x580930e1, 0xf0d14267, 0x0200d32c, 0x01ba50d2, 0xfe1a7009, 0x010c5ca6, 0xffa589a6, 0x000f0da8,
+ 0x5745037c, 0xf07d3043, 0x023d493c, 0x0199526b, 0xfe286505, 0x010823ba, 0xffa6497c, 0x000f0125,
+ 0x567e2a51, 0xf02c138a, 0x0278d1f2, 0x01788170, 0xfe3666d5, 0x0103d927, 0xffa71266, 0x000ef20b,
+ 0x55b4b3af, 0xefddea9a, 0x02b368e6, 0x0157e166, 0xfe447389, 0x00ff7dc4, 0xffa7e41a, 0x000ee070,
+ 0x54e8ae13, 0xef92b393, 0x02ed09d7, 0x013775bf, 0xfe528931, 0x00fb126b, 0xffa8be4c, 0x000ecc69,
+ 0x541a281e, 0xef4a6c58, 0x0325b0ad, 0x011741df, 0xfe60a5e5, 0x00f697f3, 0xffa9a0b1, 0x000eb60b,
+ 0x5349309e, 0xef051290, 0x035d5977, 0x00f7491a, 0xfe6ec7c0, 0x00f20f32, 0xffaa8afe, 0x000e9d6b,
+ 0x5275d684, 0xeec2a3a3, 0x0394006a, 0x00d78eb3, 0xfe7cece2, 0x00ed78ff, 0xffab7ce7, 0x000e829e,
+ 0x51a028e8, 0xee831cc3, 0x03c9a1e5, 0x00b815da, 0xfe8b1373, 0x00e8d62d, 0xffac7621, 0x000e65ba,
+ 0x50c83704, 0xee467ae1, 0x03fe3a6f, 0x0098e1b3, 0xfe99399f, 0x00e4278f, 0xffad7662, 0x000e46d3,
+ 0x4fee1037, 0xee0cbab9, 0x0431c6b5, 0x0079f54c, 0xfea75d97, 0x00df6df7, 0xffae7d5f, 0x000e25fd,
+ 0x4f11c3fe, 0xedd5d8ca, 0x0464438c, 0x005b53a4, 0xfeb57d92, 0x00daaa34, 0xffaf8acd, 0x000e034f,
+ 0x4e3361f7, 0xeda1d15c, 0x0495adf2, 0x003cffa9, 0xfec397cf, 0x00d5dd16, 0xffb09e63, 0x000ddedb,
+ 0x4d52f9df, 0xed70a07d, 0x04c6030d, 0x001efc35, 0xfed1aa92, 0x00d10769, 0xffb1b7d8, 0x000db8b7,
+ 0x4c709b8e, 0xed424205, 0x04f54029, 0x00014c12, 0xfedfb425, 0x00cc29f7, 0xffb2d6e1, 0x000d90f6,
+ 0x4b8c56f8, 0xed16b196, 0x052362ba, 0xffe3f1f7, 0xfeedb2da, 0x00c7458a, 0xffb3fb37, 0x000d67ae,
+ 0x4aa63c2c, 0xecedea99, 0x0550685d, 0xffc6f08a, 0xfefba508, 0x00c25ae8, 0xffb52490, 0x000d3cf1,
+ 0x49be5b50, 0xecc7e845, 0x057c4ed4, 0xffaa4a5d, 0xff09890f, 0x00bd6ad7, 0xffb652a7, 0x000d10d5,
+ 0x48d4c4a2, 0xeca4a59b, 0x05a7140b, 0xff8e01f1, 0xff175d53, 0x00b87619, 0xffb78533, 0x000ce36b,
+ 0x47e98874, 0xec841d68, 0x05d0b612, 0xff7219b3, 0xff252042, 0x00b37d70, 0xffb8bbed, 0x000cb4c8,
+ 0x46fcb72d, 0xec664a48, 0x05f93324, 0xff5693fe, 0xff32d04f, 0x00ae8198, 0xffb9f691, 0x000c84ff,
+ 0x460e6148, 0xec4b26a2, 0x0620899e, 0xff3b731b, 0xff406bf8, 0x00a9834e, 0xffbb34d8, 0x000c5422,
+ 0x451e9750, 0xec32acb0, 0x0646b808, 0xff20b93e, 0xff4df1be, 0x00a4834c, 0xffbc767f, 0x000c2245,
+ 0x442d69de, 0xec1cd677, 0x066bbd0d, 0xff066889, 0xff5b602c, 0x009f8249, 0xffbdbb42, 0x000bef79,
+ 0x433ae99c, 0xec099dcf, 0x068f9781, 0xfeec830d, 0xff68b5d5, 0x009a80f8, 0xffbf02dd, 0x000bbbd2,
+ 0x4247273f, 0xebf8fc64, 0x06b2465b, 0xfed30ac5, 0xff75f153, 0x0095800c, 0xffc04d0f, 0x000b8760,
+ 0x41523389, 0xebeaebaf, 0x06d3c8bb, 0xfeba0199, 0xff831148, 0x00908034, 0xffc19996, 0x000b5235,
+ 0x405c1f43, 0xebdf6500, 0x06f41de3, 0xfea16960, 0xff90145e, 0x008b821b, 0xffc2e832, 0x000b1c64,
+ 0x3f64fb40, 0xebd6617b, 0x0713453d, 0xfe8943dc, 0xff9cf947, 0x0086866b, 0xffc438a3, 0x000ae5fc,
+ 0x3e6cd85b, 0xebcfda19, 0x07313e56, 0xfe7192bd, 0xffa9bebe, 0x00818dcb, 0xffc58aaa, 0x000aaf0f,
+ 0x3d73c772, 0xebcbc7a7, 0x074e08e0, 0xfe5a579d, 0xffb66386, 0x007c98de, 0xffc6de09, 0x000a77ac,
+ 0x3c79d968, 0xebca22cc, 0x0769a4b2, 0xfe439407, 0xffc2e669, 0x0077a845, 0xffc83285, 0x000a3fe5,
+ 0x3b7f1f23, 0xebcae405, 0x078411c7, 0xfe2d496f, 0xffcf463a, 0x0072bc9d, 0xffc987e0, 0x000a07c9,
+ 0x3a83a989, 0xebce03aa, 0x079d503b, 0xfe177937, 0xffdb81d6, 0x006dd680, 0xffcadde1, 0x0009cf67,
+ 0x3987897f, 0xebd379eb, 0x07b56051, 0xfe0224b0, 0xffe79820, 0x0068f687, 0xffcc344c, 0x000996ce,
+ 0x388acfe9, 0xebdb3ed5, 0x07cc426c, 0xfded4d13, 0xfff38806, 0x00641d44, 0xffcd8aeb, 0x00095e0e,
+ 0x378d8da8, 0xebe54a4f, 0x07e1f712, 0xfdd8f38b, 0xffff507b, 0x005f4b4a, 0xffcee183, 0x00092535,
+ 0x368fd397, 0xebf1941f, 0x07f67eec, 0xfdc5192d, 0x000af07f, 0x005a8125, 0xffd037e0, 0x0008ec50,
+ 0x3591b28b, 0xec0013e8, 0x0809dac3, 0xfdb1befc, 0x00166718, 0x0055bf60, 0xffd18dcc, 0x0008b36e,
+ 0x34933b50, 0xec10c12c, 0x081c0b84, 0xfd9ee5e7, 0x0021b355, 0x00510682, 0xffd2e311, 0x00087a9c,
+ 0x33947eab, 0xec23934f, 0x082d1239, 0xfd8c8ecc, 0x002cd44d, 0x004c570f, 0xffd4377d, 0x000841e8,
+ 0x32958d55, 0xec388194, 0x083cf010, 0xfd7aba74, 0x0037c922, 0x0047b186, 0xffd58ade, 0x0008095d,
+ 0x319677fa, 0xec4f8322, 0x084ba654, 0xfd696998, 0x004290fc, 0x00431666, 0xffd6dd02, 0x0007d108,
+ 0x30974f3b, 0xec688f02, 0x08593671, 0xfd589cdc, 0x004d2b0e, 0x003e8628, 0xffd82dba, 0x000798f5,
+ 0x2f9823a8, 0xec839c22, 0x0865a1f1, 0xfd4854d3, 0x00579691, 0x003a0141, 0xffd97cd6, 0x00076130,
+ 0x2e9905c1, 0xeca0a156, 0x0870ea7e, 0xfd3891fd, 0x0061d2ca, 0x00358824, 0xffdaca2a, 0x000729c4,
+ 0x2d9a05f4, 0xecbf9558, 0x087b11de, 0xfd2954c8, 0x006bdf05, 0x00311b41, 0xffdc1588, 0x0006f2bb,
+ 0x2c9b349e, 0xece06ecb, 0x088419f6, 0xfd1a9d91, 0x0075ba95, 0x002cbb03, 0xffdd5ec6, 0x0006bc21,
+ 0x2b9ca203, 0xed032439, 0x088c04c8, 0xfd0c6ca2, 0x007f64da, 0x002867d2, 0xffdea5bb, 0x000685ff,
+ 0x2a9e5e57, 0xed27ac16, 0x0892d470, 0xfcfec233, 0x0088dd38, 0x00242213, 0xffdfea3c, 0x0006505f,
+ 0x29a079b2, 0xed4dfcc2, 0x08988b2a, 0xfcf19e6b, 0x0092231e, 0x001fea27, 0xffe12c22, 0x00061b4b,
+ 0x28a30416, 0xed760c88, 0x089d2b4a, 0xfce50161, 0x009b3605, 0x001bc06b, 0xffe26b48, 0x0005e6cb,
+ 0x27a60d6a, 0xed9fd1a2, 0x08a0b740, 0xfcd8eb17, 0x00a4156b, 0x0017a53b, 0xffe3a788, 0x0005b2e8,
+ 0x26a9a57b, 0xedcb4237, 0x08a33196, 0xfccd5b82, 0x00acc0da, 0x001398ec, 0xffe4e0bf, 0x00057faa,
+ 0x25addbf9, 0xedf8545b, 0x08a49cf0, 0xfcc25285, 0x00b537e1, 0x000f9bd2, 0xffe616c8, 0x00054d1a,
+ 0x24b2c075, 0xee26fe17, 0x08a4fc0d, 0xfcb7cff0, 0x00bd7a1c, 0x000bae3c, 0xffe74984, 0x00051b3e,
+ 0x23b86263, 0xee573562, 0x08a451c0, 0xfcadd386, 0x00c5872a, 0x0007d075, 0xffe878d3, 0x0004ea1d,
+ 0x22bed116, 0xee88f026, 0x08a2a0f8, 0xfca45cf7, 0x00cd5eb7, 0x000402c8, 0xffe9a494, 0x0004b9c0,
+ 0x21c61bc0, 0xeebc2444, 0x089fecbb, 0xfc9b6be5, 0x00d50075, 0x00004579, 0xffeaccaa, 0x00048a2b,
+ 0x20ce516f, 0xeef0c78d, 0x089c3824, 0xfc92ffe1, 0x00dc6c1e, 0xfffc98c9, 0xffebf0fa, 0x00045b65,
+ 0x1fd7810f, 0xef26cfca, 0x08978666, 0xfc8b186d, 0x00e3a175, 0xfff8fcf7, 0xffed1166, 0x00042d74,
+ 0x1ee1b965, 0xef5e32bd, 0x0891dac8, 0xfc83b4fc, 0x00eaa045, 0xfff5723d, 0xffee2dd7, 0x0004005e,
+ 0x1ded0911, 0xef96e61c, 0x088b38a9, 0xfc7cd4f0, 0x00f16861, 0xfff1f8d2, 0xffef4632, 0x0003d426,
+ 0x1cf97e8b, 0xefd0df9a, 0x0883a378, 0xfc76779e, 0x00f7f9a3, 0xffee90eb, 0xfff05a60, 0x0003a8d2,
+ 0x1c072823, 0xf00c14e1, 0x087b1ebc, 0xfc709c4d, 0x00fe53ef, 0xffeb3ab8, 0xfff16a4a, 0x00037e65,
+ 0x1b1613ff, 0xf0487b98, 0x0871ae0d, 0xfc6b4233, 0x0104772e, 0xffe7f666, 0xfff275db, 0x000354e5,
+ 0x1a26501b, 0xf0860962, 0x08675516, 0xfc66687a, 0x010a6353, 0xffe4c41e, 0xfff37d00, 0x00032c54,
+ 0x1937ea47, 0xf0c4b3e0, 0x085c1794, 0xfc620e3d, 0x01101858, 0xffe1a408, 0xfff47fa5, 0x000304b7,
+ 0x184af025, 0xf10470b0, 0x084ff957, 0xfc5e328c, 0x0115963d, 0xffde9646, 0xfff57db8, 0x0002de0e,
+ 0x175f6f2b, 0xf1453571, 0x0842fe3d, 0xfc5ad465, 0x011add0b, 0xffdb9af8, 0xfff67729, 0x0002b85f,
+ 0x1675749e, 0xf186f7c0, 0x08352a35, 0xfc57f2be, 0x011fecd3, 0xffd8b23b, 0xfff76be9, 0x000293aa,
+ 0x158d0d95, 0xf1c9ad40, 0x0826813e, 0xfc558c7c, 0x0124c5ab, 0xffd5dc28, 0xfff85be8, 0x00026ff2,
+ 0x14a646f6, 0xf20d4b92, 0x08170767, 0xfc53a07b, 0x012967b1, 0xffd318d6, 0xfff9471b, 0x00024d39,
+ 0x13c12d73, 0xf251c85d, 0x0806c0cb, 0xfc522d88, 0x012dd30a, 0xffd06858, 0xfffa2d74, 0x00022b7f,
+ 0x12ddcd8f, 0xf297194d, 0x07f5b193, 0xfc513266, 0x013207e4, 0xffcdcabe, 0xfffb0ee9, 0x00020ac7,
+ 0x11fc3395, 0xf2dd3411, 0x07e3ddf7, 0xfc50adcc, 0x01360670, 0xffcb4014, 0xfffbeb70, 0x0001eb10,
+ 0x111c6ba0, 0xf3240e61, 0x07d14a38, 0xfc509e64, 0x0139cee9, 0xffc8c866, 0xfffcc300, 0x0001cc5c,
diff --git a/services/audioflinger/Configuration.h b/services/audioflinger/Configuration.h
index 6a8aeb1..845697a 100644
--- a/services/audioflinger/Configuration.h
+++ b/services/audioflinger/Configuration.h
@@ -29,9 +29,8 @@
// uncomment to display CPU load adjusted for CPU frequency
//#define CPU_FREQUENCY_STATISTICS
-// uncomment to enable fast mixer to take performance samples for later statistical analysis
-#define FAST_MIXER_STATISTICS
-// FIXME rename to FAST_THREAD_STATISTICS
+// uncomment to enable fast threads to take performance samples for later statistical analysis
+#define FAST_THREAD_STATISTICS
// uncomment for debugging timing problems related to StateQueue::push()
//#define STATE_QUEUE_DUMP
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index bcaf8ae..8bccb47 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1953,4 +1953,4 @@
}
}
-}; // namespace android
+} // namespace android
diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp
index 0c9b976..9e7e8a4 100644
--- a/services/audioflinger/FastCapture.cpp
+++ b/services/audioflinger/FastCapture.cpp
@@ -29,18 +29,18 @@
namespace android {
-/*static*/ const FastCaptureState FastCapture::initial;
+/*static*/ const FastCaptureState FastCapture::sInitial;
FastCapture::FastCapture() : FastThread(),
- inputSource(NULL), inputSourceGen(0), pipeSink(NULL), pipeSinkGen(0),
- readBuffer(NULL), readBufferState(-1), format(Format_Invalid), sampleRate(0),
- // dummyDumpState
- totalNativeFramesRead(0)
+ mInputSource(NULL), mInputSourceGen(0), mPipeSink(NULL), mPipeSinkGen(0),
+ mReadBuffer(NULL), mReadBufferState(-1), mFormat(Format_Invalid), mSampleRate(0),
+ // mDummyDumpState
+ mTotalNativeFramesRead(0)
{
- previous = &initial;
- current = &initial;
+ mPrevious = &sInitial;
+ mCurrent = &sInitial;
- mDummyDumpState = &dummyDumpState;
+ mDummyDumpState = &mDummyFastCaptureDumpState;
}
FastCapture::~FastCapture()
@@ -63,13 +63,13 @@
void FastCapture::onIdle()
{
- preIdle = *(const FastCaptureState *)current;
- current = &preIdle;
+ mPreIdle = *(const FastCaptureState *)mCurrent;
+ mCurrent = &mPreIdle;
}
void FastCapture::onExit()
{
- delete[] readBuffer;
+ free(mReadBuffer);
}
bool FastCapture::isSubClassCommand(FastThreadState::Command command)
@@ -86,67 +86,67 @@
void FastCapture::onStateChange()
{
- const FastCaptureState * const current = (const FastCaptureState *) this->current;
- const FastCaptureState * const previous = (const FastCaptureState *) this->previous;
- FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) this->dumpState;
+ const FastCaptureState * const current = (const FastCaptureState *) mCurrent;
+ const FastCaptureState * const previous = (const FastCaptureState *) mPrevious;
+ FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState;
const size_t frameCount = current->mFrameCount;
bool eitherChanged = false;
// check for change in input HAL configuration
- NBAIO_Format previousFormat = format;
- if (current->mInputSourceGen != inputSourceGen) {
- inputSource = current->mInputSource;
- inputSourceGen = current->mInputSourceGen;
- if (inputSource == NULL) {
- format = Format_Invalid;
- sampleRate = 0;
+ NBAIO_Format previousFormat = mFormat;
+ if (current->mInputSourceGen != mInputSourceGen) {
+ mInputSource = current->mInputSource;
+ mInputSourceGen = current->mInputSourceGen;
+ if (mInputSource == NULL) {
+ mFormat = Format_Invalid;
+ mSampleRate = 0;
} else {
- format = inputSource->format();
- sampleRate = Format_sampleRate(format);
- unsigned channelCount = Format_channelCount(format);
+ mFormat = mInputSource->format();
+ mSampleRate = Format_sampleRate(mFormat);
+ unsigned channelCount = Format_channelCount(mFormat);
ALOG_ASSERT(channelCount == 1 || channelCount == 2);
}
- dumpState->mSampleRate = sampleRate;
+ dumpState->mSampleRate = mSampleRate;
eitherChanged = true;
}
// check for change in pipe
- if (current->mPipeSinkGen != pipeSinkGen) {
- pipeSink = current->mPipeSink;
- pipeSinkGen = current->mPipeSinkGen;
+ if (current->mPipeSinkGen != mPipeSinkGen) {
+ mPipeSink = current->mPipeSink;
+ mPipeSinkGen = current->mPipeSinkGen;
eitherChanged = true;
}
// input source and pipe sink must be compatible
- if (eitherChanged && inputSource != NULL && pipeSink != NULL) {
- ALOG_ASSERT(Format_isEqual(format, pipeSink->format()));
+ if (eitherChanged && mInputSource != NULL && mPipeSink != NULL) {
+ ALOG_ASSERT(Format_isEqual(mFormat, mPipeSink->format()));
}
- if ((!Format_isEqual(format, previousFormat)) || (frameCount != previous->mFrameCount)) {
- // FIXME to avoid priority inversion, don't delete here
- delete[] readBuffer;
- readBuffer = NULL;
- if (frameCount > 0 && sampleRate > 0) {
+ if ((!Format_isEqual(mFormat, previousFormat)) || (frameCount != previous->mFrameCount)) {
+ // FIXME to avoid priority inversion, don't free here
+ free(mReadBuffer);
+ mReadBuffer = NULL;
+ if (frameCount > 0 && mSampleRate > 0) {
// FIXME new may block for unbounded time at internal mutex of the heap
// implementation; it would be better to have normal capture thread allocate for
// us to avoid blocking here and to prevent possible priority inversion
- unsigned channelCount = Format_channelCount(format);
- // FIXME frameSize
- readBuffer = new short[frameCount * channelCount];
- periodNs = (frameCount * 1000000000LL) / sampleRate; // 1.00
- underrunNs = (frameCount * 1750000000LL) / sampleRate; // 1.75
- overrunNs = (frameCount * 500000000LL) / sampleRate; // 0.50
- forceNs = (frameCount * 950000000LL) / sampleRate; // 0.95
- warmupNs = (frameCount * 500000000LL) / sampleRate; // 0.50
+ (void)posix_memalign(&mReadBuffer, 32, frameCount * Format_frameSize(mFormat));
+ mPeriodNs = (frameCount * 1000000000LL) / mSampleRate; // 1.00
+ mUnderrunNs = (frameCount * 1750000000LL) / mSampleRate; // 1.75
+ mOverrunNs = (frameCount * 500000000LL) / mSampleRate; // 0.50
+ mForceNs = (frameCount * 950000000LL) / mSampleRate; // 0.95
+ mWarmupNsMin = (frameCount * 750000000LL) / mSampleRate; // 0.75
+ mWarmupNsMax = (frameCount * 1250000000LL) / mSampleRate; // 1.25
} else {
- periodNs = 0;
- underrunNs = 0;
- overrunNs = 0;
- forceNs = 0;
- warmupNs = 0;
+ mPeriodNs = 0;
+ mUnderrunNs = 0;
+ mOverrunNs = 0;
+ mForceNs = 0;
+ mWarmupNsMin = 0;
+ mWarmupNsMax = LONG_MAX;
}
- readBufferState = -1;
+ mReadBufferState = -1;
dumpState->mFrameCount = frameCount;
}
@@ -154,44 +154,43 @@
void FastCapture::onWork()
{
- const FastCaptureState * const current = (const FastCaptureState *) this->current;
- FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) this->dumpState;
- const FastCaptureState::Command command = this->command;
+ const FastCaptureState * const current = (const FastCaptureState *) mCurrent;
+ FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState;
+ const FastCaptureState::Command command = mCommand;
const size_t frameCount = current->mFrameCount;
if ((command & FastCaptureState::READ) /*&& isWarm*/) {
- ALOG_ASSERT(inputSource != NULL);
- ALOG_ASSERT(readBuffer != NULL);
+ ALOG_ASSERT(mInputSource != NULL);
+ ALOG_ASSERT(mReadBuffer != NULL);
dumpState->mReadSequence++;
ATRACE_BEGIN("read");
- ssize_t framesRead = inputSource->read(readBuffer, frameCount,
+ ssize_t framesRead = mInputSource->read(mReadBuffer, frameCount,
AudioBufferProvider::kInvalidPTS);
ATRACE_END();
dumpState->mReadSequence++;
if (framesRead >= 0) {
LOG_ALWAYS_FATAL_IF((size_t) framesRead > frameCount);
- totalNativeFramesRead += framesRead;
- dumpState->mFramesRead = totalNativeFramesRead;
- readBufferState = framesRead;
+ mTotalNativeFramesRead += framesRead;
+ dumpState->mFramesRead = mTotalNativeFramesRead;
+ mReadBufferState = framesRead;
} else {
dumpState->mReadErrors++;
- readBufferState = 0;
+ mReadBufferState = 0;
}
// FIXME rename to attemptedIO
- attemptedWrite = true;
+ mAttemptedWrite = true;
}
if (command & FastCaptureState::WRITE) {
- ALOG_ASSERT(pipeSink != NULL);
- ALOG_ASSERT(readBuffer != NULL);
- if (readBufferState < 0) {
- unsigned channelCount = Format_channelCount(format);
- // FIXME frameSize
- memset(readBuffer, 0, frameCount * channelCount * sizeof(short));
- readBufferState = frameCount;
+ ALOG_ASSERT(mPipeSink != NULL);
+ ALOG_ASSERT(mReadBuffer != NULL);
+ if (mReadBufferState < 0) {
+ unsigned channelCount = Format_channelCount(mFormat);
+ memset(mReadBuffer, 0, frameCount * Format_frameSize(mFormat));
+ mReadBufferState = frameCount;
}
- if (readBufferState > 0) {
- ssize_t framesWritten = pipeSink->write(readBuffer, readBufferState);
+ if (mReadBufferState > 0) {
+ ssize_t framesWritten = mPipeSink->write(mReadBuffer, mReadBufferState);
// FIXME This supports at most one fast capture client.
// To handle multiple clients this could be converted to an array,
// or with a lot more work the control block could be shared by all clients.
@@ -210,13 +209,4 @@
}
}
-FastCaptureDumpState::FastCaptureDumpState() : FastThreadDumpState(),
- mReadSequence(0), mFramesRead(0), mReadErrors(0), mSampleRate(0), mFrameCount(0)
-{
-}
-
-FastCaptureDumpState::~FastCaptureDumpState()
-{
-}
-
} // namespace android
diff --git a/services/audioflinger/FastCapture.h b/services/audioflinger/FastCapture.h
index e535b9d..e258a4d 100644
--- a/services/audioflinger/FastCapture.h
+++ b/services/audioflinger/FastCapture.h
@@ -20,23 +20,12 @@
#include "FastThread.h"
#include "StateQueue.h"
#include "FastCaptureState.h"
+#include "FastCaptureDumpState.h"
namespace android {
typedef StateQueue<FastCaptureState> FastCaptureStateQueue;
-struct FastCaptureDumpState : FastThreadDumpState {
- FastCaptureDumpState();
- /*virtual*/ ~FastCaptureDumpState();
-
- // FIXME by renaming, could pull up many of these to FastThreadDumpState
- uint32_t mReadSequence; // incremented before and after each read()
- uint32_t mFramesRead; // total number of frames read successfully
- uint32_t mReadErrors; // total number of read() errors
- uint32_t mSampleRate;
- size_t mFrameCount;
-};
-
class FastCapture : public FastThread {
public:
@@ -57,19 +46,21 @@
virtual void onStateChange();
virtual void onWork();
- static const FastCaptureState initial;
- FastCaptureState preIdle; // copy of state before we went into idle
+ static const FastCaptureState sInitial;
+
+ FastCaptureState mPreIdle; // copy of state before we went into idle
// FIXME by renaming, could pull up many of these to FastThread
- NBAIO_Source *inputSource;
- int inputSourceGen;
- NBAIO_Sink *pipeSink;
- int pipeSinkGen;
- short *readBuffer;
- ssize_t readBufferState; // number of initialized frames in readBuffer, or -1 to clear
- NBAIO_Format format;
- unsigned sampleRate;
- FastCaptureDumpState dummyDumpState;
- uint32_t totalNativeFramesRead; // copied to dumpState->mFramesRead
+ NBAIO_Source* mInputSource;
+ int mInputSourceGen;
+ NBAIO_Sink* mPipeSink;
+ int mPipeSinkGen;
+ void* mReadBuffer;
+ ssize_t mReadBufferState; // number of initialized frames in readBuffer,
+ // or -1 to clear
+ NBAIO_Format mFormat;
+ unsigned mSampleRate;
+ FastCaptureDumpState mDummyFastCaptureDumpState;
+ uint32_t mTotalNativeFramesRead; // copied to dumpState->mFramesRead
}; // class FastCapture
diff --git a/services/audiopolicy/AudioPolicyFactory.cpp b/services/audioflinger/FastCaptureDumpState.cpp
similarity index 66%
copy from services/audiopolicy/AudioPolicyFactory.cpp
copy to services/audioflinger/FastCaptureDumpState.cpp
index 2ae7bc1..00f8da0 100644
--- a/services/audiopolicy/AudioPolicyFactory.cpp
+++ b/services/audioflinger/FastCaptureDumpState.cpp
@@ -14,19 +14,17 @@
* limitations under the License.
*/
-#include "AudioPolicyManager.h"
+#include "FastCaptureDumpState.h"
namespace android {
-extern "C" AudioPolicyInterface* createAudioPolicyManager(
- AudioPolicyClientInterface *clientInterface)
+FastCaptureDumpState::FastCaptureDumpState() : FastThreadDumpState(),
+ mReadSequence(0), mFramesRead(0), mReadErrors(0), mSampleRate(0), mFrameCount(0)
{
- return new AudioPolicyManager(clientInterface);
}
-extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface)
+FastCaptureDumpState::~FastCaptureDumpState()
{
- delete interface;
}
-}; // namespace android
+} // android
diff --git a/services/audioflinger/FastCaptureDumpState.h b/services/audioflinger/FastCaptureDumpState.h
new file mode 100644
index 0000000..ee99099
--- /dev/null
+++ b/services/audioflinger/FastCaptureDumpState.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_AUDIO_FAST_CAPTURE_DUMP_STATE_H
+#define ANDROID_AUDIO_FAST_CAPTURE_DUMP_STATE_H
+
+#include <stdint.h>
+#include "Configuration.h"
+#include "FastThreadDumpState.h"
+
+namespace android {
+
+struct FastCaptureDumpState : FastThreadDumpState {
+ FastCaptureDumpState();
+ /*virtual*/ ~FastCaptureDumpState();
+
+ // FIXME by renaming, could pull up many of these to FastThreadDumpState
+ uint32_t mReadSequence; // incremented before and after each read()
+ uint32_t mFramesRead; // total number of frames read successfully
+ uint32_t mReadErrors; // total number of read() errors
+ uint32_t mSampleRate;
+ size_t mFrameCount;
+};
+
+} // android
+
+#endif // ANDROID_AUDIO_FAST_CAPTURE_DUMP_STATE_H
diff --git a/services/audioflinger/FastCaptureState.cpp b/services/audioflinger/FastCaptureState.cpp
index 1d029b7..c4d5e45 100644
--- a/services/audioflinger/FastCaptureState.cpp
+++ b/services/audioflinger/FastCaptureState.cpp
@@ -27,4 +27,19 @@
{
}
+// static
+const char *FastCaptureState::commandToString(Command command)
+{
+ const char *str = FastThreadState::commandToString(command);
+ if (str != NULL) {
+ return str;
+ }
+ switch (command) {
+ case FastCaptureState::READ: return "READ";
+ case FastCaptureState::WRITE: return "WRITE";
+ case FastCaptureState::READ_WRITE: return "READ_WRITE";
+ }
+ LOG_ALWAYS_FATAL("%s", __func__);
+}
+
} // android
diff --git a/services/audioflinger/FastCaptureState.h b/services/audioflinger/FastCaptureState.h
index 29c865a..9bca2d4 100644
--- a/services/audioflinger/FastCaptureState.h
+++ b/services/audioflinger/FastCaptureState.h
@@ -29,21 +29,23 @@
/*virtual*/ ~FastCaptureState();
// all pointer fields use raw pointers; objects are owned and ref-counted by RecordThread
- NBAIO_Source *mInputSource; // HAL input device, must already be negotiated
+ NBAIO_Source* mInputSource; // HAL input device, must already be negotiated
// FIXME by renaming, could pull up these fields to FastThreadState
int mInputSourceGen; // increment when mInputSource is assigned
- NBAIO_Sink *mPipeSink; // after reading from input source, write to this pipe sink
+ NBAIO_Sink* mPipeSink; // after reading from input source, write to this pipe sink
int mPipeSinkGen; // increment when mPipeSink is assigned
size_t mFrameCount; // number of frames per fast capture buffer
- audio_track_cblk_t *mCblk; // control block for the single fast client, or NULL
+ audio_track_cblk_t* mCblk; // control block for the single fast client, or NULL
// Extends FastThreadState::Command
static const Command
// The following commands also process configuration changes, and can be "or"ed:
- READ = 0x8, // read from input source
- WRITE = 0x10, // write to pipe sink
- READ_WRITE = 0x18; // read from input source and write to pipe sink
+ READ = 0x8, // read from input source
+ WRITE = 0x10, // write to pipe sink
+ READ_WRITE = 0x18; // read from input source and write to pipe sink
+ // never returns NULL; asserts if command is invalid
+ static const char *commandToString(Command command);
}; // struct FastCaptureState
} // namespace android
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 2678cbf..e070f90 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -27,10 +27,11 @@
#include "Configuration.h"
#include <time.h>
+#include <utils/Debug.h>
#include <utils/Log.h>
#include <utils/Trace.h>
#include <system/audio.h>
-#ifdef FAST_MIXER_STATISTICS
+#ifdef FAST_THREAD_STATISTICS
#include <cpustats/CentralTendencyStatistics.h>
#ifdef CPU_FREQUENCY_STATISTICS
#include <cpustats/ThreadCpuUsage.h>
@@ -44,15 +45,15 @@
namespace android {
-/*static*/ const FastMixerState FastMixer::initial;
+/*static*/ const FastMixerState FastMixer::sInitial;
FastMixer::FastMixer() : FastThread(),
- slopNs(0),
- // fastTrackNames
- // generations
- outputSink(NULL),
- outputSinkGen(0),
- mixer(NULL),
+ mSlopNs(0),
+ // mFastTrackNames
+ // mGenerations
+ mOutputSink(NULL),
+ mOutputSinkGen(0),
+ mMixer(NULL),
mSinkBuffer(NULL),
mSinkBufferSize(0),
mSinkChannelCount(FCC_2),
@@ -60,30 +61,30 @@
mMixerBufferSize(0),
mMixerBufferFormat(AUDIO_FORMAT_PCM_16_BIT),
mMixerBufferState(UNDEFINED),
- format(Format_Invalid),
- sampleRate(0),
- fastTracksGen(0),
- totalNativeFramesWritten(0),
+ mFormat(Format_Invalid),
+ mSampleRate(0),
+ mFastTracksGen(0),
+ mTotalNativeFramesWritten(0),
// timestamp
- nativeFramesWrittenButNotPresented(0) // the = 0 is to silence the compiler
+ mNativeFramesWrittenButNotPresented(0) // the = 0 is to silence the compiler
{
- // FIXME pass initial as parameter to base class constructor, and make it static local
- previous = &initial;
- current = &initial;
+ // FIXME pass sInitial as parameter to base class constructor, and make it static local
+ mPrevious = &sInitial;
+ mCurrent = &sInitial;
- mDummyDumpState = &dummyDumpState;
+ mDummyDumpState = &mDummyFastMixerDumpState;
// TODO: Add channel mask to NBAIO_Format.
// We assume that the channel mask must be a valid positional channel mask.
mSinkChannelMask = audio_channel_out_mask_from_count(mSinkChannelCount);
unsigned i;
for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
- fastTrackNames[i] = -1;
- generations[i] = 0;
+ mFastTrackNames[i] = -1;
+ mGenerations[i] = 0;
}
-#ifdef FAST_MIXER_STATISTICS
- oldLoad.tv_sec = 0;
- oldLoad.tv_nsec = 0;
+#ifdef FAST_THREAD_STATISTICS
+ mOldLoad.tv_sec = 0;
+ mOldLoad.tv_nsec = 0;
#endif
}
@@ -103,20 +104,20 @@
void FastMixer::setLog(NBLog::Writer *logWriter)
{
- if (mixer != NULL) {
- mixer->setLog(logWriter);
+ if (mMixer != NULL) {
+ mMixer->setLog(logWriter);
}
}
void FastMixer::onIdle()
{
- preIdle = *(const FastMixerState *)current;
- current = &preIdle;
+ mPreIdle = *(const FastMixerState *)mCurrent;
+ mCurrent = &mPreIdle;
}
void FastMixer::onExit()
{
- delete mixer;
+ delete mMixer;
free(mMixerBuffer);
free(mSinkBuffer);
}
@@ -135,82 +136,84 @@
void FastMixer::onStateChange()
{
- const FastMixerState * const current = (const FastMixerState *) this->current;
- const FastMixerState * const previous = (const FastMixerState *) this->previous;
- FastMixerDumpState * const dumpState = (FastMixerDumpState *) this->dumpState;
+ const FastMixerState * const current = (const FastMixerState *) mCurrent;
+ const FastMixerState * const previous = (const FastMixerState *) mPrevious;
+ FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState;
const size_t frameCount = current->mFrameCount;
// handle state change here, but since we want to diff the state,
- // we're prepared for previous == &initial the first time through
+ // we're prepared for previous == &sInitial the first time through
unsigned previousTrackMask;
// check for change in output HAL configuration
- NBAIO_Format previousFormat = format;
- if (current->mOutputSinkGen != outputSinkGen) {
- outputSink = current->mOutputSink;
- outputSinkGen = current->mOutputSinkGen;
- if (outputSink == NULL) {
- format = Format_Invalid;
- sampleRate = 0;
+ NBAIO_Format previousFormat = mFormat;
+ if (current->mOutputSinkGen != mOutputSinkGen) {
+ mOutputSink = current->mOutputSink;
+ mOutputSinkGen = current->mOutputSinkGen;
+ if (mOutputSink == NULL) {
+ mFormat = Format_Invalid;
+ mSampleRate = 0;
mSinkChannelCount = 0;
mSinkChannelMask = AUDIO_CHANNEL_NONE;
} else {
- format = outputSink->format();
- sampleRate = Format_sampleRate(format);
- mSinkChannelCount = Format_channelCount(format);
+ mFormat = mOutputSink->format();
+ mSampleRate = Format_sampleRate(mFormat);
+ mSinkChannelCount = Format_channelCount(mFormat);
LOG_ALWAYS_FATAL_IF(mSinkChannelCount > AudioMixer::MAX_NUM_CHANNELS);
// TODO: Add channel mask to NBAIO_Format
// We assume that the channel mask must be a valid positional channel mask.
mSinkChannelMask = audio_channel_out_mask_from_count(mSinkChannelCount);
}
- dumpState->mSampleRate = sampleRate;
+ dumpState->mSampleRate = mSampleRate;
}
- if ((!Format_isEqual(format, previousFormat)) || (frameCount != previous->mFrameCount)) {
+ if ((!Format_isEqual(mFormat, previousFormat)) || (frameCount != previous->mFrameCount)) {
// FIXME to avoid priority inversion, don't delete here
- delete mixer;
- mixer = NULL;
+ delete mMixer;
+ mMixer = NULL;
free(mMixerBuffer);
mMixerBuffer = NULL;
free(mSinkBuffer);
mSinkBuffer = NULL;
- if (frameCount > 0 && sampleRate > 0) {
+ if (frameCount > 0 && mSampleRate > 0) {
// FIXME new may block for unbounded time at internal mutex of the heap
// implementation; it would be better to have normal mixer allocate for us
// to avoid blocking here and to prevent possible priority inversion
- mixer = new AudioMixer(frameCount, sampleRate, FastMixerState::kMaxFastTracks);
+ mMixer = new AudioMixer(frameCount, mSampleRate, FastMixerState::kMaxFastTracks);
const size_t mixerFrameSize = mSinkChannelCount
* audio_bytes_per_sample(mMixerBufferFormat);
mMixerBufferSize = mixerFrameSize * frameCount;
(void)posix_memalign(&mMixerBuffer, 32, mMixerBufferSize);
const size_t sinkFrameSize = mSinkChannelCount
- * audio_bytes_per_sample(format.mFormat);
+ * audio_bytes_per_sample(mFormat.mFormat);
if (sinkFrameSize > mixerFrameSize) { // need a sink buffer
mSinkBufferSize = sinkFrameSize * frameCount;
(void)posix_memalign(&mSinkBuffer, 32, mSinkBufferSize);
}
- periodNs = (frameCount * 1000000000LL) / sampleRate; // 1.00
- underrunNs = (frameCount * 1750000000LL) / sampleRate; // 1.75
- overrunNs = (frameCount * 500000000LL) / sampleRate; // 0.50
- forceNs = (frameCount * 950000000LL) / sampleRate; // 0.95
- warmupNs = (frameCount * 500000000LL) / sampleRate; // 0.50
+ mPeriodNs = (frameCount * 1000000000LL) / mSampleRate; // 1.00
+ mUnderrunNs = (frameCount * 1750000000LL) / mSampleRate; // 1.75
+ mOverrunNs = (frameCount * 500000000LL) / mSampleRate; // 0.50
+ mForceNs = (frameCount * 950000000LL) / mSampleRate; // 0.95
+ mWarmupNsMin = (frameCount * 750000000LL) / mSampleRate; // 0.75
+ mWarmupNsMax = (frameCount * 1250000000LL) / mSampleRate; // 1.25
} else {
- periodNs = 0;
- underrunNs = 0;
- overrunNs = 0;
- forceNs = 0;
- warmupNs = 0;
+ mPeriodNs = 0;
+ mUnderrunNs = 0;
+ mOverrunNs = 0;
+ mForceNs = 0;
+ mWarmupNsMin = 0;
+ mWarmupNsMax = LONG_MAX;
}
mMixerBufferState = UNDEFINED;
#if !LOG_NDEBUG
for (unsigned i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
- fastTrackNames[i] = -1;
+ mFastTrackNames[i] = -1;
}
#endif
// we need to reconfigure all active tracks
previousTrackMask = 0;
- fastTracksGen = current->mFastTracksGen - 1;
+ mFastTracksGen = current->mFastTracksGen - 1;
dumpState->mFrameCount = frameCount;
} else {
previousTrackMask = previous->mTrackMask;
@@ -219,7 +222,7 @@
// check for change in active track set
const unsigned currentTrackMask = current->mTrackMask;
dumpState->mTrackMask = currentTrackMask;
- if (current->mFastTracksGen != fastTracksGen) {
+ if (current->mFastTracksGen != mFastTracksGen) {
ALOG_ASSERT(mMixerBuffer != NULL);
int name;
@@ -230,16 +233,16 @@
removedTracks &= ~(1 << i);
const FastTrack* fastTrack = ¤t->mFastTracks[i];
ALOG_ASSERT(fastTrack->mBufferProvider == NULL);
- if (mixer != NULL) {
- name = fastTrackNames[i];
+ if (mMixer != NULL) {
+ name = mFastTrackNames[i];
ALOG_ASSERT(name >= 0);
- mixer->deleteTrackName(name);
+ mMixer->deleteTrackName(name);
}
#if !LOG_NDEBUG
- fastTrackNames[i] = -1;
+ mFastTrackNames[i] = -1;
#endif
// don't reset track dump state, since other side is ignoring it
- generations[i] = fastTrack->mGeneration;
+ mGenerations[i] = fastTrack->mGeneration;
}
// now process added tracks
@@ -249,29 +252,29 @@
addedTracks &= ~(1 << i);
const FastTrack* fastTrack = ¤t->mFastTracks[i];
AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
- ALOG_ASSERT(bufferProvider != NULL && fastTrackNames[i] == -1);
- if (mixer != NULL) {
- name = mixer->getTrackName(fastTrack->mChannelMask,
+ ALOG_ASSERT(bufferProvider != NULL && mFastTrackNames[i] == -1);
+ if (mMixer != NULL) {
+ name = mMixer->getTrackName(fastTrack->mChannelMask,
fastTrack->mFormat, AUDIO_SESSION_OUTPUT_MIX);
ALOG_ASSERT(name >= 0);
- fastTrackNames[i] = name;
- mixer->setBufferProvider(name, bufferProvider);
- mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
+ mFastTrackNames[i] = name;
+ mMixer->setBufferProvider(name, bufferProvider);
+ mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
(void *)mMixerBuffer);
// newly allocated track names default to full scale volume
- mixer->setParameter(
+ mMixer->setParameter(
name,
AudioMixer::TRACK,
AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat);
- mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
+ mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
(void *)(uintptr_t)fastTrack->mFormat);
- mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
+ mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
(void *)(uintptr_t)fastTrack->mChannelMask);
- mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK,
+ mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK,
(void *)(uintptr_t)mSinkChannelMask);
- mixer->enable(name);
+ mMixer->enable(name);
}
- generations[i] = fastTrack->mGeneration;
+ mGenerations[i] = fastTrack->mGeneration;
}
// finally process (potentially) modified tracks; these use the same slot
@@ -281,38 +284,38 @@
int i = __builtin_ctz(modifiedTracks);
modifiedTracks &= ~(1 << i);
const FastTrack* fastTrack = ¤t->mFastTracks[i];
- if (fastTrack->mGeneration != generations[i]) {
+ if (fastTrack->mGeneration != mGenerations[i]) {
// this track was actually modified
AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
ALOG_ASSERT(bufferProvider != NULL);
- if (mixer != NULL) {
- name = fastTrackNames[i];
+ if (mMixer != NULL) {
+ name = mFastTrackNames[i];
ALOG_ASSERT(name >= 0);
- mixer->setBufferProvider(name, bufferProvider);
+ mMixer->setBufferProvider(name, bufferProvider);
if (fastTrack->mVolumeProvider == NULL) {
float f = AudioMixer::UNITY_GAIN_FLOAT;
- mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &f);
- mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &f);
+ mMixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &f);
+ mMixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &f);
}
- mixer->setParameter(name, AudioMixer::RESAMPLE,
+ mMixer->setParameter(name, AudioMixer::RESAMPLE,
AudioMixer::REMOVE, NULL);
- mixer->setParameter(
+ mMixer->setParameter(
name,
AudioMixer::TRACK,
AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat);
- mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
+ mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
(void *)(uintptr_t)fastTrack->mFormat);
- mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
+ mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
(void *)(uintptr_t)fastTrack->mChannelMask);
- mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK,
+ mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK,
(void *)(uintptr_t)mSinkChannelMask);
// already enabled
}
- generations[i] = fastTrack->mGeneration;
+ mGenerations[i] = fastTrack->mGeneration;
}
}
- fastTracksGen = current->mFastTracksGen;
+ mFastTracksGen = current->mFastTracksGen;
dumpState->mNumTracks = popcount(currentTrackMask);
}
@@ -320,12 +323,12 @@
void FastMixer::onWork()
{
- const FastMixerState * const current = (const FastMixerState *) this->current;
- FastMixerDumpState * const dumpState = (FastMixerDumpState *) this->dumpState;
- const FastMixerState::Command command = this->command;
+ const FastMixerState * const current = (const FastMixerState *) mCurrent;
+ FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState;
+ const FastMixerState::Command command = mCommand;
const size_t frameCount = current->mFrameCount;
- if ((command & FastMixerState::MIX) && (mixer != NULL) && isWarm) {
+ if ((command & FastMixerState::MIX) && (mMixer != NULL) && mIsWarm) {
ALOG_ASSERT(mMixerBuffer != NULL);
// for each track, update volume and check for underrun
unsigned currentTrackMask = current->mTrackMask;
@@ -335,9 +338,9 @@
const FastTrack* fastTrack = ¤t->mFastTracks[i];
// Refresh the per-track timestamp
- if (timestampStatus == NO_ERROR) {
+ if (mTimestampStatus == NO_ERROR) {
uint32_t trackFramesWrittenButNotPresented =
- nativeFramesWrittenButNotPresented;
+ mNativeFramesWrittenButNotPresented;
uint32_t trackFramesWritten = fastTrack->mBufferProvider->framesReleased();
// Can't provide an AudioTimestamp before first frame presented,
// or during the brief 32-bit wraparound window
@@ -345,20 +348,20 @@
AudioTimestamp perTrackTimestamp;
perTrackTimestamp.mPosition =
trackFramesWritten - trackFramesWrittenButNotPresented;
- perTrackTimestamp.mTime = timestamp.mTime;
+ perTrackTimestamp.mTime = mTimestamp.mTime;
fastTrack->mBufferProvider->onTimestamp(perTrackTimestamp);
}
}
- int name = fastTrackNames[i];
+ int name = mFastTrackNames[i];
ALOG_ASSERT(name >= 0);
if (fastTrack->mVolumeProvider != NULL) {
gain_minifloat_packed_t vlr = fastTrack->mVolumeProvider->getVolumeLR();
float vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
float vrf = float_from_gain(gain_minifloat_unpack_right(vlr));
- mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &vlf);
- mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &vrf);
+ mMixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &vlf);
+ mMixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &vrf);
}
// FIXME The current implementation of framesReady() for fast tracks
// takes a tryLock, which can block
@@ -379,43 +382,43 @@
if (framesReady == 0) {
underruns.mBitFields.mEmpty++;
underruns.mBitFields.mMostRecent = UNDERRUN_EMPTY;
- mixer->disable(name);
+ mMixer->disable(name);
} else {
// allow mixing partial buffer
underruns.mBitFields.mPartial++;
underruns.mBitFields.mMostRecent = UNDERRUN_PARTIAL;
- mixer->enable(name);
+ mMixer->enable(name);
}
} else {
underruns.mBitFields.mFull++;
underruns.mBitFields.mMostRecent = UNDERRUN_FULL;
- mixer->enable(name);
+ mMixer->enable(name);
}
ftDump->mUnderruns = underruns;
ftDump->mFramesReady = framesReady;
}
int64_t pts;
- if (outputSink == NULL || (OK != outputSink->getNextWriteTimestamp(&pts))) {
+ if (mOutputSink == NULL || (OK != mOutputSink->getNextWriteTimestamp(&pts))) {
pts = AudioBufferProvider::kInvalidPTS;
}
// process() is CPU-bound
- mixer->process(pts);
+ mMixer->process(pts);
mMixerBufferState = MIXED;
} else if (mMixerBufferState == MIXED) {
mMixerBufferState = UNDEFINED;
}
//bool didFullWrite = false; // dumpsys could display a count of partial writes
- if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mMixerBuffer != NULL)) {
+ if ((command & FastMixerState::WRITE) && (mOutputSink != NULL) && (mMixerBuffer != NULL)) {
if (mMixerBufferState == UNDEFINED) {
memset(mMixerBuffer, 0, mMixerBufferSize);
mMixerBufferState = ZEROED;
}
void *buffer = mSinkBuffer != NULL ? mSinkBuffer : mMixerBuffer;
- if (format.mFormat != mMixerBufferFormat) { // sink format not the same as mixer format
- memcpy_by_audio_format(buffer, format.mFormat, mMixerBuffer, mMixerBufferFormat,
- frameCount * Format_channelCount(format));
+ if (mFormat.mFormat != mMixerBufferFormat) { // sink format not the same as mixer format
+ memcpy_by_audio_format(buffer, mFormat.mFormat, mMixerBuffer, mMixerBufferFormat,
+ frameCount * Format_channelCount(mFormat));
}
// if non-NULL, then duplicate write() to this non-blocking sink
NBAIO_Sink* teeSink;
@@ -426,252 +429,34 @@
// but this code should be modified to handle both non-blocking and blocking sinks
dumpState->mWriteSequence++;
ATRACE_BEGIN("write");
- ssize_t framesWritten = outputSink->write(buffer, frameCount);
+ ssize_t framesWritten = mOutputSink->write(buffer, frameCount);
ATRACE_END();
dumpState->mWriteSequence++;
if (framesWritten >= 0) {
ALOG_ASSERT((size_t) framesWritten <= frameCount);
- totalNativeFramesWritten += framesWritten;
- dumpState->mFramesWritten = totalNativeFramesWritten;
+ mTotalNativeFramesWritten += framesWritten;
+ dumpState->mFramesWritten = mTotalNativeFramesWritten;
//if ((size_t) framesWritten == frameCount) {
// didFullWrite = true;
//}
} else {
dumpState->mWriteErrors++;
}
- attemptedWrite = true;
+ mAttemptedWrite = true;
// FIXME count # of writes blocked excessively, CPU usage, etc. for dump
- timestampStatus = outputSink->getTimestamp(timestamp);
- if (timestampStatus == NO_ERROR) {
- uint32_t totalNativeFramesPresented = timestamp.mPosition;
- if (totalNativeFramesPresented <= totalNativeFramesWritten) {
- nativeFramesWrittenButNotPresented =
- totalNativeFramesWritten - totalNativeFramesPresented;
+ mTimestampStatus = mOutputSink->getTimestamp(mTimestamp);
+ if (mTimestampStatus == NO_ERROR) {
+ uint32_t totalNativeFramesPresented = mTimestamp.mPosition;
+ if (totalNativeFramesPresented <= mTotalNativeFramesWritten) {
+ mNativeFramesWrittenButNotPresented =
+ mTotalNativeFramesWritten - totalNativeFramesPresented;
} else {
// HAL reported that more frames were presented than were written
- timestampStatus = INVALID_OPERATION;
+ mTimestampStatus = INVALID_OPERATION;
}
}
}
}
-FastMixerDumpState::FastMixerDumpState(
-#ifdef FAST_MIXER_STATISTICS
- uint32_t samplingN
-#endif
- ) : FastThreadDumpState(),
- mWriteSequence(0), mFramesWritten(0),
- mNumTracks(0), mWriteErrors(0),
- mSampleRate(0), mFrameCount(0),
- mTrackMask(0)
-{
-#ifdef FAST_MIXER_STATISTICS
- increaseSamplingN(samplingN);
-#endif
-}
-
-#ifdef FAST_MIXER_STATISTICS
-void FastMixerDumpState::increaseSamplingN(uint32_t samplingN)
-{
- if (samplingN <= mSamplingN || samplingN > kSamplingN || roundup(samplingN) != samplingN) {
- return;
- }
- uint32_t additional = samplingN - mSamplingN;
- // sample arrays aren't accessed atomically with respect to the bounds,
- // so clearing reduces chance for dumpsys to read random uninitialized samples
- memset(&mMonotonicNs[mSamplingN], 0, sizeof(mMonotonicNs[0]) * additional);
- memset(&mLoadNs[mSamplingN], 0, sizeof(mLoadNs[0]) * additional);
-#ifdef CPU_FREQUENCY_STATISTICS
- memset(&mCpukHz[mSamplingN], 0, sizeof(mCpukHz[0]) * additional);
-#endif
- mSamplingN = samplingN;
-}
-#endif
-
-FastMixerDumpState::~FastMixerDumpState()
-{
-}
-
-// helper function called by qsort()
-static int compare_uint32_t(const void *pa, const void *pb)
-{
- uint32_t a = *(const uint32_t *)pa;
- uint32_t b = *(const uint32_t *)pb;
- if (a < b) {
- return -1;
- } else if (a > b) {
- return 1;
- } else {
- return 0;
- }
-}
-
-void FastMixerDumpState::dump(int fd) const
-{
- if (mCommand == FastMixerState::INITIAL) {
- dprintf(fd, " FastMixer not initialized\n");
- return;
- }
-#define COMMAND_MAX 32
- char string[COMMAND_MAX];
- switch (mCommand) {
- case FastMixerState::INITIAL:
- strcpy(string, "INITIAL");
- break;
- case FastMixerState::HOT_IDLE:
- strcpy(string, "HOT_IDLE");
- break;
- case FastMixerState::COLD_IDLE:
- strcpy(string, "COLD_IDLE");
- break;
- case FastMixerState::EXIT:
- strcpy(string, "EXIT");
- break;
- case FastMixerState::MIX:
- strcpy(string, "MIX");
- break;
- case FastMixerState::WRITE:
- strcpy(string, "WRITE");
- break;
- case FastMixerState::MIX_WRITE:
- strcpy(string, "MIX_WRITE");
- break;
- default:
- snprintf(string, COMMAND_MAX, "%d", mCommand);
- break;
- }
- double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1000.0) +
- (mMeasuredWarmupTs.tv_nsec / 1000000.0);
- double mixPeriodSec = (double) mFrameCount / (double) mSampleRate;
- dprintf(fd, " FastMixer command=%s writeSequence=%u framesWritten=%u\n"
- " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
- " sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n"
- " mixPeriod=%.2f ms\n",
- string, mWriteSequence, mFramesWritten,
- mNumTracks, mWriteErrors, mUnderruns, mOverruns,
- mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles,
- mixPeriodSec * 1e3);
-#ifdef FAST_MIXER_STATISTICS
- // find the interval of valid samples
- uint32_t bounds = mBounds;
- uint32_t newestOpen = bounds & 0xFFFF;
- uint32_t oldestClosed = bounds >> 16;
- uint32_t n = (newestOpen - oldestClosed) & 0xFFFF;
- if (n > mSamplingN) {
- ALOGE("too many samples %u", n);
- n = mSamplingN;
- }
- // statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency,
- // and adjusted CPU load in MHz normalized for CPU clock frequency
- CentralTendencyStatistics wall, loadNs;
-#ifdef CPU_FREQUENCY_STATISTICS
- CentralTendencyStatistics kHz, loadMHz;
- uint32_t previousCpukHz = 0;
-#endif
- // Assuming a normal distribution for cycle times, three standard deviations on either side of
- // the mean account for 99.73% of the population. So if we take each tail to be 1/1000 of the
- // sample set, we get 99.8% combined, or close to three standard deviations.
- static const uint32_t kTailDenominator = 1000;
- uint32_t *tail = n >= kTailDenominator ? new uint32_t[n] : NULL;
- // loop over all the samples
- for (uint32_t j = 0; j < n; ++j) {
- size_t i = oldestClosed++ & (mSamplingN - 1);
- uint32_t wallNs = mMonotonicNs[i];
- if (tail != NULL) {
- tail[j] = wallNs;
- }
- wall.sample(wallNs);
- uint32_t sampleLoadNs = mLoadNs[i];
- loadNs.sample(sampleLoadNs);
-#ifdef CPU_FREQUENCY_STATISTICS
- uint32_t sampleCpukHz = mCpukHz[i];
- // skip bad kHz samples
- if ((sampleCpukHz & ~0xF) != 0) {
- kHz.sample(sampleCpukHz >> 4);
- if (sampleCpukHz == previousCpukHz) {
- double megacycles = (double) sampleLoadNs * (double) (sampleCpukHz >> 4) * 1e-12;
- double adjMHz = megacycles / mixPeriodSec; // _not_ wallNs * 1e9
- loadMHz.sample(adjMHz);
- }
- }
- previousCpukHz = sampleCpukHz;
-#endif
- }
- if (n) {
- dprintf(fd, " Simple moving statistics over last %.1f seconds:\n",
- wall.n() * mixPeriodSec);
- dprintf(fd, " wall clock time in ms per mix cycle:\n"
- " mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
- wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6,
- wall.stddev()*1e-6);
- dprintf(fd, " raw CPU load in us per mix cycle:\n"
- " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
- loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
- loadNs.stddev()*1e-3);
- } else {
- dprintf(fd, " No FastMixer statistics available currently\n");
- }
-#ifdef CPU_FREQUENCY_STATISTICS
- dprintf(fd, " CPU clock frequency in MHz:\n"
- " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
- kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3);
- dprintf(fd, " adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n"
- " mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
- loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev());
-#endif
- if (tail != NULL) {
- qsort(tail, n, sizeof(uint32_t), compare_uint32_t);
- // assume same number of tail samples on each side, left and right
- uint32_t count = n / kTailDenominator;
- CentralTendencyStatistics left, right;
- for (uint32_t i = 0; i < count; ++i) {
- left.sample(tail[i]);
- right.sample(tail[n - (i + 1)]);
- }
- dprintf(fd, " Distribution of mix cycle times in ms for the tails (> ~3 stddev outliers):\n"
- " left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n"
- " right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
- left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6,
- right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6,
- right.stddev()*1e-6);
- delete[] tail;
- }
-#endif
- // The active track mask and track states are updated non-atomically.
- // So if we relied on isActive to decide whether to display,
- // then we might display an obsolete track or omit an active track.
- // Instead we always display all tracks, with an indication
- // of whether we think the track is active.
- uint32_t trackMask = mTrackMask;
- dprintf(fd, " Fast tracks: kMaxFastTracks=%u activeMask=%#x\n",
- FastMixerState::kMaxFastTracks, trackMask);
- dprintf(fd, " Index Active Full Partial Empty Recent Ready\n");
- for (uint32_t i = 0; i < FastMixerState::kMaxFastTracks; ++i, trackMask >>= 1) {
- bool isActive = trackMask & 1;
- const FastTrackDump *ftDump = &mTracks[i];
- const FastTrackUnderruns& underruns = ftDump->mUnderruns;
- const char *mostRecent;
- switch (underruns.mBitFields.mMostRecent) {
- case UNDERRUN_FULL:
- mostRecent = "full";
- break;
- case UNDERRUN_PARTIAL:
- mostRecent = "partial";
- break;
- case UNDERRUN_EMPTY:
- mostRecent = "empty";
- break;
- default:
- mostRecent = "?";
- break;
- }
- dprintf(fd, " %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no",
- (underruns.mBitFields.mFull) & UNDERRUN_MASK,
- (underruns.mBitFields.mPartial) & UNDERRUN_MASK,
- (underruns.mBitFields.mEmpty) & UNDERRUN_MASK,
- mostRecent, ftDump->mFramesReady);
- }
-}
-
} // namespace android
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index fde8c2b..06a68fb 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -17,11 +17,7 @@
#ifndef ANDROID_AUDIO_FAST_MIXER_H
#define ANDROID_AUDIO_FAST_MIXER_H
-#include <linux/futex.h>
-#include <sys/syscall.h>
-#include <utils/Debug.h>
#include "FastThread.h"
-#include <utils/Thread.h>
#include "StateQueue.h"
#include "FastMixerState.h"
#include "FastMixerDumpState.h"
@@ -52,36 +48,39 @@
virtual void onStateChange();
virtual void onWork();
- // FIXME these former local variables need comments and to be renamed to have "m" prefix
- static const FastMixerState initial;
- FastMixerState preIdle; // copy of state before we went into idle
- long slopNs; // accumulated time we've woken up too early (> 0) or too late (< 0)
- int fastTrackNames[FastMixerState::kMaxFastTracks]; // handles used by mixer to identify tracks
- int generations[FastMixerState::kMaxFastTracks]; // last observed mFastTracks[i].mGeneration
- NBAIO_Sink *outputSink;
- int outputSinkGen;
- AudioMixer* mixer;
+ // FIXME these former local variables need comments
+ static const FastMixerState sInitial;
+
+ FastMixerState mPreIdle; // copy of state before we went into idle
+ long mSlopNs; // accumulated time we've woken up too early (> 0) or too late (< 0)
+ int mFastTrackNames[FastMixerState::kMaxFastTracks];
+ // handles used by mixer to identify tracks
+ int mGenerations[FastMixerState::kMaxFastTracks];
+ // last observed mFastTracks[i].mGeneration
+ NBAIO_Sink* mOutputSink;
+ int mOutputSinkGen;
+ AudioMixer* mMixer;
// mSinkBuffer audio format is stored in format.mFormat.
- void* mSinkBuffer; // used for mixer output format translation
+ void* mSinkBuffer; // used for mixer output format translation
// if sink format is different than mixer output.
- size_t mSinkBufferSize;
- uint32_t mSinkChannelCount;
+ size_t mSinkBufferSize;
+ uint32_t mSinkChannelCount;
audio_channel_mask_t mSinkChannelMask;
- void* mMixerBuffer; // mixer output buffer.
- size_t mMixerBufferSize;
- audio_format_t mMixerBufferFormat; // mixer output format: AUDIO_FORMAT_PCM_(16_BIT|FLOAT).
+ void* mMixerBuffer; // mixer output buffer.
+ size_t mMixerBufferSize;
+ audio_format_t mMixerBufferFormat; // mixer output format: AUDIO_FORMAT_PCM_(16_BIT|FLOAT).
enum {UNDEFINED, MIXED, ZEROED} mMixerBufferState;
- NBAIO_Format format;
- unsigned sampleRate;
- int fastTracksGen;
- FastMixerDumpState dummyDumpState;
- uint32_t totalNativeFramesWritten; // copied to dumpState->mFramesWritten
+ NBAIO_Format mFormat;
+ unsigned mSampleRate;
+ int mFastTracksGen;
+ FastMixerDumpState mDummyFastMixerDumpState;
+ uint32_t mTotalNativeFramesWritten; // copied to dumpState->mFramesWritten
// next 2 fields are valid only when timestampStatus == NO_ERROR
- AudioTimestamp timestamp;
- uint32_t nativeFramesWrittenButNotPresented;
+ AudioTimestamp mTimestamp;
+ uint32_t mNativeFramesWrittenButNotPresented;
}; // class FastMixer
diff --git a/services/audioflinger/FastMixerDumpState.cpp b/services/audioflinger/FastMixerDumpState.cpp
new file mode 100644
index 0000000..65fbf2b
--- /dev/null
+++ b/services/audioflinger/FastMixerDumpState.cpp
@@ -0,0 +1,199 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "FastMixerDumpState"
+//#define LOG_NDEBUG 0
+
+#include "Configuration.h"
+#ifdef FAST_THREAD_STATISTICS
+#include <cpustats/CentralTendencyStatistics.h>
+#ifdef CPU_FREQUENCY_STATISTICS
+#include <cpustats/ThreadCpuUsage.h>
+#endif
+#endif
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include "FastMixerDumpState.h"
+
+namespace android {
+
+FastMixerDumpState::FastMixerDumpState() : FastThreadDumpState(),
+ mWriteSequence(0), mFramesWritten(0),
+ mNumTracks(0), mWriteErrors(0),
+ mSampleRate(0), mFrameCount(0),
+ mTrackMask(0)
+{
+}
+
+FastMixerDumpState::~FastMixerDumpState()
+{
+}
+
+// helper function called by qsort()
+static int compare_uint32_t(const void *pa, const void *pb)
+{
+ uint32_t a = *(const uint32_t *)pa;
+ uint32_t b = *(const uint32_t *)pb;
+ if (a < b) {
+ return -1;
+ } else if (a > b) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void FastMixerDumpState::dump(int fd) const
+{
+ if (mCommand == FastMixerState::INITIAL) {
+ dprintf(fd, " FastMixer not initialized\n");
+ return;
+ }
+ double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1000.0) +
+ (mMeasuredWarmupTs.tv_nsec / 1000000.0);
+ double mixPeriodSec = (double) mFrameCount / (double) mSampleRate;
+ dprintf(fd, " FastMixer command=%s writeSequence=%u framesWritten=%u\n"
+ " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
+ " sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n"
+ " mixPeriod=%.2f ms\n",
+ FastMixerState::commandToString(mCommand), mWriteSequence, mFramesWritten,
+ mNumTracks, mWriteErrors, mUnderruns, mOverruns,
+ mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles,
+ mixPeriodSec * 1e3);
+#ifdef FAST_THREAD_STATISTICS
+ // find the interval of valid samples
+ uint32_t bounds = mBounds;
+ uint32_t newestOpen = bounds & 0xFFFF;
+ uint32_t oldestClosed = bounds >> 16;
+ uint32_t n = (newestOpen - oldestClosed) & 0xFFFF;
+ if (n > mSamplingN) {
+ ALOGE("too many samples %u", n);
+ n = mSamplingN;
+ }
+ // statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency,
+ // and adjusted CPU load in MHz normalized for CPU clock frequency
+ CentralTendencyStatistics wall, loadNs;
+#ifdef CPU_FREQUENCY_STATISTICS
+ CentralTendencyStatistics kHz, loadMHz;
+ uint32_t previousCpukHz = 0;
+#endif
+ // Assuming a normal distribution for cycle times, three standard deviations on either side of
+ // the mean account for 99.73% of the population. So if we take each tail to be 1/1000 of the
+ // sample set, we get 99.8% combined, or close to three standard deviations.
+ static const uint32_t kTailDenominator = 1000;
+ uint32_t *tail = n >= kTailDenominator ? new uint32_t[n] : NULL;
+ // loop over all the samples
+ for (uint32_t j = 0; j < n; ++j) {
+ size_t i = oldestClosed++ & (mSamplingN - 1);
+ uint32_t wallNs = mMonotonicNs[i];
+ if (tail != NULL) {
+ tail[j] = wallNs;
+ }
+ wall.sample(wallNs);
+ uint32_t sampleLoadNs = mLoadNs[i];
+ loadNs.sample(sampleLoadNs);
+#ifdef CPU_FREQUENCY_STATISTICS
+ uint32_t sampleCpukHz = mCpukHz[i];
+ // skip bad kHz samples
+ if ((sampleCpukHz & ~0xF) != 0) {
+ kHz.sample(sampleCpukHz >> 4);
+ if (sampleCpukHz == previousCpukHz) {
+ double megacycles = (double) sampleLoadNs * (double) (sampleCpukHz >> 4) * 1e-12;
+ double adjMHz = megacycles / mixPeriodSec; // _not_ wallNs * 1e9
+ loadMHz.sample(adjMHz);
+ }
+ }
+ previousCpukHz = sampleCpukHz;
+#endif
+ }
+ if (n) {
+ dprintf(fd, " Simple moving statistics over last %.1f seconds:\n",
+ wall.n() * mixPeriodSec);
+ dprintf(fd, " wall clock time in ms per mix cycle:\n"
+ " mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
+ wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6,
+ wall.stddev()*1e-6);
+ dprintf(fd, " raw CPU load in us per mix cycle:\n"
+ " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
+ loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
+ loadNs.stddev()*1e-3);
+ } else {
+ dprintf(fd, " No FastMixer statistics available currently\n");
+ }
+#ifdef CPU_FREQUENCY_STATISTICS
+ dprintf(fd, " CPU clock frequency in MHz:\n"
+ " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
+ kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3);
+ dprintf(fd, " adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n"
+ " mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
+ loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev());
+#endif
+ if (tail != NULL) {
+ qsort(tail, n, sizeof(uint32_t), compare_uint32_t);
+ // assume same number of tail samples on each side, left and right
+ uint32_t count = n / kTailDenominator;
+ CentralTendencyStatistics left, right;
+ for (uint32_t i = 0; i < count; ++i) {
+ left.sample(tail[i]);
+ right.sample(tail[n - (i + 1)]);
+ }
+ dprintf(fd, " Distribution of mix cycle times in ms for the tails "
+ "(> ~3 stddev outliers):\n"
+ " left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n"
+ " right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
+ left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6,
+ right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6,
+ right.stddev()*1e-6);
+ delete[] tail;
+ }
+#endif
+ // The active track mask and track states are updated non-atomically.
+ // So if we relied on isActive to decide whether to display,
+ // then we might display an obsolete track or omit an active track.
+ // Instead we always display all tracks, with an indication
+ // of whether we think the track is active.
+ uint32_t trackMask = mTrackMask;
+ dprintf(fd, " Fast tracks: kMaxFastTracks=%u activeMask=%#x\n",
+ FastMixerState::kMaxFastTracks, trackMask);
+ dprintf(fd, " Index Active Full Partial Empty Recent Ready\n");
+ for (uint32_t i = 0; i < FastMixerState::kMaxFastTracks; ++i, trackMask >>= 1) {
+ bool isActive = trackMask & 1;
+ const FastTrackDump *ftDump = &mTracks[i];
+ const FastTrackUnderruns& underruns = ftDump->mUnderruns;
+ const char *mostRecent;
+ switch (underruns.mBitFields.mMostRecent) {
+ case UNDERRUN_FULL:
+ mostRecent = "full";
+ break;
+ case UNDERRUN_PARTIAL:
+ mostRecent = "partial";
+ break;
+ case UNDERRUN_EMPTY:
+ mostRecent = "empty";
+ break;
+ default:
+ mostRecent = "?";
+ break;
+ }
+ dprintf(fd, " %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no",
+ (underruns.mBitFields.mFull) & UNDERRUN_MASK,
+ (underruns.mBitFields.mPartial) & UNDERRUN_MASK,
+ (underruns.mBitFields.mEmpty) & UNDERRUN_MASK,
+ mostRecent, ftDump->mFramesReady);
+ }
+}
+
+} // android
diff --git a/services/audioflinger/FastMixerDumpState.h b/services/audioflinger/FastMixerDumpState.h
index 6a1e4649..ac15e7c 100644
--- a/services/audioflinger/FastMixerDumpState.h
+++ b/services/audioflinger/FastMixerDumpState.h
@@ -17,7 +17,10 @@
#ifndef ANDROID_AUDIO_FAST_MIXER_DUMP_STATE_H
#define ANDROID_AUDIO_FAST_MIXER_DUMP_STATE_H
+#include <stdint.h>
#include "Configuration.h"
+#include "FastThreadDumpState.h"
+#include "FastMixerState.h"
namespace android {
@@ -52,22 +55,12 @@
struct FastTrackDump {
FastTrackDump() : mFramesReady(0) { }
/*virtual*/ ~FastTrackDump() { }
- FastTrackUnderruns mUnderruns;
- size_t mFramesReady; // most recent value only; no long-term statistics kept
+ FastTrackUnderruns mUnderruns;
+ size_t mFramesReady; // most recent value only; no long-term statistics kept
};
-// The FastMixerDumpState keeps a cache of FastMixer statistics that can be logged by dumpsys.
-// Each individual native word-sized field is accessed atomically. But the
-// overall structure is non-atomic, that is there may be an inconsistency between fields.
-// No barriers or locks are used for either writing or reading.
-// Only POD types are permitted, and the contents shouldn't be trusted (i.e. do range checks).
-// It has a different lifetime than the FastMixer, and so it can't be a member of FastMixer.
struct FastMixerDumpState : FastThreadDumpState {
- FastMixerDumpState(
-#ifdef FAST_MIXER_STATISTICS
- uint32_t samplingN = kSamplingNforLowRamDevice
-#endif
- );
+ FastMixerDumpState();
/*virtual*/ ~FastMixerDumpState();
void dump(int fd) const; // should only be called on a stable copy, not the original
@@ -80,14 +73,6 @@
size_t mFrameCount;
uint32_t mTrackMask; // mask of active tracks
FastTrackDump mTracks[FastMixerState::kMaxFastTracks];
-
-#ifdef FAST_MIXER_STATISTICS
- // Compile-time constant for a "low RAM device", must be a power of 2 <= kSamplingN.
- // This value was chosen such that each array uses 1 small page (4 Kbytes).
- static const uint32_t kSamplingNforLowRamDevice = 0x400;
- // Increase sampling window after construction, must be a power of 2 <= kSamplingN
- void increaseSamplingN(uint32_t samplingN);
-#endif
};
} // android
diff --git a/services/audioflinger/FastMixerState.cpp b/services/audioflinger/FastMixerState.cpp
index 3aa8dad..a8c2634 100644
--- a/services/audioflinger/FastMixerState.cpp
+++ b/services/audioflinger/FastMixerState.cpp
@@ -39,4 +39,19 @@
{
}
+// static
+const char *FastMixerState::commandToString(Command command)
+{
+ const char *str = FastThreadState::commandToString(command);
+ if (str != NULL) {
+ return str;
+ }
+ switch (command) {
+ case FastMixerState::MIX: return "MIX";
+ case FastMixerState::WRITE: return "WRITE";
+ case FastMixerState::MIX_WRITE: return "MIX_WRITE";
+ }
+ LOG_ALWAYS_FATAL("%s", __func__);
+}
+
} // namespace android
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
index 661c9ca..916514f 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -73,6 +73,9 @@
// This might be a one-time configuration rather than per-state
NBAIO_Sink* mTeeSink; // if non-NULL, then duplicate write()s to this non-blocking sink
+
+ // never returns NULL; asserts if command is invalid
+ static const char *commandToString(Command command);
}; // struct FastMixerState
} // namespace android
diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp
index 216dace..5ca579b 100644
--- a/services/audioflinger/FastThread.cpp
+++ b/services/audioflinger/FastThread.cpp
@@ -25,54 +25,58 @@
#include <utils/Log.h>
#include <utils/Trace.h>
#include "FastThread.h"
+#include "FastThreadDumpState.h"
#define FAST_DEFAULT_NS 999999999L // ~1 sec: default time to sleep
#define FAST_HOT_IDLE_NS 1000000L // 1 ms: time to sleep while hot idling
-#define MIN_WARMUP_CYCLES 2 // minimum number of loop cycles to wait for warmup
+#define MIN_WARMUP_CYCLES 2 // minimum number of consecutive in-range loop cycles
+ // to wait for warmup
#define MAX_WARMUP_CYCLES 10 // maximum number of loop cycles to wait for warmup
namespace android {
FastThread::FastThread() : Thread(false /*canCallJava*/),
- // re-initialized to &initial by subclass constructor
- previous(NULL), current(NULL),
- /* oldTs({0, 0}), */
- oldTsValid(false),
- sleepNs(-1),
- periodNs(0),
- underrunNs(0),
- overrunNs(0),
- forceNs(0),
- warmupNs(0),
- // re-initialized to &dummyDumpState by subclass constructor
+ // re-initialized to &sInitial by subclass constructor
+ mPrevious(NULL), mCurrent(NULL),
+ /* mOldTs({0, 0}), */
+ mOldTsValid(false),
+ mSleepNs(-1),
+ mPeriodNs(0),
+ mUnderrunNs(0),
+ mOverrunNs(0),
+ mForceNs(0),
+ mWarmupNsMin(0),
+ mWarmupNsMax(LONG_MAX),
+ // re-initialized to &mDummySubclassDumpState by subclass constructor
mDummyDumpState(NULL),
- dumpState(NULL),
- ignoreNextOverrun(true),
-#ifdef FAST_MIXER_STATISTICS
- // oldLoad
- oldLoadValid(false),
- bounds(0),
- full(false),
- // tcu
+ mDumpState(NULL),
+ mIgnoreNextOverrun(true),
+#ifdef FAST_THREAD_STATISTICS
+ // mOldLoad
+ mOldLoadValid(false),
+ mBounds(0),
+ mFull(false),
+ // mTcu
#endif
- coldGen(0),
- isWarm(false),
- /* measuredWarmupTs({0, 0}), */
- warmupCycles(0),
- // dummyLogWriter
- logWriter(&dummyLogWriter),
- timestampStatus(INVALID_OPERATION),
+ mColdGen(0),
+ mIsWarm(false),
+ /* mMeasuredWarmupTs({0, 0}), */
+ mWarmupCycles(0),
+ mWarmupConsecutiveInRangeCycles(0),
+ // mDummyLogWriter
+ mLogWriter(&mDummyLogWriter),
+ mTimestampStatus(INVALID_OPERATION),
- command(FastThreadState::INITIAL),
+ mCommand(FastThreadState::INITIAL),
#if 0
frameCount(0),
#endif
- attemptedWrite(false)
+ mAttemptedWrite(false)
{
- oldTs.tv_sec = 0;
- oldTs.tv_nsec = 0;
- measuredWarmupTs.tv_sec = 0;
- measuredWarmupTs.tv_nsec = 0;
+ mOldTs.tv_sec = 0;
+ mOldTs.tv_nsec = 0;
+ mMeasuredWarmupTs.tv_sec = 0;
+ mMeasuredWarmupTs.tv_nsec = 0;
}
FastThread::~FastThread()
@@ -84,34 +88,34 @@
for (;;) {
// either nanosleep, sched_yield, or busy wait
- if (sleepNs >= 0) {
- if (sleepNs > 0) {
- ALOG_ASSERT(sleepNs < 1000000000);
- const struct timespec req = {0, sleepNs};
+ if (mSleepNs >= 0) {
+ if (mSleepNs > 0) {
+ ALOG_ASSERT(mSleepNs < 1000000000);
+ const struct timespec req = {0, mSleepNs};
nanosleep(&req, NULL);
} else {
sched_yield();
}
}
// default to long sleep for next cycle
- sleepNs = FAST_DEFAULT_NS;
+ mSleepNs = FAST_DEFAULT_NS;
// poll for state change
const FastThreadState *next = poll();
if (next == NULL) {
// continue to use the default initial state until a real state is available
- // FIXME &initial not available, should save address earlier
- //ALOG_ASSERT(current == &initial && previous == &initial);
- next = current;
+ // FIXME &sInitial not available, should save address earlier
+ //ALOG_ASSERT(mCurrent == &sInitial && previous == &sInitial);
+ next = mCurrent;
}
- command = next->mCommand;
- if (next != current) {
+ mCommand = next->mCommand;
+ if (next != mCurrent) {
// As soon as possible of learning of a new dump area, start using it
- dumpState = next->mDumpState != NULL ? next->mDumpState : mDummyDumpState;
- logWriter = next->mNBLogWriter != NULL ? next->mNBLogWriter : &dummyLogWriter;
- setLog(logWriter);
+ mDumpState = next->mDumpState != NULL ? next->mDumpState : mDummyDumpState;
+ mLogWriter = next->mNBLogWriter != NULL ? next->mNBLogWriter : &mDummyLogWriter;
+ setLog(mLogWriter);
// We want to always have a valid reference to the previous (non-idle) state.
// However, the state queue only guarantees access to current and previous states.
@@ -122,37 +126,38 @@
// non-idle -> idle update previous from copy of current
// idle -> idle don't update previous
// idle -> non-idle don't update previous
- if (!(current->mCommand & FastThreadState::IDLE)) {
- if (command & FastThreadState::IDLE) {
+ if (!(mCurrent->mCommand & FastThreadState::IDLE)) {
+ if (mCommand & FastThreadState::IDLE) {
onIdle();
- oldTsValid = false;
-#ifdef FAST_MIXER_STATISTICS
- oldLoadValid = false;
+ mOldTsValid = false;
+#ifdef FAST_THREAD_STATISTICS
+ mOldLoadValid = false;
#endif
- ignoreNextOverrun = true;
+ mIgnoreNextOverrun = true;
}
- previous = current;
+ mPrevious = mCurrent;
}
- current = next;
+ mCurrent = next;
}
#if !LOG_NDEBUG
next = NULL; // not referenced again
#endif
- dumpState->mCommand = command;
+ mDumpState->mCommand = mCommand;
+ // FIXME what does this comment mean?
// << current, previous, command, dumpState >>
- switch (command) {
+ switch (mCommand) {
case FastThreadState::INITIAL:
case FastThreadState::HOT_IDLE:
- sleepNs = FAST_HOT_IDLE_NS;
+ mSleepNs = FAST_HOT_IDLE_NS;
continue;
case FastThreadState::COLD_IDLE:
// only perform a cold idle command once
// FIXME consider checking previous state and only perform if previous != COLD_IDLE
- if (current->mColdGen != coldGen) {
- int32_t *coldFutexAddr = current->mColdFutexAddr;
+ if (mCurrent->mColdGen != mColdGen) {
+ int32_t *coldFutexAddr = mCurrent->mColdFutexAddr;
ALOG_ASSERT(coldFutexAddr != NULL);
int32_t old = android_atomic_dec(coldFutexAddr);
if (old <= 0) {
@@ -164,41 +169,42 @@
}
// This may be overly conservative; there could be times that the normal mixer
// requests such a brief cold idle that it doesn't require resetting this flag.
- isWarm = false;
- measuredWarmupTs.tv_sec = 0;
- measuredWarmupTs.tv_nsec = 0;
- warmupCycles = 0;
- sleepNs = -1;
- coldGen = current->mColdGen;
-#ifdef FAST_MIXER_STATISTICS
- bounds = 0;
- full = false;
+ mIsWarm = false;
+ mMeasuredWarmupTs.tv_sec = 0;
+ mMeasuredWarmupTs.tv_nsec = 0;
+ mWarmupCycles = 0;
+ mWarmupConsecutiveInRangeCycles = 0;
+ mSleepNs = -1;
+ mColdGen = mCurrent->mColdGen;
+#ifdef FAST_THREAD_STATISTICS
+ mBounds = 0;
+ mFull = false;
#endif
- oldTsValid = !clock_gettime(CLOCK_MONOTONIC, &oldTs);
- timestampStatus = INVALID_OPERATION;
+ mOldTsValid = !clock_gettime(CLOCK_MONOTONIC, &mOldTs);
+ mTimestampStatus = INVALID_OPERATION;
} else {
- sleepNs = FAST_HOT_IDLE_NS;
+ mSleepNs = FAST_HOT_IDLE_NS;
}
continue;
case FastThreadState::EXIT:
onExit();
return false;
default:
- LOG_ALWAYS_FATAL_IF(!isSubClassCommand(command));
+ LOG_ALWAYS_FATAL_IF(!isSubClassCommand(mCommand));
break;
}
// there is a non-idle state available to us; did the state change?
- if (current != previous) {
+ if (mCurrent != mPrevious) {
onStateChange();
#if 1 // FIXME shouldn't need this
// only process state change once
- previous = current;
+ mPrevious = mCurrent;
#endif
}
// do work using current state here
- attemptedWrite = false;
+ mAttemptedWrite = false;
onWork();
// To be exactly periodic, compute the next sleep time based on current time.
@@ -207,13 +213,13 @@
struct timespec newTs;
int rc = clock_gettime(CLOCK_MONOTONIC, &newTs);
if (rc == 0) {
- //logWriter->logTimestamp(newTs);
- if (oldTsValid) {
- time_t sec = newTs.tv_sec - oldTs.tv_sec;
- long nsec = newTs.tv_nsec - oldTs.tv_nsec;
+ //mLogWriter->logTimestamp(newTs);
+ if (mOldTsValid) {
+ time_t sec = newTs.tv_sec - mOldTs.tv_sec;
+ long nsec = newTs.tv_nsec - mOldTs.tv_nsec;
ALOGE_IF(sec < 0 || (sec == 0 && nsec < 0),
"clock_gettime(CLOCK_MONOTONIC) failed: was %ld.%09ld but now %ld.%09ld",
- oldTs.tv_sec, oldTs.tv_nsec, newTs.tv_sec, newTs.tv_nsec);
+ mOldTs.tv_sec, mOldTs.tv_nsec, newTs.tv_sec, newTs.tv_nsec);
if (nsec < 0) {
--sec;
nsec += 1000000000;
@@ -221,62 +227,70 @@
// To avoid an initial underrun on fast tracks after exiting standby,
// do not start pulling data from tracks and mixing until warmup is complete.
// Warmup is considered complete after the earlier of:
- // MIN_WARMUP_CYCLES write() attempts and last one blocks for at least warmupNs
+ // MIN_WARMUP_CYCLES consecutive in-range write() attempts,
+ // where "in-range" means mWarmupNsMin <= cycle time <= mWarmupNsMax
// MAX_WARMUP_CYCLES write() attempts.
// This is overly conservative, but to get better accuracy requires a new HAL API.
- if (!isWarm && attemptedWrite) {
- measuredWarmupTs.tv_sec += sec;
- measuredWarmupTs.tv_nsec += nsec;
- if (measuredWarmupTs.tv_nsec >= 1000000000) {
- measuredWarmupTs.tv_sec++;
- measuredWarmupTs.tv_nsec -= 1000000000;
+ if (!mIsWarm && mAttemptedWrite) {
+ mMeasuredWarmupTs.tv_sec += sec;
+ mMeasuredWarmupTs.tv_nsec += nsec;
+ if (mMeasuredWarmupTs.tv_nsec >= 1000000000) {
+ mMeasuredWarmupTs.tv_sec++;
+ mMeasuredWarmupTs.tv_nsec -= 1000000000;
}
- ++warmupCycles;
- if ((nsec > warmupNs && warmupCycles >= MIN_WARMUP_CYCLES) ||
- (warmupCycles >= MAX_WARMUP_CYCLES)) {
- isWarm = true;
- dumpState->mMeasuredWarmupTs = measuredWarmupTs;
- dumpState->mWarmupCycles = warmupCycles;
+ ++mWarmupCycles;
+ if (mWarmupNsMin <= nsec && nsec <= mWarmupNsMax) {
+ ALOGV("warmup cycle %d in range: %.03f ms", mWarmupCycles, nsec * 1e-9);
+ ++mWarmupConsecutiveInRangeCycles;
+ } else {
+ ALOGV("warmup cycle %d out of range: %.03f ms", mWarmupCycles, nsec * 1e-9);
+ mWarmupConsecutiveInRangeCycles = 0;
+ }
+ if ((mWarmupConsecutiveInRangeCycles >= MIN_WARMUP_CYCLES) ||
+ (mWarmupCycles >= MAX_WARMUP_CYCLES)) {
+ mIsWarm = true;
+ mDumpState->mMeasuredWarmupTs = mMeasuredWarmupTs;
+ mDumpState->mWarmupCycles = mWarmupCycles;
}
}
- sleepNs = -1;
- if (isWarm) {
- if (sec > 0 || nsec > underrunNs) {
+ mSleepNs = -1;
+ if (mIsWarm) {
+ if (sec > 0 || nsec > mUnderrunNs) {
ATRACE_NAME("underrun");
// FIXME only log occasionally
ALOGV("underrun: time since last cycle %d.%03ld sec",
(int) sec, nsec / 1000000L);
- dumpState->mUnderruns++;
- ignoreNextOverrun = true;
- } else if (nsec < overrunNs) {
- if (ignoreNextOverrun) {
- ignoreNextOverrun = false;
+ mDumpState->mUnderruns++;
+ mIgnoreNextOverrun = true;
+ } else if (nsec < mOverrunNs) {
+ if (mIgnoreNextOverrun) {
+ mIgnoreNextOverrun = false;
} else {
// FIXME only log occasionally
ALOGV("overrun: time since last cycle %d.%03ld sec",
(int) sec, nsec / 1000000L);
- dumpState->mOverruns++;
+ mDumpState->mOverruns++;
}
// This forces a minimum cycle time. It:
// - compensates for an audio HAL with jitter due to sample rate conversion
// - works with a variable buffer depth audio HAL that never pulls at a
- // rate < than overrunNs per buffer.
+ // rate < than mOverrunNs per buffer.
// - recovers from overrun immediately after underrun
// It doesn't work with a non-blocking audio HAL.
- sleepNs = forceNs - nsec;
+ mSleepNs = mForceNs - nsec;
} else {
- ignoreNextOverrun = false;
+ mIgnoreNextOverrun = false;
}
}
-#ifdef FAST_MIXER_STATISTICS
- if (isWarm) {
+#ifdef FAST_THREAD_STATISTICS
+ if (mIsWarm) {
// advance the FIFO queue bounds
- size_t i = bounds & (dumpState->mSamplingN - 1);
- bounds = (bounds & 0xFFFF0000) | ((bounds + 1) & 0xFFFF);
- if (full) {
- bounds += 0x10000;
- } else if (!(bounds & (dumpState->mSamplingN - 1))) {
- full = true;
+ size_t i = mBounds & (mDumpState->mSamplingN - 1);
+ mBounds = (mBounds & 0xFFFF0000) | ((mBounds + 1) & 0xFFFF);
+ if (mFull) {
+ mBounds += 0x10000;
+ } else if (!(mBounds & (mDumpState->mSamplingN - 1))) {
+ mFull = true;
}
// compute the delta value of clock_gettime(CLOCK_MONOTONIC)
uint32_t monotonicNs = nsec;
@@ -288,9 +302,9 @@
struct timespec newLoad;
rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &newLoad);
if (rc == 0) {
- if (oldLoadValid) {
- sec = newLoad.tv_sec - oldLoad.tv_sec;
- nsec = newLoad.tv_nsec - oldLoad.tv_nsec;
+ if (mOldLoadValid) {
+ sec = newLoad.tv_sec - mOldLoad.tv_sec;
+ nsec = newLoad.tv_nsec - mOldLoad.tv_nsec;
if (nsec < 0) {
--sec;
nsec += 1000000000;
@@ -301,42 +315,42 @@
}
} else {
// first time through the loop
- oldLoadValid = true;
+ mOldLoadValid = true;
}
- oldLoad = newLoad;
+ mOldLoad = newLoad;
}
#ifdef CPU_FREQUENCY_STATISTICS
// get the absolute value of CPU clock frequency in kHz
int cpuNum = sched_getcpu();
- uint32_t kHz = tcu.getCpukHz(cpuNum);
+ uint32_t kHz = mTcu.getCpukHz(cpuNum);
kHz = (kHz << 4) | (cpuNum & 0xF);
#endif
// save values in FIFO queues for dumpsys
// these stores #1, #2, #3 are not atomic with respect to each other,
// or with respect to store #4 below
- dumpState->mMonotonicNs[i] = monotonicNs;
- dumpState->mLoadNs[i] = loadNs;
+ mDumpState->mMonotonicNs[i] = monotonicNs;
+ mDumpState->mLoadNs[i] = loadNs;
#ifdef CPU_FREQUENCY_STATISTICS
- dumpState->mCpukHz[i] = kHz;
+ mDumpState->mCpukHz[i] = kHz;
#endif
// this store #4 is not atomic with respect to stores #1, #2, #3 above, but
// the newest open & oldest closed halves are atomic with respect to each other
- dumpState->mBounds = bounds;
+ mDumpState->mBounds = mBounds;
ATRACE_INT("cycle_ms", monotonicNs / 1000000);
ATRACE_INT("load_us", loadNs / 1000);
}
#endif
} else {
// first time through the loop
- oldTsValid = true;
- sleepNs = periodNs;
- ignoreNextOverrun = true;
+ mOldTsValid = true;
+ mSleepNs = mPeriodNs;
+ mIgnoreNextOverrun = true;
}
- oldTs = newTs;
+ mOldTs = newTs;
} else {
// monotonic clock is broken
- oldTsValid = false;
- sleepNs = periodNs;
+ mOldTsValid = false;
+ mSleepNs = mPeriodNs;
}
} // for (;;)
diff --git a/services/audioflinger/FastThread.h b/services/audioflinger/FastThread.h
index 1330334..2efb6de 100644
--- a/services/audioflinger/FastThread.h
+++ b/services/audioflinger/FastThread.h
@@ -48,42 +48,45 @@
virtual void onStateChange() = 0;
virtual void onWork() = 0;
- // FIXME these former local variables need comments and to be renamed to have an "m" prefix
- const FastThreadState *previous;
- const FastThreadState *current;
- struct timespec oldTs;
- bool oldTsValid;
- long sleepNs; // -1: busy wait, 0: sched_yield, > 0: nanosleep
- long periodNs; // expected period; the time required to render one mix buffer
- long underrunNs; // underrun likely when write cycle is greater than this value
- long overrunNs; // overrun likely when write cycle is less than this value
- long forceNs; // if overrun detected, force the write cycle to take this much time
- long warmupNs; // warmup complete when write cycle is greater than to this value
- FastThreadDumpState *mDummyDumpState;
- FastThreadDumpState *dumpState;
- bool ignoreNextOverrun; // used to ignore initial overrun and first after an underrun
-#ifdef FAST_MIXER_STATISTICS
- struct timespec oldLoad; // previous value of clock_gettime(CLOCK_THREAD_CPUTIME_ID)
- bool oldLoadValid; // whether oldLoad is valid
- uint32_t bounds;
- bool full; // whether we have collected at least mSamplingN samples
+ // FIXME these former local variables need comments
+ const FastThreadState* mPrevious;
+ const FastThreadState* mCurrent;
+ struct timespec mOldTs;
+ bool mOldTsValid;
+ long mSleepNs; // -1: busy wait, 0: sched_yield, > 0: nanosleep
+ long mPeriodNs; // expected period; the time required to render one mix buffer
+ long mUnderrunNs; // underrun likely when write cycle is greater than this value
+ long mOverrunNs; // overrun likely when write cycle is less than this value
+ long mForceNs; // if overrun detected,
+ // force the write cycle to take this much time
+ long mWarmupNsMin; // warmup complete when write cycle is greater than or equal to
+ // this value
+ long mWarmupNsMax; // and less than or equal to this value
+ FastThreadDumpState* mDummyDumpState;
+ FastThreadDumpState* mDumpState;
+ bool mIgnoreNextOverrun; // used to ignore initial overrun and first after an
+ // underrun
+#ifdef FAST_THREAD_STATISTICS
+ struct timespec mOldLoad; // previous value of clock_gettime(CLOCK_THREAD_CPUTIME_ID)
+ bool mOldLoadValid; // whether oldLoad is valid
+ uint32_t mBounds;
+ bool mFull; // whether we have collected at least mSamplingN samples
#ifdef CPU_FREQUENCY_STATISTICS
- ThreadCpuUsage tcu; // for reading the current CPU clock frequency in kHz
+ ThreadCpuUsage mTcu; // for reading the current CPU clock frequency in kHz
#endif
#endif
- unsigned coldGen; // last observed mColdGen
- bool isWarm; // true means ready to mix, false means wait for warmup before mixing
- struct timespec measuredWarmupTs; // how long did it take for warmup to complete
- uint32_t warmupCycles; // counter of number of loop cycles required to warmup
- NBLog::Writer dummyLogWriter;
- NBLog::Writer *logWriter;
- status_t timestampStatus;
+ unsigned mColdGen; // last observed mColdGen
+ bool mIsWarm; // true means ready to mix,
+ // false means wait for warmup before mixing
+ struct timespec mMeasuredWarmupTs; // how long did it take for warmup to complete
+ uint32_t mWarmupCycles; // counter of number of loop cycles during warmup phase
+ uint32_t mWarmupConsecutiveInRangeCycles; // number of consecutive cycles in range
+ NBLog::Writer mDummyLogWriter;
+ NBLog::Writer* mLogWriter;
+ status_t mTimestampStatus;
- FastThreadState::Command command;
-#if 0
- size_t frameCount;
-#endif
- bool attemptedWrite;
+ FastThreadState::Command mCommand;
+ bool mAttemptedWrite;
}; // class FastThread
diff --git a/services/audioflinger/FastThreadDumpState.cpp b/services/audioflinger/FastThreadDumpState.cpp
new file mode 100644
index 0000000..9df5c4c
--- /dev/null
+++ b/services/audioflinger/FastThreadDumpState.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 "FastThreadDumpState.h"
+
+namespace android {
+
+FastThreadDumpState::FastThreadDumpState() :
+ mCommand(FastThreadState::INITIAL), mUnderruns(0), mOverruns(0),
+ /* mMeasuredWarmupTs({0, 0}), */
+ mWarmupCycles(0)
+#ifdef FAST_THREAD_STATISTICS
+ , mSamplingN(0), mBounds(0)
+#endif
+{
+ mMeasuredWarmupTs.tv_sec = 0;
+ mMeasuredWarmupTs.tv_nsec = 0;
+#ifdef FAST_THREAD_STATISTICS
+ increaseSamplingN(1);
+#endif
+}
+
+FastThreadDumpState::~FastThreadDumpState()
+{
+}
+
+#ifdef FAST_THREAD_STATISTICS
+void FastThreadDumpState::increaseSamplingN(uint32_t samplingN)
+{
+ if (samplingN <= mSamplingN || samplingN > kSamplingN || roundup(samplingN) != samplingN) {
+ return;
+ }
+ uint32_t additional = samplingN - mSamplingN;
+ // sample arrays aren't accessed atomically with respect to the bounds,
+ // so clearing reduces chance for dumpsys to read random uninitialized samples
+ memset(&mMonotonicNs[mSamplingN], 0, sizeof(mMonotonicNs[0]) * additional);
+ memset(&mLoadNs[mSamplingN], 0, sizeof(mLoadNs[0]) * additional);
+#ifdef CPU_FREQUENCY_STATISTICS
+ memset(&mCpukHz[mSamplingN], 0, sizeof(mCpukHz[0]) * additional);
+#endif
+ mSamplingN = samplingN;
+}
+#endif
+
+} // android
diff --git a/services/audioflinger/FastThreadDumpState.h b/services/audioflinger/FastThreadDumpState.h
new file mode 100644
index 0000000..1ce0914
--- /dev/null
+++ b/services/audioflinger/FastThreadDumpState.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_AUDIO_FAST_THREAD_DUMP_STATE_H
+#define ANDROID_AUDIO_FAST_THREAD_DUMP_STATE_H
+
+#include "Configuration.h"
+#include "FastThreadState.h"
+
+namespace android {
+
+// The FastThreadDumpState keeps a cache of FastThread statistics that can be logged by dumpsys.
+// Each individual native word-sized field is accessed atomically. But the
+// overall structure is non-atomic, that is there may be an inconsistency between fields.
+// No barriers or locks are used for either writing or reading.
+// Only POD types are permitted, and the contents shouldn't be trusted (i.e. do range checks).
+// It has a different lifetime than the FastThread, and so it can't be a member of FastThread.
+struct FastThreadDumpState {
+ FastThreadDumpState();
+ /*virtual*/ ~FastThreadDumpState();
+
+ FastThreadState::Command mCommand; // current command
+ uint32_t mUnderruns; // total number of underruns
+ uint32_t mOverruns; // total number of overruns
+ struct timespec mMeasuredWarmupTs; // measured warmup time
+ uint32_t mWarmupCycles; // number of loop cycles required to warmup
+
+#ifdef FAST_THREAD_STATISTICS
+ // Recently collected samples of per-cycle monotonic time, thread CPU time, and CPU frequency.
+ // kSamplingN is max size of sampling frame (statistics), and must be a power of 2 <= 0x8000.
+ // The sample arrays are virtually allocated based on this compile-time constant,
+ // but are only initialized and used based on the runtime parameter mSamplingN.
+ static const uint32_t kSamplingN = 0x8000;
+ // Compile-time constant for a "low RAM device", must be a power of 2 <= kSamplingN.
+ // This value was chosen such that each array uses 1 small page (4 Kbytes).
+ static const uint32_t kSamplingNforLowRamDevice = 0x400;
+ // Corresponding runtime maximum size of sample arrays, must be a power of 2 <= kSamplingN.
+ uint32_t mSamplingN;
+ // The bounds define the interval of valid samples, and are represented as follows:
+ // newest open (excluded) endpoint = lower 16 bits of bounds, modulo N
+ // oldest closed (included) endpoint = upper 16 bits of bounds, modulo N
+ // Number of valid samples is newest - oldest.
+ uint32_t mBounds; // bounds for mMonotonicNs, mThreadCpuNs, and mCpukHz
+ // The elements in the *Ns arrays are in units of nanoseconds <= 3999999999.
+ uint32_t mMonotonicNs[kSamplingN]; // delta monotonic (wall clock) time
+ uint32_t mLoadNs[kSamplingN]; // delta CPU load in time
+#ifdef CPU_FREQUENCY_STATISTICS
+ uint32_t mCpukHz[kSamplingN]; // absolute CPU clock frequency in kHz, bits 0-3 are CPU#
+#endif
+
+ // Increase sampling window after construction, must be a power of 2 <= kSamplingN
+ void increaseSamplingN(uint32_t samplingN);
+#endif
+
+}; // struct FastThreadDumpState
+
+} // android
+
+#endif // ANDROID_AUDIO_FAST_THREAD_DUMP_STATE_H
diff --git a/services/audioflinger/FastThreadState.cpp b/services/audioflinger/FastThreadState.cpp
index 6994872..ad5f31f 100644
--- a/services/audioflinger/FastThreadState.cpp
+++ b/services/audioflinger/FastThreadState.cpp
@@ -29,21 +29,16 @@
{
}
-
-FastThreadDumpState::FastThreadDumpState() :
- mCommand(FastThreadState::INITIAL), mUnderruns(0), mOverruns(0),
- /* mMeasuredWarmupTs({0, 0}), */
- mWarmupCycles(0)
-#ifdef FAST_MIXER_STATISTICS
- , mSamplingN(1), mBounds(0)
-#endif
+// static
+const char *FastThreadState::commandToString(FastThreadState::Command command)
{
- mMeasuredWarmupTs.tv_sec = 0;
- mMeasuredWarmupTs.tv_nsec = 0;
-}
-
-FastThreadDumpState::~FastThreadDumpState()
-{
+ switch (command) {
+ case FastThreadState::INITIAL: return "INITIAL";
+ case FastThreadState::HOT_IDLE: return "HOT_IDLE";
+ case FastThreadState::COLD_IDLE: return "COLD_IDLE";
+ case FastThreadState::EXIT: return "EXIT";
+ }
+ return NULL;
}
} // namespace android
diff --git a/services/audioflinger/FastThreadState.h b/services/audioflinger/FastThreadState.h
index 1ab8a0a..f18f846 100644
--- a/services/audioflinger/FastThreadState.h
+++ b/services/audioflinger/FastThreadState.h
@@ -46,43 +46,10 @@
FastThreadDumpState* mDumpState; // if non-NULL, then update dump state periodically
NBLog::Writer* mNBLogWriter; // non-blocking logger
+ // returns NULL if command belongs to a subclass
+ static const char *commandToString(Command command);
}; // struct FastThreadState
-
-// FIXME extract common part of comment at FastMixerDumpState
-struct FastThreadDumpState {
- FastThreadDumpState();
- /*virtual*/ ~FastThreadDumpState();
-
- FastThreadState::Command mCommand; // current command
- uint32_t mUnderruns; // total number of underruns
- uint32_t mOverruns; // total number of overruns
- struct timespec mMeasuredWarmupTs; // measured warmup time
- uint32_t mWarmupCycles; // number of loop cycles required to warmup
-
-#ifdef FAST_MIXER_STATISTICS
- // Recently collected samples of per-cycle monotonic time, thread CPU time, and CPU frequency.
- // kSamplingN is max size of sampling frame (statistics), and must be a power of 2 <= 0x8000.
- // The sample arrays are virtually allocated based on this compile-time constant,
- // but are only initialized and used based on the runtime parameter mSamplingN.
- static const uint32_t kSamplingN = 0x8000;
- // Corresponding runtime maximum size of sample arrays, must be a power of 2 <= kSamplingN.
- uint32_t mSamplingN;
- // The bounds define the interval of valid samples, and are represented as follows:
- // newest open (excluded) endpoint = lower 16 bits of bounds, modulo N
- // oldest closed (included) endpoint = upper 16 bits of bounds, modulo N
- // Number of valid samples is newest - oldest.
- uint32_t mBounds; // bounds for mMonotonicNs, mThreadCpuNs, and mCpukHz
- // The elements in the *Ns arrays are in units of nanoseconds <= 3999999999.
- uint32_t mMonotonicNs[kSamplingN]; // delta monotonic (wall clock) time
- uint32_t mLoadNs[kSamplingN]; // delta CPU load in time
-#ifdef CPU_FREQUENCY_STATISTICS
- uint32_t mCpukHz[kSamplingN]; // absolute CPU clock frequency in kHz, bits 0-3 are CPU#
-#endif
-#endif
-
-}; // struct FastThreadDumpState
-
} // android
#endif // ANDROID_AUDIO_FAST_THREAD_STATE_H
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 4f0c6b1..efbdcff 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -694,4 +694,4 @@
}
-}; // namespace android
+} // namespace android
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index ee48276..902d5e4 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -255,7 +255,7 @@
class Buffer : public AudioBufferProvider::Buffer {
public:
- int16_t *mBuffer;
+ void *mBuffer;
};
OutputTrack(PlaybackThread *thread,
@@ -271,7 +271,7 @@
AudioSystem::SYNC_EVENT_NONE,
int triggerSession = 0);
virtual void stop();
- bool write(int16_t* data, uint32_t frames);
+ bool write(void* data, uint32_t frames);
bool bufferQueueEmpty() const { return mBufferQueue.size() == 0; }
bool isActive() const { return mActive; }
const wp<ThreadBase>& thread() const { return mThread; }
diff --git a/services/audioflinger/StateQueue.cpp b/services/audioflinger/StateQueue.cpp
index 40d7bcd..9d4188f 100644
--- a/services/audioflinger/StateQueue.cpp
+++ b/services/audioflinger/StateQueue.cpp
@@ -48,7 +48,7 @@
, mObserverDump(&mObserverDummyDump), mMutatorDump(&mMutatorDummyDump)
#endif
{
- atomic_init(&mNext, 0);
+ atomic_init(&mNext, static_cast<uintptr_t>(0));
}
template<typename T> StateQueue<T>::~StateQueue()
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 9fccda1..c1da6bc 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -23,7 +23,9 @@
#include "Configuration.h"
#include <math.h>
#include <fcntl.h>
+#include <linux/futex.h>
#include <sys/stat.h>
+#include <sys/syscall.h>
#include <cutils/properties.h>
#include <media/AudioParameter.h>
#include <media/AudioResamplerPublic.h>
@@ -314,6 +316,165 @@
// ThreadBase
// ----------------------------------------------------------------------------
+// static
+const char *AudioFlinger::ThreadBase::threadTypeToString(AudioFlinger::ThreadBase::type_t type)
+{
+ switch (type) {
+ case MIXER:
+ return "MIXER";
+ case DIRECT:
+ return "DIRECT";
+ case DUPLICATING:
+ return "DUPLICATING";
+ case RECORD:
+ return "RECORD";
+ case OFFLOAD:
+ return "OFFLOAD";
+ default:
+ return "unknown";
+ }
+}
+
+String8 devicesToString(audio_devices_t devices)
+{
+ static const struct mapping {
+ 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_TELEPHONY_TX, "TELEPHONY_TX",
+ AUDIO_DEVICE_NONE, "NONE", // must be last
+ }, mappingsIn[] = {
+ AUDIO_DEVICE_IN_BUILTIN_MIC, "BUILTIN_MIC",
+ AUDIO_DEVICE_IN_WIRED_HEADSET, "WIRED_HEADSET",
+ AUDIO_DEVICE_IN_VOICE_CALL, "VOICE_CALL",
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX, "REMOTE_SUBMIX",
+ AUDIO_DEVICE_NONE, "NONE", // must be last
+ };
+ String8 result;
+ audio_devices_t allDevices = AUDIO_DEVICE_NONE;
+ const mapping *entry;
+ if (devices & AUDIO_DEVICE_BIT_IN) {
+ devices &= ~AUDIO_DEVICE_BIT_IN;
+ entry = mappingsIn;
+ } else {
+ entry = mappingsOut;
+ }
+ for ( ; entry->mDevices != AUDIO_DEVICE_NONE; entry++) {
+ allDevices = (audio_devices_t) (allDevices | entry->mDevices);
+ if (devices & entry->mDevices) {
+ if (!result.isEmpty()) {
+ result.append("|");
+ }
+ result.append(entry->mString);
+ }
+ }
+ if (devices & ~allDevices) {
+ if (!result.isEmpty()) {
+ result.append("|");
+ }
+ result.appendFormat("0x%X", devices & ~allDevices);
+ }
+ if (result.isEmpty()) {
+ result.append(entry->mString);
+ }
+ return result;
+}
+
+String8 inputFlagsToString(audio_input_flags_t flags)
+{
+ static const struct mapping {
+ 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
+ };
+ String8 result;
+ audio_input_flags_t allFlags = AUDIO_INPUT_FLAG_NONE;
+ const mapping *entry;
+ for (entry = mappings; entry->mFlag != AUDIO_INPUT_FLAG_NONE; entry++) {
+ allFlags = (audio_input_flags_t) (allFlags | entry->mFlag);
+ if (flags & entry->mFlag) {
+ if (!result.isEmpty()) {
+ result.append("|");
+ }
+ result.append(entry->mString);
+ }
+ }
+ if (flags & ~allFlags) {
+ if (!result.isEmpty()) {
+ result.append("|");
+ }
+ result.appendFormat("0x%X", flags & ~allFlags);
+ }
+ if (result.isEmpty()) {
+ result.append(entry->mString);
+ }
+ return result;
+}
+
+String8 outputFlagsToString(audio_output_flags_t flags)
+{
+ static const struct mapping {
+ 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
+ };
+ String8 result;
+ audio_output_flags_t allFlags = AUDIO_OUTPUT_FLAG_NONE;
+ const mapping *entry;
+ for (entry = mappings; entry->mFlag != AUDIO_OUTPUT_FLAG_NONE; entry++) {
+ allFlags = (audio_output_flags_t) (allFlags | entry->mFlag);
+ if (flags & entry->mFlag) {
+ if (!result.isEmpty()) {
+ result.append("|");
+ }
+ result.append(entry->mString);
+ }
+ }
+ if (flags & ~allFlags) {
+ if (!result.isEmpty()) {
+ result.append("|");
+ }
+ result.appendFormat("0x%X", flags & ~allFlags);
+ }
+ if (result.isEmpty()) {
+ result.append(entry->mString);
+ }
+ return result;
+}
+
+const char *sourceToString(audio_source_t source)
+{
+ switch (source) {
+ case AUDIO_SOURCE_DEFAULT: return "default";
+ case AUDIO_SOURCE_MIC: return "mic";
+ case AUDIO_SOURCE_VOICE_UPLINK: return "voice uplink";
+ case AUDIO_SOURCE_VOICE_DOWNLINK: return "voice downlink";
+ case AUDIO_SOURCE_VOICE_CALL: return "voice call";
+ case AUDIO_SOURCE_CAMCORDER: return "camcorder";
+ 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_FM_TUNER: return "FM tuner";
+ case AUDIO_SOURCE_HOTWORD: return "hotword";
+ default: return "unknown";
+ }
+}
+
AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
audio_devices_t outDevice, audio_devices_t inDevice, type_t type)
: Thread(false /*canCallJava*/),
@@ -338,7 +499,7 @@
// do not lock the mutex in destructor
releaseWakeLock_l();
if (mPowerManager != 0) {
- sp<IBinder> binder = mPowerManager->asBinder();
+ sp<IBinder> binder = IInterface::asBinder(mPowerManager);
binder->unlinkToDeath(mDeathRecipient);
}
}
@@ -577,20 +738,22 @@
bool locked = AudioFlinger::dumpTryLock(mLock);
if (!locked) {
- dprintf(fd, "thread %p maybe dead locked\n", this);
+ dprintf(fd, "thread %p may be deadlocked\n", this);
}
+ dprintf(fd, " Thread name: %s\n", mThreadName);
dprintf(fd, " I/O handle: %d\n", mId);
dprintf(fd, " TID: %d\n", getTid());
dprintf(fd, " Standby: %s\n", mStandby ? "yes" : "no");
- dprintf(fd, " Sample rate: %u\n", mSampleRate);
+ dprintf(fd, " Sample rate: %u Hz\n", mSampleRate);
dprintf(fd, " HAL frame count: %zu\n", mFrameCount);
+ dprintf(fd, " HAL format: 0x%x (%s)\n", mHALFormat, formatToString(mHALFormat));
dprintf(fd, " HAL buffer size: %u bytes\n", mBufferSize);
- dprintf(fd, " Channel Count: %u\n", mChannelCount);
- dprintf(fd, " Channel Mask: 0x%08x (%s)\n", mChannelMask,
+ 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", mHALFormat, formatToString(mHALFormat));
- dprintf(fd, " Frame size: %zu\n", mFrameSize);
+ dprintf(fd, " Format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
+ dprintf(fd, " Frame size: %zu bytes\n", mFrameSize);
dprintf(fd, " Pending config events:");
size_t numConfig = mConfigEvents.size();
if (numConfig) {
@@ -602,6 +765,9 @@
} else {
dprintf(fd, " none\n");
}
+ dprintf(fd, " Output device: %#x (%s)\n", mOutDevice, devicesToString(mOutDevice).string());
+ dprintf(fd, " Input device: %#x (%s)\n", mInDevice, devicesToString(mInDevice).string());
+ dprintf(fd, " Audio source: %d (%s)\n", mAudioSource, sourceToString(mAudioSource));
if (locked) {
mLock.unlock();
@@ -635,19 +801,19 @@
String16 AudioFlinger::ThreadBase::getWakeLockTag()
{
switch (mType) {
- case MIXER:
- return String16("AudioMix");
- case DIRECT:
- return String16("AudioDirectOut");
- case DUPLICATING:
- return String16("AudioDup");
- case RECORD:
- return String16("AudioIn");
- case OFFLOAD:
- return String16("AudioOffload");
- default:
- ALOG_ASSERT(false);
- return String16("AudioUnknown");
+ case MIXER:
+ return String16("AudioMix");
+ case DIRECT:
+ return String16("AudioDirectOut");
+ case DUPLICATING:
+ return String16("AudioDup");
+ case RECORD:
+ return String16("AudioIn");
+ case OFFLOAD:
+ return String16("AudioOffload");
+ default:
+ ALOG_ASSERT(false);
+ return String16("AudioUnknown");
}
}
@@ -674,7 +840,7 @@
if (status == NO_ERROR) {
mWakeLockToken = binder;
}
- ALOGV("acquireWakeLock_l() %s status %d", mName, status);
+ ALOGV("acquireWakeLock_l() %s status %d", mThreadName, status);
}
}
@@ -687,7 +853,7 @@
void AudioFlinger::ThreadBase::releaseWakeLock_l()
{
if (mWakeLockToken != 0) {
- ALOGV("releaseWakeLock_l() %s", mName);
+ ALOGV("releaseWakeLock_l() %s", mThreadName);
if (mPowerManager != 0) {
mPowerManager->releaseWakeLock(mWakeLockToken, 0,
true /* FIXME force oneway contrary to .aidl */);
@@ -708,7 +874,7 @@
sp<IBinder> binder =
defaultServiceManager()->checkService(String16("power"));
if (binder == 0) {
- ALOGW("Thread %s cannot connect to the power manager service", mName);
+ ALOGW("Thread %s cannot connect to the power manager service", mThreadName);
} else {
mPowerManager = interface_cast<IPowerManager>(binder);
binder->linkToDeath(mDeathRecipient);
@@ -728,7 +894,7 @@
status_t status;
status = mPowerManager->updateWakeLockUids(mWakeLockToken, uids.size(), uids.array(),
true /* FIXME force oneway contrary to .aidl */);
- ALOGV("acquireWakeLock_l() %s status %d", mName, status);
+ ALOGV("acquireWakeLock_l() %s status %d", mThreadName, status);
}
}
@@ -912,7 +1078,7 @@
// mSinkBuffer is not guaranteed to be compatible with effect processing (PCM 16 stereo).
if (mType == DIRECT) {
ALOGW("createEffect_l() Cannot add effect %s on Direct output type thread %s",
- desc->name, mName);
+ desc->name, mThreadName);
lStatus = BAD_VALUE;
goto Exit;
}
@@ -936,7 +1102,8 @@
case DUPLICATING:
case RECORD:
default:
- ALOGW("createEffect_l() Cannot add global effect %s on thread %s", desc->name, mName);
+ ALOGW("createEffect_l() Cannot add global effect %s on thread %s",
+ desc->name, mThreadName);
lStatus = BAD_VALUE;
goto Exit;
}
@@ -1201,8 +1368,8 @@
// mLatchD, mLatchQ,
mLatchDValid(false), mLatchQValid(false)
{
- snprintf(mName, kNameLength, "AudioOut_%X", id);
- mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mName);
+ snprintf(mThreadName, kThreadNameLength, "AudioOut_%X", id);
+ mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName);
// Assumes constructor is called by AudioFlinger with it's mLock held, but
// it would be safer to explicitly pass initial masterVolume/masterMute as
@@ -1315,7 +1482,10 @@
void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
{
- dprintf(fd, "\nOutput thread %p:\n", this);
+ dprintf(fd, "\nOutput thread %p type %d (%s):\n", this, type(), threadTypeToString(type()));
+
+ dumpBase(fd, args);
+
dprintf(fd, " Normal frame count: %zu\n", mNormalFrameCount);
dprintf(fd, " Last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
dprintf(fd, " Total writes: %d\n", mNumWrites);
@@ -1326,15 +1496,17 @@
dprintf(fd, " Mixer buffer: %p\n", mMixerBuffer);
dprintf(fd, " Effect buffer: %p\n", mEffectBuffer);
dprintf(fd, " Fast track availMask=%#x\n", mFastTrackAvailMask);
-
- dumpBase(fd, args);
+ AudioStreamOut *output = mOutput;
+ audio_output_flags_t flags = output != NULL ? output->flags : AUDIO_OUTPUT_FLAG_NONE;
+ String8 flagsAsString = outputFlagsToString(flags);
+ dprintf(fd, " AudioStreamOut: %p flags %#x (%s)\n", output, flags, flagsAsString.string());
}
// Thread virtuals
void AudioFlinger::PlaybackThread::onFirstRef()
{
- run(mName, ANDROID_PRIORITY_URGENT_AUDIO);
+ run(mThreadName, ANDROID_PRIORITY_URGENT_AUDIO);
}
// ThreadBase virtuals
@@ -1378,9 +1550,10 @@
(
(sharedBuffer != 0)
) ||
- // use case 2: callback handler and frame count is default or at least as large as HAL
+ // use case 2: frame count is default or at least as large as HAL
(
- (tid != -1) &&
+ // we formerly checked for a callback handler (non-0 tid),
+ // but that is no longer required for TRANSFER_OBTAIN mode
((frameCount == 0) ||
(frameCount >= mFrameCount))
)
@@ -1420,20 +1593,25 @@
audio_is_linear_pcm(format),
channelMask, sampleRate, mSampleRate, hasFastMixer(), tid, mFastTrackAvailMask);
*flags &= ~IAudioFlinger::TRACK_FAST;
- // For compatibility with AudioTrack calculation, buffer depth is forced
- // to be at least 2 x the normal mixer frame count and cover audio hardware latency.
- // 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.
+ }
+ }
+ // For normal PCM streaming tracks, update minimum frame count.
+ // For compatibility with AudioTrack calculation, buffer depth is forced
+ // to be at least 2 x the normal mixer frame count and cover audio hardware latency.
+ // 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) {
uint32_t latencyMs = mOutput->stream->get_latency(mOutput->stream);
uint32_t minBufCount = latencyMs / ((1000 * mNormalFrameCount) / mSampleRate);
if (minBufCount < 2) {
minBufCount = 2;
}
- size_t minFrameCount = mNormalFrameCount * minBufCount;
- if (frameCount < minFrameCount) {
+ size_t minFrameCount =
+ minBufCount * sourceFramesNeeded(sampleRate, mNormalFrameCount, mSampleRate);
+ if (frameCount < minFrameCount) { // including frameCount == 0
frameCount = minFrameCount;
}
- }
}
*pFrameCount = frameCount;
@@ -1861,6 +2039,22 @@
}
}
+ if (mType == DUPLICATING && mMixerBufferEnabled && mEffectBufferEnabled) {
+ // For best precision, we use float instead of the associated output
+ // device format (typically PCM 16 bit).
+
+ mFormat = AUDIO_FORMAT_PCM_FLOAT;
+ mFrameSize = mChannelCount * audio_bytes_per_sample(mFormat);
+ mBufferSize = mFrameSize * mFrameCount;
+
+ // TODO: We currently use the associated output device channel mask and sample rate.
+ // (1) Perhaps use the ORed channel mask of all downstream MixerThreads
+ // (if a valid mask) to avoid premature downmix.
+ // (2) Perhaps use the maximum sample rate of all downstream MixerThreads
+ // instead of the output device sample rate to avoid loss of high frequency information.
+ // This may need to be updated as MixerThread/OutputTracks are added and not here.
+ }
+
// Calculate size of normal sink buffer relative to the HAL output buffer size
double multiplier = 1.0;
if (mType == MIXER && (kUseFastMixer == FastMixer_Static ||
@@ -2137,6 +2331,7 @@
} else {
bytesWritten = framesWritten;
}
+ mLatchDValid = false;
status_t status = mNormalSink->getTimestamp(mLatchD.mTimestamp);
if (status == NO_ERROR) {
size_t totalFramesWritten = mNormalSink->framesWritten();
@@ -2640,7 +2835,9 @@
}
} else {
+ ATRACE_BEGIN("sleep");
usleep(sleepTime);
+ ATRACE_END();
}
}
@@ -2800,6 +2997,12 @@
mNormalFrameCount);
mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
+ if (type == DUPLICATING) {
+ // The Duplicating thread uses the AudioMixer and delivers data to OutputTracks
+ // (downstream MixerThreads) in DuplicatingThread::threadLoop_write().
+ // Do not create or use mFastMixer, mOutputSink, mPipeSink, or mNormalSink.
+ return;
+ }
// create an NBAIO sink for the HAL output stream, and negotiate
mOutputSink = new AudioStreamOutSink(output->stream);
size_t numCounterOffers = 0;
@@ -2841,6 +3044,7 @@
NBAIO_Format format = mOutputSink->format();
NBAIO_Format origformat = format;
// adjust format to match that of the Fast Mixer
+ ALOGV("format changed from %d to %d", format.mFormat, fastMixerFormat);
format.mFormat = fastMixerFormat;
format.mFrameSize = audio_bytes_per_sample(format.mFormat) * format.mChannelCount;
@@ -3020,8 +3224,10 @@
#endif
}
state->mCommand = FastMixerState::MIX_WRITE;
+#ifdef FAST_THREAD_STATISTICS
mFastMixerDumpState.increaseSamplingN(mAudioFlinger->isLowRamDevice() ?
- FastMixerDumpState::kSamplingNforLowRamDevice : FastMixerDumpState::kSamplingN);
+ FastThreadDumpState::kSamplingNforLowRamDevice : FastThreadDumpState::kSamplingN);
+#endif
sq->end();
sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
if (kUseFastMixer == FastMixer_Dynamic) {
@@ -3386,8 +3592,7 @@
if (sr == mSampleRate) {
desiredFrames = mNormalFrameCount;
} else {
- // +1 for rounding and +1 for additional sample needed for interpolation
- desiredFrames = (mNormalFrameCount * sr) / mSampleRate + 1 + 1;
+ desiredFrames = sourceFramesNeeded(sr, mNormalFrameCount, mSampleRate);
// add frames already consumed but not yet released by the resampler
// because mAudioTrackServerProxy->framesReady() will include these frames
desiredFrames += mAudioMixer->getUnreleasedFrames(track->name());
@@ -3405,6 +3610,23 @@
}
size_t framesReady = track->framesReady();
+ if (ATRACE_ENABLED()) {
+ // I wish we had formatted trace names
+ char traceName[16];
+ strcpy(traceName, "nRdy");
+ int name = track->name();
+ if (AudioMixer::TRACK0 <= name &&
+ name < (int) (AudioMixer::TRACK0 + AudioMixer::MAX_NUM_TRACKS)) {
+ name -= AudioMixer::TRACK0;
+ traceName[4] = (name / 10) + '0';
+ traceName[5] = (name % 10) + '0';
+ } else {
+ traceName[4] = '?';
+ traceName[5] = '?';
+ }
+ traceName[6] = '\0';
+ ATRACE_INT(traceName, framesReady);
+ }
if ((framesReady >= minFrames) && track->isReady() &&
!track->isPaused() && !track->isTerminated())
{
@@ -4797,16 +5019,8 @@
ssize_t AudioFlinger::DuplicatingThread::threadLoop_write()
{
- // We convert the duplicating thread format to AUDIO_FORMAT_PCM_16_BIT
- // for delivery downstream as needed. This in-place conversion is safe as
- // AUDIO_FORMAT_PCM_16_BIT is smaller than any other supported format
- // (AUDIO_FORMAT_PCM_8_BIT is not allowed here).
- if (mFormat != AUDIO_FORMAT_PCM_16_BIT) {
- memcpy_by_audio_format(mSinkBuffer, AUDIO_FORMAT_PCM_16_BIT,
- mSinkBuffer, mFormat, writeFrames * mChannelCount);
- }
for (size_t i = 0; i < outputTracks.size(); i++) {
- outputTracks[i]->write(reinterpret_cast<int16_t*>(mSinkBuffer), writeFrames);
+ outputTracks[i]->write(mSinkBuffer, writeFrames);
}
mStandby = false;
return (ssize_t)mSinkBufferSize;
@@ -4833,25 +5047,26 @@
void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread)
{
Mutex::Autolock _l(mLock);
- // FIXME explain this formula
- size_t frameCount = (3 * mNormalFrameCount * mSampleRate) / thread->sampleRate();
- // OutputTrack is forced to AUDIO_FORMAT_PCM_16_BIT regardless of mFormat
- // due to current usage case and restrictions on the AudioBufferProvider.
- // Actual buffer conversion is done in threadLoop_write().
- //
- // TODO: This may change in the future, depending on multichannel
- // (and non int16_t*) support on AF::PlaybackThread::OutputTrack
- OutputTrack *outputTrack = new OutputTrack(thread,
+ // The downstream MixerThread consumes thread->frameCount() amount of frames per mix pass.
+ // Adjust for thread->sampleRate() to determine minimum buffer frame count.
+ // Then triple buffer because Threads do not run synchronously and may not be clock locked.
+ const size_t frameCount =
+ 3 * sourceFramesNeeded(mSampleRate, thread->frameCount(), thread->sampleRate());
+ // TODO: Consider asynchronous sample rate conversion to handle clock disparity
+ // from different OutputTracks and their associated MixerThreads (e.g. one may
+ // nearly empty and the other may be dropping data).
+
+ sp<OutputTrack> outputTrack = new OutputTrack(thread,
this,
mSampleRate,
- AUDIO_FORMAT_PCM_16_BIT,
+ mFormat,
mChannelMask,
frameCount,
IPCThreadState::self()->getCallingUid());
if (outputTrack->cblk() != NULL) {
thread->setStreamVolume(AUDIO_STREAM_PATCH, 1.0f);
mOutputTracks.add(outputTrack);
- ALOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread);
+ ALOGV("addOutputTrack() track %p, on thread %p", outputTrack.get(), thread);
updateWaitTime_l();
}
}
@@ -4952,8 +5167,8 @@
// mFastCaptureNBLogWriter
, mFastTrackAvail(false)
{
- snprintf(mName, kNameLength, "AudioIn_%X", id);
- mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mName);
+ snprintf(mThreadName, kThreadNameLength, "AudioIn_%X", id);
+ mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName);
readInputParameters_l();
@@ -5094,7 +5309,7 @@
void AudioFlinger::RecordThread::onFirstRef()
{
- run(mName, PRIORITY_URGENT_AUDIO);
+ run(mThreadName, PRIORITY_URGENT_AUDIO);
}
bool AudioFlinger::RecordThread::threadLoop()
@@ -5135,7 +5350,9 @@
// sleep with mutex unlocked
if (sleepUs > 0) {
+ ATRACE_BEGIN("sleep");
usleep(sleepUs);
+ ATRACE_END();
sleepUs = 0;
}
@@ -5279,7 +5496,8 @@
state->mCommand = FastCaptureState::READ_WRITE;
#if 0 // FIXME
mFastCaptureDumpState.increaseSamplingN(mAudioFlinger->isLowRamDevice() ?
- FastCaptureDumpState::kSamplingNforLowRamDevice : FastMixerDumpState::kSamplingN);
+ FastThreadDumpState::kSamplingNforLowRamDevice :
+ FastThreadDumpState::kSamplingN);
#endif
didModify = true;
}
@@ -5427,8 +5645,8 @@
upmix_to_stereo_i16_from_mono_i16((int16_t *)dst, (const int16_t *)src,
part1);
} else {
- downmix_to_mono_i16_from_stereo_i16((int16_t *)dst, (const int16_t *)src,
- part1);
+ downmix_to_mono_i16_from_stereo_i16((int16_t *)dst,
+ (const int16_t *)src, part1);
}
dst += part1 * activeTrack->mFrameSize;
front += part1;
@@ -5939,15 +6157,13 @@
{
dprintf(fd, "\nInput thread %p:\n", this);
- if (mActiveTracks.size() > 0) {
- dprintf(fd, " Buffer size: %zu bytes\n", mBufferSize);
- } else {
+ dumpBase(fd, args);
+
+ if (mActiveTracks.size() == 0) {
dprintf(fd, " No active record clients\n");
}
dprintf(fd, " Fast capture thread: %s\n", hasFastCapture() ? "yes" : "no");
dprintf(fd, " Fast track available: %s\n", mFastTrackAvail ? "yes" : "no");
-
- dumpBase(fd, args);
}
void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args __unused)
@@ -6412,4 +6628,4 @@
config->ext.mix.usecase.source = mAudioSource;
}
-}; // namespace android
+} // namespace android
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 1088843..9350e48 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -32,6 +32,8 @@
OFFLOAD // Thread class is OffloadThread
};
+ static const char *threadTypeToString(type_t type);
+
ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
audio_devices_t outDevice, audio_devices_t inDevice, type_t type);
virtual ~ThreadBase();
@@ -406,6 +408,7 @@
audio_channel_mask_t mChannelMask;
uint32_t mChannelCount;
size_t mFrameSize;
+ // not HAL frame size, this is for output sink (to pipe to fast mixer)
audio_format_t mFormat; // Source format for Recording and
// Sink format for Playback.
// Sink format may be different than
@@ -429,8 +432,8 @@
const audio_io_handle_t mId;
Vector< sp<EffectChain> > mEffectChains;
- static const int kNameLength = 16; // prctl(PR_SET_NAME) limit
- char mName[kNameLength];
+ static const int kThreadNameLength = 16; // prctl(PR_SET_NAME) limit
+ char mThreadName[kThreadNameLength]; // guaranteed NUL-terminated
sp<IPowerManager> mPowerManager;
sp<IBinder> mWakeLockToken;
const sp<PMDeathRecipient> mDeathRecipient;
@@ -1167,7 +1170,8 @@
const sp<MemoryDealer> mReadOnlyHeap;
// one-time initialization, no locks required
- sp<FastCapture> mFastCapture; // non-0 if there is also a fast capture
+ sp<FastCapture> mFastCapture; // non-0 if there is also
+ // a fast capture
// FIXME audio watchdog thread
// contents are not guaranteed to be consistent, no locks required
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index e970036..8329be4 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -20,6 +20,7 @@
//#define LOG_NDEBUG 0
#include "Configuration.h"
+#include <linux/futex.h>
#include <math.h>
#include <sys/syscall.h>
#include <utils/Log.h>
@@ -859,6 +860,7 @@
if (mState == FLUSHED) {
mState = IDLE;
}
+ mPreviousValid = false;
}
}
@@ -1709,36 +1711,18 @@
mActive = false;
}
-bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t frames)
+bool AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frames)
{
Buffer *pInBuffer;
Buffer inBuffer;
- uint32_t channelCount = mChannelCount;
bool outputBufferFull = false;
inBuffer.frameCount = frames;
- inBuffer.i16 = data;
+ inBuffer.raw = data;
uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs();
if (!mActive && frames != 0) {
- start();
- sp<ThreadBase> thread = mThread.promote();
- if (thread != 0) {
- MixerThread *mixerThread = (MixerThread *)thread.get();
- if (mFrameCount > frames) {
- if (mBufferQueue.size() < kMaxOverFlowBuffers) {
- uint32_t startFrames = (mFrameCount - frames);
- pInBuffer = new Buffer;
- pInBuffer->mBuffer = new int16_t[startFrames * channelCount];
- pInBuffer->frameCount = startFrames;
- pInBuffer->i16 = pInBuffer->mBuffer;
- memset(pInBuffer->raw, 0, startFrames * channelCount * sizeof(int16_t));
- mBufferQueue.add(pInBuffer);
- } else {
- ALOGW("OutputTrack::write() %p no more buffers in queue", this);
- }
- }
- }
+ (void) start();
}
while (waitTimeLeftMs) {
@@ -1773,20 +1757,20 @@
uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount :
pInBuffer->frameCount;
- memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channelCount * sizeof(int16_t));
+ memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * mFrameSize);
Proxy::Buffer buf;
buf.mFrameCount = outFrames;
buf.mRaw = NULL;
mClientProxy->releaseBuffer(&buf);
pInBuffer->frameCount -= outFrames;
- pInBuffer->i16 += outFrames * channelCount;
+ pInBuffer->raw = (int8_t *)pInBuffer->raw + outFrames * mFrameSize;
mOutBuffer.frameCount -= outFrames;
- mOutBuffer.i16 += outFrames * channelCount;
+ mOutBuffer.raw = (int8_t *)mOutBuffer.raw + outFrames * mFrameSize;
if (pInBuffer->frameCount == 0) {
if (mBufferQueue.size()) {
mBufferQueue.removeAt(0);
- delete [] pInBuffer->mBuffer;
+ free(pInBuffer->mBuffer);
delete pInBuffer;
ALOGV("OutputTrack::write() %p thread %p released overflow buffer %d", this,
mThread.unsafe_get(), mBufferQueue.size());
@@ -1802,11 +1786,10 @@
if (thread != 0 && !thread->standby()) {
if (mBufferQueue.size() < kMaxOverFlowBuffers) {
pInBuffer = new Buffer;
- pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channelCount];
+ pInBuffer->mBuffer = malloc(inBuffer.frameCount * mFrameSize);
pInBuffer->frameCount = inBuffer.frameCount;
- pInBuffer->i16 = pInBuffer->mBuffer;
- memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channelCount *
- sizeof(int16_t));
+ pInBuffer->raw = pInBuffer->mBuffer;
+ memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * mFrameSize);
mBufferQueue.add(pInBuffer);
ALOGV("OutputTrack::write() %p thread %p adding overflow buffer %d", this,
mThread.unsafe_get(), mBufferQueue.size());
@@ -1817,23 +1800,10 @@
}
}
- // Calling write() with a 0 length buffer, means that no more data will be written:
- // If no more buffers are pending, fill output track buffer to make sure it is started
- // by output mixer.
- if (frames == 0 && mBufferQueue.size() == 0) {
- // FIXME borken, replace by getting framesReady() from proxy
- size_t user = 0; // was mCblk->user
- if (user < mFrameCount) {
- frames = mFrameCount - user;
- pInBuffer = new Buffer;
- pInBuffer->mBuffer = new int16_t[frames * channelCount];
- pInBuffer->frameCount = frames;
- pInBuffer->i16 = pInBuffer->mBuffer;
- memset(pInBuffer->raw, 0, frames * channelCount * sizeof(int16_t));
- mBufferQueue.add(pInBuffer);
- } else if (mActive) {
- stop();
- }
+ // Calling write() with a 0 length buffer means that no more data will be written:
+ // We rely on stop() to set the appropriate flags to allow the remaining frames to play out.
+ if (frames == 0 && mBufferQueue.size() == 0 && mActive) {
+ stop();
}
return outputBufferFull;
@@ -1859,7 +1829,7 @@
for (size_t i = 0; i < size; i++) {
Buffer *pBuffer = mBufferQueue.itemAt(i);
- delete [] pBuffer->mBuffer;
+ free(pBuffer->mBuffer);
delete pBuffer;
}
mBufferQueue.clear();
@@ -2212,4 +2182,4 @@
mProxy->releaseBuffer(buffer);
}
-}; // namespace android
+} // namespace android
diff --git a/services/audioflinger/test-resample.cpp b/services/audioflinger/test-resample.cpp
index 84a655a..7893778 100644
--- a/services/audioflinger/test-resample.cpp
+++ b/services/audioflinger/test-resample.cpp
@@ -427,6 +427,14 @@
printf("quality: %d channels: %d msec: %" PRId64 " Mfrms/s: %.2lf\n",
quality, channels, time/1000000, output_frames * looplimit / (time / 1e9) / 1e6);
resampler->reset();
+
+ // TODO fix legacy bug: reset does not clear buffers.
+ // delete and recreate resampler here.
+ delete resampler;
+ resampler = AudioResampler::create(format, channels,
+ output_freq, quality);
+ resampler->setSampleRate(input_freq);
+ resampler->setVolume(AudioResampler::UNITY_GAIN_FLOAT, AudioResampler::UNITY_GAIN_FLOAT);
}
memset(output_vaddr, 0, output_size);
diff --git a/services/audioflinger/tests/Android.mk b/services/audioflinger/tests/Android.mk
index 7bba05b..8604ef5 100644
--- a/services/audioflinger/tests/Android.mk
+++ b/services/audioflinger/tests/Android.mk
@@ -10,19 +10,10 @@
liblog \
libutils \
libcutils \
- libstlport \
libaudioutils \
libaudioresampler
-LOCAL_STATIC_LIBRARIES := \
- libgtest \
- libgtest_main
-
LOCAL_C_INCLUDES := \
- bionic \
- bionic/libstdc++/include \
- external/gtest/include \
- external/stlport/stlport \
$(call include-path-for, audio-utils) \
frameworks/av/services/audioflinger
@@ -32,21 +23,24 @@
LOCAL_MODULE := resampler_tests
LOCAL_MODULE_TAGS := tests
-include $(BUILD_EXECUTABLE)
+include $(BUILD_NATIVE_TEST)
#
# audio mixer test tool
#
include $(CLEAR_VARS)
+# Clang++ aborts on AudioMixer.cpp,
+# b/18373866, "do not know how to split this operator."
+ifeq ($(filter $(TARGET_ARCH),arm arm64),$(TARGET_ARCH))
+ LOCAL_CLANG := false
+endif
+
LOCAL_SRC_FILES:= \
test-mixer.cpp \
../AudioMixer.cpp.arm \
LOCAL_C_INCLUDES := \
- bionic \
- bionic/libstdc++/include \
- external/stlport/stlport \
$(call include-path-for, audio-effects) \
$(call include-path-for, audio-utils) \
frameworks/av/services/audioflinger
@@ -55,7 +49,6 @@
libsndfile
LOCAL_SHARED_LIBRARIES := \
- libstlport \
libeffects \
libnbaio \
libcommon_time_client \
@@ -70,4 +63,6 @@
LOCAL_MODULE_TAGS := optional
+LOCAL_CXX_STL := libc++
+
include $(BUILD_EXECUTABLE)
diff --git a/services/audioflinger/tests/build_and_run_all_unit_tests.sh b/services/audioflinger/tests/build_and_run_all_unit_tests.sh
index 2c453b0..7f4d456 100755
--- a/services/audioflinger/tests/build_and_run_all_unit_tests.sh
+++ b/services/audioflinger/tests/build_and_run_all_unit_tests.sh
@@ -15,7 +15,7 @@
echo "waiting for device"
adb root && adb wait-for-device remount
adb push $OUT/system/lib/libaudioresampler.so /system/lib
-adb push $OUT/system/bin/resampler_tests /system/bin
+adb push $OUT/data/nativetest/resampler_tests /system/bin
sh $ANDROID_BUILD_TOP/frameworks/av/services/audioflinger/tests/run_all_unit_tests.sh
diff --git a/services/audioflinger/tests/mixer_to_wav_tests.sh b/services/audioflinger/tests/mixer_to_wav_tests.sh
index 9b39e77..d0482a1 100755
--- a/services/audioflinger/tests/mixer_to_wav_tests.sh
+++ b/services/audioflinger/tests/mixer_to_wav_tests.sh
@@ -60,11 +60,21 @@
fi
# Test:
+# process__genericResampling with mixed integer and float track input
+# track__Resample / track__genericResample
+ adb shell test-mixer $1 -s 48000 \
+ -o /sdcard/tm48000grif.wav \
+ sine:2,4000,7520 chirp:2,9200 sine:1,3000,18000 \
+ sine:f,6,6000,19000 chirp:i,4,30000
+ adb pull /sdcard/tm48000grif.wav $2
+
+# Test:
# process__genericResampling
# track__Resample / track__genericResample
adb shell test-mixer $1 -s 48000 \
-o /sdcard/tm48000gr.wav \
- sine:2,4000,7520 chirp:2,9200 sine:1,3000,18000
+ sine:2,4000,7520 chirp:2,9200 sine:1,3000,18000 \
+ sine:6,6000,19000
adb pull /sdcard/tm48000gr.wav $2
# Test:
diff --git a/services/audioflinger/tests/test-mixer.cpp b/services/audioflinger/tests/test-mixer.cpp
index 9a4fad6..8da6245 100644
--- a/services/audioflinger/tests/test-mixer.cpp
+++ b/services/audioflinger/tests/test-mixer.cpp
@@ -39,7 +39,7 @@
fprintf(stderr, "Usage: %s [-f] [-m] [-c channels]"
" [-s sample-rate] [-o <output-file>] [-a <aux-buffer-file>] [-P csv]"
" (<input-file> | <command>)+\n", name);
- fprintf(stderr, " -f enable floating point input track\n");
+ fprintf(stderr, " -f enable floating point input track by default\n");
fprintf(stderr, " -m enable floating point mixer output\n");
fprintf(stderr, " -c number of mixer output channels\n");
fprintf(stderr, " -s mixer sample-rate\n");
@@ -47,8 +47,8 @@
fprintf(stderr, " -a <aux-buffer-file>\n");
fprintf(stderr, " -P # frames provided per call to resample() in CSV format\n");
fprintf(stderr, " <input-file> is a WAV file\n");
- fprintf(stderr, " <command> can be 'sine:<channels>,<frequency>,<samplerate>'\n");
- fprintf(stderr, " 'chirp:<channels>,<samplerate>'\n");
+ fprintf(stderr, " <command> can be 'sine:[(i|f),]<channels>,<frequency>,<samplerate>'\n");
+ fprintf(stderr, " 'chirp:[(i|f),]<channels>,<samplerate>'\n");
}
static int writeFile(const char *filename, const void *buffer,
@@ -78,6 +78,18 @@
return EXIT_SUCCESS;
}
+const char *parseFormat(const char *s, bool *useFloat) {
+ if (!strncmp(s, "f,", 2)) {
+ *useFloat = true;
+ return s + 2;
+ }
+ if (!strncmp(s, "i,", 2)) {
+ *useFloat = false;
+ return s + 2;
+ }
+ return s;
+}
+
int main(int argc, char* argv[]) {
const char* const progname = argv[0];
bool useInputFloat = false;
@@ -88,8 +100,9 @@
std::vector<int> Pvalues;
const char* outputFilename = NULL;
const char* auxFilename = NULL;
- std::vector<int32_t> Names;
- std::vector<SignalProvider> Providers;
+ std::vector<int32_t> names;
+ std::vector<SignalProvider> providers;
+ std::vector<audio_format_t> formats;
for (int ch; (ch = getopt(argc, argv, "fmc:s:o:a:P:")) != -1;) {
switch (ch) {
@@ -138,54 +151,65 @@
size_t outputFrames = 0;
// create providers for each track
- Providers.resize(argc);
+ names.resize(argc);
+ providers.resize(argc);
+ formats.resize(argc);
for (int i = 0; i < argc; ++i) {
static const char chirp[] = "chirp:";
static const char sine[] = "sine:";
static const double kSeconds = 1;
+ bool useFloat = useInputFloat;
if (!strncmp(argv[i], chirp, strlen(chirp))) {
std::vector<int> v;
+ const char *s = parseFormat(argv[i] + strlen(chirp), &useFloat);
- parseCSV(argv[i] + strlen(chirp), v);
+ parseCSV(s, v);
if (v.size() == 2) {
printf("creating chirp(%d %d)\n", v[0], v[1]);
- if (useInputFloat) {
- Providers[i].setChirp<float>(v[0], 0, v[1]/2, v[1], kSeconds);
+ if (useFloat) {
+ providers[i].setChirp<float>(v[0], 0, v[1]/2, v[1], kSeconds);
+ formats[i] = AUDIO_FORMAT_PCM_FLOAT;
} else {
- Providers[i].setChirp<int16_t>(v[0], 0, v[1]/2, v[1], kSeconds);
+ providers[i].setChirp<int16_t>(v[0], 0, v[1]/2, v[1], kSeconds);
+ formats[i] = AUDIO_FORMAT_PCM_16_BIT;
}
- Providers[i].setIncr(Pvalues);
+ providers[i].setIncr(Pvalues);
} else {
fprintf(stderr, "malformed input '%s'\n", argv[i]);
}
} else if (!strncmp(argv[i], sine, strlen(sine))) {
std::vector<int> v;
+ const char *s = parseFormat(argv[i] + strlen(sine), &useFloat);
- parseCSV(argv[i] + strlen(sine), v);
+ parseCSV(s, v);
if (v.size() == 3) {
printf("creating sine(%d %d %d)\n", v[0], v[1], v[2]);
- if (useInputFloat) {
- Providers[i].setSine<float>(v[0], v[1], v[2], kSeconds);
+ if (useFloat) {
+ providers[i].setSine<float>(v[0], v[1], v[2], kSeconds);
+ formats[i] = AUDIO_FORMAT_PCM_FLOAT;
} else {
- Providers[i].setSine<int16_t>(v[0], v[1], v[2], kSeconds);
+ providers[i].setSine<int16_t>(v[0], v[1], v[2], kSeconds);
+ formats[i] = AUDIO_FORMAT_PCM_16_BIT;
}
- Providers[i].setIncr(Pvalues);
+ providers[i].setIncr(Pvalues);
} else {
fprintf(stderr, "malformed input '%s'\n", argv[i]);
}
} else {
printf("creating filename(%s)\n", argv[i]);
if (useInputFloat) {
- Providers[i].setFile<float>(argv[i]);
+ providers[i].setFile<float>(argv[i]);
+ formats[i] = AUDIO_FORMAT_PCM_FLOAT;
} else {
- Providers[i].setFile<short>(argv[i]);
+ providers[i].setFile<short>(argv[i]);
+ formats[i] = AUDIO_FORMAT_PCM_16_BIT;
}
- Providers[i].setIncr(Pvalues);
+ providers[i].setIncr(Pvalues);
}
// calculate the number of output frames
- size_t nframes = (int64_t) Providers[i].getNumFrames() * outputSampleRate
- / Providers[i].getSampleRate();
+ size_t nframes = (int64_t) providers[i].getNumFrames() * outputSampleRate
+ / providers[i].getSampleRate();
if (i == 0 || outputFrames > nframes) { // choose minimum for outputFrames
outputFrames = nframes;
}
@@ -213,22 +237,20 @@
// create the mixer.
const size_t mixerFrameCount = 320; // typical numbers may range from 240 or 960
AudioMixer *mixer = new AudioMixer(mixerFrameCount, outputSampleRate);
- audio_format_t inputFormat = useInputFloat
- ? AUDIO_FORMAT_PCM_FLOAT : AUDIO_FORMAT_PCM_16_BIT;
audio_format_t mixerFormat = useMixerFloat
? AUDIO_FORMAT_PCM_FLOAT : AUDIO_FORMAT_PCM_16_BIT;
- float f = AudioMixer::UNITY_GAIN_FLOAT / Providers.size(); // normalize volume by # tracks
+ float f = AudioMixer::UNITY_GAIN_FLOAT / providers.size(); // normalize volume by # tracks
static float f0; // zero
// set up the tracks.
- for (size_t i = 0; i < Providers.size(); ++i) {
- //printf("track %d out of %d\n", i, Providers.size());
- uint32_t channelMask = audio_channel_out_mask_from_count(Providers[i].getNumChannels());
+ for (size_t i = 0; i < providers.size(); ++i) {
+ //printf("track %d out of %d\n", i, providers.size());
+ uint32_t channelMask = audio_channel_out_mask_from_count(providers[i].getNumChannels());
int32_t name = mixer->getTrackName(channelMask,
- inputFormat, AUDIO_SESSION_OUTPUT_MIX);
+ formats[i], AUDIO_SESSION_OUTPUT_MIX);
ALOG_ASSERT(name >= 0);
- Names.push_back(name);
- mixer->setBufferProvider(name, &Providers[i]);
+ names[i] = name;
+ mixer->setBufferProvider(name, &providers[i]);
mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
(void *)outputAddr);
mixer->setParameter(
@@ -240,7 +262,7 @@
name,
AudioMixer::TRACK,
AudioMixer::FORMAT,
- (void *)(uintptr_t)inputFormat);
+ (void *)(uintptr_t)formats[i]);
mixer->setParameter(
name,
AudioMixer::TRACK,
@@ -255,7 +277,7 @@
name,
AudioMixer::RESAMPLE,
AudioMixer::SAMPLE_RATE,
- (void *)(uintptr_t)Providers[i].getSampleRate());
+ (void *)(uintptr_t)providers[i].getSampleRate());
if (useRamp) {
mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &f0);
mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &f0);
@@ -277,11 +299,11 @@
// pump the mixer to process data.
size_t i;
for (i = 0; i < outputFrames - mixerFrameCount; i += mixerFrameCount) {
- for (size_t j = 0; j < Names.size(); ++j) {
- mixer->setParameter(Names[j], AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
+ for (size_t j = 0; j < names.size(); ++j) {
+ mixer->setParameter(names[j], AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
(char *) outputAddr + i * outputFrameSize);
if (auxFilename) {
- mixer->setParameter(Names[j], AudioMixer::TRACK, AudioMixer::AUX_BUFFER,
+ mixer->setParameter(names[j], AudioMixer::TRACK, AudioMixer::AUX_BUFFER,
(char *) auxAddr + i * auxFrameSize);
}
}
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index 188fc89..351ed79 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -3,19 +3,19 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- AudioPolicyService.cpp \
- AudioPolicyEffects.cpp
+ service/AudioPolicyService.cpp \
+ service/AudioPolicyEffects.cpp
ifeq ($(USE_LEGACY_AUDIO_POLICY), 1)
LOCAL_SRC_FILES += \
- AudioPolicyInterfaceImplLegacy.cpp \
- AudioPolicyClientImplLegacy.cpp
+ service/AudioPolicyInterfaceImplLegacy.cpp \
+ service/AudioPolicyClientImplLegacy.cpp
LOCAL_CFLAGS += -DUSE_LEGACY_AUDIO_POLICY
else
LOCAL_SRC_FILES += \
- AudioPolicyInterfaceImpl.cpp \
- AudioPolicyClientImpl.cpp
+ service/AudioPolicyInterfaceImpl.cpp \
+ service/AudioPolicyClientImpl.cpp
endif
LOCAL_C_INCLUDES := \
@@ -53,7 +53,15 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- AudioPolicyManager.cpp
+ managerdefault/AudioPolicyManager.cpp \
+ managerdefault/ConfigParsingUtils.cpp \
+ managerdefault/Devices.cpp \
+ managerdefault/Gains.cpp \
+ managerdefault/HwModule.cpp \
+ managerdefault/IOProfile.cpp \
+ managerdefault/Ports.cpp \
+ managerdefault/AudioInputDescriptor.cpp \
+ managerdefault/AudioOutputDescriptor.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -73,7 +81,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- AudioPolicyFactory.cpp
+ manager/AudioPolicyFactory.cpp
LOCAL_SHARED_LIBRARIES := \
libaudiopolicymanagerdefault
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 4508fa7..116d0d6 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -75,7 +75,8 @@
// indicate a change in device connection status
virtual status_t setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
- const char *device_address) = 0;
+ const char *device_address,
+ const char *device_name) = 0;
// retrieve a device connection status
virtual audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device,
const char *device_address) = 0;
diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h
deleted file mode 100644
index cbdafa6..0000000
--- a/services/audiopolicy/AudioPolicyManager.h
+++ /dev/null
@@ -1,937 +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 <stdint.h>
-#include <sys/types.h>
-#include <cutils/config_utils.h>
-#include <cutils/misc.h>
-#include <utils/Timers.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/SortedVector.h>
-#include <media/AudioPolicy.h>
-#include "AudioPolicyInterface.h"
-
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-// Attenuation applied to STRATEGY_SONIFICATION streams when a headset is connected: 6dB
-#define SONIFICATION_HEADSET_VOLUME_FACTOR 0.5
-// Min volume for STRATEGY_SONIFICATION streams when limited by music volume: -36dB
-#define SONIFICATION_HEADSET_VOLUME_MIN 0.016
-// Time in milliseconds during which we consider that music is still active after a music
-// track was stopped - see computeVolume()
-#define SONIFICATION_HEADSET_MUSIC_DELAY 5000
-// Time in milliseconds after media stopped playing during which we consider that the
-// sonification should be as unobtrusive as during the time media was playing.
-#define SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY 5000
-// Time in milliseconds during witch some streams are muted while the audio path
-// is switched
-#define MUTE_TIME_MS 2000
-
-#define NUM_TEST_OUTPUTS 5
-
-#define NUM_VOL_CURVE_KNEES 2
-
-// Default minimum length allowed for offloading a compressed track
-// Can be overridden by the audio.offload.min.duration.secs property
-#define OFFLOAD_DEFAULT_MIN_DURATION_SECS 60
-
-#define MAX_MIXER_SAMPLING_RATE 48000
-#define MAX_MIXER_CHANNEL_COUNT 8
-
-// ----------------------------------------------------------------------------
-// AudioPolicyManager implements audio policy manager behavior common to all platforms.
-// ----------------------------------------------------------------------------
-
-class AudioPolicyManager: public AudioPolicyInterface
-#ifdef AUDIO_POLICY_TEST
- , public Thread
-#endif //AUDIO_POLICY_TEST
-{
-
-public:
- AudioPolicyManager(AudioPolicyClientInterface *clientInterface);
- virtual ~AudioPolicyManager();
-
- // AudioPolicyInterface
- virtual status_t setDeviceConnectionState(audio_devices_t device,
- audio_policy_dev_state_t state,
- const char *device_address);
- virtual audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device,
- const char *device_address);
- virtual void setPhoneState(audio_mode_t state);
- virtual void setForceUse(audio_policy_force_use_t usage,
- audio_policy_forced_cfg_t config);
- virtual audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage);
- virtual void setSystemProperty(const char* property, const char* value);
- virtual status_t initCheck();
- virtual audio_io_handle_t getOutput(audio_stream_type_t stream,
- uint32_t samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_output_flags_t flags,
- const audio_offload_info_t *offloadInfo);
- virtual status_t getOutputForAttr(const audio_attributes_t *attr,
- audio_io_handle_t *output,
- audio_session_t session,
- audio_stream_type_t *stream,
- uint32_t samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_output_flags_t flags,
- const audio_offload_info_t *offloadInfo);
- virtual status_t startOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session);
- virtual status_t stopOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session);
- virtual void releaseOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session);
- virtual status_t getInputForAttr(const audio_attributes_t *attr,
- audio_io_handle_t *input,
- audio_session_t session,
- uint32_t samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_input_flags_t flags,
- input_type_t *inputType);
-
- // indicates to the audio policy manager that the input starts being used.
- virtual status_t startInput(audio_io_handle_t input,
- audio_session_t session);
-
- // indicates to the audio policy manager that the input stops being used.
- virtual status_t stopInput(audio_io_handle_t input,
- audio_session_t session);
- virtual void releaseInput(audio_io_handle_t input,
- audio_session_t session);
- virtual void closeAllInputs();
- virtual void initStreamVolume(audio_stream_type_t stream,
- int indexMin,
- int indexMax);
- virtual status_t setStreamVolumeIndex(audio_stream_type_t stream,
- int index,
- audio_devices_t device);
- virtual status_t getStreamVolumeIndex(audio_stream_type_t stream,
- int *index,
- audio_devices_t device);
-
- // return the strategy corresponding to a given stream type
- virtual uint32_t getStrategyForStream(audio_stream_type_t stream);
- // return the strategy corresponding to the given audio attributes
- virtual uint32_t getStrategyForAttr(const audio_attributes_t *attr);
-
- // return the enabled output devices for the given stream type
- virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream);
-
- virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc = NULL);
- virtual status_t registerEffect(const effect_descriptor_t *desc,
- audio_io_handle_t io,
- uint32_t strategy,
- int session,
- int id);
- virtual status_t unregisterEffect(int id);
- virtual status_t setEffectEnabled(int id, bool enabled);
-
- virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
- // return whether a stream is playing remotely, override to change the definition of
- // local/remote playback, used for instance by notification manager to not make
- // media players lose audio focus when not playing locally
- // For the base implementation, "remotely" means playing during screen mirroring which
- // uses an output for playback with a non-empty, non "0" address.
- virtual bool isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
- virtual bool isSourceActive(audio_source_t source) const;
-
- virtual status_t dump(int fd);
-
- virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo);
-
- virtual status_t listAudioPorts(audio_port_role_t role,
- audio_port_type_t type,
- unsigned int *num_ports,
- struct audio_port *ports,
- unsigned int *generation);
- virtual status_t getAudioPort(struct audio_port *port);
- virtual status_t createAudioPatch(const struct audio_patch *patch,
- audio_patch_handle_t *handle,
- uid_t uid);
- virtual status_t releaseAudioPatch(audio_patch_handle_t handle,
- uid_t uid);
- virtual status_t listAudioPatches(unsigned int *num_patches,
- struct audio_patch *patches,
- unsigned int *generation);
- virtual status_t setAudioPortConfig(const struct audio_port_config *config);
- virtual void clearAudioPatches(uid_t uid);
-
- virtual status_t acquireSoundTriggerSession(audio_session_t *session,
- audio_io_handle_t *ioHandle,
- audio_devices_t *device);
-
- virtual status_t releaseSoundTriggerSession(audio_session_t session);
-
- virtual status_t registerPolicyMixes(Vector<AudioMix> mixes);
- virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes);
-
-protected:
-
- enum routing_strategy {
- STRATEGY_MEDIA,
- STRATEGY_PHONE,
- STRATEGY_SONIFICATION,
- STRATEGY_SONIFICATION_RESPECTFUL,
- STRATEGY_DTMF,
- STRATEGY_ENFORCED_AUDIBLE,
- STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
- STRATEGY_ACCESSIBILITY,
- STRATEGY_REROUTING,
- NUM_STRATEGIES
- };
-
- // 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 in volIndexToAmpl()
-
- enum { VOLMIN = 0, VOLKNEE1 = 1, VOLKNEE2 = 2, VOLMAX = 3, VOLCNT = 4};
-
- class VolumeCurvePoint
- {
- public:
- int mIndex;
- 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 HwModule;
-
- class AudioGain: public RefBase
- {
- public:
- AudioGain(int index, bool useInChannelMask);
- virtual ~AudioGain() {}
-
- 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);
- int mIndex;
- struct audio_gain mGain;
- bool mUseInChannelMask;
- };
-
- class AudioPort: public virtual RefBase
- {
- public:
- AudioPort(const String8& name, audio_port_type_t type,
- audio_port_role_t role, const sp<HwModule>& module);
- virtual ~AudioPort() {}
-
- virtual void toAudioPort(struct audio_port *port) const;
-
- void importAudioPort(const sp<AudioPort> port);
- void clearCapabilities();
-
- void loadSamplingRates(char *name);
- void loadFormats(char *name);
- void loadOutChannels(char *name);
- void loadInChannels(char *name);
-
- audio_gain_mode_t loadGainMode(char *name);
- void loadGain(cnode *root, int index);
- virtual void loadGains(cnode *root);
-
- // 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) const;
- status_t checkFormat(audio_format_t format) const;
- 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;
-
- static const audio_format_t sPcmFormatCompareTable[];
- static int compareFormats(audio_format_t format1, audio_format_t format2);
-
- void dump(int fd, int spaces) 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
- sp<HwModule> mModule; // audio HW module exposing this I/O stream
- uint32_t mFlags; // attribute flags (e.g primary output,
- // direct output...).
- };
-
- class AudioPortConfig: public virtual RefBase
- {
- public:
- AudioPortConfig();
- virtual ~AudioPortConfig() {}
-
- status_t applyAudioPortConfig(const struct audio_port_config *config,
- struct audio_port_config *backupConfig = NULL);
- virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
- const struct audio_port_config *srcConfig = NULL) const = 0;
- virtual sp<AudioPort> getAudioPort() const = 0;
- uint32_t mSamplingRate;
- audio_format_t mFormat;
- audio_channel_mask_t mChannelMask;
- struct audio_gain_config mGain;
- };
-
-
- class AudioPatch: public RefBase
- {
- public:
- AudioPatch(audio_patch_handle_t handle,
- const struct audio_patch *patch, uid_t uid) :
- mHandle(handle), mPatch(*patch), mUid(uid), mAfPatchHandle(0) {}
-
- status_t dump(int fd, int spaces, int index) const;
-
- audio_patch_handle_t mHandle;
- struct audio_patch mPatch;
- uid_t mUid;
- audio_patch_handle_t mAfPatchHandle;
- };
-
- class DeviceDescriptor: public AudioPort, public AudioPortConfig
- {
- public:
- DeviceDescriptor(const String8& name, audio_devices_t type);
-
- virtual ~DeviceDescriptor() {}
-
- bool equals(const sp<DeviceDescriptor>& other) const;
-
- // AudioPortConfig
- virtual sp<AudioPort> getAudioPort() const { return (AudioPort*) this; }
- virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
- const struct audio_port_config *srcConfig = NULL) const;
-
- // AudioPort
- virtual void loadGains(cnode *root);
- virtual void toAudioPort(struct audio_port *port) const;
-
- status_t dump(int fd, int spaces, int index) const;
-
- audio_devices_t mDeviceType;
- String8 mAddress;
- audio_port_handle_t mId;
- };
-
- class DeviceVector : public SortedVector< sp<DeviceDescriptor> >
- {
- public:
- DeviceVector() : SortedVector(), mDeviceTypes(AUDIO_DEVICE_NONE) {}
-
- ssize_t add(const sp<DeviceDescriptor>& item);
- 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 loadDevicesFromName(char *name, 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> getDeviceFromName(const String8& name) const;
- DeviceVector getDevicesFromTypeAddr(audio_devices_t type, String8 address)
- const;
-
- private:
- void refreshTypes();
- audio_devices_t mDeviceTypes;
- };
-
- // the IOProfile class describes the capabilities of an output or input stream.
- // It is currently assumed that all combination of listed parameters are supported.
- // It is used by the policy manager to determine if an output or input is suitable for
- // a given use case, open/close it accordingly and connect/disconnect audio tracks
- // to/from it.
- class IOProfile : public AudioPort
- {
- public:
- IOProfile(const String8& name, audio_port_role_t role, const sp<HwModule>& module);
- virtual ~IOProfile();
-
- // This method is used for both output and input.
- // If parameter updatedSamplingRate is non-NULL, it is assigned the actual sample rate.
- // For input, flags is interpreted as audio_input_flags_t.
- // TODO: merge audio_output_flags_t and audio_input_flags_t.
- bool isCompatibleProfile(audio_devices_t device,
- String8 address,
- uint32_t samplingRate,
- uint32_t *updatedSamplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- uint32_t flags) const;
-
- void dump(int fd);
- void log();
-
- DeviceVector mSupportedDevices; // supported devices
- // (devices this output can be routed to)
- };
-
- class HwModule : public RefBase
- {
- public:
- HwModule(const char *name);
- ~HwModule();
-
- status_t loadOutput(cnode *root);
- status_t loadInput(cnode *root);
- status_t loadDevice(cnode *root);
-
- status_t addOutputProfile(String8 name, const audio_config_t *config,
- audio_devices_t device, String8 address);
- status_t removeOutputProfile(String8 name);
- status_t addInputProfile(String8 name, const audio_config_t *config,
- audio_devices_t device, String8 address);
- status_t removeInputProfile(String8 name);
-
- 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
-
- };
-
- // default volume curve
- static const VolumeCurvePoint sDefaultVolumeCurve[AudioPolicyManager::VOLCNT];
- // default volume curve for media strategy
- static const VolumeCurvePoint sDefaultMediaVolumeCurve[AudioPolicyManager::VOLCNT];
- // volume curve for non-media audio on ext media outputs (HDMI, Line, etc)
- static const VolumeCurvePoint sExtMediaSystemVolumeCurve[AudioPolicyManager::VOLCNT];
- // volume curve for media strategy on speakers
- static const VolumeCurvePoint sSpeakerMediaVolumeCurve[AudioPolicyManager::VOLCNT];
- static const VolumeCurvePoint sSpeakerMediaVolumeCurveDrc[AudioPolicyManager::VOLCNT];
- // volume curve for sonification strategy on speakers
- static const VolumeCurvePoint sSpeakerSonificationVolumeCurve[AudioPolicyManager::VOLCNT];
- static const VolumeCurvePoint sSpeakerSonificationVolumeCurveDrc[AudioPolicyManager::VOLCNT];
- static const VolumeCurvePoint sDefaultSystemVolumeCurve[AudioPolicyManager::VOLCNT];
- static const VolumeCurvePoint sDefaultSystemVolumeCurveDrc[AudioPolicyManager::VOLCNT];
- static const VolumeCurvePoint sHeadsetSystemVolumeCurve[AudioPolicyManager::VOLCNT];
- static const VolumeCurvePoint sDefaultVoiceVolumeCurve[AudioPolicyManager::VOLCNT];
- static const VolumeCurvePoint sSpeakerVoiceVolumeCurve[AudioPolicyManager::VOLCNT];
- static const VolumeCurvePoint sLinearVolumeCurve[AudioPolicyManager::VOLCNT];
- static const VolumeCurvePoint sSilentVolumeCurve[AudioPolicyManager::VOLCNT];
- static const VolumeCurvePoint sFullScaleVolumeCurve[AudioPolicyManager::VOLCNT];
- // default volume curves per stream and device category. See initializeVolumeCurves()
- static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][DEVICE_CATEGORY_CNT];
-
- // 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.
- class AudioOutputDescriptor: public AudioPortConfig
- {
- public:
- AudioOutputDescriptor(const sp<IOProfile>& profile);
-
- status_t dump(int fd);
-
- audio_devices_t device() const;
- void changeRefCount(audio_stream_type_t stream, int delta);
-
- bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); }
- audio_devices_t supportedDevices();
- uint32_t latency();
- bool sharesHwModuleWith(const sp<AudioOutputDescriptor> outputDesc);
- bool isActive(uint32_t inPastMs = 0) const;
- bool isStreamActive(audio_stream_type_t stream,
- uint32_t inPastMs = 0,
- nsecs_t sysTime = 0) const;
- bool isStrategyActive(routing_strategy strategy,
- uint32_t inPastMs = 0,
- nsecs_t sysTime = 0) const;
-
- virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
- const struct audio_port_config *srcConfig = NULL) const;
- virtual sp<AudioPort> getAudioPort() const { return mProfile; }
- void toAudioPort(struct audio_port *port) const;
-
- audio_port_handle_t mId;
- audio_io_handle_t mIoHandle; // output handle
- uint32_t mLatency; //
- audio_output_flags_t mFlags; //
- audio_devices_t mDevice; // current device this output is routed to
- AudioMix *mPolicyMix; // non NULL when used by a dynamic policy
- audio_patch_handle_t mPatchHandle;
- uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output
- nsecs_t mStopTime[AUDIO_STREAM_CNT];
- sp<AudioOutputDescriptor> mOutput1; // used by duplicated outputs: first output
- sp<AudioOutputDescriptor> mOutput2; // used by duplicated outputs: second output
- float mCurVolume[AUDIO_STREAM_CNT]; // current stream volume
- int mMuteCount[AUDIO_STREAM_CNT]; // mute request counter
- const sp<IOProfile> mProfile; // I/O profile this output derives from
- bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible
- // device selection. See checkDeviceMuteStrategies()
- uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only)
- };
-
- // descriptor for audio inputs. Used to maintain current configuration of each opened audio input
- // and keep track of the usage of this input.
- class AudioInputDescriptor: public AudioPortConfig
- {
- public:
- AudioInputDescriptor(const sp<IOProfile>& profile);
-
- status_t dump(int fd);
-
- audio_port_handle_t mId;
- audio_io_handle_t mIoHandle; // input handle
- 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;
- virtual sp<AudioPort> getAudioPort() const { return mProfile; }
- void toAudioPort(struct audio_port *port) const;
- };
-
- // stream descriptor used for volume control
- class StreamDescriptor
- {
- public:
- StreamDescriptor();
-
- int getVolumeIndex(audio_devices_t device);
- void dump(int fd);
-
- int mIndexMin; // min volume index
- int mIndexMax; // max volume index
- KeyedVector<audio_devices_t, int> mIndexCur; // current volume index per device
- bool mCanBeMuted; // true is the stream can be muted
-
- const VolumeCurvePoint *mVolumeCurve[DEVICE_CATEGORY_CNT];
- };
-
- // stream descriptor used for volume control
- class EffectDescriptor : public RefBase
- {
- public:
-
- status_t dump(int fd);
-
- int mIo; // io the effect is attached to
- routing_strategy mStrategy; // routing strategy the effect is associated to
- int mSession; // audio session the effect is on
- effect_descriptor_t mDesc; // effect descriptor
- bool mEnabled; // enabled state: CPU load being used or not
- };
-
- void addOutput(audio_io_handle_t output, sp<AudioOutputDescriptor> outputDesc);
- void addInput(audio_io_handle_t input, sp<AudioInputDescriptor> inputDesc);
-
- // return the strategy corresponding to a given stream type
- static routing_strategy getStrategy(audio_stream_type_t stream);
-
- // return appropriate device for streams handled by the specified strategy according to current
- // phone state, connected devices...
- // if fromCache is true, the device is returned from mDeviceForStrategy[],
- // otherwise it is determine by current state
- // (device connected,phone state, force use, a2dp output...)
- // This allows to:
- // 1 speed up process when the state is stable (when starting or stopping an output)
- // 2 access to either current device selection (fromCache == true) or
- // "future" device selection (fromCache == false) when called from a context
- // where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
- // before updateDevicesAndOutputs() is called.
- virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy,
- bool fromCache);
-
- // change the route of the specified output. Returns the number of ms we have slept to
- // allow new routing to take effect in certain cases.
- virtual uint32_t setOutputDevice(audio_io_handle_t output,
- audio_devices_t device,
- bool force = false,
- int delayMs = 0,
- audio_patch_handle_t *patchHandle = NULL,
- const char* address = NULL);
- status_t resetOutputDevice(audio_io_handle_t output,
- int delayMs = 0,
- audio_patch_handle_t *patchHandle = NULL);
- status_t setInputDevice(audio_io_handle_t input,
- audio_devices_t device,
- bool force = false,
- audio_patch_handle_t *patchHandle = NULL);
- status_t resetInputDevice(audio_io_handle_t input,
- audio_patch_handle_t *patchHandle = NULL);
-
- // select input device corresponding to requested audio source
- virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource);
-
- // return io handle of active input or 0 if no input is active
- // Only considers inputs from physical devices (e.g. main mic, headset mic) when
- // ignoreVirtualInputs is true.
- audio_io_handle_t getActiveInput(bool ignoreVirtualInputs = true);
-
- uint32_t activeInputsCount() const;
-
- // initialize volume curves for each strategy and device category
- void initializeVolumeCurves();
-
- // compute the actual volume for a given stream according to the requested index and a particular
- // device
- virtual float computeVolume(audio_stream_type_t stream, int index,
- audio_io_handle_t output, audio_devices_t device);
-
- // check that volume change is permitted, compute and send new volume to audio hardware
- virtual status_t checkAndSetVolume(audio_stream_type_t stream, int index,
- audio_io_handle_t output,
- audio_devices_t device,
- int delayMs = 0, bool force = false);
-
- // apply all stream volumes to the specified output and device
- void applyStreamVolumes(audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false);
-
- // Mute or unmute all streams handled by the specified strategy on the specified output
- void setStrategyMute(routing_strategy strategy,
- bool on,
- audio_io_handle_t output,
- int delayMs = 0,
- audio_devices_t device = (audio_devices_t)0);
-
- // Mute or unmute the stream on the specified output
- void setStreamMute(audio_stream_type_t stream,
- bool on,
- audio_io_handle_t output,
- int delayMs = 0,
- audio_devices_t device = (audio_devices_t)0);
-
- // handle special cases for sonification strategy while in call: mute streams or replace by
- // a special tone in the device used for communication
- void handleIncallSonification(audio_stream_type_t stream, bool starting, bool stateChange);
-
- // true if device is in a telephony or VoIP call
- virtual bool isInCall();
-
- // true if given state represents a device in a telephony or VoIP call
- virtual bool isStateInCall(int state);
-
- // when a device is connected, checks if an open output can be routed
- // to this device. If none is open, tries to open one of the available outputs.
- // Returns an output suitable to this device or 0.
- // when a device is disconnected, checks if an output is not used any more and
- // returns its handle if any.
- // transfers the audio tracks and effects from one output thread to another accordingly.
- status_t checkOutputsForDevice(const sp<DeviceDescriptor> devDesc,
- audio_policy_dev_state_t state,
- SortedVector<audio_io_handle_t>& outputs,
- const String8 address);
-
- status_t checkInputsForDevice(audio_devices_t device,
- audio_policy_dev_state_t state,
- SortedVector<audio_io_handle_t>& inputs,
- const String8 address);
-
- // close an output and its companion duplicating output.
- void closeOutput(audio_io_handle_t output);
-
- // close an input.
- void closeInput(audio_io_handle_t input);
-
- // checks and if necessary changes outputs used for all strategies.
- // must be called every time a condition that affects the output choice for a given strategy
- // changes: connected device, phone state, force use...
- // Must be called before updateDevicesAndOutputs()
- void checkOutputForStrategy(routing_strategy strategy);
-
- // Same as checkOutputForStrategy() but for a all strategies in order of priority
- void checkOutputForAllStrategies();
-
- // manages A2DP output suspend/restore according to phone state and BT SCO usage
- void checkA2dpSuspend();
-
- // returns the A2DP output handle if it is open or 0 otherwise
- audio_io_handle_t getA2dpOutput();
-
- // selects the most appropriate device on output for current state
- // must be called every time a condition that affects the device choice for a given output is
- // changed: connected device, phone state, force use, output start, output stop..
- // see getDeviceForStrategy() for the use of fromCache parameter
- audio_devices_t getNewOutputDevice(audio_io_handle_t output, bool fromCache);
-
- // updates cache of device used by all strategies (mDeviceForStrategy[])
- // must be called every time a condition that affects the device choice for a given strategy is
- // changed: connected device, phone state, force use...
- // cached values are used by getDeviceForStrategy() if parameter fromCache is true.
- // Must be called after checkOutputForAllStrategies()
- void updateDevicesAndOutputs();
-
- // selects the most appropriate device on input for current state
- audio_devices_t getNewInputDevice(audio_io_handle_t input);
-
- virtual uint32_t getMaxEffectsCpuLoad();
- virtual uint32_t getMaxEffectsMemory();
-#ifdef AUDIO_POLICY_TEST
- virtual bool threadLoop();
- void exit();
- int testOutputIndex(audio_io_handle_t output);
-#endif //AUDIO_POLICY_TEST
-
- status_t setEffectEnabled(const sp<EffectDescriptor>& effectDesc, bool enabled);
-
- // returns the category the device belongs to with regard to volume curve management
- static device_category getDeviceCategory(audio_devices_t device);
-
- // extract one device relevant for volume control from multiple device selection
- static audio_devices_t getDeviceForVolume(audio_devices_t device);
-
- SortedVector<audio_io_handle_t> getOutputsForDevice(audio_devices_t device,
- DefaultKeyedVector<audio_io_handle_t, sp<AudioOutputDescriptor> > openOutputs);
- bool vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
- SortedVector<audio_io_handle_t>& outputs2);
-
- // mute/unmute strategies using an incompatible device combination
- // if muting, wait for the audio in pcm buffer to be drained before proceeding
- // if unmuting, unmute only after the specified delay
- // Returns the number of ms waited
- virtual uint32_t checkDeviceMuteStrategies(sp<AudioOutputDescriptor> outputDesc,
- audio_devices_t prevDevice,
- uint32_t delayMs);
-
- audio_io_handle_t selectOutput(const SortedVector<audio_io_handle_t>& outputs,
- audio_output_flags_t flags,
- audio_format_t format);
- // samplingRate parameter is an in/out and so may be modified
- sp<IOProfile> getInputProfile(audio_devices_t device,
- String8 address,
- uint32_t& samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_input_flags_t flags);
- sp<IOProfile> getProfileForDirectOutput(audio_devices_t device,
- uint32_t samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_output_flags_t flags);
-
- audio_io_handle_t selectOutputForEffects(const SortedVector<audio_io_handle_t>& outputs);
-
- bool isNonOffloadableEffectEnabled();
-
- virtual status_t addAudioPatch(audio_patch_handle_t handle,
- const sp<AudioPatch>& patch);
- virtual status_t removeAudioPatch(audio_patch_handle_t handle);
-
- sp<AudioOutputDescriptor> getOutputFromId(audio_port_handle_t id) const;
- sp<AudioInputDescriptor> getInputFromId(audio_port_handle_t id) const;
- sp<HwModule> getModuleForDevice(audio_devices_t device) const;
- sp<HwModule> getModuleFromName(const char *name) const;
- audio_devices_t availablePrimaryOutputDevices();
- audio_devices_t availablePrimaryInputDevices();
-
- void updateCallRouting(audio_devices_t rxDevice, int delayMs = 0);
-
- //
- // Audio policy configuration file parsing (audio_policy.conf)
- //
- 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);
- void loadHwModule(cnode *root);
- void loadHwModules(cnode *root);
- void loadGlobalConfig(cnode *root, const sp<HwModule>& module);
- status_t loadAudioPolicyConfig(const char *path);
- void defaultAudioPolicyConfig(void);
-
-
- uid_t mUidCached;
- AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
- audio_io_handle_t mPrimaryOutput; // primary output handle
- // list of descriptors for outputs currently opened
- DefaultKeyedVector<audio_io_handle_t, sp<AudioOutputDescriptor> > mOutputs;
- // copy of mOutputs before setDeviceConnectionState() opens new outputs
- // reset to mOutputs when updateDevicesAndOutputs() is called.
- DefaultKeyedVector<audio_io_handle_t, sp<AudioOutputDescriptor> > mPreviousOutputs;
- DefaultKeyedVector<audio_io_handle_t, sp<AudioInputDescriptor> > mInputs; // list of input descriptors
- DeviceVector mAvailableOutputDevices; // all available output devices
- DeviceVector mAvailableInputDevices; // all available input devices
- int mPhoneState; // current phone state
- audio_policy_forced_cfg_t mForceUse[AUDIO_POLICY_FORCE_USE_CNT]; // current forced use configuration
-
- StreamDescriptor mStreams[AUDIO_STREAM_CNT]; // stream descriptors for volume control
- 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
-
- // Maximum CPU load allocated to audio effects in 0.1 MIPS (ARMv5TE, 0 WS memory) units
- static const uint32_t MAX_EFFECTS_CPU_LOAD = 1000;
- // Maximum memory allocated to audio effects in KB
- static const uint32_t MAX_EFFECTS_MEMORY = 512;
- uint32_t mTotalEffectsCpuLoad; // current CPU load used by effects
- uint32_t mTotalEffectsMemory; // current memory used by effects
- KeyedVector<int, sp<EffectDescriptor> > 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
-
- Vector < sp<HwModule> > mHwModules;
- volatile int32_t mNextUniqueId;
- volatile int32_t mAudioPortGeneration;
-
- DefaultKeyedVector<audio_patch_handle_t, sp<AudioPatch> > mAudioPatches;
-
- DefaultKeyedVector<audio_session_t, audio_io_handle_t> mSoundTriggerSessions;
-
- sp<AudioPatch> mCallTxPatch;
- sp<AudioPatch> mCallRxPatch;
-
- // 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 {
- STARTING_OUTPUT,
- STARTING_BEACON,
- STOPPING_OUTPUT,
- STOPPING_BEACON
- };
- uint32_t mBeaconMuteRefCount; // ref count for stream that would mute beacon
- uint32_t mBeaconPlayingRefCount;// ref count for the playing beacon streams
- bool mBeaconMuted; // has STREAM_TTS been muted
-
- // custom mix entry in mPolicyMixes
- class AudioPolicyMix : public RefBase {
- public:
- AudioPolicyMix() {}
-
- AudioMix mMix; // Audio policy mix descriptor
- sp<AudioOutputDescriptor> mOutput; // Corresponding output stream
- };
- DefaultKeyedVector<String8, sp<AudioPolicyMix> > mPolicyMixes; // list of registered mixes
-
-
-#ifdef AUDIO_POLICY_TEST
- Mutex mLock;
- Condition mWaitWorkCV;
-
- int mCurOutput;
- bool mDirectOutput;
- audio_io_handle_t mTestOutputs[NUM_TEST_OUTPUTS];
- int mTestInput;
- uint32_t mTestDevice;
- uint32_t mTestSamplingRate;
- uint32_t mTestFormat;
- uint32_t mTestChannels;
- uint32_t mTestLatencyMs;
-#endif //AUDIO_POLICY_TEST
- static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
- int indexInUi);
- static bool isVirtualInputDevice(audio_devices_t device);
- uint32_t nextUniqueId();
- uint32_t nextAudioPortGeneration();
-private:
- // updates device caching and output for streams that can influence the
- // routing of notifications
- void handleNotificationRoutingForStream(audio_stream_type_t stream);
- static bool deviceDistinguishesOnAddress(audio_devices_t device);
- // find the outputs on a given output descriptor that have the given address.
- // to be called on an AudioOutputDescriptor whose supported devices (as defined
- // in mProfile->mSupportedDevices) matches the device whose address is to be matched.
- // see deviceDistinguishesOnAddress(audio_devices_t) for whether the device type is one
- // where addresses are used to distinguish between one connected device and another.
- void findIoHandlesByAddress(sp<AudioOutputDescriptor> desc /*in*/,
- const audio_devices_t device /*in*/,
- const String8 address /*in*/,
- SortedVector<audio_io_handle_t>& outputs /*out*/);
- uint32_t curAudioPortGeneration() const { return mAudioPortGeneration; }
- // internal method to return the output handle for the given device and format
- audio_io_handle_t getOutputForDevice(
- audio_devices_t device,
- audio_session_t session,
- audio_stream_type_t stream,
- uint32_t samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_output_flags_t flags,
- const audio_offload_info_t *offloadInfo);
- // internal function to derive a stream type value from audio attributes
- audio_stream_type_t streamTypefromAttributesInt(const audio_attributes_t *attr);
- // return true if any output is playing anything besides the stream to ignore
- bool isAnyOutputActive(audio_stream_type_t streamToIgnore);
- // event is one of STARTING_OUTPUT, STARTING_BEACON, STOPPING_OUTPUT, STOPPING_BEACON
- // returns 0 if no mute/unmute event happened, the largest latency of the device where
- // the mute/unmute happened
- uint32_t handleEventForBeacon(int event);
- uint32_t setBeaconMute(bool mute);
- bool isValidAttributes(const audio_attributes_t *paa);
-
- // select input device corresponding to requested audio source and return associated policy
- // mix if any. Calls getDeviceForInputSource().
- audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource,
- AudioMix **policyMix = NULL);
-
- // Called by setDeviceConnectionState().
- status_t setDeviceConnectionStateInt(audio_devices_t device,
- audio_policy_dev_state_t state,
- const char *device_address);
- sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t device,
- const char *device_address);
-
-};
-
-};
diff --git a/services/audiopolicy/AudioPolicyFactory.cpp b/services/audiopolicy/manager/AudioPolicyFactory.cpp
similarity index 94%
rename from services/audiopolicy/AudioPolicyFactory.cpp
rename to services/audiopolicy/manager/AudioPolicyFactory.cpp
index 2ae7bc1..9910a1f 100644
--- a/services/audiopolicy/AudioPolicyFactory.cpp
+++ b/services/audiopolicy/manager/AudioPolicyFactory.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "AudioPolicyManager.h"
+#include "managerdefault/AudioPolicyManager.h"
namespace android {
diff --git a/services/audiopolicy/AudioPolicyFactory.cpp b/services/audiopolicy/managerdefault/ApmImplDefinitions.h
similarity index 60%
copy from services/audiopolicy/AudioPolicyFactory.cpp
copy to services/audiopolicy/managerdefault/ApmImplDefinitions.h
index 2ae7bc1..620979b 100644
--- a/services/audiopolicy/AudioPolicyFactory.cpp
+++ b/services/audiopolicy/managerdefault/ApmImplDefinitions.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 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,19 +14,19 @@
* limitations under the License.
*/
-#include "AudioPolicyManager.h"
-
namespace android {
-extern "C" AudioPolicyInterface* createAudioPolicyManager(
- AudioPolicyClientInterface *clientInterface)
-{
- return new AudioPolicyManager(clientInterface);
-}
+enum routing_strategy {
+ STRATEGY_MEDIA,
+ STRATEGY_PHONE,
+ STRATEGY_SONIFICATION,
+ STRATEGY_SONIFICATION_RESPECTFUL,
+ STRATEGY_DTMF,
+ STRATEGY_ENFORCED_AUDIBLE,
+ STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
+ STRATEGY_ACCESSIBILITY,
+ STRATEGY_REROUTING,
+ NUM_STRATEGIES
+};
-extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface)
-{
- delete interface;
-}
-
-}; // namespace android
+}; //namespace android
diff --git a/services/audiopolicy/managerdefault/AudioInputDescriptor.cpp b/services/audiopolicy/managerdefault/AudioInputDescriptor.cpp
new file mode 100644
index 0000000..f4054c8
--- /dev/null
+++ b/services/audiopolicy/managerdefault/AudioInputDescriptor.cpp
@@ -0,0 +1,100 @@
+/*
+ * 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::AudioInputDescriptor"
+//#define LOG_NDEBUG 0
+
+#include "AudioPolicyManager.h"
+
+namespace android {
+
+AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile)
+ : mId(0), mIoHandle(0),
+ mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0), mRefCount(0),
+ mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile), mIsSoundTrigger(false)
+{
+ if (profile != NULL) {
+ mSamplingRate = profile->pickSamplingRate();
+ mFormat = profile->pickFormat();
+ mChannelMask = profile->pickChannelMask();
+ if (profile->mGains.size() > 0) {
+ profile->mGains[0]->getDefaultConfig(&mGain);
+ }
+ }
+}
+
+void AudioInputDescriptor::toAudioPortConfig(
+ struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig) const
+{
+ ALOG_ASSERT(mProfile != 0,
+ "toAudioPortConfig() called on input with null profile %d", mIoHandle);
+ dstConfig->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
+ AUDIO_PORT_CONFIG_FORMAT|AUDIO_PORT_CONFIG_GAIN;
+ if (srcConfig != NULL) {
+ dstConfig->config_mask |= srcConfig->config_mask;
+ }
+
+ AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
+
+ dstConfig->id = mId;
+ dstConfig->role = AUDIO_PORT_ROLE_SINK;
+ dstConfig->type = AUDIO_PORT_TYPE_MIX;
+ dstConfig->ext.mix.hw_module = mProfile->mModule->mHandle;
+ dstConfig->ext.mix.handle = mIoHandle;
+ dstConfig->ext.mix.usecase.source = mInputSource;
+}
+
+void AudioInputDescriptor::toAudioPort(
+ struct audio_port *port) const
+{
+ ALOG_ASSERT(mProfile != 0, "toAudioPort() called on input with null profile %d", mIoHandle);
+
+ mProfile->toAudioPort(port);
+ port->id = mId;
+ toAudioPortConfig(&port->active_config);
+ port->ext.mix.hw_module = mProfile->mModule->mHandle;
+ port->ext.mix.handle = mIoHandle;
+ port->ext.mix.latency_class = AUDIO_LATENCY_NORMAL;
+}
+
+status_t AudioInputDescriptor::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, " ID: %d\n", mId);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Format: %d\n", mFormat);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
+ 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());
+
+ return NO_ERROR;
+}
+
+}; //namespace android
diff --git a/services/audiopolicy/managerdefault/AudioInputDescriptor.h b/services/audiopolicy/managerdefault/AudioInputDescriptor.h
new file mode 100644
index 0000000..02579e6
--- /dev/null
+++ b/services/audiopolicy/managerdefault/AudioInputDescriptor.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.
+ */
+
+namespace android {
+
+// descriptor for audio inputs. Used to maintain current configuration of each opened audio input
+// and keep track of the usage of this input.
+class AudioInputDescriptor: public AudioPortConfig
+{
+public:
+ AudioInputDescriptor(const sp<IOProfile>& profile);
+
+ status_t dump(int fd);
+
+ audio_port_handle_t mId;
+ audio_io_handle_t mIoHandle; // input handle
+ 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;
+ virtual sp<AudioPort> getAudioPort() const { return mProfile; }
+ void toAudioPort(struct audio_port *port) const;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioOutputDescriptor.cpp b/services/audiopolicy/managerdefault/AudioOutputDescriptor.cpp
new file mode 100644
index 0000000..4b85972
--- /dev/null
+++ b/services/audiopolicy/managerdefault/AudioOutputDescriptor.cpp
@@ -0,0 +1,221 @@
+/*
+ * 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::AudioOutputDescriptor"
+//#define LOG_NDEBUG 0
+
+#include "AudioPolicyManager.h"
+
+namespace android {
+
+AudioOutputDescriptor::AudioOutputDescriptor(
+ const sp<IOProfile>& profile)
+ : mId(0), mIoHandle(0), mLatency(0),
+ mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL),
+ mPatchHandle(0),
+ mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0)
+{
+ // clear usage count for all stream types
+ for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
+ mRefCount[i] = 0;
+ mCurVolume[i] = -1.0;
+ mMuteCount[i] = 0;
+ mStopTime[i] = 0;
+ }
+ for (int i = 0; i < NUM_STRATEGIES; i++) {
+ mStrategyMutedByDevice[i] = false;
+ }
+ if (profile != NULL) {
+ mFlags = (audio_output_flags_t)profile->mFlags;
+ mSamplingRate = profile->pickSamplingRate();
+ mFormat = profile->pickFormat();
+ mChannelMask = profile->pickChannelMask();
+ if (profile->mGains.size() > 0) {
+ profile->mGains[0]->getDefaultConfig(&mGain);
+ }
+ }
+}
+
+audio_devices_t AudioOutputDescriptor::device() const
+{
+ if (isDuplicated()) {
+ return (audio_devices_t)(mOutput1->mDevice | mOutput2->mDevice);
+ } else {
+ return mDevice;
+ }
+}
+
+uint32_t AudioOutputDescriptor::latency()
+{
+ if (isDuplicated()) {
+ return (mOutput1->mLatency > mOutput2->mLatency) ? mOutput1->mLatency : mOutput2->mLatency;
+ } else {
+ return mLatency;
+ }
+}
+
+bool AudioOutputDescriptor::sharesHwModuleWith(
+ const sp<AudioOutputDescriptor> outputDesc)
+{
+ if (isDuplicated()) {
+ return mOutput1->sharesHwModuleWith(outputDesc) || mOutput2->sharesHwModuleWith(outputDesc);
+ } else if (outputDesc->isDuplicated()){
+ return sharesHwModuleWith(outputDesc->mOutput1) || sharesHwModuleWith(outputDesc->mOutput2);
+ } else {
+ return (mProfile->mModule == outputDesc->mProfile->mModule);
+ }
+}
+
+void AudioOutputDescriptor::changeRefCount(audio_stream_type_t stream,
+ int delta)
+{
+ // forward usage count change to attached outputs
+ if (isDuplicated()) {
+ mOutput1->changeRefCount(stream, delta);
+ mOutput2->changeRefCount(stream, delta);
+ }
+ if ((delta + (int)mRefCount[stream]) < 0) {
+ ALOGW("changeRefCount() invalid delta %d for stream %d, refCount %d",
+ delta, stream, mRefCount[stream]);
+ mRefCount[stream] = 0;
+ return;
+ }
+ mRefCount[stream] += delta;
+ ALOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
+}
+
+audio_devices_t AudioOutputDescriptor::supportedDevices()
+{
+ if (isDuplicated()) {
+ return (audio_devices_t)(mOutput1->supportedDevices() | mOutput2->supportedDevices());
+ } else {
+ return mProfile->mSupportedDevices.types() ;
+ }
+}
+
+bool AudioOutputDescriptor::isActive(uint32_t inPastMs) const
+{
+ return isStrategyActive(NUM_STRATEGIES, inPastMs);
+}
+
+bool AudioOutputDescriptor::isStrategyActive(routing_strategy strategy,
+ uint32_t inPastMs,
+ nsecs_t sysTime) const
+{
+ if ((sysTime == 0) && (inPastMs != 0)) {
+ sysTime = systemTime();
+ }
+ for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
+ if (i == AUDIO_STREAM_PATCH) {
+ continue;
+ }
+ if (((AudioPolicyManager::getStrategy((audio_stream_type_t)i) == strategy) ||
+ (NUM_STRATEGIES == strategy)) &&
+ isStreamActive((audio_stream_type_t)i, inPastMs, sysTime)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioOutputDescriptor::isStreamActive(audio_stream_type_t stream,
+ uint32_t inPastMs,
+ nsecs_t sysTime) const
+{
+ if (mRefCount[stream] != 0) {
+ return true;
+ }
+ if (inPastMs == 0) {
+ return false;
+ }
+ if (sysTime == 0) {
+ sysTime = systemTime();
+ }
+ if (ns2ms(sysTime - mStopTime[stream]) < inPastMs) {
+ return true;
+ }
+ return false;
+}
+
+void AudioOutputDescriptor::toAudioPortConfig(
+ struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig) const
+{
+ ALOG_ASSERT(!isDuplicated(), "toAudioPortConfig() called on duplicated output %d", mIoHandle);
+
+ dstConfig->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
+ AUDIO_PORT_CONFIG_FORMAT|AUDIO_PORT_CONFIG_GAIN;
+ if (srcConfig != NULL) {
+ dstConfig->config_mask |= srcConfig->config_mask;
+ }
+ AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
+
+ dstConfig->id = mId;
+ dstConfig->role = AUDIO_PORT_ROLE_SOURCE;
+ dstConfig->type = AUDIO_PORT_TYPE_MIX;
+ dstConfig->ext.mix.hw_module = mProfile->mModule->mHandle;
+ dstConfig->ext.mix.handle = mIoHandle;
+ dstConfig->ext.mix.usecase.stream = AUDIO_STREAM_DEFAULT;
+}
+
+void AudioOutputDescriptor::toAudioPort(
+ struct audio_port *port) const
+{
+ ALOG_ASSERT(!isDuplicated(), "toAudioPort() called on duplicated output %d", mIoHandle);
+ mProfile->toAudioPort(port);
+ port->id = mId;
+ toAudioPortConfig(&port->active_config);
+ port->ext.mix.hw_module = mProfile->mModule->mHandle;
+ port->ext.mix.handle = mIoHandle;
+ port->ext.mix.latency_class =
+ mFlags & AUDIO_OUTPUT_FLAG_FAST ? AUDIO_LATENCY_LOW : AUDIO_LATENCY_NORMAL;
+}
+
+status_t AudioOutputDescriptor::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, " ID: %d\n", mId);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Format: %08x\n", mFormat);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Latency: %d\n", mLatency);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Flags %08x\n", mFlags);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Devices %08x\n", device());
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Stream volume refCount muteCount\n");
+ result.append(buffer);
+ for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
+ snprintf(buffer, SIZE, " %02d %.03f %02d %02d\n",
+ i, mCurVolume[i], mRefCount[i], mMuteCount[i]);
+ result.append(buffer);
+ }
+ write(fd, result.string(), result.size());
+
+ return NO_ERROR;
+}
+
+
+
+}; //namespace android
diff --git a/services/audiopolicy/managerdefault/AudioOutputDescriptor.h b/services/audiopolicy/managerdefault/AudioOutputDescriptor.h
new file mode 100644
index 0000000..32f46e4
--- /dev/null
+++ b/services/audiopolicy/managerdefault/AudioOutputDescriptor.h
@@ -0,0 +1,69 @@
+/*
+ * 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 "ApmImplDefinitions.h"
+
+namespace android {
+
+// 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.
+class AudioOutputDescriptor: public AudioPortConfig
+{
+public:
+ AudioOutputDescriptor(const sp<IOProfile>& profile);
+
+ status_t dump(int fd);
+
+ audio_devices_t device() const;
+ void changeRefCount(audio_stream_type_t stream, int delta);
+
+ bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); }
+ audio_devices_t supportedDevices();
+ uint32_t latency();
+ bool sharesHwModuleWith(const sp<AudioOutputDescriptor> outputDesc);
+ bool isActive(uint32_t inPastMs = 0) const;
+ bool isStreamActive(audio_stream_type_t stream,
+ uint32_t inPastMs = 0,
+ nsecs_t sysTime = 0) const;
+ bool isStrategyActive(routing_strategy strategy,
+ uint32_t inPastMs = 0,
+ nsecs_t sysTime = 0) const;
+
+ virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig = NULL) const;
+ virtual sp<AudioPort> getAudioPort() const { return mProfile; }
+ void toAudioPort(struct audio_port *port) const;
+
+ audio_port_handle_t mId;
+ audio_io_handle_t mIoHandle; // output handle
+ uint32_t mLatency; //
+ audio_output_flags_t mFlags; //
+ audio_devices_t mDevice; // current device this output is routed to
+ AudioMix *mPolicyMix; // non NULL when used by a dynamic policy
+ audio_patch_handle_t mPatchHandle;
+ uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output
+ nsecs_t mStopTime[AUDIO_STREAM_CNT];
+ sp<AudioOutputDescriptor> mOutput1; // used by duplicated outputs: first output
+ sp<AudioOutputDescriptor> mOutput2; // used by duplicated outputs: second output
+ float mCurVolume[AUDIO_STREAM_CNT]; // current stream volume
+ int mMuteCount[AUDIO_STREAM_CNT]; // mute request counter
+ const sp<IOProfile> mProfile; // I/O profile this output derives from
+ bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible
+ // device selection. See checkDeviceMuteStrategies()
+ uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only)
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
similarity index 72%
rename from services/audiopolicy/AudioPolicyManager.cpp
rename to services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 7f27659..53ec0f6 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AudioPolicyManager"
+#define LOG_TAG "APM::AudioPolicyManager"
//#define LOG_NDEBUG 0
//#define VERY_VERBOSE_LOGGING
@@ -51,184 +51,29 @@
namespace android {
// ----------------------------------------------------------------------------
-// Definitions for audio_policy.conf file parsing
-// ----------------------------------------------------------------------------
-
-struct StringToEnum {
- const char *name;
- uint32_t value;
-};
-
-#define STRING_TO_ENUM(string) { #string, string }
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-
-const StringToEnum sDeviceNameToEnumTable[] = {
- 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_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),
-};
-
-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),
-};
-
-const StringToEnum sInputFlagNameToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_INPUT_FLAG_FAST),
- STRING_TO_ENUM(AUDIO_INPUT_FLAG_HW_HOTWORD),
-};
-
-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),
-};
-
-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 sGainModeNameToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_GAIN_MODE_JOINT),
- STRING_TO_ENUM(AUDIO_GAIN_MODE_CHANNELS),
- STRING_TO_ENUM(AUDIO_GAIN_MODE_RAMP),
-};
-
-
-uint32_t AudioPolicyManager::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;
-}
-
-const char *AudioPolicyManager::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 "";
-}
-
-bool AudioPolicyManager::stringToBool(const char *value)
-{
- return ((strcasecmp("true", value) == 0) || (strcmp("1", value) == 0));
-}
-
-
-// ----------------------------------------------------------------------------
// AudioPolicyInterface implementation
// ----------------------------------------------------------------------------
status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
- audio_policy_dev_state_t state,
- const char *device_address)
+ audio_policy_dev_state_t state,
+ const char *device_address,
+ const char *device_name)
{
- return setDeviceConnectionStateInt(device, state, device_address);
+ return setDeviceConnectionStateInt(device, state, device_address, device_name);
}
status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device,
audio_policy_dev_state_t state,
- const char *device_address)
+ const char *device_address,
+ const char *device_name)
{
- ALOGV("setDeviceConnectionState() device: %x, state %d, address %s",
- device, state, device_address != NULL ? device_address : "");
+ ALOGV("setDeviceConnectionStateInt() device: 0x%X, state %d, address %s name %s",
+- device, state, device_address, device_name);
// connect/disconnect only 1 device at a time
if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
- sp<DeviceDescriptor> devDesc = getDeviceDescriptor(device, device_address);
+ sp<DeviceDescriptor> devDesc = getDeviceDescriptor(device, device_address, device_name);
// handle output devices
if (audio_is_output_device(device)) {
@@ -259,8 +104,7 @@
mAvailableOutputDevices.remove(devDesc);
return INVALID_OPERATION;
}
- mAvailableOutputDevices[index]->mId = nextUniqueId();
- mAvailableOutputDevices[index]->mModule = module;
+ mAvailableOutputDevices[index]->attach(module);
} else {
return NO_MEMORY;
}
@@ -275,8 +119,7 @@
ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %zu outputs",
outputs.size());
-
- // Set connect to HALs
+ // Send connect to HALs
AudioParameter param = AudioParameter(devDesc->mAddress);
param.addInt(String8(AUDIO_PARAMETER_DEVICE_CONNECT), device);
mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString());
@@ -291,7 +134,7 @@
ALOGV("setDeviceConnectionState() disconnecting output device %x", device);
- // Set Disconnect to HALs
+ // Send Disconnect to HALs
AudioParameter param = AudioParameter(devDesc->mAddress);
param.addInt(String8(AUDIO_PARAMETER_DEVICE_DISCONNECT), device);
mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString());
@@ -377,8 +220,7 @@
index = mAvailableInputDevices.add(devDesc);
if (index >= 0) {
- mAvailableInputDevices[index]->mId = nextUniqueId();
- mAvailableInputDevices[index]->mModule = module;
+ mAvailableInputDevices[index]->attach(module);
} else {
return NO_MEMORY;
}
@@ -432,7 +274,7 @@
audio_policy_dev_state_t AudioPolicyManager::getDeviceConnectionState(audio_devices_t device,
const char *device_address)
{
- sp<DeviceDescriptor> devDesc = getDeviceDescriptor(device, device_address);
+ sp<DeviceDescriptor> devDesc = getDeviceDescriptor(device, device_address, "");
DeviceVector *deviceVector;
if (audio_is_output_device(device)) {
@@ -452,9 +294,9 @@
}
}
-sp<AudioPolicyManager::DeviceDescriptor> AudioPolicyManager::getDeviceDescriptor(
- const audio_devices_t device,
- const char *device_address)
+sp<DeviceDescriptor> AudioPolicyManager::getDeviceDescriptor(const audio_devices_t device,
+ const char *device_address,
+ const char *device_name)
{
String8 address = (device_address == NULL) ? String8("") : String8(device_address);
// handle legacy remote submix case where the address was not always specified
@@ -477,7 +319,8 @@
}
}
- sp<DeviceDescriptor> devDesc = new DeviceDescriptor(String8(""), device);
+ sp<DeviceDescriptor> devDesc =
+ new DeviceDescriptor(String8(device_name != NULL ? device_name : ""), device);
devDesc->mAddress = address;
return devDesc;
}
@@ -640,18 +483,18 @@
// force routing command to audio hardware when starting a call
// even if no device change is needed
force = true;
- for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+ for (int j = 0; j < ApmGains::DEVICE_CATEGORY_CNT; j++) {
mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] =
- sVolumeProfiles[AUDIO_STREAM_VOICE_CALL][j];
+ ApmGains::sVolumeProfiles[AUDIO_STREAM_VOICE_CALL][j];
}
} else if (isStateInCall(oldState) && !isStateInCall(state)) {
ALOGV(" Exiting call in setPhoneState()");
// force routing command to audio hardware when exiting a call
// even if no device change is needed
force = true;
- for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+ for (int j = 0; j < ApmGains::DEVICE_CATEGORY_CNT; j++) {
mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] =
- sVolumeProfiles[AUDIO_STREAM_DTMF][j];
+ ApmGains::sVolumeProfiles[AUDIO_STREAM_DTMF][j];
}
} else if (isStateInCall(state) && (state != oldState)) {
ALOGV(" Switching between telephony and VoIP in setPhoneState()");
@@ -842,7 +685,7 @@
// Find a direct output profile compatible with the parameters passed, even if the input flags do
// not explicitly request a direct output
-sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getProfileForDirectOutput(
+sp<IOProfile> AudioPolicyManager::getProfileForDirectOutput(
audio_devices_t device,
uint32_t samplingRate,
audio_format_t format,
@@ -1130,6 +973,10 @@
if (audio_is_linear_pcm(format) && samplingRate <= MAX_MIXER_SAMPLING_RATE) {
goto non_direct_output;
}
+ // fall back to mixer output if possible when the direct output could not be open
+ if (audio_is_linear_pcm(format) && samplingRate <= MAX_MIXER_SAMPLING_RATE) {
+ goto non_direct_output;
+ }
return AUDIO_IO_HANDLE_NONE;
}
outputDesc->mSamplingRate = config.sample_rate;
@@ -1322,7 +1169,8 @@
outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) {
setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
- outputDesc->mPolicyMix->mRegistrationId);
+ outputDesc->mPolicyMix->mRegistrationId,
+ "remote-submix");
}
// force reevaluating accessibility routing when ringtone or alarm starts
@@ -1371,7 +1219,8 @@
outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) {
setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- outputDesc->mPolicyMix->mRegistrationId);
+ outputDesc->mPolicyMix->mRegistrationId,
+ "remote-submix");
}
outputDesc->mStopTime[stream] = systemTime();
@@ -1672,7 +1521,7 @@
if (address != "") {
setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
- address);
+ address, "remote-submix");
}
}
}
@@ -1720,7 +1569,7 @@
if (address != "") {
setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- address);
+ address, "remote-submix");
}
}
@@ -1849,7 +1698,7 @@
status_t status = NO_ERROR;
for (size_t i = 0; i < mOutputs.size(); i++) {
audio_devices_t curDevice =
- getDeviceForVolume(mOutputs.valueAt(i)->device());
+ ApmGains::getDeviceForVolume(mOutputs.valueAt(i)->device());
if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & strategyDevice) != 0)) {
status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice);
if (volStatus != NO_ERROR) {
@@ -1879,7 +1728,7 @@
if (device == AUDIO_DEVICE_OUT_DEFAULT) {
device = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
}
- device = getDeviceForVolume(device);
+ device = ApmGains::getDeviceForVolume(device);
*index = mStreams[stream].getVolumeIndex(device);
ALOGV("getStreamVolumeIndex() stream %d device %08x index %d", stream, device, *index);
@@ -2177,11 +2026,11 @@
if (mixes[i].mMixType == MIX_TYPE_PLAYERS) {
setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
- address.string());
+ address.string(), "remote-submix");
} else {
setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
- address.string());
+ address.string(), "remote-submix");
}
}
return NO_ERROR;
@@ -2219,7 +2068,7 @@
{
setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- address.string());
+ address.string(), "remote-submix");
}
if (getDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address.string()) ==
@@ -2227,7 +2076,7 @@
{
setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- address.string());
+ address.string(), "remote-submix");
}
module->removeOutputProfile(address);
module->removeInputProfile(address);
@@ -2463,7 +2312,7 @@
return NO_ERROR;
}
-sp<AudioPolicyManager::AudioOutputDescriptor> AudioPolicyManager::getOutputFromId(
+sp<AudioOutputDescriptor> AudioPolicyManager::getOutputFromId(
audio_port_handle_t id) const
{
sp<AudioOutputDescriptor> outputDesc = NULL;
@@ -2476,7 +2325,7 @@
return outputDesc;
}
-sp<AudioPolicyManager::AudioInputDescriptor> AudioPolicyManager::getInputFromId(
+sp<AudioInputDescriptor> AudioPolicyManager::getInputFromId(
audio_port_handle_t id) const
{
sp<AudioInputDescriptor> inputDesc = NULL;
@@ -2489,7 +2338,7 @@
return inputDesc;
}
-sp <AudioPolicyManager::HwModule> AudioPolicyManager::getModuleForDevice(
+sp <HwModule> AudioPolicyManager::getModuleForDevice(
audio_devices_t device) const
{
sp <HwModule> module;
@@ -2517,7 +2366,7 @@
return module;
}
-sp <AudioPolicyManager::HwModule> AudioPolicyManager::getModuleFromName(const char *name) const
+sp <HwModule> AudioPolicyManager::getModuleFromName(const char *name) const
{
sp <HwModule> module;
@@ -3042,6 +2891,8 @@
return android_atomic_inc(&mAudioPortGeneration);
}
+int32_t volatile AudioPolicyManager::mNextUniqueId = 1;
+
AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
:
#ifdef AUDIO_POLICY_TEST
@@ -3052,7 +2903,7 @@
mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0),
mA2dpSuspended(false),
- mSpeakerDrcEnabled(false), mNextUniqueId(1),
+ mSpeakerDrcEnabled(false),
mAudioPortGeneration(1),
mBeaconMuteRefCount(0),
mBeaconPlayingRefCount(0),
@@ -3065,7 +2916,7 @@
mForceUse[i] = AUDIO_POLICY_FORCE_NONE;
}
- mDefaultOutputDevice = new DeviceDescriptor(String8(""), AUDIO_DEVICE_OUT_SPEAKER);
+ mDefaultOutputDevice = new DeviceDescriptor(String8("Speaker"), AUDIO_DEVICE_OUT_SPEAKER);
if (loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE) != NO_ERROR) {
if (loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE) != NO_ERROR) {
ALOGE("could not load audio policy configuration file, setting defaults");
@@ -3148,9 +2999,8 @@
ssize_t index =
mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[k]);
// give a valid ID to an attached device once confirmed it is reachable
- if ((index >= 0) && (mAvailableOutputDevices[index]->mId == 0)) {
- mAvailableOutputDevices[index]->mId = nextUniqueId();
- mAvailableOutputDevices[index]->mModule = mHwModules[i];
+ if (index >= 0 && !mAvailableOutputDevices[index]->isAttached()) {
+ mAvailableOutputDevices[index]->attach(mHwModules[i]);
}
}
if (mPrimaryOutput == 0 &&
@@ -3217,9 +3067,8 @@
ssize_t index =
mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[k]);
// give a valid ID to an attached device once confirmed it is reachable
- if ((index >= 0) && (mAvailableInputDevices[index]->mId == 0)) {
- mAvailableInputDevices[index]->mId = nextUniqueId();
- mAvailableInputDevices[index]->mModule = mHwModules[i];
+ if (index >= 0 && !mAvailableInputDevices[index]->isAttached()) {
+ mAvailableInputDevices[index]->attach(mHwModules[i]);
}
}
mpClientInterface->closeInput(input);
@@ -3232,7 +3081,7 @@
}
// make sure all attached devices have been allocated a unique ID
for (size_t i = 0; i < mAvailableOutputDevices.size();) {
- if (mAvailableOutputDevices[i]->mId == 0) {
+ if (!mAvailableOutputDevices[i]->isAttached()) {
ALOGW("Input device %08x unreachable", mAvailableOutputDevices[i]->mDeviceType);
mAvailableOutputDevices.remove(mAvailableOutputDevices[i]);
continue;
@@ -3240,7 +3089,7 @@
i++;
}
for (size_t i = 0; i < mAvailableInputDevices.size();) {
- if (mAvailableInputDevices[i]->mId == 0) {
+ if (!mAvailableInputDevices[i]->isAttached()) {
ALOGW("Input device %08x unreachable", mAvailableInputDevices[i]->mDeviceType);
mAvailableInputDevices.remove(mAvailableInputDevices[i]);
continue;
@@ -4328,7 +4177,7 @@
return AUDIO_DEVICE_NONE;
}
audio_devices_t devices;
- AudioPolicyManager::routing_strategy strategy = getStrategy(stream);
+ routing_strategy strategy = getStrategy(stream);
devices = getDeviceForStrategy(strategy, true /*fromCache*/);
SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(devices, mOutputs);
for (size_t i = 0; i < outputs.size(); i++) {
@@ -4349,7 +4198,7 @@
return devices;
}
-AudioPolicyManager::routing_strategy AudioPolicyManager::getStrategy(
+routing_strategy AudioPolicyManager::getStrategy(
audio_stream_type_t stream) {
ALOG_ASSERT(stream != AUDIO_STREAM_PATCH,"getStrategy() called for AUDIO_STREAM_PATCH");
@@ -4618,7 +4467,7 @@
if (device) break;
device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_DEVICE;
if (device) break;
- if (mPhoneState != AUDIO_MODE_IN_CALL) {
+ if (!isInCall()) {
device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_ACCESSORY;
if (device) break;
device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
@@ -5128,7 +4977,7 @@
return status;
}
-sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device,
+sp<IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device,
String8 address,
uint32_t& samplingRate,
audio_format_t format,
@@ -5338,305 +5187,29 @@
}
-audio_devices_t AudioPolicyManager::getDeviceForVolume(audio_devices_t device)
-{
- if (device == AUDIO_DEVICE_NONE) {
- // this happens when forcing a route update and no track is active on an output.
- // In this case the returned category is not important.
- device = AUDIO_DEVICE_OUT_SPEAKER;
- } else if (popcount(device) > 1) {
- // Multiple device selection is either:
- // - speaker + one other device: give priority to speaker in this case.
- // - one A2DP device + another device: happens with duplicated output. In this case
- // retain the device on the A2DP output as the other must not correspond to an active
- // selection if not the speaker.
- // - HDMI-CEC system audio mode only output: give priority to available item in order.
- if (device & AUDIO_DEVICE_OUT_SPEAKER) {
- device = AUDIO_DEVICE_OUT_SPEAKER;
- } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) {
- device = AUDIO_DEVICE_OUT_HDMI_ARC;
- } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) {
- device = AUDIO_DEVICE_OUT_AUX_LINE;
- } else if (device & AUDIO_DEVICE_OUT_SPDIF) {
- device = AUDIO_DEVICE_OUT_SPDIF;
- } else {
- device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
- }
- }
-
- /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/
- if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE)
- device = AUDIO_DEVICE_OUT_SPEAKER;
-
- ALOGW_IF(popcount(device) != 1,
- "getDeviceForVolume() invalid device combination: %08x",
- device);
-
- return device;
-}
-
-AudioPolicyManager::device_category AudioPolicyManager::getDeviceCategory(audio_devices_t device)
-{
- switch(getDeviceForVolume(device)) {
- case AUDIO_DEVICE_OUT_EARPIECE:
- return DEVICE_CATEGORY_EARPIECE;
- case AUDIO_DEVICE_OUT_WIRED_HEADSET:
- case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
- case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
- case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
- case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
- case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
- return DEVICE_CATEGORY_HEADSET;
- case AUDIO_DEVICE_OUT_LINE:
- case AUDIO_DEVICE_OUT_AUX_DIGITAL:
- /*USB? Remote submix?*/
- return DEVICE_CATEGORY_EXT_MEDIA;
- case AUDIO_DEVICE_OUT_SPEAKER:
- case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
- case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
- case AUDIO_DEVICE_OUT_USB_ACCESSORY:
- case AUDIO_DEVICE_OUT_USB_DEVICE:
- case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
- default:
- return DEVICE_CATEGORY_SPEAKER;
- }
-}
-
-/* static */
-float AudioPolicyManager::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
- int indexInUi)
-{
- device_category deviceCategory = getDeviceCategory(device);
- const VolumeCurvePoint *curve = streamDesc.mVolumeCurve[deviceCategory];
-
- // the volume index in the UI is relative to the min and max volume indices for this stream type
- int nbSteps = 1 + curve[VOLMAX].mIndex -
- curve[VOLMIN].mIndex;
- int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) /
- (streamDesc.mIndexMax - streamDesc.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[VOLMIN].mIndex) { // out of bounds
- return 0.0f;
- } else if (volIdx < curve[VOLKNEE1].mIndex) {
- segment = 0;
- } else if (volIdx < curve[VOLKNEE2].mIndex) {
- segment = 1;
- } else if (volIdx <= curve[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)) );
-
- float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
-
- ALOGVV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f] ampl=%.5f",
- curve[segment].mIndex, volIdx,
- curve[segment+1].mIndex,
- curve[segment].mDBAttenuation,
- decibels,
- curve[segment+1].mDBAttenuation,
- amplification);
-
- return amplification;
-}
-
-const AudioPolicyManager::VolumeCurvePoint
- AudioPolicyManager::sDefaultVolumeCurve[AudioPolicyManager::VOLCNT] = {
- {1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f}
-};
-
-const AudioPolicyManager::VolumeCurvePoint
- AudioPolicyManager::sDefaultMediaVolumeCurve[AudioPolicyManager::VOLCNT] = {
- {1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f}
-};
-
-const AudioPolicyManager::VolumeCurvePoint
- AudioPolicyManager::sExtMediaSystemVolumeCurve[AudioPolicyManager::VOLCNT] = {
- {1, -58.0f}, {20, -40.0f}, {60, -21.0f}, {100, -10.0f}
-};
-
-const AudioPolicyManager::VolumeCurvePoint
- AudioPolicyManager::sSpeakerMediaVolumeCurve[AudioPolicyManager::VOLCNT] = {
- {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f}
-};
-
-const AudioPolicyManager::VolumeCurvePoint
- AudioPolicyManager::sSpeakerMediaVolumeCurveDrc[AudioPolicyManager::VOLCNT] = {
- {1, -55.0f}, {20, -43.0f}, {86, -12.0f}, {100, 0.0f}
-};
-
-const AudioPolicyManager::VolumeCurvePoint
- AudioPolicyManager::sSpeakerSonificationVolumeCurve[AudioPolicyManager::VOLCNT] = {
- {1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f}
-};
-
-const AudioPolicyManager::VolumeCurvePoint
- AudioPolicyManager::sSpeakerSonificationVolumeCurveDrc[AudioPolicyManager::VOLCNT] = {
- {1, -35.7f}, {33, -26.1f}, {66, -13.2f}, {100, 0.0f}
-};
-
-// AUDIO_STREAM_SYSTEM, AUDIO_STREAM_ENFORCED_AUDIBLE and AUDIO_STREAM_DTMF volume tracks
-// AUDIO_STREAM_RING on phones and AUDIO_STREAM_MUSIC on tablets.
-// AUDIO_STREAM_DTMF tracks AUDIO_STREAM_VOICE_CALL while in call (See AudioService.java).
-// The range is constrained between -24dB and -6dB over speaker and -30dB and -18dB over headset.
-
-const AudioPolicyManager::VolumeCurvePoint
- AudioPolicyManager::sDefaultSystemVolumeCurve[AudioPolicyManager::VOLCNT] = {
- {1, -24.0f}, {33, -18.0f}, {66, -12.0f}, {100, -6.0f}
-};
-
-const AudioPolicyManager::VolumeCurvePoint
- AudioPolicyManager::sDefaultSystemVolumeCurveDrc[AudioPolicyManager::VOLCNT] = {
- {1, -34.0f}, {33, -24.0f}, {66, -15.0f}, {100, -6.0f}
-};
-
-const AudioPolicyManager::VolumeCurvePoint
- AudioPolicyManager::sHeadsetSystemVolumeCurve[AudioPolicyManager::VOLCNT] = {
- {1, -30.0f}, {33, -26.0f}, {66, -22.0f}, {100, -18.0f}
-};
-
-const AudioPolicyManager::VolumeCurvePoint
- AudioPolicyManager::sDefaultVoiceVolumeCurve[AudioPolicyManager::VOLCNT] = {
- {0, -42.0f}, {33, -28.0f}, {66, -14.0f}, {100, 0.0f}
-};
-
-const AudioPolicyManager::VolumeCurvePoint
- AudioPolicyManager::sSpeakerVoiceVolumeCurve[AudioPolicyManager::VOLCNT] = {
- {0, -24.0f}, {33, -16.0f}, {66, -8.0f}, {100, 0.0f}
-};
-
-const AudioPolicyManager::VolumeCurvePoint
- AudioPolicyManager::sLinearVolumeCurve[AudioPolicyManager::VOLCNT] = {
- {0, -96.0f}, {33, -68.0f}, {66, -34.0f}, {100, 0.0f}
-};
-
-const AudioPolicyManager::VolumeCurvePoint
- AudioPolicyManager::sSilentVolumeCurve[AudioPolicyManager::VOLCNT] = {
- {0, -96.0f}, {1, -96.0f}, {2, -96.0f}, {100, -96.0f}
-};
-
-const AudioPolicyManager::VolumeCurvePoint
- AudioPolicyManager::sFullScaleVolumeCurve[AudioPolicyManager::VOLCNT] = {
- {0, 0.0f}, {1, 0.0f}, {2, 0.0f}, {100, 0.0f}
-};
-
-const AudioPolicyManager::VolumeCurvePoint
- *AudioPolicyManager::sVolumeProfiles[AUDIO_STREAM_CNT]
- [AudioPolicyManager::DEVICE_CATEGORY_CNT] = {
- { // AUDIO_STREAM_VOICE_CALL
- sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
- sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_SYSTEM
- sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
- sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_RING
- sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
- sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- sDefaultVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_MUSIC
- sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
- sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_ALARM
- sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
- sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- sDefaultVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_NOTIFICATION
- sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
- sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- sDefaultVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_BLUETOOTH_SCO
- sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
- sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_ENFORCED_AUDIBLE
- sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
- sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_DTMF
- sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
- sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_TTS
- // "Transmitted Through Speaker": always silent except on DEVICE_CATEGORY_SPEAKER
- sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET
- sLinearVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- sSilentVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_ACCESSIBILITY
- sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
- sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_REROUTING
- sFullScaleVolumeCurve, // DEVICE_CATEGORY_HEADSET
- sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- sFullScaleVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- sFullScaleVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_PATCH
- sFullScaleVolumeCurve, // DEVICE_CATEGORY_HEADSET
- sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- sFullScaleVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- sFullScaleVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
-};
-
void AudioPolicyManager::initializeVolumeCurves()
{
for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
- for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+ for (int j = 0; j < ApmGains::DEVICE_CATEGORY_CNT; j++) {
mStreams[i].mVolumeCurve[j] =
- sVolumeProfiles[i][j];
+ ApmGains::sVolumeProfiles[i][j];
}
}
// Check availability of DRC on speaker path: if available, override some of the speaker curves
if (mSpeakerDrcEnabled) {
- mStreams[AUDIO_STREAM_SYSTEM].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
- sDefaultSystemVolumeCurveDrc;
- mStreams[AUDIO_STREAM_RING].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
- sSpeakerSonificationVolumeCurveDrc;
- mStreams[AUDIO_STREAM_ALARM].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
- sSpeakerSonificationVolumeCurveDrc;
- mStreams[AUDIO_STREAM_NOTIFICATION].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
- sSpeakerSonificationVolumeCurveDrc;
- mStreams[AUDIO_STREAM_MUSIC].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
- sSpeakerMediaVolumeCurveDrc;
- mStreams[AUDIO_STREAM_ACCESSIBILITY].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
- sSpeakerMediaVolumeCurveDrc;
+ mStreams[AUDIO_STREAM_SYSTEM].mVolumeCurve[ApmGains::DEVICE_CATEGORY_SPEAKER] =
+ ApmGains::sDefaultSystemVolumeCurveDrc;
+ mStreams[AUDIO_STREAM_RING].mVolumeCurve[ApmGains::DEVICE_CATEGORY_SPEAKER] =
+ ApmGains::sSpeakerSonificationVolumeCurveDrc;
+ mStreams[AUDIO_STREAM_ALARM].mVolumeCurve[ApmGains::DEVICE_CATEGORY_SPEAKER] =
+ ApmGains::sSpeakerSonificationVolumeCurveDrc;
+ mStreams[AUDIO_STREAM_NOTIFICATION].mVolumeCurve[ApmGains::DEVICE_CATEGORY_SPEAKER] =
+ ApmGains::sSpeakerSonificationVolumeCurveDrc;
+ mStreams[AUDIO_STREAM_MUSIC].mVolumeCurve[ApmGains::DEVICE_CATEGORY_SPEAKER] =
+ ApmGains::sSpeakerMediaVolumeCurveDrc;
+ mStreams[AUDIO_STREAM_ACCESSIBILITY].mVolumeCurve[ApmGains::DEVICE_CATEGORY_SPEAKER] =
+ ApmGains::sSpeakerMediaVolumeCurveDrc;
}
}
@@ -5653,7 +5226,7 @@
device = outputDesc->device();
}
- volume = volIndexToAmpl(device, streamDesc, index);
+ volume = ApmGains::volIndexToAmpl(device, streamDesc, index);
// if a headset is connected, apply the following rules to ring tones and notifications
// to avoid sound level bursts in user's ears:
@@ -5909,319 +5482,6 @@
}
-// --- AudioOutputDescriptor class implementation
-
-AudioPolicyManager::AudioOutputDescriptor::AudioOutputDescriptor(
- const sp<IOProfile>& profile)
- : mId(0), mIoHandle(0), mLatency(0),
- mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL),
- mPatchHandle(0),
- mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0)
-{
- // clear usage count for all stream types
- for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
- mRefCount[i] = 0;
- mCurVolume[i] = -1.0;
- mMuteCount[i] = 0;
- mStopTime[i] = 0;
- }
- for (int i = 0; i < NUM_STRATEGIES; i++) {
- mStrategyMutedByDevice[i] = false;
- }
- if (profile != NULL) {
- mFlags = (audio_output_flags_t)profile->mFlags;
- mSamplingRate = profile->pickSamplingRate();
- mFormat = profile->pickFormat();
- mChannelMask = profile->pickChannelMask();
- if (profile->mGains.size() > 0) {
- profile->mGains[0]->getDefaultConfig(&mGain);
- }
- }
-}
-
-audio_devices_t AudioPolicyManager::AudioOutputDescriptor::device() const
-{
- if (isDuplicated()) {
- return (audio_devices_t)(mOutput1->mDevice | mOutput2->mDevice);
- } else {
- return mDevice;
- }
-}
-
-uint32_t AudioPolicyManager::AudioOutputDescriptor::latency()
-{
- if (isDuplicated()) {
- return (mOutput1->mLatency > mOutput2->mLatency) ? mOutput1->mLatency : mOutput2->mLatency;
- } else {
- return mLatency;
- }
-}
-
-bool AudioPolicyManager::AudioOutputDescriptor::sharesHwModuleWith(
- const sp<AudioOutputDescriptor> outputDesc)
-{
- if (isDuplicated()) {
- return mOutput1->sharesHwModuleWith(outputDesc) || mOutput2->sharesHwModuleWith(outputDesc);
- } else if (outputDesc->isDuplicated()){
- return sharesHwModuleWith(outputDesc->mOutput1) || sharesHwModuleWith(outputDesc->mOutput2);
- } else {
- return (mProfile->mModule == outputDesc->mProfile->mModule);
- }
-}
-
-void AudioPolicyManager::AudioOutputDescriptor::changeRefCount(audio_stream_type_t stream,
- int delta)
-{
- // forward usage count change to attached outputs
- if (isDuplicated()) {
- mOutput1->changeRefCount(stream, delta);
- mOutput2->changeRefCount(stream, delta);
- }
- if ((delta + (int)mRefCount[stream]) < 0) {
- ALOGW("changeRefCount() invalid delta %d for stream %d, refCount %d",
- delta, stream, mRefCount[stream]);
- mRefCount[stream] = 0;
- return;
- }
- mRefCount[stream] += delta;
- ALOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
-}
-
-audio_devices_t AudioPolicyManager::AudioOutputDescriptor::supportedDevices()
-{
- if (isDuplicated()) {
- return (audio_devices_t)(mOutput1->supportedDevices() | mOutput2->supportedDevices());
- } else {
- return mProfile->mSupportedDevices.types() ;
- }
-}
-
-bool AudioPolicyManager::AudioOutputDescriptor::isActive(uint32_t inPastMs) const
-{
- return isStrategyActive(NUM_STRATEGIES, inPastMs);
-}
-
-bool AudioPolicyManager::AudioOutputDescriptor::isStrategyActive(routing_strategy strategy,
- uint32_t inPastMs,
- nsecs_t sysTime) const
-{
- if ((sysTime == 0) && (inPastMs != 0)) {
- sysTime = systemTime();
- }
- for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
- if (i == AUDIO_STREAM_PATCH) {
- continue;
- }
- if (((getStrategy((audio_stream_type_t)i) == strategy) ||
- (NUM_STRATEGIES == strategy)) &&
- isStreamActive((audio_stream_type_t)i, inPastMs, sysTime)) {
- return true;
- }
- }
- return false;
-}
-
-bool AudioPolicyManager::AudioOutputDescriptor::isStreamActive(audio_stream_type_t stream,
- uint32_t inPastMs,
- nsecs_t sysTime) const
-{
- if (mRefCount[stream] != 0) {
- return true;
- }
- if (inPastMs == 0) {
- return false;
- }
- if (sysTime == 0) {
- sysTime = systemTime();
- }
- if (ns2ms(sysTime - mStopTime[stream]) < inPastMs) {
- return true;
- }
- return false;
-}
-
-void AudioPolicyManager::AudioOutputDescriptor::toAudioPortConfig(
- struct audio_port_config *dstConfig,
- const struct audio_port_config *srcConfig) const
-{
- ALOG_ASSERT(!isDuplicated(), "toAudioPortConfig() called on duplicated output %d", mIoHandle);
-
- dstConfig->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
- AUDIO_PORT_CONFIG_FORMAT|AUDIO_PORT_CONFIG_GAIN;
- if (srcConfig != NULL) {
- dstConfig->config_mask |= srcConfig->config_mask;
- }
- AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
-
- dstConfig->id = mId;
- dstConfig->role = AUDIO_PORT_ROLE_SOURCE;
- dstConfig->type = AUDIO_PORT_TYPE_MIX;
- dstConfig->ext.mix.hw_module = mProfile->mModule->mHandle;
- dstConfig->ext.mix.handle = mIoHandle;
- dstConfig->ext.mix.usecase.stream = AUDIO_STREAM_DEFAULT;
-}
-
-void AudioPolicyManager::AudioOutputDescriptor::toAudioPort(
- struct audio_port *port) const
-{
- ALOG_ASSERT(!isDuplicated(), "toAudioPort() called on duplicated output %d", mIoHandle);
- mProfile->toAudioPort(port);
- port->id = mId;
- toAudioPortConfig(&port->active_config);
- port->ext.mix.hw_module = mProfile->mModule->mHandle;
- port->ext.mix.handle = mIoHandle;
- port->ext.mix.latency_class =
- mFlags & AUDIO_OUTPUT_FLAG_FAST ? AUDIO_LATENCY_LOW : AUDIO_LATENCY_NORMAL;
-}
-
-status_t AudioPolicyManager::AudioOutputDescriptor::dump(int fd)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, " ID: %d\n", mId);
- result.append(buffer);
- snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
- result.append(buffer);
- snprintf(buffer, SIZE, " Format: %08x\n", mFormat);
- result.append(buffer);
- snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
- result.append(buffer);
- snprintf(buffer, SIZE, " Latency: %d\n", mLatency);
- result.append(buffer);
- snprintf(buffer, SIZE, " Flags %08x\n", mFlags);
- result.append(buffer);
- snprintf(buffer, SIZE, " Devices %08x\n", device());
- result.append(buffer);
- snprintf(buffer, SIZE, " Stream volume refCount muteCount\n");
- result.append(buffer);
- for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
- snprintf(buffer, SIZE, " %02d %.03f %02d %02d\n",
- i, mCurVolume[i], mRefCount[i], mMuteCount[i]);
- result.append(buffer);
- }
- write(fd, result.string(), result.size());
-
- return NO_ERROR;
-}
-
-// --- AudioInputDescriptor class implementation
-
-AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile)
- : mId(0), mIoHandle(0),
- mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0), mRefCount(0),
- mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile), mIsSoundTrigger(false)
-{
- if (profile != NULL) {
- mSamplingRate = profile->pickSamplingRate();
- mFormat = profile->pickFormat();
- mChannelMask = profile->pickChannelMask();
- if (profile->mGains.size() > 0) {
- profile->mGains[0]->getDefaultConfig(&mGain);
- }
- }
-}
-
-void AudioPolicyManager::AudioInputDescriptor::toAudioPortConfig(
- struct audio_port_config *dstConfig,
- const struct audio_port_config *srcConfig) const
-{
- ALOG_ASSERT(mProfile != 0,
- "toAudioPortConfig() called on input with null profile %d", mIoHandle);
- dstConfig->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
- AUDIO_PORT_CONFIG_FORMAT|AUDIO_PORT_CONFIG_GAIN;
- if (srcConfig != NULL) {
- dstConfig->config_mask |= srcConfig->config_mask;
- }
-
- AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
-
- dstConfig->id = mId;
- dstConfig->role = AUDIO_PORT_ROLE_SINK;
- dstConfig->type = AUDIO_PORT_TYPE_MIX;
- dstConfig->ext.mix.hw_module = mProfile->mModule->mHandle;
- dstConfig->ext.mix.handle = mIoHandle;
- dstConfig->ext.mix.usecase.source = mInputSource;
-}
-
-void AudioPolicyManager::AudioInputDescriptor::toAudioPort(
- struct audio_port *port) const
-{
- ALOG_ASSERT(mProfile != 0, "toAudioPort() called on input with null profile %d", mIoHandle);
-
- mProfile->toAudioPort(port);
- port->id = mId;
- toAudioPortConfig(&port->active_config);
- port->ext.mix.hw_module = mProfile->mModule->mHandle;
- port->ext.mix.handle = mIoHandle;
- port->ext.mix.latency_class = AUDIO_LATENCY_NORMAL;
-}
-
-status_t AudioPolicyManager::AudioInputDescriptor::dump(int fd)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, " ID: %d\n", mId);
- result.append(buffer);
- snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
- result.append(buffer);
- snprintf(buffer, SIZE, " Format: %d\n", mFormat);
- result.append(buffer);
- snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
- 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());
-
- return NO_ERROR;
-}
-
-// --- StreamDescriptor class implementation
-
-AudioPolicyManager::StreamDescriptor::StreamDescriptor()
- : mIndexMin(0), mIndexMax(1), mCanBeMuted(true)
-{
- mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, 0);
-}
-
-int AudioPolicyManager::StreamDescriptor::getVolumeIndex(audio_devices_t device)
-{
- device = AudioPolicyManager::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);
-}
-
-void AudioPolicyManager::StreamDescriptor::dump(int fd)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- 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());
-}
-
// --- EffectDescriptor class implementation
status_t AudioPolicyManager::EffectDescriptor::dump(int fd)
@@ -6245,1601 +5505,9 @@
return NO_ERROR;
}
-// --- HwModule class implementation
-
-AudioPolicyManager::HwModule::HwModule(const char *name)
- : mName(strndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN)),
- mHalVersion(AUDIO_DEVICE_API_VERSION_MIN), mHandle(0)
-{
-}
-
-AudioPolicyManager::HwModule::~HwModule()
-{
- for (size_t i = 0; i < mOutputProfiles.size(); i++) {
- mOutputProfiles[i]->mSupportedDevices.clear();
- }
- for (size_t i = 0; i < mInputProfiles.size(); i++) {
- mInputProfiles[i]->mSupportedDevices.clear();
- }
- free((void *)mName);
-}
-
-status_t AudioPolicyManager::HwModule::loadInput(cnode *root)
-{
- cnode *node = root->first_child;
-
- sp<IOProfile> profile = new IOProfile(String8(root->name), AUDIO_PORT_ROLE_SINK, this);
-
- 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.loadDevicesFromName((char *)node->value,
- mDeclaredDevices);
- } else if (strcmp(node->name, FLAGS_TAG) == 0) {
- profile->mFlags = 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());
-
- mInputProfiles.add(profile);
- return NO_ERROR;
- } else {
- return BAD_VALUE;
- }
-}
-
-status_t AudioPolicyManager::HwModule::loadOutput(cnode *root)
-{
- cnode *node = root->first_child;
-
- sp<IOProfile> profile = new IOProfile(String8(root->name), AUDIO_PORT_ROLE_SOURCE, this);
-
- 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.loadDevicesFromName((char *)node->value,
- mDeclaredDevices);
- } else if (strcmp(node->name, FLAGS_TAG) == 0) {
- profile->mFlags = 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);
-
- mOutputProfiles.add(profile);
- return NO_ERROR;
- } else {
- return BAD_VALUE;
- }
-}
-
-status_t AudioPolicyManager::HwModule::loadDevice(cnode *root)
-{
- cnode *node = root->first_child;
-
- audio_devices_t type = AUDIO_DEVICE_NONE;
- while (node) {
- if (strcmp(node->name, DEVICE_TYPE) == 0) {
- type = 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(String8(root->name), type);
- deviceDesc->mModule = this;
-
- node = root->first_child;
- while (node) {
- if (strcmp(node->name, 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 name %s type %08x address %s",
- deviceDesc->mName.string(), type, deviceDesc->mAddress.string());
-
- mDeclaredDevices.add(deviceDesc);
-
- return NO_ERROR;
-}
-
-status_t AudioPolicyManager::HwModule::addOutputProfile(String8 name, const audio_config_t *config,
- audio_devices_t device, String8 address)
-{
- sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SOURCE, this);
-
- profile->mSamplingRates.add(config->sample_rate);
- profile->mChannelMasks.add(config->channel_mask);
- profile->mFormats.add(config->format);
-
- sp<DeviceDescriptor> devDesc = new DeviceDescriptor(String8(""), device);
- devDesc->mAddress = address;
- profile->mSupportedDevices.add(devDesc);
-
- mOutputProfiles.add(profile);
-
- return NO_ERROR;
-}
-
-status_t AudioPolicyManager::HwModule::removeOutputProfile(String8 name)
-{
- for (size_t i = 0; i < mOutputProfiles.size(); i++) {
- if (mOutputProfiles[i]->mName == name) {
- mOutputProfiles.removeAt(i);
- break;
- }
- }
-
- return NO_ERROR;
-}
-
-status_t AudioPolicyManager::HwModule::addInputProfile(String8 name, const audio_config_t *config,
- audio_devices_t device, String8 address)
-{
- sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SINK, this);
-
- profile->mSamplingRates.add(config->sample_rate);
- profile->mChannelMasks.add(config->channel_mask);
- profile->mFormats.add(config->format);
-
- sp<DeviceDescriptor> devDesc = new DeviceDescriptor(String8(""), device);
- devDesc->mAddress = address;
- profile->mSupportedDevices.add(devDesc);
-
- ALOGV("addInputProfile() name %s rate %d mask 0x08", name.string(), config->sample_rate, config->channel_mask);
-
- mInputProfiles.add(profile);
-
- return NO_ERROR;
-}
-
-status_t AudioPolicyManager::HwModule::removeInputProfile(String8 name)
-{
- for (size_t i = 0; i < mInputProfiles.size(); i++) {
- if (mInputProfiles[i]->mName == name) {
- mInputProfiles.removeAt(i);
- break;
- }
- }
-
- return NO_ERROR;
-}
-
-
-void AudioPolicyManager::HwModule::dump(int fd)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, " - name: %s\n", mName);
- result.append(buffer);
- snprintf(buffer, SIZE, " - handle: %d\n", mHandle);
- result.append(buffer);
- snprintf(buffer, SIZE, " - version: %u.%u\n", mHalVersion >> 8, mHalVersion & 0xFF);
- result.append(buffer);
- write(fd, result.string(), result.size());
- if (mOutputProfiles.size()) {
- write(fd, " - outputs:\n", strlen(" - outputs:\n"));
- for (size_t i = 0; i < mOutputProfiles.size(); i++) {
- snprintf(buffer, SIZE, " output %zu:\n", i);
- write(fd, buffer, strlen(buffer));
- mOutputProfiles[i]->dump(fd);
- }
- }
- if (mInputProfiles.size()) {
- write(fd, " - inputs:\n", strlen(" - inputs:\n"));
- for (size_t i = 0; i < mInputProfiles.size(); i++) {
- snprintf(buffer, SIZE, " input %zu:\n", i);
- write(fd, buffer, strlen(buffer));
- 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);
- }
- }
-}
-
-// --- AudioPort class implementation
-
-
-AudioPolicyManager::AudioPort::AudioPort(const String8& name, audio_port_type_t type,
- audio_port_role_t role, const sp<HwModule>& module) :
- mName(name), mType(type), mRole(role), mModule(module), mFlags(0)
-{
- mUseInChannelMask = ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) ||
- ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK));
-}
-
-void AudioPolicyManager::AudioPort::toAudioPort(struct audio_port *port) const
-{
- port->role = mRole;
- port->type = mType;
- 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 = i;
- for (i = 0; i < mChannelMasks.size() && i < AUDIO_PORT_MAX_CHANNEL_MASKS; i++) {
- if (mChannelMasks[i] != 0) {
- port->channel_masks[i] = mChannelMasks[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];
- }
- }
- port->num_formats = i;
-
- ALOGV("AudioPort::toAudioPort() num gains %zu", mGains.size());
-
- for (i = 0; i < mGains.size() && i < AUDIO_PORT_MAX_GAINS; i++) {
- port->gains[i] = mGains[i]->mGain;
- }
- port->num_gains = i;
-}
-
-void AudioPolicyManager::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;
- break;
- }
- }
- if (!hasRate) { // never import a sampling rate twice
- mSamplingRates.add(rate);
- }
- }
- }
- 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 channel mask twice
- mFormats.add(format);
- }
- }
- }
- for (size_t k = 0 ; k < port->mGains.size() ; k++) {
- sp<AudioGain> gain = port->mGains.itemAt(k);
- if (gain != 0) {
- bool hasGain = false;
- for (size_t l = 0 ; l < mGains.size() ; l++) {
- if (gain == mGains.itemAt(l)) {
- hasGain = true;
- break;
- }
- }
- if (!hasGain) { // never import a gain twice
- mGains.add(gain);
- }
- }
- }
-}
-
-void AudioPolicyManager::AudioPort::clearCapabilities() {
- mChannelMasks.clear();
- mFormats.clear();
- mSamplingRates.clear();
- mGains.clear();
-}
-
-void AudioPolicyManager::AudioPort::loadSamplingRates(char *name)
-{
- 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 AudioPolicyManager::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)stringToEnum(sFormatNameToEnumTable,
- ARRAY_SIZE(sFormatNameToEnumTable),
- str);
- if (format != AUDIO_FORMAT_DEFAULT) {
- mFormats.add(format);
- }
- str = strtok(NULL, "|");
- }
-}
-
-void AudioPolicyManager::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)stringToEnum(sInChannelsNameToEnumTable,
- ARRAY_SIZE(sInChannelsNameToEnumTable),
- str);
- if (channelMask != 0) {
- ALOGV("loadInChannels() adding channelMask %04x", channelMask);
- mChannelMasks.add(channelMask);
- }
- str = strtok(NULL, "|");
- }
-}
-
-void AudioPolicyManager::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)stringToEnum(sOutChannelsNameToEnumTable,
- ARRAY_SIZE(sOutChannelsNameToEnumTable),
- str);
- if (channelMask != 0) {
- mChannelMasks.add(channelMask);
- }
- str = strtok(NULL, "|");
- }
- return;
-}
-
-audio_gain_mode_t AudioPolicyManager::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)stringToEnum(sGainModeNameToEnumTable,
- ARRAY_SIZE(sGainModeNameToEnumTable),
- str);
- str = strtok(NULL, "|");
- }
- return mode;
-}
-
-void AudioPolicyManager::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)stringToEnum(sInChannelsNameToEnumTable,
- ARRAY_SIZE(sInChannelsNameToEnumTable),
- (char *)node->value);
- } else {
- gain->mGain.channel_mask =
- (audio_channel_mask_t)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 AudioPolicyManager::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 AudioPolicyManager::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 AudioPolicyManager::AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate,
- uint32_t *updatedSamplingRate) const
-{
- if (mSamplingRates.isEmpty()) {
- 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;
- }
- }
- }
- // This uses hard-coded knowledge about AudioFlinger resampling ratios.
- // TODO Move these assumptions out.
- static const uint32_t kMaxDownSampleRatio = 6; // beyond this aliasing occurs
- static const uint32_t kMaxUpSampleRatio = 256; // beyond this sample rate inaccuracies occur
- // due to approximation by an int32_t of the
- // phase increments
- // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
- if (minAbove >= 0) {
- candidate = mSamplingRates[minAbove];
- if (candidate / kMaxDownSampleRatio <= 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 * kMaxUpSampleRatio >= samplingRate) {
- if (updatedSamplingRate != NULL) {
- *updatedSamplingRate = candidate;
- }
- return NO_ERROR;
- }
- }
- // leave updatedSamplingRate unmodified
- return BAD_VALUE;
-}
-
-status_t AudioPolicyManager::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 AudioPolicyManager::AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask)
- const
-{
- if (mChannelMasks.isEmpty()) {
- return NO_ERROR;
- }
-
- const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
- for (size_t i = 0; i < mChannelMasks.size(); i ++) {
- // FIXME Does not handle multi-channel automatic conversions yet
- audio_channel_mask_t supported = mChannelMasks[i];
- if (supported == channelMask) {
- return NO_ERROR;
- }
- if (isRecordThread) {
- // This uses hard-coded knowledge that AudioFlinger can silently down-mix and up-mix.
- // FIXME Abstract this out to a table.
- if (((supported == AUDIO_CHANNEL_IN_FRONT_BACK || supported == AUDIO_CHANNEL_IN_STEREO)
- && channelMask == AUDIO_CHANNEL_IN_MONO) ||
- (supported == AUDIO_CHANNEL_IN_MONO && (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
- || channelMask == AUDIO_CHANNEL_IN_STEREO))) {
- return NO_ERROR;
- }
- }
- }
- return BAD_VALUE;
-}
-
-status_t AudioPolicyManager::AudioPort::checkFormat(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;
-}
-
-
-uint32_t AudioPolicyManager::AudioPort::pickSamplingRate() const
-{
- // special case for uninitialized dynamic profile
- if (mSamplingRates.size() == 1 && mSamplingRates[0] == 0) {
- return 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))) {
- uint32_t samplingRate = UINT_MAX;
- for (size_t i = 0; i < mSamplingRates.size(); i ++) {
- if ((mSamplingRates[i] < samplingRate) && (mSamplingRates[i] > 0)) {
- samplingRate = mSamplingRates[i];
- }
- }
- return (samplingRate == UINT_MAX) ? 0 : samplingRate;
- }
-
- 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
- if (mType != AUDIO_PORT_TYPE_MIX) {
- maxRate = UINT_MAX;
- }
- for (size_t i = 0; i < mSamplingRates.size(); i ++) {
- if ((mSamplingRates[i] > samplingRate) && (mSamplingRates[i] <= maxRate)) {
- samplingRate = mSamplingRates[i];
- }
- }
- return samplingRate;
-}
-
-audio_channel_mask_t AudioPolicyManager::AudioPort::pickChannelMask() 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;
-
- // 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))) {
- uint32_t channelCount = 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]);
- }
- if ((cnlCount < channelCount) && (cnlCount > 0)) {
- channelMask = mChannelMasks[i];
- channelCount = cnlCount;
- }
- }
- return channelMask;
- }
-
- 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]);
- }
- if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
- channelMask = mChannelMasks[i];
- channelCount = cnlCount;
- }
- }
- return channelMask;
-}
-
-/* format in order of increasing preference */
-const audio_format_t AudioPolicyManager::AudioPort::sPcmFormatCompareTable[] = {
- AUDIO_FORMAT_DEFAULT,
- AUDIO_FORMAT_PCM_16_BIT,
- AUDIO_FORMAT_PCM_8_24_BIT,
- AUDIO_FORMAT_PCM_24_BIT_PACKED,
- AUDIO_FORMAT_PCM_32_BIT,
- AUDIO_FORMAT_PCM_FLOAT,
-};
-
-int AudioPolicyManager::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()
- if (!audio_is_linear_pcm(format1)) {
- if (!audio_is_linear_pcm(format2)) {
- return 0;
- }
- return 1;
- }
- if (!audio_is_linear_pcm(format2)) {
- return -1;
- }
-
- int index1 = -1, index2 = -1;
- for (size_t i = 0;
- (i < ARRAY_SIZE(sPcmFormatCompareTable)) && ((index1 == -1) || (index2 == -1));
- i ++) {
- if (sPcmFormatCompareTable[i] == format1) {
- index1 = i;
- }
- if (sPcmFormatCompareTable[i] == format2) {
- index2 = i;
- }
- }
- // format1 not found => index1 < 0 => format2 > format1
- // format2 not found => index2 < 0 => format2 < format1
- return index1 - index2;
-}
-
-audio_format_t AudioPolicyManager::AudioPort::pickFormat() const
-{
- // special case for uninitialized dynamic profile
- if (mFormats.size() == 1 && mFormats[0] == 0) {
- return AUDIO_FORMAT_DEFAULT;
- }
-
- audio_format_t format = AUDIO_FORMAT_DEFAULT;
- audio_format_t bestFormat =
- AudioPolicyManager::AudioPort::sPcmFormatCompareTable[
- ARRAY_SIZE(AudioPolicyManager::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)))) {
- 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];
- }
- }
- return format;
-}
-
-status_t AudioPolicyManager::AudioPort::checkGain(const struct audio_gain_config *gainConfig,
- int index) const
-{
- if (index < 0 || (size_t)index >= mGains.size()) {
- return BAD_VALUE;
- }
- return mGains[index]->checkConfig(gainConfig);
-}
-
-void AudioPolicyManager::AudioPort::dump(int fd, int spaces) const
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- if (mName.size() != 0) {
- snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
- result.append(buffer);
- }
-
- 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]);
- }
- 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 = enumToString(sFormatNameToEnumTable,
- ARRAY_SIZE(sFormatNameToEnumTable),
- mFormats[i]);
- if (i == 0 && strcmp(formatStr, "") == 0) {
- snprintf(buffer, SIZE, "Dynamic");
- } 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);
- result.append(buffer);
- for (size_t i = 0; i < mGains.size(); i++) {
- mGains[i]->dump(fd, spaces + 2, i);
- }
- }
-}
-
-// --- AudioGain class implementation
-
-AudioPolicyManager::AudioGain::AudioGain(int index, bool useInChannelMask)
-{
- mIndex = index;
- mUseInChannelMask = useInChannelMask;
- memset(&mGain, 0, sizeof(struct audio_gain));
-}
-
-void AudioPolicyManager::AudioGain::getDefaultConfig(struct audio_gain_config *config)
-{
- config->index = mIndex;
- config->mode = mGain.mode;
- config->channel_mask = mGain.channel_mask;
- if ((mGain.mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
- config->values[0] = mGain.default_value;
- } else {
- uint32_t numValues;
- if (mUseInChannelMask) {
- numValues = audio_channel_count_from_in_mask(mGain.channel_mask);
- } else {
- numValues = audio_channel_count_from_out_mask(mGain.channel_mask);
- }
- for (size_t i = 0; i < numValues; i++) {
- config->values[i] = mGain.default_value;
- }
- }
- if ((mGain.mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
- config->ramp_duration_ms = mGain.min_ramp_ms;
- }
-}
-
-status_t AudioPolicyManager::AudioGain::checkConfig(const struct audio_gain_config *config)
-{
- if ((config->mode & ~mGain.mode) != 0) {
- return BAD_VALUE;
- }
- if ((config->mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
- if ((config->values[0] < mGain.min_value) ||
- (config->values[0] > mGain.max_value)) {
- return BAD_VALUE;
- }
- } else {
- if ((config->channel_mask & ~mGain.channel_mask) != 0) {
- return BAD_VALUE;
- }
- uint32_t numValues;
- if (mUseInChannelMask) {
- numValues = audio_channel_count_from_in_mask(config->channel_mask);
- } else {
- numValues = audio_channel_count_from_out_mask(config->channel_mask);
- }
- for (size_t i = 0; i < numValues; i++) {
- if ((config->values[i] < mGain.min_value) ||
- (config->values[i] > mGain.max_value)) {
- return BAD_VALUE;
- }
- }
- }
- if ((config->mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
- if ((config->ramp_duration_ms < mGain.min_ramp_ms) ||
- (config->ramp_duration_ms > mGain.max_ramp_ms)) {
- return BAD_VALUE;
- }
- }
- return NO_ERROR;
-}
-
-void AudioPolicyManager::AudioGain::dump(int fd, int spaces, int index) const
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "%*sGain %d:\n", spaces, "", index+1);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- mode: %08x\n", spaces, "", mGain.mode);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- min_value: %d mB\n", spaces, "", mGain.min_value);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- max_value: %d mB\n", spaces, "", mGain.max_value);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- default_value: %d mB\n", spaces, "", mGain.default_value);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- step_value: %d mB\n", spaces, "", mGain.step_value);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms);
- result.append(buffer);
-
- write(fd, result.string(), result.size());
-}
-
-// --- AudioPortConfig class implementation
-
-AudioPolicyManager::AudioPortConfig::AudioPortConfig()
-{
- mSamplingRate = 0;
- mChannelMask = AUDIO_CHANNEL_NONE;
- mFormat = AUDIO_FORMAT_INVALID;
- mGain.index = -1;
-}
-
-status_t AudioPolicyManager::AudioPortConfig::applyAudioPortConfig(
- const struct audio_port_config *config,
- struct audio_port_config *backupConfig)
-{
- struct audio_port_config localBackupConfig;
- status_t status = NO_ERROR;
-
- localBackupConfig.config_mask = config->config_mask;
- toAudioPortConfig(&localBackupConfig);
-
- sp<AudioPort> audioport = getAudioPort();
- if (audioport == 0) {
- status = NO_INIT;
- 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->checkFormat(config->format);
- if (status != NO_ERROR) {
- goto exit;
- }
- mFormat = config->format;
- }
- if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) {
- status = audioport->checkGain(&config->gain, config->gain.index);
- if (status != NO_ERROR) {
- goto exit;
- }
- mGain = config->gain;
- }
-
-exit:
- if (status != NO_ERROR) {
- applyAudioPortConfig(&localBackupConfig);
- }
- if (backupConfig != NULL) {
- *backupConfig = localBackupConfig;
- }
- return status;
-}
-
-void AudioPolicyManager::AudioPortConfig::toAudioPortConfig(
- struct audio_port_config *dstConfig,
- const struct audio_port_config *srcConfig) const
-{
- if (dstConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
- dstConfig->sample_rate = mSamplingRate;
- if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE)) {
- dstConfig->sample_rate = srcConfig->sample_rate;
- }
- } else {
- dstConfig->sample_rate = 0;
- }
- if (dstConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
- dstConfig->channel_mask = mChannelMask;
- if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK)) {
- dstConfig->channel_mask = srcConfig->channel_mask;
- }
- } else {
- dstConfig->channel_mask = AUDIO_CHANNEL_NONE;
- }
- if (dstConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
- dstConfig->format = mFormat;
- if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT)) {
- dstConfig->format = srcConfig->format;
- }
- } else {
- dstConfig->format = AUDIO_FORMAT_INVALID;
- }
- if (dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) {
- dstConfig->gain = mGain;
- if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)) {
- dstConfig->gain = srcConfig->gain;
- }
- } else {
- dstConfig->gain.index = -1;
- }
- if (dstConfig->gain.index != -1) {
- dstConfig->config_mask |= AUDIO_PORT_CONFIG_GAIN;
- } else {
- dstConfig->config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
- }
-}
-
-// --- IOProfile class implementation
-
-AudioPolicyManager::IOProfile::IOProfile(const String8& name, audio_port_role_t role,
- const sp<HwModule>& module)
- : AudioPort(name, AUDIO_PORT_TYPE_MIX, role, module)
-{
-}
-
-AudioPolicyManager::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
-bool AudioPolicyManager::IOProfile::isCompatibleProfile(audio_devices_t device,
- String8 address,
- uint32_t samplingRate,
- uint32_t *updatedSamplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- 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;
- ALOG_ASSERT(isPlaybackThread != isRecordThread);
-
- if (device != AUDIO_DEVICE_NONE && mSupportedDevices.getDevice(device, address) == 0) {
- return false;
- }
-
- if (samplingRate == 0) {
- return false;
- }
- uint32_t myUpdatedSamplingRate = samplingRate;
- if (isPlaybackThread && checkExactSamplingRate(samplingRate) != NO_ERROR) {
- return false;
- }
- if (isRecordThread && checkCompatibleSamplingRate(samplingRate, &myUpdatedSamplingRate) !=
- NO_ERROR) {
- return false;
- }
-
- if (!audio_is_valid_format(format) || checkFormat(format) != NO_ERROR) {
- return false;
- }
-
- if (isPlaybackThread && (!audio_is_output_channel(channelMask) ||
- checkExactChannelMask(channelMask) != NO_ERROR)) {
- return false;
- }
- if (isRecordThread && (!audio_is_input_channel(channelMask) ||
- checkCompatibleChannelMask(channelMask) != NO_ERROR)) {
- return false;
- }
-
- if (isPlaybackThread && (mFlags & 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) &
- ~AUDIO_INPUT_FLAG_FAST)) {
- return false;
- }
-
- if (updatedSamplingRate != NULL) {
- *updatedSamplingRate = myUpdatedSamplingRate;
- }
- return true;
-}
-
-void AudioPolicyManager::IOProfile::dump(int fd)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- AudioPort::dump(fd, 4);
-
- snprintf(buffer, SIZE, " - flags: 0x%04x\n", mFlags);
- result.append(buffer);
- snprintf(buffer, SIZE, " - devices:\n");
- result.append(buffer);
- write(fd, result.string(), result.size());
- for (size_t i = 0; i < mSupportedDevices.size(); i++) {
- mSupportedDevices[i]->dump(fd, 6, i);
- }
-}
-
-void AudioPolicyManager::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);
-}
-
-
-// --- DeviceDescriptor implementation
-
-
-AudioPolicyManager::DeviceDescriptor::DeviceDescriptor(const String8& name, audio_devices_t type) :
- AudioPort(name, AUDIO_PORT_TYPE_DEVICE,
- audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
- AUDIO_PORT_ROLE_SOURCE,
- NULL),
- mDeviceType(type), mAddress(""), mId(0)
-{
-}
-
-bool AudioPolicyManager::DeviceDescriptor::equals(const sp<DeviceDescriptor>& other) const
-{
- // Devices are considered equal if they:
- // - are of the same type (a device type cannot be AUDIO_DEVICE_NONE)
- // - have the same address or one device does not specify the address
- // - have the same channel mask or one device does not specify the channel mask
- return (mDeviceType == other->mDeviceType) &&
- (mAddress == "" || other->mAddress == "" || mAddress == other->mAddress) &&
- (mChannelMask == 0 || other->mChannelMask == 0 ||
- mChannelMask == other->mChannelMask);
-}
-
-void AudioPolicyManager::DeviceDescriptor::loadGains(cnode *root)
-{
- AudioPort::loadGains(root);
- if (mGains.size() > 0) {
- mGains[0]->getDefaultConfig(&mGain);
- }
-}
-
-
-void AudioPolicyManager::DeviceVector::refreshTypes()
-{
- mDeviceTypes = AUDIO_DEVICE_NONE;
- for(size_t i = 0; i < size(); i++) {
- mDeviceTypes |= itemAt(i)->mDeviceType;
- }
- ALOGV("DeviceVector::refreshTypes() mDeviceTypes %08x", mDeviceTypes);
-}
-
-ssize_t AudioPolicyManager::DeviceVector::indexOf(const sp<DeviceDescriptor>& item) const
-{
- for(size_t i = 0; i < size(); i++) {
- if (item->equals(itemAt(i))) {
- return i;
- }
- }
- return -1;
-}
-
-ssize_t AudioPolicyManager::DeviceVector::add(const sp<DeviceDescriptor>& item)
-{
- ssize_t ret = indexOf(item);
-
- if (ret < 0) {
- ret = SortedVector::add(item);
- if (ret >= 0) {
- refreshTypes();
- }
- } else {
- ALOGW("DeviceVector::add device %08x already in", item->mDeviceType);
- ret = -1;
- }
- return ret;
-}
-
-ssize_t AudioPolicyManager::DeviceVector::remove(const sp<DeviceDescriptor>& item)
-{
- size_t i;
- ssize_t ret = indexOf(item);
-
- if (ret < 0) {
- ALOGW("DeviceVector::remove device %08x not in", item->mDeviceType);
- } else {
- ret = SortedVector::removeAt(ret);
- if (ret >= 0) {
- refreshTypes();
- }
- }
- return ret;
-}
-
-void AudioPolicyManager::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(String8(""), type | role_bit));
- }
-}
-
-void AudioPolicyManager::DeviceVector::loadDevicesFromName(char *name,
- const DeviceVector& declaredDevices)
-{
- char *devName = strtok(name, "|");
- while (devName != NULL) {
- if (strlen(devName) != 0) {
- audio_devices_t type = stringToEnum(sDeviceNameToEnumTable,
- ARRAY_SIZE(sDeviceNameToEnumTable),
- devName);
- if (type != AUDIO_DEVICE_NONE) {
- sp<DeviceDescriptor> dev = new DeviceDescriptor(String8(""), 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.getDeviceFromName(String8(devName));
- if (deviceDesc != 0) {
- add(deviceDesc);
- }
- }
- }
- devName = strtok(NULL, "|");
- }
-}
-
-sp<AudioPolicyManager::DeviceDescriptor> AudioPolicyManager::DeviceVector::getDevice(
- audio_devices_t type, String8 address) const
-{
- sp<DeviceDescriptor> device;
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->mDeviceType == type) {
- if (address == "" || itemAt(i)->mAddress == address) {
- device = itemAt(i);
- if (itemAt(i)->mAddress == address) {
- break;
- }
- }
- }
- }
- ALOGV("DeviceVector::getDevice() for type %08x address %s found %p",
- type, address.string(), device.get());
- return device;
-}
-
-sp<AudioPolicyManager::DeviceDescriptor> AudioPolicyManager::DeviceVector::getDeviceFromId(
- audio_port_handle_t id) const
-{
- sp<DeviceDescriptor> device;
- for (size_t i = 0; i < size(); i++) {
- ALOGV("DeviceVector::getDeviceFromId(%d) itemAt(%zu)->mId %d", id, i, itemAt(i)->mId);
- if (itemAt(i)->mId == id) {
- device = itemAt(i);
- break;
- }
- }
- return device;
-}
-
-AudioPolicyManager::DeviceVector AudioPolicyManager::DeviceVector::getDevicesFromType(
- audio_devices_t type) const
-{
- DeviceVector devices;
- for (size_t i = 0; (i < size()) && (type != AUDIO_DEVICE_NONE); i++) {
- if (itemAt(i)->mDeviceType & type & ~AUDIO_DEVICE_BIT_IN) {
- devices.add(itemAt(i));
- type &= ~itemAt(i)->mDeviceType;
- ALOGV("DeviceVector::getDevicesFromType() for type %x found %p",
- itemAt(i)->mDeviceType, itemAt(i).get());
- }
- }
- return devices;
-}
-
-AudioPolicyManager::DeviceVector AudioPolicyManager::DeviceVector::getDevicesFromTypeAddr(
- audio_devices_t type, String8 address) const
-{
- DeviceVector devices;
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->mDeviceType == type) {
- if (itemAt(i)->mAddress == address) {
- devices.add(itemAt(i));
- }
- }
- }
- return devices;
-}
-
-sp<AudioPolicyManager::DeviceDescriptor> AudioPolicyManager::DeviceVector::getDeviceFromName(
- const String8& name) const
-{
- sp<DeviceDescriptor> device;
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->mName == name) {
- device = itemAt(i);
- break;
- }
- }
- return device;
-}
-
-void AudioPolicyManager::DeviceDescriptor::toAudioPortConfig(
- struct audio_port_config *dstConfig,
- const struct audio_port_config *srcConfig) const
-{
- dstConfig->config_mask = AUDIO_PORT_CONFIG_CHANNEL_MASK|AUDIO_PORT_CONFIG_GAIN;
- if (srcConfig != NULL) {
- dstConfig->config_mask |= srcConfig->config_mask;
- }
-
- AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
-
- dstConfig->id = mId;
- dstConfig->role = audio_is_output_device(mDeviceType) ?
- AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE;
- dstConfig->type = AUDIO_PORT_TYPE_DEVICE;
- dstConfig->ext.device.type = mDeviceType;
- dstConfig->ext.device.hw_module = mModule->mHandle;
- strncpy(dstConfig->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN);
-}
-
-void AudioPolicyManager::DeviceDescriptor::toAudioPort(struct audio_port *port) const
-{
- ALOGV("DeviceDescriptor::toAudioPort() handle %d type %x", mId, mDeviceType);
- AudioPort::toAudioPort(port);
- port->id = mId;
- toAudioPortConfig(&port->active_config);
- port->ext.device.type = mDeviceType;
- port->ext.device.hw_module = mModule->mHandle;
- strncpy(port->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN);
-}
-
-status_t AudioPolicyManager::DeviceDescriptor::dump(int fd, int spaces, int index) const
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "%*sDevice %d:\n", spaces, "", index+1);
- result.append(buffer);
- if (mId != 0) {
- snprintf(buffer, SIZE, "%*s- id: %2d\n", spaces, "", mId);
- result.append(buffer);
- }
- snprintf(buffer, SIZE, "%*s- type: %-48s\n", spaces, "",
- enumToString(sDeviceNameToEnumTable,
- ARRAY_SIZE(sDeviceNameToEnumTable),
- mDeviceType));
- 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);
-
- return NO_ERROR;
-}
-
-status_t AudioPolicyManager::AudioPatch::dump(int fd, int spaces, int index) const
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
-
- snprintf(buffer, SIZE, "%*sAudio patch %d:\n", spaces, "", index+1);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- handle: %2d\n", spaces, "", mHandle);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- audio flinger handle: %2d\n", spaces, "", mAfPatchHandle);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- owner uid: %2d\n", spaces, "", mUid);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- %d sources:\n", spaces, "", mPatch.num_sources);
- result.append(buffer);
- for (size_t i = 0; i < mPatch.num_sources; i++) {
- if (mPatch.sources[i].type == AUDIO_PORT_TYPE_DEVICE) {
- snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
- mPatch.sources[i].id, enumToString(sDeviceNameToEnumTable,
- ARRAY_SIZE(sDeviceNameToEnumTable),
- mPatch.sources[i].ext.device.type));
- } 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);
- }
- result.append(buffer);
- }
- snprintf(buffer, SIZE, "%*s- %d sinks:\n", spaces, "", mPatch.num_sinks);
- result.append(buffer);
- for (size_t i = 0; i < mPatch.num_sinks; i++) {
- if (mPatch.sinks[i].type == AUDIO_PORT_TYPE_DEVICE) {
- snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
- mPatch.sinks[i].id, enumToString(sDeviceNameToEnumTable,
- ARRAY_SIZE(sDeviceNameToEnumTable),
- mPatch.sinks[i].ext.device.type));
- } 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);
- }
- result.append(buffer);
- }
-
- write(fd, result.string(), result.size());
- return NO_ERROR;
-}
// --- audio_policy.conf file parsing
-
-uint32_t AudioPolicyManager::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 |= stringToEnum(sOutputFlagNameToEnumTable,
- ARRAY_SIZE(sOutputFlagNameToEnumTable),
- flagName);
- }
- 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;
- }
-
- return flag;
-}
-
-uint32_t AudioPolicyManager::parseInputFlagNames(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 |= stringToEnum(sInputFlagNameToEnumTable,
- ARRAY_SIZE(sInputFlagNameToEnumTable),
- flagName);
- }
- flagName = strtok(NULL, "|");
- }
- return flag;
-}
-
-audio_devices_t AudioPolicyManager::parseDeviceNames(char *name)
-{
- uint32_t device = 0;
-
- char *devName = strtok(name, "|");
- while (devName != NULL) {
- if (strlen(devName) != 0) {
- device |= stringToEnum(sDeviceNameToEnumTable,
- ARRAY_SIZE(sDeviceNameToEnumTable),
- devName);
- }
- devName = strtok(NULL, "|");
- }
- return device;
-}
-
+// TODO candidate to be moved to ConfigParsingUtils
void AudioPolicyManager::loadHwModule(cnode *root)
{
status_t status = NAME_NOT_FOUND;
@@ -7889,6 +5557,7 @@
}
}
+// TODO candidate to be moved to ConfigParsingUtils
void AudioPolicyManager::loadHwModules(cnode *root)
{
cnode *node = config_find(root, AUDIO_HW_MODULE_TAG);
@@ -7904,6 +5573,7 @@
}
}
+// TODO candidate to be moved to ConfigParsingUtils
void AudioPolicyManager::loadGlobalConfig(cnode *root, const sp<HwModule>& module)
{
cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
@@ -7924,11 +5594,12 @@
ALOGV("loadGlobalConfig() Attached Output Devices %08x",
mAvailableOutputDevices.types());
} else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) {
- audio_devices_t device = (audio_devices_t)stringToEnum(sDeviceNameToEnumTable,
- ARRAY_SIZE(sDeviceNameToEnumTable),
- (char *)node->value);
+ audio_devices_t device = (audio_devices_t)ConfigParsingUtils::stringToEnum(
+ sDeviceNameToEnumTable,
+ ARRAY_SIZE(sDeviceNameToEnumTable),
+ (char *)node->value);
if (device != AUDIO_DEVICE_NONE) {
- mDefaultOutputDevice = new DeviceDescriptor(String8(""), device);
+ mDefaultOutputDevice = new DeviceDescriptor(String8("default-output"), device);
} else {
ALOGW("loadGlobalConfig() default device not specified");
}
@@ -7938,7 +5609,7 @@
declaredDevices);
ALOGV("loadGlobalConfig() Available InputDevices %08x", mAvailableInputDevices.types());
} else if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
- mSpeakerDrcEnabled = stringToBool((char *)node->value);
+ mSpeakerDrcEnabled = ConfigParsingUtils::stringToBool((char *)node->value);
ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", mSpeakerDrcEnabled);
} else if (strcmp(AUDIO_HAL_VERSION_TAG, node->name) == 0) {
uint32_t major, minor;
@@ -7951,6 +5622,7 @@
}
}
+// TODO candidate to be moved to ConfigParsingUtils
status_t AudioPolicyManager::loadAudioPolicyConfig(const char *path)
{
cnode *root;
@@ -7979,8 +5651,8 @@
{
sp<HwModule> module;
sp<IOProfile> profile;
- sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(String8(""),
- AUDIO_DEVICE_IN_BUILTIN_MIC);
+ sp<DeviceDescriptor> defaultInputDevice =
+ new DeviceDescriptor(String8("builtin-mic"), AUDIO_DEVICE_IN_BUILTIN_MIC);
mAvailableOutputDevices.add(mDefaultOutputDevice);
mAvailableInputDevices.add(defaultInputDevice);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
new file mode 100644
index 0000000..61ea6f2
--- /dev/null
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -0,0 +1,560 @@
+/*
+ * 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 <stdint.h>
+#include <sys/types.h>
+#include <cutils/config_utils.h>
+#include <cutils/misc.h>
+#include <utils/Timers.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/SortedVector.h>
+#include <media/AudioPolicy.h>
+#include "AudioPolicyInterface.h"
+
+#include "Gains.h"
+#include "Ports.h"
+#include "ConfigParsingUtils.h"
+#include "Devices.h"
+#include "IOProfile.h"
+#include "HwModule.h"
+#include "AudioInputDescriptor.h"
+#include "AudioOutputDescriptor.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+// Attenuation applied to STRATEGY_SONIFICATION streams when a headset is connected: 6dB
+#define SONIFICATION_HEADSET_VOLUME_FACTOR 0.5
+// Min volume for STRATEGY_SONIFICATION streams when limited by music volume: -36dB
+#define SONIFICATION_HEADSET_VOLUME_MIN 0.016
+// Time in milliseconds during which we consider that music is still active after a music
+// track was stopped - see computeVolume()
+#define SONIFICATION_HEADSET_MUSIC_DELAY 5000
+// Time in milliseconds after media stopped playing during which we consider that the
+// sonification should be as unobtrusive as during the time media was playing.
+#define SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY 5000
+// Time in milliseconds during witch some streams are muted while the audio path
+// is switched
+#define MUTE_TIME_MS 2000
+
+#define NUM_TEST_OUTPUTS 5
+
+#define NUM_VOL_CURVE_KNEES 2
+
+// Default minimum length allowed for offloading a compressed track
+// Can be overridden by the audio.offload.min.duration.secs property
+#define OFFLOAD_DEFAULT_MIN_DURATION_SECS 60
+
+#define MAX_MIXER_SAMPLING_RATE 48000
+#define MAX_MIXER_CHANNEL_COUNT 8
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManager implements audio policy manager behavior common to all platforms.
+// ----------------------------------------------------------------------------
+
+class AudioPolicyManager: public AudioPolicyInterface
+#ifdef AUDIO_POLICY_TEST
+ , public Thread
+#endif //AUDIO_POLICY_TEST
+{
+
+public:
+ AudioPolicyManager(AudioPolicyClientInterface *clientInterface);
+ virtual ~AudioPolicyManager();
+
+ // AudioPolicyInterface
+ virtual status_t setDeviceConnectionState(audio_devices_t device,
+ audio_policy_dev_state_t state,
+ const char *device_address,
+ const char *device_name);
+ virtual audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device,
+ const char *device_address);
+ virtual void setPhoneState(audio_mode_t state);
+ virtual void setForceUse(audio_policy_force_use_t usage,
+ audio_policy_forced_cfg_t config);
+ virtual audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage);
+ virtual void setSystemProperty(const char* property, const char* value);
+ virtual status_t initCheck();
+ virtual audio_io_handle_t getOutput(audio_stream_type_t stream,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo);
+ virtual status_t getOutputForAttr(const audio_attributes_t *attr,
+ audio_io_handle_t *output,
+ audio_session_t session,
+ audio_stream_type_t *stream,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo);
+ virtual status_t startOutput(audio_io_handle_t output,
+ audio_stream_type_t stream,
+ audio_session_t session);
+ virtual status_t stopOutput(audio_io_handle_t output,
+ audio_stream_type_t stream,
+ audio_session_t session);
+ virtual void releaseOutput(audio_io_handle_t output,
+ audio_stream_type_t stream,
+ audio_session_t session);
+ virtual status_t getInputForAttr(const audio_attributes_t *attr,
+ audio_io_handle_t *input,
+ audio_session_t session,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_input_flags_t flags,
+ input_type_t *inputType);
+
+ // indicates to the audio policy manager that the input starts being used.
+ virtual status_t startInput(audio_io_handle_t input,
+ audio_session_t session);
+
+ // indicates to the audio policy manager that the input stops being used.
+ virtual status_t stopInput(audio_io_handle_t input,
+ audio_session_t session);
+ virtual void releaseInput(audio_io_handle_t input,
+ audio_session_t session);
+ virtual void closeAllInputs();
+ virtual void initStreamVolume(audio_stream_type_t stream,
+ int indexMin,
+ int indexMax);
+ virtual status_t setStreamVolumeIndex(audio_stream_type_t stream,
+ int index,
+ audio_devices_t device);
+ virtual status_t getStreamVolumeIndex(audio_stream_type_t stream,
+ int *index,
+ audio_devices_t device);
+
+ // return the strategy corresponding to a given stream type
+ virtual uint32_t getStrategyForStream(audio_stream_type_t stream);
+ // return the strategy corresponding to the given audio attributes
+ virtual uint32_t getStrategyForAttr(const audio_attributes_t *attr);
+
+ // return the enabled output devices for the given stream type
+ virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream);
+
+ virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc = NULL);
+ virtual status_t registerEffect(const effect_descriptor_t *desc,
+ audio_io_handle_t io,
+ uint32_t strategy,
+ int session,
+ int id);
+ virtual status_t unregisterEffect(int id);
+ virtual status_t setEffectEnabled(int id, bool enabled);
+
+ virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
+ // return whether a stream is playing remotely, override to change the definition of
+ // local/remote playback, used for instance by notification manager to not make
+ // media players lose audio focus when not playing locally
+ // For the base implementation, "remotely" means playing during screen mirroring which
+ // uses an output for playback with a non-empty, non "0" address.
+ virtual bool isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
+ virtual bool isSourceActive(audio_source_t source) const;
+
+ virtual status_t dump(int fd);
+
+ virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo);
+
+ virtual status_t listAudioPorts(audio_port_role_t role,
+ audio_port_type_t type,
+ unsigned int *num_ports,
+ struct audio_port *ports,
+ unsigned int *generation);
+ virtual status_t getAudioPort(struct audio_port *port);
+ virtual status_t createAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ uid_t uid);
+ virtual status_t releaseAudioPatch(audio_patch_handle_t handle,
+ uid_t uid);
+ virtual status_t listAudioPatches(unsigned int *num_patches,
+ struct audio_patch *patches,
+ unsigned int *generation);
+ virtual status_t setAudioPortConfig(const struct audio_port_config *config);
+ virtual void clearAudioPatches(uid_t uid);
+
+ virtual status_t acquireSoundTriggerSession(audio_session_t *session,
+ audio_io_handle_t *ioHandle,
+ audio_devices_t *device);
+
+ virtual status_t releaseSoundTriggerSession(audio_session_t session);
+
+ virtual status_t registerPolicyMixes(Vector<AudioMix> mixes);
+ virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes);
+
+ // Audio policy configuration file parsing (audio_policy.conf)
+ // TODO candidates to be moved to ConfigParsingUtils
+ void loadHwModule(cnode *root);
+ void loadHwModules(cnode *root);
+ void loadGlobalConfig(cnode *root, const sp<HwModule>& module);
+ status_t loadAudioPolicyConfig(const char *path);
+ void defaultAudioPolicyConfig(void);
+
+ // return the strategy corresponding to a given stream type
+ static routing_strategy getStrategy(audio_stream_type_t stream);
+
+ static uint32_t nextUniqueId();
+protected:
+
+ class EffectDescriptor : public RefBase
+ {
+ public:
+
+ status_t dump(int fd);
+
+ int mIo; // io the effect is attached to
+ routing_strategy mStrategy; // routing strategy the effect is associated to
+ int mSession; // audio session the effect is on
+ effect_descriptor_t mDesc; // effect descriptor
+ bool mEnabled; // enabled state: CPU load being used or not
+ };
+
+ void addOutput(audio_io_handle_t output, sp<AudioOutputDescriptor> outputDesc);
+ void addInput(audio_io_handle_t input, sp<AudioInputDescriptor> inputDesc);
+
+ // return appropriate device for streams handled by the specified strategy according to current
+ // phone state, connected devices...
+ // if fromCache is true, the device is returned from mDeviceForStrategy[],
+ // otherwise it is determine by current state
+ // (device connected,phone state, force use, a2dp output...)
+ // This allows to:
+ // 1 speed up process when the state is stable (when starting or stopping an output)
+ // 2 access to either current device selection (fromCache == true) or
+ // "future" device selection (fromCache == false) when called from a context
+ // where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
+ // before updateDevicesAndOutputs() is called.
+ virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy,
+ bool fromCache);
+
+ // change the route of the specified output. Returns the number of ms we have slept to
+ // allow new routing to take effect in certain cases.
+ virtual uint32_t setOutputDevice(audio_io_handle_t output,
+ audio_devices_t device,
+ bool force = false,
+ int delayMs = 0,
+ audio_patch_handle_t *patchHandle = NULL,
+ const char* address = NULL);
+ status_t resetOutputDevice(audio_io_handle_t output,
+ int delayMs = 0,
+ audio_patch_handle_t *patchHandle = NULL);
+ status_t setInputDevice(audio_io_handle_t input,
+ audio_devices_t device,
+ bool force = false,
+ audio_patch_handle_t *patchHandle = NULL);
+ status_t resetInputDevice(audio_io_handle_t input,
+ audio_patch_handle_t *patchHandle = NULL);
+
+ // select input device corresponding to requested audio source
+ virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource);
+
+ // return io handle of active input or 0 if no input is active
+ // Only considers inputs from physical devices (e.g. main mic, headset mic) when
+ // ignoreVirtualInputs is true.
+ audio_io_handle_t getActiveInput(bool ignoreVirtualInputs = true);
+
+ uint32_t activeInputsCount() const;
+
+ // initialize volume curves for each strategy and device category
+ void initializeVolumeCurves();
+
+ // compute the actual volume for a given stream according to the requested index and a particular
+ // device
+ virtual float computeVolume(audio_stream_type_t stream, int index,
+ audio_io_handle_t output, audio_devices_t device);
+
+ // check that volume change is permitted, compute and send new volume to audio hardware
+ virtual status_t checkAndSetVolume(audio_stream_type_t stream, int index,
+ audio_io_handle_t output,
+ audio_devices_t device,
+ int delayMs = 0, bool force = false);
+
+ // apply all stream volumes to the specified output and device
+ void applyStreamVolumes(audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false);
+
+ // Mute or unmute all streams handled by the specified strategy on the specified output
+ void setStrategyMute(routing_strategy strategy,
+ bool on,
+ audio_io_handle_t output,
+ int delayMs = 0,
+ audio_devices_t device = (audio_devices_t)0);
+
+ // Mute or unmute the stream on the specified output
+ void setStreamMute(audio_stream_type_t stream,
+ bool on,
+ audio_io_handle_t output,
+ int delayMs = 0,
+ audio_devices_t device = (audio_devices_t)0);
+
+ // handle special cases for sonification strategy while in call: mute streams or replace by
+ // a special tone in the device used for communication
+ void handleIncallSonification(audio_stream_type_t stream, bool starting, bool stateChange);
+
+ // true if device is in a telephony or VoIP call
+ virtual bool isInCall();
+
+ // true if given state represents a device in a telephony or VoIP call
+ virtual bool isStateInCall(int state);
+
+ // when a device is connected, checks if an open output can be routed
+ // to this device. If none is open, tries to open one of the available outputs.
+ // Returns an output suitable to this device or 0.
+ // when a device is disconnected, checks if an output is not used any more and
+ // returns its handle if any.
+ // transfers the audio tracks and effects from one output thread to another accordingly.
+ status_t checkOutputsForDevice(const sp<DeviceDescriptor> devDesc,
+ audio_policy_dev_state_t state,
+ SortedVector<audio_io_handle_t>& outputs,
+ const String8 address);
+
+ status_t checkInputsForDevice(audio_devices_t device,
+ audio_policy_dev_state_t state,
+ SortedVector<audio_io_handle_t>& inputs,
+ const String8 address);
+
+ // close an output and its companion duplicating output.
+ void closeOutput(audio_io_handle_t output);
+
+ // close an input.
+ void closeInput(audio_io_handle_t input);
+
+ // checks and if necessary changes outputs used for all strategies.
+ // must be called every time a condition that affects the output choice for a given strategy
+ // changes: connected device, phone state, force use...
+ // Must be called before updateDevicesAndOutputs()
+ void checkOutputForStrategy(routing_strategy strategy);
+
+ // Same as checkOutputForStrategy() but for a all strategies in order of priority
+ void checkOutputForAllStrategies();
+
+ // manages A2DP output suspend/restore according to phone state and BT SCO usage
+ void checkA2dpSuspend();
+
+ // returns the A2DP output handle if it is open or 0 otherwise
+ audio_io_handle_t getA2dpOutput();
+
+ // selects the most appropriate device on output for current state
+ // must be called every time a condition that affects the device choice for a given output is
+ // changed: connected device, phone state, force use, output start, output stop..
+ // see getDeviceForStrategy() for the use of fromCache parameter
+ audio_devices_t getNewOutputDevice(audio_io_handle_t output, bool fromCache);
+
+ // updates cache of device used by all strategies (mDeviceForStrategy[])
+ // must be called every time a condition that affects the device choice for a given strategy is
+ // changed: connected device, phone state, force use...
+ // cached values are used by getDeviceForStrategy() if parameter fromCache is true.
+ // Must be called after checkOutputForAllStrategies()
+ void updateDevicesAndOutputs();
+
+ // selects the most appropriate device on input for current state
+ audio_devices_t getNewInputDevice(audio_io_handle_t input);
+
+ virtual uint32_t getMaxEffectsCpuLoad();
+ virtual uint32_t getMaxEffectsMemory();
+#ifdef AUDIO_POLICY_TEST
+ virtual bool threadLoop();
+ void exit();
+ int testOutputIndex(audio_io_handle_t output);
+#endif //AUDIO_POLICY_TEST
+
+ status_t setEffectEnabled(const sp<EffectDescriptor>& effectDesc, bool enabled);
+
+ SortedVector<audio_io_handle_t> getOutputsForDevice(audio_devices_t device,
+ DefaultKeyedVector<audio_io_handle_t, sp<AudioOutputDescriptor> > openOutputs);
+ bool vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
+ SortedVector<audio_io_handle_t>& outputs2);
+
+ // mute/unmute strategies using an incompatible device combination
+ // if muting, wait for the audio in pcm buffer to be drained before proceeding
+ // if unmuting, unmute only after the specified delay
+ // Returns the number of ms waited
+ virtual uint32_t checkDeviceMuteStrategies(sp<AudioOutputDescriptor> outputDesc,
+ audio_devices_t prevDevice,
+ uint32_t delayMs);
+
+ audio_io_handle_t selectOutput(const SortedVector<audio_io_handle_t>& outputs,
+ audio_output_flags_t flags,
+ audio_format_t format);
+ // samplingRate parameter is an in/out and so may be modified
+ sp<IOProfile> getInputProfile(audio_devices_t device,
+ String8 address,
+ uint32_t& samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_input_flags_t flags);
+ sp<IOProfile> getProfileForDirectOutput(audio_devices_t device,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_output_flags_t flags);
+
+ audio_io_handle_t selectOutputForEffects(const SortedVector<audio_io_handle_t>& outputs);
+
+ bool isNonOffloadableEffectEnabled();
+
+ virtual status_t addAudioPatch(audio_patch_handle_t handle,
+ const sp<AudioPatch>& patch);
+ virtual status_t removeAudioPatch(audio_patch_handle_t handle);
+
+ sp<AudioOutputDescriptor> getOutputFromId(audio_port_handle_t id) const;
+ sp<AudioInputDescriptor> getInputFromId(audio_port_handle_t id) const;
+ sp<HwModule> getModuleForDevice(audio_devices_t device) const;
+ sp<HwModule> getModuleFromName(const char *name) const;
+ audio_devices_t availablePrimaryOutputDevices();
+ audio_devices_t availablePrimaryInputDevices();
+
+ void updateCallRouting(audio_devices_t rxDevice, int delayMs = 0);
+
+
+ uid_t mUidCached;
+ AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
+ audio_io_handle_t mPrimaryOutput; // primary output handle
+ // list of descriptors for outputs currently opened
+ DefaultKeyedVector<audio_io_handle_t, sp<AudioOutputDescriptor> > mOutputs;
+ // copy of mOutputs before setDeviceConnectionState() opens new outputs
+ // reset to mOutputs when updateDevicesAndOutputs() is called.
+ DefaultKeyedVector<audio_io_handle_t, sp<AudioOutputDescriptor> > mPreviousOutputs;
+ DefaultKeyedVector<audio_io_handle_t, sp<AudioInputDescriptor> > mInputs; // list of input descriptors
+ DeviceVector mAvailableOutputDevices; // all available output devices
+ DeviceVector mAvailableInputDevices; // all available input devices
+ int mPhoneState; // current phone state
+ audio_policy_forced_cfg_t mForceUse[AUDIO_POLICY_FORCE_USE_CNT]; // current forced use configuration
+
+ StreamDescriptor mStreams[AUDIO_STREAM_CNT]; // stream descriptors for volume control
+ 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
+
+ // Maximum CPU load allocated to audio effects in 0.1 MIPS (ARMv5TE, 0 WS memory) units
+ static const uint32_t MAX_EFFECTS_CPU_LOAD = 1000;
+ // Maximum memory allocated to audio effects in KB
+ static const uint32_t MAX_EFFECTS_MEMORY = 512;
+ uint32_t mTotalEffectsCpuLoad; // current CPU load used by effects
+ uint32_t mTotalEffectsMemory; // current memory used by effects
+ KeyedVector<int, sp<EffectDescriptor> > 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
+
+ Vector < sp<HwModule> > mHwModules;
+ static volatile int32_t mNextUniqueId;
+ volatile int32_t mAudioPortGeneration;
+
+ DefaultKeyedVector<audio_patch_handle_t, sp<AudioPatch> > mAudioPatches;
+
+ DefaultKeyedVector<audio_session_t, audio_io_handle_t> mSoundTriggerSessions;
+
+ sp<AudioPatch> mCallTxPatch;
+ sp<AudioPatch> mCallRxPatch;
+
+ // 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 {
+ STARTING_OUTPUT,
+ STARTING_BEACON,
+ STOPPING_OUTPUT,
+ STOPPING_BEACON
+ };
+ uint32_t mBeaconMuteRefCount; // ref count for stream that would mute beacon
+ uint32_t mBeaconPlayingRefCount;// ref count for the playing beacon streams
+ bool mBeaconMuted; // has STREAM_TTS been muted
+
+ // custom mix entry in mPolicyMixes
+ class AudioPolicyMix : public RefBase {
+ public:
+ AudioPolicyMix() {}
+
+ AudioMix mMix; // Audio policy mix descriptor
+ sp<AudioOutputDescriptor> mOutput; // Corresponding output stream
+ };
+ DefaultKeyedVector<String8, sp<AudioPolicyMix> > mPolicyMixes; // list of registered mixes
+
+
+#ifdef AUDIO_POLICY_TEST
+ Mutex mLock;
+ Condition mWaitWorkCV;
+
+ int mCurOutput;
+ bool mDirectOutput;
+ audio_io_handle_t mTestOutputs[NUM_TEST_OUTPUTS];
+ int mTestInput;
+ uint32_t mTestDevice;
+ uint32_t mTestSamplingRate;
+ uint32_t mTestFormat;
+ uint32_t mTestChannels;
+ uint32_t mTestLatencyMs;
+#endif //AUDIO_POLICY_TEST
+
+ static bool isVirtualInputDevice(audio_devices_t device);
+
+ uint32_t nextAudioPortGeneration();
+private:
+ // updates device caching and output for streams that can influence the
+ // routing of notifications
+ void handleNotificationRoutingForStream(audio_stream_type_t stream);
+ static bool deviceDistinguishesOnAddress(audio_devices_t device);
+ // find the outputs on a given output descriptor that have the given address.
+ // to be called on an AudioOutputDescriptor whose supported devices (as defined
+ // in mProfile->mSupportedDevices) matches the device whose address is to be matched.
+ // see deviceDistinguishesOnAddress(audio_devices_t) for whether the device type is one
+ // where addresses are used to distinguish between one connected device and another.
+ void findIoHandlesByAddress(sp<AudioOutputDescriptor> desc /*in*/,
+ const audio_devices_t device /*in*/,
+ const String8 address /*in*/,
+ SortedVector<audio_io_handle_t>& outputs /*out*/);
+ uint32_t curAudioPortGeneration() const { return mAudioPortGeneration; }
+ // internal method to return the output handle for the given device and format
+ audio_io_handle_t getOutputForDevice(
+ audio_devices_t device,
+ audio_session_t session,
+ audio_stream_type_t stream,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo);
+ // internal function to derive a stream type value from audio attributes
+ audio_stream_type_t streamTypefromAttributesInt(const audio_attributes_t *attr);
+ // return true if any output is playing anything besides the stream to ignore
+ bool isAnyOutputActive(audio_stream_type_t streamToIgnore);
+ // event is one of STARTING_OUTPUT, STARTING_BEACON, STOPPING_OUTPUT, STOPPING_BEACON
+ // returns 0 if no mute/unmute event happened, the largest latency of the device where
+ // the mute/unmute happened
+ uint32_t handleEventForBeacon(int event);
+ uint32_t setBeaconMute(bool mute);
+ bool isValidAttributes(const audio_attributes_t *paa);
+
+ // select input device corresponding to requested audio source and return associated policy
+ // mix if any. Calls getDeviceForInputSource().
+ audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource,
+ AudioMix **policyMix = NULL);
+
+ // Called by setDeviceConnectionState().
+ status_t setDeviceConnectionStateInt(audio_devices_t device,
+ audio_policy_dev_state_t state,
+ const char *device_address,
+ const char *device_name);
+ sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t device,
+ const char *device_address,
+ const char *device_name);
+};
+
+};
diff --git a/services/audiopolicy/managerdefault/ConfigParsingUtils.cpp b/services/audiopolicy/managerdefault/ConfigParsingUtils.cpp
new file mode 100644
index 0000000..1afd487
--- /dev/null
+++ b/services/audiopolicy/managerdefault/ConfigParsingUtils.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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::ConfigParsingUtils"
+//#define LOG_NDEBUG 0
+
+#include "AudioPolicyManager.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);
+ }
+ 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;
+ }
+
+ return flag;
+}
+
+//static
+uint32_t ConfigParsingUtils::parseInputFlagNames(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 |= stringToEnum(sInputFlagNameToEnumTable,
+ ARRAY_SIZE(sInputFlagNameToEnumTable),
+ flagName);
+ }
+ flagName = strtok(NULL, "|");
+ }
+ return flag;
+}
+
+//static
+audio_devices_t ConfigParsingUtils::parseDeviceNames(char *name)
+{
+ uint32_t device = 0;
+
+ char *devName = strtok(name, "|");
+ while (devName != NULL) {
+ if (strlen(devName) != 0) {
+ device |= stringToEnum(sDeviceNameToEnumTable,
+ ARRAY_SIZE(sDeviceNameToEnumTable),
+ devName);
+ }
+ devName = strtok(NULL, "|");
+ }
+ return device;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/managerdefault/ConfigParsingUtils.h b/services/audiopolicy/managerdefault/ConfigParsingUtils.h
new file mode 100644
index 0000000..b2d9763
--- /dev/null
+++ b/services/audiopolicy/managerdefault/ConfigParsingUtils.h
@@ -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.
+ */
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+// Definitions for audio_policy.conf file parsing
+// ----------------------------------------------------------------------------
+
+struct StringToEnum {
+ const char *name;
+ uint32_t value;
+};
+
+#define STRING_TO_ENUM(string) { #string, string }
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
+const StringToEnum sDeviceNameToEnumTable[] = {
+ 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_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),
+};
+
+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),
+};
+
+const StringToEnum sInputFlagNameToEnumTable[] = {
+ STRING_TO_ENUM(AUDIO_INPUT_FLAG_FAST),
+ STRING_TO_ENUM(AUDIO_INPUT_FLAG_HW_HOTWORD),
+};
+
+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),
+};
+
+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 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);
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/managerdefault/Devices.cpp b/services/audiopolicy/managerdefault/Devices.cpp
new file mode 100644
index 0000000..13c8bbc
--- /dev/null
+++ b/services/audiopolicy/managerdefault/Devices.cpp
@@ -0,0 +1,282 @@
+/*
+ * 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::Devices"
+//#define LOG_NDEBUG 0
+
+#include "AudioPolicyManager.h"
+
+namespace android {
+
+String8 DeviceDescriptor::emptyNameStr = String8("");
+
+DeviceDescriptor::DeviceDescriptor(const String8& name, audio_devices_t type) :
+ AudioPort(name, AUDIO_PORT_TYPE_DEVICE,
+ audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
+ AUDIO_PORT_ROLE_SOURCE,
+ NULL),
+ mDeviceType(type), mAddress("")
+{
+
+}
+
+bool DeviceDescriptor::equals(const sp<DeviceDescriptor>& other) const
+{
+ // Devices are considered equal if they:
+ // - are of the same type (a device type cannot be AUDIO_DEVICE_NONE)
+ // - have the same address or one device does not specify the address
+ // - have the same channel mask or one device does not specify the channel mask
+ return (mDeviceType == other->mDeviceType) &&
+ (mAddress == "" || other->mAddress == "" || mAddress == other->mAddress) &&
+ (mChannelMask == 0 || other->mChannelMask == 0 ||
+ 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;
+ for(size_t i = 0; i < size(); i++) {
+ mDeviceTypes |= itemAt(i)->mDeviceType;
+ }
+ ALOGV("DeviceVector::refreshTypes() mDeviceTypes %08x", mDeviceTypes);
+}
+
+ssize_t DeviceVector::indexOf(const sp<DeviceDescriptor>& item) const
+{
+ for(size_t i = 0; i < size(); i++) {
+ if (item->equals(itemAt(i))) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+ssize_t DeviceVector::add(const sp<DeviceDescriptor>& item)
+{
+ ssize_t ret = indexOf(item);
+
+ if (ret < 0) {
+ ret = SortedVector::add(item);
+ if (ret >= 0) {
+ refreshTypes();
+ }
+ } else {
+ ALOGW("DeviceVector::add device %08x already in", item->mDeviceType);
+ ret = -1;
+ }
+ return ret;
+}
+
+ssize_t DeviceVector::remove(const sp<DeviceDescriptor>& item)
+{
+ size_t i;
+ ssize_t ret = indexOf(item);
+
+ if (ret < 0) {
+ ALOGW("DeviceVector::remove device %08x not in", item->mDeviceType);
+ } else {
+ ret = SortedVector::removeAt(ret);
+ if (ret >= 0) {
+ refreshTypes();
+ }
+ }
+ return ret;
+}
+
+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(String8("device_type"), type | role_bit));
+ }
+}
+
+void DeviceVector::loadDevicesFromName(char *name,
+ const DeviceVector& declaredDevices)
+{
+ char *devName = strtok(name, "|");
+ while (devName != NULL) {
+ if (strlen(devName) != 0) {
+ audio_devices_t type = ConfigParsingUtils::stringToEnum(sDeviceNameToEnumTable,
+ ARRAY_SIZE(sDeviceNameToEnumTable),
+ devName);
+ if (type != AUDIO_DEVICE_NONE) {
+ sp<DeviceDescriptor> dev = new DeviceDescriptor(String8(name), 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.getDeviceFromName(String8(devName));
+ if (deviceDesc != 0) {
+ add(deviceDesc);
+ }
+ }
+ }
+ devName = strtok(NULL, "|");
+ }
+}
+
+sp<DeviceDescriptor> DeviceVector::getDevice(audio_devices_t type, String8 address) const
+{
+ sp<DeviceDescriptor> device;
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->mDeviceType == type) {
+ if (address == "" || itemAt(i)->mAddress == address) {
+ device = itemAt(i);
+ if (itemAt(i)->mAddress == address) {
+ break;
+ }
+ }
+ }
+ }
+ ALOGV("DeviceVector::getDevice() for type %08x address %s found %p",
+ type, address.string(), device.get());
+ return device;
+}
+
+sp<DeviceDescriptor> DeviceVector::getDeviceFromId(audio_port_handle_t id) const
+{
+ sp<DeviceDescriptor> device;
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->getHandle() == id) {
+ device = itemAt(i);
+ break;
+ }
+ }
+ return device;
+}
+
+DeviceVector DeviceVector::getDevicesFromType(audio_devices_t type) const
+{
+ DeviceVector devices;
+ for (size_t i = 0; (i < size()) && (type != AUDIO_DEVICE_NONE); i++) {
+ if (itemAt(i)->mDeviceType & type & ~AUDIO_DEVICE_BIT_IN) {
+ devices.add(itemAt(i));
+ type &= ~itemAt(i)->mDeviceType;
+ ALOGV("DeviceVector::getDevicesFromType() for type %x found %p",
+ itemAt(i)->mDeviceType, itemAt(i).get());
+ }
+ }
+ return devices;
+}
+
+DeviceVector DeviceVector::getDevicesFromTypeAddr(
+ audio_devices_t type, String8 address) const
+{
+ DeviceVector devices;
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->mDeviceType == type) {
+ if (itemAt(i)->mAddress == address) {
+ devices.add(itemAt(i));
+ }
+ }
+ }
+ return devices;
+}
+
+sp<DeviceDescriptor> DeviceVector::getDeviceFromName(const String8& name) const
+{
+ sp<DeviceDescriptor> device;
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->mName == name) {
+ device = itemAt(i);
+ break;
+ }
+ }
+ return device;
+}
+
+void DeviceDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig) const
+{
+ dstConfig->config_mask = AUDIO_PORT_CONFIG_CHANNEL_MASK|AUDIO_PORT_CONFIG_GAIN;
+ if (srcConfig != NULL) {
+ dstConfig->config_mask |= srcConfig->config_mask;
+ }
+
+ AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
+
+ dstConfig->id = mId;
+ dstConfig->role = audio_is_output_device(mDeviceType) ?
+ AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE;
+ dstConfig->type = AUDIO_PORT_TYPE_DEVICE;
+ dstConfig->ext.device.type = mDeviceType;
+
+ //TODO Understand why this test is necessary. i.e. why at boot time does it crash
+ // without the test?
+ // This has been demonstrated to NOT be true (at start up)
+ // ALOG_ASSERT(mModule != NULL);
+ dstConfig->ext.device.hw_module = mModule != NULL ? mModule->mHandle : NULL;
+ strncpy(dstConfig->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN);
+}
+
+void DeviceDescriptor::toAudioPort(struct audio_port *port) const
+{
+ ALOGV("DeviceDescriptor::toAudioPort() handle %d type %x", mId, mDeviceType);
+ AudioPort::toAudioPort(port);
+ port->id = mId;
+ toAudioPortConfig(&port->active_config);
+ port->ext.device.type = mDeviceType;
+ port->ext.device.hw_module = mModule->mHandle;
+ strncpy(port->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN);
+}
+
+status_t DeviceDescriptor::dump(int fd, int spaces, int index) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "%*sDevice %d:\n", spaces, "", index+1);
+ result.append(buffer);
+ if (mId != 0) {
+ snprintf(buffer, SIZE, "%*s- id: %2d\n", spaces, "", mId);
+ result.append(buffer);
+ }
+ snprintf(buffer, SIZE, "%*s- type: %-48s\n", spaces, "",
+ ConfigParsingUtils::enumToString(sDeviceNameToEnumTable,
+ ARRAY_SIZE(sDeviceNameToEnumTable),
+ mDeviceType));
+ 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);
+
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/managerdefault/Devices.h b/services/audiopolicy/managerdefault/Devices.h
new file mode 100644
index 0000000..65e1416
--- /dev/null
+++ b/services/audiopolicy/managerdefault/Devices.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+namespace android {
+
+class AudioPort;
+class AudioPortConfig;
+
+class DeviceDescriptor: public AudioPort, public AudioPortConfig
+{
+public:
+ DeviceDescriptor(const String8& name, audio_devices_t type);
+
+ virtual ~DeviceDescriptor() {}
+
+ bool equals(const sp<DeviceDescriptor>& other) const;
+
+ // AudioPortConfig
+ virtual sp<AudioPort> getAudioPort() const { return (AudioPort*) this; }
+ virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig = NULL) const;
+
+ // AudioPort
+ virtual void loadGains(cnode *root);
+ virtual void toAudioPort(struct audio_port *port) const;
+
+ status_t dump(int fd, int spaces, int index) const;
+
+ audio_devices_t mDeviceType;
+ String8 mAddress;
+ audio_port_handle_t mId;
+
+ static String8 emptyNameStr;
+};
+
+class DeviceVector : public SortedVector< sp<DeviceDescriptor> >
+{
+public:
+ DeviceVector() : SortedVector(), mDeviceTypes(AUDIO_DEVICE_NONE) {}
+
+ ssize_t add(const sp<DeviceDescriptor>& item);
+ 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 loadDevicesFromName(char *name, 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> getDeviceFromName(const String8& name) const;
+ DeviceVector getDevicesFromTypeAddr(audio_devices_t type, String8 address)
+ const;
+
+private:
+ void refreshTypes();
+ audio_devices_t mDeviceTypes;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/managerdefault/Gains.cpp b/services/audiopolicy/managerdefault/Gains.cpp
new file mode 100644
index 0000000..4aca26d
--- /dev/null
+++ b/services/audiopolicy/managerdefault/Gains.cpp
@@ -0,0 +1,446 @@
+/*
+ * 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::Gains"
+//#define LOG_NDEBUG 0
+
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+#include "AudioPolicyManager.h"
+
+#include <math.h>
+
+namespace android {
+
+const VolumeCurvePoint
+ApmGains::sDefaultVolumeCurve[ApmGains::VOLCNT] = {
+ {1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f}
+};
+
+
+const VolumeCurvePoint
+ApmGains::sDefaultMediaVolumeCurve[ApmGains::VOLCNT] = {
+ {1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f}
+};
+
+const VolumeCurvePoint
+ApmGains::sExtMediaSystemVolumeCurve[ApmGains::VOLCNT] = {
+ {1, -58.0f}, {20, -40.0f}, {60, -21.0f}, {100, -10.0f}
+};
+
+const VolumeCurvePoint
+ApmGains::sSpeakerMediaVolumeCurve[ApmGains::VOLCNT] = {
+ {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f}
+};
+
+const VolumeCurvePoint
+ApmGains::sSpeakerMediaVolumeCurveDrc[ApmGains::VOLCNT] = {
+ {1, -55.0f}, {20, -43.0f}, {86, -12.0f}, {100, 0.0f}
+};
+
+const VolumeCurvePoint
+ApmGains::sSpeakerSonificationVolumeCurve[ApmGains::VOLCNT] = {
+ {1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f}
+};
+
+const VolumeCurvePoint
+ApmGains::sSpeakerSonificationVolumeCurveDrc[ApmGains::VOLCNT] = {
+ {1, -35.7f}, {33, -26.1f}, {66, -13.2f}, {100, 0.0f}
+};
+
+// AUDIO_STREAM_SYSTEM, AUDIO_STREAM_ENFORCED_AUDIBLE and AUDIO_STREAM_DTMF volume tracks
+// AUDIO_STREAM_RING on phones and AUDIO_STREAM_MUSIC on tablets.
+// AUDIO_STREAM_DTMF tracks AUDIO_STREAM_VOICE_CALL while in call (See AudioService.java).
+// The range is constrained between -24dB and -6dB over speaker and -30dB and -18dB over headset.
+
+const VolumeCurvePoint
+ApmGains::sDefaultSystemVolumeCurve[ApmGains::VOLCNT] = {
+ {1, -24.0f}, {33, -18.0f}, {66, -12.0f}, {100, -6.0f}
+};
+
+const VolumeCurvePoint
+ApmGains::sDefaultSystemVolumeCurveDrc[ApmGains::VOLCNT] = {
+ {1, -34.0f}, {33, -24.0f}, {66, -15.0f}, {100, -6.0f}
+};
+
+const VolumeCurvePoint
+ApmGains::sHeadsetSystemVolumeCurve[ApmGains::VOLCNT] = {
+ {1, -30.0f}, {33, -26.0f}, {66, -22.0f}, {100, -18.0f}
+};
+
+const VolumeCurvePoint
+ApmGains::sDefaultVoiceVolumeCurve[ApmGains::VOLCNT] = {
+ {0, -42.0f}, {33, -28.0f}, {66, -14.0f}, {100, 0.0f}
+};
+
+const VolumeCurvePoint
+ApmGains::sSpeakerVoiceVolumeCurve[ApmGains::VOLCNT] = {
+ {0, -24.0f}, {33, -16.0f}, {66, -8.0f}, {100, 0.0f}
+};
+
+const VolumeCurvePoint
+ApmGains::sLinearVolumeCurve[ApmGains::VOLCNT] = {
+ {0, -96.0f}, {33, -68.0f}, {66, -34.0f}, {100, 0.0f}
+};
+
+const VolumeCurvePoint
+ApmGains::sSilentVolumeCurve[ApmGains::VOLCNT] = {
+ {0, -96.0f}, {1, -96.0f}, {2, -96.0f}, {100, -96.0f}
+};
+
+const VolumeCurvePoint
+ApmGains::sFullScaleVolumeCurve[ApmGains::VOLCNT] = {
+ {0, 0.0f}, {1, 0.0f}, {2, 0.0f}, {100, 0.0f}
+};
+
+const VolumeCurvePoint *ApmGains::sVolumeProfiles[AUDIO_STREAM_CNT]
+ [ApmGains::DEVICE_CATEGORY_CNT] = {
+ { // AUDIO_STREAM_VOICE_CALL
+ ApmGains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ ApmGains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ ApmGains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ ApmGains::sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_SYSTEM
+ ApmGains::sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ ApmGains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_RING
+ ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ ApmGains::sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ ApmGains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_MUSIC
+ ApmGains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ ApmGains::sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ ApmGains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ ApmGains::sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_ALARM
+ ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ ApmGains::sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ ApmGains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_NOTIFICATION
+ ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ ApmGains::sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ ApmGains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_BLUETOOTH_SCO
+ ApmGains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ ApmGains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ ApmGains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ ApmGains::sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_ENFORCED_AUDIBLE
+ ApmGains::sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ ApmGains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_DTMF
+ ApmGains::sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ ApmGains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_TTS
+ // "Transmitted Through Speaker": always silent except on DEVICE_CATEGORY_SPEAKER
+ ApmGains::sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ ApmGains::sLinearVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ ApmGains::sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ ApmGains::sSilentVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_ACCESSIBILITY
+ ApmGains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ ApmGains::sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ ApmGains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ ApmGains::sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_REROUTING
+ ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ ApmGains::sFullScaleVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_PATCH
+ ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ ApmGains::sFullScaleVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+};
+
+//static
+audio_devices_t ApmGains::getDeviceForVolume(audio_devices_t device)
+{
+ if (device == AUDIO_DEVICE_NONE) {
+ // this happens when forcing a route update and no track is active on an output.
+ // In this case the returned category is not important.
+ device = AUDIO_DEVICE_OUT_SPEAKER;
+ } else if (popcount(device) > 1) {
+ // Multiple device selection is either:
+ // - speaker + one other device: give priority to speaker in this case.
+ // - one A2DP device + another device: happens with duplicated output. In this case
+ // retain the device on the A2DP output as the other must not correspond to an active
+ // selection if not the speaker.
+ // - HDMI-CEC system audio mode only output: give priority to available item in order.
+ if (device & AUDIO_DEVICE_OUT_SPEAKER) {
+ device = AUDIO_DEVICE_OUT_SPEAKER;
+ } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) {
+ device = AUDIO_DEVICE_OUT_HDMI_ARC;
+ } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) {
+ device = AUDIO_DEVICE_OUT_AUX_LINE;
+ } else if (device & AUDIO_DEVICE_OUT_SPDIF) {
+ device = AUDIO_DEVICE_OUT_SPDIF;
+ } else {
+ device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
+ }
+ }
+
+ /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/
+ if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE)
+ device = AUDIO_DEVICE_OUT_SPEAKER;
+
+ ALOGW_IF(popcount(device) != 1,
+ "getDeviceForVolume() invalid device combination: %08x",
+ device);
+
+ return device;
+}
+
+//static
+ApmGains::device_category ApmGains::getDeviceCategory(audio_devices_t device)
+{
+ switch(getDeviceForVolume(device)) {
+ case AUDIO_DEVICE_OUT_EARPIECE:
+ return ApmGains::DEVICE_CATEGORY_EARPIECE;
+ case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+ case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+ return ApmGains::DEVICE_CATEGORY_HEADSET;
+ case AUDIO_DEVICE_OUT_LINE:
+ case AUDIO_DEVICE_OUT_AUX_DIGITAL:
+ /*USB? Remote submix?*/
+ return ApmGains::DEVICE_CATEGORY_EXT_MEDIA;
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+ case AUDIO_DEVICE_OUT_USB_ACCESSORY:
+ case AUDIO_DEVICE_OUT_USB_DEVICE:
+ case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
+ default:
+ return ApmGains::DEVICE_CATEGORY_SPEAKER;
+ }
+}
+
+//static
+float ApmGains::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
+ int indexInUi)
+{
+ ApmGains::device_category deviceCategory = ApmGains::getDeviceCategory(device);
+ const VolumeCurvePoint *curve = streamDesc.mVolumeCurve[deviceCategory];
+
+ // the volume index in the UI is relative to the min and max volume indices for this stream type
+ int nbSteps = 1 + curve[ApmGains::VOLMAX].mIndex -
+ curve[ApmGains::VOLMIN].mIndex;
+ int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) /
+ (streamDesc.mIndexMax - streamDesc.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[ApmGains::VOLMIN].mIndex) { // out of bounds
+ return 0.0f;
+ } else if (volIdx < curve[ApmGains::VOLKNEE1].mIndex) {
+ segment = 0;
+ } else if (volIdx < curve[ApmGains::VOLKNEE2].mIndex) {
+ segment = 1;
+ } else if (volIdx <= curve[ApmGains::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)) );
+
+ float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
+
+ ALOGVV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f] ampl=%.5f",
+ curve[segment].mIndex, volIdx,
+ curve[segment+1].mIndex,
+ curve[segment].mDBAttenuation,
+ decibels,
+ curve[segment+1].mDBAttenuation,
+ amplification);
+
+ return amplification;
+}
+
+
+
+AudioGain::AudioGain(int index, bool useInChannelMask)
+{
+ mIndex = index;
+ mUseInChannelMask = useInChannelMask;
+ memset(&mGain, 0, sizeof(struct audio_gain));
+}
+
+void AudioGain::getDefaultConfig(struct audio_gain_config *config)
+{
+ config->index = mIndex;
+ config->mode = mGain.mode;
+ config->channel_mask = mGain.channel_mask;
+ if ((mGain.mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
+ config->values[0] = mGain.default_value;
+ } else {
+ uint32_t numValues;
+ if (mUseInChannelMask) {
+ numValues = audio_channel_count_from_in_mask(mGain.channel_mask);
+ } else {
+ numValues = audio_channel_count_from_out_mask(mGain.channel_mask);
+ }
+ for (size_t i = 0; i < numValues; i++) {
+ config->values[i] = mGain.default_value;
+ }
+ }
+ if ((mGain.mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
+ config->ramp_duration_ms = mGain.min_ramp_ms;
+ }
+}
+
+status_t AudioGain::checkConfig(const struct audio_gain_config *config)
+{
+ if ((config->mode & ~mGain.mode) != 0) {
+ return BAD_VALUE;
+ }
+ if ((config->mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
+ if ((config->values[0] < mGain.min_value) ||
+ (config->values[0] > mGain.max_value)) {
+ return BAD_VALUE;
+ }
+ } else {
+ if ((config->channel_mask & ~mGain.channel_mask) != 0) {
+ return BAD_VALUE;
+ }
+ uint32_t numValues;
+ if (mUseInChannelMask) {
+ numValues = audio_channel_count_from_in_mask(config->channel_mask);
+ } else {
+ numValues = audio_channel_count_from_out_mask(config->channel_mask);
+ }
+ for (size_t i = 0; i < numValues; i++) {
+ if ((config->values[i] < mGain.min_value) ||
+ (config->values[i] > mGain.max_value)) {
+ return BAD_VALUE;
+ }
+ }
+ }
+ if ((config->mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
+ if ((config->ramp_duration_ms < mGain.min_ramp_ms) ||
+ (config->ramp_duration_ms > mGain.max_ramp_ms)) {
+ return BAD_VALUE;
+ }
+ }
+ return NO_ERROR;
+}
+
+void AudioGain::dump(int fd, int spaces, int index) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "%*sGain %d:\n", spaces, "", index+1);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- mode: %08x\n", spaces, "", mGain.mode);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- min_value: %d mB\n", spaces, "", mGain.min_value);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- max_value: %d mB\n", spaces, "", mGain.max_value);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- default_value: %d mB\n", spaces, "", mGain.default_value);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- step_value: %d mB\n", spaces, "", mGain.step_value);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms);
+ result.append(buffer);
+
+ write(fd, result.string(), result.size());
+}
+
+
+// --- StreamDescriptor class implementation
+
+StreamDescriptor::StreamDescriptor()
+ : mIndexMin(0), mIndexMax(1), mCanBeMuted(true)
+{
+ mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, 0);
+}
+
+int StreamDescriptor::getVolumeIndex(audio_devices_t device)
+{
+ device = ApmGains::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);
+}
+
+void StreamDescriptor::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ 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());
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/managerdefault/Gains.h b/services/audiopolicy/managerdefault/Gains.h
new file mode 100644
index 0000000..b4ab129
--- /dev/null
+++ b/services/audiopolicy/managerdefault/Gains.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.
+ */
+
+namespace android {
+
+class VolumeCurvePoint
+{
+public:
+ int mIndex;
+ float mDBAttenuation;
+};
+
+class StreamDescriptor;
+
+class ApmGains
+{
+public :
+ // 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 in volIndexToAmpl()
+ enum { VOLMIN = 0, VOLKNEE1 = 1, VOLKNEE2 = 2, VOLMAX = 3, VOLCNT = 4};
+
+ // 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
+ };
+
+ // returns the category the device belongs to with regard to volume curve management
+ static ApmGains::device_category getDeviceCategory(audio_devices_t device);
+
+ // extract one device relevant for volume control from multiple device selection
+ static audio_devices_t getDeviceForVolume(audio_devices_t device);
+
+ static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
+ int indexInUi);
+
+ // default volume curve
+ static const VolumeCurvePoint sDefaultVolumeCurve[ApmGains::VOLCNT];
+ // default volume curve for media strategy
+ static const VolumeCurvePoint sDefaultMediaVolumeCurve[ApmGains::VOLCNT];
+ // volume curve for non-media audio on ext media outputs (HDMI, Line, etc)
+ static const VolumeCurvePoint sExtMediaSystemVolumeCurve[ApmGains::VOLCNT];
+ // volume curve for media strategy on speakers
+ static const VolumeCurvePoint sSpeakerMediaVolumeCurve[ApmGains::VOLCNT];
+ static const VolumeCurvePoint sSpeakerMediaVolumeCurveDrc[ApmGains::VOLCNT];
+ // volume curve for sonification strategy on speakers
+ static const VolumeCurvePoint sSpeakerSonificationVolumeCurve[ApmGains::VOLCNT];
+ static const VolumeCurvePoint sSpeakerSonificationVolumeCurveDrc[ApmGains::VOLCNT];
+ static const VolumeCurvePoint sDefaultSystemVolumeCurve[ApmGains::VOLCNT];
+ static const VolumeCurvePoint sDefaultSystemVolumeCurveDrc[ApmGains::VOLCNT];
+ static const VolumeCurvePoint sHeadsetSystemVolumeCurve[ApmGains::VOLCNT];
+ static const VolumeCurvePoint sDefaultVoiceVolumeCurve[ApmGains::VOLCNT];
+ static const VolumeCurvePoint sSpeakerVoiceVolumeCurve[ApmGains::VOLCNT];
+ static const VolumeCurvePoint sLinearVolumeCurve[ApmGains::VOLCNT];
+ static const VolumeCurvePoint sSilentVolumeCurve[ApmGains::VOLCNT];
+ static const VolumeCurvePoint sFullScaleVolumeCurve[ApmGains::VOLCNT];
+ // default volume curves per stream and device category. See initializeVolumeCurves()
+ static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][ApmGains::DEVICE_CATEGORY_CNT];
+};
+
+
+class AudioGain: public RefBase
+{
+public:
+ AudioGain(int index, bool useInChannelMask);
+ virtual ~AudioGain() {}
+
+ 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);
+ int mIndex;
+ struct audio_gain mGain;
+ bool mUseInChannelMask;
+};
+
+
+// stream descriptor used for volume control
+class StreamDescriptor
+{
+public:
+ StreamDescriptor();
+
+ int getVolumeIndex(audio_devices_t device);
+ void dump(int fd);
+
+ int mIndexMin; // min volume index
+ int mIndexMax; // max volume index
+ KeyedVector<audio_devices_t, int> mIndexCur; // current volume index per device
+ bool mCanBeMuted; // true is the stream can be muted
+
+ const VolumeCurvePoint *mVolumeCurve[ApmGains::DEVICE_CATEGORY_CNT];
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/managerdefault/HwModule.cpp b/services/audiopolicy/managerdefault/HwModule.cpp
new file mode 100644
index 0000000..a04bdc8
--- /dev/null
+++ b/services/audiopolicy/managerdefault/HwModule.cpp
@@ -0,0 +1,279 @@
+/*
+ * 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::HwModule"
+//#define LOG_NDEBUG 0
+
+#include "AudioPolicyManager.h"
+#include "audio_policy_conf.h"
+#include <hardware/audio.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()
+{
+ for (size_t i = 0; i < mOutputProfiles.size(); i++) {
+ mOutputProfiles[i]->mSupportedDevices.clear();
+ }
+ for (size_t i = 0; i < mInputProfiles.size(); i++) {
+ mInputProfiles[i]->mSupportedDevices.clear();
+ }
+ 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, this);
+
+ 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.loadDevicesFromName((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());
+
+ 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, this);
+
+ 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.loadDevicesFromName((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);
+
+ 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, 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(String8(root->name), type);
+ deviceDesc->mModule = this;
+
+ node = root->first_child;
+ while (node) {
+ if (strcmp(node->name, 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 name %s type %08x address %s",
+ deviceDesc->mName.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)
+{
+ sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SOURCE, this);
+
+ profile->mSamplingRates.add(config->sample_rate);
+ profile->mChannelMasks.add(config->channel_mask);
+ profile->mFormats.add(config->format);
+
+ sp<DeviceDescriptor> devDesc = new DeviceDescriptor(name, device);
+ devDesc->mAddress = address;
+ profile->mSupportedDevices.add(devDesc);
+
+ mOutputProfiles.add(profile);
+
+ return NO_ERROR;
+}
+
+status_t HwModule::removeOutputProfile(String8 name)
+{
+ for (size_t i = 0; i < mOutputProfiles.size(); i++) {
+ if (mOutputProfiles[i]->mName == name) {
+ mOutputProfiles.removeAt(i);
+ break;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t HwModule::addInputProfile(String8 name, const audio_config_t *config,
+ audio_devices_t device, String8 address)
+{
+ sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SINK, this);
+
+ profile->mSamplingRates.add(config->sample_rate);
+ profile->mChannelMasks.add(config->channel_mask);
+ profile->mFormats.add(config->format);
+
+ sp<DeviceDescriptor> devDesc = new DeviceDescriptor(name, device);
+ devDesc->mAddress = address;
+ profile->mSupportedDevices.add(devDesc);
+
+ ALOGV("addInputProfile() name %s rate %d mask 0x08", name.string(), config->sample_rate, config->channel_mask);
+
+ mInputProfiles.add(profile);
+
+ return NO_ERROR;
+}
+
+status_t HwModule::removeInputProfile(String8 name)
+{
+ for (size_t i = 0; i < mInputProfiles.size(); i++) {
+ if (mInputProfiles[i]->mName == name) {
+ mInputProfiles.removeAt(i);
+ break;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+
+void HwModule::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, " - name: %s\n", mName);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " - handle: %d\n", mHandle);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " - version: %u.%u\n", mHalVersion >> 8, mHalVersion & 0xFF);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ if (mOutputProfiles.size()) {
+ write(fd, " - outputs:\n", strlen(" - outputs:\n"));
+ for (size_t i = 0; i < mOutputProfiles.size(); i++) {
+ snprintf(buffer, SIZE, " output %zu:\n", i);
+ write(fd, buffer, strlen(buffer));
+ mOutputProfiles[i]->dump(fd);
+ }
+ }
+ if (mInputProfiles.size()) {
+ write(fd, " - inputs:\n", strlen(" - inputs:\n"));
+ for (size_t i = 0; i < mInputProfiles.size(); i++) {
+ snprintf(buffer, SIZE, " input %zu:\n", i);
+ write(fd, buffer, strlen(buffer));
+ 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);
+ }
+ }
+}
+
+} //namespace android
diff --git a/services/audiopolicy/managerdefault/HwModule.h b/services/audiopolicy/managerdefault/HwModule.h
new file mode 100644
index 0000000..f814dd9
--- /dev/null
+++ b/services/audiopolicy/managerdefault/HwModule.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+namespace android {
+
+class HwModule : public RefBase
+{
+public:
+ HwModule(const char *name);
+ ~HwModule();
+
+ status_t loadOutput(cnode *root);
+ status_t loadInput(cnode *root);
+ status_t loadDevice(cnode *root);
+
+ status_t addOutputProfile(String8 name, const audio_config_t *config,
+ audio_devices_t device, String8 address);
+ status_t removeOutputProfile(String8 name);
+ status_t addInputProfile(String8 name, const audio_config_t *config,
+ audio_devices_t device, String8 address);
+ status_t removeInputProfile(String8 name);
+
+ 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
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/managerdefault/IOProfile.cpp b/services/audiopolicy/managerdefault/IOProfile.cpp
new file mode 100644
index 0000000..538ac1a
--- /dev/null
+++ b/services/audiopolicy/managerdefault/IOProfile.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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::IOProfile"
+//#define LOG_NDEBUG 0
+
+#include "AudioPolicyManager.h"
+
+namespace android {
+
+IOProfile::IOProfile(const String8& name, audio_port_role_t role,
+ const sp<HwModule>& module)
+ : AudioPort(name, AUDIO_PORT_TYPE_MIX, role, module)
+{
+}
+
+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
+bool IOProfile::isCompatibleProfile(audio_devices_t device,
+ String8 address,
+ uint32_t samplingRate,
+ uint32_t *updatedSamplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ 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;
+ ALOG_ASSERT(isPlaybackThread != isRecordThread);
+
+ if (device != AUDIO_DEVICE_NONE && mSupportedDevices.getDevice(device, address) == 0) {
+ return false;
+ }
+
+ if (samplingRate == 0) {
+ return false;
+ }
+ uint32_t myUpdatedSamplingRate = samplingRate;
+ if (isPlaybackThread && checkExactSamplingRate(samplingRate) != NO_ERROR) {
+ return false;
+ }
+ if (isRecordThread && checkCompatibleSamplingRate(samplingRate, &myUpdatedSamplingRate) !=
+ NO_ERROR) {
+ return false;
+ }
+
+ if (!audio_is_valid_format(format) || checkFormat(format) != NO_ERROR) {
+ return false;
+ }
+
+ if (isPlaybackThread && (!audio_is_output_channel(channelMask) ||
+ checkExactChannelMask(channelMask) != NO_ERROR)) {
+ return false;
+ }
+ if (isRecordThread && (!audio_is_input_channel(channelMask) ||
+ checkCompatibleChannelMask(channelMask) != NO_ERROR)) {
+ return false;
+ }
+
+ if (isPlaybackThread && (mFlags & 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) &
+ ~AUDIO_INPUT_FLAG_FAST)) {
+ return false;
+ }
+
+ if (updatedSamplingRate != NULL) {
+ *updatedSamplingRate = myUpdatedSamplingRate;
+ }
+ return true;
+}
+
+void IOProfile::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ AudioPort::dump(fd, 4);
+
+ snprintf(buffer, SIZE, " - flags: 0x%04x\n", mFlags);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " - devices:\n");
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ for (size_t i = 0; i < mSupportedDevices.size(); i++) {
+ mSupportedDevices[i]->dump(fd, 6, i);
+ }
+}
+
+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);
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/managerdefault/IOProfile.h b/services/audiopolicy/managerdefault/IOProfile.h
new file mode 100644
index 0000000..3317969
--- /dev/null
+++ b/services/audiopolicy/managerdefault/IOProfile.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+namespace android {
+
+class HwModule;
+
+// the IOProfile class describes the capabilities of an output or input stream.
+// It is currently assumed that all combination of listed parameters are supported.
+// It is used by the policy manager to determine if an output or input is suitable for
+// a given use case, open/close it accordingly and connect/disconnect audio tracks
+// to/from it.
+class IOProfile : public AudioPort
+{
+public:
+ IOProfile(const String8& name, audio_port_role_t role, const sp<HwModule>& module);
+ virtual ~IOProfile();
+
+ // This method is used for both output and input.
+ // If parameter updatedSamplingRate is non-NULL, it is assigned the actual sample rate.
+ // For input, flags is interpreted as audio_input_flags_t.
+ // TODO: merge audio_output_flags_t and audio_input_flags_t.
+ bool isCompatibleProfile(audio_devices_t device,
+ String8 address,
+ uint32_t samplingRate,
+ uint32_t *updatedSamplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ uint32_t flags) const;
+
+ void dump(int fd);
+ void log();
+
+ DeviceVector mSupportedDevices; // supported devices
+ // (devices this output can be routed to)
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/managerdefault/Ports.cpp b/services/audiopolicy/managerdefault/Ports.cpp
new file mode 100644
index 0000000..3e55cee
--- /dev/null
+++ b/services/audiopolicy/managerdefault/Ports.cpp
@@ -0,0 +1,844 @@
+/*
+ * 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::Ports"
+//#define LOG_NDEBUG 0
+
+#include "AudioPolicyManager.h"
+
+#include "audio_policy_conf.h"
+
+namespace android {
+
+// --- AudioPort class implementation
+
+AudioPort::AudioPort(const String8& name, audio_port_type_t type,
+ audio_port_role_t role, const sp<HwModule>& module) :
+ mName(name), mType(type), mRole(role), mModule(module), mFlags(0), mId(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) {
+ mId = AudioPolicyManager::nextUniqueId();
+ mModule = module;
+}
+
+void AudioPort::toAudioPort(struct audio_port *port) const
+{
+ 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 = i;
+ for (i = 0; i < mChannelMasks.size() && i < AUDIO_PORT_MAX_CHANNEL_MASKS; i++) {
+ if (mChannelMasks[i] != 0) {
+ port->channel_masks[i] = mChannelMasks[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];
+ }
+ }
+ port->num_formats = i;
+
+ ALOGV("AudioPort::toAudioPort() num gains %zu", mGains.size());
+
+ for (i = 0; i < mGains.size() && i < AUDIO_PORT_MAX_GAINS; i++) {
+ port->gains[i] = mGains[i]->mGain;
+ }
+ 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;
+ break;
+ }
+ }
+ if (!hasRate) { // never import a sampling rate twice
+ mSamplingRates.add(rate);
+ }
+ }
+ }
+ 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 channel mask twice
+ mFormats.add(format);
+ }
+ }
+ }
+ for (size_t k = 0 ; k < port->mGains.size() ; k++) {
+ sp<AudioGain> gain = port->mGains.itemAt(k);
+ if (gain != 0) {
+ bool hasGain = false;
+ for (size_t l = 0 ; l < mGains.size() ; l++) {
+ if (gain == mGains.itemAt(l)) {
+ hasGain = true;
+ break;
+ }
+ }
+ if (!hasGain) { // never import a gain twice
+ mGains.add(gain);
+ }
+ }
+ }
+}
+
+void AudioPort::clearCapabilities() {
+ mChannelMasks.clear();
+ mFormats.clear();
+ mSamplingRates.clear();
+ mGains.clear();
+}
+
+void AudioPort::loadSamplingRates(char *name)
+{
+ 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, "|");
+ }
+}
+
+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) {
+ ALOGV("loadInChannels() adding channelMask %04x", 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) {
+ 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()) {
+ 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;
+ }
+ }
+ }
+ // This uses hard-coded knowledge about AudioFlinger resampling ratios.
+ // TODO Move these assumptions out.
+ static const uint32_t kMaxDownSampleRatio = 6; // beyond this aliasing occurs
+ static const uint32_t kMaxUpSampleRatio = 256; // beyond this sample rate inaccuracies occur
+ // due to approximation by an int32_t of the
+ // phase increments
+ // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
+ if (minAbove >= 0) {
+ candidate = mSamplingRates[minAbove];
+ if (candidate / kMaxDownSampleRatio <= 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 * kMaxUpSampleRatio >= 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)
+ const
+{
+ if (mChannelMasks.isEmpty()) {
+ return NO_ERROR;
+ }
+
+ const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
+ for (size_t i = 0; i < mChannelMasks.size(); i ++) {
+ // FIXME Does not handle multi-channel automatic conversions yet
+ audio_channel_mask_t supported = mChannelMasks[i];
+ if (supported == channelMask) {
+ return NO_ERROR;
+ }
+ if (isRecordThread) {
+ // This uses hard-coded knowledge that AudioFlinger can silently down-mix and up-mix.
+ // FIXME Abstract this out to a table.
+ if (((supported == AUDIO_CHANNEL_IN_FRONT_BACK || supported == AUDIO_CHANNEL_IN_STEREO)
+ && channelMask == AUDIO_CHANNEL_IN_MONO) ||
+ (supported == AUDIO_CHANNEL_IN_MONO && (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
+ || channelMask == AUDIO_CHANNEL_IN_STEREO))) {
+ return NO_ERROR;
+ }
+ }
+ }
+ return BAD_VALUE;
+}
+
+status_t AudioPort::checkFormat(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;
+}
+
+
+uint32_t AudioPort::pickSamplingRate() const
+{
+ // special case for uninitialized dynamic profile
+ if (mSamplingRates.size() == 1 && mSamplingRates[0] == 0) {
+ return 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))) {
+ uint32_t samplingRate = UINT_MAX;
+ for (size_t i = 0; i < mSamplingRates.size(); i ++) {
+ if ((mSamplingRates[i] < samplingRate) && (mSamplingRates[i] > 0)) {
+ samplingRate = mSamplingRates[i];
+ }
+ }
+ return (samplingRate == UINT_MAX) ? 0 : samplingRate;
+ }
+
+ 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
+ if (mType != AUDIO_PORT_TYPE_MIX) {
+ maxRate = UINT_MAX;
+ }
+ for (size_t i = 0; i < mSamplingRates.size(); i ++) {
+ if ((mSamplingRates[i] > samplingRate) && (mSamplingRates[i] <= maxRate)) {
+ samplingRate = mSamplingRates[i];
+ }
+ }
+ return samplingRate;
+}
+
+audio_channel_mask_t AudioPort::pickChannelMask() 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;
+
+ // 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))) {
+ uint32_t channelCount = 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]);
+ }
+ if ((cnlCount < channelCount) && (cnlCount > 0)) {
+ channelMask = mChannelMasks[i];
+ channelCount = cnlCount;
+ }
+ }
+ return channelMask;
+ }
+
+ 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]);
+ }
+ if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
+ channelMask = mChannelMasks[i];
+ channelCount = cnlCount;
+ }
+ }
+ return channelMask;
+}
+
+/* format in order of increasing preference */
+const audio_format_t AudioPort::sPcmFormatCompareTable[] = {
+ AUDIO_FORMAT_DEFAULT,
+ AUDIO_FORMAT_PCM_16_BIT,
+ AUDIO_FORMAT_PCM_8_24_BIT,
+ AUDIO_FORMAT_PCM_24_BIT_PACKED,
+ AUDIO_FORMAT_PCM_32_BIT,
+ AUDIO_FORMAT_PCM_FLOAT,
+};
+
+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()
+ if (!audio_is_linear_pcm(format1)) {
+ if (!audio_is_linear_pcm(format2)) {
+ return 0;
+ }
+ return 1;
+ }
+ if (!audio_is_linear_pcm(format2)) {
+ return -1;
+ }
+
+ int index1 = -1, index2 = -1;
+ for (size_t i = 0;
+ (i < ARRAY_SIZE(sPcmFormatCompareTable)) && ((index1 == -1) || (index2 == -1));
+ i ++) {
+ if (sPcmFormatCompareTable[i] == format1) {
+ index1 = i;
+ }
+ if (sPcmFormatCompareTable[i] == format2) {
+ index2 = i;
+ }
+ }
+ // format1 not found => index1 < 0 => format2 > format1
+ // format2 not found => index2 < 0 => format2 < format1
+ return index1 - index2;
+}
+
+audio_format_t AudioPort::pickFormat() const
+{
+ // special case for uninitialized dynamic profile
+ if (mFormats.size() == 1 && mFormats[0] == 0) {
+ return AUDIO_FORMAT_DEFAULT;
+ }
+
+ 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)))) {
+ 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];
+ }
+ }
+ return format;
+}
+
+status_t AudioPort::checkGain(const struct audio_gain_config *gainConfig,
+ int index) const
+{
+ if (index < 0 || (size_t)index >= mGains.size()) {
+ return BAD_VALUE;
+ }
+ return mGains[index]->checkConfig(gainConfig);
+}
+
+void AudioPort::dump(int fd, int spaces) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ if (mName.size() != 0) {
+ snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
+ result.append(buffer);
+ }
+
+ 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]);
+ }
+ 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]);
+ if (i == 0 && strcmp(formatStr, "") == 0) {
+ snprintf(buffer, SIZE, "Dynamic");
+ } 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);
+ result.append(buffer);
+ for (size_t i = 0; i < mGains.size(); i++) {
+ mGains[i]->dump(fd, spaces + 2, i);
+ }
+ }
+}
+
+
+// --- AudioPortConfig class implementation
+
+AudioPortConfig::AudioPortConfig()
+{
+ mSamplingRate = 0;
+ mChannelMask = AUDIO_CHANNEL_NONE;
+ mFormat = AUDIO_FORMAT_INVALID;
+ mGain.index = -1;
+}
+
+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;
+
+ localBackupConfig.config_mask = config->config_mask;
+ toAudioPortConfig(&localBackupConfig);
+
+ sp<AudioPort> audioport = getAudioPort();
+ if (audioport == 0) {
+ status = NO_INIT;
+ 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->checkFormat(config->format);
+ if (status != NO_ERROR) {
+ goto exit;
+ }
+ mFormat = config->format;
+ }
+ if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) {
+ status = audioport->checkGain(&config->gain, config->gain.index);
+ if (status != NO_ERROR) {
+ goto exit;
+ }
+ mGain = config->gain;
+ }
+
+exit:
+ if (status != NO_ERROR) {
+ applyAudioPortConfig(&localBackupConfig);
+ }
+ if (backupConfig != NULL) {
+ *backupConfig = localBackupConfig;
+ }
+ return status;
+}
+
+void AudioPortConfig::toAudioPortConfig(struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig) const
+{
+ if (dstConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
+ dstConfig->sample_rate = mSamplingRate;
+ if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE)) {
+ dstConfig->sample_rate = srcConfig->sample_rate;
+ }
+ } else {
+ dstConfig->sample_rate = 0;
+ }
+ if (dstConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
+ dstConfig->channel_mask = mChannelMask;
+ if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK)) {
+ dstConfig->channel_mask = srcConfig->channel_mask;
+ }
+ } else {
+ dstConfig->channel_mask = AUDIO_CHANNEL_NONE;
+ }
+ if (dstConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
+ dstConfig->format = mFormat;
+ if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT)) {
+ dstConfig->format = srcConfig->format;
+ }
+ } else {
+ dstConfig->format = AUDIO_FORMAT_INVALID;
+ }
+ if (dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) {
+ dstConfig->gain = mGain;
+ if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)) {
+ dstConfig->gain = srcConfig->gain;
+ }
+ } else {
+ dstConfig->gain.index = -1;
+ }
+ if (dstConfig->gain.index != -1) {
+ dstConfig->config_mask |= AUDIO_PORT_CONFIG_GAIN;
+ } else {
+ dstConfig->config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
+ }
+}
+
+
+// --- AudioPatch class implementation
+
+AudioPatch::AudioPatch(audio_patch_handle_t handle,
+ const struct audio_patch *patch, uid_t uid) :
+ mHandle(handle), mPatch(*patch), mUid(uid), mAfPatchHandle(0)
+{}
+
+status_t AudioPatch::dump(int fd, int spaces, int index) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "%*sAudio patch %d:\n", spaces, "", index+1);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- handle: %2d\n", spaces, "", mHandle);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- audio flinger handle: %2d\n", spaces, "", mAfPatchHandle);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- owner uid: %2d\n", spaces, "", mUid);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- %d sources:\n", spaces, "", mPatch.num_sources);
+ result.append(buffer);
+ for (size_t i = 0; i < mPatch.num_sources; i++) {
+ if (mPatch.sources[i].type == AUDIO_PORT_TYPE_DEVICE) {
+ snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
+ mPatch.sources[i].id, ConfigParsingUtils::enumToString(sDeviceNameToEnumTable,
+ ARRAY_SIZE(sDeviceNameToEnumTable),
+ mPatch.sources[i].ext.device.type));
+ } 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);
+ }
+ result.append(buffer);
+ }
+ snprintf(buffer, SIZE, "%*s- %d sinks:\n", spaces, "", mPatch.num_sinks);
+ result.append(buffer);
+ for (size_t i = 0; i < mPatch.num_sinks; i++) {
+ if (mPatch.sinks[i].type == AUDIO_PORT_TYPE_DEVICE) {
+ snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
+ mPatch.sinks[i].id, ConfigParsingUtils::enumToString(sDeviceNameToEnumTable,
+ ARRAY_SIZE(sDeviceNameToEnumTable),
+ mPatch.sinks[i].ext.device.type));
+ } 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);
+ }
+ result.append(buffer);
+ }
+
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+
+}; // namespace android
diff --git a/services/audiopolicy/managerdefault/Ports.h b/services/audiopolicy/managerdefault/Ports.h
new file mode 100644
index 0000000..f6e0e93
--- /dev/null
+++ b/services/audiopolicy/managerdefault/Ports.h
@@ -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.
+ */
+
+namespace android {
+
+class HwModule;
+
+class AudioPort: public virtual RefBase
+{
+public:
+ AudioPort(const String8& name, audio_port_type_t type,
+ audio_port_role_t role, const sp<HwModule>& module);
+ virtual ~AudioPort() {}
+
+ audio_port_handle_t getHandle() { return mId; }
+
+ void attach(const sp<HwModule>& module);
+ bool isAttached() { return mId != 0; }
+
+ virtual void toAudioPort(struct audio_port *port) const;
+
+ void importAudioPort(const sp<AudioPort> port);
+ void clearCapabilities();
+
+ void loadSamplingRates(char *name);
+ void loadFormats(char *name);
+ void loadOutChannels(char *name);
+ void loadInChannels(char *name);
+
+ audio_gain_mode_t loadGainMode(char *name);
+ void loadGain(cnode *root, int index);
+ virtual void loadGains(cnode *root);
+
+ // 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) const;
+ status_t checkFormat(audio_format_t format) const;
+ 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;
+
+ static const audio_format_t sPcmFormatCompareTable[];
+ static int compareFormats(audio_format_t format1, audio_format_t format2);
+
+ void dump(int fd, int spaces) 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
+ sp<HwModule> mModule; // audio HW module exposing this I/O stream
+ uint32_t mFlags; // attribute flags (e.g primary output,
+ // direct output...).
+
+
+protected:
+ //TODO - clarify the role of mId in this case, both an "attached" indicator
+ // and a unique ID for identifying a port to the (upcoming) selection API,
+ // and its relationship to the mId in AudioOutputDescriptor and AudioInputDescriptor.
+ audio_port_handle_t mId;
+};
+
+class AudioPortConfig: public virtual RefBase
+{
+public:
+ AudioPortConfig();
+ virtual ~AudioPortConfig() {}
+
+ status_t applyAudioPortConfig(const struct audio_port_config *config,
+ struct audio_port_config *backupConfig = NULL);
+ virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig = NULL) const = 0;
+ virtual sp<AudioPort> getAudioPort() const = 0;
+ uint32_t mSamplingRate;
+ audio_format_t mFormat;
+ audio_channel_mask_t mChannelMask;
+ struct audio_gain_config mGain;
+};
+
+
+class AudioPatch: public RefBase
+{
+public:
+ AudioPatch(audio_patch_handle_t handle, const struct audio_patch *patch, uid_t uid);
+
+ status_t dump(int fd, int spaces, int index) const;
+
+ audio_patch_handle_t mHandle;
+ struct audio_patch mPatch;
+ uid_t mUid;
+ audio_patch_handle_t mAfPatchHandle;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/audio_policy_conf.h b/services/audiopolicy/managerdefault/audio_policy_conf.h
similarity index 100%
rename from services/audiopolicy/audio_policy_conf.h
rename to services/audiopolicy/managerdefault/audio_policy_conf.h
diff --git a/services/audiopolicy/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
similarity index 100%
rename from services/audiopolicy/AudioPolicyClientImpl.cpp
rename to services/audiopolicy/service/AudioPolicyClientImpl.cpp
diff --git a/services/audiopolicy/AudioPolicyClientImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyClientImplLegacy.cpp
similarity index 100%
rename from services/audiopolicy/AudioPolicyClientImplLegacy.cpp
rename to services/audiopolicy/service/AudioPolicyClientImplLegacy.cpp
diff --git a/services/audiopolicy/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
similarity index 100%
rename from services/audiopolicy/AudioPolicyEffects.cpp
rename to services/audiopolicy/service/AudioPolicyEffects.cpp
diff --git a/services/audiopolicy/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
similarity index 100%
rename from services/audiopolicy/AudioPolicyEffects.h
rename to services/audiopolicy/service/AudioPolicyEffects.h
diff --git a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
similarity index 98%
rename from services/audiopolicy/AudioPolicyInterfaceImpl.cpp
rename to services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index a45dbb3..e9ff8389 100644
--- a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -28,7 +28,8 @@
status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
- const char *device_address)
+ const char *device_address,
+ const char *device_name)
{
if (mAudioPolicyManager == NULL) {
return NO_INIT;
@@ -46,8 +47,8 @@
ALOGV("setDeviceConnectionState()");
Mutex::Autolock _l(mLock);
- return mAudioPolicyManager->setDeviceConnectionState(device,
- state, device_address);
+ return mAudioPolicyManager->setDeviceConnectionState(device, state,
+ device_address, device_name);
}
audio_policy_dev_state_t AudioPolicyService::getDeviceConnectionState(
diff --git a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
similarity index 99%
rename from services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
rename to services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
index b8846c6..5a91192 100644
--- a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
@@ -33,7 +33,8 @@
status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
- const char *device_address)
+ const char *device_address,
+ const char *device_name __unused)
{
if (mpAudioPolicy == NULL) {
return NO_INIT;
diff --git a/services/audiopolicy/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
similarity index 99%
rename from services/audiopolicy/AudioPolicyService.cpp
rename to services/audiopolicy/service/AudioPolicyService.cpp
index 0955e10..eb9116d 100644
--- a/services/audiopolicy/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -35,6 +35,7 @@
#include <hardware_legacy/power.h>
#include <media/AudioEffect.h>
#include <media/EffectsFactoryApi.h>
+#include <media/AudioParameter.h>
#include <hardware/hardware.h>
#include <system/audio.h>
@@ -160,7 +161,7 @@
mNotificationClients.add(uid, notificationClient);
- sp<IBinder> binder = client->asBinder();
+ sp<IBinder> binder = IInterface::asBinder(client);
binder->linkToDeath(notificationClient);
}
}
diff --git a/services/audiopolicy/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
similarity index 98%
rename from services/audiopolicy/AudioPolicyService.h
rename to services/audiopolicy/service/AudioPolicyService.h
index 09375cf..0378384 100644
--- a/services/audiopolicy/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -31,9 +31,11 @@
#include <media/ToneGenerator.h>
#include <media/AudioEffect.h>
#include <media/AudioPolicy.h>
+#ifdef USE_LEGACY_AUDIO_POLICY
#include <hardware_legacy/AudioPolicyInterface.h>
+#endif
#include "AudioPolicyEffects.h"
-#include "AudioPolicyManager.h"
+#include "managerdefault/AudioPolicyManager.h"
namespace android {
@@ -59,7 +61,8 @@
virtual status_t setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
- const char *device_address);
+ const char *device_address,
+ const char *device_name);
virtual audio_policy_dev_state_t getDeviceConnectionState(
audio_devices_t device,
const char *device_address);
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index e184d97..5d6423a 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -23,8 +23,10 @@
LOCAL_SRC_FILES:= \
CameraService.cpp \
CameraDeviceFactory.cpp \
+ CameraFlashlight.cpp \
common/Camera2ClientBase.cpp \
common/CameraDeviceBase.cpp \
+ common/CameraModule.cpp \
common/FrameProcessorBase.cpp \
api1/CameraClient.cpp \
api1/Camera2Client.cpp \
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp
new file mode 100644
index 0000000..7a79750
--- /dev/null
+++ b/services/camera/libcameraservice/CameraFlashlight.cpp
@@ -0,0 +1,875 @@
+/*
+ * 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 "CameraFlashlight"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+// #define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <cutils/properties.h>
+
+#include "camera/CameraMetadata.h"
+#include "CameraFlashlight.h"
+#include "gui/IGraphicBufferConsumer.h"
+#include "gui/BufferQueue.h"
+#include "camera/camera2/CaptureRequest.h"
+#include "CameraDeviceFactory.h"
+
+
+namespace android {
+
+/////////////////////////////////////////////////////////////////////
+// CameraFlashlight implementation begins
+// used by camera service to control flashflight.
+/////////////////////////////////////////////////////////////////////
+CameraFlashlight::CameraFlashlight(CameraModule& cameraModule,
+ const camera_module_callbacks_t& callbacks) :
+ mCameraModule(&cameraModule),
+ mCallbacks(&callbacks),
+ mFlashlightMapInitialized(false) {
+}
+
+CameraFlashlight::~CameraFlashlight() {
+}
+
+status_t CameraFlashlight::createFlashlightControl(const String8& cameraId) {
+ ALOGV("%s: creating a flash light control for camera %s", __FUNCTION__,
+ cameraId.string());
+ if (mFlashControl != NULL) {
+ return INVALID_OPERATION;
+ }
+
+ status_t res = OK;
+
+ if (mCameraModule->getRawModule()->module_api_version >=
+ CAMERA_MODULE_API_VERSION_2_4) {
+ mFlashControl = new ModuleFlashControl(*mCameraModule, *mCallbacks);
+ if (mFlashControl == NULL) {
+ ALOGV("%s: cannot create flash control for module api v2.4+",
+ __FUNCTION__);
+ return NO_MEMORY;
+ }
+ } else {
+ uint32_t deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
+
+ if (mCameraModule->getRawModule()->module_api_version >=
+ CAMERA_MODULE_API_VERSION_2_0) {
+ camera_info info;
+ res = mCameraModule->getCameraInfo(
+ atoi(String8(cameraId).string()), &info);
+ if (res) {
+ ALOGE("%s: failed to get camera info for camera %s",
+ __FUNCTION__, cameraId.string());
+ return res;
+ }
+ deviceVersion = info.device_version;
+ }
+
+ if (deviceVersion >= CAMERA_DEVICE_API_VERSION_2_0) {
+ CameraDeviceClientFlashControl *flashControl =
+ new CameraDeviceClientFlashControl(*mCameraModule,
+ *mCallbacks);
+ if (!flashControl) {
+ return NO_MEMORY;
+ }
+
+ mFlashControl = flashControl;
+ } else {
+ mFlashControl =
+ new CameraHardwareInterfaceFlashControl(*mCameraModule,
+ *mCallbacks);
+ }
+ }
+
+ return OK;
+}
+
+status_t CameraFlashlight::setTorchMode(const String8& cameraId, bool enabled) {
+ if (!mFlashlightMapInitialized) {
+ ALOGE("%s: findFlashUnits() must be called before this method.");
+ return NO_INIT;
+ }
+
+ ALOGV("%s: set torch mode of camera %s to %d", __FUNCTION__,
+ cameraId.string(), enabled);
+
+ status_t res = OK;
+ Mutex::Autolock l(mLock);
+
+ if (mFlashControl == NULL) {
+ if (enabled == false) {
+ return OK;
+ }
+
+ res = createFlashlightControl(cameraId);
+ if (res) {
+ return res;
+ }
+ res = mFlashControl->setTorchMode(cameraId, enabled);
+ return res;
+ }
+
+ // if flash control already exists, turning on torch mode may fail if it's
+ // tied to another camera device for module v2.3 and below.
+ res = mFlashControl->setTorchMode(cameraId, enabled);
+ if (res == BAD_INDEX) {
+ // flash control is tied to another camera device, need to close it and
+ // try again.
+ mFlashControl.clear();
+ res = createFlashlightControl(cameraId);
+ if (res) {
+ return res;
+ }
+ res = mFlashControl->setTorchMode(cameraId, enabled);
+ }
+
+ return res;
+}
+
+status_t CameraFlashlight::findFlashUnits() {
+ Mutex::Autolock l(mLock);
+ status_t res;
+ int32_t numCameras = mCameraModule->getNumberOfCameras();
+
+ mHasFlashlightMap.clear();
+ mFlashlightMapInitialized = false;
+
+ for (int32_t i = 0; i < numCameras; i++) {
+ bool hasFlash = false;
+ String8 id = String8::format("%d", i);
+
+ res = createFlashlightControl(id);
+ if (res) {
+ ALOGE("%s: failed to create flash control for %s", __FUNCTION__,
+ id.string());
+ } else {
+ res = mFlashControl->hasFlashUnit(id, &hasFlash);
+ if (res == -EUSERS || res == -EBUSY) {
+ ALOGE("%s: failed to check if camera %s has a flash unit. Some "
+ "camera devices may be opened", __FUNCTION__,
+ id.string());
+ return res;
+ } else if (res) {
+ ALOGE("%s: failed to check if camera %s has a flash unit. %s"
+ " (%d)", __FUNCTION__, id.string(), strerror(-res),
+ res);
+ }
+
+ mFlashControl.clear();
+ }
+ mHasFlashlightMap.add(id, hasFlash);
+ }
+
+ mFlashlightMapInitialized = true;
+ return OK;
+}
+
+bool CameraFlashlight::hasFlashUnit(const String8& cameraId) {
+ status_t res;
+
+ Mutex::Autolock l(mLock);
+ return hasFlashUnitLocked(cameraId);
+}
+
+bool CameraFlashlight::hasFlashUnitLocked(const String8& cameraId) {
+ if (!mFlashlightMapInitialized) {
+ ALOGE("%s: findFlashUnits() must be called before this method.");
+ return false;
+ }
+
+ ssize_t index = mHasFlashlightMap.indexOfKey(cameraId);
+ if (index == NAME_NOT_FOUND) {
+ ALOGE("%s: camera %s not present when findFlashUnits() was called",
+ __FUNCTION__, cameraId.string());
+ return false;
+ }
+
+ return mHasFlashlightMap.valueAt(index);
+}
+
+status_t CameraFlashlight::prepareDeviceOpen(const String8& cameraId) {
+ ALOGV("%s: prepare for device open", __FUNCTION__);
+
+ Mutex::Autolock l(mLock);
+ if (!mFlashlightMapInitialized) {
+ ALOGE("%s: findFlashUnits() must be called before this method.");
+ return NO_INIT;
+ }
+
+ if (mCameraModule->getRawModule()->module_api_version <
+ CAMERA_MODULE_API_VERSION_2_4) {
+ // framework is going to open a camera device, all flash light control
+ // should be closed for backward compatible support.
+ mFlashControl.clear();
+
+ if (mOpenedCameraIds.size() == 0) {
+ // notify torch unavailable for all cameras with a flash
+ int numCameras = mCameraModule->getNumberOfCameras();
+ for (int i = 0; i < numCameras; i++) {
+ if (hasFlashUnitLocked(String8::format("%d", i))) {
+ mCallbacks->torch_mode_status_change(mCallbacks,
+ String8::format("%d", i).string(),
+ TORCH_MODE_STATUS_NOT_AVAILABLE);
+ }
+ }
+ }
+
+ // close flash control that may be opened by calling hasFlashUnitLocked.
+ mFlashControl.clear();
+ }
+
+ if (mOpenedCameraIds.indexOf(cameraId) == NAME_NOT_FOUND) {
+ mOpenedCameraIds.add(cameraId);
+ }
+
+ return OK;
+}
+
+status_t CameraFlashlight::deviceClosed(const String8& cameraId) {
+ ALOGV("%s: device %s is closed", __FUNCTION__, cameraId.string());
+
+ Mutex::Autolock l(mLock);
+ if (!mFlashlightMapInitialized) {
+ ALOGE("%s: findFlashUnits() must be called before this method.");
+ return NO_INIT;
+ }
+
+ ssize_t index = mOpenedCameraIds.indexOf(cameraId);
+ if (index == NAME_NOT_FOUND) {
+ ALOGE("%s: couldn't find camera %s in the opened list", __FUNCTION__,
+ cameraId.string());
+ } else {
+ mOpenedCameraIds.removeAt(index);
+ }
+
+ // Cannot do anything until all cameras are closed.
+ if (mOpenedCameraIds.size() != 0)
+ return OK;
+
+ if (mCameraModule->getRawModule()->module_api_version <
+ CAMERA_MODULE_API_VERSION_2_4) {
+ // notify torch available for all cameras with a flash
+ int numCameras = mCameraModule->getNumberOfCameras();
+ for (int i = 0; i < numCameras; i++) {
+ if (hasFlashUnitLocked(String8::format("%d", i))) {
+ mCallbacks->torch_mode_status_change(mCallbacks,
+ String8::format("%d", i).string(),
+ TORCH_MODE_STATUS_AVAILABLE_OFF);
+ }
+ }
+ }
+
+ return OK;
+}
+// CameraFlashlight implementation ends
+
+
+FlashControlBase::~FlashControlBase() {
+}
+
+/////////////////////////////////////////////////////////////////////
+// ModuleFlashControl implementation begins
+// Flash control for camera module v2.4 and above.
+/////////////////////////////////////////////////////////////////////
+ModuleFlashControl::ModuleFlashControl(CameraModule& cameraModule,
+ const camera_module_callbacks_t& callbacks) :
+ mCameraModule(&cameraModule) {
+}
+
+ModuleFlashControl::~ModuleFlashControl() {
+}
+
+status_t ModuleFlashControl::hasFlashUnit(const String8& cameraId, bool *hasFlash) {
+ if (!hasFlash) {
+ return BAD_VALUE;
+ }
+
+ *hasFlash = false;
+ Mutex::Autolock l(mLock);
+
+ camera_info info;
+ status_t res = mCameraModule->getCameraInfo(atoi(cameraId.string()),
+ &info);
+ if (res != 0) {
+ return res;
+ }
+
+ CameraMetadata metadata;
+ metadata = info.static_camera_characteristics;
+ camera_metadata_entry flashAvailable =
+ metadata.find(ANDROID_FLASH_INFO_AVAILABLE);
+ if (flashAvailable.count == 1 && flashAvailable.data.u8[0] == 1) {
+ *hasFlash = true;
+ }
+
+ return OK;
+}
+
+status_t ModuleFlashControl::setTorchMode(const String8& cameraId, bool enabled) {
+ ALOGV("%s: set camera %s torch mode to %d", __FUNCTION__,
+ cameraId.string(), enabled);
+
+ Mutex::Autolock l(mLock);
+ return mCameraModule->setTorchMode(cameraId.string(), enabled);
+}
+// ModuleFlashControl implementation ends
+
+/////////////////////////////////////////////////////////////////////
+// CameraDeviceClientFlashControl implementation begins
+// Flash control for camera module <= v2.3 and camera HAL v2-v3
+/////////////////////////////////////////////////////////////////////
+CameraDeviceClientFlashControl::CameraDeviceClientFlashControl(
+ CameraModule& cameraModule,
+ const camera_module_callbacks_t& callbacks) :
+ mCameraModule(&cameraModule),
+ mCallbacks(&callbacks),
+ mTorchEnabled(false),
+ mMetadata(NULL),
+ mStreaming(false) {
+}
+
+CameraDeviceClientFlashControl::~CameraDeviceClientFlashControl() {
+ disconnectCameraDevice();
+ if (mMetadata) {
+ delete mMetadata;
+ }
+
+ mAnw.clear();
+ mSurfaceTexture.clear();
+ mProducer.clear();
+ mConsumer.clear();
+
+ if (mTorchEnabled) {
+ if (mCallbacks) {
+ ALOGV("%s: notify the framework that torch was turned off",
+ __FUNCTION__);
+ mCallbacks->torch_mode_status_change(mCallbacks,
+ mCameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
+ }
+ }
+}
+
+status_t CameraDeviceClientFlashControl::initializeSurface(
+ sp<CameraDeviceBase> &device, int32_t width, int32_t height) {
+ status_t res;
+ BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+
+ mSurfaceTexture = new GLConsumer(mConsumer, 0, GLConsumer::TEXTURE_EXTERNAL,
+ true, true);
+ if (mSurfaceTexture == NULL) {
+ return NO_MEMORY;
+ }
+
+ int32_t format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ res = mSurfaceTexture->setDefaultBufferSize(width, height);
+ if (res) {
+ return res;
+ }
+ res = mSurfaceTexture->setDefaultBufferFormat(format);
+ if (res) {
+ return res;
+ }
+
+ mAnw = new Surface(mProducer, /*useAsync*/ true);
+ if (mAnw == NULL) {
+ return NO_MEMORY;
+ }
+ res = device->createStream(mAnw, width, height, format,
+ HAL_DATASPACE_UNKNOWN, &mStreamId);
+ if (res) {
+ return res;
+ }
+
+ res = device->configureStreams();
+ if (res) {
+ return res;
+ }
+
+ return res;
+}
+
+status_t CameraDeviceClientFlashControl::getSmallestSurfaceSize(
+ const camera_info& info, int32_t *width, int32_t *height) {
+ if (!width || !height) {
+ return BAD_VALUE;
+ }
+
+ int32_t w = INT32_MAX;
+ int32_t h = 1;
+
+ CameraMetadata metadata;
+ metadata = info.static_camera_characteristics;
+ camera_metadata_entry streamConfigs =
+ metadata.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ for (size_t i = 0; i < streamConfigs.count; i += 4) {
+ int32_t fmt = streamConfigs.data.i32[i];
+ if (fmt == ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED) {
+ int32_t ww = streamConfigs.data.i32[i + 1];
+ int32_t hh = streamConfigs.data.i32[i + 2];
+
+ if (w * h > ww * hh) {
+ w = ww;
+ h = hh;
+ }
+ }
+ }
+
+ // if stream configuration is not found, try available processed sizes.
+ if (streamConfigs.count == 0) {
+ camera_metadata_entry availableProcessedSizes =
+ metadata.find(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES);
+ for (size_t i = 0; i < availableProcessedSizes.count; i += 2) {
+ int32_t ww = availableProcessedSizes.data.i32[i];
+ int32_t hh = availableProcessedSizes.data.i32[i + 1];
+ if (w * h > ww * hh) {
+ w = ww;
+ h = hh;
+ }
+ }
+ }
+
+ if (w == INT32_MAX) {
+ return NAME_NOT_FOUND;
+ }
+
+ *width = w;
+ *height = h;
+
+ return OK;
+}
+
+status_t CameraDeviceClientFlashControl::connectCameraDevice(
+ const String8& cameraId) {
+ camera_info info;
+ status_t res = mCameraModule->getCameraInfo(atoi(cameraId.string()), &info);
+ if (res != 0) {
+ ALOGE("%s: failed to get camera info for camera %s", __FUNCTION__,
+ cameraId.string());
+ return res;
+ }
+
+ sp<CameraDeviceBase> device =
+ CameraDeviceFactory::createDevice(atoi(cameraId.string()));
+ if (device == NULL) {
+ return NO_MEMORY;
+ }
+
+ res = device->initialize(mCameraModule);
+ if (res) {
+ return res;
+ }
+
+ int32_t width, height;
+ res = getSmallestSurfaceSize(info, &width, &height);
+ if (res) {
+ return res;
+ }
+ res = initializeSurface(device, width, height);
+ if (res) {
+ return res;
+ }
+
+ mCameraId = cameraId;
+ mStreaming = (info.device_version <= CAMERA_DEVICE_API_VERSION_3_1);
+ mDevice = device;
+
+ return OK;
+}
+
+status_t CameraDeviceClientFlashControl::disconnectCameraDevice() {
+ if (mDevice != NULL) {
+ mDevice->disconnect();
+ mDevice.clear();
+ }
+
+ return OK;
+}
+
+
+
+status_t CameraDeviceClientFlashControl::hasFlashUnit(const String8& cameraId,
+ bool *hasFlash) {
+ ALOGV("%s: checking if camera %s has a flash unit", __FUNCTION__,
+ cameraId.string());
+
+ Mutex::Autolock l(mLock);
+ return hasFlashUnitLocked(cameraId, hasFlash);
+
+}
+
+status_t CameraDeviceClientFlashControl::hasFlashUnitLocked(
+ const String8& cameraId, bool *hasFlash) {
+ if (!hasFlash) {
+ return BAD_VALUE;
+ }
+
+ camera_info info;
+ status_t res = mCameraModule->getCameraInfo(
+ atoi(cameraId.string()), &info);
+ if (res != 0) {
+ ALOGE("%s: failed to get camera info for camera %s", __FUNCTION__,
+ cameraId.string());
+ return res;
+ }
+
+ CameraMetadata metadata;
+ metadata = info.static_camera_characteristics;
+ camera_metadata_entry flashAvailable =
+ metadata.find(ANDROID_FLASH_INFO_AVAILABLE);
+ if (flashAvailable.count == 1 && flashAvailable.data.u8[0] == 1) {
+ *hasFlash = true;
+ }
+
+ return OK;
+}
+
+status_t CameraDeviceClientFlashControl::submitTorchEnabledRequest() {
+ status_t res;
+
+ if (mMetadata == NULL) {
+ mMetadata = new CameraMetadata();
+ if (mMetadata == NULL) {
+ return NO_MEMORY;
+ }
+ res = mDevice->createDefaultRequest(
+ CAMERA3_TEMPLATE_PREVIEW, mMetadata);
+ if (res) {
+ return res;
+ }
+ }
+
+ uint8_t torchOn = ANDROID_FLASH_MODE_TORCH;
+ mMetadata->update(ANDROID_FLASH_MODE, &torchOn, 1);
+ mMetadata->update(ANDROID_REQUEST_OUTPUT_STREAMS, &mStreamId, 1);
+
+ uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;
+ mMetadata->update(ANDROID_CONTROL_AE_MODE, &aeMode, 1);
+
+ int32_t requestId = 0;
+ mMetadata->update(ANDROID_REQUEST_ID, &requestId, 1);
+
+ if (mStreaming) {
+ res = mDevice->setStreamingRequest(*mMetadata);
+ } else {
+ res = mDevice->capture(*mMetadata);
+ }
+ return res;
+}
+
+
+
+
+status_t CameraDeviceClientFlashControl::setTorchMode(
+ const String8& cameraId, bool enabled) {
+ bool hasFlash = false;
+
+ Mutex::Autolock l(mLock);
+ status_t res = hasFlashUnitLocked(cameraId, &hasFlash);
+
+ // pre-check
+ if (enabled) {
+ // invalid camera?
+ if (res) {
+ return -EINVAL;
+ }
+ // no flash unit?
+ if (!hasFlash) {
+ return -ENOSYS;
+ }
+ // already opened for a different device?
+ if (mDevice != NULL && cameraId != mCameraId) {
+ return BAD_INDEX;
+ }
+ } else if (mDevice == NULL || cameraId != mCameraId) {
+ // disabling the torch mode of an un-opened or different device.
+ return OK;
+ } else {
+ // disabling the torch mode of currently opened device
+ disconnectCameraDevice();
+ mTorchEnabled = false;
+ mCallbacks->torch_mode_status_change(mCallbacks,
+ cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
+ return OK;
+ }
+
+ if (mDevice == NULL) {
+ res = connectCameraDevice(cameraId);
+ if (res) {
+ return res;
+ }
+ }
+
+ res = submitTorchEnabledRequest();
+ if (res) {
+ return res;
+ }
+
+ mTorchEnabled = true;
+ mCallbacks->torch_mode_status_change(mCallbacks,
+ cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_ON);
+ return OK;
+}
+// CameraDeviceClientFlashControl implementation ends
+
+
+/////////////////////////////////////////////////////////////////////
+// CameraHardwareInterfaceFlashControl implementation begins
+// Flash control for camera module <= v2.3 and camera HAL v1
+/////////////////////////////////////////////////////////////////////
+CameraHardwareInterfaceFlashControl::CameraHardwareInterfaceFlashControl(
+ CameraModule& cameraModule,
+ const camera_module_callbacks_t& callbacks) :
+ mCameraModule(&cameraModule),
+ mCallbacks(&callbacks),
+ mTorchEnabled(false) {
+
+}
+
+CameraHardwareInterfaceFlashControl::~CameraHardwareInterfaceFlashControl() {
+ disconnectCameraDevice();
+
+ mAnw.clear();
+ mSurfaceTexture.clear();
+ mProducer.clear();
+ mConsumer.clear();
+
+ if (mTorchEnabled) {
+ if (mCallbacks) {
+ ALOGV("%s: notify the framework that torch was turned off",
+ __FUNCTION__);
+ mCallbacks->torch_mode_status_change(mCallbacks,
+ mCameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
+ }
+ }
+}
+
+status_t CameraHardwareInterfaceFlashControl::setTorchMode(
+ const String8& cameraId, bool enabled) {
+ Mutex::Autolock l(mLock);
+
+ // pre-check
+ status_t res;
+ if (enabled) {
+ bool hasFlash = false;
+ res = hasFlashUnitLocked(cameraId, &hasFlash);
+ // invalid camera?
+ if (res) {
+ // hasFlashUnitLocked() returns BAD_INDEX if mDevice is connected to
+ // another camera device.
+ return res == BAD_INDEX ? BAD_INDEX : -EINVAL;
+ }
+ // no flash unit?
+ if (!hasFlash) {
+ return -ENOSYS;
+ }
+ } else if (mDevice == NULL || cameraId != mCameraId) {
+ // disabling the torch mode of an un-opened or different device.
+ return OK;
+ } else {
+ // disabling the torch mode of currently opened device
+ disconnectCameraDevice();
+ mTorchEnabled = false;
+ mCallbacks->torch_mode_status_change(mCallbacks,
+ cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
+ return OK;
+ }
+
+ res = startPreviewAndTorch();
+ if (res) {
+ return res;
+ }
+
+ mTorchEnabled = true;
+ mCallbacks->torch_mode_status_change(mCallbacks,
+ cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_ON);
+ return OK;
+}
+
+status_t CameraHardwareInterfaceFlashControl::hasFlashUnit(
+ const String8& cameraId, bool *hasFlash) {
+ Mutex::Autolock l(mLock);
+ return hasFlashUnitLocked(cameraId, hasFlash);
+}
+
+status_t CameraHardwareInterfaceFlashControl::hasFlashUnitLocked(
+ const String8& cameraId, bool *hasFlash) {
+ if (!hasFlash) {
+ return BAD_VALUE;
+ }
+
+ status_t res;
+ if (mDevice == NULL) {
+ res = connectCameraDevice(cameraId);
+ if (res) {
+ return res;
+ }
+ }
+
+ if (cameraId != mCameraId) {
+ return BAD_INDEX;
+ }
+
+ const char *flashMode =
+ mParameters.get(CameraParameters::KEY_SUPPORTED_FLASH_MODES);
+ if (flashMode && strstr(flashMode, CameraParameters::FLASH_MODE_TORCH)) {
+ *hasFlash = true;
+ } else {
+ *hasFlash = false;
+ }
+
+ return OK;
+}
+
+status_t CameraHardwareInterfaceFlashControl::startPreviewAndTorch() {
+ status_t res = OK;
+ res = mDevice->startPreview();
+ if (res) {
+ ALOGE("%s: start preview failed. %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ return res;
+ }
+
+ mParameters.set(CameraParameters::KEY_FLASH_MODE,
+ CameraParameters::FLASH_MODE_TORCH);
+
+ return mDevice->setParameters(mParameters);
+}
+
+status_t CameraHardwareInterfaceFlashControl::getSmallestSurfaceSize(
+ int32_t *width, int32_t *height) {
+ if (!width || !height) {
+ return BAD_VALUE;
+ }
+
+ int32_t w = INT32_MAX;
+ int32_t h = 1;
+ Vector<Size> sizes;
+
+ mParameters.getSupportedPreviewSizes(sizes);
+ for (size_t i = 0; i < sizes.size(); i++) {
+ Size s = sizes[i];
+ if (w * h > s.width * s.height) {
+ w = s.width;
+ h = s.height;
+ }
+ }
+
+ if (w == INT32_MAX) {
+ return NAME_NOT_FOUND;
+ }
+
+ *width = w;
+ *height = h;
+
+ return OK;
+}
+
+status_t CameraHardwareInterfaceFlashControl::initializePreviewWindow(
+ sp<CameraHardwareInterface> device, int32_t width, int32_t height) {
+ status_t res;
+ BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+
+ mSurfaceTexture = new GLConsumer(mConsumer, 0, GLConsumer::TEXTURE_EXTERNAL,
+ true, true);
+ if (mSurfaceTexture == NULL) {
+ return NO_MEMORY;
+ }
+
+ int32_t format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ res = mSurfaceTexture->setDefaultBufferSize(width, height);
+ if (res) {
+ return res;
+ }
+ res = mSurfaceTexture->setDefaultBufferFormat(format);
+ if (res) {
+ return res;
+ }
+
+ mAnw = new Surface(mProducer, /*useAsync*/ true);
+ if (mAnw == NULL) {
+ return NO_MEMORY;
+ }
+
+ res = native_window_api_connect(mAnw.get(), NATIVE_WINDOW_API_CAMERA);
+ if (res) {
+ ALOGE("%s: Unable to connect to native window", __FUNCTION__);
+ return res;
+ }
+
+ return device->setPreviewWindow(mAnw);
+}
+
+status_t CameraHardwareInterfaceFlashControl::connectCameraDevice(
+ const String8& cameraId) {
+ sp<CameraHardwareInterface> device =
+ new CameraHardwareInterface(cameraId.string());
+
+ status_t res = device->initialize(mCameraModule);
+ if (res) {
+ ALOGE("%s: initializing camera %s failed", __FUNCTION__,
+ cameraId.string());
+ return res;
+ }
+
+ // need to set __get_memory in set_callbacks().
+ device->setCallbacks(NULL, NULL, NULL, NULL);
+
+ mParameters = device->getParameters();
+
+ int32_t width, height;
+ res = getSmallestSurfaceSize(&width, &height);
+ if (res) {
+ ALOGE("%s: failed to get smallest surface size for camera %s",
+ __FUNCTION__, cameraId.string());
+ return res;
+ }
+
+ res = initializePreviewWindow(device, width, height);
+ if (res) {
+ ALOGE("%s: failed to initialize preview window for camera %s",
+ __FUNCTION__, cameraId.string());
+ return res;
+ }
+
+ mCameraId = cameraId;
+ mDevice = device;
+ return OK;
+}
+
+status_t CameraHardwareInterfaceFlashControl::disconnectCameraDevice() {
+ if (mDevice == NULL) {
+ return OK;
+ }
+
+ mParameters.set(CameraParameters::KEY_FLASH_MODE,
+ CameraParameters::FLASH_MODE_OFF);
+ mDevice->setParameters(mParameters);
+ mDevice->stopPreview();
+ status_t res = native_window_api_disconnect(mAnw.get(),
+ NATIVE_WINDOW_API_CAMERA);
+ if (res) {
+ ALOGW("%s: native_window_api_disconnect failed: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
+ mDevice->setPreviewWindow(NULL);
+ mDevice->release();
+
+ return OK;
+}
+// CameraHardwareInterfaceFlashControl implementation ends
+
+}
diff --git a/services/camera/libcameraservice/CameraFlashlight.h b/services/camera/libcameraservice/CameraFlashlight.h
new file mode 100644
index 0000000..30f01f0
--- /dev/null
+++ b/services/camera/libcameraservice/CameraFlashlight.h
@@ -0,0 +1,225 @@
+/*
+ * 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_SERVERS_CAMERA_CAMERAFLASHLIGHT_H
+#define ANDROID_SERVERS_CAMERA_CAMERAFLASHLIGHT_H
+
+#include "hardware/camera_common.h"
+#include "utils/KeyedVector.h"
+#include "utils/SortedVector.h"
+#include "gui/GLConsumer.h"
+#include "gui/Surface.h"
+#include "common/CameraDeviceBase.h"
+#include "device1/CameraHardwareInterface.h"
+
+namespace android {
+
+/**
+ * FlashControlBase is a base class for flash control. It defines the functions
+ * that a flash control for each camera module/device version should implement.
+ */
+class FlashControlBase : public virtual VirtualLightRefBase {
+ public:
+ virtual ~FlashControlBase();
+
+ // Whether a camera device has a flash unit. Calling this function may
+ // cause the torch mode to be turned off in HAL v1 devices. If
+ // previously-on torch mode is turned off,
+ // callbacks.torch_mode_status_change() should be invoked.
+ virtual status_t hasFlashUnit(const String8& cameraId,
+ bool *hasFlash) = 0;
+
+ // set the torch mode to on or off.
+ virtual status_t setTorchMode(const String8& cameraId,
+ bool enabled) = 0;
+};
+
+/**
+ * CameraFlashlight can be used by camera service to control flashflight.
+ */
+class CameraFlashlight : public virtual VirtualLightRefBase {
+ public:
+ CameraFlashlight(CameraModule& cameraModule,
+ const camera_module_callbacks_t& callbacks);
+ virtual ~CameraFlashlight();
+
+ // Find all flash units. This must be called before other methods. All
+ // camera devices must be closed when it's called because HAL v1 devices
+ // need to be opened to query available flash modes.
+ status_t findFlashUnits();
+
+ // Whether a camera device has a flash unit. Before findFlashUnits() is
+ // called, this function always returns false.
+ bool hasFlashUnit(const String8& cameraId);
+
+ // set the torch mode to on or off.
+ status_t setTorchMode(const String8& cameraId, bool enabled);
+
+ // Notify CameraFlashlight that camera service is going to open a camera
+ // device. CameraFlashlight will free the resources that may cause the
+ // camera open to fail. Camera service must call this function before
+ // opening a camera device.
+ status_t prepareDeviceOpen(const String8& cameraId);
+
+ // Notify CameraFlashlight that camera service has closed a camera
+ // device. CameraFlashlight may invoke callbacks for torch mode
+ // available depending on the implementation.
+ status_t deviceClosed(const String8& cameraId);
+
+ private:
+ // create flashlight control based on camera module API and camera
+ // device API versions.
+ status_t createFlashlightControl(const String8& cameraId);
+
+ // mLock should be locked.
+ bool hasFlashUnitLocked(const String8& cameraId);
+
+ sp<FlashControlBase> mFlashControl;
+ CameraModule *mCameraModule;
+ const camera_module_callbacks_t *mCallbacks;
+ SortedVector<String8> mOpenedCameraIds;
+
+ // camera id -> if it has a flash unit
+ KeyedVector<String8, bool> mHasFlashlightMap;
+ bool mFlashlightMapInitialized;
+
+ Mutex mLock; // protect CameraFlashlight API
+};
+
+/**
+ * Flash control for camera module v2.4 and above.
+ */
+class ModuleFlashControl : public FlashControlBase {
+ public:
+ ModuleFlashControl(CameraModule& cameraModule,
+ const camera_module_callbacks_t& callbacks);
+ virtual ~ModuleFlashControl();
+
+ // FlashControlBase
+ status_t hasFlashUnit(const String8& cameraId, bool *hasFlash);
+ status_t setTorchMode(const String8& cameraId, bool enabled);
+
+ private:
+ CameraModule *mCameraModule;
+
+ Mutex mLock;
+};
+
+/**
+ * Flash control for camera module <= v2.3 and camera HAL v2-v3
+ */
+class CameraDeviceClientFlashControl : public FlashControlBase {
+ public:
+ CameraDeviceClientFlashControl(CameraModule& cameraModule,
+ const camera_module_callbacks_t& callbacks);
+ virtual ~CameraDeviceClientFlashControl();
+
+ // FlashControlBase
+ status_t setTorchMode(const String8& cameraId, bool enabled);
+ status_t hasFlashUnit(const String8& cameraId, bool *hasFlash);
+
+ private:
+ // connect to a camera device
+ status_t connectCameraDevice(const String8& cameraId);
+ // disconnect and free mDevice
+ status_t disconnectCameraDevice();
+
+ // initialize a surface
+ status_t initializeSurface(sp<CameraDeviceBase>& device, int32_t width,
+ int32_t height);
+
+ // submit a request to enable the torch mode
+ status_t submitTorchEnabledRequest();
+
+ // get the smallest surface size of IMPLEMENTATION_DEFINED
+ status_t getSmallestSurfaceSize(const camera_info& info, int32_t *width,
+ int32_t *height);
+
+ // protected by mLock
+ status_t hasFlashUnitLocked(const String8& cameraId, bool *hasFlash);
+
+ CameraModule *mCameraModule;
+ const camera_module_callbacks_t *mCallbacks;
+ String8 mCameraId;
+ bool mTorchEnabled;
+ CameraMetadata *mMetadata;
+ // WORKAROUND: will be set to true for HAL v2 devices where
+ // setStreamingRequest() needs to be call for torch mode settings to
+ // take effect.
+ bool mStreaming;
+
+ sp<CameraDeviceBase> mDevice;
+
+ sp<IGraphicBufferProducer> mProducer;
+ sp<IGraphicBufferConsumer> mConsumer;
+ sp<GLConsumer> mSurfaceTexture;
+ sp<ANativeWindow> mAnw;
+ int32_t mStreamId;
+
+ Mutex mLock;
+};
+
+/**
+ * Flash control for camera module <= v2.3 and camera HAL v1
+ */
+class CameraHardwareInterfaceFlashControl : public FlashControlBase {
+ public:
+ CameraHardwareInterfaceFlashControl(CameraModule& cameraModule,
+ const camera_module_callbacks_t& callbacks);
+ virtual ~CameraHardwareInterfaceFlashControl();
+
+ // FlashControlBase
+ status_t setTorchMode(const String8& cameraId, bool enabled);
+ status_t hasFlashUnit(const String8& cameraId, bool *hasFlash);
+
+ private:
+ // connect to a camera device
+ status_t connectCameraDevice(const String8& cameraId);
+
+ // disconnect and free mDevice
+ status_t disconnectCameraDevice();
+
+ // initialize the preview window
+ status_t initializePreviewWindow(sp<CameraHardwareInterface> device,
+ int32_t width, int32_t height);
+
+ // start preview and enable torch
+ status_t startPreviewAndTorch();
+
+ // get the smallest surface
+ status_t getSmallestSurfaceSize(int32_t *width, int32_t *height);
+
+ // protected by mLock
+ status_t hasFlashUnitLocked(const String8& cameraId, bool *hasFlash);
+
+ CameraModule *mCameraModule;
+ const camera_module_callbacks_t *mCallbacks;
+ sp<CameraHardwareInterface> mDevice;
+ String8 mCameraId;
+ CameraParameters mParameters;
+ bool mTorchEnabled;
+
+ sp<IGraphicBufferProducer> mProducer;
+ sp<IGraphicBufferConsumer> mConsumer;
+ sp<GLConsumer> mSurfaceTexture;
+ sp<ANativeWindow> mAnw;
+
+ Mutex mLock;
+};
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 76428da..6f37f16 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -29,6 +29,7 @@
#include <binder/MemoryHeapBase.h>
#include <cutils/atomic.h>
#include <cutils/properties.h>
+#include <cutils/multiuser.h>
#include <gui/Surface.h>
#include <hardware/hardware.h>
#include <media/AudioSystem.h>
@@ -86,6 +87,38 @@
camera_id,
new_status);
}
+
+static void torch_mode_status_change(
+ const struct camera_module_callbacks* callbacks,
+ const char* camera_id,
+ int new_status) {
+ if (!callbacks || !camera_id) {
+ ALOGE("%s invalid parameters. callbacks %p, camera_id %p", __FUNCTION__,
+ callbacks, camera_id);
+ }
+ sp<CameraService> cs = const_cast<CameraService*>(
+ static_cast<const CameraService*>(callbacks));
+
+ ICameraServiceListener::TorchStatus status;
+ switch (new_status) {
+ case TORCH_MODE_STATUS_NOT_AVAILABLE:
+ status = ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE;
+ break;
+ case TORCH_MODE_STATUS_AVAILABLE_OFF:
+ status = ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF;
+ break;
+ case TORCH_MODE_STATUS_AVAILABLE_ON:
+ status = ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON;
+ break;
+ default:
+ ALOGE("Unknown torch status %d", new_status);
+ return;
+ }
+
+ cs->onTorchStatusChanged(
+ String8(camera_id),
+ status);
+}
} // extern "C"
// ----------------------------------------------------------------------------
@@ -95,7 +128,7 @@
static CameraService *gCameraService;
CameraService::CameraService()
- :mSoundRef(0), mModule(0)
+ :mSoundRef(0), mModule(0), mFlashlight(0)
{
ALOGI("CameraService started (pid=%d)", getpid());
gCameraService = this;
@@ -105,6 +138,8 @@
}
this->camera_device_status_change = android::camera_device_status_change;
+ this->torch_mode_status_change = android::torch_mode_status_change;
+
}
void CameraService::onFirstRef()
@@ -113,31 +148,47 @@
BnCameraService::onFirstRef();
+ camera_module_t *rawModule;
if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
- (const hw_module_t **)&mModule) < 0) {
+ (const hw_module_t **)&rawModule) < 0) {
ALOGE("Could not load camera HAL module");
mNumberOfCameras = 0;
}
else {
- ALOGI("Loaded \"%s\" camera module", mModule->common.name);
- mNumberOfCameras = mModule->get_number_of_cameras();
+ mModule = new CameraModule(rawModule);
+ const hw_module_t *common = mModule->getRawModule();
+ ALOGI("Loaded \"%s\" cameraCa module", common->name);
+ mNumberOfCameras = mModule->getNumberOfCameras();
if (mNumberOfCameras > MAX_CAMERAS) {
ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
mNumberOfCameras, MAX_CAMERAS);
mNumberOfCameras = MAX_CAMERAS;
}
- for (int i = 0; i < mNumberOfCameras; i++) {
- setCameraFree(i);
+
+ mFlashlight = new CameraFlashlight(*mModule, *this);
+ status_t res = mFlashlight->findFlashUnits();
+ if (res) {
+ // impossible because we haven't open any camera devices.
+ ALOGE("failed to find flash units.");
}
- if (mModule->common.module_api_version >=
- CAMERA_MODULE_API_VERSION_2_1) {
- mModule->set_callbacks(this);
+ for (int i = 0; i < mNumberOfCameras; i++) {
+ setCameraFree(i);
+
+ String8 cameraName = String8::format("%d", i);
+ if (mFlashlight->hasFlashUnit(cameraName)) {
+ mTorchStatusMap.add(cameraName,
+ ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF);
+ }
+ }
+
+ if (common->module_api_version >= CAMERA_MODULE_API_VERSION_2_1) {
+ mModule->setCallbacks(this);
}
VendorTagDescriptor::clearGlobalVendorTagDescriptor();
- if (mModule->common.module_api_version >= CAMERA_MODULE_API_VERSION_2_2) {
+ if (common->module_api_version >= CAMERA_MODULE_API_VERSION_2_2) {
setUpVendorTags();
}
@@ -152,6 +203,9 @@
}
}
+ if (mModule) {
+ delete mModule;
+ }
VendorTagDescriptor::clearGlobalVendorTagDescriptor();
gCameraService = NULL;
}
@@ -159,7 +213,7 @@
void CameraService::onDeviceStatusChanged(int cameraId,
int newStatus)
{
- ALOGI("%s: Status changed for cameraId=%d, newStatus=%d", __FUNCTION__,
+ ALOGV("%s: Status changed for cameraId=%d, newStatus=%d", __FUNCTION__,
cameraId, newStatus);
if (cameraId < 0 || cameraId >= MAX_CAMERAS) {
@@ -220,6 +274,43 @@
}
+void CameraService::onTorchStatusChanged(const String8& cameraId,
+ ICameraServiceListener::TorchStatus newStatus) {
+ Mutex::Autolock al(mTorchStatusMutex);
+ onTorchStatusChangedLocked(cameraId, newStatus);
+}
+
+void CameraService::onTorchStatusChangedLocked(const String8& cameraId,
+ ICameraServiceListener::TorchStatus newStatus) {
+ ALOGI("%s: Torch status changed for cameraId=%s, newStatus=%d",
+ __FUNCTION__, cameraId.string(), newStatus);
+
+ ICameraServiceListener::TorchStatus status;
+ status_t res = getTorchStatusLocked(cameraId, &status);
+ if (res) {
+ ALOGE("%s: cannot get torch status of camera %s", cameraId.string());
+ return;
+ }
+ if (status == newStatus) {
+ ALOGE("%s: Torch state transition to the same status 0x%x not allowed",
+ __FUNCTION__, (uint32_t)newStatus);
+ return;
+ }
+
+ res = setTorchStatusLocked(cameraId, newStatus);
+ if (res) {
+ ALOGE("%s: Failed to set the torch status", __FUNCTION__,
+ (uint32_t)newStatus);
+ return;
+ }
+
+ Vector<sp<ICameraServiceListener> >::const_iterator it;
+ for (it = mListenerList.begin(); it != mListenerList.end(); ++it) {
+ (*it)->onTorchStatusChanged(newStatus, String16(cameraId.string()));
+ }
+}
+
+
int32_t CameraService::getNumberOfCameras() {
return mNumberOfCameras;
}
@@ -236,7 +327,7 @@
struct camera_info info;
status_t rc = filterGetInfoErrorCode(
- mModule->get_camera_info(cameraId, &info));
+ mModule->getCameraInfo(cameraId, &info));
cameraInfo->facing = info.facing;
cameraInfo->orientation = info.orientation;
return rc;
@@ -347,7 +438,7 @@
int facing;
status_t ret = OK;
- if (mModule->common.module_api_version < CAMERA_MODULE_API_VERSION_2_0 ||
+ if (mModule->getRawModule()->module_api_version < CAMERA_MODULE_API_VERSION_2_0 ||
getDeviceVersion(cameraId, &facing) <= CAMERA_DEVICE_API_VERSION_2_1 ) {
/**
* Backwards compatibility mode for old HALs:
@@ -368,7 +459,7 @@
* Normal HAL 2.1+ codepath.
*/
struct camera_info info;
- ret = filterGetInfoErrorCode(mModule->get_camera_info(cameraId, &info));
+ ret = filterGetInfoErrorCode(mModule->getCameraInfo(cameraId, &info));
*cameraInfo = info.static_camera_characteristics;
}
@@ -387,12 +478,12 @@
int CameraService::getDeviceVersion(int cameraId, int* facing) {
struct camera_info info;
- if (mModule->get_camera_info(cameraId, &info) != OK) {
+ if (mModule->getCameraInfo(cameraId, &info) != OK) {
return -1;
}
int deviceVersion;
- if (mModule->common.module_api_version >= CAMERA_MODULE_API_VERSION_2_0) {
+ if (mModule->getRawModule()->module_api_version >= CAMERA_MODULE_API_VERSION_2_0) {
deviceVersion = info.device_version;
} else {
deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
@@ -405,19 +496,6 @@
return deviceVersion;
}
-status_t CameraService::filterOpenErrorCode(status_t err) {
- switch(err) {
- case NO_ERROR:
- case -EBUSY:
- case -EINVAL:
- case -EUSERS:
- return err;
- default:
- break;
- }
- return -ENODEV;
-}
-
status_t CameraService::filterGetInfoErrorCode(status_t err) {
switch(err) {
case NO_ERROR:
@@ -433,13 +511,13 @@
vendor_tag_ops_t vOps = vendor_tag_ops_t();
// Check if vendor operations have been implemented
- if (mModule->get_vendor_tag_ops == NULL) {
+ if (!mModule->isVendorTagDefined()) {
ALOGI("%s: No vendor tags defined for this device.", __FUNCTION__);
return false;
}
ATRACE_BEGIN("camera3->get_metadata_vendor_tag_ops");
- mModule->get_vendor_tag_ops(&vOps);
+ mModule->getVendorTagOps(&vOps);
ATRACE_END();
// Ensure all vendor operations are present
@@ -592,7 +670,10 @@
}
char value[PROPERTY_VALUE_MAX];
- property_get("sys.secpolicy.camera.disabled", value, "0");
+ char key[PROPERTY_KEY_MAX];
+ int 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.
ALOGI("Camera is disabled. connect X (pid %d) rejected", callingPid);
@@ -671,6 +752,9 @@
int halVersion,
bool legacyMode) {
+ // give flashlight a chance to close devices if necessary.
+ mFlashlight->prepareDeviceOpen(String8::format("%d", cameraId));
+
int facing = -1;
int deviceVersion = getDeviceVersion(cameraId, &facing);
@@ -755,7 +839,7 @@
Mutex::Autolock lock(mServiceLock);
sp<BasicClient> clientTmp;
if (!canConnectUnsafe(cameraId, clientPackageName,
- cameraClient->asBinder(),
+ IInterface::asBinder(cameraClient),
/*out*/clientTmp)) {
return -EBUSY;
} else if (client.get() != NULL) {
@@ -789,8 +873,9 @@
/*out*/
sp<ICamera>& device) {
+ int apiVersion = mModule->getRawModule()->module_api_version;
if (halVersion != CAMERA_HAL_API_VERSION_UNSPECIFIED &&
- mModule->common.module_api_version < CAMERA_MODULE_API_VERSION_2_3) {
+ apiVersion < CAMERA_MODULE_API_VERSION_2_3) {
/*
* Either the HAL version is unspecified in which case this just creates
* a camera client selected by the latest device version, or
@@ -798,7 +883,7 @@
* the open_legacy call
*/
ALOGE("%s: camera HAL module version %x doesn't support connecting to legacy HAL devices!",
- __FUNCTION__, mModule->common.module_api_version);
+ __FUNCTION__, apiVersion);
return INVALID_OPERATION;
}
@@ -818,7 +903,7 @@
Mutex::Autolock lock(mServiceLock);
sp<BasicClient> clientTmp;
if (!canConnectUnsafe(cameraId, clientPackageName,
- cameraClient->asBinder(),
+ IInterface::asBinder(cameraClient),
/*out*/clientTmp)) {
return -EBUSY;
} else if (client.get() != NULL) {
@@ -846,6 +931,97 @@
return OK;
}
+bool CameraService::validCameraIdForSetTorchMode(const String8& cameraId) {
+ // invalid string for int
+ if (cameraId.string() == NULL) {
+ return false;
+ }
+ errno = 0;
+ char *endptr;
+ long id = strtol(cameraId.string(), &endptr, 10); // base 10
+ if (errno || id > INT_MAX || id < INT_MIN || *endptr != 0) {
+ return false;
+ }
+
+ // id matches one of the plugged-in devices?
+ ICameraServiceListener::Status deviceStatus = getStatus(id);
+ if (deviceStatus != ICameraServiceListener::STATUS_PRESENT &&
+ deviceStatus != ICameraServiceListener::STATUS_NOT_AVAILABLE) {
+ return false;
+ }
+
+ return true;
+}
+
+status_t CameraService::setTorchMode(const String16& cameraId, bool enabled,
+ const sp<IBinder>& clientBinder) {
+ if (enabled && clientBinder == NULL) {
+ ALOGE("%s: torch client binder is NULL", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ String8 id = String8(cameraId.string());
+
+ // verify id is valid.
+ if (validCameraIdForSetTorchMode(id) == false) {
+ ALOGE("%s: camera id is invalid %s", id.string());
+ return -EINVAL;
+ }
+
+ {
+ Mutex::Autolock al(mTorchStatusMutex);
+ ICameraServiceListener::TorchStatus status;
+ status_t res = getTorchStatusLocked(id, &status);
+ if (res) {
+ ALOGE("%s: getting current torch status failed for camera %s",
+ __FUNCTION__, id.string());
+ return -EINVAL;
+ }
+
+ if (status == ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE) {
+ if (getStatus(atoi(id.string())) ==
+ ICameraServiceListener::STATUS_NOT_AVAILABLE) {
+ ALOGE("%s: torch mode of camera %s is not available because "
+ "camera is in use", __FUNCTION__, id.string());
+ return -EBUSY;
+ } else {
+ ALOGE("%s: torch mode of camera %s is not available due to "
+ "insufficient resources", __FUNCTION__, id.string());
+ return -EUSERS;
+ }
+ }
+ }
+
+ status_t res = mFlashlight->setTorchMode(id, enabled);
+ if (res) {
+ ALOGE("%s: setting torch mode of camera %s to %d failed. %s (%d)",
+ __FUNCTION__, id.string(), enabled, strerror(-res), res);
+ return res;
+ }
+
+ {
+ // update the link to client's death
+ Mutex::Autolock al(mTorchClientMapMutex);
+ ssize_t index = mTorchClientMap.indexOfKey(id);
+ if (enabled) {
+ if (index == NAME_NOT_FOUND) {
+ mTorchClientMap.add(id, clientBinder);
+ } else {
+ const sp<IBinder> oldBinder = mTorchClientMap.valueAt(index);
+ oldBinder->unlinkToDeath(this);
+
+ mTorchClientMap.replaceValueAt(index, clientBinder);
+ }
+ clientBinder->linkToDeath(this);
+ } else if (index != NAME_NOT_FOUND) {
+ sp<IBinder> oldBinder = mTorchClientMap.valueAt(index);
+ oldBinder->unlinkToDeath(this);
+ }
+ }
+
+ return OK;
+}
+
status_t CameraService::connectFinishUnsafe(const sp<BasicClient>& client,
const sp<IBinder>& remoteCallback) {
status_t status = client->initialize(mModule);
@@ -889,7 +1065,7 @@
{
sp<BasicClient> client;
if (!canConnectUnsafe(cameraId, clientPackageName,
- cameraCb->asBinder(),
+ IInterface::asBinder(cameraCb),
/*out*/client)) {
return -EBUSY;
}
@@ -962,7 +1138,7 @@
{
sp<BasicClient> client;
if (!canConnectUnsafe(cameraId, clientPackageName,
- cameraCb->asBinder(),
+ IInterface::asBinder(cameraCb),
/*out*/client)) {
return -EBUSY;
}
@@ -971,6 +1147,9 @@
int facing = -1;
int deviceVersion = getDeviceVersion(cameraId, &facing);
+ // give flashlight a chance to close devices if necessary.
+ mFlashlight->prepareDeviceOpen(String8::format("%d", cameraId));
+
switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
ALOGW("Camera using old HAL version: %d", deviceVersion);
@@ -1024,7 +1203,7 @@
Vector<sp<ICameraServiceListener> >::iterator it, end;
for (it = mListenerList.begin(); it != mListenerList.end(); ++it) {
- if ((*it)->asBinder() == listener->asBinder()) {
+ if (IInterface::asBinder(*it) == IInterface::asBinder(listener)) {
ALOGW("%s: Tried to add listener %p which was already subscribed",
__FUNCTION__, listener.get());
return ALREADY_EXISTS;
@@ -1042,6 +1221,16 @@
}
}
+ /* Immediately signal current torch status to this listener only */
+ {
+ Mutex::Autolock al(mTorchStatusMutex);
+ for (size_t i = 0; i < mTorchStatusMap.size(); i++ ) {
+ String16 id = String16(mTorchStatusMap.keyAt(i).string());
+ listener->onTorchStatusChanged(mTorchStatusMap.valueAt(i), id);
+ }
+
+ }
+
return OK;
}
status_t CameraService::removeListener(
@@ -1057,7 +1246,7 @@
Vector<sp<ICameraServiceListener> >::iterator it;
for (it = mListenerList.begin(); it != mListenerList.end(); ++it) {
- if ((*it)->asBinder() == listener->asBinder()) {
+ if (IInterface::asBinder(*it) == IInterface::asBinder(listener)) {
mListenerList.erase(it);
return OK;
}
@@ -1170,7 +1359,7 @@
// Found our camera, clear and leave.
LOG1("removeClient: clear pro %p", clientPro.get());
- clientPro->getRemoteCallback()->asBinder()->unlinkToDeath(this);
+ IInterface::asBinder(clientPro->getRemoteCallback())->unlinkToDeath(this);
}
}
@@ -1364,7 +1553,8 @@
int cameraId, int cameraFacing,
int clientPid, uid_t clientUid,
int servicePid) :
- CameraService::BasicClient(cameraService, cameraClient->asBinder(),
+ CameraService::BasicClient(cameraService,
+ IInterface::asBinder(cameraClient),
clientPackageName,
cameraId, cameraFacing,
clientPid, clientUid,
@@ -1475,9 +1665,14 @@
mCameraId,
&rejectSourceStates);
+ // Notify flashlight that a camera device is closed.
+ mCameraService->mFlashlight->deviceClosed(
+ String8::format("%d", mCameraId));
}
// Always stop watching, even if no camera op is active
- mAppOpsManager.stopWatchingMode(mOpsCallback);
+ if (mOpsCallback != NULL) {
+ mAppOpsManager.stopWatchingMode(mOpsCallback);
+ }
mOpsCallback.clear();
return OK;
@@ -1573,7 +1768,7 @@
int clientPid,
uid_t clientUid,
int servicePid)
- : CameraService::BasicClient(cameraService, remoteCallback->asBinder(),
+ : CameraService::BasicClient(cameraService, IInterface::asBinder(remoteCallback),
clientPackageName, cameraId, cameraFacing,
clientPid, clientUid, servicePid)
{
@@ -1630,14 +1825,11 @@
return NO_ERROR;
}
- result = String8::format("Camera module HAL API version: 0x%x\n",
- mModule->common.hal_api_version);
- result.appendFormat("Camera module API version: 0x%x\n",
- mModule->common.module_api_version);
- result.appendFormat("Camera module name: %s\n",
- mModule->common.name);
- result.appendFormat("Camera module author: %s\n",
- mModule->common.author);
+ const hw_module_t* common = mModule->getRawModule();
+ result = String8::format("Camera module HAL API version: 0x%x\n", common->hal_api_version);
+ result.appendFormat("Camera module API version: 0x%x\n", common->module_api_version);
+ result.appendFormat("Camera module name: %s\n", common->name);
+ result.appendFormat("Camera module author: %s\n", common->author);
result.appendFormat("Number of camera devices: %d\n\n", mNumberOfCameras);
sp<VendorTagDescriptor> desc = VendorTagDescriptor::getGlobalVendorTagDescriptor();
@@ -1657,7 +1849,7 @@
result = String8::format("Camera %d static information:\n", i);
camera_info info;
- status_t rc = mModule->get_camera_info(i, &info);
+ status_t rc = mModule->getCameraInfo(i, &info);
if (rc != OK) {
result.appendFormat(" Error reading static information!\n");
write(fd, result.string(), result.size());
@@ -1666,8 +1858,7 @@
info.facing == CAMERA_FACING_BACK ? "BACK" : "FRONT");
result.appendFormat(" Orientation: %d\n", info.orientation);
int deviceVersion;
- if (mModule->common.module_api_version <
- CAMERA_MODULE_API_VERSION_2_0) {
+ if (common->module_api_version < CAMERA_MODULE_API_VERSION_2_0) {
deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
} else {
deviceVersion = info.device_version;
@@ -1722,6 +1913,24 @@
return NO_ERROR;
}
+void CameraService::handleTorchClientBinderDied(const wp<IBinder> &who) {
+ Mutex::Autolock al(mTorchClientMapMutex);
+ for (size_t i = 0; i < mTorchClientMap.size(); i++) {
+ if (mTorchClientMap[i] == who) {
+ // turn off the torch mode that was turned on by dead client
+ String8 cameraId = mTorchClientMap.keyAt(i);
+ status_t res = mFlashlight->setTorchMode(cameraId, false);
+ if (res) {
+ ALOGE("%s: torch client died but couldn't turn off torch: "
+ "%s (%d)", __FUNCTION__, strerror(-res), res);
+ return;
+ }
+ mTorchClientMap.removeItemsAt(i);
+ break;
+ }
+ }
+}
+
/*virtual*/void CameraService::binderDied(
const wp<IBinder> &who) {
@@ -1732,6 +1941,10 @@
ALOGV("java clients' binder died");
+ // check torch client
+ handleTorchClientBinderDied(who);
+
+ // check camera device client
sp<BasicClient> cameraClient = getClientByRemote(who);
if (cameraClient == 0) {
@@ -1808,6 +2021,19 @@
}
}
+ if (status == ICameraServiceListener::STATUS_NOT_PRESENT ||
+ status == ICameraServiceListener::STATUS_NOT_AVAILABLE) {
+ // update torch status to not available when the camera device
+ // becomes not present or not available.
+ onTorchStatusChanged(String8::format("%d", cameraId),
+ ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE);
+ } else if (status == ICameraServiceListener::STATUS_PRESENT) {
+ // update torch status to available when the camera device becomes
+ // present or available
+ onTorchStatusChanged(String8::format("%d", cameraId),
+ ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF);
+ }
+
Vector<sp<ICameraServiceListener> >::const_iterator it;
for (it = mListenerList.begin(); it != mListenerList.end(); ++it) {
(*it)->onStatusChanged(status, cameraId);
@@ -1825,4 +2051,33 @@
return mStatusList[cameraId];
}
+status_t CameraService::getTorchStatusLocked(
+ const String8& cameraId,
+ ICameraServiceListener::TorchStatus *status) const {
+ if (!status) {
+ return BAD_VALUE;
+ }
+ ssize_t index = mTorchStatusMap.indexOfKey(cameraId);
+ if (index == NAME_NOT_FOUND) {
+ // invalid camera ID or the camera doesn't have a flash unit
+ return NAME_NOT_FOUND;
+ }
+
+ *status = mTorchStatusMap.valueAt(index);
+ return OK;
+}
+
+status_t CameraService::setTorchStatusLocked(const String8& cameraId,
+ ICameraServiceListener::TorchStatus status) {
+ ssize_t index = mTorchStatusMap.indexOfKey(cameraId);
+ if (index == NAME_NOT_FOUND) {
+ return BAD_VALUE;
+ }
+ ICameraServiceListener::TorchStatus& item =
+ mTorchStatusMap.editValueAt(index);
+ item = status;
+
+ return OK;
+}
+
}; // namespace android
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index a7328cf..22afc8c 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -36,6 +36,10 @@
#include <camera/CameraParameters.h>
#include <camera/ICameraServiceListener.h>
+#include "CameraFlashlight.h"
+
+
+#include "common/CameraModule.h"
/* This needs to be increased if we can have more cameras */
#define MAX_CAMERAS 2
@@ -68,6 +72,9 @@
// HAL Callbacks
virtual void onDeviceStatusChanged(int cameraId,
int newStatus);
+ virtual void onTorchStatusChanged(const String8& cameraId,
+ ICameraServiceListener::TorchStatus
+ newStatus);
/////////////////////////////////////////////////////////////////////
// ICameraService
@@ -110,6 +117,9 @@
/*out*/
String16* parameters);
+ virtual status_t setTorchMode(const String16& cameraId, bool enabled,
+ const sp<IBinder>& clientBinder);
+
// OK = supports api of that version, -EOPNOTSUPP = does not support
virtual status_t supportsCameraApi(
int cameraId, int apiVersion);
@@ -140,7 +150,6 @@
/////////////////////////////////////////////////////////////////////
// Shared utilities
- static status_t filterOpenErrorCode(status_t err);
static status_t filterGetInfoErrorCode(status_t err);
/////////////////////////////////////////////////////////////////////
@@ -153,7 +162,7 @@
class BasicClient : public virtual RefBase {
public:
- virtual status_t initialize(camera_module_t *module) = 0;
+ virtual status_t initialize(CameraModule *module) = 0;
virtual void disconnect();
// because we can't virtually inherit IInterface, which breaks
@@ -273,7 +282,7 @@
}
virtual sp<IBinder> asBinderWrapper() {
- return asBinder();
+ return asBinder(this);
}
protected:
@@ -385,7 +394,7 @@
sp<MediaPlayer> mSoundPlayer[NUM_SOUNDS];
int mSoundRef; // reference count (release all MediaPlayer when 0)
- camera_module_t *mModule;
+ CameraModule* mModule;
Vector<sp<ICameraServiceListener> >
mListenerList;
@@ -406,6 +415,37 @@
int32_t cameraId,
const StatusVector *rejectSourceStates = NULL);
+ // flashlight control
+ sp<CameraFlashlight> mFlashlight;
+ // guard mTorchStatusMap
+ Mutex mTorchStatusMutex;
+ // guard mTorchClientMap
+ Mutex mTorchClientMapMutex;
+ // camera id -> torch status
+ KeyedVector<String8, ICameraServiceListener::TorchStatus> mTorchStatusMap;
+ // camera id -> torch client binder
+ // only store the last client that turns on each camera's torch mode
+ KeyedVector<String8, sp<IBinder> > mTorchClientMap;
+
+ // check and handle if torch client's process has died
+ void handleTorchClientBinderDied(const wp<IBinder> &who);
+
+ // handle torch mode status change and invoke callbacks. mTorchStatusMutex
+ // should be locked.
+ void onTorchStatusChangedLocked(const String8& cameraId,
+ ICameraServiceListener::TorchStatus newStatus);
+
+ // validate the camera id for use of setting a torch mode.
+ bool validCameraIdForSetTorchMode(const String8& cameraId);
+
+ // get a camera's torch status. mTorchStatusMutex should be locked.
+ status_t getTorchStatusLocked(const String8 &cameraId,
+ ICameraServiceListener::TorchStatus *status) const;
+
+ // set a camera's torch status. mTorchStatusMutex should be locked.
+ status_t setTorchStatusLocked(const String8 &cameraId,
+ ICameraServiceListener::TorchStatus status);
+
// IBinder::DeathRecipient implementation
virtual void binderDied(const wp<IBinder> &who);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index dcab4ad..5dbdeb2 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -67,7 +67,7 @@
mLegacyMode = legacyMode;
}
-status_t Camera2Client::initialize(camera_module_t *module)
+status_t Camera2Client::initialize(CameraModule *module)
{
ATRACE_CALL();
ALOGV("%s: Initializing client for camera %d", __FUNCTION__, mCameraId);
@@ -165,7 +165,8 @@
String8 result;
result.appendFormat("Client2[%d] (%p) Client: %s PID: %d, dump:\n",
mCameraId,
- getRemoteCallback()->asBinder().get(),
+ (getRemoteCallback() != NULL ?
+ (IInterface::asBinder(getRemoteCallback()).get()) : NULL),
String8(mClientPackageName).string(),
mClientPid);
result.append(" State: ");
@@ -531,7 +532,7 @@
sp<IBinder> binder;
sp<ANativeWindow> window;
if (bufferProducer != 0) {
- binder = bufferProducer->asBinder();
+ binder = IInterface::asBinder(bufferProducer);
// 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.
@@ -1958,7 +1959,7 @@
return width * height * 2;
case HAL_PIXEL_FORMAT_RGBA_8888:
return width * height * 4;
- case HAL_PIXEL_FORMAT_RAW_SENSOR:
+ case HAL_PIXEL_FORMAT_RAW16:
return width * height * 2;
default:
ALOGE("%s: Unknown preview format: %x",
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index d68bb29..5a8241f 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -94,7 +94,7 @@
virtual ~Camera2Client();
- status_t initialize(camera_module_t *module);
+ status_t initialize(CameraModule *module);
virtual status_t dump(int fd, const Vector<String16>& args);
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index 1a4d9a6..6bea3b6 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -59,7 +59,7 @@
LOG1("CameraClient::CameraClient X (pid %d, id %d)", callingPid, cameraId);
}
-status_t CameraClient::initialize(camera_module_t *module) {
+status_t CameraClient::initialize(CameraModule *module) {
int callingPid = getCallingPid();
status_t res;
@@ -75,7 +75,7 @@
snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);
mHardware = new CameraHardwareInterface(camera_device_name);
- res = mHardware->initialize(&module->common);
+ res = mHardware->initialize(module);
if (res != OK) {
ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
@@ -118,7 +118,8 @@
size_t len = snprintf(buffer, SIZE, "Client[%d] (%p) PID: %d\n",
mCameraId,
- getRemoteCallback()->asBinder().get(),
+ (getRemoteCallback() != NULL ?
+ IInterface::asBinder(getRemoteCallback()).get() : NULL),
mClientPid);
len = (len > SIZE - 1) ? SIZE - 1 : len;
write(fd, buffer, len);
@@ -205,7 +206,7 @@
}
if (mRemoteCallback != 0 &&
- (client->asBinder() == mRemoteCallback->asBinder())) {
+ (IInterface::asBinder(client) == IInterface::asBinder(mRemoteCallback))) {
LOG1("Connect to the same client");
return NO_ERROR;
}
@@ -328,7 +329,7 @@
sp<IBinder> binder;
sp<ANativeWindow> window;
if (bufferProducer != 0) {
- binder = bufferProducer->asBinder();
+ binder = IInterface::asBinder(bufferProducer);
// 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.
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 63a9d0f..95616b2 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -68,7 +68,7 @@
bool legacyMode = false);
~CameraClient();
- status_t initialize(camera_module_t *module);
+ status_t initialize(CameraModule *module);
status_t dump(int fd, const Vector<String16>& args);
diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
index eadaa00..fd4e714 100644
--- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
@@ -155,7 +155,7 @@
callbackFormat, params.previewFormat);
res = device->createStream(mCallbackWindow,
params.previewWidth, params.previewHeight,
- callbackFormat, &mCallbackStreamId);
+ callbackFormat, HAL_DATASPACE_JFIF, &mCallbackStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Can't create output stream for callbacks: "
"%s (%d)", __FUNCTION__, mId,
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index 2772267..5b387f9 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -145,7 +145,8 @@
// Create stream for HAL production
res = device->createStream(mCaptureWindow,
params.pictureWidth, params.pictureHeight,
- HAL_PIXEL_FORMAT_BLOB, &mCaptureStreamId);
+ HAL_PIXEL_FORMAT_BLOB, HAL_DATASPACE_JFIF,
+ &mCaptureStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Can't create output stream for capture: "
"%s (%d)", __FUNCTION__, mId,
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 4f4cfb0..87e0132 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -182,9 +182,9 @@
supportedPreviewFormats +=
CameraParameters::PIXEL_FORMAT_YUV420SP;
break;
- // Not advertizing JPEG, RAW_SENSOR, etc, for preview formats
+ // Not advertizing JPEG, RAW16, etc, for preview formats
case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
- case HAL_PIXEL_FORMAT_RAW_SENSOR:
+ case HAL_PIXEL_FORMAT_RAW16:
case HAL_PIXEL_FORMAT_BLOB:
addComma = false;
break;
@@ -2253,7 +2253,7 @@
case HAL_PIXEL_FORMAT_RGBA_8888: // RGBA8888
fmt = CameraParameters::PIXEL_FORMAT_RGBA8888;
break;
- case HAL_PIXEL_FORMAT_RAW_SENSOR:
+ case HAL_PIXEL_FORMAT_RAW16:
ALOGW("Raw sensor preview format requested.");
fmt = CameraParameters::PIXEL_FORMAT_BAYER_RGGB;
break;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 7e5be84..e628a7e 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -19,11 +19,13 @@
#include <system/graphics.h>
+#include <utils/Compat.h>
#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
#include <utils/Mutex.h>
#include <utils/String8.h>
#include <utils/Vector.h>
-#include <utils/KeyedVector.h>
+
#include <camera/CameraParameters.h>
#include <camera/CameraParameters2.h>
#include <camera/CameraMetadata.h>
@@ -187,7 +189,7 @@
static const int MAX_INITIAL_PREVIEW_WIDTH = 1920;
static const int MAX_INITIAL_PREVIEW_HEIGHT = 1080;
// Aspect ratio tolerance
- static const float ASPECT_RATIO_TOLERANCE = 0.001;
+ static const CONSTEXPR float ASPECT_RATIO_TOLERANCE = 0.001;
// Full static camera info, object owned by someone else, such as
// Camera2Device.
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index 470624b..ea5dcdd 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -181,7 +181,8 @@
if (mPreviewStreamId == NO_STREAM) {
res = device->createStream(mPreviewWindow,
params.previewWidth, params.previewHeight,
- CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, &mPreviewStreamId);
+ CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, HAL_DATASPACE_UNKNOWN,
+ &mPreviewStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to create preview stream: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
@@ -420,9 +421,12 @@
if (mRecordingStreamId == NO_STREAM) {
mRecordingFrameCount = 0;
+ // Selecting BT.709 colorspace by default
+ // TODO: Wire this in from encoder side
res = device->createStream(mRecordingWindow,
params.videoWidth, params.videoHeight,
- CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, &mRecordingStreamId);
+ CAMERA2_HAL_PIXEL_FORMAT_OPAQUE,
+ HAL_DATASPACE_BT709, &mRecordingStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Can't create output stream for recording: "
"%s (%d)", __FUNCTION__, mId,
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 8b7e4b4..db7e10d 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -186,7 +186,7 @@
(int)HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
res = device->createStream(mZslWindow,
params.fastInfo.arrayWidth, params.fastInfo.arrayHeight,
- streamType, &mZslStreamId);
+ streamType, HAL_DATASPACE_UNKNOWN, &mZslStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Can't create output stream for ZSL: "
"%s (%d)", __FUNCTION__, mId,
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index e6865bb..dde1779 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -42,8 +42,14 @@
int clientPid,
uid_t clientUid,
int servicePid) :
- BasicClient(cameraService, remoteCallback->asBinder(), clientPackageName,
- cameraId, cameraFacing, clientPid, clientUid, servicePid),
+ BasicClient(cameraService,
+ IInterface::asBinder(remoteCallback),
+ clientPackageName,
+ cameraId,
+ cameraFacing,
+ clientPid,
+ clientUid,
+ servicePid),
mRemoteCallback(remoteCallback) {
}
@@ -65,7 +71,7 @@
ALOGI("CameraDeviceClient %d: Opened", cameraId);
}
-status_t CameraDeviceClient::initialize(camera_module_t *module)
+status_t CameraDeviceClient::initialize(CameraModule *module)
{
ATRACE_CALL();
status_t res;
@@ -157,7 +163,7 @@
if (surface == 0) continue;
sp<IGraphicBufferProducer> gbp = surface->getIGraphicBufferProducer();
- int idx = mStreamMap.indexOfKey(gbp->asBinder());
+ int idx = mStreamMap.indexOfKey(IInterface::asBinder(gbp));
// Trying to submit request with surface that wasn't created
if (idx == NAME_NOT_FOUND) {
@@ -308,11 +314,10 @@
return res;
}
-status_t CameraDeviceClient::createStream(int width, int height, int format,
+status_t CameraDeviceClient::createStream(
const sp<IGraphicBufferProducer>& bufferProducer)
{
ATRACE_CALL();
- ALOGV("%s (w = %d, h = %d, f = 0x%x)", __FUNCTION__, width, height, format);
status_t res;
if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
@@ -327,7 +332,7 @@
// Don't create multiple streams for the same target surface
{
- ssize_t index = mStreamMap.indexOfKey(bufferProducer->asBinder());
+ ssize_t index = mStreamMap.indexOfKey(IInterface::asBinder(bufferProducer));
if (index != NAME_NOT_FOUND) {
ALOGW("%s: Camera %d: Buffer producer already has a stream for it "
"(ID %zd)",
@@ -361,14 +366,11 @@
bool flexibleConsumer = (consumerUsage & disallowedFlags) == 0 &&
(consumerUsage & allowedFlags) != 0;
- sp<IBinder> binder;
- sp<ANativeWindow> anw;
- if (bufferProducer != 0) {
- binder = bufferProducer->asBinder();
- anw = new Surface(bufferProducer, useAsync);
- }
+ sp<IBinder> binder = IInterface::asBinder(bufferProducer);
+ sp<ANativeWindow> anw = new Surface(bufferProducer, useAsync);
- // TODO: remove w,h,f since we are ignoring them
+ int width, height, format;
+ android_dataspace dataSpace;
if ((res = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, &width)) != OK) {
ALOGE("%s: Camera %d: Failed to query Surface width", __FUNCTION__,
@@ -385,6 +387,12 @@
mCameraId);
return res;
}
+ if ((res = anw->query(anw.get(), NATIVE_WINDOW_DEFAULT_DATASPACE,
+ reinterpret_cast<int*>(&dataSpace))) != OK) {
+ ALOGE("%s: Camera %d: Failed to query Surface dataSpace", __FUNCTION__,
+ mCameraId);
+ return res;
+ }
// FIXME: remove this override since the default format should be
// IMPLEMENTATION_DEFINED. b/9487482
@@ -397,17 +405,18 @@
// Round dimensions to the nearest dimensions available for this format
if (flexibleConsumer && !CameraDeviceClient::roundBufferDimensionNearest(width, height,
- format, mDevice->info(), /*out*/&width, /*out*/&height)) {
+ format, dataSpace, mDevice->info(), /*out*/&width, /*out*/&height)) {
ALOGE("%s: No stream configurations with the format %#x defined, failed to create stream.",
__FUNCTION__, format);
return BAD_VALUE;
}
int streamId = -1;
- res = mDevice->createStream(anw, width, height, format, &streamId);
+ res = mDevice->createStream(anw, width, height, format, dataSpace,
+ &streamId);
if (res == OK) {
- mStreamMap.add(bufferProducer->asBinder(), streamId);
+ mStreamMap.add(binder, streamId);
ALOGV("%s: Camera %d: Successfully created a new stream ID %d",
__FUNCTION__, mCameraId, streamId);
@@ -439,10 +448,12 @@
bool CameraDeviceClient::roundBufferDimensionNearest(int32_t width, int32_t height,
- int32_t format, const CameraMetadata& info,
+ int32_t format, android_dataspace dataSpace, const CameraMetadata& info,
/*out*/int32_t* outWidth, /*out*/int32_t* outHeight) {
camera_metadata_ro_entry streamConfigs =
+ (dataSpace == HAL_DATASPACE_DEPTH) ?
+ info.find(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS) :
info.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
int32_t bestWidth = -1;
@@ -582,7 +593,8 @@
String8 result;
result.appendFormat("CameraDeviceClient[%d] (%p) dump:\n",
mCameraId,
- getRemoteCallback()->asBinder().get());
+ (getRemoteCallback() != NULL ?
+ IInterface::asBinder(getRemoteCallback()).get() : NULL) );
result.appendFormat(" Current client: %s (PID %d, UID %u)\n",
String8(mClientPackageName).string(),
mClientPid, mClientUid);
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 84e46b7..c89c269 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -84,9 +84,6 @@
virtual status_t deleteStream(int streamId);
virtual status_t createStream(
- int width,
- int height,
- int format,
const sp<IGraphicBufferProducer>& bufferProducer);
// Create a request object from a template.
@@ -119,7 +116,7 @@
int servicePid);
virtual ~CameraDeviceClient();
- virtual status_t initialize(camera_module_t *module);
+ virtual status_t initialize(CameraModule *module);
virtual status_t dump(int fd, const Vector<String16>& args);
@@ -161,7 +158,8 @@
// a width <= ROUNDING_WIDTH_CAP
static const int32_t ROUNDING_WIDTH_CAP = 1080;
static bool roundBufferDimensionNearest(int32_t width, int32_t height, int32_t format,
- const CameraMetadata& info, /*out*/int32_t* outWidth, /*out*/int32_t* outHeight);
+ android_dataspace dataSpace, const CameraMetadata& info,
+ /*out*/int32_t* outWidth, /*out*/int32_t* outHeight);
// IGraphicsBufferProducer binder -> Stream ID
KeyedVector<sp<IBinder>, int> mStreamMap;
diff --git a/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp b/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp
index 2ea460f..ba93554 100644
--- a/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp
+++ b/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp
@@ -50,7 +50,7 @@
mExclusiveLock = false;
}
-status_t ProCamera2Client::initialize(camera_module_t *module)
+status_t ProCamera2Client::initialize(CameraModule *module)
{
ATRACE_CALL();
status_t res;
@@ -276,12 +276,12 @@
sp<IBinder> binder;
sp<ANativeWindow> window;
if (bufferProducer != 0) {
- binder = bufferProducer->asBinder();
+ binder = IInterface::asBinder(bufferProducer);
window = new Surface(bufferProducer);
}
return mDevice->createStream(window, width, height, format,
- streamId);
+ HAL_DATASPACE_UNKNOWN, streamId);
}
// Create a request object from a template.
@@ -334,7 +334,8 @@
String8 result;
result.appendFormat("ProCamera2Client[%d] (%p) PID: %d, dump:\n",
mCameraId,
- getRemoteCallback()->asBinder().get(),
+ (getRemoteCallback() != NULL ?
+ IInterface::asBinder(getRemoteCallback()).get() : NULL),
mClientPid);
result.append(" State:\n");
write(fd, result.string(), result.size());
diff --git a/services/camera/libcameraservice/api_pro/ProCamera2Client.h b/services/camera/libcameraservice/api_pro/ProCamera2Client.h
index 9d83122..7f5f6ac 100644
--- a/services/camera/libcameraservice/api_pro/ProCamera2Client.h
+++ b/services/camera/libcameraservice/api_pro/ProCamera2Client.h
@@ -85,7 +85,7 @@
int servicePid);
virtual ~ProCamera2Client();
- virtual status_t initialize(camera_module_t *module);
+ virtual status_t initialize(CameraModule *module);
virtual status_t dump(int fd, const Vector<String16>& args);
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index d6db151..0415d67 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -78,7 +78,7 @@
}
template <typename TClientBase>
-status_t Camera2ClientBase<TClientBase>::initialize(camera_module_t *module) {
+status_t Camera2ClientBase<TClientBase>::initialize(CameraModule *module) {
ATRACE_CALL();
ALOGV("%s: Initializing client for camera %d", __FUNCTION__,
TClientBase::mCameraId);
@@ -128,7 +128,8 @@
String8 result;
result.appendFormat("Camera2ClientBase[%d] (%p) PID: %d, dump:\n",
TClientBase::mCameraId,
- TClientBase::getRemoteCallback()->asBinder().get(),
+ (TClientBase::getRemoteCallback() != NULL ?
+ IInterface::asBinder(TClientBase::getRemoteCallback()).get() : NULL),
TClientBase::mClientPid);
result.append(" State: ");
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index d198e4e..eb21d55 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -18,6 +18,7 @@
#define ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_BASE_H
#include "common/CameraDeviceBase.h"
+#include "common/CameraModule.h"
#include "camera/CaptureResult.h"
namespace android {
@@ -55,7 +56,7 @@
int servicePid);
virtual ~Camera2ClientBase();
- virtual status_t initialize(camera_module_t *module);
+ virtual status_t initialize(CameraModule *module);
virtual status_t dump(int fd, const Vector<String16>& args);
/**
@@ -111,7 +112,7 @@
pid_t mInitialClientPid;
virtual sp<IBinder> asBinderWrapper() {
- return IInterface::asBinder();
+ return IInterface::asBinder(this);
}
virtual status_t dumpDevice(int fd, const Vector<String16>& args);
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index d26e20c..8764504 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -29,6 +29,7 @@
#include "hardware/camera3.h"
#include "camera/CameraMetadata.h"
#include "camera/CaptureResult.h"
+#include "common/CameraModule.h"
namespace android {
@@ -45,7 +46,7 @@
*/
virtual int getId() const = 0;
- virtual status_t initialize(camera_module_t *module) = 0;
+ virtual status_t initialize(CameraModule *module) = 0;
virtual status_t disconnect() = 0;
virtual status_t dump(int fd, const Vector<String16> &args) = 0;
@@ -99,17 +100,14 @@
nsecs_t timeout) = 0;
/**
- * Create an output stream of the requested size and format.
+ * Create an output stream of the requested size, format, and dataspace
*
- * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device selects
- * an appropriate format; it can be queried with getStreamInfo.
- *
- * 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.
+ * For HAL_PIXEL_FORMAT_BLOB formats, the width and height should be the
+ * logical dimensions of the buffer, not the number of bytes.
*/
virtual status_t createStream(sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, int format, int *id) = 0;
+ uint32_t width, uint32_t height, int format,
+ android_dataspace dataSpace, int *id) = 0;
/**
* Create an input reprocess stream that uses buffers from an existing
diff --git a/services/camera/libcameraservice/common/CameraModule.cpp b/services/camera/libcameraservice/common/CameraModule.cpp
new file mode 100644
index 0000000..5f767ad
--- /dev/null
+++ b/services/camera/libcameraservice/common/CameraModule.cpp
@@ -0,0 +1,144 @@
+/*
+ * 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 "CameraModule"
+//#define LOG_NDEBUG 0
+
+#include "CameraModule.h"
+
+namespace android {
+
+void CameraModule::deriveCameraCharacteristicsKeys(
+ uint32_t deviceVersion, CameraMetadata &chars) {
+ // 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;
+ }
+
+ // Keys added in HAL3.3
+ if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_3) {
+ Vector<uint8_t> controlModes;
+ uint8_t data = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE;
+ chars.update(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &data, /*count*/1);
+ data = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE;
+ chars.update(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &data, /*count*/1);
+ controlModes.push(ANDROID_CONTROL_MODE_OFF);
+ controlModes.push(ANDROID_CONTROL_MODE_AUTO);
+ camera_metadata_entry entry = chars.find(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
+ if (entry.count > 1 || entry.data.u8[0] != ANDROID_CONTROL_SCENE_MODE_DISABLED) {
+ controlModes.push(ANDROID_CONTROL_MODE_USE_SCENE_MODE);
+ }
+ chars.update(ANDROID_CONTROL_AVAILABLE_MODES, controlModes);
+ }
+ return;
+}
+
+CameraModule::CameraModule(camera_module_t *module) {
+ if (module == NULL) {
+ ALOGE("%s: camera hardware module must not be null", __FUNCTION__);
+ assert(0);
+ }
+
+ mModule = module;
+ for (int i = 0; i < MAX_CAMERAS_PER_MODULE; i++) {
+ mCameraInfoCached[i] = false;
+ }
+}
+
+int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) {
+ Mutex::Autolock lock(mCameraInfoLock);
+ if (cameraId < 0 || cameraId >= MAX_CAMERAS_PER_MODULE) {
+ ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId);
+ return -EINVAL;
+ }
+
+ // Only override static_camera_characteristics for API2 devices
+ int apiVersion = mModule->common.module_api_version;
+ if (apiVersion < CAMERA_MODULE_API_VERSION_2_0) {
+ return mModule->get_camera_info(cameraId, info);
+ }
+
+ camera_info &wrappedInfo = mCameraInfo[cameraId];
+ if (!mCameraInfoCached[cameraId]) {
+ camera_info rawInfo;
+ int ret = mModule->get_camera_info(cameraId, &rawInfo);
+ if (ret != 0) {
+ return ret;
+ }
+ CameraMetadata &m = mCameraCharacteristics[cameraId];
+ m = rawInfo.static_camera_characteristics;
+ deriveCameraCharacteristicsKeys(rawInfo.device_version, m);
+ wrappedInfo = rawInfo;
+ wrappedInfo.static_camera_characteristics = m.getAndLock();
+ mCameraInfoCached[cameraId] = true;
+ }
+ *info = wrappedInfo;
+ return 0;
+}
+
+int CameraModule::open(const char* id, struct hw_device_t** device) {
+ return filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device));
+}
+
+int CameraModule::openLegacy(
+ const char* id, uint32_t halVersion, struct hw_device_t** device) {
+ return mModule->open_legacy(&mModule->common, id, halVersion, device);
+}
+
+const hw_module_t* CameraModule::getRawModule() {
+ return &mModule->common;
+}
+
+int CameraModule::getNumberOfCameras() {
+ return mModule->get_number_of_cameras();
+}
+
+int CameraModule::setCallbacks(const camera_module_callbacks_t *callbacks) {
+ return mModule->set_callbacks(callbacks);
+}
+
+bool CameraModule::isVendorTagDefined() {
+ return mModule->get_vendor_tag_ops != NULL;
+}
+
+void CameraModule::getVendorTagOps(vendor_tag_ops_t* ops) {
+ if (mModule->get_vendor_tag_ops) {
+ mModule->get_vendor_tag_ops(ops);
+ }
+}
+
+int CameraModule::setTorchMode(const char* camera_id, bool enable) {
+ return mModule->set_torch_mode(camera_id, enable);
+}
+
+
+status_t CameraModule::filterOpenErrorCode(status_t err) {
+ switch(err) {
+ case NO_ERROR:
+ case -EBUSY:
+ case -EINVAL:
+ case -EUSERS:
+ return err;
+ default:
+ break;
+ }
+ return -ENODEV;
+}
+
+
+}; // namespace android
+
diff --git a/services/camera/libcameraservice/common/CameraModule.h b/services/camera/libcameraservice/common/CameraModule.h
new file mode 100644
index 0000000..16207aa
--- /dev/null
+++ b/services/camera/libcameraservice/common/CameraModule.h
@@ -0,0 +1,65 @@
+/*
+ * 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_SERVERS_CAMERA_CAMERAMODULE_H
+#define ANDROID_SERVERS_CAMERA_CAMERAMODULE_H
+
+#include <hardware/camera.h>
+#include <camera/CameraMetadata.h>
+#include <utils/Mutex.h>
+
+/* This needs to be increased if we can have more cameras */
+#define MAX_CAMERAS_PER_MODULE 2
+
+
+namespace android {
+/**
+ * A wrapper class for HAL camera module.
+ *
+ * This class wraps camera_module_t returned from HAL to provide a wrapped
+ * get_camera_info implementation which CameraService generates some
+ * camera characteristics keys defined in newer HAL version on an older HAL.
+ */
+class CameraModule {
+public:
+ CameraModule(camera_module_t *module);
+
+ const hw_module_t* getRawModule();
+ int getCameraInfo(int cameraId, struct camera_info *info);
+ int getNumberOfCameras(void);
+ int open(const char* id, struct hw_device_t** device);
+ int openLegacy(const char* id, uint32_t halVersion, struct hw_device_t** device);
+ int setCallbacks(const camera_module_callbacks_t *callbacks);
+ bool isVendorTagDefined();
+ void getVendorTagOps(vendor_tag_ops_t* ops);
+ int setTorchMode(const char* camera_id, bool enable);
+
+private:
+ // Derive camera characteristics keys defined after HAL device version
+ static void deriveCameraCharacteristicsKeys(uint32_t deviceVersion, CameraMetadata &chars);
+ status_t filterOpenErrorCode(status_t err);
+
+ camera_module_t *mModule;
+ CameraMetadata mCameraCharacteristics[MAX_CAMERAS_PER_MODULE];
+ camera_info mCameraInfo[MAX_CAMERAS_PER_MODULE];
+ bool mCameraInfoCached[MAX_CAMERAS_PER_MODULE];
+ Mutex mCameraInfoLock;
+};
+
+} // namespace android
+
+#endif
+
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.h b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
index 6386838..f5ebbf8 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
@@ -89,24 +89,22 @@
}
}
- status_t initialize(hw_module_t *module)
+ status_t initialize(CameraModule *module)
{
ALOGI("Opening camera %s", mName.string());
- camera_module_t *cameraModule = reinterpret_cast<camera_module_t *>(module);
camera_info info;
- status_t res = cameraModule->get_camera_info(atoi(mName.string()), &info);
+ status_t res = module->getCameraInfo(atoi(mName.string()), &info);
if (res != OK) return res;
int rc = OK;
- if (module->module_api_version >= CAMERA_MODULE_API_VERSION_2_3 &&
+ if (module->getRawModule()->module_api_version >= CAMERA_MODULE_API_VERSION_2_3 &&
info.device_version > CAMERA_DEVICE_API_VERSION_1_0) {
// Open higher version camera device as HAL1.0 device.
- rc = cameraModule->open_legacy(module, mName.string(),
- CAMERA_DEVICE_API_VERSION_1_0,
- (hw_device_t **)&mDevice);
+ rc = module->openLegacy(mName.string(),
+ CAMERA_DEVICE_API_VERSION_1_0,
+ (hw_device_t **)&mDevice);
} else {
- rc = CameraService::filterOpenErrorCode(module->methods->open(
- module, mName.string(), (hw_device_t **)&mDevice));
+ rc = module->open(mName.string(), (hw_device_t **)&mDevice);
}
if (rc != OK) {
ALOGE("Could not open camera %s: %d", mName.string(), rc);
@@ -588,7 +586,7 @@
#ifndef container_of
#define container_of(ptr, type, member) ({ \
- const typeof(((type *) 0)->member) *__mptr = (ptr); \
+ const __typeof__(((type *) 0)->member) *__mptr = (ptr); \
(type *) ((char *) __mptr - (char *)(&((type *)0)->member)); })
#endif
diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp
index d1158d6..ee862a2 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.cpp
+++ b/services/camera/libcameraservice/device2/Camera2Device.cpp
@@ -53,7 +53,7 @@
return mId;
}
-status_t Camera2Device::initialize(camera_module_t *module)
+status_t Camera2Device::initialize(CameraModule *module)
{
ATRACE_CALL();
ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mId);
@@ -68,8 +68,7 @@
camera2_device_t *device;
- res = CameraService::filterOpenErrorCode(module->common.methods->open(
- &module->common, name, reinterpret_cast<hw_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__,
@@ -87,7 +86,7 @@
}
camera_info info;
- res = module->get_camera_info(mId, &info);
+ res = module->getCameraInfo(mId, &info);
if (res != OK ) return res;
if (info.device_version != device->common.version) {
@@ -242,7 +241,8 @@
}
status_t Camera2Device::createStream(sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, int format, int *id) {
+ uint32_t width, uint32_t height, int format,
+ android_dataspace /*dataSpace*/, int *id) {
ATRACE_CALL();
status_t res;
ALOGV("%s: E", __FUNCTION__);
diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h
index 4def8ae..e4c2856 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.h
+++ b/services/camera/libcameraservice/device2/Camera2Device.h
@@ -43,7 +43,7 @@
* CameraDevice interface
*/
virtual int getId() const;
- virtual status_t initialize(camera_module_t *module);
+ 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;
@@ -57,7 +57,8 @@
virtual status_t clearStreamingRequest(int64_t *lastFrameNumber = NULL);
virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout);
virtual status_t createStream(sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, int format, int *id);
+ uint32_t width, uint32_t height, int format,
+ android_dataspace dataSpace, 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);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 53e6fa9..529d249 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -86,7 +86,7 @@
* CameraDeviceBase interface
*/
-status_t Camera3Device::initialize(camera_module_t *module)
+status_t Camera3Device::initialize(CameraModule *module)
{
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
@@ -106,9 +106,8 @@
camera3_device_t *device;
ATRACE_BEGIN("camera3->open");
- res = CameraService::filterOpenErrorCode(module->common.methods->open(
- &module->common, deviceName.string(),
- reinterpret_cast<hw_device_t**>(&device)));
+ res = module->open(deviceName.string(),
+ reinterpret_cast<hw_device_t**>(&device));
ATRACE_END();
if (res != OK) {
@@ -127,7 +126,7 @@
}
camera_info info;
- res = CameraService::filterGetInfoErrorCode(module->get_camera_info(
+ res = CameraService::filterGetInfoErrorCode(module->getCameraInfo(
mId, &info));
if (res != OK) return res;
@@ -802,12 +801,13 @@
}
status_t Camera3Device::createStream(sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, int format, int *id) {
+ uint32_t width, uint32_t height, int format, android_dataspace dataSpace,
+ int *id) {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
- ALOGV("Camera %d: Creating new stream %d: %d x %d, format %d",
- mId, mNextStreamId, width, height, format);
+ ALOGV("Camera %d: Creating new stream %d: %d x %d, format %d, dataspace %d",
+ mId, mNextStreamId, width, height, format, dataSpace);
status_t res;
bool wasActive = false;
@@ -847,10 +847,10 @@
}
newStream = new Camera3OutputStream(mNextStreamId, consumer,
- width, height, jpegBufferSize, format);
+ width, height, jpegBufferSize, format, dataSpace);
} else {
newStream = new Camera3OutputStream(mNextStreamId, consumer,
- width, height, format);
+ width, height, format, dataSpace);
}
newStream->setStatusTracker(mStatusTracker);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index ec8dc10..e2ad1fa 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -73,7 +73,7 @@
virtual int getId() const;
// Transitions to idle state on success.
- virtual status_t initialize(camera_module_t *module);
+ 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;
@@ -95,7 +95,8 @@
// If adding streams while actively capturing, will pause device before adding
// stream, reconfiguring device, and unpausing.
virtual status_t createStream(sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, int format, int *id);
+ uint32_t width, uint32_t height, int format,
+ android_dataspace dataSpace, int *id);
virtual status_t createInputStream(
uint32_t width, uint32_t height, int format,
int *id);
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
index 6656b09..6201484 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
@@ -28,7 +28,7 @@
Camera3DummyStream::Camera3DummyStream(int id) :
Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, DUMMY_WIDTH, DUMMY_HEIGHT,
- /*maxSize*/0, DUMMY_FORMAT) {
+ /*maxSize*/0, DUMMY_FORMAT, DUMMY_DATASPACE) {
}
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h
index 3e42623..7f52d84 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.h
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h
@@ -75,6 +75,7 @@
static const int DUMMY_WIDTH = 320;
static const int DUMMY_HEIGHT = 240;
static const int DUMMY_FORMAT = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ static const android_dataspace DUMMY_DATASPACE = HAL_DATASPACE_UNKNOWN;
static const uint32_t DUMMY_USAGE = GRALLOC_USAGE_HW_COMPOSER;
/**
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index cc66459..ff0acbb 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -30,9 +30,10 @@
namespace camera3 {
Camera3IOStreamBase::Camera3IOStreamBase(int id, camera3_stream_type_t type,
- uint32_t width, uint32_t height, size_t maxSize, int format) :
+ uint32_t width, uint32_t height, size_t maxSize, int format,
+ android_dataspace dataSpace) :
Camera3Stream(id, type,
- width, height, maxSize, format),
+ width, height, maxSize, format, dataSpace),
mTotalBufferCount(0),
mHandoutTotalBufferCount(0),
mHandoutOutputBufferCount(0),
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
index a35c290..83d4350 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
@@ -33,7 +33,8 @@
public Camera3Stream {
protected:
Camera3IOStreamBase(int id, camera3_stream_type_t type,
- uint32_t width, uint32_t height, size_t maxSize, int format);
+ uint32_t width, uint32_t height, size_t maxSize, int format,
+ android_dataspace dataSpace);
public:
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index 319be1d..85ed88d 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -29,7 +29,7 @@
Camera3InputStream::Camera3InputStream(int id,
uint32_t width, uint32_t height, int format) :
Camera3IOStreamBase(id, CAMERA3_STREAM_INPUT, width, height,
- /*maxSize*/0, format) {
+ /*maxSize*/0, format, HAL_DATASPACE_UNKNOWN) {
if (format == HAL_PIXEL_FORMAT_BLOB) {
ALOGE("%s: Bad format, BLOB not supported", __FUNCTION__);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 77ad503..103d90b 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -33,9 +33,10 @@
Camera3OutputStream::Camera3OutputStream(int id,
sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, int format) :
+ uint32_t width, uint32_t height, int format,
+ android_dataspace dataSpace) :
Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height,
- /*maxSize*/0, format),
+ /*maxSize*/0, format, dataSpace),
mConsumer(consumer),
mTransform(0),
mTraceFirstBuffer(true) {
@@ -48,9 +49,10 @@
Camera3OutputStream::Camera3OutputStream(int id,
sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, size_t maxSize, int format) :
+ uint32_t width, uint32_t height, size_t maxSize, int format,
+ android_dataspace dataSpace) :
Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height, maxSize,
- format),
+ format, dataSpace),
mConsumer(consumer),
mTransform(0),
mTraceFirstBuffer(true) {
@@ -69,10 +71,11 @@
Camera3OutputStream::Camera3OutputStream(int id, camera3_stream_type_t type,
uint32_t width, uint32_t height,
- int format) :
+ int format,
+ android_dataspace dataSpace) :
Camera3IOStreamBase(id, type, width, height,
/*maxSize*/0,
- format),
+ format, dataSpace),
mTransform(0) {
// Subclasses expected to initialize mConsumer themselves
@@ -323,6 +326,14 @@
return res;
}
+ res = native_window_set_buffers_data_space(mConsumer.get(),
+ camera3_stream::data_space);
+ if (res != OK) {
+ ALOGE("%s: Unable to configure stream dataspace %#x for stream %d",
+ __FUNCTION__, camera3_stream::data_space, mId);
+ return res;
+ }
+
int maxConsumerBuffers;
res = mConsumer->query(mConsumer.get(),
NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index be278c5..f016d60 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -39,14 +39,16 @@
* Set up a stream for formats that have 2 dimensions, such as RAW and YUV.
*/
Camera3OutputStream(int id, sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, int format);
+ uint32_t width, uint32_t height, int format,
+ android_dataspace dataSpace);
/**
* Set up a stream for formats that have a variable buffer size for the same
* dimensions, such as compressed JPEG.
*/
Camera3OutputStream(int id, sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, size_t maxSize, int format);
+ uint32_t width, uint32_t height, size_t maxSize, int format,
+ android_dataspace dataSpace);
virtual ~Camera3OutputStream();
@@ -64,7 +66,8 @@
protected:
Camera3OutputStream(int id, camera3_stream_type_t type,
- uint32_t width, uint32_t height, int format);
+ uint32_t width, uint32_t height, int format,
+ android_dataspace dataSpace);
/**
* Note that we release the lock briefly in this function
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 3c0e908..f829741 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -46,7 +46,8 @@
Camera3Stream::Camera3Stream(int id,
camera3_stream_type type,
- uint32_t width, uint32_t height, size_t maxSize, int format) :
+ uint32_t width, uint32_t height, size_t maxSize, int format,
+ android_dataspace dataSpace) :
camera3_stream(),
mId(id),
mName(String8::format("Camera3Stream[%d]", id)),
@@ -58,6 +59,7 @@
camera3_stream::width = width;
camera3_stream::height = height;
camera3_stream::format = format;
+ camera3_stream::data_space = dataSpace;
camera3_stream::usage = 0;
camera3_stream::max_buffers = 0;
camera3_stream::priv = NULL;
@@ -84,6 +86,10 @@
return camera3_stream::format;
}
+android_dataspace Camera3Stream::getDataSpace() const {
+ return camera3_stream::data_space;
+}
+
camera3_stream* Camera3Stream::startConfiguration() {
ATRACE_CALL();
Mutex::Autolock l(mLock);
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index d0e1337..72f3ee9 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -119,9 +119,10 @@
/**
* Get the stream's dimensions and format
*/
- uint32_t getWidth() const;
- uint32_t getHeight() const;
- int getFormat() const;
+ uint32_t getWidth() const;
+ uint32_t getHeight() const;
+ int getFormat() const;
+ android_dataspace getDataSpace() const;
/**
* Start the stream configuration process. Returns a handle to the stream's
@@ -264,7 +265,8 @@
mutable Mutex mLock;
Camera3Stream(int id, camera3_stream_type type,
- uint32_t width, uint32_t height, size_t maxSize, int format);
+ uint32_t width, uint32_t height, size_t maxSize, int format,
+ android_dataspace dataSpace);
/**
* Interface to be implemented by derived classes
diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
index 81330ea..5bf7a4c 100644
--- a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
@@ -114,7 +114,8 @@
int bufferCount) :
Camera3OutputStream(id, CAMERA3_STREAM_BIDIRECTIONAL,
width, height,
- HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+ HAL_DATASPACE_UNKNOWN),
mDepth(bufferCount) {
sp<IGraphicBufferProducer> producer;
diff --git a/services/medialog/Android.mk b/services/medialog/Android.mk
index 95f2fef..03438bf 100644
--- a/services/medialog/Android.mk
+++ b/services/medialog/Android.mk
@@ -10,4 +10,6 @@
LOCAL_32_BIT_ONLY := true
+LOCAL_C_INCLUDES := $(call include-path-for, audio-utils)
+
include $(BUILD_SHARED_LIBRARY)
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index d3b67f6..081aff7 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -143,7 +143,7 @@
sp<Module> module = mModules.valueAt(index);
module->setClient(client);
- client->asBinder()->linkToDeath(module);
+ IInterface::asBinder(client)->linkToDeath(module);
moduleInterface = module;
module->setCaptureState_l(mCaptureState);
@@ -510,7 +510,7 @@
mModels.clear();
}
if (mClient != 0) {
- mClient->asBinder()->unlinkToDeath(this);
+ IInterface::asBinder(mClient)->unlinkToDeath(this);
}
sp<SoundTriggerHwService> service = mService.promote();
if (service == 0) {
diff --git a/soundtrigger/ISoundTrigger.cpp b/soundtrigger/ISoundTrigger.cpp
index 42280d1..eecc1ea 100644
--- a/soundtrigger/ISoundTrigger.cpp
+++ b/soundtrigger/ISoundTrigger.cpp
@@ -58,7 +58,7 @@
}
Parcel data, reply;
data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor());
- data.writeStrongBinder(modelMemory->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(modelMemory));
status_t status = remote()->transact(LOAD_SOUND_MODEL, data, &reply);
if (status != NO_ERROR ||
(status = (status_t)reply.readInt32()) != NO_ERROR) {
@@ -91,7 +91,7 @@
} else {
data.writeInt32(dataMemory->size());
}
- data.writeStrongBinder(dataMemory->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(dataMemory));
status_t status = remote()->transact(START_RECOGNITION, data, &reply);
if (status != NO_ERROR) {
status = (status_t)reply.readInt32();
diff --git a/soundtrigger/ISoundTriggerClient.cpp b/soundtrigger/ISoundTriggerClient.cpp
index b0b4428..e0d3add 100644
--- a/soundtrigger/ISoundTriggerClient.cpp
+++ b/soundtrigger/ISoundTriggerClient.cpp
@@ -44,7 +44,7 @@
{
Parcel data, reply;
data.writeInterfaceToken(ISoundTriggerClient::getInterfaceDescriptor());
- data.writeStrongBinder(eventMemory->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(eventMemory));
remote()->transact(ON_RECOGNITION_EVENT,
data,
&reply);
@@ -54,7 +54,7 @@
{
Parcel data, reply;
data.writeInterfaceToken(ISoundTriggerClient::getInterfaceDescriptor());
- data.writeStrongBinder(eventMemory->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(eventMemory));
remote()->transact(ON_SOUNDMODEL_EVENT,
data,
&reply);
@@ -63,7 +63,7 @@
{
Parcel data, reply;
data.writeInterfaceToken(ISoundTriggerClient::getInterfaceDescriptor());
- data.writeStrongBinder(eventMemory->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(eventMemory));
remote()->transact(ON_SERVICE_STATE_CHANGE,
data,
&reply);
diff --git a/soundtrigger/ISoundTriggerHwService.cpp b/soundtrigger/ISoundTriggerHwService.cpp
index 05728e9..75f68b8 100644
--- a/soundtrigger/ISoundTriggerHwService.cpp
+++ b/soundtrigger/ISoundTriggerHwService.cpp
@@ -82,7 +82,7 @@
Parcel data, reply;
data.writeInterfaceToken(ISoundTriggerHwService::getInterfaceDescriptor());
data.write(&handle, sizeof(sound_trigger_module_handle_t));
- data.writeStrongBinder(client->asBinder());
+ data.writeStrongBinder(IInterface::asBinder(client));
remote()->transact(ATTACH, data, &reply);
status_t status = reply.readInt32();
if (reply.readInt32() != 0) {
@@ -147,7 +147,7 @@
reply->writeInt32(status);
if (module != 0) {
reply->writeInt32(1);
- reply->writeStrongBinder(module->asBinder());
+ reply->writeStrongBinder(IInterface::asBinder(module));
} else {
reply->writeInt32(0);
}
diff --git a/soundtrigger/SoundTrigger.cpp b/soundtrigger/SoundTrigger.cpp
index 0015c30..2138cb7 100644
--- a/soundtrigger/SoundTrigger.cpp
+++ b/soundtrigger/SoundTrigger.cpp
@@ -104,7 +104,7 @@
status_t status = service->attach(module, soundTrigger, soundTrigger->mISoundTrigger);
if (status == NO_ERROR && soundTrigger->mISoundTrigger != 0) {
- soundTrigger->mISoundTrigger->asBinder()->linkToDeath(soundTrigger);
+ IInterface::asBinder(soundTrigger->mISoundTrigger)->linkToDeath(soundTrigger);
} else {
ALOGW("Error %d connecting to sound trigger service", status);
soundTrigger.clear();
@@ -144,7 +144,7 @@
mCallback.clear();
if (mISoundTrigger != 0) {
mISoundTrigger->detach();
- mISoundTrigger->asBinder()->unlinkToDeath(this);
+ IInterface::asBinder(mISoundTrigger)->unlinkToDeath(this);
mISoundTrigger = 0;
}
}
diff --git a/tools/resampler_tools/Android.mk b/tools/resampler_tools/Android.mk
index e8cbe39..b58e4cd 100644
--- a/tools/resampler_tools/Android.mk
+++ b/tools/resampler_tools/Android.mk
@@ -1,6 +1,6 @@
# Copyright 2005 The Android Open Source Project
#
-# Android.mk for resampler_tools
+# Android.mk for resampler_tools
#
diff --git a/tools/resampler_tools/fir.cpp b/tools/resampler_tools/fir.cpp
index 62eddca..fe4d212 100644
--- a/tools/resampler_tools/fir.cpp
+++ b/tools/resampler_tools/fir.cpp
@@ -66,19 +66,20 @@
static void usage(char* name) {
fprintf(stderr,
- "usage: %s [-h] [-d] [-s sample_rate] [-c cut-off_frequency] [-n half_zero_crossings]"
+ "usage: %s [-h] [-d] [-D] [-s sample_rate] [-c cut-off_frequency] [-n half_zero_crossings]"
" [-f {float|fixed|fixed16}] [-b beta] [-v dBFS] [-l lerp]\n"
- " %s [-h] [-d] [-s sample_rate] [-c cut-off_frequency] [-n half_zero_crossings]"
+ " %s [-h] [-d] [-D] [-s sample_rate] [-c cut-off_frequency] [-n half_zero_crossings]"
" [-f {float|fixed|fixed16}] [-b beta] [-v dBFS] -p M/N\n"
" -h this help message\n"
" -d debug, print comma-separated coefficient table\n"
+ " -D generate extra declarations\n"
" -p generate poly-phase filter coefficients, with sample increment M/N\n"
" -s sample rate (48000)\n"
" -c cut-off frequency (20478)\n"
" -n number of zero-crossings on one side (8)\n"
" -l number of lerping bits (4)\n"
" -m number of polyphases (related to -l, default 16)\n"
- " -f output format, can be fixed-point or floating-point (fixed)\n"
+ " -f output format, can be fixed, fixed16, or float (fixed)\n"
" -b kaiser window parameter beta (7.865 [-80dB])\n"
" -v attenuation in dBFS (0)\n",
name, name
@@ -97,7 +98,8 @@
double Fs = 48000;
double Fc = 20478;
double atten = 1;
- int format = 0;
+ int format = 0; // 0=fixed, 1=float
+ bool declarations = false;
// in order to keep the errors associated with the linear
// interpolation of the coefficients below the quantization error
@@ -158,11 +160,14 @@
int M = 1 << 4; // number of phases for interpolation
int ch;
- while ((ch = getopt(argc, argv, ":hds:c:n:f:l:m:b:p:v:z:")) != -1) {
+ while ((ch = getopt(argc, argv, ":hds:c:n:f:l:m:b:p:v:z:D")) != -1) {
switch (ch) {
case 'd':
debug = true;
break;
+ case 'D':
+ declarations = true;
+ break;
case 'p':
if (sscanf(optarg, "%u/%u", &polyM, &polyN) != 2) {
usage(argv[0]);
@@ -225,24 +230,26 @@
for (int i = M-1 ; i; i>>=1, nz++);
// generate the right half of the filter
if (!debug) {
- printf("// cmd-line: ");
- for (int i=1 ; i<argc ; i++) {
- printf("%s ", argv[i]);
+ printf("// cmd-line:");
+ for (int i=0 ; i<argc ; i++) {
+ printf(" %s", argv[i]);
}
printf("\n");
- if (!polyphase) {
- printf("const int32_t RESAMPLE_FIR_SIZE = %d;\n", N);
- printf("const int32_t RESAMPLE_FIR_INT_PHASES = %d;\n", M);
- printf("const int32_t RESAMPLE_FIR_NUM_COEF = %d;\n", nzc);
- } else {
- printf("const int32_t RESAMPLE_FIR_SIZE = %d;\n", 2*nzc*polyN);
- printf("const int32_t RESAMPLE_FIR_NUM_COEF = %d;\n", 2*nzc);
+ if (declarations) {
+ if (!polyphase) {
+ printf("const int32_t RESAMPLE_FIR_SIZE = %d;\n", N);
+ printf("const int32_t RESAMPLE_FIR_INT_PHASES = %d;\n", M);
+ printf("const int32_t RESAMPLE_FIR_NUM_COEF = %d;\n", nzc);
+ } else {
+ printf("const int32_t RESAMPLE_FIR_SIZE = %d;\n", 2*nzc*polyN);
+ printf("const int32_t RESAMPLE_FIR_NUM_COEF = %d;\n", 2*nzc);
+ }
+ if (!format) {
+ printf("const int32_t RESAMPLE_FIR_COEF_BITS = %d;\n", nc);
+ }
+ printf("\n");
+ printf("static %s resampleFIR[] = {", !format ? "int32_t" : "float");
}
- if (!format) {
- printf("const int32_t RESAMPLE_FIR_COEF_BITS = %d;\n", nc);
- }
- printf("\n");
- printf("static %s resampleFIR[] = {", !format ? "int32_t" : "float");
}
if (!polyphase) {
@@ -260,12 +267,15 @@
if (!format) {
int64_t yi = toint(y, 1ULL<<(nc-1));
if (nc > 16) {
- printf("0x%08x, ", int32_t(yi));
+ printf("0x%08x,", int32_t(yi));
} else {
- printf("0x%04x, ", int32_t(yi)&0xffff);
+ printf("0x%04x,", int32_t(yi)&0xffff);
}
} else {
- printf("%.9g%s ", y, debug ? "," : "f,");
+ printf("%.9g%s", y, debug ? "," : "f,");
+ }
+ if (j != nzc-1) {
+ printf(" ");
}
}
}
@@ -283,23 +293,22 @@
if (!format) {
int64_t yi = toint(y, 1ULL<<(nc-1));
if (nc > 16) {
- printf("0x%08x, ", int32_t(yi));
+ printf("0x%08x,", int32_t(yi));
} else {
- printf("0x%04x, ", int32_t(yi)&0xffff);
+ printf("0x%04x,", int32_t(yi)&0xffff);
}
} else {
- printf("%.9g%s", y, debug ? "" : "f");
+ printf("%.9g%s", y, debug ? "," : "f,");
}
- if (debug && (i==nzc-1)) {
- } else {
- printf(", ");
+ if (i != nzc-1) {
+ printf(" ");
}
}
}
}
- if (!debug) {
+ if (!debug && declarations) {
printf("\n};");
}
printf("\n");