diff options
-rw-r--r-- | camera/Android.mk | 5 | ||||
-rw-r--r-- | camera/VendorTagDescriptor.cpp | 7 | ||||
-rw-r--r-- | include/ndk/NdkMediaCodec.h | 57 | ||||
-rw-r--r-- | include/ndk/NdkMediaCrypto.h | 55 | ||||
-rw-r--r-- | include/ndk/NdkMediaError.h | 48 | ||||
-rw-r--r-- | include/ndk/NdkMediaExtractor.h | 29 | ||||
-rw-r--r-- | media/ndk/Android.mk | 2 | ||||
-rw-r--r-- | media/ndk/NdkMediaCodec.cpp | 256 | ||||
-rw-r--r-- | media/ndk/NdkMediaCrypto.cpp | 117 | ||||
-rw-r--r-- | media/ndk/NdkMediaCryptoPriv.h | 41 | ||||
-rw-r--r-- | media/ndk/NdkMediaExtractor.cpp | 148 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 102 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 17 | ||||
-rw-r--r-- | services/audioflinger/Effects.cpp | 4 | ||||
-rw-r--r-- | services/audioflinger/Threads.cpp | 33 | ||||
-rw-r--r-- | services/audioflinger/Threads.h | 19 | ||||
-rw-r--r-- | services/audioflinger/Tracks.cpp | 4 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyService.cpp | 184 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyService.h | 17 | ||||
-rw-r--r-- | services/camera/libcameraservice/api1/client2/Parameters.cpp | 3 |
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); |