summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camera/Android.mk5
-rw-r--r--camera/VendorTagDescriptor.cpp7
-rw-r--r--include/ndk/NdkMediaCodec.h57
-rw-r--r--include/ndk/NdkMediaCrypto.h55
-rw-r--r--include/ndk/NdkMediaError.h48
-rw-r--r--include/ndk/NdkMediaExtractor.h29
-rw-r--r--media/ndk/Android.mk2
-rw-r--r--media/ndk/NdkMediaCodec.cpp256
-rw-r--r--media/ndk/NdkMediaCrypto.cpp117
-rw-r--r--media/ndk/NdkMediaCryptoPriv.h41
-rw-r--r--media/ndk/NdkMediaExtractor.cpp148
-rw-r--r--services/audioflinger/AudioFlinger.cpp102
-rw-r--r--services/audioflinger/AudioFlinger.h17
-rw-r--r--services/audioflinger/Effects.cpp4
-rw-r--r--services/audioflinger/Threads.cpp33
-rw-r--r--services/audioflinger/Threads.h19
-rw-r--r--services/audioflinger/Tracks.cpp4
-rw-r--r--services/audiopolicy/AudioPolicyService.cpp184
-rw-r--r--services/audiopolicy/AudioPolicyService.h17
-rw-r--r--services/camera/libcameraservice/api1/client2/Parameters.cpp3
20 files changed, 905 insertions, 243 deletions
diff --git a/camera/Android.mk b/camera/Android.mk
index 18800b4..5774b6f 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -52,11 +52,6 @@ LOCAL_C_INCLUDES += \
system/media/camera/include \
system/media/private/camera/include
-## Enable asserts for 'eng' builds
-ifeq ($(TARGET_BUILD_VARIANT),eng)
-LOCAL_CFLAGS += -UNDEBUG
-endif
-
LOCAL_MODULE:= libcamera_client
include $(BUILD_SHARED_LIBRARY)
diff --git a/camera/VendorTagDescriptor.cpp b/camera/VendorTagDescriptor.cpp
index ba24fcb..59dce91 100644
--- a/camera/VendorTagDescriptor.cpp
+++ b/camera/VendorTagDescriptor.cpp
@@ -120,7 +120,7 @@ status_t VendorTagDescriptor::createDescriptorFromOps(const vendor_tag_ops_t* vO
// Set up tag to section index map
ssize_t index = sections.indexOf(sectionString);
- assert(index >= 0);
+ LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index);
desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index));
// Set up reverse mapping
@@ -217,7 +217,8 @@ status_t VendorTagDescriptor::createFromParcel(const Parcel* parcel,
__FUNCTION__, sectionCount, (maxSectionIndex + 1));
return BAD_VALUE;
}
- assert(desc->mSections.setCapacity(sectionCount) > 0);
+ LOG_ALWAYS_FATAL_IF(desc->mSections.setCapacity(sectionCount) <= 0,
+ "Vector capacity must be positive");
for (size_t i = 0; i < sectionCount; ++i) {
String8 sectionName = parcel->readString8();
if (sectionName.isEmpty()) {
@@ -228,7 +229,7 @@ status_t VendorTagDescriptor::createFromParcel(const Parcel* parcel,
}
}
- assert(tagCount == allTags.size());
+ LOG_ALWAYS_FATAL_IF(tagCount != allTags.size(), "tagCount must be the same as allTags size");
// Set up reverse mapping
for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
uint32_t tag = allTags[i];
diff --git a/include/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h
index 2af88d0..5233fe3 100644
--- a/include/ndk/NdkMediaCodec.h
+++ b/include/ndk/NdkMediaCodec.h
@@ -29,6 +29,7 @@
#include <android/native_window.h>
+#include "NdkMediaCrypto.h"
#include "NdkMediaFormat.h"
#ifdef __cplusplus
@@ -46,6 +47,7 @@ struct AMediaCodecBufferInfo {
uint32_t flags;
};
typedef struct AMediaCodecBufferInfo AMediaCodecBufferInfo;
+typedef struct AMediaCodecCryptoInfo AMediaCodecCryptoInfo;
enum {
AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM = 4,
@@ -55,7 +57,6 @@ enum {
AMEDIACODEC_INFO_TRY_AGAIN_LATER = -1
};
-
/**
* Create codec by name. Use this if you know the exact codec you want to use.
* When configuring, you will need to specify whether to use the codec as an
@@ -82,8 +83,12 @@ int AMediaCodec_delete(AMediaCodec*);
/**
* Configure the codec. For decoding you would typically get the format from an extractor.
*/
-int AMediaCodec_configure(AMediaCodec*, const AMediaFormat* format,
- ANativeWindow* surface, uint32_t flags); // TODO: other args
+int AMediaCodec_configure(
+ AMediaCodec*,
+ const AMediaFormat* format,
+ ANativeWindow* surface,
+ AMediaCrypto *crypto,
+ uint32_t flags);
/**
* Start the codec. A codec must be configured before it can be started, and must be started
@@ -128,6 +133,12 @@ int AMediaCodec_queueInputBuffer(AMediaCodec*,
size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags);
/**
+ * Send the specified buffer to the codec for processing.
+ */
+int AMediaCodec_queueSecureInputBuffer(AMediaCodec*,
+ size_t idx, off_t offset, AMediaCodecCryptoInfo*, uint64_t time, uint32_t flags);
+
+/**
* Get the index of the next available buffer of processed data.
*/
ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec*, AMediaCodecBufferInfo *info, int64_t timeoutUs);
@@ -139,6 +150,46 @@ AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec*);
int AMediaCodec_releaseOutputBuffer(AMediaCodec*, size_t idx, bool render);
+typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata);
+
+/**
+ * Set a callback to be called when a new buffer is available, or there was a format
+ * or buffer change.
+ * Note that you cannot perform any operations on the mediacodec from within the callback.
+ * If you need to perform mediacodec operations, you must do so on a different thread.
+ */
+int AMediaCodec_setNotificationCallback(AMediaCodec*, OnCodecEvent callback, void *userdata);
+
+
+enum {
+ AMEDIACODECRYPTOINFO_MODE_CLEAR = 0,
+ AMEDIACODECRYPTOINFO_MODE_AES_CTR = 1
+};
+
+/**
+ * create an AMediaCodecCryptoInfo from scratch. Use this if you need to use custom
+ * crypto info, rather than one obtained from AMediaExtractor.
+ */
+AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
+ int numsubsamples,
+ uint8_t key[16],
+ uint8_t iv[16],
+ uint32_t mode,
+ size_t *clearbytes,
+ size_t *encryptedbytes);
+
+/**
+ * delete an AMediaCodecCryptoInfo create previously with AMediaCodecCryptoInfo_new, or
+ * obtained from AMediaExtractor
+ */
+int AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo*);
+
+size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo*);
+int AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo*, uint8_t *dst);
+int AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo*, uint8_t *dst);
+uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo*);
+int AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo*, size_t *dst);
+int AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo*, size_t *dst);
#ifdef __cplusplus
} // extern "C"
diff --git a/include/ndk/NdkMediaCrypto.h b/include/ndk/NdkMediaCrypto.h
new file mode 100644
index 0000000..0bcba9f
--- /dev/null
+++ b/include/ndk/NdkMediaCrypto.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_MEDIA_CRYPTO_H
+#define _NDK_MEDIA_CRYPTO_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AMediaCrypto;
+typedef struct AMediaCrypto AMediaCrypto;
+
+typedef uint8_t AMediaUUID[16];
+
+bool AMediaCrypto_isCryptoSchemeSupport(const AMediaUUID uuid);
+
+bool AMediaCrypto_requiresSecureDecoderComponent(const char *mime);
+
+AMediaCrypto* AMediaCrypto_new(const AMediaUUID uuid, const void *initData, size_t initDataSize);
+
+void AMediaCrypto_delete(AMediaCrypto* crypto);
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _NDK_MEDIA_CRYPTO_H
diff --git a/include/ndk/NdkMediaError.h b/include/ndk/NdkMediaError.h
new file mode 100644
index 0000000..b89a10e
--- /dev/null
+++ b/include/ndk/NdkMediaError.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_MEDIA_ERROR_H
+#define _NDK_MEDIA_ERROR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ AMEDIAERROR_BASE = -10000,
+
+ AMEDIAERROR_GENERIC = AMEDIAERROR_BASE,
+ AMEDIAERROR_MALFORMED = AMEDIAERROR_BASE - 1,
+ AMEDIAERROR_UNSUPPORTED = AMEDIAERROR_BASE - 2
+};
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _NDK_MEDIA_ERROR_H
diff --git a/include/ndk/NdkMediaExtractor.h b/include/ndk/NdkMediaExtractor.h
index a7c32c4..9e50ec0 100644
--- a/include/ndk/NdkMediaExtractor.h
+++ b/include/ndk/NdkMediaExtractor.h
@@ -30,7 +30,9 @@
#include <sys/types.h>
+#include "NdkMediaCodec.h"
#include "NdkMediaFormat.h"
+#include "NdkMediaCrypto.h"
#ifdef __cplusplus
extern "C" {
@@ -112,6 +114,33 @@ int64_t AMediaExtractor_getSampletime(AMediaExtractor*);
*/
bool AMediaExtractor_advance(AMediaExtractor*);
+
+/**
+ * mapping of crypto scheme uuid to the scheme specific data for that scheme
+ */
+typedef struct PsshEntry {
+ AMediaUUID uuid;
+ size_t datalen;
+ void *data;
+} PsshEntry;
+
+/**
+ * list of crypto schemes and their data
+ */
+typedef struct PsshInfo {
+ size_t numentries;
+ PsshEntry entries[0];
+} PsshInfo;
+
+/**
+ * Get the PSSH info if present.
+ */
+PsshInfo* AMediaExtractor_getPsshInfo(AMediaExtractor*);
+
+
+AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *);
+
+
enum {
AMEDIAEXTRACTOR_SAMPLE_FLAG_SYNC = 1,
AMEDIAEXTRACTOR_SAMPLE_FLAG_ENCRYPTED = 2,
diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk
index b8dd19e..03f26a0 100644
--- a/media/ndk/Android.mk
+++ b/media/ndk/Android.mk
@@ -22,6 +22,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
NdkMediaCodec.cpp \
+ NdkMediaCrypto.cpp \
NdkMediaExtractor.cpp \
NdkMediaFormat.cpp \
NdkMediaMuxer.cpp \
@@ -34,6 +35,7 @@ LOCAL_C_INCLUDES := \
frameworks/av/include/ndk
LOCAL_SHARED_LIBRARIES := \
+ libbinder \
libmedia \
libstagefright \
libstagefright_foundation \
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 9592af8..1f62fa2 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -18,13 +18,14 @@
#define LOG_TAG "NdkMediaCodec"
#include "NdkMediaCodec.h"
+#include "NdkMediaError.h"
+#include "NdkMediaCryptoPriv.h"
#include "NdkMediaFormatPriv.h"
#include <utils/Log.h>
#include <utils/StrongPointer.h>
#include <gui/Surface.h>
-#include <media/ICrypto.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/ABuffer.h>
@@ -42,29 +43,97 @@ static int translate_error(status_t err) {
return AMEDIACODEC_INFO_TRY_AGAIN_LATER;
}
ALOGE("sf error code: %d", err);
- return -1000;
+ return AMEDIAERROR_GENERIC;
}
+enum {
+ kWhatActivityNotify,
+ kWhatRequestActivityNotifications,
+ kWhatStopActivityNotifications,
+};
+
class CodecHandler: public AHandler {
+private:
+ AMediaCodec* mCodec;
public:
- CodecHandler(sp<android::MediaCodec>);
+ CodecHandler(AMediaCodec *codec);
virtual void onMessageReceived(const sp<AMessage> &msg);
};
-CodecHandler::CodecHandler(sp<android::MediaCodec>) {
+struct AMediaCodec {
+ sp<android::MediaCodec> mCodec;
+ sp<ALooper> mLooper;
+ sp<CodecHandler> mHandler;
+ sp<AMessage> mActivityNotification;
+ int32_t mGeneration;
+ bool mRequestedActivityNotification;
+ OnCodecEvent mCallback;
+ void *mCallbackUserData;
+};
+CodecHandler::CodecHandler(AMediaCodec *codec) {
+ mCodec = codec;
}
void CodecHandler::onMessageReceived(const sp<AMessage> &msg) {
- ALOGI("handler got message %d", msg->what());
+
+ switch (msg->what()) {
+ case kWhatRequestActivityNotifications:
+ {
+ if (mCodec->mRequestedActivityNotification) {
+ break;
+ }
+
+ mCodec->mCodec->requestActivityNotification(mCodec->mActivityNotification);
+ mCodec->mRequestedActivityNotification = true;
+ break;
+ }
+
+ case kWhatActivityNotify:
+ {
+ {
+ int32_t generation;
+ msg->findInt32("generation", &generation);
+
+ if (generation != mCodec->mGeneration) {
+ // stale
+ break;
+ }
+
+ mCodec->mRequestedActivityNotification = false;
+ }
+
+ if (mCodec->mCallback) {
+ mCodec->mCallback(mCodec, mCodec->mCallbackUserData);
+ }
+ break;
+ }
+
+ case kWhatStopActivityNotifications:
+ {
+ uint32_t replyID;
+ msg->senderAwaitsResponse(&replyID);
+
+ mCodec->mGeneration++;
+ mCodec->mRequestedActivityNotification = false;
+
+ sp<AMessage> response = new AMessage;
+ response->postReply(replyID);
+ break;
+ }
+
+ default:
+ ALOGE("shouldn't be here");
+ break;
+ }
+
}
-struct AMediaCodec {
- sp<android::MediaCodec> mCodec;
- sp<ALooper> mLooper;
- sp<CodecHandler> mHandler;
-};
+
+static void requestActivityNotification(AMediaCodec *codec) {
+ (new AMessage(kWhatRequestActivityNotifications, codec->mHandler->id()))->post();
+}
extern "C" {
@@ -76,14 +145,17 @@ static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool
false, // runOnCallingThread
true, // canCallJava XXX
PRIORITY_FOREGROUND);
- ALOGV("looper start: %d", ret);
if (name_is_type) {
mData->mCodec = android::MediaCodec::CreateByType(mData->mLooper, name, encoder);
} else {
mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name);
}
- mData->mHandler = new CodecHandler(mData->mCodec);
+ mData->mHandler = new CodecHandler(mData);
mData->mLooper->registerHandler(mData->mHandler);
+ mData->mGeneration = 1;
+ mData->mRequestedActivityNotification = false;
+ mData->mCallback = NULL;
+
return mData;
}
@@ -116,7 +188,11 @@ int AMediaCodec_delete(AMediaCodec *mData) {
}
int AMediaCodec_configure(
- AMediaCodec *mData, const AMediaFormat* format, ANativeWindow* window, uint32_t flags) {
+ AMediaCodec *mData,
+ const AMediaFormat* format,
+ ANativeWindow* window,
+ AMediaCrypto *crypto,
+ uint32_t flags) {
sp<AMessage> nativeFormat;
AMediaFormat_getFormat(format, &nativeFormat);
ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str());
@@ -125,15 +201,30 @@ int AMediaCodec_configure(
surface = (Surface*) window;
}
- return translate_error(mData->mCodec->configure(nativeFormat, surface, NULL, flags));
+ return translate_error(mData->mCodec->configure(nativeFormat, surface,
+ crypto ? crypto->mCrypto : NULL, flags));
}
int AMediaCodec_start(AMediaCodec *mData) {
- return translate_error(mData->mCodec->start());
+ status_t ret = mData->mCodec->start();
+ if (ret != OK) {
+ return translate_error(ret);
+ }
+ mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler->id());
+ mData->mActivityNotification->setInt32("generation", mData->mGeneration);
+ requestActivityNotification(mData);
+ return OK;
}
int AMediaCodec_stop(AMediaCodec *mData) {
- return translate_error(mData->mCodec->stop());
+ int ret = translate_error(mData->mCodec->stop());
+
+ sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler->id());
+ sp<AMessage> response;
+ msg->postAndAwaitResponse(&response);
+ mData->mActivityNotification.clear();
+
+ return ret;
}
int AMediaCodec_flush(AMediaCodec *mData) {
@@ -143,6 +234,7 @@ int AMediaCodec_flush(AMediaCodec *mData) {
ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) {
size_t idx;
status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs);
+ requestActivityNotification(mData);
if (ret == OK) {
return idx;
}
@@ -200,7 +292,7 @@ ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData,
int64_t presentationTimeUs;
status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs,
&flags, timeoutUs);
-
+ requestActivityNotification(mData);
switch (ret) {
case OK:
info->offset = offset;
@@ -234,5 +326,135 @@ int AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render)
}
}
+int AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) {
+ mData->mCallback = callback;
+ mData->mCallbackUserData = userdata;
+ return OK;
+}
+
+typedef struct AMediaCodecCryptoInfo {
+ int numsubsamples;
+ uint8_t key[16];
+ uint8_t iv[16];
+ uint32_t mode;
+ size_t *clearbytes;
+ size_t *encryptedbytes;
+} AMediaCodecCryptoInfo;
+
+int AMediaCodec_queueSecureInputBuffer(
+ AMediaCodec* codec,
+ size_t idx,
+ off_t offset,
+ AMediaCodecCryptoInfo* crypto,
+ uint64_t time,
+ uint32_t flags) {
+
+ CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples];
+ for (int i = 0; i < crypto->numsubsamples; i++) {
+ subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i];
+ subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i];
+ }
+
+ AString errormsg;
+ status_t err = codec->mCodec->queueSecureInputBuffer(idx,
+ offset,
+ subSamples,
+ crypto->numsubsamples,
+ crypto->key,
+ crypto->iv,
+ (CryptoPlugin::Mode) crypto->mode,
+ time,
+ flags,
+ &errormsg);
+ if (err != 0) {
+ ALOGE("queSecureInputBuffer: %s", errormsg.c_str());
+ }
+ delete subSamples;
+ return translate_error(err);
+}
+
+
+
+AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
+ int numsubsamples,
+ uint8_t key[16],
+ uint8_t iv[16],
+ uint32_t mode,
+ size_t *clearbytes,
+ size_t *encryptedbytes) {
+
+ // size needed to store all the crypto data
+ size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
+ AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
+ if (!ret) {
+ ALOGE("couldn't allocate %d bytes", cryptosize);
+ return NULL;
+ }
+ ret->numsubsamples = numsubsamples;
+ memcpy(ret->key, key, 16);
+ memcpy(ret->iv, iv, 16);
+ ret->mode = mode;
+
+ // clearbytes and encryptedbytes point at the actual data, which follows
+ ret->clearbytes = (size_t*) ((&ret->encryptedbytes) + sizeof(ret->encryptedbytes));
+ ret->encryptedbytes = (size_t*) (ret->clearbytes + (sizeof(size_t) * numsubsamples));
+
+ size_t *dst = ret->clearbytes;
+ memcpy(dst, clearbytes, numsubsamples * sizeof(size_t));
+ dst += numsubsamples * sizeof(size_t);
+ memcpy(dst, encryptedbytes, numsubsamples * sizeof(size_t));
+
+ return ret;
+}
+
+
+int AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
+ free(info);
+ return OK;
+}
+
+size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
+ return ci->numsubsamples;
+}
+
+int AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
+ if (!dst || !ci) {
+ return AMEDIAERROR_UNSUPPORTED;
+ }
+ memcpy(dst, ci->key, 16);
+ return OK;
+}
+
+int AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
+ if (!dst || !ci) {
+ return AMEDIAERROR_UNSUPPORTED;
+ }
+ memcpy(dst, ci->iv, 16);
+ return OK;
+}
+
+uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
+ if (!ci) {
+ return AMEDIAERROR_UNSUPPORTED;
+ }
+ return ci->mode;
+}
+
+int AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
+ if (!dst || !ci) {
+ return AMEDIAERROR_UNSUPPORTED;
+ }
+ memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples);
+ return OK;
+}
+
+int AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
+ if (!dst || !ci) {
+ return AMEDIAERROR_UNSUPPORTED;
+ }
+ memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples);
+ return OK;
+}
+
} // extern "C"
diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp
new file mode 100644
index 0000000..25dfe6a
--- /dev/null
+++ b/media/ndk/NdkMediaCrypto.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "NdkMediaCrypto"
+
+
+#include "NdkMediaCrypto.h"
+#include "NdkMediaCodec.h"
+#include "NdkMediaFormatPriv.h"
+
+
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
+#include <binder/IServiceManager.h>
+#include <media/ICrypto.h>
+#include <media/IMediaPlayerService.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <android_util_Binder.h>
+
+#include <jni.h>
+
+using namespace android;
+
+static int translate_error(status_t err) {
+ if (err == OK) {
+ return OK;
+ }
+ ALOGE("sf error code: %d", err);
+ return -1000;
+}
+
+
+static sp<ICrypto> makeCrypto() {
+ sp<IServiceManager> sm = defaultServiceManager();
+
+ sp<IBinder> binder =
+ sm->getService(String16("media.player"));
+
+ sp<IMediaPlayerService> service =
+ interface_cast<IMediaPlayerService>(binder);
+
+ if (service == NULL) {
+ return NULL;
+ }
+
+ sp<ICrypto> crypto = service->makeCrypto();
+
+ if (crypto == NULL || (crypto->initCheck() != OK && crypto->initCheck() != NO_INIT)) {
+ return NULL;
+ }
+
+ return crypto;
+}
+
+struct AMediaCrypto {
+ sp<ICrypto> mCrypto;
+};
+
+
+extern "C" {
+
+
+bool AMediaCrypto_isCryptoSchemeSupport(const AMediaUUID uuid) {
+ sp<ICrypto> crypto = makeCrypto();
+ if (crypto == NULL) {
+ return false;
+ }
+ return crypto->isCryptoSchemeSupported(uuid);
+}
+
+bool AMediaCrypto_requiresSecureDecoderComponent(const char *mime) {
+ sp<ICrypto> crypto = makeCrypto();
+ if (crypto == NULL) {
+ return false;
+ }
+ return crypto->requiresSecureDecoderComponent(mime);
+}
+
+AMediaCrypto* AMediaCrypto_new(const AMediaUUID uuid, const void *data, size_t datasize) {
+
+ sp<ICrypto> tmp = makeCrypto();
+ if (tmp == NULL) {
+ return NULL;
+ }
+
+ if (tmp->createPlugin(uuid, data, datasize) != 0) {
+ return NULL;
+ }
+
+ AMediaCrypto *crypto = new AMediaCrypto();
+ crypto->mCrypto = tmp;
+
+ return crypto;
+}
+
+void AMediaCrypto_delete(AMediaCrypto* crypto) {
+ delete crypto;
+}
+
+
+
+} // extern "C"
+
diff --git a/media/ndk/NdkMediaCryptoPriv.h b/media/ndk/NdkMediaCryptoPriv.h
new file mode 100644
index 0000000..14ea928
--- /dev/null
+++ b/media/ndk/NdkMediaCryptoPriv.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_MEDIA_CRYPTO_PRIV_H
+#define _NDK_MEDIA_CRYPTO_PRIV_H
+
+#include <sys/types.h>
+#include <utils/StrongPointer.h>
+#include <media/ICrypto.h>
+
+using namespace android;
+
+struct AMediaCrypto {
+ sp<ICrypto> mCrypto;
+};
+
+#endif // _NDK_MEDIA_CRYPTO_PRIV_H
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index 681633a..0a66988 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -18,12 +18,14 @@
#define LOG_TAG "NdkMediaExtractor"
+#include "NdkMediaError.h"
#include "NdkMediaExtractor.h"
#include "NdkMediaFormatPriv.h"
#include <utils/Log.h>
#include <utils/StrongPointer.h>
+#include <media/hardware/CryptoAPI.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MetaData.h>
@@ -41,11 +43,12 @@ static int translate_error(status_t err) {
return OK;
}
ALOGE("sf error code: %d", err);
- return -1000;
+ return AMEDIAERROR_GENERIC;
}
struct AMediaExtractor {
sp<NuMediaExtractor> mImpl;
+ sp<ABuffer> mPsshBuf;
};
@@ -79,14 +82,14 @@ int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location)
if (env == NULL) {
ALOGE("setDataSource(path) must be called from Java thread");
env->ExceptionClear();
- return -1;
+ return AMEDIAERROR_UNSUPPORTED;
}
jclass mediahttpclass = env->FindClass("android/media/MediaHTTPService");
if (mediahttpclass == NULL) {
ALOGE("can't find MediaHttpService");
env->ExceptionClear();
- return -1;
+ return AMEDIAERROR_UNSUPPORTED;
}
jmethodID mediaHttpCreateMethod = env->GetStaticMethodID(mediahttpclass,
@@ -94,7 +97,7 @@ int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location)
if (mediaHttpCreateMethod == NULL) {
ALOGE("can't find method");
env->ExceptionClear();
- return -1;
+ return AMEDIAERROR_UNSUPPORTED;
}
jstring jloc = env->NewStringUTF(location);
@@ -110,7 +113,7 @@ int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location)
mData->mImpl->setDataSource(httpService, location, NULL);
env->ExceptionClear();
- return 0;
+ return OK;
}
int AMediaExtractor_getTrackCount(AMediaExtractor *mData) {
@@ -184,6 +187,141 @@ int64_t AMediaExtractor_getSampletime(AMediaExtractor *mData) {
return time;
}
+PsshInfo* AMediaExtractor_getPsshInfo(AMediaExtractor *ex) {
+
+ if (ex->mPsshBuf != NULL) {
+ return (PsshInfo*) ex->mPsshBuf->data();
+ }
+
+ sp<AMessage> format;
+ ex->mImpl->getFileFormat(&format);
+ sp<ABuffer> buffer;
+ if(!format->findBuffer("pssh", &buffer)) {
+ return NULL;
+ }
+
+ // the format of the buffer is 1 or more of:
+ // {
+ // 16 byte uuid
+ // 4 byte data length N
+ // N bytes of data
+ // }
+
+ // Determine the number of entries in the source data.
+ // Since we got the data from stagefright, we trust it is valid and properly formatted.
+ const uint8_t* data = buffer->data();
+ size_t len = buffer->size();
+ size_t numentries = 0;
+ while (len > 0) {
+ numentries++;
+
+ // skip uuid
+ data += 16;
+ len -= 16;
+
+ // get data length
+ uint32_t datalen = *((uint32_t*)data);
+ data += 4;
+ len -= 4;
+
+ // skip the data
+ data += datalen;
+ len -= datalen;
+ }
+
+ // there are <numentries> in the buffer, we need
+ // (source buffer size) + 4 + (4 * numentries) bytes for the PsshInfo structure
+ size_t newsize = buffer->size() + 4 + (4 * numentries);
+ ex->mPsshBuf = new ABuffer(newsize);
+ ex->mPsshBuf->setRange(0, newsize);
+
+ // copy data
+ const uint8_t* src = buffer->data();
+ uint8_t* dst = ex->mPsshBuf->data();
+ uint8_t* dstdata = dst + 4 + numentries * sizeof(PsshEntry);
+ *((uint32_t*)dst) = numentries;
+ dst += 4;
+ for (size_t i = 0; i < numentries; i++) {
+ // copy uuid
+ memcpy(dst, src, 16);
+ src += 16;
+ dst += 16;
+
+ // get/copy data length
+ uint32_t datalen = *((uint32_t*)src);
+ memcpy(dst, src, 4);
+ src += 4;
+ dst += 4;
+
+ // the next entry in the destination is a pointer to the actual data, which we store
+ // after the array of PsshEntry
+ memcpy(dst, &dstdata, sizeof(dstdata));
+ dst += 4;
+
+ // copy the actual data
+ memcpy(dstdata, src, datalen);
+ dstdata += datalen;
+ src += datalen;
+ }
+
+ return (PsshInfo*) ex->mPsshBuf->data();
+}
+
+AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *ex) {
+ sp<MetaData> meta;
+ if(ex->mImpl->getSampleMeta(&meta) != 0) {
+ return NULL;
+ }
+
+ uint32_t type;
+ const void *crypteddata;
+ size_t cryptedsize;
+ if (!meta->findData(kKeyEncryptedSizes, &type, &crypteddata, &cryptedsize)) {
+ return NULL;
+ }
+ size_t numSubSamples = cryptedsize / sizeof(size_t);
+
+ const void *cleardata;
+ size_t clearsize;
+ if (meta->findData(kKeyPlainSizes, &type, &cleardata, &clearsize)) {
+ if (clearsize != cryptedsize) {
+ // The two must be of the same length.
+ return NULL;
+ }
+ }
+
+ const void *key;
+ size_t keysize;
+ if (meta->findData(kKeyCryptoIV, &type, &key, &keysize)) {
+ if (keysize != 16) {
+ // IVs must be 16 bytes in length.
+ return NULL;
+ }
+ }
+
+ const void *iv;
+ size_t ivsize;
+ if (meta->findData(kKeyCryptoIV, &type, &iv, &ivsize)) {
+ if (ivsize != 16) {
+ // IVs must be 16 bytes in length.
+ return NULL;
+ }
+ }
+
+ int32_t mode;
+ if (!meta->findInt32(kKeyCryptoMode, &mode)) {
+ mode = CryptoPlugin::kMode_AES_CTR;
+ }
+
+ return AMediaCodecCryptoInfo_new(
+ numSubSamples,
+ (uint8_t*) key,
+ (uint8_t*) iv,
+ mode,
+ (size_t*) cleardata,
+ (size_t*) crypteddata);
+}
+
} // extern "C"
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index e256f32..11170c2 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -82,6 +82,7 @@ namespace android {
static const char kDeadlockedString[] = "AudioFlinger may be deadlocked\n";
static const char kHardwareLockedString[] = "Hardware lock is taken\n";
+static const char kClientLockedString[] = "Client lock is taken\n";
nsecs_t AudioFlinger::mStandbyTimeInNsecs = kDefaultStandbyTimeInNsecs;
@@ -382,7 +383,16 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
write(fd, result.string(), result.size());
}
+ bool clientLocked = dumpTryLock(mClientLock);
+ if (!clientLocked) {
+ String8 result(kClientLockedString);
+ write(fd, result.string(), result.size());
+ }
dumpClients(fd, args);
+ if (clientLocked) {
+ mClientLock.unlock();
+ }
+
dumpInternals(fd, args);
// dump playback threads
@@ -426,8 +436,9 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
return NO_ERROR;
}
-sp<AudioFlinger::Client> AudioFlinger::registerPid_l(pid_t pid)
+sp<AudioFlinger::Client> AudioFlinger::registerPid(pid_t pid)
{
+ Mutex::Autolock _cl(mClientLock);
// If pid is already in the mClients wp<> map, then use that entry
// (for which promote() is always != 0), otherwise create a new entry and Client.
sp<Client> client = mClients.valueFor(pid).promote();
@@ -564,7 +575,7 @@ sp<IAudioTrack> AudioFlinger::createTrack(
}
pid_t pid = IPCThreadState::self()->getCallingPid();
- client = registerPid_l(pid);
+ client = registerPid(pid);
PlaybackThread *effectThread = NULL;
if (sessionId != NULL && *sessionId != AUDIO_SESSION_ALLOCATE) {
@@ -623,7 +634,8 @@ sp<IAudioTrack> AudioFlinger::createTrack(
if (lStatus != NO_ERROR) {
// remove local strong reference to Client before deleting the Track so that the
- // Client destructor is called by the TrackBase destructor with mLock held
+ // Client destructor is called by the TrackBase destructor with mClientLock held
+ Mutex::Autolock _cl(mClientLock);
client.clear();
track.clear();
goto Exit;
@@ -1140,21 +1152,29 @@ status_t AudioFlinger::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrame
void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
{
-
Mutex::Autolock _l(mLock);
+ bool clientAdded = false;
+ {
+ Mutex::Autolock _cl(mClientLock);
- pid_t pid = IPCThreadState::self()->getCallingPid();
- if (mNotificationClients.indexOfKey(pid) < 0) {
- sp<NotificationClient> notificationClient = new NotificationClient(this,
- client,
- pid);
- ALOGV("registerClient() client %p, pid %d", notificationClient.get(), pid);
+ pid_t pid = IPCThreadState::self()->getCallingPid();
+ if (mNotificationClients.indexOfKey(pid) < 0) {
+ sp<NotificationClient> notificationClient = new NotificationClient(this,
+ client,
+ pid);
+ ALOGV("registerClient() client %p, pid %d", notificationClient.get(), pid);
- mNotificationClients.add(pid, notificationClient);
+ mNotificationClients.add(pid, notificationClient);
- sp<IBinder> binder = client->asBinder();
- binder->linkToDeath(notificationClient);
+ sp<IBinder> binder = client->asBinder();
+ binder->linkToDeath(notificationClient);
+ clientAdded = true;
+ }
+ }
+ // mClientLock should not be held here because ThreadBase::sendIoConfigEvent() will lock the
+ // ThreadBase mutex and teh locknig order is ThreadBase::mLock then AudioFlinger::mClientLock.
+ if (clientAdded) {
// the config change is always sent from playback or record threads to avoid deadlock
// with AudioSystem::gLock
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
@@ -1170,8 +1190,10 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
void AudioFlinger::removeNotificationClient(pid_t pid)
{
Mutex::Autolock _l(mLock);
-
- mNotificationClients.removeItem(pid);
+ {
+ Mutex::Autolock _cl(mClientLock);
+ mNotificationClients.removeItem(pid);
+ }
ALOGV("%d died, releasing its sessions", pid);
size_t num = mAudioSessionRefs.size();
@@ -1194,22 +1216,18 @@ void AudioFlinger::removeNotificationClient(pid_t pid)
}
}
-// audioConfigChanged_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::audioConfigChanged_l(
- const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
- int event,
- audio_io_handle_t ioHandle,
- const void *param2)
+void AudioFlinger::audioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2)
{
- size_t size = notificationClients.size();
+ Mutex::Autolock _l(mClientLock);
+ size_t size = mNotificationClients.size();
for (size_t i = 0; i < size; i++) {
- notificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event,
+ mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event,
ioHandle,
param2);
}
}
-// removeClient_l() must be called with AudioFlinger::mLock held
+// removeClient_l() must be called with AudioFlinger::mClientLock held
void AudioFlinger::removeClient_l(pid_t pid)
{
ALOGV("removeClient_l() pid %d, calling pid %d", pid,
@@ -1247,7 +1265,7 @@ AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
// 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
}
-// Client destructor must be called with AudioFlinger::mLock held
+// Client destructor must be called with AudioFlinger::mClientLock held
AudioFlinger::Client::~Client()
{
mAudioFlinger->removeClient_l(mPid);
@@ -1377,7 +1395,7 @@ sp<IAudioRecord> AudioFlinger::openRecord(
}
pid_t pid = IPCThreadState::self()->getCallingPid();
- client = registerPid_l(pid);
+ client = registerPid(pid);
if (sessionId != NULL && *sessionId != AUDIO_SESSION_ALLOCATE) {
lSessionId = *sessionId;
@@ -1400,7 +1418,8 @@ sp<IAudioRecord> AudioFlinger::openRecord(
if (lStatus != NO_ERROR) {
// remove local strong reference to Client before deleting the RecordTrack so that the
- // Client destructor is called by the TrackBase destructor with mLock held
+ // Client destructor is called by the TrackBase destructor with mClientLock held
+ Mutex::Autolock _cl(mClientLock);
client.clear();
recordTrack.clear();
goto Exit;
@@ -1638,7 +1657,7 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
}
// notify client processes of the new output creation
- thread->audioConfigChanged_l(mNotificationClients, AudioSystem::OUTPUT_OPENED);
+ thread->audioConfigChanged(AudioSystem::OUTPUT_OPENED);
// the first primary output opened designates the primary hw device
if ((mPrimaryHardwareDev == NULL) && (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
@@ -1674,7 +1693,7 @@ audio_io_handle_t AudioFlinger::openDuplicateOutput(audio_io_handle_t output1,
thread->addOutputTrack(thread2);
mPlaybackThreads.add(id, thread);
// notify client processes of the new output creation
- thread->audioConfigChanged_l(mNotificationClients, AudioSystem::OUTPUT_OPENED);
+ thread->audioConfigChanged(AudioSystem::OUTPUT_OPENED);
return id;
}
@@ -1724,7 +1743,7 @@ status_t AudioFlinger::closeOutput_nonvirtual(audio_io_handle_t output)
}
}
}
- audioConfigChanged_l(mNotificationClients, AudioSystem::OUTPUT_CLOSED, output, NULL);
+ audioConfigChanged(AudioSystem::OUTPUT_CLOSED, output, NULL);
}
thread->exit();
// The thread entity (active unit of execution) is no longer running here,
@@ -1904,7 +1923,7 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
}
// notify client processes of the new input creation
- thread->audioConfigChanged_l(mNotificationClients, AudioSystem::INPUT_OPENED);
+ thread->audioConfigChanged(AudioSystem::INPUT_OPENED);
return id;
}
@@ -1929,7 +1948,7 @@ status_t AudioFlinger::closeInput_nonvirtual(audio_io_handle_t input)
}
ALOGV("closeInput() %d", input);
- audioConfigChanged_l(mNotificationClients, AudioSystem::INPUT_CLOSED, input, NULL);
+ audioConfigChanged(AudioSystem::INPUT_CLOSED, input, NULL);
mRecordThreads.removeItem(input);
}
thread->exit();
@@ -1973,13 +1992,16 @@ void AudioFlinger::acquireAudioSessionId(int audioSession, pid_t pid)
caller = pid;
}
- // Ignore requests received from processes not known as notification client. The request
- // is likely proxied by mediaserver (e.g CameraService) and releaseAudioSessionId() can be
- // called from a different pid leaving a stale session reference. Also we don't know how
- // to clear this reference if the client process dies.
- if (mNotificationClients.indexOfKey(caller) < 0) {
- ALOGW("acquireAudioSessionId() unknown client %d for session %d", caller, audioSession);
- return;
+ {
+ Mutex::Autolock _cl(mClientLock);
+ // Ignore requests received from processes not known as notification client. The request
+ // is likely proxied by mediaserver (e.g CameraService) and releaseAudioSessionId() can be
+ // called from a different pid leaving a stale session reference. Also we don't know how
+ // to clear this reference if the client process dies.
+ if (mNotificationClients.indexOfKey(caller) < 0) {
+ ALOGW("acquireAudioSessionId() unknown client %d for session %d", caller, audioSession);
+ return;
+ }
}
size_t num = mAudioSessionRefs.size();
@@ -2348,7 +2370,7 @@ sp<IEffect> AudioFlinger::createEffect(
}
}
- sp<Client> client = registerPid_l(pid);
+ sp<Client> client = registerPid(pid);
// create effect on selected output thread
handle = thread->createEffect_l(client, effectClient, priority, sessionId,
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index fd9fe96..d69d6a2 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -454,11 +454,7 @@ private:
// no range check, doesn't check per-thread stream volume, AudioFlinger::mLock held
float streamVolume_l(audio_stream_type_t stream) const
{ return mStreamTypes[stream].volume; }
- void audioConfigChanged_l(const DefaultKeyedVector< pid_t,sp<NotificationClient> >&
- notificationClients,
- int event,
- audio_io_handle_t ioHandle,
- const void *param2);
+ void audioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2);
// Allocate an audio_io_handle_t, session ID, effect ID, or audio_module_handle_t.
// They all share the same ID space, but the namespaces are actually independent
@@ -483,8 +479,6 @@ private:
void removeClient_l(pid_t pid);
void removeNotificationClient(pid_t pid);
- DefaultKeyedVector< pid_t,sp<NotificationClient> > notificationClients() {
- Mutex::Autolock _l(mLock); return mNotificationClients; }
bool isNonOffloadableGlobalEffectEnabled_l();
void onNonOffloadableGlobalEffectEnable();
@@ -554,7 +548,11 @@ private:
};
mutable Mutex mLock;
-
+ // protects mClients and mNotificationClients.
+ // must be locked after mLock and ThreadBase::mLock if both must be locked
+ // avoids acquiring AudioFlinger::mLock from inside thread loop.
+ mutable Mutex mClientLock;
+ // protected by mClientLock
DefaultKeyedVector< pid_t, wp<Client> > mClients; // see ~Client()
mutable Mutex mHardwareLock;
@@ -603,6 +601,7 @@ private:
DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> > mRecordThreads;
+ // protected by mClientLock
DefaultKeyedVector< pid_t, sp<NotificationClient> > mNotificationClients;
volatile int32_t mNextUniqueId; // updated by android_atomic_inc
@@ -623,7 +622,7 @@ private:
// to be created
private:
- sp<Client> registerPid_l(pid_t pid); // always returns non-0
+ sp<Client> registerPid(pid_t pid); // always returns non-0
// for use from destructor
status_t closeOutput_nonvirtual(audio_io_handle_t output);
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 29b56db..77aca00 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1162,8 +1162,8 @@ void AudioFlinger::EffectHandle::disconnect(bool unpinIfLast)
mCblk->~effect_param_cblk_t(); // destroy our shared-structure.
}
mCblkMemory.clear(); // free the shared memory before releasing the heap it belongs to
- // Client destructor must run with AudioFlinger mutex locked
- Mutex::Autolock _l(mClient->audioFlinger()->mLock);
+ // Client destructor must run with AudioFlinger client mutex locked
+ Mutex::Autolock _l(mClient->audioFlinger()->mClientLock);
mClient.clear();
}
}
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 91d63e7..2d4e025 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -401,8 +401,7 @@ status_t AudioFlinger::ThreadBase::sendSetParameterConfigEvent_l(const String8&
}
// post condition: mConfigEvents.isEmpty()
-void AudioFlinger::ThreadBase::processConfigEvents_l(
- const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients)
+void AudioFlinger::ThreadBase::processConfigEvents_l()
{
bool configChanged = false;
@@ -423,7 +422,7 @@ void AudioFlinger::ThreadBase::processConfigEvents_l(
} break;
case CFG_EVENT_IO: {
IoConfigEventData *data = (IoConfigEventData *)event->mData.get();
- audioConfigChanged_l(notificationClients, data->mEvent, data->mParam);
+ audioConfigChanged(data->mEvent, data->mParam);
} break;
case CFG_EVENT_SET_PARAMETER: {
SetParameterConfigEventData *data = (SetParameterConfigEventData *)event->mData.get();
@@ -1638,15 +1637,11 @@ String8 AudioFlinger::PlaybackThread::getParameters(const String8& keys)
return out_s8;
}
-// audioConfigChanged_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::PlaybackThread::audioConfigChanged_l(
- const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
- int event,
- int param) {
+void AudioFlinger::PlaybackThread::audioConfigChanged(int event, int param) {
AudioSystem::OutputDescriptor desc;
void *param2 = NULL;
- ALOGV("PlaybackThread::audioConfigChanged_l, thread %p, event %d, param %d", this, event,
+ ALOGV("PlaybackThread::audioConfigChanged, thread %p, event %d, param %d", this, event,
param);
switch (event) {
@@ -1667,7 +1662,7 @@ void AudioFlinger::PlaybackThread::audioConfigChanged_l(
default:
break;
}
- mAudioFlinger->audioConfigChanged_l(notificationClients, event, mId, param2);
+ mAudioFlinger->audioConfigChanged(event, mId, param2);
}
void AudioFlinger::PlaybackThread::writeCallback()
@@ -2317,15 +2312,11 @@ bool AudioFlinger::PlaybackThread::threadLoop()
Vector< sp<EffectChain> > effectChains;
- DefaultKeyedVector< pid_t,sp<NotificationClient> > notificationClients =
- mAudioFlinger->notificationClients();
-
{ // scope for mLock
Mutex::Autolock _l(mLock);
- processConfigEvents_l(notificationClients);
- notificationClients.clear();
+ processConfigEvents_l();
if (logString != NULL) {
mNBLogWriter->logTimestamp();
@@ -4695,14 +4686,11 @@ reacquire_wakelock:
// activeTracks accumulates a copy of a subset of mActiveTracks
Vector< sp<RecordTrack> > activeTracks;
- DefaultKeyedVector< pid_t,sp<NotificationClient> > notificationClients =
- mAudioFlinger->notificationClients();
{ // scope for mLock
Mutex::Autolock _l(mLock);
- processConfigEvents_l(notificationClients);
- notificationClients.clear();
+ processConfigEvents_l();
// check exitPending here because checkForNewParameters_l() and
// checkForNewParameters_l() can temporarily release mLock
@@ -5605,10 +5593,7 @@ String8 AudioFlinger::RecordThread::getParameters(const String8& keys)
return out_s8;
}
-void AudioFlinger::RecordThread::audioConfigChanged_l(
- const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
- int event,
- int param __unused) {
+void AudioFlinger::RecordThread::audioConfigChanged(int event, int param __unused) {
AudioSystem::OutputDescriptor desc;
const void *param2 = NULL;
@@ -5627,7 +5612,7 @@ void AudioFlinger::RecordThread::audioConfigChanged_l(
default:
break;
}
- mAudioFlinger->audioConfigChanged_l(notificationClients, event, mId, param2);
+ mAudioFlinger->audioConfigChanged(event, mId, param2);
}
void AudioFlinger::RecordThread::readInputParameters_l()
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 9578993..cc2b246 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -200,10 +200,7 @@ public:
status_t& status) = 0;
virtual status_t setParameters(const String8& keyValuePairs);
virtual String8 getParameters(const String8& keys) = 0;
- virtual void audioConfigChanged_l(
- const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
- int event,
- int param = 0) = 0;
+ virtual void audioConfigChanged(int event, int param = 0) = 0;
// sendConfigEvent_l() must be called with ThreadBase::mLock held
// Can temporarily release the lock if waiting for a reply from
// processConfigEvents_l().
@@ -212,8 +209,7 @@ public:
void sendIoConfigEvent_l(int event, int param = 0);
void sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio);
status_t sendSetParameterConfigEvent_l(const String8& keyValuePair);
- void processConfigEvents_l(
- const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients);
+ void processConfigEvents_l();
virtual void cacheParameters_l() = 0;
// see note at declaration of mStandby, mOutDevice and mInDevice
@@ -502,10 +498,7 @@ public:
{ return android_atomic_acquire_load(&mSuspended) > 0; }
virtual String8 getParameters(const String8& keys);
- virtual void audioConfigChanged_l(
- const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
- int event,
- int param = 0);
+ virtual void audioConfigChanged(int event, int param = 0);
status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
// FIXME rename mixBuffer() to sinkBuffer() and remove int16_t* dependency.
// Consider also removing and passing an explicit mMainBuffer initialization
@@ -652,7 +645,6 @@ private:
friend class AudioFlinger; // for numerous
- PlaybackThread(const Client&);
PlaybackThread& operator = (const PlaybackThread&);
status_t addTrack_l(const sp<Track>& track);
@@ -1037,10 +1029,7 @@ public:
status_t& status);
virtual void cacheParameters_l() {}
virtual String8 getParameters(const String8& keys);
- virtual void audioConfigChanged_l(
- const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
- int event,
- int param = 0);
+ virtual void audioConfigChanged(int event, int param = 0);
void readInputParameters_l();
virtual uint32_t getInputFramesLost();
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 56107aa..6dc7f30 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -200,8 +200,8 @@ AudioFlinger::ThreadBase::TrackBase::~TrackBase()
}
mCblkMemory.clear(); // free the shared memory before releasing the heap it belongs to
if (mClient != 0) {
- // Client destructor must run with AudioFlinger mutex locked
- Mutex::Autolock _l(mClient->audioFlinger()->mLock);
+ // Client destructor must run with AudioFlinger client mutex locked
+ Mutex::Autolock _l(mClient->audioFlinger()->mClientLock);
// If the client's reference count drops to zero, the associated destructor
// must run with AudioFlinger lock held. Thus the explicit clear() rather than
// relying on the automatic clear() at end of scope.
diff --git a/services/audiopolicy/AudioPolicyService.cpp b/services/audiopolicy/AudioPolicyService.cpp
index 2811475..4e9a2f0 100644
--- a/services/audiopolicy/AudioPolicyService.cpp
+++ b/services/audiopolicy/AudioPolicyService.cpp
@@ -51,7 +51,7 @@ static const char kCmdDeadlockedString[] = "AudioPolicyService command thread ma
static const int kDumpLockRetries = 50;
static const int kDumpLockSleepUs = 20000;
-static const nsecs_t kAudioCommandTimeout = 3000000000LL; // 3 seconds
+static const nsecs_t kAudioCommandTimeoutNs = seconds(3); // 3 seconds
namespace {
extern struct audio_policy_service_ops aps_ops;
@@ -268,10 +268,6 @@ AudioPolicyService::AudioCommandThread::~AudioCommandThread()
if (!mAudioCommands.isEmpty()) {
release_wake_lock(mName.string());
}
- for (size_t k=0; k < mAudioCommands.size(); k++) {
- delete mAudioCommands[k]->mParam;
- delete mAudioCommands[k];
- }
mAudioCommands.clear();
delete mpToneGenerator;
}
@@ -292,20 +288,19 @@ bool AudioPolicyService::AudioCommandThread::threadLoop()
nsecs_t curTime = systemTime();
// commands are sorted by increasing time stamp: execute them from index 0 and up
if (mAudioCommands[0]->mTime <= curTime) {
- AudioCommand *command = mAudioCommands[0];
+ sp<AudioCommand> command = mAudioCommands[0];
mAudioCommands.removeAt(0);
- mLastCommand = *command;
+ mLastCommand = command;
switch (command->mCommand) {
case START_TONE: {
mLock.unlock();
- ToneData *data = (ToneData *)command->mParam;
+ ToneData *data = (ToneData *)command->mParam.get();
ALOGV("AudioCommandThread() processing start tone %d on stream %d",
data->mType, data->mStream);
delete mpToneGenerator;
mpToneGenerator = new ToneGenerator(data->mStream, 1.0);
mpToneGenerator->startTone(data->mType);
- delete data;
mLock.lock();
}break;
case STOP_TONE: {
@@ -319,42 +314,27 @@ bool AudioPolicyService::AudioCommandThread::threadLoop()
mLock.lock();
}break;
case SET_VOLUME: {
- VolumeData *data = (VolumeData *)command->mParam;
+ VolumeData *data = (VolumeData *)command->mParam.get();
ALOGV("AudioCommandThread() processing set volume stream %d, \
volume %f, output %d", data->mStream, data->mVolume, data->mIO);
command->mStatus = AudioSystem::setStreamVolume(data->mStream,
data->mVolume,
data->mIO);
- if (command->mWaitStatus) {
- command->mCond.signal();
- command->mCond.waitRelative(mLock, kAudioCommandTimeout);
- }
- delete data;
}break;
case SET_PARAMETERS: {
- ParametersData *data = (ParametersData *)command->mParam;
+ ParametersData *data = (ParametersData *)command->mParam.get();
ALOGV("AudioCommandThread() processing set parameters string %s, io %d",
data->mKeyValuePairs.string(), data->mIO);
command->mStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);
- if (command->mWaitStatus) {
- command->mCond.signal();
- command->mCond.waitRelative(mLock, kAudioCommandTimeout);
- }
- delete data;
}break;
case SET_VOICE_VOLUME: {
- VoiceVolumeData *data = (VoiceVolumeData *)command->mParam;
+ VoiceVolumeData *data = (VoiceVolumeData *)command->mParam.get();
ALOGV("AudioCommandThread() processing set voice volume volume %f",
data->mVolume);
command->mStatus = AudioSystem::setVoiceVolume(data->mVolume);
- if (command->mWaitStatus) {
- command->mCond.signal();
- command->mCond.waitRelative(mLock, kAudioCommandTimeout);
- }
- delete data;
}break;
case STOP_OUTPUT: {
- StopOutputData *data = (StopOutputData *)command->mParam;
+ StopOutputData *data = (StopOutputData *)command->mParam.get();
ALOGV("AudioCommandThread() processing stop output %d",
data->mIO);
sp<AudioPolicyService> svc = mService.promote();
@@ -364,10 +344,9 @@ bool AudioPolicyService::AudioCommandThread::threadLoop()
mLock.unlock();
svc->doStopOutput(data->mIO, data->mStream, data->mSession);
mLock.lock();
- delete data;
}break;
case RELEASE_OUTPUT: {
- ReleaseOutputData *data = (ReleaseOutputData *)command->mParam;
+ ReleaseOutputData *data = (ReleaseOutputData *)command->mParam.get();
ALOGV("AudioCommandThread() processing release output %d",
data->mIO);
sp<AudioPolicyService> svc = mService.promote();
@@ -377,12 +356,17 @@ bool AudioPolicyService::AudioCommandThread::threadLoop()
mLock.unlock();
svc->doReleaseOutput(data->mIO);
mLock.lock();
- delete data;
}break;
default:
ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
}
- delete command;
+ {
+ Mutex::Autolock _l(command->mLock);
+ if (command->mWaitStatus) {
+ command->mWaitStatus = false;
+ command->mCond.signal();
+ }
+ }
waitTime = INT64_MAX;
} else {
waitTime = mAudioCommands[0]->mTime - curTime;
@@ -425,8 +409,12 @@ status_t AudioPolicyService::AudioCommandThread::dump(int fd)
result.append(buffer);
}
result.append(" Last Command\n");
- mLastCommand.dump(buffer, SIZE);
- result.append(buffer);
+ if (mLastCommand != 0) {
+ mLastCommand->dump(buffer, SIZE);
+ result.append(buffer);
+ } else {
+ result.append(" none\n");
+ }
write(fd, result.string(), result.size());
@@ -438,27 +426,22 @@ status_t AudioPolicyService::AudioCommandThread::dump(int fd)
void AudioPolicyService::AudioCommandThread::startToneCommand(ToneGenerator::tone_type type,
audio_stream_type_t stream)
{
- AudioCommand *command = new AudioCommand();
+ sp<AudioCommand> command = new AudioCommand();
command->mCommand = START_TONE;
- ToneData *data = new ToneData();
+ sp<ToneData> data = new ToneData();
data->mType = type;
data->mStream = stream;
command->mParam = data;
- Mutex::Autolock _l(mLock);
- insertCommand_l(command);
ALOGV("AudioCommandThread() adding tone start type %d, stream %d", type, stream);
- mWaitWorkCV.signal();
+ sendCommand(command);
}
void AudioPolicyService::AudioCommandThread::stopToneCommand()
{
- AudioCommand *command = new AudioCommand();
+ sp<AudioCommand> command = new AudioCommand();
command->mCommand = STOP_TONE;
- command->mParam = NULL;
- Mutex::Autolock _l(mLock);
- insertCommand_l(command);
ALOGV("AudioCommandThread() adding tone stop");
- mWaitWorkCV.signal();
+ sendCommand(command);
}
status_t AudioPolicyService::AudioCommandThread::volumeCommand(audio_stream_type_t stream,
@@ -466,109 +449,96 @@ status_t AudioPolicyService::AudioCommandThread::volumeCommand(audio_stream_type
audio_io_handle_t output,
int delayMs)
{
- status_t status = NO_ERROR;
-
- AudioCommand *command = new AudioCommand();
+ sp<AudioCommand> command = new AudioCommand();
command->mCommand = SET_VOLUME;
- VolumeData *data = new VolumeData();
+ sp<VolumeData> data = new VolumeData();
data->mStream = stream;
data->mVolume = volume;
data->mIO = output;
command->mParam = data;
- Mutex::Autolock _l(mLock);
- insertCommand_l(command, delayMs);
+ command->mWaitStatus = true;
ALOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d",
stream, volume, output);
- mWaitWorkCV.signal();
- if (command->mWaitStatus) {
- command->mCond.wait(mLock);
- status = command->mStatus;
- command->mCond.signal();
- }
- return status;
+ return sendCommand(command, delayMs);
}
status_t AudioPolicyService::AudioCommandThread::parametersCommand(audio_io_handle_t ioHandle,
const char *keyValuePairs,
int delayMs)
{
- status_t status = NO_ERROR;
-
- AudioCommand *command = new AudioCommand();
+ sp<AudioCommand> command = new AudioCommand();
command->mCommand = SET_PARAMETERS;
- ParametersData *data = new ParametersData();
+ sp<ParametersData> data = new ParametersData();
data->mIO = ioHandle;
data->mKeyValuePairs = String8(keyValuePairs);
command->mParam = data;
- Mutex::Autolock _l(mLock);
- insertCommand_l(command, delayMs);
+ command->mWaitStatus = true;
ALOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d",
keyValuePairs, ioHandle, delayMs);
- mWaitWorkCV.signal();
- if (command->mWaitStatus) {
- command->mCond.wait(mLock);
- status = command->mStatus;
- command->mCond.signal();
- }
- return status;
+ return sendCommand(command, delayMs);
}
status_t AudioPolicyService::AudioCommandThread::voiceVolumeCommand(float volume, int delayMs)
{
- status_t status = NO_ERROR;
-
- AudioCommand *command = new AudioCommand();
+ sp<AudioCommand> command = new AudioCommand();
command->mCommand = SET_VOICE_VOLUME;
- VoiceVolumeData *data = new VoiceVolumeData();
+ sp<VoiceVolumeData> data = new VoiceVolumeData();
data->mVolume = volume;
command->mParam = data;
- Mutex::Autolock _l(mLock);
- insertCommand_l(command, delayMs);
+ command->mWaitStatus = true;
ALOGV("AudioCommandThread() adding set voice volume volume %f", volume);
- mWaitWorkCV.signal();
- if (command->mWaitStatus) {
- command->mCond.wait(mLock);
- status = command->mStatus;
- command->mCond.signal();
- }
- return status;
+ return sendCommand(command, delayMs);
}
void AudioPolicyService::AudioCommandThread::stopOutputCommand(audio_io_handle_t output,
audio_stream_type_t stream,
int session)
{
- AudioCommand *command = new AudioCommand();
+ sp<AudioCommand> command = new AudioCommand();
command->mCommand = STOP_OUTPUT;
- StopOutputData *data = new StopOutputData();
+ sp<StopOutputData> data = new StopOutputData();
data->mIO = output;
data->mStream = stream;
data->mSession = session;
command->mParam = data;
- Mutex::Autolock _l(mLock);
- insertCommand_l(command);
ALOGV("AudioCommandThread() adding stop output %d", output);
- mWaitWorkCV.signal();
+ sendCommand(command);
}
void AudioPolicyService::AudioCommandThread::releaseOutputCommand(audio_io_handle_t output)
{
- AudioCommand *command = new AudioCommand();
+ sp<AudioCommand> command = new AudioCommand();
command->mCommand = RELEASE_OUTPUT;
- ReleaseOutputData *data = new ReleaseOutputData();
+ sp<ReleaseOutputData> data = new ReleaseOutputData();
data->mIO = output;
command->mParam = data;
- Mutex::Autolock _l(mLock);
- insertCommand_l(command);
ALOGV("AudioCommandThread() adding release output %d", output);
- mWaitWorkCV.signal();
+ sendCommand(command);
+}
+
+status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
+{
+ {
+ Mutex::Autolock _l(mLock);
+ insertCommand_l(command, delayMs);
+ mWaitWorkCV.signal();
+ }
+ Mutex::Autolock _l(command->mLock);
+ while (command->mWaitStatus) {
+ nsecs_t timeOutNs = kAudioCommandTimeoutNs + milliseconds(delayMs);
+ if (command->mCond.waitRelative(command->mLock, timeOutNs) != NO_ERROR) {
+ command->mStatus = TIMED_OUT;
+ command->mWaitStatus = false;
+ }
+ }
+ return command->mStatus;
}
// insertCommand_l() must be called with mLock held
-void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *command, int delayMs)
+void AudioPolicyService::AudioCommandThread::insertCommand_l(sp<AudioCommand>& command, int delayMs)
{
ssize_t i; // not size_t because i will count down to -1
- Vector <AudioCommand *> removedCommands;
+ Vector < sp<AudioCommand> > removedCommands;
command->mTime = systemTime() + milliseconds(delayMs);
// acquire wake lock to make sure delayed commands are processed
@@ -578,15 +548,15 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma
// check same pending commands with later time stamps and eliminate them
for (i = mAudioCommands.size()-1; i >= 0; i--) {
- AudioCommand *command2 = mAudioCommands[i];
+ sp<AudioCommand> command2 = mAudioCommands[i];
// commands are sorted by increasing time stamp: no need to scan the rest of mAudioCommands
if (command2->mTime <= command->mTime) break;
if (command2->mCommand != command->mCommand) continue;
switch (command->mCommand) {
case SET_PARAMETERS: {
- ParametersData *data = (ParametersData *)command->mParam;
- ParametersData *data2 = (ParametersData *)command2->mParam;
+ ParametersData *data = (ParametersData *)command->mParam.get();
+ ParametersData *data2 = (ParametersData *)command2->mParam.get();
if (data->mIO != data2->mIO) break;
ALOGV("Comparing parameter command %s to new command %s",
data2->mKeyValuePairs.string(), data->mKeyValuePairs.string());
@@ -621,8 +591,8 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma
} break;
case SET_VOLUME: {
- VolumeData *data = (VolumeData *)command->mParam;
- VolumeData *data2 = (VolumeData *)command2->mParam;
+ VolumeData *data = (VolumeData *)command->mParam.get();
+ VolumeData *data2 = (VolumeData *)command2->mParam.get();
if (data->mIO != data2->mIO) break;
if (data->mStream != data2->mStream) break;
ALOGV("Filtering out volume command on output %d for stream %d",
@@ -644,12 +614,8 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma
for (size_t j = 0; j < removedCommands.size(); j++) {
// removed commands always have time stamps greater than current command
for (size_t k = i + 1; k < mAudioCommands.size(); k++) {
- if (mAudioCommands[k] == removedCommands[j]) {
+ if (mAudioCommands[k].get() == removedCommands[j].get()) {
ALOGV("suppressing command: %d", mAudioCommands[k]->mCommand);
- // for commands that are not filtered,
- // command->mParam is deleted in threadLoop
- delete mAudioCommands[k]->mParam;
- delete mAudioCommands[k];
mAudioCommands.removeAt(k);
break;
}
@@ -657,10 +623,8 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma
}
removedCommands.clear();
- // wait for status only if delay is 0
- if (delayMs == 0) {
- command->mWaitStatus = true;
- } else {
+ // Disable wait for status if delay is not 0
+ if (delayMs != 0) {
command->mWaitStatus = false;
}
@@ -688,7 +652,7 @@ void AudioPolicyService::AudioCommandThread::AudioCommand::dump(char* buffer, si
(int)ns2s(mTime),
(int)ns2ms(mTime)%1000,
mWaitStatus,
- mParam);
+ mParam.get());
}
/******* helpers for the service_ops callbacks defined below *********/
diff --git a/services/audiopolicy/AudioPolicyService.h b/services/audiopolicy/AudioPolicyService.h
index 28e3a4b..26037e4 100644
--- a/services/audiopolicy/AudioPolicyService.h
+++ b/services/audiopolicy/AudioPolicyService.h
@@ -194,30 +194,31 @@ private:
audio_stream_type_t stream,
int session);
void releaseOutputCommand(audio_io_handle_t output);
-
- void insertCommand_l(AudioCommand *command, int delayMs = 0);
+ status_t sendCommand(sp<AudioCommand>& command, int delayMs = 0);
+ void insertCommand_l(sp<AudioCommand>& command, int delayMs = 0);
private:
class AudioCommandData;
// descriptor for requested tone playback event
- class AudioCommand {
+ class AudioCommand: public RefBase {
public:
AudioCommand()
- : mCommand(-1) {}
+ : mCommand(-1), mStatus(NO_ERROR), mWaitStatus(false) {}
void dump(char* buffer, size_t size);
int mCommand; // START_TONE, STOP_TONE ...
nsecs_t mTime; // time stamp
+ Mutex mLock; // mutex associated to mCond
Condition mCond; // condition for status return
status_t mStatus; // command status
bool mWaitStatus; // true if caller is waiting for status
- AudioCommandData *mParam; // command specific parameter data
+ sp<AudioCommandData> mParam; // command specific parameter data
};
- class AudioCommandData {
+ class AudioCommandData: public RefBase {
public:
virtual ~AudioCommandData() {}
protected:
@@ -262,9 +263,9 @@ private:
Mutex mLock;
Condition mWaitWorkCV;
- Vector <AudioCommand *> mAudioCommands; // list of pending commands
+ Vector < sp<AudioCommand> > mAudioCommands; // list of pending commands
ToneGenerator *mpToneGenerator; // the tone generator
- AudioCommand mLastCommand; // last processed command (used by dump)
+ sp<AudioCommand> mLastCommand; // last processed command (used by dump)
String8 mName; // string used by wake lock fo delayed commands
wp<AudioPolicyService> mService;
};
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 5bfb969..65592d3 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -1754,6 +1754,9 @@ status_t Parameters::updateRequest(CameraMetadata *request) const {
camera_metadata_entry_t intent =
request->find(ANDROID_CONTROL_CAPTURE_INTENT);
+
+ if (intent.count == 0) return BAD_VALUE;
+
if (intent.data.u8[0] == ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE) {
res = request->update(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
fastInfo.bestStillCaptureFpsRange, 2);