Merge "AAC encoder: handle missing object types" into klp-dev
diff --git a/camera/camera2/ICameraDeviceUser.cpp b/camera/camera2/ICameraDeviceUser.cpp
index 923f487..1e5822f 100644
--- a/camera/camera2/ICameraDeviceUser.cpp
+++ b/camera/camera2/ICameraDeviceUser.cpp
@@ -41,6 +41,20 @@
CREATE_DEFAULT_REQUEST,
GET_CAMERA_INFO,
WAIT_UNTIL_IDLE,
+ FLUSH
+};
+
+namespace {
+ // Read empty strings without printing a false error message.
+ String16 readMaybeEmptyString16(const Parcel& parcel) {
+ size_t len;
+ const char16_t* str = parcel.readString16Inplace(&len);
+ if (str != NULL) {
+ return String16(str, len);
+ } else {
+ return String16();
+ }
+ }
};
class BpCameraDeviceUser : public BpInterface<ICameraDeviceUser>
@@ -183,6 +197,16 @@
return reply.readInt32();
}
+ virtual status_t flush()
+ {
+ ALOGV("flush");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+ remote()->transact(FLUSH, data, &reply);
+ reply.readExceptionCode();
+ return reply.readInt32();
+ }
+
private:
@@ -250,7 +274,7 @@
sp<IGraphicBufferProducer> bp;
if (data.readInt32() != 0) {
- String16 name = data.readString16();
+ String16 name = readMaybeEmptyString16(data);
bp = interface_cast<IGraphicBufferProducer>(
data.readStrongBinder());
@@ -312,6 +336,12 @@
reply->writeInt32(waitUntilIdle());
return NO_ERROR;
} break;
+ case FLUSH: {
+ CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+ reply->writeNoException();
+ reply->writeInt32(flush());
+ return NO_ERROR;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index 3f8567c..d027ba9 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -21,6 +21,7 @@
#include <binder/IPCThreadState.h>
#include <utils/Errors.h>
#include <utils/Thread.h>
+#include <utils/Timers.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
@@ -35,6 +36,8 @@
#include <media/stagefright/MediaMuxer.h>
#include <media/ICrypto.h>
+#include <stdlib.h>
+#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
@@ -42,6 +45,12 @@
using namespace android;
+static const uint32_t kMinBitRate = 100000; // 0.1Mbps
+static const uint32_t kMaxBitRate = 100 * 1000000; // 100Mbps
+static const uint32_t kMaxTimeLimitSec = 180; // 3 minutes
+static const uint32_t kFallbackWidth = 1280; // 720p
+static const uint32_t kFallbackHeight = 720;
+
// Command-line parameters.
static bool gVerbose = false; // chatty on stdout
static bool gRotate = false; // rotate 90 degrees
@@ -49,6 +58,7 @@
static uint32_t gVideoWidth = 0; // default width+height
static uint32_t gVideoHeight = 0;
static uint32_t gBitRate = 4000000; // 4Mbps
+static uint32_t gTimeLimitSec = kMaxTimeLimitSec;
// Set by signal handler to stop recording.
static bool gStopRequested;
@@ -57,8 +67,6 @@
static struct sigaction gOrigSigactionINT;
static struct sigaction gOrigSigactionHUP;
-static const uint32_t kMinBitRate = 100000; // 0.1Mbps
-static const uint32_t kMaxBitRate = 100 * 1000000; // 100Mbps
/*
* Catch keyboard interrupt signals. On receipt, the "stop requested"
@@ -70,9 +78,8 @@
gStopRequested = true;
switch (signum) {
case SIGINT:
- sigaction(SIGINT, &gOrigSigactionINT, NULL);
- break;
case SIGHUP:
+ sigaction(SIGINT, &gOrigSigactionINT, NULL);
sigaction(SIGHUP, &gOrigSigactionHUP, NULL);
break;
default:
@@ -138,7 +145,6 @@
format->setFloat("frame-rate", displayFps);
format->setInt32("i-frame-interval", 10);
- /// MediaCodec
sp<ALooper> looper = new ALooper;
looper->setName("screenrecord_looper");
looper->start();
@@ -279,7 +285,8 @@
status_t err;
ssize_t trackIdx = -1;
uint32_t debugNumFrames = 0;
- time_t debugStartWhen = time(NULL);
+ int64_t startWhenNsec = systemTime(CLOCK_MONOTONIC);
+ int64_t endWhenNsec = startWhenNsec + seconds_to_nanoseconds(gTimeLimitSec);
Vector<sp<ABuffer> > buffers;
err = encoder->getOutputBuffers(&buffers);
@@ -296,6 +303,14 @@
size_t bufIndex, offset, size;
int64_t ptsUsec;
uint32_t flags;
+
+ if (systemTime(CLOCK_MONOTONIC) > endWhenNsec) {
+ if (gVerbose) {
+ printf("Time limit reached\n");
+ }
+ break;
+ }
+
ALOGV("Calling dequeueOutputBuffer");
err = encoder->dequeueOutputBuffer(&bufIndex, &offset, &size, &ptsUsec,
&flags, kTimeout);
@@ -345,7 +360,6 @@
}
break;
case -EAGAIN: // INFO_TRY_AGAIN_LATER
- // not expected with infinite timeout
ALOGV("Got -EAGAIN, looping");
break;
case INFO_FORMAT_CHANGED: // INFO_OUTPUT_FORMAT_CHANGED
@@ -370,18 +384,24 @@
if (err != NO_ERROR) {
fprintf(stderr,
"Unable to get new output buffers (err=%d)\n", err);
+ return err;
}
break;
+ case INVALID_OPERATION:
+ fprintf(stderr, "Request for encoder buffer failed\n");
+ return err;
default:
- ALOGW("Got weird result %d from dequeueOutputBuffer", err);
+ fprintf(stderr,
+ "Got weird result %d from dequeueOutputBuffer\n", err);
return err;
}
}
ALOGV("Encoder stopping (req=%d)", gStopRequested);
if (gVerbose) {
- printf("Encoder stopping; recorded %u frames in %ld seconds\n",
- debugNumFrames, time(NULL) - debugStartWhen);
+ printf("Encoder stopping; recorded %u frames in %lld seconds\n",
+ debugNumFrames,
+ nanoseconds_to_seconds(systemTime(CLOCK_MONOTONIC) - startWhenNsec));
}
return NO_ERROR;
}
@@ -432,12 +452,12 @@
sp<IGraphicBufferProducer> bufferProducer;
err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer);
if (err != NO_ERROR && !gSizeSpecified) {
- ALOGV("Retrying with 720p");
- if (gVideoWidth != 1280 && gVideoHeight != 720) {
+ if (gVideoWidth != kFallbackWidth && gVideoHeight != kFallbackHeight) {
+ ALOGV("Retrying with 720p");
fprintf(stderr, "WARNING: failed at %dx%d, retrying at 720p\n",
gVideoWidth, gVideoHeight);
- gVideoWidth = 1280;
- gVideoHeight = 720;
+ gVideoWidth = kFallbackWidth;
+ gVideoHeight = kFallbackHeight;
err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer);
}
}
@@ -477,6 +497,29 @@
}
/*
+ * Sends a broadcast to the media scanner to tell it about the new video.
+ */
+static status_t notifyMediaScanner(const char* fileName) {
+ String8 command("am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file://");
+ command.append(fileName);
+ if (gVerbose) {
+ printf("Shell: %s\n", command.string());
+ }
+
+ // TODO: for non-verbose mode we should suppress stdout
+ int status = system(command.string());
+ if (status < 0) {
+ fprintf(stderr, "Unable to fork shell for media scanner broadcast\n");
+ return UNKNOWN_ERROR;
+ } else if (status != 0) {
+ fprintf(stderr, "am command failed (status=%d): '%s'\n",
+ status, command.string());
+ return UNKNOWN_ERROR;
+ }
+ return NO_ERROR;
+}
+
+/*
* Parses a string of the form "1280x720".
*
* Returns true on success.
@@ -514,10 +557,13 @@
"\n"
"Options:\n"
"--size WIDTHxHEIGHT\n"
- " Set the video size, e.g. \"1280x720\". For best results, use\n"
- " a size supported by the AVC encoder.\n"
+ " Set the video size, e.g. \"1280x720\". Default is the device's main\n"
+ " display resolution (if supported), 1280x720 if not. For best results,\n"
+ " use a size supported by the AVC encoder.\n"
"--bit-rate RATE\n"
- " Set the video bit rate, in megabits per second. Default 4Mbps.\n"
+ " Set the video bit rate, in megabits per second. Default %dMbps.\n"
+ "--time-limit TIME\n"
+ " Set the maximum recording time, in seconds. Default / maximum is %d.\n"
"--rotate\n"
" Rotate the output 90 degrees.\n"
"--verbose\n"
@@ -525,8 +571,9 @@
"--help\n"
" Show this message.\n"
"\n"
- "Recording continues until Ctrl-C is hit.\n"
- "\n"
+ "Recording continues until Ctrl-C is hit or the time limit is reached.\n"
+ "\n",
+ gBitRate / 1000000, gTimeLimitSec
);
}
@@ -539,6 +586,7 @@
{ "verbose", no_argument, NULL, 'v' },
{ "size", required_argument, NULL, 's' },
{ "bit-rate", required_argument, NULL, 'b' },
+ { "time-limit", required_argument, NULL, 't' },
{ "rotate", no_argument, NULL, 'r' },
{ NULL, 0, NULL, 0 }
};
@@ -580,6 +628,15 @@
return 2;
}
break;
+ case 't':
+ gTimeLimitSec = atoi(optarg);
+ if (gTimeLimitSec == 0 || gTimeLimitSec > kMaxTimeLimitSec) {
+ fprintf(stderr,
+ "Time limit %ds outside acceptable range [1,%d]\n",
+ gTimeLimitSec, kMaxTimeLimitSec);
+ return 2;
+ }
+ break;
case 'r':
gRotate = true;
break;
@@ -609,6 +666,10 @@
close(fd);
status_t err = recordScreen(fileName);
+ if (err == NO_ERROR) {
+ // Try to notify the media scanner. Not fatal if this fails.
+ notifyMediaScanner(fileName);
+ }
ALOGD(err == NO_ERROR ? "success" : "failed");
return (int) err;
}
diff --git a/drm/common/DrmInfoEvent.cpp b/drm/common/DrmInfoEvent.cpp
index 2315aa9..27a5a2d 100644
--- a/drm/common/DrmInfoEvent.cpp
+++ b/drm/common/DrmInfoEvent.cpp
@@ -16,29 +16,16 @@
#include <utils/String8.h>
#include <drm/DrmInfoEvent.h>
-#include <stdlib.h>
using namespace android;
DrmInfoEvent::DrmInfoEvent(int uniqueId, int infoType, const String8 message)
: mUniqueId(uniqueId),
mInfoType(infoType),
- mMessage(message),
- mDrmBuffer() {
+ mMessage(message) {
}
-DrmInfoEvent::DrmInfoEvent(int uniqueId, int infoType, const String8 message,
- const DrmBuffer& drmBuffer)
- : mUniqueId(uniqueId), mInfoType(infoType), mMessage(message), mDrmBuffer() {
- setData(drmBuffer);
-}
-
-DrmInfoEvent::~DrmInfoEvent() {
- delete [] mDrmBuffer.data;
-}
-
-
int DrmInfoEvent::getUniqueId() const {
return mUniqueId;
}
@@ -51,80 +38,3 @@
return mMessage;
}
-int DrmInfoEvent::getCount() const {
- return mAttributes.size();
-}
-
-status_t DrmInfoEvent::put(const String8& key, String8& value) {
- mAttributes.add(key, value);
- return DRM_NO_ERROR;
-}
-
-const String8 DrmInfoEvent::get(const String8& key) const {
- if (mAttributes.indexOfKey(key) != NAME_NOT_FOUND) {
- return mAttributes.valueFor(key);
- }
- return String8("");
-}
-
-const DrmBuffer& DrmInfoEvent::getData() const {
- return mDrmBuffer;
-}
-
-void DrmInfoEvent::setData(const DrmBuffer& drmBuffer) {
- delete [] mDrmBuffer.data;
- mDrmBuffer.data = new char[drmBuffer.length];;
- mDrmBuffer.length = drmBuffer.length;
- memcpy(mDrmBuffer.data, drmBuffer.data, drmBuffer.length);
-}
-
-DrmInfoEvent::KeyIterator DrmInfoEvent::keyIterator() const {
- return KeyIterator(this);
-}
-
-DrmInfoEvent::Iterator DrmInfoEvent::iterator() const {
- return Iterator(this);
-}
-
-// KeyIterator implementation
-DrmInfoEvent::KeyIterator::KeyIterator(const DrmInfoEvent::KeyIterator& keyIterator)
- : mDrmInfoEvent(keyIterator.mDrmInfoEvent), mIndex(keyIterator.mIndex) {
-}
-
-bool DrmInfoEvent::KeyIterator::hasNext() {
- return (mIndex < mDrmInfoEvent->mAttributes.size());
-}
-
-const String8& DrmInfoEvent::KeyIterator::next() {
- const String8& key = mDrmInfoEvent->mAttributes.keyAt(mIndex);
- mIndex++;
- return key;
-}
-
-DrmInfoEvent::KeyIterator& DrmInfoEvent::KeyIterator::operator=(
- const DrmInfoEvent::KeyIterator& keyIterator) {
- mDrmInfoEvent = keyIterator.mDrmInfoEvent;
- mIndex = keyIterator.mIndex;
- return *this;
-}
-
-// Iterator implementation
-DrmInfoEvent::Iterator::Iterator(const DrmInfoEvent::Iterator& iterator)
- : mDrmInfoEvent(iterator.mDrmInfoEvent), mIndex(iterator.mIndex) {
-}
-
-DrmInfoEvent::Iterator& DrmInfoEvent::Iterator::operator=(const DrmInfoEvent::Iterator& iterator) {
- mDrmInfoEvent = iterator.mDrmInfoEvent;
- mIndex = iterator.mIndex;
- return *this;
-}
-
-bool DrmInfoEvent::Iterator::hasNext() {
- return mIndex < mDrmInfoEvent->mAttributes.size();
-}
-
-const String8& DrmInfoEvent::Iterator::next() {
- const String8& value = mDrmInfoEvent->mAttributes.editValueAt(mIndex);
- mIndex++;
- return value;
-}
diff --git a/drm/common/IDrmServiceListener.cpp b/drm/common/IDrmServiceListener.cpp
index d825afb..6eeea40 100644
--- a/drm/common/IDrmServiceListener.cpp
+++ b/drm/common/IDrmServiceListener.cpp
@@ -32,19 +32,6 @@
data.writeInt32(event.getType());
data.writeString8(event.getMessage());
- data.writeInt32(event.getCount());
- DrmInfoEvent::KeyIterator keyIt = event.keyIterator();
- while (keyIt.hasNext()) {
- String8 key = keyIt.next();
- data.writeString8(key);
- data.writeString8(event.get(key));
- }
- const DrmBuffer& value = event.getData();
- data.writeInt32(value.length);
- if (value.length > 0) {
- data.write(value.data, value.length);
- }
-
remote()->transact(NOTIFY, data, &reply);
return reply.readInt32();
}
@@ -62,24 +49,7 @@
int type = data.readInt32();
const String8& message = data.readString8();
- DrmInfoEvent event(uniqueId, type, message);
- int size = data.readInt32();
- for (int index = 0; index < size; index++) {
- String8 key(data.readString8());
- String8 value(data.readString8());
- event.put(key, value);
- }
- int valueSize = data.readInt32();
- if (valueSize > 0) {
- char* valueData = new char[valueSize];
- data.read(valueData, valueSize);
- DrmBuffer drmBuffer(valueData, valueSize);
- event.setData(drmBuffer);
- delete[] valueData;
- }
-
- status_t status = notify(event);
-
+ status_t status = notify(DrmInfoEvent(uniqueId, type, message));
reply->writeInt32(status);
return DRM_NO_ERROR;
diff --git a/drm/mediadrm/plugins/mock/Android.mk b/drm/mediadrm/plugins/mock/Android.mk
deleted file mode 100644
index ada23a2..0000000
--- a/drm/mediadrm/plugins/mock/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- MockDrmCryptoPlugin.cpp
-
-LOCAL_MODULE := libmockdrmcryptoplugin
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_SHARED_LIBRARIES)/mediadrm
-
-LOCAL_SHARED_LIBRARIES := \
- libutils liblog
-
-LOCAL_C_INCLUDES += \
- $(TOP)/frameworks/av/include \
- $(TOP)/frameworks/native/include/media
-
-# Set the following flag to enable the decryption passthru flow
-#LOCAL_CFLAGS += -DENABLE_PASSTHRU_DECRYPTION
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
deleted file mode 100644
index 4770db0..0000000
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
+++ /dev/null
@@ -1,705 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MockDrmCryptoPlugin"
-#include <utils/Log.h>
-
-
-#include "drm/DrmAPI.h"
-#include "MockDrmCryptoPlugin.h"
-#include "media/stagefright/MediaErrors.h"
-
-using namespace android;
-
-// Shared library entry point
-DrmFactory *createDrmFactory()
-{
- return new MockDrmFactory();
-}
-
-// Shared library entry point
-CryptoFactory *createCryptoFactory()
-{
- return new MockCryptoFactory();
-}
-
-const uint8_t mock_uuid[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
-
-namespace android {
-
- // MockDrmFactory
- bool MockDrmFactory::isCryptoSchemeSupported(const uint8_t uuid[16])
- {
- return (!memcmp(uuid, mock_uuid, sizeof(uuid)));
- }
-
- bool MockDrmFactory::isContentTypeSupported(const String8 &mimeType)
- {
- if (mimeType != "" && mimeType != "video/mp4") {
- return false;
- }
- return true;
- }
-
- status_t MockDrmFactory::createDrmPlugin(const uint8_t uuid[16], DrmPlugin **plugin)
- {
- *plugin = new MockDrmPlugin();
- return OK;
- }
-
- // MockCryptoFactory
- bool MockCryptoFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) const
- {
- return (!memcmp(uuid, mock_uuid, sizeof(uuid)));
- }
-
- status_t MockCryptoFactory::createPlugin(const uint8_t uuid[16], const void *data,
- size_t size, CryptoPlugin **plugin)
- {
- *plugin = new MockCryptoPlugin();
- return OK;
- }
-
-
- // MockDrmPlugin methods
-
- status_t MockDrmPlugin::openSession(Vector<uint8_t> &sessionId)
- {
- const size_t kSessionIdSize = 8;
-
- Mutex::Autolock lock(mLock);
- for (size_t i = 0; i < kSessionIdSize / sizeof(long); i++) {
- long r = random();
- sessionId.appendArray((uint8_t *)&r, sizeof(long));
- }
- mSessions.add(sessionId);
-
- ALOGD("MockDrmPlugin::openSession() -> %s", vectorToString(sessionId).string());
- return OK;
- }
-
- status_t MockDrmPlugin::closeSession(Vector<uint8_t> const &sessionId)
- {
- Mutex::Autolock lock(mLock);
- ALOGD("MockDrmPlugin::closeSession(%s)", vectorToString(sessionId).string());
- ssize_t index = findSession(sessionId);
- if (index == kNotFound) {
- ALOGD("Invalid sessionId");
- return BAD_VALUE;
- }
- mSessions.removeAt(index);
- return OK;
- }
-
-
- status_t MockDrmPlugin::getKeyRequest(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &initData,
- String8 const &mimeType, KeyType keyType,
- KeyedVector<String8, String8> const &optionalParameters,
- Vector<uint8_t> &request, String8 &defaultUrl)
- {
- Mutex::Autolock lock(mLock);
- ALOGD("MockDrmPlugin::getKeyRequest(sessionId=%s, initData=%s, mimeType=%s"
- ", keyType=%d, optionalParameters=%s))",
- vectorToString(sessionId).string(), vectorToString(initData).string(), mimeType.string(),
- keyType, stringMapToString(optionalParameters).string());
-
- ssize_t index = findSession(sessionId);
- if (index == kNotFound) {
- ALOGD("Invalid sessionId");
- return BAD_VALUE;
- }
-
- // Properties used in mock test, set by mock plugin and verifed cts test app
- // byte[] initData -> mock-initdata
- // string mimeType -> mock-mimetype
- // string keyType -> mock-keytype
- // string optionalParameters -> mock-optparams formatted as {key1,value1},{key2,value2}
-
- mByteArrayProperties.add(String8("mock-initdata"), initData);
- mStringProperties.add(String8("mock-mimetype"), mimeType);
-
- String8 keyTypeStr;
- keyTypeStr.appendFormat("%d", (int)keyType);
- mStringProperties.add(String8("mock-keytype"), keyTypeStr);
-
- String8 params;
- for (size_t i = 0; i < optionalParameters.size(); i++) {
- params.appendFormat("%s{%s,%s}", i ? "," : "",
- optionalParameters.keyAt(i).string(),
- optionalParameters.valueAt(i).string());
- }
- mStringProperties.add(String8("mock-optparams"), params);
-
- // Properties used in mock test, set by cts test app returned from mock plugin
- // byte[] mock-request -> request
- // string mock-default-url -> defaultUrl
-
- index = mByteArrayProperties.indexOfKey(String8("mock-request"));
- if (index < 0) {
- ALOGD("Missing 'mock-request' parameter for mock");
- return BAD_VALUE;
- } else {
- request = mByteArrayProperties.valueAt(index);
- }
-
- index = mStringProperties.indexOfKey(String8("mock-defaultUrl"));
- if (index < 0) {
- ALOGD("Missing 'mock-defaultUrl' parameter for mock");
- return BAD_VALUE;
- } else {
- defaultUrl = mStringProperties.valueAt(index);
- }
- return OK;
- }
-
- status_t MockDrmPlugin::provideKeyResponse(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &response,
- Vector<uint8_t> &keySetId)
- {
- Mutex::Autolock lock(mLock);
- ALOGD("MockDrmPlugin::provideKeyResponse(sessionId=%s, response=%s)",
- vectorToString(sessionId).string(), vectorToString(response).string());
- ssize_t index = findSession(sessionId);
- if (index == kNotFound) {
- ALOGD("Invalid sessionId");
- return BAD_VALUE;
- }
- if (response.size() == 0) {
- return BAD_VALUE;
- }
-
- // Properties used in mock test, set by mock plugin and verifed cts test app
- // byte[] response -> mock-response
- mByteArrayProperties.add(String8("mock-response"), response);
-
- const size_t kKeySetIdSize = 8;
-
- for (size_t i = 0; i < kKeySetIdSize / sizeof(long); i++) {
- long r = random();
- keySetId.appendArray((uint8_t *)&r, sizeof(long));
- }
- mKeySets.add(keySetId);
-
- return OK;
- }
-
- status_t MockDrmPlugin::removeKeys(Vector<uint8_t> const &keySetId)
- {
- Mutex::Autolock lock(mLock);
- ALOGD("MockDrmPlugin::removeKeys(keySetId=%s)",
- vectorToString(keySetId).string());
-
- ssize_t index = findKeySet(keySetId);
- if (index == kNotFound) {
- ALOGD("Invalid keySetId");
- return BAD_VALUE;
- }
- mKeySets.removeAt(index);
-
- return OK;
- }
-
- status_t MockDrmPlugin::restoreKeys(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keySetId)
- {
- Mutex::Autolock lock(mLock);
- ALOGD("MockDrmPlugin::restoreKeys(sessionId=%s, keySetId=%s)",
- vectorToString(sessionId).string(),
- vectorToString(keySetId).string());
- ssize_t index = findSession(sessionId);
- if (index == kNotFound) {
- ALOGD("Invalid sessionId");
- return BAD_VALUE;
- }
-
- index = findKeySet(keySetId);
- if (index == kNotFound) {
- ALOGD("Invalid keySetId");
- return BAD_VALUE;
- }
-
- return OK;
- }
-
- status_t MockDrmPlugin::queryKeyStatus(Vector<uint8_t> const &sessionId,
- KeyedVector<String8, String8> &infoMap) const
- {
- ALOGD("MockDrmPlugin::queryKeyStatus(sessionId=%s)",
- vectorToString(sessionId).string());
-
- ssize_t index = findSession(sessionId);
- if (index == kNotFound) {
- ALOGD("Invalid sessionId");
- return BAD_VALUE;
- }
-
- infoMap.add(String8("purchaseDuration"), String8("1000"));
- infoMap.add(String8("licenseDuration"), String8("100"));
- return OK;
- }
-
- status_t MockDrmPlugin::getProvisionRequest(Vector<uint8_t> &request,
- String8 &defaultUrl)
- {
- Mutex::Autolock lock(mLock);
- ALOGD("MockDrmPlugin::getProvisionRequest()");
-
- // Properties used in mock test, set by cts test app returned from mock plugin
- // byte[] mock-request -> request
- // string mock-default-url -> defaultUrl
-
- ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-request"));
- if (index < 0) {
- ALOGD("Missing 'mock-request' parameter for mock");
- return BAD_VALUE;
- } else {
- request = mByteArrayProperties.valueAt(index);
- }
-
- index = mStringProperties.indexOfKey(String8("mock-defaultUrl"));
- if (index < 0) {
- ALOGD("Missing 'mock-defaultUrl' parameter for mock");
- return BAD_VALUE;
- } else {
- defaultUrl = mStringProperties.valueAt(index);
- }
- return OK;
- }
-
- status_t MockDrmPlugin::provideProvisionResponse(Vector<uint8_t> const &response)
- {
- Mutex::Autolock lock(mLock);
- ALOGD("MockDrmPlugin::provideProvisionResponse(%s)",
- vectorToString(response).string());
-
- // Properties used in mock test, set by mock plugin and verifed cts test app
- // byte[] response -> mock-response
-
- mByteArrayProperties.add(String8("mock-response"), response);
- return OK;
- }
-
- status_t MockDrmPlugin::getSecureStops(List<Vector<uint8_t> > &secureStops)
- {
- Mutex::Autolock lock(mLock);
- ALOGD("MockDrmPlugin::getSecureStops()");
-
- // Properties used in mock test, set by cts test app returned from mock plugin
- // byte[] mock-secure-stop1 -> first secure stop in list
- // byte[] mock-secure-stop2 -> second secure stop in list
-
- Vector<uint8_t> ss1, ss2;
- ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-secure-stop1"));
- if (index < 0) {
- ALOGD("Missing 'mock-secure-stop1' parameter for mock");
- return BAD_VALUE;
- } else {
- ss1 = mByteArrayProperties.valueAt(index);
- }
-
- index = mByteArrayProperties.indexOfKey(String8("mock-secure-stop2"));
- if (index < 0) {
- ALOGD("Missing 'mock-secure-stop2' parameter for mock");
- return BAD_VALUE;
- } else {
- ss2 = mByteArrayProperties.valueAt(index);
- }
-
- secureStops.push_back(ss1);
- secureStops.push_back(ss2);
- return OK;
- }
-
- status_t MockDrmPlugin::releaseSecureStops(Vector<uint8_t> const &ssRelease)
- {
- Mutex::Autolock lock(mLock);
- ALOGD("MockDrmPlugin::releaseSecureStops(%s)",
- vectorToString(ssRelease).string());
-
- // Properties used in mock test, set by mock plugin and verifed cts test app
- // byte[] secure-stop-release -> mock-ssrelease
- mByteArrayProperties.add(String8("mock-ssrelease"), ssRelease);
-
- return OK;
- }
-
- status_t MockDrmPlugin::getPropertyString(String8 const &name, String8 &value) const
- {
- ALOGD("MockDrmPlugin::getPropertyString(name=%s)", name.string());
- ssize_t index = mStringProperties.indexOfKey(name);
- if (index < 0) {
- ALOGD("no property for '%s'", name.string());
- return BAD_VALUE;
- }
- value = mStringProperties.valueAt(index);
- return OK;
- }
-
- status_t MockDrmPlugin::getPropertyByteArray(String8 const &name,
- Vector<uint8_t> &value) const
- {
- ALOGD("MockDrmPlugin::getPropertyByteArray(name=%s)", name.string());
- ssize_t index = mByteArrayProperties.indexOfKey(name);
- if (index < 0) {
- ALOGD("no property for '%s'", name.string());
- return BAD_VALUE;
- }
- value = mByteArrayProperties.valueAt(index);
- return OK;
- }
-
- status_t MockDrmPlugin::setPropertyString(String8 const &name,
- String8 const &value)
- {
- Mutex::Autolock lock(mLock);
- ALOGD("MockDrmPlugin::setPropertyString(name=%s, value=%s)",
- name.string(), value.string());
-
- if (name == "mock-send-event") {
- unsigned code, extra;
- sscanf(value.string(), "%d %d", &code, &extra);
- DrmPlugin::EventType eventType = (DrmPlugin::EventType)code;
-
- Vector<uint8_t> const *pSessionId = NULL;
- ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-event-session-id"));
- if (index >= 0) {
- pSessionId = &mByteArrayProperties[index];
- }
-
- Vector<uint8_t> const *pData = NULL;
- index = mByteArrayProperties.indexOfKey(String8("mock-event-data"));
- if (index >= 0) {
- pData = &mByteArrayProperties[index];
- }
- ALOGD("sending event from mock drm plugin: %d %d %s %s",
- (int)code, extra, pSessionId ? vectorToString(*pSessionId) : "{}",
- pData ? vectorToString(*pData) : "{}");
-
- sendEvent(eventType, extra, pSessionId, pData);
- } else {
- mStringProperties.add(name, value);
- }
- return OK;
- }
-
- status_t MockDrmPlugin::setPropertyByteArray(String8 const &name,
- Vector<uint8_t> const &value)
- {
- Mutex::Autolock lock(mLock);
- ALOGD("MockDrmPlugin::setPropertyByteArray(name=%s, value=%s)",
- name.string(), vectorToString(value).string());
- mByteArrayProperties.add(name, value);
- return OK;
- }
-
- status_t MockDrmPlugin::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
- String8 const &algorithm)
- {
- Mutex::Autolock lock(mLock);
-
- ALOGD("MockDrmPlugin::setCipherAlgorithm(sessionId=%s, algorithm=%s)",
- vectorToString(sessionId).string(), algorithm.string());
-
- ssize_t index = findSession(sessionId);
- if (index == kNotFound) {
- ALOGD("Invalid sessionId");
- return BAD_VALUE;
- }
-
- if (algorithm == "AES/CBC/NoPadding") {
- return OK;
- }
- return BAD_VALUE;
- }
-
- status_t MockDrmPlugin::setMacAlgorithm(Vector<uint8_t> const &sessionId,
- String8 const &algorithm)
- {
- Mutex::Autolock lock(mLock);
-
- ALOGD("MockDrmPlugin::setMacAlgorithm(sessionId=%s, algorithm=%s)",
- vectorToString(sessionId).string(), algorithm.string());
-
- ssize_t index = findSession(sessionId);
- if (index == kNotFound) {
- ALOGD("Invalid sessionId");
- return BAD_VALUE;
- }
-
- if (algorithm == "HmacSHA256") {
- return OK;
- }
- return BAD_VALUE;
- }
-
- status_t MockDrmPlugin::encrypt(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &input,
- Vector<uint8_t> const &iv,
- Vector<uint8_t> &output)
- {
- Mutex::Autolock lock(mLock);
- ALOGD("MockDrmPlugin::encrypt(sessionId=%s, keyId=%s, input=%s, iv=%s)",
- vectorToString(sessionId).string(),
- vectorToString(keyId).string(),
- vectorToString(input).string(),
- vectorToString(iv).string());
-
- ssize_t index = findSession(sessionId);
- if (index == kNotFound) {
- ALOGD("Invalid sessionId");
- return BAD_VALUE;
- }
-
- // Properties used in mock test, set by mock plugin and verifed cts test app
- // byte[] keyId -> mock-keyid
- // byte[] input -> mock-input
- // byte[] iv -> mock-iv
- mByteArrayProperties.add(String8("mock-keyid"), keyId);
- mByteArrayProperties.add(String8("mock-input"), input);
- mByteArrayProperties.add(String8("mock-iv"), iv);
-
- // Properties used in mock test, set by cts test app returned from mock plugin
- // byte[] mock-output -> output
- index = mByteArrayProperties.indexOfKey(String8("mock-output"));
- if (index < 0) {
- ALOGD("Missing 'mock-request' parameter for mock");
- return BAD_VALUE;
- } else {
- output = mByteArrayProperties.valueAt(index);
- }
- return OK;
- }
-
- status_t MockDrmPlugin::decrypt(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &input,
- Vector<uint8_t> const &iv,
- Vector<uint8_t> &output)
- {
- Mutex::Autolock lock(mLock);
- ALOGD("MockDrmPlugin::decrypt(sessionId=%s, keyId=%s, input=%s, iv=%s)",
- vectorToString(sessionId).string(),
- vectorToString(keyId).string(),
- vectorToString(input).string(),
- vectorToString(iv).string());
-
- ssize_t index = findSession(sessionId);
- if (index == kNotFound) {
- ALOGD("Invalid sessionId");
- return BAD_VALUE;
- }
-
- // Properties used in mock test, set by mock plugin and verifed cts test app
- // byte[] keyId -> mock-keyid
- // byte[] input -> mock-input
- // byte[] iv -> mock-iv
- mByteArrayProperties.add(String8("mock-keyid"), keyId);
- mByteArrayProperties.add(String8("mock-input"), input);
- mByteArrayProperties.add(String8("mock-iv"), iv);
-
- // Properties used in mock test, set by cts test app returned from mock plugin
- // byte[] mock-output -> output
- index = mByteArrayProperties.indexOfKey(String8("mock-output"));
- if (index < 0) {
- ALOGD("Missing 'mock-request' parameter for mock");
- return BAD_VALUE;
- } else {
- output = mByteArrayProperties.valueAt(index);
- }
- return OK;
- }
-
- status_t MockDrmPlugin::sign(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &message,
- Vector<uint8_t> &signature)
- {
- Mutex::Autolock lock(mLock);
- ALOGD("MockDrmPlugin::sign(sessionId=%s, keyId=%s, message=%s)",
- vectorToString(sessionId).string(),
- vectorToString(keyId).string(),
- vectorToString(message).string());
-
- ssize_t index = findSession(sessionId);
- if (index == kNotFound) {
- ALOGD("Invalid sessionId");
- return BAD_VALUE;
- }
-
- // Properties used in mock test, set by mock plugin and verifed cts test app
- // byte[] keyId -> mock-keyid
- // byte[] message -> mock-message
- mByteArrayProperties.add(String8("mock-keyid"), keyId);
- mByteArrayProperties.add(String8("mock-message"), message);
-
- // Properties used in mock test, set by cts test app returned from mock plugin
- // byte[] mock-signature -> signature
- index = mByteArrayProperties.indexOfKey(String8("mock-signature"));
- if (index < 0) {
- ALOGD("Missing 'mock-request' parameter for mock");
- return BAD_VALUE;
- } else {
- signature = mByteArrayProperties.valueAt(index);
- }
- return OK;
- }
-
- status_t MockDrmPlugin::verify(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &message,
- Vector<uint8_t> const &signature,
- bool &match)
- {
- Mutex::Autolock lock(mLock);
- ALOGD("MockDrmPlugin::verify(sessionId=%s, keyId=%s, message=%s, signature=%s)",
- vectorToString(sessionId).string(),
- vectorToString(keyId).string(),
- vectorToString(message).string(),
- vectorToString(signature).string());
-
- ssize_t index = findSession(sessionId);
- if (index == kNotFound) {
- ALOGD("Invalid sessionId");
- return BAD_VALUE;
- }
-
- // Properties used in mock test, set by mock plugin and verifed cts test app
- // byte[] keyId -> mock-keyid
- // byte[] message -> mock-message
- // byte[] signature -> mock-signature
- mByteArrayProperties.add(String8("mock-keyid"), keyId);
- mByteArrayProperties.add(String8("mock-message"), message);
- mByteArrayProperties.add(String8("mock-signature"), signature);
-
- // Properties used in mock test, set by cts test app returned from mock plugin
- // String mock-match "1" or "0" -> match
- index = mStringProperties.indexOfKey(String8("mock-match"));
- if (index < 0) {
- ALOGD("Missing 'mock-request' parameter for mock");
- return BAD_VALUE;
- } else {
- match = atol(mStringProperties.valueAt(index).string());
- }
- return OK;
- }
-
- ssize_t MockDrmPlugin::findSession(Vector<uint8_t> const &sessionId) const
- {
- ALOGD("findSession: nsessions=%d, size=%d", mSessions.size(), sessionId.size());
- for (size_t i = 0; i < mSessions.size(); ++i) {
- if (memcmp(mSessions[i].array(), sessionId.array(), sessionId.size()) == 0) {
- return i;
- }
- }
- return kNotFound;
- }
-
- ssize_t MockDrmPlugin::findKeySet(Vector<uint8_t> const &keySetId) const
- {
- ALOGD("findKeySet: nkeySets=%d, size=%d", mKeySets.size(), keySetId.size());
- for (size_t i = 0; i < mKeySets.size(); ++i) {
- if (memcmp(mKeySets[i].array(), keySetId.array(), keySetId.size()) == 0) {
- return i;
- }
- }
- return kNotFound;
- }
-
-
- // Conversion utilities
- String8 MockDrmPlugin::vectorToString(Vector<uint8_t> const &vector) const
- {
- return arrayToString(vector.array(), vector.size());
- }
-
- String8 MockDrmPlugin::arrayToString(uint8_t const *array, size_t len) const
- {
- String8 result("{ ");
- for (size_t i = 0; i < len; i++) {
- result.appendFormat("0x%02x ", array[i]);
- }
- result += "}";
- return result;
- }
-
- String8 MockDrmPlugin::stringMapToString(KeyedVector<String8, String8> map) const
- {
- String8 result("{ ");
- for (size_t i = 0; i < map.size(); i++) {
- result.appendFormat("%s{name=%s, value=%s}", i > 0 ? ", " : "",
- map.keyAt(i).string(), map.valueAt(i).string());
- }
- return result + " }";
- }
-
- bool operator<(Vector<uint8_t> const &lhs, Vector<uint8_t> const &rhs) {
- return lhs.size() < rhs.size() || (memcmp(lhs.array(), rhs.array(), lhs.size()) < 0);
- }
-
- //
- // Crypto Plugin
- //
-
- bool MockCryptoPlugin::requiresSecureDecoderComponent(const char *mime) const
- {
- ALOGD("MockCryptoPlugin::requiresSecureDecoderComponent(mime=%s)", mime);
- return false;
- }
-
- ssize_t
- MockCryptoPlugin::decrypt(bool secure, const uint8_t key[16], const uint8_t iv[16],
- Mode mode, const void *srcPtr, const SubSample *subSamples,
- size_t numSubSamples, void *dstPtr, AString *errorDetailMsg)
- {
- ALOGD("MockCryptoPlugin::decrypt(secure=%d, key=%s, iv=%s, mode=%d, src=%p, "
- "subSamples=%s, dst=%p)",
- (int)secure,
- arrayToString(key, sizeof(key)).string(),
- arrayToString(iv, sizeof(iv)).string(),
- (int)mode, srcPtr,
- subSamplesToString(subSamples, numSubSamples).string(),
- dstPtr);
- return OK;
- }
-
- // Conversion utilities
- String8 MockCryptoPlugin::arrayToString(uint8_t const *array, size_t len) const
- {
- String8 result("{ ");
- for (size_t i = 0; i < len; i++) {
- result.appendFormat("0x%02x ", array[i]);
- }
- result += "}";
- return result;
- }
-
- String8 MockCryptoPlugin::subSamplesToString(SubSample const *subSamples,
- size_t numSubSamples) const
- {
- String8 result;
- for (size_t i = 0; i < numSubSamples; i++) {
- result.appendFormat("[%d] {clear:%d, encrypted:%d} ", i,
- subSamples[i].mNumBytesOfClearData,
- subSamples[i].mNumBytesOfEncryptedData);
- }
- return result;
- }
-
-};
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
deleted file mode 100644
index 2297f9b..0000000
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <utils/Mutex.h>
-
-#include "drm/DrmAPI.h"
-#include "hardware/CryptoAPI.h"
-
-extern "C" {
- android::DrmFactory *createDrmFactory();
- android::CryptoFactory *createCryptoFactory();
-}
-
-namespace android {
-
- class MockDrmFactory : public DrmFactory {
- public:
- MockDrmFactory() {}
- virtual ~MockDrmFactory() {}
-
- bool isCryptoSchemeSupported(const uint8_t uuid[16]);
- bool isContentTypeSupported(const String8 &mimeType);
- status_t createDrmPlugin(const uint8_t uuid[16], DrmPlugin **plugin);
- };
-
- class MockCryptoFactory : public CryptoFactory {
- public:
- MockCryptoFactory() {}
- virtual ~MockCryptoFactory() {}
-
- bool isCryptoSchemeSupported(const uint8_t uuid[16]) const;
- status_t createPlugin(
- const uint8_t uuid[16], const void *data, size_t size,
- CryptoPlugin **plugin);
- };
-
-
-
- class MockDrmPlugin : public DrmPlugin {
- public:
- MockDrmPlugin() {}
- virtual ~MockDrmPlugin() {}
-
- // from DrmPlugin
- status_t openSession(Vector<uint8_t> &sessionId);
- status_t closeSession(Vector<uint8_t> const &sessionId);
-
- status_t getKeyRequest(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &initData,
- String8 const &mimeType, KeyType keyType,
- KeyedVector<String8, String8> const &optionalParameters,
- Vector<uint8_t> &request, String8 &defaultUrl);
-
- status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &response,
- Vector<uint8_t> &keySetId);
-
- status_t removeKeys(Vector<uint8_t> const &keySetId);
-
- status_t restoreKeys(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keySetId);
-
- status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
- KeyedVector<String8, String8> &infoMap) const;
-
- status_t getProvisionRequest(Vector<uint8_t> &request,
- String8 &defaultUrl);
-
- status_t provideProvisionResponse(Vector<uint8_t> const &response);
-
- status_t getSecureStops(List<Vector<uint8_t> > &secureStops);
- status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
-
- status_t getPropertyString(String8 const &name, String8 &value ) const;
- status_t getPropertyByteArray(String8 const &name,
- Vector<uint8_t> &value ) const;
-
- status_t setPropertyString(String8 const &name,
- String8 const &value );
- status_t setPropertyByteArray(String8 const &name,
- Vector<uint8_t> const &value );
-
- status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
- String8 const &algorithm);
-
- status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
- String8 const &algorithm);
-
- status_t encrypt(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &input,
- Vector<uint8_t> const &iv,
- Vector<uint8_t> &output);
-
- status_t decrypt(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &input,
- Vector<uint8_t> const &iv,
- Vector<uint8_t> &output);
-
- status_t sign(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &message,
- Vector<uint8_t> &signature);
-
- status_t verify(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &message,
- Vector<uint8_t> const &signature,
- bool &match);
-
- private:
- String8 vectorToString(Vector<uint8_t> const &vector) const;
- String8 arrayToString(uint8_t const *array, size_t len) const;
- String8 stringMapToString(KeyedVector<String8, String8> map) const;
-
- SortedVector<Vector<uint8_t> > mSessions;
- SortedVector<Vector<uint8_t> > mKeySets;
-
- static const ssize_t kNotFound = -1;
- ssize_t findSession(Vector<uint8_t> const &sessionId) const;
- ssize_t findKeySet(Vector<uint8_t> const &keySetId) const;
-
- Mutex mLock;
- KeyedVector<String8, String8> mStringProperties;
- KeyedVector<String8, Vector<uint8_t> > mByteArrayProperties;
- };
-
-
- class MockCryptoPlugin : public CryptoPlugin {
-
- bool requiresSecureDecoderComponent(const char *mime) const;
-
- ssize_t decrypt(bool secure,
- const uint8_t key[16], const uint8_t iv[16],
- Mode mode, const void *srcPtr,
- const SubSample *subSamples, size_t numSubSamples,
- void *dstPtr, AString *errorDetailMsg);
- private:
- String8 subSamplesToString(CryptoPlugin::SubSample const *subSamples, size_t numSubSamples) const;
- String8 arrayToString(uint8_t const *array, size_t len) const;
- };
-};
diff --git a/include/camera/camera2/ICameraDeviceUser.h b/include/camera/camera2/ICameraDeviceUser.h
index 45988d0..f71f302 100644
--- a/include/camera/camera2/ICameraDeviceUser.h
+++ b/include/camera/camera2/ICameraDeviceUser.h
@@ -63,6 +63,9 @@
// Wait until all the submitted requests have finished processing
virtual status_t waitUntilIdle() = 0;
+
+ // Flush all pending and in-progress work as quickly as possible.
+ virtual status_t flush() = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/drm/DrmInfoEvent.h b/include/drm/DrmInfoEvent.h
index 23b2950..dfca228 100644
--- a/include/drm/DrmInfoEvent.h
+++ b/include/drm/DrmInfoEvent.h
@@ -17,8 +17,6 @@
#ifndef __DRM_INFO_EVENT_H__
#define __DRM_INFO_EVENT_H__
-#include "drm_framework_common.h"
-
namespace android {
class String8;
@@ -73,70 +71,18 @@
public:
/**
- * Constructor for DrmInfoEvent.
- * Data in drmBuffer are copied to newly allocated buffer.
+ * Constructor for DrmInfoEvent
*
* @param[in] uniqueId Unique session identifier
* @param[in] infoType Type of information
* @param[in] message Message description
- * @param[in] drmBuffer Binary information
*/
DrmInfoEvent(int uniqueId, int infoType, const String8 message);
- DrmInfoEvent(int uniqueId, int infoType, const String8 message, const DrmBuffer& drmBuffer);
/**
* Destructor for DrmInfoEvent
*/
- ~DrmInfoEvent();
-
-public:
- /**
- * Iterator for key
- */
- class KeyIterator {
- friend class DrmInfoEvent;
-
- private:
- KeyIterator(const DrmInfoEvent* drmInfoEvent)
- : mDrmInfoEvent(const_cast <DrmInfoEvent*> (drmInfoEvent)), mIndex(0) {}
-
- public:
- KeyIterator(const KeyIterator& keyIterator);
- KeyIterator& operator=(const KeyIterator& keyIterator);
- virtual ~KeyIterator() {}
-
- public:
- bool hasNext();
- const String8& next();
-
- private:
- DrmInfoEvent* mDrmInfoEvent;
- unsigned int mIndex;
- };
-
- /**
- * Iterator
- */
- class Iterator {
- friend class DrmInfoEvent;
-
- private:
- Iterator(const DrmInfoEvent* drmInfoEvent)
- : mDrmInfoEvent(const_cast <DrmInfoEvent*> (drmInfoEvent)), mIndex(0) {}
-
- public:
- Iterator(const Iterator& iterator);
- Iterator& operator=(const Iterator& iterator);
- virtual ~Iterator() {}
-
- public:
- bool hasNext();
- const String8& next();
-
- private:
- DrmInfoEvent* mDrmInfoEvent;
- unsigned int mIndex;
- };
+ virtual ~DrmInfoEvent() {}
public:
/**
@@ -160,69 +106,10 @@
*/
const String8 getMessage() const;
- /**
- * Returns the number of attributes contained in this instance
- *
- * @return Number of attributes
- */
- int getCount() const;
-
- /**
- * Adds optional information as <key, value> pair to this instance
- *
- * @param[in] key Key to add
- * @param[in] value Value to add
- * @return Returns the error code
- */
- status_t put(const String8& key, String8& value);
-
- /**
- * Retrieves the value of given key
- *
- * @param key Key whose value to be retrieved
- * @return The value
- */
- const String8 get(const String8& key) const;
-
- /**
- * Returns KeyIterator object to walk through the keys associated with this instance
- *
- * @return KeyIterator object
- */
- KeyIterator keyIterator() const;
-
- /**
- * Returns Iterator object to walk through the values associated with this instance
- *
- * @return Iterator object
- */
- Iterator iterator() const;
-
- /**
- * Returns the Binary information associated with this instance
- *
- * @return Binary information
- */
- const DrmBuffer& getData() const;
-
- /**
- * Sets the Binary information associated with this instance.
- * Data in drmBuffer are copied to newly allocated buffer.
- *
- * @param[in] drmBuffer Binary information associated with this instance
- */
- void setData(const DrmBuffer& drmBuffer);
-
-private:
- DrmInfoEvent(const DrmInfoEvent& ref);
- const DrmInfoEvent& operator=(const DrmInfoEvent& ref);
-
private:
int mUniqueId;
int mInfoType;
const String8 mMessage;
- KeyedVector<String8, String8> mAttributes;
- DrmBuffer mDrmBuffer;
};
};
diff --git a/include/media/AudioTimestamp.h b/include/media/AudioTimestamp.h
new file mode 100644
index 0000000..c29c7e5
--- /dev/null
+++ b/include/media/AudioTimestamp.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_TIMESTAMP_H
+#define ANDROID_AUDIO_TIMESTAMP_H
+
+#include <time.h>
+
+class AudioTimestamp {
+public:
+ AudioTimestamp() : mPosition(0) {
+ mTime.tv_sec = 0;
+ mTime.tv_nsec = 0;
+ }
+ // FIXME change type to match android.media.AudioTrack
+ uint32_t mPosition; // a frame position in AudioTrack::getPosition() units
+ struct timespec mTime; // corresponding CLOCK_MONOTONIC when frame is expected to present
+};
+
+#endif // ANDROID_AUDIO_TIMESTAMP_H
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index ae92cdd..453c106 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -19,6 +19,7 @@
#include <cutils/sched_policy.h>
#include <media/AudioSystem.h>
+#include <media/AudioTimestamp.h>
#include <media/IAudioTrack.h>
#include <utils/threads.h>
@@ -62,6 +63,9 @@
// voluntary invalidation by mediaserver, or mediaserver crash.
EVENT_STREAM_END = 7, // Sent after all the buffers queued in AF and HW are played
// back (after stop is called)
+ EVENT_NEW_TIMESTAMP = 8, // Delivered periodically and when there's a significant change
+ // in the mapping from frame position to presentation time.
+ // See AudioTimestamp for the information included with event.
};
/* Client should declare Buffer on the stack and pass address to obtainBuffer()
@@ -107,6 +111,8 @@
* - EVENT_NEW_POS: pointer to const uint32_t containing the new position in frames.
* - EVENT_BUFFER_END: unused.
* - EVENT_NEW_IAUDIOTRACK: unused.
+ * - EVENT_STREAM_END: unused.
+ * - EVENT_NEW_TIMESTAMP: pointer to const AudioTimestamp.
*/
typedef void (*callback_t)(int event, void* user, void *info);
@@ -221,6 +227,7 @@
* - INVALID_OPERATION: AudioTrack is already initialized
* - BAD_VALUE: invalid parameter (channelMask, format, sampleRate...)
* - NO_INIT: audio server or audio hardware not initialized
+ * If status is not equal to NO_ERROR, don't call any other APIs on this AudioTrack.
* If sharedBuffer is non-0, the frameCount parameter is ignored and
* replaced by the shared buffer's total allocated size in frame units.
*
@@ -243,7 +250,7 @@
transfer_type transferType = TRANSFER_DEFAULT,
const audio_offload_info_t *offloadInfo = NULL);
- /* Result of constructing the AudioTrack. This must be checked
+ /* Result of constructing the AudioTrack. This must be checked for successful initialization
* before using any AudioTrack API (except for set()), because using
* an uninitialized AudioTrack produces undefined results.
* See set() method above for possible return codes.
@@ -564,6 +571,16 @@
/* Get parameters */
String8 getParameters(const String8& keys);
+ /* Poll for a timestamp on demand.
+ * Use if EVENT_NEW_TIMESTAMP is not delivered often enough for your needs,
+ * or if you need to get the most recent timestamp outside of the event callback handler.
+ * Caution: calling this method too often may be inefficient;
+ * if you need a high resolution mapping between frame position and presentation time,
+ * consider implementing that at application level, based on the low resolution timestamps.
+ * Returns NO_ERROR if timestamp is valid.
+ */
+ status_t getTimestamp(AudioTimestamp& timestamp);
+
protected:
/* copying audio tracks is not allowed */
AudioTrack(const AudioTrack& other);
@@ -630,7 +647,7 @@
bool isOffloaded() const
{ return (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0; }
- // may be changed if IAudioTrack is re-created
+ // Next 3 fields may be changed if IAudioTrack is re-created, but always != 0
sp<IAudioTrack> mAudioTrack;
sp<IMemory> mCblkMemory;
audio_track_cblk_t* mCblk; // re-load after mLock.unlock()
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index 1014403..afac4ae 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -26,6 +26,7 @@
#include <binder/IMemory.h>
#include <utils/LinearTransform.h>
#include <utils/String8.h>
+#include <media/AudioTimestamp.h>
namespace android {
@@ -86,6 +87,9 @@
/* Send parameters to the audio hardware */
virtual status_t setParameters(const String8& keyValuePairs) = 0;
+
+ /* Return NO_ERROR if timestamp is valid */
+ virtual status_t getTimestamp(AudioTimestamp& timestamp) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 1379379..ad7409d 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -422,6 +422,9 @@
// Return the total number of frames which AudioFlinger desired but were unavailable,
// and thus which resulted in an underrun.
virtual uint32_t getUnderrunFrames() const { return mCblk->u.mStreaming.mUnderrunFrames; }
+
+ // Return the total number of frames that AudioFlinger has obtained and released
+ virtual size_t framesReleased() const { return mCblk->mServer; }
};
class StaticAudioTrackServerProxy : public AudioTrackServerProxy {
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index dd0ec73..176197c 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -148,10 +148,8 @@
mAudioTrackThread->requestExitAndWait();
mAudioTrackThread.clear();
}
- if (mAudioTrack != 0) {
- mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
- mAudioTrack.clear();
- }
+ mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
+ mAudioTrack.clear();
IPCThreadState::self()->flushCommands();
AudioSystem::releaseAudioSessionId(mSessionId);
}
@@ -222,6 +220,7 @@
AutoMutex lock(mLock);
+ // invariant that mAudioTrack != 0 is true only after set() returns successfully
if (mAudioTrack != 0) {
ALOGE("Track already in use");
return INVALID_OPERATION;
@@ -387,6 +386,9 @@
if (previousState == STATE_STOPPED || previousState == STATE_FLUSHED) {
// reset current position as seen by client to 0
mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition());
+ // force refresh of remaining frames by processAudioBuffer() as last
+ // write before stop could be partial.
+ mRefreshRemaining = true;
}
mNewPosition = mProxy->getPosition() + mUpdatePeriod;
int32_t flags = android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags);
@@ -965,6 +967,7 @@
ALOGE("Could not get control block");
return NO_INIT;
}
+ // invariant that mAudioTrack != 0 is true only after set() returns successfully
if (mAudioTrack != 0) {
mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
mDeathNotifier.clear();
@@ -1547,7 +1550,7 @@
return NS_NEVER;
}
- if (mRetryOnPartialBuffer) {
+ if (mRetryOnPartialBuffer && !isOffloaded()) {
mRetryOnPartialBuffer = false;
if (avail < mRemainingFrames) {
int64_t myns = ((mRemainingFrames - avail) * 1100000000LL) / sampleRate;
@@ -1705,11 +1708,13 @@
status_t AudioTrack::setParameters(const String8& keyValuePairs)
{
AutoMutex lock(mLock);
- if (mAudioTrack != 0) {
- return mAudioTrack->setParameters(keyValuePairs);
- } else {
- return NO_INIT;
- }
+ return mAudioTrack->setParameters(keyValuePairs);
+}
+
+status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp)
+{
+ AutoMutex lock(mLock);
+ return mAudioTrack->getTimestamp(timestamp);
}
String8 AudioTrack::getParameters(const String8& keys)
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index a2b49a3..f0d75ba 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -39,7 +39,8 @@
ALLOCATE_TIMED_BUFFER,
QUEUE_TIMED_BUFFER,
SET_MEDIA_TIME_TRANSFORM,
- SET_PARAMETERS
+ SET_PARAMETERS,
+ GET_TIMESTAMP,
};
class BpAudioTrack : public BpInterface<IAudioTrack>
@@ -166,6 +167,21 @@
}
return status;
}
+
+ virtual status_t getTimestamp(AudioTimestamp& timestamp) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_TIMESTAMP, data, &reply);
+ if (status == NO_ERROR) {
+ status = reply.readInt32();
+ if (status == NO_ERROR) {
+ timestamp.mPosition = reply.readInt32();
+ timestamp.mTime.tv_sec = reply.readInt32();
+ timestamp.mTime.tv_nsec = reply.readInt32();
+ }
+ }
+ return status;
+ }
};
IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack");
@@ -241,6 +257,18 @@
reply->writeInt32(setParameters(keyValuePairs));
return NO_ERROR;
} break;
+ case GET_TIMESTAMP: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ AudioTimestamp timestamp;
+ status_t status = getTimestamp(timestamp);
+ reply->writeInt32(status);
+ if (status == NO_ERROR) {
+ reply->writeInt32(timestamp.mPosition);
+ reply->writeInt32(timestamp.mTime.tv_sec);
+ reply->writeInt32(timestamp.mTime.tv_nsec);
+ }
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp
index 4b527d0..eebcb79 100644
--- a/media/libmediaplayerservice/Drm.cpp
+++ b/media/libmediaplayerservice/Drm.cpp
@@ -222,7 +222,11 @@
}
}
- return mFactory->isContentTypeSupported(mimeType);
+ if (mimeType != "") {
+ return mFactory->isContentTypeSupported(mimeType);
+ }
+
+ return true;
}
status_t Drm::createPlugin(const uint8_t uuid[16]) {
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 2418aab..e38e261 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -680,6 +680,14 @@
int64_t AudioPlayer::getRealTimeUs() {
Mutex::Autolock autoLock(mLock);
+ if (useOffload()) {
+ if (mSeeking) {
+ return mSeekTimeUs;
+ }
+ mPositionTimeRealUs = getOutputPlayPositionUs_l();
+ return mPositionTimeRealUs;
+ }
+
return getRealTimeUsLocked();
}
@@ -741,11 +749,6 @@
return 0;
}
- if (useOffload()) {
- mPositionTimeRealUs = getOutputPlayPositionUs_l();
- return mPositionTimeRealUs;
- }
-
int64_t realTimeOffset = getRealTimeUsLocked() - mPositionTimeRealUs;
if (realTimeOffset < 0) {
realTimeOffset = 0;
@@ -758,8 +761,14 @@
int64_t *realtime_us, int64_t *mediatime_us) {
Mutex::Autolock autoLock(mLock);
- *realtime_us = mPositionTimeRealUs;
- *mediatime_us = mPositionTimeMediaUs;
+ if (useOffload()) {
+ mPositionTimeRealUs = getOutputPlayPositionUs_l();
+ *realtime_us = mPositionTimeRealUs;
+ *mediatime_us = mPositionTimeRealUs;
+ } else {
+ *realtime_us = mPositionTimeRealUs;
+ *mediatime_us = mPositionTimeMediaUs;
+ }
return mPositionTimeRealUs != -1 && mPositionTimeMediaUs != -1;
}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 52e178e..5fbee7e 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -2805,7 +2805,6 @@
// Reset and recreate
reset_l();
- mFlags |= PREPARING;
status_t err;
@@ -2816,6 +2815,7 @@
err = setDataSource_l(uri, &uriHeaders);
}
+ mFlags |= PREPARING;
if ( err != OK ) {
// This will force beingPrepareAsync_l() to notify
// a MEDIA_ERROR to the client and abort the prepare
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index e5e4113..5df04f4 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -411,6 +411,7 @@
virtual status_t setMediaTimeTransform(const LinearTransform& xform,
int target);
virtual status_t setParameters(const String8& keyValuePairs);
+ virtual status_t getTimestamp(AudioTimestamp& timestamp);
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 5600411c..d34833f 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -59,6 +59,7 @@
void setMainBuffer(int16_t *buffer) { mMainBuffer = buffer; }
int16_t *mainBuffer() const { return mMainBuffer; }
int auxEffectId() const { return mAuxEffectId; }
+ virtual status_t getTimestamp(AudioTimestamp& timestamp);
// implement FastMixerState::VolumeProvider interface
virtual uint32_t getVolumeLR();
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 2c2931f..3921b68 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -943,7 +943,9 @@
mDraining(false),
mScreenState(AudioFlinger::mScreenState),
// index 0 is reserved for normal mixer's submix
- mFastTrackAvailMask(((1 << FastMixerState::kMaxFastTracks) - 1) & ~1)
+ mFastTrackAvailMask(((1 << FastMixerState::kMaxFastTracks) - 1) & ~1),
+ // mLatchD, mLatchQ,
+ mLatchDValid(false), mLatchQValid(false)
{
snprintf(mName, kNameLength, "AudioOut_%X", id);
mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mName);
@@ -1818,6 +1820,14 @@
} else {
bytesWritten = framesWritten;
}
+ status_t status = INVALID_OPERATION; // mLatchD.mTimestamp is invalid
+ if (status == NO_ERROR) {
+ size_t totalFramesWritten = mNormalSink->framesWritten();
+ if (totalFramesWritten >= mLatchD.mTimestamp.mPosition) {
+ mLatchD.mUnpresentedFrames = totalFramesWritten - mLatchD.mTimestamp.mPosition;
+ mLatchDValid = true;
+ }
+ }
// otherwise use the HAL / AudioStreamOut directly
} else {
// Direct output and offload threads
@@ -2096,6 +2106,12 @@
logString = NULL;
}
+ if (mLatchDValid) {
+ mLatchQ = mLatchD;
+ mLatchDValid = false;
+ mLatchQValid = true;
+ }
+
if (checkForNewParameters_l()) {
cacheParameters_l();
}
@@ -3794,10 +3810,6 @@
size_t count = mActiveTracks.size();
mixer_state mixerStatus = MIXER_IDLE;
- if (mFlushPending) {
- flushHw_l();
- mFlushPending = false;
- }
// find out which tracks need to be processed
for (size_t i = 0; i < count; i++) {
sp<Track> t = mActiveTracks[i].promote();
@@ -3922,6 +3934,12 @@
// compute volume for this track
processVolume_l(track, last);
}
+
+ if (mFlushPending) {
+ flushHw_l();
+ mFlushPending = false;
+ }
+
// remove all the tracks that need to be...
removeTracks_l(*tracksToRemove);
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 31d5323..1333de2 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -606,6 +606,17 @@
// accessed by both binder threads and within threadLoop(), lock on mutex needed
unsigned mFastTrackAvailMask; // bit i set if fast track [i] is available
virtual void flushOutput_l();
+
+private:
+ // timestamp latch:
+ // D input is written by threadLoop_write while mutex is unlocked, and read while locked
+ // Q output is written while locked, and read while locked
+ struct {
+ AudioTimestamp mTimestamp;
+ uint32_t mUnpresentedFrames;
+ } mLatchD, mLatchQ;
+ bool mLatchDValid; // true means mLatchD is valid, and clock it into latch at next opportunity
+ bool mLatchQValid; // true means mLatchQ is valid
};
class MixerThread : public PlaybackThread {
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index e676365..9622709 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -283,6 +283,11 @@
return mTrack->setParameters(keyValuePairs);
}
+status_t AudioFlinger::TrackHandle::getTimestamp(AudioTimestamp& timestamp)
+{
+ return mTrack->getTimestamp(timestamp);
+}
+
status_t AudioFlinger::TrackHandle::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -711,6 +716,29 @@
}
}
+status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& timestamp)
+{
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread == 0) {
+ return false;
+ }
+ Mutex::Autolock _l(thread->mLock);
+ PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+ if (!playbackThread->mLatchQValid) {
+ return INVALID_OPERATION;
+ }
+ uint32_t unpresentedFrames =
+ ((int64_t) playbackThread->mLatchQ.mUnpresentedFrames * mSampleRate) /
+ playbackThread->mSampleRate;
+ uint32_t framesWritten = mAudioTrackServerProxy->framesReleased();
+ if (framesWritten < unpresentedFrames) {
+ return INVALID_OPERATION;
+ }
+ timestamp.mPosition = framesWritten - unpresentedFrames;
+ timestamp.mTime = playbackThread->mLatchQ.mTimestamp.mTime;
+ return NO_ERROR;
+}
+
status_t AudioFlinger::PlaybackThread::Track::attachAuxEffect(int EffectId)
{
status_t status = DEAD_OBJECT;
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index 76750aa..7ad461a 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -100,7 +100,7 @@
* Internal to CaptureSequencer
*/
static const nsecs_t kWaitDuration = 100000000; // 100 ms
- static const int kMaxTimeoutsForPrecaptureStart = 2; // 200 ms
+ static const int kMaxTimeoutsForPrecaptureStart = 10; // 1 sec
static const int kMaxTimeoutsForPrecaptureEnd = 20; // 2 sec
static const int kMaxTimeoutsForCaptureEnd = 40; // 4 sec
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 414316d..f147c06 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -436,6 +436,20 @@
return res;
}
+status_t CameraDeviceClient::flush() {
+ ATRACE_CALL();
+ ALOGV("%s", __FUNCTION__);
+
+ status_t res = OK;
+ if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+
+ if (!mDevice.get()) return DEAD_OBJECT;
+
+ return mDevice->flush();
+}
+
status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) {
String8 result;
result.appendFormat("CameraDeviceClient[%d] (%p) PID: %d, dump:\n",
@@ -486,14 +500,12 @@
ATRACE_CALL();
ALOGV("%s", __FUNCTION__);
- Mutex::Autolock icl(mBinderSerializationLock);
- SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
-
- if (mRemoteCallback != NULL) {
+ // Thread-safe. No lock necessary.
+ sp<ICameraDeviceCallbacks> remoteCb = mRemoteCallback;
+ if (remoteCb != NULL) {
ALOGV("%s: frame = %p ", __FUNCTION__, &frame);
- mRemoteCallback->onResultReceived(frameId, frame);
+ remoteCb->onResultReceived(frameId, frame);
}
-
}
// TODO: move to Camera2ClientBase
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 21d633c..c6b6336 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -89,6 +89,10 @@
// Wait until all the submitted requests have finished processing
virtual status_t waitUntilIdle();
+
+ // Flush all active and pending requests as fast as possible
+ virtual status_t flush();
+
/**
* Interface used by CameraService
*/
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index aa92bec..ebbd4ea 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -209,6 +209,13 @@
*/
virtual status_t pushReprocessBuffer(int reprocessStreamId,
buffer_handle_t *buffer, wp<BufferReleasedListener> listener) = 0;
+
+ /**
+ * Flush all pending and in-flight requests. Blocks until flush is
+ * complete.
+ */
+ virtual status_t flush() = 0;
+
};
}; // namespace android
diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp
index 710d0e9..fe2cd77 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.cpp
+++ b/services/camera/libcameraservice/device2/Camera2Device.cpp
@@ -567,6 +567,13 @@
return res;
}
+status_t Camera2Device::flush() {
+ ATRACE_CALL();
+
+ mRequestQueue.clear();
+ return waitUntilDrained();
+}
+
/**
* Camera2Device::MetadataQueue
*/
@@ -591,9 +598,7 @@
Camera2Device::MetadataQueue::~MetadataQueue() {
ATRACE_CALL();
- Mutex::Autolock l(mMutex);
- freeBuffers(mEntries.begin(), mEntries.end());
- freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
+ clear();
}
// Connect to camera2 HAL as consumer (input requests/reprocessing)
@@ -784,6 +789,23 @@
return signalConsumerLocked();
}
+status_t Camera2Device::MetadataQueue::clear()
+{
+ ATRACE_CALL();
+ ALOGV("%s: E", __FUNCTION__);
+
+ Mutex::Autolock l(mMutex);
+
+ // Clear streaming slot
+ freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
+ mStreamSlotCount = 0;
+
+ // Clear request queue
+ freeBuffers(mEntries.begin(), mEntries.end());
+ mCount = 0;
+ return OK;
+}
+
status_t Camera2Device::MetadataQueue::dump(int fd,
const Vector<String16>& /*args*/) {
ATRACE_CALL();
diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h
index 8945ec2..2aa22a2 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.h
+++ b/services/camera/libcameraservice/device2/Camera2Device.h
@@ -67,6 +67,8 @@
virtual status_t triggerPrecaptureMetering(uint32_t id);
virtual status_t pushReprocessBuffer(int reprocessStreamId,
buffer_handle_t *buffer, wp<BufferReleasedListener> listener);
+ // Flush implemented as just a wait
+ virtual status_t flush();
private:
const int mId;
camera2_device_t *mHal2Device;
@@ -113,6 +115,9 @@
status_t setStreamSlot(camera_metadata_t *buf);
status_t setStreamSlot(const List<camera_metadata_t*> &bufs);
+ // Clear the request queue and the streaming slot
+ status_t clear();
+
status_t dump(int fd, const Vector<String16>& args);
private:
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 0a4a24c..47321e0 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -952,6 +952,16 @@
return INVALID_OPERATION;
}
+status_t Camera3Device::flush() {
+ ATRACE_CALL();
+ ALOGV("%s: Camera %d: Flushing all requests", __FUNCTION__, mId);
+
+ Mutex::Autolock l(mLock);
+
+ mRequestThread->clear();
+ return mHal3Device->ops->flush(mHal3Device);
+}
+
/**
* Camera3Device private methods
*/
@@ -1414,6 +1424,8 @@
Mutex::Autolock l(mRequestLock);
mRequestQueue.push_back(request);
+ unpauseForNewRequests();
+
return OK;
}
@@ -1479,6 +1491,9 @@
mRepeatingRequests.clear();
mRepeatingRequests.insert(mRepeatingRequests.begin(),
requests.begin(), requests.end());
+
+ unpauseForNewRequests();
+
return OK;
}
@@ -1488,6 +1503,14 @@
return OK;
}
+status_t Camera3Device::RequestThread::clear() {
+ Mutex::Autolock l(mRequestLock);
+ mRepeatingRequests.clear();
+ mRequestQueue.clear();
+ mTriggerMap.clear();
+ return OK;
+}
+
void Camera3Device::RequestThread::setPaused(bool paused) {
Mutex::Autolock l(mPauseLock);
mDoPause = paused;
@@ -1773,7 +1796,9 @@
mRequestQueue.erase(firstRequest);
}
- // Not paused
+ // In case we've been unpaused by setPaused clearing mDoPause, need to
+ // update internal pause state (capture/setRepeatingRequest unpause
+ // directly).
Mutex::Autolock pl(mPauseLock);
mPaused = false;
@@ -1806,6 +1831,16 @@
return false;
}
+void Camera3Device::RequestThread::unpauseForNewRequests() {
+ // With work to do, mark thread as unpaused.
+ // If paused by request (setPaused), don't resume, to avoid
+ // extra signaling/waiting overhead to waitUntilPaused
+ Mutex::Autolock p(mPauseLock);
+ if (!mDoPause) {
+ mPaused = false;
+ }
+}
+
void Camera3Device::RequestThread::setErrorState(const char *fmt, ...) {
sp<Camera3Device> parent = mParent.promote();
if (parent != NULL) {
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 76c08ae..6565048 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -124,6 +124,8 @@
virtual status_t pushReprocessBuffer(int reprocessStreamId,
buffer_handle_t *buffer, wp<BufferReleasedListener> listener);
+ virtual status_t flush();
+
private:
static const size_t kInFlightWarnLimit = 20;
static const nsecs_t kShutdownTimeout = 5000000000; // 5 sec
@@ -249,6 +251,11 @@
status_t queueRequest(sp<CaptureRequest> request);
/**
+ * Remove all queued and repeating requests, and pending triggers
+ */
+ status_t clear();
+
+ /**
* Queue a trigger to be dispatched with the next outgoing
* process_capture_request. The settings for that request only
* will be temporarily rewritten to add the trigger tag/value.
@@ -307,6 +314,7 @@
// Pause handling
bool waitIfPaused();
+ void unpauseForNewRequests();
// Relay error to parent device object setErrorState
void setErrorState(const char *fmt, ...);