Merge "AudioPolicyManager: fix setStreamVolumeIndex()." into nyc-mr1-dev
diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.cpp b/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
index 40275cf..d27956c 100644
--- a/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
+++ b/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
@@ -24,6 +24,7 @@
#include "DrmPlugin.h"
#include "ClearKeyUUID.h"
+#include "MimeType.h"
#include "SessionLibrary.h"
namespace clearkeydrm {
@@ -32,10 +33,14 @@
return isClearKeyUUID(uuid);
}
-bool DrmFactory::isContentTypeSupported(const android::String8 &initDataType) {
+bool DrmFactory::isContentTypeSupported(const android::String8 &type) {
// This should match the types handed by InitDataParser.
- return initDataType == "cenc" ||
- initDataType == "webm";
+ return type == kIsoBmffVideoMimeType ||
+ type == kIsoBmffAudioMimeType ||
+ type == kCencInitDataFormat ||
+ type == kWebmVideoMimeType ||
+ type == kWebmAudioMimeType ||
+ type == kWebmInitDataFormat;
}
android::status_t DrmFactory::createDrmPlugin(
diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.h b/drm/mediadrm/plugins/clearkey/DrmFactory.h
index 164d3d0..87db982 100644
--- a/drm/mediadrm/plugins/clearkey/DrmFactory.h
+++ b/drm/mediadrm/plugins/clearkey/DrmFactory.h
@@ -32,7 +32,7 @@
virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
- virtual bool isContentTypeSupported(const android::String8 &initDataType);
+ virtual bool isContentTypeSupported(const android::String8 &mimeType);
virtual android::status_t createDrmPlugin(
const uint8_t uuid[16], android::DrmPlugin** plugin);
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
index e5ee403..86bf047 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
@@ -46,7 +46,7 @@
status_t DrmPlugin::getKeyRequest(
const Vector<uint8_t>& scope,
const Vector<uint8_t>& initData,
- const String8& initDataType,
+ const String8& mimeType,
KeyType keyType,
const KeyedVector<String8, String8>& optionalParameters,
Vector<uint8_t>& request,
@@ -62,7 +62,7 @@
if (!session.get()) {
return android::ERROR_DRM_SESSION_NOT_OPENED;
}
- return session->getKeyRequest(initData, initDataType, &request);
+ return session->getKeyRequest(initData, mimeType, &request);
}
status_t DrmPlugin::provideKeyResponse(
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
index 9095045..efb9f8b 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
@@ -49,7 +49,7 @@
virtual status_t getKeyRequest(
const Vector<uint8_t>& scope,
- const Vector<uint8_t>& initData,
+ const Vector<uint8_t>& mimeType,
const String8& initDataType,
KeyType keyType,
const KeyedVector<String8, String8>& optionalParameters,
diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
index c22d73a..0216b8d 100644
--- a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
@@ -27,6 +27,7 @@
#include "InitDataParser.h"
#include "ClearKeyUUID.h"
+#include "MimeType.h"
#include "Utils.h"
namespace clearkeydrm {
@@ -41,16 +42,20 @@
}
android::status_t InitDataParser::parse(const Vector<uint8_t>& initData,
- const String8& initDataType,
+ const String8& type,
Vector<uint8_t>* licenseRequest) {
// Build a list of the key IDs
Vector<const uint8_t*> keyIds;
- if (initDataType == "cenc") {
+ if (type == kIsoBmffVideoMimeType ||
+ type == kIsoBmffAudioMimeType ||
+ type == kCencInitDataFormat) {
android::status_t res = parsePssh(initData, &keyIds);
if (res != android::OK) {
return res;
}
- } else if (initDataType == "webm") {
+ } else if (type == kWebmVideoMimeType ||
+ type == kWebmAudioMimeType ||
+ type == kWebmInitDataFormat) {
// WebM "init data" is just a single key ID
if (initData.size() != kKeyIdSize) {
return android::ERROR_DRM_CANNOT_HANDLE;
diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.h b/drm/mediadrm/plugins/clearkey/InitDataParser.h
index 9505d2a..a9707bf 100644
--- a/drm/mediadrm/plugins/clearkey/InitDataParser.h
+++ b/drm/mediadrm/plugins/clearkey/InitDataParser.h
@@ -29,7 +29,7 @@
InitDataParser() {}
android::status_t parse(const android::Vector<uint8_t>& initData,
- const android::String8& initDataType,
+ const android::String8& type,
android::Vector<uint8_t>* licenseRequest);
private:
diff --git a/drm/mediadrm/plugins/clearkey/MimeType.h b/drm/mediadrm/plugins/clearkey/MimeType.h
new file mode 100644
index 0000000..085f17a
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/MimeType.h
@@ -0,0 +1,15 @@
+#ifndef CLEARKEY_MIMETYPE_H_
+#define CLEARKEY_MIMETYPE_H_
+
+#include <utils/String8.h>
+
+namespace {
+ const android::String8 kCencInitDataFormat("cenc");
+ const android::String8 kIsoBmffAudioMimeType("audio/mp4");
+ const android::String8 kIsoBmffVideoMimeType("video/mp4");
+ const android::String8 kWebmInitDataFormat("webm");
+ const android::String8 kWebmAudioMimeType("audio/webm");
+ const android::String8 kWebmVideoMimeType("video/webm");
+}
+
+#endif // CLEARKEY_MIMETYPE_H_
diff --git a/drm/mediadrm/plugins/clearkey/Session.cpp b/drm/mediadrm/plugins/clearkey/Session.cpp
index 95016f5..d210f5e 100644
--- a/drm/mediadrm/plugins/clearkey/Session.cpp
+++ b/drm/mediadrm/plugins/clearkey/Session.cpp
@@ -36,10 +36,10 @@
status_t Session::getKeyRequest(
const Vector<uint8_t>& initData,
- const String8& initDataType,
+ const String8& mimeType,
Vector<uint8_t>* keyRequest) const {
InitDataParser parser;
- return parser.parse(initData, initDataType, keyRequest);
+ return parser.parse(initData, mimeType, keyRequest);
}
status_t Session::provideKeyResponse(const Vector<uint8_t>& response) {
diff --git a/drm/mediadrm/plugins/clearkey/Session.h b/drm/mediadrm/plugins/clearkey/Session.h
index cab0dc3..0933506 100644
--- a/drm/mediadrm/plugins/clearkey/Session.h
+++ b/drm/mediadrm/plugins/clearkey/Session.h
@@ -38,7 +38,7 @@
const android::Vector<uint8_t>& sessionId() const { return mSessionId; }
android::status_t getKeyRequest(
- const android::Vector<uint8_t>& initData,
+ const android::Vector<uint8_t>& mimeType,
const android::String8& initDataType,
android::Vector<uint8_t>* keyRequest) const;
diff --git a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
index 4ba65ed..e275108 100644
--- a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
+++ b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
@@ -30,27 +30,27 @@
namespace {
const size_t kKeyIdSize = 16;
- const String8 kCencType("cenc");
- const String8 kWebMType("webm");
+ const String8 kCencMimeType("video/mp4");
+ const String8 kWebmMimeType("video/webm");
const String8 kBase64Padding("=");
}
class InitDataParserTest : public ::testing::Test {
protected:
status_t attemptParse(const Vector<uint8_t>& initData,
- const String8& initDataType,
+ const String8& mimeType,
Vector<uint8_t>* licenseRequest) {
InitDataParser parser;
- return parser.parse(initData, initDataType, licenseRequest);
+ return parser.parse(initData, mimeType, licenseRequest);
}
void attemptParseExpectingSuccess(const Vector<uint8_t>& initData,
- const String8& initDataType,
+ const String8& mimeType,
const Vector<String8>& expectedKeys) {
const String8 kRequestPrefix("{\"kids\":[");
const String8 kRequestSuffix("],\"type\":\"temporary\"}");
Vector<uint8_t> request;
- ASSERT_EQ(android::OK, attemptParse(initData, initDataType, &request));
+ ASSERT_EQ(android::OK, attemptParse(initData, mimeType, &request));
String8 requestString(reinterpret_cast<const char*>(request.array()),
request.size());
@@ -68,9 +68,9 @@
}
void attemptParseExpectingFailure(const Vector<uint8_t>& initData,
- const String8& initDataType) {
+ const String8& mimeType) {
Vector<uint8_t> request;
- ASSERT_NE(android::OK, attemptParse(initData, initDataType, &request));
+ ASSERT_NE(android::OK, attemptParse(initData, mimeType, &request));
EXPECT_EQ(0, request.size());
}
};
@@ -93,7 +93,7 @@
Vector<String8> expectedKeys;
expectedKeys.push(String8("01234567890ABCDE"));
- attemptParseExpectingSuccess(initData, kCencType, expectedKeys);
+ attemptParseExpectingSuccess(initData, kCencMimeType, expectedKeys);
}
TEST_F(InitDataParserTest, ParsesMultipleKeyPssh) {
@@ -120,7 +120,7 @@
expectedKeys.push(String8("ClearKeyClearKey"));
expectedKeys.push(String8(" GOOGLE GOOGLE "));
- attemptParseExpectingSuccess(initData, kCencType, expectedKeys);
+ attemptParseExpectingSuccess(initData, kCencMimeType, expectedKeys);
}
TEST_F(InitDataParserTest, ParsesWebM) {
@@ -134,7 +134,7 @@
Vector<String8> expectedKeys;
expectedKeys.push(String8("01234567890ABCDE"));
- attemptParseExpectingSuccess(initData, kWebMType, expectedKeys);
+ attemptParseExpectingSuccess(initData, kWebmMimeType, expectedKeys);
}
TEST_F(InitDataParserTest, FailsForPsshTooSmall) {
@@ -147,7 +147,7 @@
Vector<uint8_t> initData;
initData.appendArray(pssh, 16);
- attemptParseExpectingFailure(initData, kCencType);
+ attemptParseExpectingFailure(initData, kCencMimeType);
}
TEST_F(InitDataParserTest, FailsForWebMTooSmall) {
@@ -157,7 +157,7 @@
Vector<uint8_t> initData;
initData.appendArray(initDataRaw, 8);
- attemptParseExpectingFailure(initData, kWebMType);
+ attemptParseExpectingFailure(initData, kWebmMimeType);
}
TEST_F(InitDataParserTest, FailsForPsshBadSystemId) {
@@ -175,7 +175,7 @@
Vector<uint8_t> initData;
initData.appendArray(pssh, 52);
- attemptParseExpectingFailure(initData, kCencType);
+ attemptParseExpectingFailure(initData, kCencMimeType);
}
TEST_F(InitDataParserTest, FailsForPsshBadSize) {
@@ -193,7 +193,7 @@
Vector<uint8_t> initData;
initData.appendArray(pssh, 52);
- attemptParseExpectingFailure(initData, kCencType);
+ attemptParseExpectingFailure(initData, kCencMimeType);
}
TEST_F(InitDataParserTest, FailsForPsshWrongVersion) {
@@ -211,7 +211,7 @@
Vector<uint8_t> initData;
initData.appendArray(pssh, 52);
- attemptParseExpectingFailure(initData, kCencType);
+ attemptParseExpectingFailure(initData, kCencMimeType);
}
TEST_F(InitDataParserTest, FailsForPsshBadKeyCount) {
@@ -229,7 +229,7 @@
Vector<uint8_t> initData;
initData.appendArray(pssh, 52);
- attemptParseExpectingFailure(initData, kCencType);
+ attemptParseExpectingFailure(initData, kCencMimeType);
}
} // namespace clearkeydrm
diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h
index ec0dad5..7bb9e8b 100644
--- a/include/media/Visualizer.h
+++ b/include/media/Visualizer.h
@@ -95,8 +95,7 @@
// install a callback to receive periodic captures. The capture rate is specified in milliHertz
// and the capture format is according to flags (see callback_flags).
- status_t setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate,
- bool force = false);
+ status_t setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate);
// set the capture size capture size must be a power of two in the range
// [VISUALIZER_CAPTURE_SIZE_MAX. VISUALIZER_CAPTURE_SIZE_MIN]
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index ffdb9b5..7becf57 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -522,6 +522,12 @@
mTimestampMutator.push(timestamp);
}
+ // Flushes the shared ring buffer if the client had requested it using mStreaming.mFlush.
+ // If flush occurs then:
+ // cblk->u.mStreaming.mFront, ServerProxy::mFlush and ServerProxy::mFlushed will be modified
+ // client will be notified via Futex
+ virtual void flushBufferIfNeeded();
+
// Total count of the number of flushed frames since creation (never reset).
virtual int64_t framesFlushed() const { return mFlushed; }
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 0c310c5..91f9fc7 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -25,6 +25,7 @@
#include <time.h>
#include <math.h>
#include <audio_effects/effect_visualizer.h>
+#include <cutils/log.h>
extern "C" {
@@ -599,6 +600,14 @@
} break;
case VISUALIZER_CMD_MEASURE: {
+ if (pReplyData == NULL || replySize == NULL ||
+ *replySize < (sizeof(int32_t) * MEASUREMENT_COUNT)) {
+ ALOGV("VISUALIZER_CMD_MEASURE() error *replySize %" PRIu32
+ " < (sizeof(int32_t) * MEASUREMENT_COUNT) %" PRIu32, *replySize,
+ sizeof(int32_t) * MEASUREMENT_COUNT);
+ android_errorWriteLog(0x534e4554, "30229821");
+ return -EINVAL;
+ }
uint16_t peakU16 = 0;
float sumRmsSquared = 0.0f;
uint8_t nbValidMeasurements = 0;
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 7119517..846f8b8 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -622,6 +622,56 @@
}
__attribute__((no_sanitize("integer")))
+void ServerProxy::flushBufferIfNeeded()
+{
+ audio_track_cblk_t* cblk = mCblk;
+ // The acquire_load is not really required. But since the write is a release_store in the
+ // client, using acquire_load here makes it easier for people to maintain the code,
+ // and the logic for communicating ipc variables seems somewhat standard,
+ // and there really isn't much penalty for 4 or 8 byte atomics.
+ int32_t flush = android_atomic_acquire_load(&cblk->u.mStreaming.mFlush);
+ if (flush != mFlush) {
+ ALOGV("ServerProxy::flushBufferIfNeeded() mStreaming.mFlush = 0x%x, mFlush = 0x%0x",
+ flush, mFlush);
+ int32_t rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
+ int32_t front = cblk->u.mStreaming.mFront;
+
+ // effectively obtain then release whatever is in the buffer
+ const size_t overflowBit = mFrameCountP2 << 1;
+ const size_t mask = overflowBit - 1;
+ int32_t newFront = (front & ~mask) | (flush & mask);
+ ssize_t filled = rear - newFront;
+ if (filled >= (ssize_t)overflowBit) {
+ // front and rear offsets span the overflow bit of the p2 mask
+ // so rebasing newFront on the front offset is off by the overflow bit.
+ // adjust newFront to match rear offset.
+ ALOGV("flush wrap: filled %zx >= overflowBit %zx", filled, overflowBit);
+ newFront += overflowBit;
+ filled -= overflowBit;
+ }
+ // 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 %zd=%#x",
+ mFlush, flush, front, rear,
+ (unsigned)mask, newFront, filled, (unsigned)filled);
+ newFront = rear;
+ }
+ mFlush = flush;
+ android_atomic_release_store(newFront, &cblk->u.mStreaming.mFront);
+ // There is no danger from a false positive, so err on the side of caution
+ if (true /*front != newFront*/) {
+ int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
+ if (!(old & CBLK_FUTEX_WAKE)) {
+ (void) syscall(__NR_futex, &cblk->mFutex,
+ mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
+ }
+ }
+ mFlushed += (newFront - front) & mask;
+ }
+}
+
+__attribute__((no_sanitize("integer")))
status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
{
LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
@@ -636,44 +686,9 @@
int32_t rear;
// See notes on barriers at ClientProxy::obtainBuffer()
if (mIsOut) {
- int32_t flush = cblk->u.mStreaming.mFlush;
+ flushBufferIfNeeded(); // might modify mFront
rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
front = cblk->u.mStreaming.mFront;
- if (flush != mFlush) {
- // effectively obtain then release whatever is in the buffer
- const size_t overflowBit = mFrameCountP2 << 1;
- const size_t mask = overflowBit - 1;
- int32_t newFront = (front & ~mask) | (flush & mask);
- ssize_t filled = rear - newFront;
- if (filled >= (ssize_t)overflowBit) {
- // front and rear offsets span the overflow bit of the p2 mask
- // so rebasing newFront on the front offset is off by the overflow bit.
- // adjust newFront to match rear offset.
- ALOGV("flush wrap: filled %zx >= overflowBit %zx", filled, overflowBit);
- newFront += overflowBit;
- filled -= overflowBit;
- }
- // 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 %zd=%#x",
- mFlush, flush, front, rear,
- (unsigned)mask, newFront, filled, (unsigned)filled);
- newFront = rear;
- }
- mFlush = flush;
- android_atomic_release_store(newFront, &cblk->u.mStreaming.mFront);
- // There is no danger from a false positive, so err on the side of caution
- if (true /*front != newFront*/) {
- int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
- if (!(old & CBLK_FUTEX_WAKE)) {
- (void) syscall(__NR_futex, &cblk->mFutex,
- mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
- }
- }
- mFlushed += (newFront - front) & mask;
- front = newFront;
- }
} else {
front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
rear = cblk->u.mStreaming.mRear;
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
index 26dd2c9..a750824 100644
--- a/media/libmedia/ICrypto.cpp
+++ b/media/libmedia/ICrypto.cpp
@@ -150,10 +150,10 @@
if (isCryptoError(result)) {
errorDetailMsg->setTo(reply.readCString());
- }
-
- if (dstType == kDestinationTypeVmPointer && result >= 0) {
- reply.read(dstPtr, result);
+ } else if (dstType == kDestinationTypeVmPointer) {
+ // For the non-secure case, copy the decrypted-in-place
+ // data from shared memory to its final destination
+ memcpy(dstPtr, sharedBuffer->pointer(), result);
}
return result;
@@ -320,7 +320,10 @@
dstPtr = secureBufferId;
} else {
dstType = kDestinationTypeVmPointer;
- dstPtr = malloc(totalSize);
+
+ // For the non-secure case, decrypt in-place back to the
+ // shared memory segment.
+ dstPtr = sharedBuffer->pointer();
}
AString errorDetailMsg;
@@ -366,14 +369,7 @@
reply->writeCString(errorDetailMsg.c_str());
}
- if (dstType == kDestinationTypeVmPointer) {
- if (result >= 0) {
- CHECK_LE(result, static_cast<ssize_t>(totalSize));
- reply->write(dstPtr, result);
- }
- free(dstPtr);
- dstPtr = NULL;
- } else if (dstType == kDestinationTypeNativeHandle) {
+ if (dstType == kDestinationTypeNativeHandle) {
int err;
if ((err = native_handle_close(nativeHandle)) < 0) {
ALOGW("secure buffer native_handle_close failed: %d", err);
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index 5289c5f..595bad9 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -412,11 +412,11 @@
reply->writeInt32(offset);
reply->writeInt32(length);
buf->meta_data()->writeToParcel(*reply);
- if (transferBuf == buf) {
- buf->addRemoteRefcount(1);
- if (!supportNonblockingRead()) {
- maxNumBuffers = 0; // stop readMultiple with one shared buffer.
- }
+ transferBuf->addRemoteRefcount(1);
+ if (transferBuf != buf) {
+ transferBuf->release(); // release local ref
+ } else if (!supportNonblockingRead()) {
+ maxNumBuffers = 0; // stop readMultiple with one shared buffer.
}
} else {
ALOGV_IF(buf->mMemory != nullptr,
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
index 31e310b..37bf0bd 100644
--- a/media/libmedia/Visualizer.cpp
+++ b/media/libmedia/Visualizer.cpp
@@ -55,7 +55,7 @@
{
ALOGV("Visualizer::~Visualizer()");
setEnabled(false);
- setCaptureCallBack(NULL, NULL, 0, 0, true);
+ setCaptureCallBack(NULL, NULL, 0, 0);
}
status_t Visualizer::setEnabled(bool enabled)
@@ -77,13 +77,11 @@
status_t status = AudioEffect::setEnabled(enabled);
- if (status == NO_ERROR) {
- if (t != 0) {
- if (enabled) {
- t->run("Visualizer");
- } else {
- t->requestExit();
- }
+ if (t != 0) {
+ if (enabled && status == NO_ERROR) {
+ t->run("Visualizer");
+ } else {
+ t->requestExit();
}
}
@@ -95,14 +93,14 @@
}
status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags,
- uint32_t rate, bool force)
+ uint32_t rate)
{
if (rate > CAPTURE_RATE_MAX) {
return BAD_VALUE;
}
Mutex::Autolock _l(mCaptureLock);
- if (force || mEnabled) {
+ if (mEnabled) {
return INVALID_OPERATION;
}
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index f84f484..5e96c2b 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -2481,12 +2481,16 @@
ALOGW("Recorded file size exceeds limit %" PRId64 "bytes",
mOwner->mMaxFileSizeLimitBytes);
mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
+ copy->release();
+ mSource->stop();
break;
}
if (mOwner->exceedsFileDurationLimit()) {
ALOGW("Recorded file duration exceeds limit %" PRId64 "microseconds",
mOwner->mMaxFileDurationLimitUs);
mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
+ copy->release();
+ mSource->stop();
break;
}
@@ -2507,6 +2511,7 @@
int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) {
copy->release();
+ mSource->stop();
mIsMalformed = true;
break;
}
@@ -2514,6 +2519,7 @@
int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) {
copy->release();
+ mSource->stop();
mIsMalformed = true;
break;
}
@@ -2525,6 +2531,7 @@
timestampUs -= previousPausedDurationUs;
if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
copy->release();
+ mSource->stop();
mIsMalformed = true;
break;
}
@@ -2553,6 +2560,7 @@
timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) {
copy->release();
+ mSource->stop();
mIsMalformed = true;
break;
}
@@ -2566,6 +2574,7 @@
(cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL;
if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) {
copy->release();
+ mSource->stop();
mIsMalformed = true;
break;
}
@@ -2609,6 +2618,7 @@
if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
copy->release();
+ mSource->stop();
mIsMalformed = true;
break;
}
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index a669dca..276d731 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -305,7 +305,10 @@
sp<IMediaSource> source = mImpl->getTrack(index);
- CHECK_EQ((status_t)OK, source->start());
+ status_t ret = source->start();
+ if (ret != OK) {
+ return ret;
+ }
mSelectedTracks.push();
TrackInfo *info = &mSelectedTracks.editItemAt(mSelectedTracks.size() - 1);
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index e994069..e40dbcf 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -303,6 +303,12 @@
status_t MuxOMX::freeNode(node_id node) {
Mutex::Autolock autoLock(mLock);
+ // exit if we have already freed the node
+ if (mNodeLocation.indexOfKey(node) < 0) {
+ ALOGD("MuxOMX::freeNode: node %d seems to be released already --- ignoring.", node);
+ return OK;
+ }
+
status_t err = getOMX_l(node)->freeNode(node);
if (err != OK) {
diff --git a/media/libstagefright/http/MediaHTTP.cpp b/media/libstagefright/http/MediaHTTP.cpp
index 76ec625..5b18814 100644
--- a/media/libstagefright/http/MediaHTTP.cpp
+++ b/media/libstagefright/http/MediaHTTP.cpp
@@ -58,15 +58,19 @@
extHeaders.add(String8("User-Agent"), String8(MakeUserAgent().c_str()));
}
- bool success = mHTTPConnection->connect(uri, &extHeaders);
+ mLastURI = uri;
+ // reconnect() calls with uri == old mLastURI.c_str(), which gets zapped
+ // as part of the above assignment. Ensure no accidental later use.
+ uri = NULL;
+
+ bool success = mHTTPConnection->connect(mLastURI.c_str(), &extHeaders);
mLastHeaders = extHeaders;
- mLastURI = uri;
mCachedSizeValid = false;
if (success) {
- AString sanitized = uriDebugString(uri);
+ AString sanitized = uriDebugString(mLastURI);
mName = String8::format("MediaHTTP(%s)", sanitized.c_str());
}
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 26b41d0..93d6584 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -139,7 +139,6 @@
mRepeatLastFrameTimestamp(-1ll),
mLatestBufferId(-1),
mLatestBufferFrameNum(0),
- mLatestBufferUseCount(0),
mLatestBufferFence(Fence::NO_FENCE),
mRepeatBufferDeferred(false),
mTimePerCaptureUs(-1ll),
@@ -398,12 +397,16 @@
sp<Fence> fence = new Fence(fenceFd);
if (mBufferSlot[id] != NULL &&
mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) {
- ALOGV("cbi %d matches bq slot %d, handle=%p",
- cbi, id, mBufferSlot[id]->handle);
+ mBufferUseCount[id]--;
- if (id == mLatestBufferId) {
- CHECK_GT(mLatestBufferUseCount--, 0);
- } else {
+ ALOGV("codecBufferEmptied: slot=%d, cbi=%d, useCount=%d, handle=%p",
+ id, cbi, mBufferUseCount[id], mBufferSlot[id]->handle);
+
+ if (mBufferUseCount[id] < 0) {
+ ALOGW("mBufferUseCount for bq slot %d < 0 (=%d)", id, mBufferUseCount[id]);
+ mBufferUseCount[id] = 0;
+ }
+ if (id != mLatestBufferId && mBufferUseCount[id] == 0) {
releaseBuffer(id, codecBuffer.mFrameNumber, mBufferSlot[id], fence);
}
} else {
@@ -614,6 +617,7 @@
if (item.mGraphicBuffer != NULL) {
ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mSlot);
mBufferSlot[item.mSlot] = item.mGraphicBuffer;
+ mBufferUseCount[item.mSlot] = 0;
}
if (item.mDataSpace != mLastDataSpace) {
@@ -699,7 +703,7 @@
return false;
}
- ++mLatestBufferUseCount;
+ ++mBufferUseCount[item.mSlot];
/* repeat last frame up to kRepeatLastFrameCount times.
* in case of static scene, a single repeat might not get rid of encoder
@@ -720,10 +724,8 @@
void GraphicBufferSource::setLatestBuffer_l(
const BufferItem &item, bool dropped) {
- ALOGV("setLatestBuffer_l");
-
if (mLatestBufferId >= 0) {
- if (mLatestBufferUseCount == 0) {
+ if (mBufferUseCount[mLatestBufferId] == 0) {
releaseBuffer(mLatestBufferId, mLatestBufferFrameNum,
mBufferSlot[mLatestBufferId], mLatestBufferFence);
// mLatestBufferFence will be set to new fence just below
@@ -734,7 +736,13 @@
mLatestBufferFrameNum = item.mFrameNumber;
mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
- mLatestBufferUseCount = dropped ? 0 : 1;
+ if (!dropped) {
+ ++mBufferUseCount[item.mSlot];
+ }
+
+ ALOGV("setLatestBuffer_l: slot=%d, useCount=%d",
+ item.mSlot, mBufferUseCount[item.mSlot]);
+
mRepeatBufferDeferred = false;
mRepeatLastFrameCount = kRepeatLastFrameCount;
mLatestBufferFence = item.mFence;
@@ -842,7 +850,7 @@
}
status_t GraphicBufferSource::submitBuffer_l(const BufferItem &item, int cbi) {
- ALOGV("submitBuffer_l cbi=%d", cbi);
+ ALOGV("submitBuffer_l: slot=%d, cbi=%d", item.mSlot, cbi);
int64_t timeUs = getTimestamp(item);
if (timeUs < 0ll) {
@@ -935,6 +943,7 @@
void GraphicBufferSource::releaseBuffer(
int &id, uint64_t frameNum,
const sp<GraphicBuffer> buffer, const sp<Fence> &fence) {
+ ALOGV("releaseBuffer: slot=%d", id);
if (mIsPersistent) {
mConsumer->detachBuffer(id);
mBufferSlot[id] = NULL;
@@ -978,6 +987,7 @@
if (item.mGraphicBuffer != NULL) {
ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mSlot);
mBufferSlot[item.mSlot] = item.mGraphicBuffer;
+ mBufferUseCount[item.mSlot] = 0;
}
releaseBuffer(item.mSlot, item.mFrameNumber,
@@ -1011,6 +1021,7 @@
for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
if ((slotMask & 0x01) != 0) {
mBufferSlot[i] = NULL;
+ mBufferUseCount[i] = 0;
}
slotMask >>= 1;
}
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 30bfddb..aa4ceb3 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -295,6 +295,7 @@
// is done processing a GraphicBuffer, we can use this to map back
// to a slot number.
sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
+ int32_t mBufferUseCount[BufferQueue::NUM_BUFFER_SLOTS];
// Tracks codec buffers.
Vector<CodecBuffer> mCodecBuffers;
@@ -327,7 +328,6 @@
int mLatestBufferId;
uint64_t mLatestBufferFrameNum;
- int32_t mLatestBufferUseCount;
sp<Fence> mLatestBufferFence;
// The previous buffer should've been repeated but
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 35d5de6..5f903a9 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -372,8 +372,7 @@
status_t OMXNodeInstance::sendCommand(
OMX_COMMANDTYPE cmd, OMX_S32 param) {
if (cmd == OMX_CommandStateSet) {
- // We do not support returning from unloaded state, so there are no configurations past
- // first StateSet command.
+ // There are no configurations past first StateSet command.
mSailed = true;
}
const sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
@@ -531,6 +530,12 @@
status_t OMXNodeInstance::enableNativeBuffers(
OMX_U32 portIndex, OMX_BOOL graphic, OMX_BOOL enable) {
+ if (portIndex >= NELEM(mSecureBufferType)) {
+ ALOGE("b/31385713, portIndex(%u)", portIndex);
+ android_errorWriteLog(0x534e4554, "31385713");
+ return BAD_VALUE;
+ }
+
Mutex::Autolock autoLock(mLock);
CLOG_CONFIG(enableNativeBuffers, "%s:%u%s, %d", portString(portIndex), portIndex,
graphic ? ", graphic" : "", enable);
@@ -811,7 +816,7 @@
params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, data);
} else {
buffer_meta = new BufferMeta(
- params, portIndex, false /* copyFromOmx */, false /* copyToOmx */, NULL);
+ params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, NULL);
}
OMX_BUFFERHEADERTYPE *header;
@@ -1039,7 +1044,7 @@
}
BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate);
- // update backup buffer for input, codec buffer for output
+ // update backup buffer
sp<ABuffer> data = bufferMeta->getBuffer(
header, false /* backup */, false /* limit */);
bufferMeta->setNativeHandle(nativeHandle);
@@ -1217,6 +1222,12 @@
return BAD_VALUE;
}
+ if (portIndex >= NELEM(mSecureBufferType)) {
+ ALOGE("b/31385713, portIndex(%u)", portIndex);
+ android_errorWriteLog(0x534e4554, "31385713");
+ return BAD_VALUE;
+ }
+
Mutex::Autolock autoLock(mLock);
BufferMeta *buffer_meta = new BufferMeta(size, portIndex);
@@ -1299,7 +1310,6 @@
}
CHECK_EQ(header->pAppPrivate, buffer_meta);
- memset(header->pBuffer, 0, header->nAllocLen);
*buffer = makeBufferID(header);
@@ -1393,23 +1403,11 @@
}
BufferMeta *buffer_meta =
static_cast<BufferMeta *>(header->pAppPrivate);
- sp<ABuffer> backup = buffer_meta->getBuffer(header, true /* backup */, false /* limit */);
- sp<ABuffer> codec = buffer_meta->getBuffer(header, false /* backup */, false /* limit */);
- // convert incoming ANW meta buffers if component is configured for gralloc metadata mode
- // ignore rangeOffset in this case
- if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource
- && backup->capacity() >= sizeof(VideoNativeMetadata)
- && codec->capacity() >= sizeof(VideoGrallocMetadata)
- && ((VideoNativeMetadata *)backup->base())->eType
- == kMetadataBufferTypeANWBuffer) {
- VideoNativeMetadata &backupMeta = *(VideoNativeMetadata *)backup->base();
- VideoGrallocMetadata &codecMeta = *(VideoGrallocMetadata *)codec->base();
- CLOG_BUFFER(emptyBuffer, "converting ANWB %p to handle %p",
- backupMeta.pBuffer, backupMeta.pBuffer->handle);
- codecMeta.pHandle = backupMeta.pBuffer != NULL ? backupMeta.pBuffer->handle : NULL;
- codecMeta.eType = kMetadataBufferTypeGrallocSource;
- header->nFilledLen = rangeLength ? sizeof(codecMeta) : 0;
+ // set up proper filled length if component is configured for gralloc metadata mode
+ // ignore rangeOffset in this case (as client may be assuming ANW meta buffers).
+ if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource) {
+ header->nFilledLen = rangeLength ? sizeof(VideoGrallocMetadata) : 0;
header->nOffset = 0;
} else {
// rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
@@ -1844,6 +1842,13 @@
&& arg2 == OMX_StateExecuting) {
bufferSource->omxExecuting();
}
+
+ // allow configuration if we return to the loaded state
+ if (event == OMX_EventCmdComplete
+ && arg1 == OMX_CommandStateSet
+ && arg2 == OMX_StateLoaded) {
+ mSailed = false;
+ }
}
// static
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index face727..89f2d9c 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -148,7 +148,14 @@
EXPORT
bool AMediaExtractor_advance(AMediaExtractor *mData) {
//ALOGV("advance");
- return mData->mImpl->advance();
+ status_t err = mData->mImpl->advance();
+ if (err == ERROR_END_OF_STREAM) {
+ return false;
+ } else if (err != OK) {
+ ALOGE("sf error code: %d", err);
+ return false;
+ }
+ return true;
}
EXPORT
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index bbea971..aedde69 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -279,12 +279,29 @@
mConfig.inputCfg.buffer.s32,
mConfig.inputCfg.buffer.frameCount/2);
}
+ int ret;
+ if (isProcessImplemented()) {
+ // do the actual processing in the effect engine
+ ret = (*mEffectInterface)->process(mEffectInterface,
+ &mConfig.inputCfg.buffer,
+ &mConfig.outputCfg.buffer);
+ } else {
+ if (mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw) {
+ size_t frameCnt = mConfig.inputCfg.buffer.frameCount * FCC_2; //always stereo here
+ int16_t *in = mConfig.inputCfg.buffer.s16;
+ int16_t *out = mConfig.outputCfg.buffer.s16;
- // do the actual processing in the effect engine
- int ret = (*mEffectInterface)->process(mEffectInterface,
- &mConfig.inputCfg.buffer,
- &mConfig.outputCfg.buffer);
-
+ if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+ for (size_t i = 0; i < frameCnt; i++) {
+ out[i] = clamp16((int32_t)out[i] + (int32_t)in[i]);
+ }
+ } else {
+ memcpy(mConfig.outputCfg.buffer.raw, mConfig.inputCfg.buffer.raw,
+ frameCnt * sizeof(int16_t));
+ }
+ }
+ ret = -ENODATA;
+ }
// force transition to IDLE state when engine is ready
if (mState == STOPPED && ret == -ENODATA) {
mDisableWaitCnt = 1;
@@ -301,7 +318,7 @@
// accumulate input onto output
sp<EffectChain> chain = mChain.promote();
if (chain != 0 && chain->activeTrackCnt() != 0) {
- size_t frameCnt = mConfig.inputCfg.buffer.frameCount * 2; //always stereo here
+ size_t frameCnt = mConfig.inputCfg.buffer.frameCount * FCC_2; //always stereo here
int16_t *in = mConfig.inputCfg.buffer.s16;
int16_t *out = mConfig.outputCfg.buffer.s16;
for (size_t i = 0; i < frameCnt; i++) {
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 322c06a..da0f3c5 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -119,6 +119,8 @@
{ return (mDescriptor.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) != 0; }
bool isImplementationSoftware() const
{ return (mDescriptor.flags & EFFECT_FLAG_HW_ACC_MASK) == 0; }
+ bool isProcessImplemented() const
+ { return (mDescriptor.flags & EFFECT_FLAG_NO_PROCESS) == 0; }
status_t setOffloaded(bool offloaded, audio_io_handle_t io);
bool isOffloaded() const;
void addEffectToHal_l();
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 6aedd29..a91fc26 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1272,6 +1272,12 @@
desc->name, mThreadName);
return BAD_VALUE;
}
+
+ // always allow effects without processing load or latency
+ if ((desc->flags & EFFECT_FLAG_NO_PROCESS_MASK) == EFFECT_FLAG_NO_PROCESS) {
+ return NO_ERROR;
+ }
+
audio_input_flags_t flags = mInput->flags;
if (hasFastCapture() || (flags & AUDIO_INPUT_FLAG_FAST)) {
if (flags & AUDIO_INPUT_FLAG_RAW) {
@@ -1328,6 +1334,11 @@
break;
}
}
+
+ // always allow effects without processing load or latency
+ if ((desc->flags & EFFECT_FLAG_NO_PROCESS_MASK) == EFFECT_FLAG_NO_PROCESS) {
+ break;
+ }
if (flags & AUDIO_OUTPUT_FLAG_RAW) {
ALOGW("checkEffectCompatibility_l(): effect %s on playback thread in raw mode",
desc->name);
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index b387af3..3cca054 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -777,6 +777,13 @@
Mutex::Autolock _l(thread->mLock);
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+ // Flush the ring buffer now if the track is not active in the PlaybackThread.
+ // Otherwise the flush would not be done until the track is resumed.
+ // Requires FastTrack removal be BLOCK_UNTIL_ACKED
+ if (playbackThread->mActiveTracks.indexOf(this) < 0) {
+ (void)mServerProxy->flushBufferIfNeeded();
+ }
+
if (isOffloaded()) {
// If offloaded we allow flush during any state except terminated
// and keep the track active to avoid problems if user is seeking
@@ -828,6 +835,10 @@
if (!isOffloaded() && !isDirect())
return;
+ // Clear the client ring buffer so that the app can prime the buffer while paused.
+ // Otherwise it might not get cleared until playback is resumed and obtainBuffer() is called.
+ mServerProxy->flushBufferIfNeeded();
+
mFlushHwPending = false;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index b2106cd..cc76ce1 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -4941,6 +4941,18 @@
audio_devices_t device)
{
float volumeDB = mVolumeCurves->volIndexToDb(stream, Volume::getDeviceCategory(device), index);
+
+ // handle the case of accessibility active while a ringtone is playing: if the ringtone is much
+ // louder than the accessibility prompt, the prompt cannot be heard, thus masking the touch
+ // exploration of the dialer UI. In this situation, bring the accessibility volume closer to
+ // the ringtone volume
+ if ((stream == AUDIO_STREAM_ACCESSIBILITY)
+ && (AUDIO_MODE_RINGTONE == mEngine->getPhoneState())
+ && isStreamActive(AUDIO_STREAM_RING, 0)) {
+ const float ringVolumeDB = computeVolume(AUDIO_STREAM_RING, index, device);
+ return ringVolumeDB - 4 > volumeDB ? ringVolumeDB - 4 : volumeDB;
+ }
+
// if a headset is connected, apply the following rules to ring tones and notifications
// to avoid sound level bursts in user's ears:
// - always attenuate notifications volume by 6dB