diff options
156 files changed, 3174 insertions, 1202 deletions
diff --git a/apex/Android.bp b/apex/Android.bp index c1ef3d88fc..be6185e6a7 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -31,6 +31,8 @@ apex_defaults { "libmpeg2extractor", "liboggextractor", "libwavextractor", + // JNI + "libmediaparser-jni" ], }, }, diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp index aecb70abad..0b0f5846cf 100644 --- a/camera/CameraBase.cpp +++ b/camera/CameraBase.cpp @@ -29,6 +29,7 @@ #include <binder/IMemory.h> #include <camera/CameraBase.h> +#include <camera/CameraUtils.h> // needed to instantiate #include <camera/Camera.h> @@ -124,9 +125,7 @@ const sp<::android::hardware::ICameraService> CameraBase<TCam, TCamTraits>::getC { Mutex::Autolock _l(gLock); if (gCameraService.get() == 0) { - char value[PROPERTY_VALUE_MAX]; - property_get("config.disable_cameraservice", value, "0"); - if (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0) { + if (CameraUtils::isCameraServiceDisabled()) { return gCameraService; } diff --git a/camera/CameraMetadata.cpp b/camera/CameraMetadata.cpp index 135384adb1..024311f4af 100644 --- a/camera/CameraMetadata.cpp +++ b/camera/CameraMetadata.cpp @@ -169,6 +169,11 @@ bool CameraMetadata::isEmpty() const { return entryCount() == 0; } +size_t CameraMetadata::bufferSize() const { + return (mBuffer == NULL) ? 0 : + get_camera_metadata_size(mBuffer); +} + status_t CameraMetadata::sort() { if (mLocked) { ALOGE("%s: CameraMetadata is locked", __FUNCTION__); diff --git a/camera/CameraUtils.cpp b/camera/CameraUtils.cpp index 67fc116558..f9b1b37dc9 100644 --- a/camera/CameraUtils.cpp +++ b/camera/CameraUtils.cpp @@ -23,6 +23,7 @@ #include <system/window.h> #include <system/graphics.h> +#include <cutils/properties.h> #include <utils/Log.h> namespace android { @@ -122,4 +123,10 @@ status_t CameraUtils::getRotationTransform(const CameraMetadata& staticInfo, return OK; } +bool CameraUtils::isCameraServiceDisabled() { + char value[PROPERTY_VALUE_MAX]; + property_get("config.disable_cameraservice", value, "0"); + return (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0); +} + } /* namespace android */ diff --git a/camera/ICameraClient.cpp b/camera/ICameraClient.cpp index c02c81b72d..bef2ea0acd 100644 --- a/camera/ICameraClient.cpp +++ b/camera/ICameraClient.cpp @@ -142,7 +142,8 @@ status_t BnCameraClient::onTransact( camera_frame_metadata_t metadata; if (data.dataAvail() > 0) { metadata.number_of_faces = data.readInt32(); - if (metadata.number_of_faces <= 0 || + // Zero faces is a valid case, to notify clients that no faces are now visible + if (metadata.number_of_faces < 0 || metadata.number_of_faces > (int32_t)(INT32_MAX / sizeof(camera_face_t))) { ALOGE("%s: Too large face count: %d", __FUNCTION__, metadata.number_of_faces); return BAD_VALUE; diff --git a/camera/include/camera/CameraMetadata.h b/camera/include/camera/CameraMetadata.h index 9d1b5c7c04..e883ffa651 100644 --- a/camera/include/camera/CameraMetadata.h +++ b/camera/include/camera/CameraMetadata.h @@ -128,6 +128,11 @@ class CameraMetadata: public Parcelable { bool isEmpty() const; /** + * Return the allocated camera metadata buffer size in bytes. + */ + size_t bufferSize() const; + + /** * Sort metadata buffer for faster find */ status_t sort(); diff --git a/camera/include/camera/CameraUtils.h b/camera/include/camera/CameraUtils.h index f596f8063d..a397ccdd5e 100644 --- a/camera/include/camera/CameraUtils.h +++ b/camera/include/camera/CameraUtils.h @@ -47,6 +47,11 @@ class CameraUtils { */ static bool isNativeHandleMetadata(const sp<IMemory>& imageData); + /** + * Check if camera service is disabled on this device + */ + static bool isCameraServiceDisabled(); + private: CameraUtils(); }; diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp index c15c5a557c..78974ae7fc 100644 --- a/camera/ndk/impl/ACameraDevice.cpp +++ b/camera/ndk/impl/ACameraDevice.cpp @@ -1361,31 +1361,11 @@ CameraDevice::checkAndFireSequenceCompleteLocked() { it->second.isSequenceCompleted = true; } - if (it->second.isSequenceCompleted && hasCallback) { - auto cbIt = mSequenceCallbackMap.find(sequenceId); - CallbackHolder cbh = cbIt->second; - - // send seq complete callback - sp<AMessage> msg = new AMessage(kWhatCaptureSeqEnd, mHandler); - msg->setPointer(kContextKey, cbh.mContext); - msg->setObject(kSessionSpKey, cbh.mSession); - msg->setPointer(kCallbackFpKey, (void*) cbh.mOnCaptureSequenceCompleted); - msg->setInt32(kSequenceIdKey, sequenceId); - msg->setInt64(kFrameNumberKey, lastFrameNumber); - - // Clear the session sp before we send out the message - // This will guarantee the rare case where the message is processed - // before cbh goes out of scope and causing we call the session - // destructor while holding device lock - cbh.mSession.clear(); - postSessionMsgAndCleanup(msg); - } } if (it->second.isSequenceCompleted && it->second.isInflightCompleted) { - if (mSequenceCallbackMap.find(sequenceId) != mSequenceCallbackMap.end()) { - mSequenceCallbackMap.erase(sequenceId); - } + sendCaptureSequenceCompletedLocked(sequenceId, lastFrameNumber); + it = mSequenceLastFrameNumberMap.erase(it); ALOGV("%s: Remove holder for sequenceId %d", __FUNCTION__, sequenceId); } else { @@ -1412,13 +1392,7 @@ CameraDevice::removeCompletedCallbackHolderLocked(int64_t lastCompletedRegularFr lastCompletedRegularFrameNumber); if (lastFrameNumber <= lastCompletedRegularFrameNumber) { if (it->second.isSequenceCompleted) { - // Check if there is callback for this sequence - // This should not happen because we always register callback (with nullptr inside) - if (mSequenceCallbackMap.count(sequenceId) == 0) { - ALOGW("No callback found for sequenceId %d", sequenceId); - } else { - mSequenceCallbackMap.erase(sequenceId); - } + sendCaptureSequenceCompletedLocked(sequenceId, lastFrameNumber); it = mSequenceLastFrameNumberMap.erase(it); ALOGV("%s: Remove holder for sequenceId %d", __FUNCTION__, sequenceId); @@ -1709,5 +1683,33 @@ CameraDevice::ServiceCallback::onRepeatingRequestError( return ret; } +void +CameraDevice::sendCaptureSequenceCompletedLocked(int sequenceId, int64_t lastFrameNumber) { + auto cbIt = mSequenceCallbackMap.find(sequenceId); + if (cbIt != mSequenceCallbackMap.end()) { + CallbackHolder cbh = cbIt->second; + mSequenceCallbackMap.erase(cbIt); + + // send seq complete callback + sp<AMessage> msg = new AMessage(kWhatCaptureSeqEnd, mHandler); + msg->setPointer(kContextKey, cbh.mContext); + msg->setObject(kSessionSpKey, cbh.mSession); + msg->setPointer(kCallbackFpKey, (void*) cbh.mOnCaptureSequenceCompleted); + msg->setInt32(kSequenceIdKey, sequenceId); + msg->setInt64(kFrameNumberKey, lastFrameNumber); + + // Clear the session sp before we send out the message + // This will guarantee the rare case where the message is processed + // before cbh goes out of scope and causing we call the session + // destructor while holding device lock + cbh.mSession.clear(); + postSessionMsgAndCleanup(msg); + } else { + // Check if there is callback for this sequence + // This should not happen because we always register callback (with nullptr inside) + ALOGW("No callback found for sequenceId %d", sequenceId); + } +} + } // namespace acam } // namespace android diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h index d937865a51..3073dfb023 100644 --- a/camera/ndk/impl/ACameraDevice.h +++ b/camera/ndk/impl/ACameraDevice.h @@ -354,6 +354,7 @@ class CameraDevice final : public RefBase { void checkRepeatingSequenceCompleteLocked(const int sequenceId, const int64_t lastFrameNumber); void checkAndFireSequenceCompleteLocked(); void removeCompletedCallbackHolderLocked(int64_t lastCompletedRegularFrameNumber); + void sendCaptureSequenceCompletedLocked(int sequenceId, int64_t lastFrameNumber); // Misc variables int32_t mShadingMapSize[2]; // const after constructor diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp index b58ebe21e9..2cba665570 100644 --- a/camera/ndk/impl/ACameraManager.cpp +++ b/camera/ndk/impl/ACameraManager.cpp @@ -24,6 +24,7 @@ #include <utils/Vector.h> #include <cutils/properties.h> #include <stdlib.h> +#include <camera/CameraUtils.h> #include <camera/VendorTagDescriptor.h> using namespace android::acam; @@ -70,12 +71,6 @@ CameraManagerGlobal::~CameraManagerGlobal() { mCameraService.clear(); } -static bool isCameraServiceDisabled() { - char value[PROPERTY_VALUE_MAX]; - property_get("config.disable_cameraservice", value, "0"); - return (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0); -} - sp<hardware::ICameraService> CameraManagerGlobal::getCameraService() { Mutex::Autolock _l(mLock); return getCameraServiceLocked(); @@ -83,7 +78,7 @@ sp<hardware::ICameraService> CameraManagerGlobal::getCameraService() { sp<hardware::ICameraService> CameraManagerGlobal::getCameraServiceLocked() { if (mCameraService.get() == nullptr) { - if (isCameraServiceDisabled()) { + if (CameraUtils::isCameraServiceDisabled()) { return mCameraService; } diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h index 1354fce27a..56349828ae 100644 --- a/camera/ndk/include/camera/NdkCameraMetadataTags.h +++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h @@ -1957,7 +1957,10 @@ typedef enum acamera_metadata_tag { * explicitly set ACAMERA_CONTROL_ZOOM_RATIO, its value defaults to 1.0.</p> * <p>One limitation of controlling zoom using zoomRatio is that the ACAMERA_SCALER_CROP_REGION * must only be used for letterboxing or pillarboxing of the sensor active array, and no - * FREEFORM cropping can be used with ACAMERA_CONTROL_ZOOM_RATIO other than 1.0.</p> + * FREEFORM cropping can be used with ACAMERA_CONTROL_ZOOM_RATIO other than 1.0. If + * ACAMERA_CONTROL_ZOOM_RATIO is not 1.0, and ACAMERA_SCALER_CROP_REGION is set to be + * windowboxing, the camera framework will override the ACAMERA_SCALER_CROP_REGION to be + * the active array.</p> * * @see ACAMERA_CONTROL_AE_REGIONS * @see ACAMERA_CONTROL_ZOOM_RATIO @@ -3651,7 +3654,9 @@ typedef enum acamera_metadata_tag { * </ol> * </li> * <li>Setting ACAMERA_CONTROL_ZOOM_RATIO to values different than 1.0 and - * ACAMERA_SCALER_CROP_REGION to be windowboxing at the same time is undefined behavior.</li> + * ACAMERA_SCALER_CROP_REGION to be windowboxing at the same time are not supported. In this + * case, the camera framework will override the ACAMERA_SCALER_CROP_REGION to be the active + * array.</li> * </ul> * <p>LEGACY capability devices will only support CENTER_ONLY cropping.</p> * diff --git a/cmds/stagefright/SimplePlayer.cpp b/cmds/stagefright/SimplePlayer.cpp index f4b8164970..e000633b36 100644 --- a/cmds/stagefright/SimplePlayer.cpp +++ b/cmds/stagefright/SimplePlayer.cpp @@ -272,7 +272,7 @@ void SimplePlayer::onMessageReceived(const sp<AMessage> &msg) { status_t SimplePlayer::onPrepare() { CHECK_EQ(mState, UNPREPARED); - mExtractor = new NuMediaExtractor; + mExtractor = new NuMediaExtractor(NuMediaExtractor::EntryPoint::OTHER); status_t err = mExtractor->setDataSource( NULL /* httpService */, mPath.c_str()); diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp index c26e0b90a5..33c46635e2 100644 --- a/cmds/stagefright/codec.cpp +++ b/cmds/stagefright/codec.cpp @@ -79,7 +79,7 @@ static int decode( static int64_t kTimeout = 500ll; - sp<NuMediaExtractor> extractor = new NuMediaExtractor; + sp<NuMediaExtractor> extractor = new NuMediaExtractor(NuMediaExtractor::EntryPoint::OTHER); if (extractor->setDataSource(NULL /* httpService */, path) != OK) { fprintf(stderr, "unable to instantiate extractor.\n"); return 1; diff --git a/cmds/stagefright/mediafilter.cpp b/cmds/stagefright/mediafilter.cpp index b894545089..ca058ab4c5 100644 --- a/cmds/stagefright/mediafilter.cpp +++ b/cmds/stagefright/mediafilter.cpp @@ -319,7 +319,8 @@ static int decode( static int64_t kTimeout = 500ll; - sp<NuMediaExtractor> extractor = new NuMediaExtractor; + sp<NuMediaExtractor> extractor = new NuMediaExtractor(NuMediaExtractor::EntryPoint::OTHER); + if (extractor->setDataSource(NULL /* httpService */, path) != OK) { fprintf(stderr, "unable to instantiate extractor.\n"); return 1; diff --git a/cmds/stagefright/muxer.cpp b/cmds/stagefright/muxer.cpp index 4a83a4aac8..bc7e41e968 100644 --- a/cmds/stagefright/muxer.cpp +++ b/cmds/stagefright/muxer.cpp @@ -62,7 +62,7 @@ static int muxing( int trimEndTimeMs, int rotationDegrees, MediaMuxer::OutputFormat container = MediaMuxer::OUTPUT_FORMAT_MPEG_4) { - sp<NuMediaExtractor> extractor = new NuMediaExtractor; + sp<NuMediaExtractor> extractor = new NuMediaExtractor(NuMediaExtractor::EntryPoint::OTHER); if (extractor->setDataSource(NULL /* httpService */, path) != OK) { fprintf(stderr, "unable to instantiate extractor. %s\n", path); return 1; diff --git a/drm/common/Android.bp b/drm/common/Android.bp index 272684c29d..248570e126 100644 --- a/drm/common/Android.bp +++ b/drm/common/Android.bp @@ -14,7 +14,7 @@ // limitations under the License. // -cc_library_static { +cc_library { name: "libdrmframeworkcommon", srcs: [ @@ -35,7 +35,11 @@ cc_library_static { cflags: ["-Wall", "-Werror"], - shared_libs: ["libbinder"], + shared_libs: [ + "libbinder", + "liblog", + "libutils" + ], export_include_dirs: ["include"], } diff --git a/drm/drmserver/Android.bp b/drm/drmserver/Android.bp index b68e6c2ea6..141fe70bbb 100644 --- a/drm/drmserver/Android.bp +++ b/drm/drmserver/Android.bp @@ -31,12 +31,11 @@ cc_binary { "liblog", "libbinder", "libdl", + "libdrmframeworkcommon", "libselinux", "libstagefright_foundation", ], - static_libs: ["libdrmframeworkcommon"], - cflags: [ "-Wall", "-Wextra", diff --git a/drm/libdrmframework/Android.bp b/drm/libdrmframework/Android.bp index 940c17d2b8..b4a7b2595e 100644 --- a/drm/libdrmframework/Android.bp +++ b/drm/libdrmframework/Android.bp @@ -29,12 +29,11 @@ cc_library_shared { "liblog", "libbinder", "libdl", + "libdrmframeworkcommon", ], - static_libs: ["libdrmframeworkcommon"], - export_include_dirs: ["include"], - export_static_lib_headers: ["libdrmframeworkcommon"], + export_shared_lib_headers: ["libdrmframeworkcommon"], cflags: ["-Werror"], } diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp index bb9d7ec791..9f52f7af32 100644 --- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp +++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp @@ -36,11 +36,11 @@ cc_library_shared { "libcrypto", "libssl", "libdrmframework", + "libdrmframeworkcommon", ], static_libs: [ "libdrmutility", - "libdrmframeworkcommon", "libfwdlock-common", "libfwdlock-converter", "libfwdlock-decoder", diff --git a/drm/libdrmframework/plugins/passthru/Android.bp b/drm/libdrmframework/plugins/passthru/Android.bp index 05b6440a0b..8045586741 100644 --- a/drm/libdrmframework/plugins/passthru/Android.bp +++ b/drm/libdrmframework/plugins/passthru/Android.bp @@ -19,12 +19,11 @@ cc_library_shared { srcs: ["src/DrmPassthruPlugIn.cpp"], - static_libs: ["libdrmframeworkcommon"], - shared_libs: [ "libutils", "liblog", "libdl", + "libdrmframeworkcommon", ], local_include_dirs: ["include"], diff --git a/drm/libmediadrm/DrmMetricsConsumer.cpp b/drm/libmediadrm/DrmMetricsConsumer.cpp index b47b4ff332..5f0b26ec3e 100644 --- a/drm/libmediadrm/DrmMetricsConsumer.cpp +++ b/drm/libmediadrm/DrmMetricsConsumer.cpp @@ -37,8 +37,8 @@ template <typename T> std::string GetAttributeName(T type); template <> std::string GetAttributeName<KeyStatusType>(KeyStatusType type) { static const char *type_names[] = {"USABLE", "EXPIRED", "OUTPUT_NOT_ALLOWED", "STATUS_PENDING", - "INTERNAL_ERROR"}; - if (((size_t)type) > arraysize(type_names)) { + "INTERNAL_ERROR", "USABLE_IN_FUTURE"}; + if (((size_t)type) >= arraysize(type_names)) { return "UNKNOWN_TYPE"; } return type_names[(size_t)type]; @@ -48,7 +48,7 @@ template <> std::string GetAttributeName<EventType>(EventType type) { static const char *type_names[] = {"PROVISION_REQUIRED", "KEY_NEEDED", "KEY_EXPIRED", "VENDOR_DEFINED", "SESSION_RECLAIMED"}; - if (((size_t)type) > arraysize(type_names)) { + if (((size_t)type) >= arraysize(type_names)) { return "UNKNOWN_TYPE"; } return type_names[(size_t)type]; diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc index f05c2d271f..f75e4c7a9b 100644 --- a/media/audioserver/audioserver.rc +++ b/media/audioserver/audioserver.rc @@ -6,8 +6,11 @@ service audioserver /system/bin/audioserver capabilities BLOCK_SUSPEND ioprio rt 4 task_profiles ProcessCapacityHigh HighPerformance - - onrestart setprop sys.audio.restart.hal 1 + onrestart restart vendor.audio-hal + onrestart restart vendor.audio-hal-4-0-msd + # Keep the original service names for backward compatibility + onrestart restart vendor.audio-hal-2-0 + onrestart restart audio-hal-2-0 on property:vts.native_server.on=1 stop audioserver @@ -37,11 +40,16 @@ on property:init.svc.audioserver=running start audio-hal-2-0 on property:sys.audio.restart.hal=1 - restart vendor.audio-hal - restart vendor.audio-hal-4-0-msd + # See b/159966243. Avoid restart loop between audioserver and HAL. # Keep the original service names for backward compatibility - restart vendor.audio-hal-2-0 - restart audio-hal-2-0 + stop vendor.audio-hal + stop vendor.audio-hal-4-0-msd + stop vendor.audio-hal-2-0 + stop audio-hal-2-0 + start vendor.audio-hal + start vendor.audio-hal-4-0-msd + start vendor.audio-hal-2-0 + start audio-hal-2-0 # reset the property setprop sys.audio.restart.hal 0 diff --git a/media/codec2/components/avc/C2SoftAvcEnc.cpp b/media/codec2/components/avc/C2SoftAvcEnc.cpp index ab93ce39f5..566895fa6b 100644 --- a/media/codec2/components/avc/C2SoftAvcEnc.cpp +++ b/media/codec2/components/avc/C2SoftAvcEnc.cpp @@ -1328,13 +1328,13 @@ c2_status_t C2SoftAvcEnc::setEncodeArgs( ps_inp_raw_buf->apv_bufs[1] = uPlane; ps_inp_raw_buf->apv_bufs[2] = vPlane; - ps_inp_raw_buf->au4_wd[0] = input->width(); - ps_inp_raw_buf->au4_wd[1] = input->width() / 2; - ps_inp_raw_buf->au4_wd[2] = input->width() / 2; + ps_inp_raw_buf->au4_wd[0] = mSize->width; + ps_inp_raw_buf->au4_wd[1] = mSize->width / 2; + ps_inp_raw_buf->au4_wd[2] = mSize->width / 2; - ps_inp_raw_buf->au4_ht[0] = input->height(); - ps_inp_raw_buf->au4_ht[1] = input->height() / 2; - ps_inp_raw_buf->au4_ht[2] = input->height() / 2; + ps_inp_raw_buf->au4_ht[0] = mSize->height; + ps_inp_raw_buf->au4_ht[1] = mSize->height / 2; + ps_inp_raw_buf->au4_ht[2] = mSize->height / 2; ps_inp_raw_buf->au4_strd[0] = yStride; ps_inp_raw_buf->au4_strd[1] = uStride; @@ -1359,11 +1359,11 @@ c2_status_t C2SoftAvcEnc::setEncodeArgs( ps_inp_raw_buf->apv_bufs[0] = yPlane; ps_inp_raw_buf->apv_bufs[1] = uPlane; - ps_inp_raw_buf->au4_wd[0] = input->width(); - ps_inp_raw_buf->au4_wd[1] = input->width(); + ps_inp_raw_buf->au4_wd[0] = mSize->width; + ps_inp_raw_buf->au4_wd[1] = mSize->width; - ps_inp_raw_buf->au4_ht[0] = input->height(); - ps_inp_raw_buf->au4_ht[1] = input->height() / 2; + ps_inp_raw_buf->au4_ht[0] = mSize->height; + ps_inp_raw_buf->au4_ht[1] = mSize->height / 2; ps_inp_raw_buf->au4_strd[0] = yStride; ps_inp_raw_buf->au4_strd[1] = uStride; diff --git a/media/codec2/components/gav1/Android.bp b/media/codec2/components/gav1/Android.bp index 5c4abb7e30..f37408935a 100644 --- a/media/codec2/components/gav1/Android.bp +++ b/media/codec2/components/gav1/Android.bp @@ -13,8 +13,4 @@ cc_library_shared { srcs: ["C2SoftGav1Dec.cpp"], static_libs: ["libgav1"], - - include_dirs: [ - "external/libgav1/libgav1/", - ], } diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.cpp b/media/codec2/components/gav1/C2SoftGav1Dec.cpp index ec5f549049..120ba7a59a 100644 --- a/media/codec2/components/gav1/C2SoftGav1Dec.cpp +++ b/media/codec2/components/gav1/C2SoftGav1Dec.cpp @@ -288,9 +288,7 @@ void C2SoftGav1Dec::onReset() { void C2SoftGav1Dec::onRelease() { destroyDecoder(); } c2_status_t C2SoftGav1Dec::onFlush_sm() { - Libgav1StatusCode status = - mCodecCtx->EnqueueFrame(/*data=*/nullptr, /*size=*/0, - /*user_private_data=*/0); + Libgav1StatusCode status = mCodecCtx->SignalEOS(); if (status != kLibgav1StatusOk) { ALOGE("Failed to flush av1 decoder. status: %d.", status); return C2_CORRUPTED; @@ -299,7 +297,7 @@ c2_status_t C2SoftGav1Dec::onFlush_sm() { // Dequeue frame (if any) that was enqueued previously. const libgav1::DecoderBuffer *buffer; status = mCodecCtx->DequeueFrame(&buffer); - if (status != kLibgav1StatusOk) { + if (status != kLibgav1StatusOk && status != kLibgav1StatusNothingToDequeue) { ALOGE("Failed to dequeue frame after flushing the av1 decoder. status: %d", status); return C2_CORRUPTED; @@ -433,7 +431,8 @@ void C2SoftGav1Dec::process(const std::unique_ptr<C2Work> &work, TIME_DIFF(mTimeEnd, mTimeStart, delay); const Libgav1StatusCode status = - mCodecCtx->EnqueueFrame(bitstream, inSize, frameIndex); + mCodecCtx->EnqueueFrame(bitstream, inSize, frameIndex, + /*buffer_private_data=*/nullptr); GETTIME(&mTimeEnd, nullptr); TIME_DIFF(mTimeStart, mTimeEnd, decodeTime); @@ -447,17 +446,6 @@ void C2SoftGav1Dec::process(const std::unique_ptr<C2Work> &work, return; } - } else { - const Libgav1StatusCode status = - mCodecCtx->EnqueueFrame(/*data=*/nullptr, /*size=*/0, - /*user_private_data=*/0); - if (status != kLibgav1StatusOk) { - ALOGE("Failed to flush av1 decoder. status: %d.", status); - work->result = C2_CORRUPTED; - work->workletsProcessed = 1u; - mSignalledError = true; - return; - } } (void)outputBuffer(pool, work); @@ -470,13 +458,12 @@ void C2SoftGav1Dec::process(const std::unique_ptr<C2Work> &work, } } -static void copyOutputBufferToYV12Frame(uint8_t *dst, const uint8_t *srcY, - const uint8_t *srcU, - const uint8_t *srcV, size_t srcYStride, - size_t srcUStride, size_t srcVStride, - uint32_t width, uint32_t height) { - const size_t dstYStride = align(width, 16); - const size_t dstUVStride = align(dstYStride / 2, 16); +static void copyOutputBufferToYuvPlanarFrame(uint8_t *dst, const uint8_t *srcY, + const uint8_t *srcU, + const uint8_t *srcV, size_t srcYStride, + size_t srcUStride, size_t srcVStride, + size_t dstYStride, size_t dstUVStride, + uint32_t width, uint32_t height) { uint8_t *const dstStart = dst; for (size_t i = 0; i < height; ++i) { @@ -570,10 +557,10 @@ static void convertYUV420Planar16ToY410(uint32_t *dst, const uint16_t *srcY, static void convertYUV420Planar16ToYUV420Planar( uint8_t *dst, const uint16_t *srcY, const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride, size_t srcUStride, - size_t srcVStride, size_t dstStride, size_t width, size_t height) { + size_t srcVStride, size_t dstYStride, size_t dstUVStride, + size_t width, size_t height) { uint8_t *dstY = (uint8_t *)dst; - size_t dstYSize = dstStride * height; - size_t dstUVStride = align(dstStride / 2, 16); + size_t dstYSize = dstYStride * height; size_t dstUVSize = dstUVStride * height / 2; uint8_t *dstV = dstY + dstYSize; uint8_t *dstU = dstV + dstUVSize; @@ -584,7 +571,7 @@ static void convertYUV420Planar16ToYUV420Planar( } srcY += srcYStride; - dstY += dstStride; + dstY += dstYStride; } for (size_t y = 0; y < (height + 1) / 2; ++y) { @@ -607,13 +594,14 @@ bool C2SoftGav1Dec::outputBuffer(const std::shared_ptr<C2BlockPool> &pool, const libgav1::DecoderBuffer *buffer; const Libgav1StatusCode status = mCodecCtx->DequeueFrame(&buffer); - if (status != kLibgav1StatusOk) { + if (status != kLibgav1StatusOk && status != kLibgav1StatusNothingToDequeue) { ALOGE("av1 decoder DequeueFrame failed. status: %d.", status); return false; } - // |buffer| can be NULL if status was equal to kLibgav1StatusOk. This is not - // an error. This could mean one of two things: + // |buffer| can be NULL if status was equal to kLibgav1StatusOk or + // kLibgav1StatusNothingToDequeue. This is not an error. This could mean one + // of two things: // - The EnqueueFrame() call was either a flush (called with nullptr). // - The enqueued frame did not have any displayable frames. if (!buffer) { @@ -683,6 +671,9 @@ bool C2SoftGav1Dec::outputBuffer(const std::shared_ptr<C2BlockPool> &pool, size_t srcYStride = buffer->stride[0]; size_t srcUStride = buffer->stride[1]; size_t srcVStride = buffer->stride[2]; + C2PlanarLayout layout = wView.layout(); + size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc; + size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc; if (buffer->bitdepth == 10) { const uint16_t *srcY = (const uint16_t *)buffer->plane[0]; @@ -692,18 +683,19 @@ bool C2SoftGav1Dec::outputBuffer(const std::shared_ptr<C2BlockPool> &pool, if (format == HAL_PIXEL_FORMAT_RGBA_1010102) { convertYUV420Planar16ToY410( (uint32_t *)dst, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2, - srcVStride / 2, align(mWidth, 16), mWidth, mHeight); + srcVStride / 2, dstYStride / sizeof(uint32_t), mWidth, mHeight); } else { convertYUV420Planar16ToYUV420Planar(dst, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2, srcVStride / 2, - align(mWidth, 16), mWidth, mHeight); + dstYStride, dstUVStride, mWidth, mHeight); } } else { const uint8_t *srcY = (const uint8_t *)buffer->plane[0]; const uint8_t *srcU = (const uint8_t *)buffer->plane[1]; const uint8_t *srcV = (const uint8_t *)buffer->plane[2]; - copyOutputBufferToYV12Frame(dst, srcY, srcU, srcV, srcYStride, srcUStride, - srcVStride, mWidth, mHeight); + copyOutputBufferToYuvPlanarFrame(dst, srcY, srcU, srcV, srcYStride, srcUStride, + srcVStride, dstYStride, dstUVStride, + mWidth, mHeight); } finishWork(buffer->user_private_data, work, std::move(block)); block = nullptr; @@ -722,9 +714,7 @@ c2_status_t C2SoftGav1Dec::drainInternal( return C2_OMITTED; } - Libgav1StatusCode status = - mCodecCtx->EnqueueFrame(/*data=*/nullptr, /*size=*/0, - /*user_private_data=*/0); + const Libgav1StatusCode status = mCodecCtx->SignalEOS(); if (status != kLibgav1StatusOk) { ALOGE("Failed to flush av1 decoder. status: %d.", status); return C2_CORRUPTED; diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.h b/media/codec2/components/gav1/C2SoftGav1Dec.h index a7c08bbc39..555adc9986 100644 --- a/media/codec2/components/gav1/C2SoftGav1Dec.h +++ b/media/codec2/components/gav1/C2SoftGav1Dec.h @@ -18,8 +18,8 @@ #define ANDROID_C2_SOFT_GAV1_DEC_H_ #include <SimpleC2Component.h> -#include "libgav1/src/decoder.h" -#include "libgav1/src/decoder_settings.h" +#include "libgav1/src/gav1/decoder.h" +#include "libgav1/src/gav1/decoder_settings.h" #define GETTIME(a, b) gettimeofday(a, b); #define TIME_DIFF(start, end, diff) \ diff --git a/media/codec2/components/vorbis/C2SoftVorbisDec.cpp b/media/codec2/components/vorbis/C2SoftVorbisDec.cpp index 15564d9e9e..a8b53775e9 100644 --- a/media/codec2/components/vorbis/C2SoftVorbisDec.cpp +++ b/media/codec2/components/vorbis/C2SoftVorbisDec.cpp @@ -279,6 +279,8 @@ void C2SoftVorbisDec::process( // skip 7 <type + "vorbis"> bytes makeBitReader((const uint8_t *)data + 7, inSize - 7, &buf, &ref, &bits); if (data[0] == 1) { + // release any memory that vorbis_info_init will blindly overwrite + vorbis_info_clear(mVi); vorbis_info_init(mVi); if (0 != _vorbis_unpack_info(mVi, &bits)) { ALOGE("Encountered error while unpacking info"); @@ -323,6 +325,8 @@ void C2SoftVorbisDec::process( work->result = C2_CORRUPTED; return; } + // release any memory that vorbis_dsp_init will blindly overwrite + vorbis_dsp_clear(mState); if (0 != vorbis_dsp_init(mState, mVi)) { ALOGE("Encountered error while dsp init"); mSignalledError = true; diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp index 1972d3f613..54107bd852 100644 --- a/media/codec2/sfplugin/CCodec.cpp +++ b/media/codec2/sfplugin/CCodec.cpp @@ -1331,8 +1331,6 @@ void CCodec::start() { mCallback->onError(err2, ACTION_CODE_FATAL); return; } - // We're not starting after flush. - (void)mSentConfigAfterResume.test_and_set(); err2 = mChannel->start(inputFormat, outputFormat, buffersBoundToCodec); if (err2 != OK) { mCallback->onError(err2, ACTION_CODE_FATAL); @@ -1580,7 +1578,6 @@ void CCodec::signalResume() { return; } - mSentConfigAfterResume.clear(); { Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); const std::unique_ptr<Config> &config = *configLocked; @@ -1797,7 +1794,7 @@ void CCodec::onMessageReceived(const sp<AMessage> &msg) { // handle configuration changes in work done Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); const std::unique_ptr<Config> &config = *configLocked; - bool changed = !mSentConfigAfterResume.test_and_set(); + bool changed = false; Config::Watcher<C2StreamInitDataInfo::output> initData = config->watch<C2StreamInitDataInfo::output>(); if (!work->worklets.empty() diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp index 0626c8d979..1654b11c31 100644 --- a/media/codec2/sfplugin/CCodecBufferChannel.cpp +++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp @@ -618,25 +618,26 @@ void CCodecBufferChannel::feedInputBufferIfAvailable() { } void CCodecBufferChannel::feedInputBufferIfAvailableInternal() { - if (mInputMetEos || mPipelineWatcher.lock()->pipelineFull()) { + if (mInputMetEos) { return; } { Mutexed<Output>::Locked output(mOutput); if (!output->buffers || output->buffers->hasPending() || - output->buffers->numClientBuffers() >= output->numSlots) { + output->buffers->numActiveSlots() >= output->numSlots) { return; } } - size_t numInputSlots = mInput.lock()->numSlots; - for (size_t i = 0; i < numInputSlots; ++i) { + size_t numActiveSlots = 0; + while (!mPipelineWatcher.lock()->pipelineFull()) { sp<MediaCodecBuffer> inBuffer; size_t index; { Mutexed<Input>::Locked input(mInput); - if (input->buffers->numClientBuffers() >= input->numSlots) { - return; + numActiveSlots = input->buffers->numActiveSlots(); + if (numActiveSlots >= input->numSlots) { + break; } if (!input->buffers->requestNewBuffer(&index, &inBuffer)) { ALOGV("[%s] no new buffer available", mName); @@ -646,6 +647,7 @@ void CCodecBufferChannel::feedInputBufferIfAvailableInternal() { ALOGV("[%s] new input index = %zu [%p]", mName, index, inBuffer.get()); mCallback->onInputBufferAvailable(index, inBuffer); } + ALOGV("[%s] # active slots after feedInputBufferIfAvailable = %zu", mName, numActiveSlots); } status_t CCodecBufferChannel::renderOutputBuffer( diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp index e58a1e438b..bddaa9f22b 100644 --- a/media/codec2/sfplugin/CCodecBuffers.cpp +++ b/media/codec2/sfplugin/CCodecBuffers.cpp @@ -272,8 +272,6 @@ OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister( // The output format can be processed without a registered slot. if (outputFormat) { - ALOGD("[%s] popFromStashAndRegister: output format changed to %s", - mName, outputFormat->debugString().c_str()); updateSkipCutBuffer(outputFormat, entry.notify); } @@ -301,6 +299,10 @@ OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister( } if (!entry.notify) { + if (outputFormat) { + ALOGD("[%s] popFromStashAndRegister: output format changed to %s", + mName, outputFormat->debugString().c_str()); + } mPending.pop_front(); return DISCARD; } @@ -317,6 +319,10 @@ OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister( // Append information from the front stash entry to outBuffer. (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp); (*outBuffer)->meta()->setInt32("flags", entry.flags); + if (outputFormat) { + ALOGD("[%s] popFromStashAndRegister: output format changed to %s", + mName, outputFormat->debugString().c_str()); + } ALOGV("[%s] popFromStashAndRegister: " "out buffer index = %zu [%p] => %p + %zu (%lld)", mName, *index, outBuffer->get(), @@ -487,11 +493,12 @@ void FlexBuffersImpl::flush() { mBuffers.clear(); } -size_t FlexBuffersImpl::numClientBuffers() const { +size_t FlexBuffersImpl::numActiveSlots() const { return std::count_if( mBuffers.begin(), mBuffers.end(), [](const Entry &entry) { - return (entry.clientBuffer != nullptr); + return (entry.clientBuffer != nullptr + || !entry.compBuffer.expired()); }); } @@ -637,11 +644,11 @@ void BuffersArrayImpl::grow( } } -size_t BuffersArrayImpl::numClientBuffers() const { +size_t BuffersArrayImpl::numActiveSlots() const { return std::count_if( mBuffers.begin(), mBuffers.end(), [](const Entry &entry) { - return entry.ownedByClient; + return entry.ownedByClient || !entry.compBuffer.expired(); }); } @@ -691,8 +698,8 @@ void InputBuffersArray::flush() { mImpl.flush(); } -size_t InputBuffersArray::numClientBuffers() const { - return mImpl.numClientBuffers(); +size_t InputBuffersArray::numActiveSlots() const { + return mImpl.numActiveSlots(); } sp<Codec2Buffer> InputBuffersArray::createNewBuffer() { @@ -729,8 +736,8 @@ std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) { return nullptr; } -size_t SlotInputBuffers::numClientBuffers() const { - return mImpl.numClientBuffers(); +size_t SlotInputBuffers::numActiveSlots() const { + return mImpl.numActiveSlots(); } sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() { @@ -781,8 +788,8 @@ std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) { return std::move(array); } -size_t LinearInputBuffers::numClientBuffers() const { - return mImpl.numClientBuffers(); +size_t LinearInputBuffers::numActiveSlots() const { + return mImpl.numActiveSlots(); } // static @@ -958,8 +965,8 @@ std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode( return std::move(array); } -size_t GraphicMetadataInputBuffers::numClientBuffers() const { - return mImpl.numClientBuffers(); +size_t GraphicMetadataInputBuffers::numActiveSlots() const { + return mImpl.numActiveSlots(); } sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() { @@ -1023,8 +1030,8 @@ std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) { return std::move(array); } -size_t GraphicInputBuffers::numClientBuffers() const { - return mImpl.numClientBuffers(); +size_t GraphicInputBuffers::numActiveSlots() const { + return mImpl.numActiveSlots(); } sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() { @@ -1113,8 +1120,8 @@ void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const { mImpl.getArray(array); } -size_t OutputBuffersArray::numClientBuffers() const { - return mImpl.numClientBuffers(); +size_t OutputBuffersArray::numActiveSlots() const { + return mImpl.numActiveSlots(); } void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) { @@ -1224,8 +1231,8 @@ std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) return array; } -size_t FlexOutputBuffers::numClientBuffers() const { - return mImpl.numClientBuffers(); +size_t FlexOutputBuffers::numActiveSlots() const { + return mImpl.numActiveSlots(); } // LinearOutputBuffers diff --git a/media/codec2/sfplugin/CCodecBuffers.h b/media/codec2/sfplugin/CCodecBuffers.h index 0d4fa8117c..4772ab53eb 100644 --- a/media/codec2/sfplugin/CCodecBuffers.h +++ b/media/codec2/sfplugin/CCodecBuffers.h @@ -72,7 +72,7 @@ public: /** * Return number of buffers the client owns. */ - virtual size_t numClientBuffers() const = 0; + virtual size_t numActiveSlots() const = 0; /** * Examine image data from the buffer and update the format if necessary. @@ -584,7 +584,7 @@ public: * Return the number of buffers that are sent to the client but not released * yet. */ - size_t numClientBuffers() const; + size_t numActiveSlots() const; /** * Return the number of buffers that are sent to the component but not @@ -705,7 +705,7 @@ public: * Return the number of buffers that are sent to the client but not released * yet. */ - size_t numClientBuffers() const; + size_t numActiveSlots() const; /** * Return the size of the array. @@ -765,7 +765,7 @@ public: void flush() override; - size_t numClientBuffers() const final; + size_t numActiveSlots() const final; protected: sp<Codec2Buffer> createNewBuffer() override; @@ -796,7 +796,7 @@ public: std::unique_ptr<InputBuffers> toArrayMode(size_t size) final; - size_t numClientBuffers() const final; + size_t numActiveSlots() const final; protected: sp<Codec2Buffer> createNewBuffer() final; @@ -826,7 +826,7 @@ public: std::unique_ptr<InputBuffers> toArrayMode(size_t size) override; - size_t numClientBuffers() const final; + size_t numActiveSlots() const final; protected: sp<Codec2Buffer> createNewBuffer() override; @@ -894,7 +894,7 @@ public: std::unique_ptr<InputBuffers> toArrayMode(size_t size) final; - size_t numClientBuffers() const final; + size_t numActiveSlots() const final; protected: sp<Codec2Buffer> createNewBuffer() override; @@ -924,7 +924,7 @@ public: std::unique_ptr<InputBuffers> toArrayMode( size_t size) final; - size_t numClientBuffers() const final; + size_t numActiveSlots() const final; protected: sp<Codec2Buffer> createNewBuffer() override; @@ -965,7 +965,7 @@ public: array->clear(); } - size_t numClientBuffers() const final { + size_t numActiveSlots() const final { return 0u; } @@ -1019,7 +1019,7 @@ public: void getArray(Vector<sp<MediaCodecBuffer>> *array) const final; - size_t numClientBuffers() const final; + size_t numActiveSlots() const final; /** * Reallocate the array, filled with buffers with the same size as given @@ -1073,7 +1073,7 @@ public: std::unique_ptr<OutputBuffersArray> toArrayMode(size_t size) override; - size_t numClientBuffers() const final; + size_t numActiveSlots() const final; /** * Return an appropriate Codec2Buffer object for the type of buffers. diff --git a/media/codec2/sfplugin/InputSurfaceWrapper.h b/media/codec2/sfplugin/InputSurfaceWrapper.h index bb35763f41..479acb109b 100644 --- a/media/codec2/sfplugin/InputSurfaceWrapper.h +++ b/media/codec2/sfplugin/InputSurfaceWrapper.h @@ -61,24 +61,24 @@ public: /// Input Surface configuration struct Config { // IN PARAMS (GBS) - float mMinFps; // minimum fps (repeat frame to achieve this) - float mMaxFps; // max fps (via frame drop) - float mCaptureFps; // capture fps - float mCodedFps; // coded fps - bool mSuspended; // suspended - int64_t mTimeOffsetUs; // time offset (input => codec) - int64_t mSuspendAtUs; // suspend/resume time - int64_t mStartAtUs; // start time - bool mStopped; // stopped - int64_t mStopAtUs; // stop time + float mMinFps = 0.0; // minimum fps (repeat frame to achieve this) + float mMaxFps = 0.0; // max fps (via frame drop) + float mCaptureFps = 0.0; // capture fps + float mCodedFps = 0.0; // coded fps + bool mSuspended = false; // suspended + int64_t mTimeOffsetUs = 0; // time offset (input => codec) + int64_t mSuspendAtUs = 0; // suspend/resume time + int64_t mStartAtUs = 0; // start time + bool mStopped = false; // stopped + int64_t mStopAtUs = 0; // stop time // OUT PARAMS (GBS) - int64_t mInputDelayUs; // delay between encoder input and surface input + int64_t mInputDelayUs = 0; // delay between encoder input and surface input // IN PARAMS (CODEC WRAPPER) - float mFixedAdjustedFps; // fixed fps via PTS manipulation - float mMinAdjustedFps; // minimum fps via PTS manipulation - uint64_t mUsage; // consumer usage + float mFixedAdjustedFps = 0.0; // fixed fps via PTS manipulation + float mMinAdjustedFps = 0.0; // minimum fps via PTS manipulation + uint64_t mUsage = 0; // consumer usage }; /** diff --git a/media/codec2/sfplugin/include/media/stagefright/CCodec.h b/media/codec2/sfplugin/include/media/stagefright/CCodec.h index ecb2506c93..dbbb5d5bc1 100644 --- a/media/codec2/sfplugin/include/media/stagefright/CCodec.h +++ b/media/codec2/sfplugin/include/media/stagefright/CCodec.h @@ -193,7 +193,6 @@ private: Mutexed<std::unique_ptr<CCodecConfig>> mConfig; Mutexed<std::list<std::unique_ptr<C2Work>>> mWorkDoneQueue; - std::atomic_flag mSentConfigAfterResume; friend class CCodecCallbackImpl; diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp index b88e4e8d98..27bd357d6a 100644 --- a/media/extractors/mkv/MatroskaExtractor.cpp +++ b/media/extractors/mkv/MatroskaExtractor.cpp @@ -840,7 +840,7 @@ media_status_t MatroskaSource::readBlock() { } if (err != OK) { - mPendingFrames.clear(); + clearPendingFrames(); mBlockIter.advance(); mbuf->release(); diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h index a47f189a9c..cab89292c3 100644 --- a/media/libaaudio/include/aaudio/AAudio.h +++ b/media/libaaudio/include/aaudio/AAudio.h @@ -1035,6 +1035,11 @@ AAUDIO_API aaudio_result_t AAudioStreamBuilder_delete(AAudioStreamBuilder* buil * but still allow queries to the stream to occur from other threads. This often * happens if you are monitoring stream progress from a UI thread. * + * NOTE: This function is only fully implemented for MMAP streams, + * which are low latency streams supported by some devices. + * On other "Legacy" streams some audio resources will still be in use + * and some callbacks may still be in process after this call. + * * @param stream reference provided by AAudioStreamBuilder_openStream() * @return {@link #AAUDIO_OK} or a negative error. */ diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp index 9fa2e40ccc..fce322bcab 100644 --- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp +++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp @@ -14,8 +14,6 @@ * limitations under the License. */ -#define LOG_TAG (mInService ? "AudioStreamInternalCapture_Service" \ - : "AudioStreamInternalCapture_Client") //#define LOG_NDEBUG 0 #include <utils/Log.h> @@ -29,6 +27,14 @@ #define ATRACE_TAG ATRACE_TAG_AUDIO #include <utils/Trace.h> +// We do this after the #includes because if a header uses ALOG. +// it would fail on the reference to mInService. +#undef LOG_TAG +// This file is used in both client and server processes. +// This is needed to make sense of the logs more easily. +#define LOG_TAG (mInService ? "AudioStreamInternalCapture_Service" \ + : "AudioStreamInternalCapture_Client") + using android::WrappingBuffer; using namespace aaudio; diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp index 1303daf3bc..d6b73b4773 100644 --- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp +++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp @@ -14,8 +14,6 @@ * limitations under the License. */ -#define LOG_TAG (mInService ? "AudioStreamInternalPlay_Service" \ - : "AudioStreamInternalPlay_Client") //#define LOG_NDEBUG 0 #include <utils/Log.h> @@ -26,6 +24,14 @@ #include "client/AudioStreamInternalPlay.h" #include "utility/AudioClock.h" +// We do this after the #includes because if a header uses ALOG. +// it would fail on the reference to mInService. +#undef LOG_TAG +// This file is used in both client and server processes. +// This is needed to make sense of the logs more easily. +#define LOG_TAG (mInService ? "AudioStreamInternalPlay_Service" \ + : "AudioStreamInternalPlay_Client") + using android::WrappingBuffer; using namespace aaudio; diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp index 8965875c58..cfa7221fed 100644 --- a/media/libaaudio/src/core/AAudioAudio.cpp +++ b/media/libaaudio/src/core/AAudioAudio.cpp @@ -255,17 +255,16 @@ AAUDIO_API aaudio_result_t AAudioStream_close(AAudioStream* stream) { if (audioStream != nullptr) { aaudio_stream_id_t id = audioStream->getId(); ALOGD("%s(s#%u) called ---------------", __func__, id); - result = audioStream->safeRelease(); - // safeRelease will only fail if called illegally, for example, from a callback. + result = audioStream->safeReleaseClose(); + // safeReleaseClose will only fail if called illegally, for example, from a callback. // That would result in deleting an active stream, which would cause a crash. if (result != AAUDIO_OK) { ALOGW("%s(s#%u) failed. Close it from another thread.", __func__, id); } else { audioStream->unregisterPlayerBase(); - // Mark CLOSED to keep destructors from asserting. - audioStream->closeFinal(); - delete audioStream; + // Allow the stream to be deleted. + AudioStreamBuilder::stopUsingStream(audioStream); } ALOGD("%s(s#%u) returned %d ---------", __func__, id, result); } diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp index f5c75ca92d..f439310db7 100644 --- a/media/libaaudio/src/core/AudioStream.cpp +++ b/media/libaaudio/src/core/AudioStream.cpp @@ -39,7 +39,7 @@ static aaudio_stream_id_t AAudio_getNextStreamId() { } AudioStream::AudioStream() - : mPlayerBase(new MyPlayerBase(this)) + : mPlayerBase(new MyPlayerBase()) , mStreamId(AAudio_getNextStreamId()) { // mThread is a pthread_t of unknown size so we need memset. @@ -48,6 +48,10 @@ AudioStream::AudioStream() } AudioStream::~AudioStream() { + // Please preserve this log because there have been several bugs related to + // AudioStream deletion and late callbacks. + ALOGD("%s(s#%u) mPlayerBase strongCount = %d", + __func__, getId(), mPlayerBase->getStrongCount()); // If the stream is deleted when OPEN or in use then audio resources will leak. // This would indicate an internal error. So we want to find this ASAP. LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED @@ -55,8 +59,6 @@ AudioStream::~AudioStream() { || getState() == AAUDIO_STREAM_STATE_DISCONNECTED), "~AudioStream() - still in use, state = %s", AudioGlobal_convertStreamStateToText(getState())); - - mPlayerBase->clearParentReference(); // remove reference to this AudioStream } aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder) @@ -301,18 +303,29 @@ aaudio_result_t AudioStream::safeStop() { } aaudio_result_t AudioStream::safeRelease() { - // This get temporarily unlocked in the release() when joining callback threads. + // This get temporarily unlocked in the MMAP release() when joining callback threads. std::lock_guard<std::mutex> lock(mStreamLock); if (collidesWithCallback()) { ALOGE("%s cannot be called from a callback!", __func__); return AAUDIO_ERROR_INVALID_STATE; } - if (getState() == AAUDIO_STREAM_STATE_CLOSING) { + if (getState() == AAUDIO_STREAM_STATE_CLOSING) { // already released? return AAUDIO_OK; } return release_l(); } +aaudio_result_t AudioStream::safeReleaseClose() { + // This get temporarily unlocked in the MMAP release() when joining callback threads. + std::lock_guard<std::mutex> lock(mStreamLock); + if (collidesWithCallback()) { + ALOGE("%s cannot be called from a callback!", __func__); + return AAUDIO_ERROR_INVALID_STATE; + } + releaseCloseFinal(); + return AAUDIO_OK; +} + void AudioStream::setState(aaudio_stream_state_t state) { ALOGD("%s(s#%d) from %d to %d", __func__, getId(), mState, state); // Track transition to DISCONNECTED state. @@ -391,7 +404,9 @@ void* AudioStream::wrapUserThread() { // It converts the 'C' function call to a C++ method call. static void* AudioStream_internalThreadProc(void* threadArg) { AudioStream *audioStream = (AudioStream *) threadArg; - return audioStream->wrapUserThread(); + // Use an sp<> to prevent the stream from being deleted while running. + android::sp<AudioStream> protectedStream(audioStream); + return protectedStream->wrapUserThread(); } // This is not exposed in the API. @@ -520,11 +535,18 @@ bool AudioStream::collidesWithCallback() const { } #if AAUDIO_USE_VOLUME_SHAPER -android::media::VolumeShaper::Status AudioStream::applyVolumeShaper( - const android::media::VolumeShaper::Configuration& configuration __unused, - const android::media::VolumeShaper::Operation& operation __unused) { - ALOGW("applyVolumeShaper() is not supported"); - return android::media::VolumeShaper::Status::ok(); +::android::binder::Status AudioStream::MyPlayerBase::applyVolumeShaper( + const ::android::media::VolumeShaper::Configuration& configuration, + const ::android::media::VolumeShaper::Operation& operation) { + android::sp<AudioStream> audioStream; + { + std::lock_guard<std::mutex> lock(mParentLock); + audioStream = mParent.promote(); + } + if (audioStream) { + return audioStream->applyVolumeShaper(configuration, operation); + } + return android::NO_ERROR; } #endif @@ -534,26 +556,36 @@ void AudioStream::setDuckAndMuteVolume(float duckAndMuteVolume) { doSetVolume(); // apply this change } -AudioStream::MyPlayerBase::MyPlayerBase(AudioStream *parent) : mParent(parent) { -} - -AudioStream::MyPlayerBase::~MyPlayerBase() { -} - -void AudioStream::MyPlayerBase::registerWithAudioManager() { +void AudioStream::MyPlayerBase::registerWithAudioManager(const android::sp<AudioStream>& parent) { + std::lock_guard<std::mutex> lock(mParentLock); + mParent = parent; if (!mRegistered) { - init(android::PLAYER_TYPE_AAUDIO, AAudioConvert_usageToInternal(mParent->getUsage())); + init(android::PLAYER_TYPE_AAUDIO, AAudioConvert_usageToInternal(parent->getUsage())); mRegistered = true; } } void AudioStream::MyPlayerBase::unregisterWithAudioManager() { + std::lock_guard<std::mutex> lock(mParentLock); if (mRegistered) { baseDestroy(); mRegistered = false; } } +android::status_t AudioStream::MyPlayerBase::playerSetVolume() { + android::sp<AudioStream> audioStream; + { + std::lock_guard<std::mutex> lock(mParentLock); + audioStream = mParent.promote(); + } + if (audioStream) { + // No pan and only left volume is taken into account from IPLayer interface + audioStream->setDuckAndMuteVolume(mVolumeMultiplierL /* * mPanMultiplierL */); + } + return android::NO_ERROR; +} + void AudioStream::MyPlayerBase::destroy() { unregisterWithAudioManager(); } diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h index fb71c36d1b..e0bd9d82b5 100644 --- a/media/libaaudio/src/core/AudioStream.h +++ b/media/libaaudio/src/core/AudioStream.h @@ -25,8 +25,10 @@ #include <binder/Status.h> #include <utils/StrongPointer.h> -#include "media/VolumeShaper.h" -#include "media/PlayerBase.h" +#include <media/AudioSystem.h> +#include <media/PlayerBase.h> +#include <media/VolumeShaper.h> + #include "utility/AAudioUtilities.h" #include "utility/MonotonicCounter.h" @@ -45,7 +47,8 @@ constexpr pid_t CALLBACK_THREAD_NONE = 0; /** * AAudio audio stream. */ -class AudioStream { +// By extending AudioDeviceCallback, we also inherit from RefBase. +class AudioStream : public android::AudioSystem::AudioDeviceCallback { public: AudioStream(); @@ -117,6 +120,17 @@ public: virtual void logOpen(); void logReleaseBufferState(); + /* Note about naming for "release" and "close" related methods. + * + * These names are intended to match the public AAudio API. + * The original AAudio API had an AAudioStream_close() function that + * released the hardware and deleted the stream. That made it difficult + * because apps want to release the HW ASAP but are not in a rush to delete + * the stream object. So in R we added an AAudioStream_release() function + * that just released the hardware. + * The AAudioStream_close() method releases if needed and then closes. + */ + /** * Free any hardware or system resources from the open() call. * It is safe to call release_l() multiple times. @@ -126,22 +140,27 @@ public: return AAUDIO_OK; } - aaudio_result_t closeFinal() { + /** + * Free any resources not already freed by release_l(). + * Assume release_l() already called. + */ + virtual void close_l() { + // Releasing the stream will set the state to CLOSING. + assert(getState() == AAUDIO_STREAM_STATE_CLOSING); + // setState() prevents a transition from CLOSING to any state other than CLOSED. // State is checked by destructor. setState(AAUDIO_STREAM_STATE_CLOSED); - return AAUDIO_OK; } /** * Release then close the stream. - * @return AAUDIO_OK or negative error. */ - aaudio_result_t releaseCloseFinal() { - aaudio_result_t result = release_l(); // TODO review locking - if (result == AAUDIO_OK) { - result = closeFinal(); + void releaseCloseFinal() { + if (getState() != AAUDIO_STREAM_STATE_CLOSING) { // not already released? + // Ignore result and keep closing. + (void) release_l(); } - return result; + close_l(); } // This is only used to identify a stream in the logs without @@ -328,6 +347,10 @@ public: */ bool collidesWithCallback() const; + // Implement AudioDeviceCallback + void onAudioDeviceUpdate(audio_io_handle_t audioIo, + audio_port_handle_t deviceId) override {}; + // ============== I/O =========================== // A Stream will only implement read() or write() depending on its direction. virtual aaudio_result_t write(const void *buffer __unused, @@ -366,7 +389,7 @@ public: */ void registerPlayerBase() { if (getDirection() == AAUDIO_DIRECTION_OUTPUT) { - mPlayerBase->registerWithAudioManager(); + mPlayerBase->registerWithAudioManager(this); } } @@ -395,21 +418,33 @@ public: */ aaudio_result_t systemStopFromCallback(); + /** + * Safely RELEASE a stream after taking mStreamLock and checking + * to make sure we are not being called from a callback. + * @return AAUDIO_OK or a negative error + */ aaudio_result_t safeRelease(); + /** + * Safely RELEASE and CLOSE a stream after taking mStreamLock and checking + * to make sure we are not being called from a callback. + * @return AAUDIO_OK or a negative error + */ + aaudio_result_t safeReleaseClose(); + protected: // PlayerBase allows the system to control the stream volume. class MyPlayerBase : public android::PlayerBase { public: - explicit MyPlayerBase(AudioStream *parent); + MyPlayerBase() {}; - virtual ~MyPlayerBase(); + virtual ~MyPlayerBase() = default; /** * Register for volume changes and remote control. */ - void registerWithAudioManager(); + void registerWithAudioManager(const android::sp<AudioStream>& parent); /** * UnRegister. @@ -421,8 +456,6 @@ protected: */ void destroy() override; - void clearParentReference() { mParent = nullptr; } - // Just a stub. The ability to start audio through PlayerBase is being deprecated. android::status_t playerStart() override { return android::NO_ERROR; @@ -438,18 +471,10 @@ protected: return android::NO_ERROR; } - android::status_t playerSetVolume() override { - // No pan and only left volume is taken into account from IPLayer interface - mParent->setDuckAndMuteVolume(mVolumeMultiplierL /* * mPanMultiplierL */); - return android::NO_ERROR; - } + android::status_t playerSetVolume() override; #if AAUDIO_USE_VOLUME_SHAPER - ::android::binder::Status applyVolumeShaper( - const ::android::media::VolumeShaper::Configuration& configuration, - const ::android::media::VolumeShaper::Operation& operation) { - return mParent->applyVolumeShaper(configuration, operation); - } + ::android::binder::Status applyVolumeShaper(); #endif aaudio_result_t getResult() { @@ -457,9 +482,12 @@ protected: } private: - AudioStream *mParent; - aaudio_result_t mResult = AAUDIO_OK; - bool mRegistered = false; + // Use a weak pointer so the AudioStream can be deleted. + + std::mutex mParentLock; + android::wp<AudioStream> mParent; + aaudio_result_t mResult = AAUDIO_OK; + bool mRegistered = false; }; /** diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp index 60dad84ee8..630b289d5f 100644 --- a/media/libaaudio/src/core/AudioStreamBuilder.cpp +++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp @@ -63,27 +63,26 @@ AudioStreamBuilder::~AudioStreamBuilder() { static aaudio_result_t builder_createStream(aaudio_direction_t direction, aaudio_sharing_mode_t sharingMode, bool tryMMap, - AudioStream **audioStreamPtr) { - *audioStreamPtr = nullptr; + android::sp<AudioStream> &stream) { aaudio_result_t result = AAUDIO_OK; switch (direction) { case AAUDIO_DIRECTION_INPUT: if (tryMMap) { - *audioStreamPtr = new AudioStreamInternalCapture(AAudioBinderClient::getInstance(), + stream = new AudioStreamInternalCapture(AAudioBinderClient::getInstance(), false); } else { - *audioStreamPtr = new AudioStreamRecord(); + stream = new AudioStreamRecord(); } break; case AAUDIO_DIRECTION_OUTPUT: if (tryMMap) { - *audioStreamPtr = new AudioStreamInternalPlay(AAudioBinderClient::getInstance(), + stream = new AudioStreamInternalPlay(AAudioBinderClient::getInstance(), false); } else { - *audioStreamPtr = new AudioStreamTrack(); + stream = new AudioStreamTrack(); } break; @@ -98,7 +97,7 @@ static aaudio_result_t builder_createStream(aaudio_direction_t direction, // Fall back to Legacy path if MMAP not available. // Exact behavior is controlled by MMapPolicy. aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) { - AudioStream *audioStream = nullptr; + if (streamPtr == nullptr) { ALOGE("%s() streamPtr is null", __func__); return AAUDIO_ERROR_NULL; @@ -171,41 +170,48 @@ aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) { setPrivacySensitive(true); } - result = builder_createStream(getDirection(), sharingMode, allowMMap, &audioStream); + android::sp<AudioStream> audioStream; + result = builder_createStream(getDirection(), sharingMode, allowMMap, audioStream); if (result == AAUDIO_OK) { // Open the stream using the parameters from the builder. result = audioStream->open(*this); - if (result == AAUDIO_OK) { - *streamPtr = audioStream; - } else { + if (result != AAUDIO_OK) { bool isMMap = audioStream->isMMap(); - delete audioStream; - audioStream = nullptr; - if (isMMap && allowLegacy) { ALOGV("%s() MMAP stream did not open so try Legacy path", __func__); // If MMAP stream failed to open then TRY using a legacy stream. result = builder_createStream(getDirection(), sharingMode, - false, &audioStream); + false, audioStream); if (result == AAUDIO_OK) { result = audioStream->open(*this); - if (result == AAUDIO_OK) { - *streamPtr = audioStream; - } else { - delete audioStream; - audioStream = nullptr; - } } } } - if (audioStream != nullptr) { + if (result == AAUDIO_OK) { audioStream->logOpen(); - } + *streamPtr = startUsingStream(audioStream); + } // else audioStream will go out of scope and be deleted } return result; } +AudioStream *AudioStreamBuilder::startUsingStream(android::sp<AudioStream> &audioStream) { + // Increment the smart pointer so it will not get deleted when + // we pass it to the C caller and it goes out of scope. + // The C code cannot hold a smart pointer so we increment the reference + // count to indicate that the C app owns a reference. + audioStream->incStrong(nullptr); + return audioStream.get(); +} + +void AudioStreamBuilder::stopUsingStream(AudioStream *stream) { + // Undo the effect of startUsingStream() + android::sp<AudioStream> spAudioStream(stream); + ALOGV("%s() strongCount = %d", __func__, spAudioStream->getStrongCount()); + spAudioStream->decStrong(nullptr); +} + aaudio_result_t AudioStreamBuilder::validate() const { // Check for values that are ridiculously out of range to prevent math overflow exploits. diff --git a/media/libaaudio/src/core/AudioStreamBuilder.h b/media/libaaudio/src/core/AudioStreamBuilder.h index d5fb80d842..9f93341ea4 100644 --- a/media/libaaudio/src/core/AudioStreamBuilder.h +++ b/media/libaaudio/src/core/AudioStreamBuilder.h @@ -108,9 +108,16 @@ public: virtual aaudio_result_t validate() const override; + void logParameters() const; + // Mark the stream so it can be deleted. + static void stopUsingStream(AudioStream *stream); + private: + // Extract a raw pointer that we can pass to a 'C' app. + static AudioStream *startUsingStream(android::sp<AudioStream> &spAudioStream); + bool mSharingModeMatchRequired = false; // must match sharing mode requested aaudio_performance_mode_t mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE; diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp index c062882524..33c1bf567d 100644 --- a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp +++ b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp @@ -34,8 +34,7 @@ using namespace android; using namespace aaudio; AudioStreamLegacy::AudioStreamLegacy() - : AudioStream() - , mDeviceCallback(new StreamDeviceCallback(this)) { + : AudioStream() { } AudioStreamLegacy::~AudioStreamLegacy() { @@ -163,7 +162,11 @@ aaudio_result_t AudioStreamLegacy::checkForDisconnectRequest(bool errorCallbackE } void AudioStreamLegacy::forceDisconnect(bool errorCallbackEnabled) { - if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) { + // There is no need to disconnect if already in these states. + if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED + && getState() != AAUDIO_STREAM_STATE_CLOSING + && getState() != AAUDIO_STREAM_STATE_CLOSED + ) { setState(AAUDIO_STREAM_STATE_DISCONNECTED); if (errorCallbackEnabled) { maybeCallErrorCallback(AAUDIO_ERROR_DISCONNECTED); @@ -205,24 +208,30 @@ aaudio_result_t AudioStreamLegacy::getBestTimestamp(clockid_t clockId, return AAudioConvert_androidToAAudioResult(status); } -void AudioStreamLegacy::onAudioDeviceUpdate(audio_port_handle_t deviceId) -{ +void AudioStreamLegacy::onAudioDeviceUpdate(audio_io_handle_t /* audioIo */, + audio_port_handle_t deviceId) { // Device routing is a common source of errors and DISCONNECTS. - // Please leave this log in place. - ALOGD("%s() devId %d => %d", __func__, (int) getDeviceId(), (int)deviceId); - if (getDeviceId() != AAUDIO_UNSPECIFIED && getDeviceId() != deviceId && - getState() != AAUDIO_STREAM_STATE_DISCONNECTED) { + // Please leave this log in place. If there is a bug then this might + // get called after the stream has been deleted so log before we + // touch the stream object. + ALOGD("%s(deviceId = %d)", __func__, (int)deviceId); + if (getDeviceId() != AAUDIO_UNSPECIFIED + && getDeviceId() != deviceId + && getState() != AAUDIO_STREAM_STATE_DISCONNECTED + ) { // Note that isDataCallbackActive() is affected by state so call it before DISCONNECTING. // If we have a data callback and the stream is active, then ask the data callback // to DISCONNECT and call the error callback. if (isDataCallbackActive()) { - ALOGD("onAudioDeviceUpdate() request DISCONNECT in data callback due to device change"); + ALOGD("%s() request DISCONNECT in data callback, device %d => %d", + __func__, (int) getDeviceId(), (int) deviceId); // If the stream is stopped before the data callback has a chance to handle the // request then the requestStop() and requestPause() methods will handle it after // the callback has stopped. mRequestDisconnect.request(); } else { - ALOGD("onAudioDeviceUpdate() DISCONNECT the stream now"); + ALOGD("%s() DISCONNECT the stream now, device %d => %d", + __func__, (int) getDeviceId(), (int) deviceId); forceDisconnect(); } } diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.h b/media/libaaudio/src/legacy/AudioStreamLegacy.h index 9c24b2be7f..fefe6e0a02 100644 --- a/media/libaaudio/src/legacy/AudioStreamLegacy.h +++ b/media/libaaudio/src/legacy/AudioStreamLegacy.h @@ -87,29 +87,13 @@ public: protected: - class StreamDeviceCallback : public android::AudioSystem::AudioDeviceCallback - { - public: - - StreamDeviceCallback(AudioStreamLegacy *parent) : mParent(parent) {} - virtual ~StreamDeviceCallback() {} - - virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo __unused, - audio_port_handle_t deviceId) { - if (mParent != nullptr) { - mParent->onAudioDeviceUpdate(deviceId); - } - } - - AudioStreamLegacy *mParent; - }; - aaudio_result_t getBestTimestamp(clockid_t clockId, int64_t *framePosition, int64_t *timeNanoseconds, android::ExtendedTimestamp *extendedTimestamp); - void onAudioDeviceUpdate(audio_port_handle_t deviceId); + void onAudioDeviceUpdate(audio_io_handle_t audioIo, + audio_port_handle_t deviceId) override; /* * Check to see whether a callback thread has requested a disconnected. @@ -140,7 +124,6 @@ protected: int32_t mBlockAdapterBytesPerFrame = 0; aaudio_wrapping_frames_t mPositionWhenStarting = 0; int32_t mCallbackBufferSize = 0; - const android::sp<StreamDeviceCallback> mDeviceCallback; AtomicRequestor mRequestDisconnect; diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp index b0dc59e2b4..d62951e80a 100644 --- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp +++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp @@ -282,7 +282,7 @@ aaudio_result_t AudioStreamRecord::open(const AudioStreamBuilder& builder) : (aaudio_session_id_t) mAudioRecord->getSessionId(); setSessionId(actualSessionId); - mAudioRecord->addAudioDeviceCallback(mDeviceCallback); + mAudioRecord->addAudioDeviceCallback(this); return AAUDIO_OK; } @@ -291,16 +291,24 @@ aaudio_result_t AudioStreamRecord::release_l() { // TODO add close() or release() to AudioFlinger's AudioRecord API. // Then call it from here if (getState() != AAUDIO_STREAM_STATE_CLOSING) { - mAudioRecord->removeAudioDeviceCallback(mDeviceCallback); + mAudioRecord->removeAudioDeviceCallback(this); logReleaseBufferState(); - mAudioRecord.clear(); - mFixedBlockWriter.close(); + // Data callbacks may still be running! return AudioStream::release_l(); } else { return AAUDIO_OK; // already released } } +void AudioStreamRecord::close_l() { + mAudioRecord.clear(); + // Do not close mFixedBlockWriter because a data callback + // thread might still be running if someone else has a reference + // to mAudioRecord. + // It has a unique_ptr to its buffer so it will clean up by itself. + AudioStream::close_l(); +} + const void * AudioStreamRecord::maybeConvertDeviceData(const void *audioData, int32_t numFrames) { if (mFormatConversionBufferFloat.get() != nullptr) { LOG_ALWAYS_FATAL_IF(numFrames > mFormatConversionBufferSizeInFrames, diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.h b/media/libaaudio/src/legacy/AudioStreamRecord.h index c5944c7753..e4ef1c0922 100644 --- a/media/libaaudio/src/legacy/AudioStreamRecord.h +++ b/media/libaaudio/src/legacy/AudioStreamRecord.h @@ -39,6 +39,7 @@ public: aaudio_result_t open(const AudioStreamBuilder & builder) override; aaudio_result_t release_l() override; + void close_l() override; aaudio_result_t requestStart() override; aaudio_result_t requestStop() override; diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp index 48694801c0..3831046605 100644 --- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp +++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp @@ -224,7 +224,7 @@ aaudio_result_t AudioStreamTrack::open(const AudioStreamBuilder& builder) mInitialBufferCapacity = getBufferCapacity(); mInitialFramesPerBurst = getFramesPerBurst(); - mAudioTrack->addAudioDeviceCallback(mDeviceCallback); + mAudioTrack->addAudioDeviceCallback(this); // Update performance mode based on the actual stream flags. // For example, if the sample rate is not allowed then you won't get a FAST track. @@ -253,19 +253,26 @@ aaudio_result_t AudioStreamTrack::open(const AudioStreamBuilder& builder) aaudio_result_t AudioStreamTrack::release_l() { if (getState() != AAUDIO_STREAM_STATE_CLOSING) { - mAudioTrack->removeAudioDeviceCallback(mDeviceCallback); + status_t err = mAudioTrack->removeAudioDeviceCallback(this); + ALOGE_IF(err, "%s() removeAudioDeviceCallback returned %d", __func__, err); logReleaseBufferState(); - // TODO Investigate why clear() causes a hang in test_various.cpp - // if I call close() from a data callback. - // But the same thing in AudioRecord is OK! - // mAudioTrack.clear(); - mFixedBlockReader.close(); + // Data callbacks may still be running! return AudioStream::release_l(); } else { return AAUDIO_OK; // already released } } +void AudioStreamTrack::close_l() { + // Stop callbacks before deleting mFixedBlockReader memory. + mAudioTrack.clear(); + // Do not close mFixedBlockReader because a data callback + // thread might still be running if someone else has a reference + // to mAudioRecord. + // It has a unique_ptr to its buffer so it will clean up by itself. + AudioStream::close_l(); +} + void AudioStreamTrack::processCallback(int event, void *info) { switch (event) { diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.h b/media/libaaudio/src/legacy/AudioStreamTrack.h index 93a1ff4e68..6334f6619e 100644 --- a/media/libaaudio/src/legacy/AudioStreamTrack.h +++ b/media/libaaudio/src/legacy/AudioStreamTrack.h @@ -42,6 +42,7 @@ public: aaudio_result_t open(const AudioStreamBuilder & builder) override; aaudio_result_t release_l() override; + void close_l() override; aaudio_result_t requestStart() override; aaudio_result_t requestPause() override; diff --git a/media/libaaudio/tests/test_various.cpp b/media/libaaudio/tests/test_various.cpp index a20c799847..cbf863fec7 100644 --- a/media/libaaudio/tests/test_various.cpp +++ b/media/libaaudio/tests/test_various.cpp @@ -33,6 +33,11 @@ aaudio_data_callback_result_t NoopDataCallbackProc( void *audioData, int32_t numFrames ) { + aaudio_direction_t direction = AAudioStream_getDirection(stream); + if (direction == AAUDIO_DIRECTION_INPUT) { + return AAUDIO_CALLBACK_RESULT_CONTINUE; + } + // Check to make sure the buffer is initialized to all zeros. int channels = AAudioStream_getChannelCount(stream); int numSamples = channels * numFrames; bool allZeros = true; @@ -48,7 +53,8 @@ aaudio_data_callback_result_t NoopDataCallbackProc( constexpr int64_t NANOS_PER_MILLISECOND = 1000 * 1000; void checkReleaseThenClose(aaudio_performance_mode_t perfMode, - aaudio_sharing_mode_t sharingMode) { + aaudio_sharing_mode_t sharingMode, + aaudio_direction_t direction = AAUDIO_DIRECTION_OUTPUT) { AAudioStreamBuilder* aaudioBuilder = nullptr; AAudioStream* aaudioStream = nullptr; @@ -61,6 +67,7 @@ void checkReleaseThenClose(aaudio_performance_mode_t perfMode, nullptr); AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, perfMode); AAudioStreamBuilder_setSharingMode(aaudioBuilder, sharingMode); + AAudioStreamBuilder_setDirection(aaudioBuilder, direction); AAudioStreamBuilder_setFormat(aaudioBuilder, AAUDIO_FORMAT_PCM_FLOAT); // Create an AAudioStream using the Builder. @@ -88,14 +95,28 @@ void checkReleaseThenClose(aaudio_performance_mode_t perfMode, // We should NOT be able to start or change a stream after it has been released. EXPECT_EQ(AAUDIO_ERROR_INVALID_STATE, AAudioStream_requestStart(aaudioStream)); EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, AAudioStream_getState(aaudioStream)); - EXPECT_EQ(AAUDIO_ERROR_INVALID_STATE, AAudioStream_requestPause(aaudioStream)); + // Pause is only implemented for OUTPUT. + if (direction == AAUDIO_DIRECTION_OUTPUT) { + EXPECT_EQ(AAUDIO_ERROR_INVALID_STATE, + AAudioStream_requestPause(aaudioStream)); + } EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, AAudioStream_getState(aaudioStream)); EXPECT_EQ(AAUDIO_ERROR_INVALID_STATE, AAudioStream_requestStop(aaudioStream)); EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, AAudioStream_getState(aaudioStream)); // Does this crash? - EXPECT_LT(0, AAudioStream_getFramesRead(aaudioStream)); - EXPECT_LT(0, AAudioStream_getFramesWritten(aaudioStream)); + EXPECT_GT(AAudioStream_getFramesRead(aaudioStream), 0); + EXPECT_GT(AAudioStream_getFramesWritten(aaudioStream), 0); + EXPECT_GT(AAudioStream_getFramesPerBurst(aaudioStream), 0); + EXPECT_GE(AAudioStream_getXRunCount(aaudioStream), 0); + EXPECT_GT(AAudioStream_getBufferCapacityInFrames(aaudioStream), 0); + EXPECT_GT(AAudioStream_getBufferSizeInFrames(aaudioStream), 0); + + int64_t timestampFrames = 0; + int64_t timestampNanos = 0; + aaudio_result_t result = AAudioStream_getTimestamp(aaudioStream, CLOCK_MONOTONIC, + ×tampFrames, ×tampNanos); + EXPECT_TRUE(result == AAUDIO_ERROR_INVALID_STATE || result == AAUDIO_ERROR_UNIMPLEMENTED); // Verify Closing State. Does this crash? aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNKNOWN; @@ -107,20 +128,42 @@ void checkReleaseThenClose(aaudio_performance_mode_t perfMode, EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream)); } -TEST(test_various, aaudio_release_close_none) { +TEST(test_various, aaudio_release_close_none_output) { + checkReleaseThenClose(AAUDIO_PERFORMANCE_MODE_NONE, + AAUDIO_SHARING_MODE_SHARED, + AAUDIO_DIRECTION_OUTPUT); + // No EXCLUSIVE streams with MODE_NONE. +} + +TEST(test_various, aaudio_release_close_none_input) { checkReleaseThenClose(AAUDIO_PERFORMANCE_MODE_NONE, - AAUDIO_SHARING_MODE_SHARED); + AAUDIO_SHARING_MODE_SHARED, + AAUDIO_DIRECTION_INPUT); // No EXCLUSIVE streams with MODE_NONE. } -TEST(test_various, aaudio_release_close_low_shared) { +TEST(test_various, aaudio_release_close_low_shared_output) { + checkReleaseThenClose(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, + AAUDIO_SHARING_MODE_SHARED, + AAUDIO_DIRECTION_OUTPUT); +} + +TEST(test_various, aaudio_release_close_low_shared_input) { + checkReleaseThenClose(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, + AAUDIO_SHARING_MODE_SHARED, + AAUDIO_DIRECTION_INPUT); +} + +TEST(test_various, aaudio_release_close_low_exclusive_output) { checkReleaseThenClose(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, - AAUDIO_SHARING_MODE_SHARED); + AAUDIO_SHARING_MODE_EXCLUSIVE, + AAUDIO_DIRECTION_OUTPUT); } -TEST(test_various, aaudio_release_close_low_exclusive) { +TEST(test_various, aaudio_release_close_low_exclusive_input) { checkReleaseThenClose(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, - AAUDIO_SHARING_MODE_EXCLUSIVE); + AAUDIO_SHARING_MODE_EXCLUSIVE, + AAUDIO_DIRECTION_INPUT); } enum FunctionToCall { diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp index 0c40cbb1a3..fa2a159d05 100644 --- a/media/libaudioclient/Android.bp +++ b/media/libaudioclient/Android.bp @@ -63,6 +63,7 @@ cc_library_shared { "AudioEffect.cpp", "AudioRecord.cpp", + "AudioSanitizer.cpp", "AudioSystem.cpp", "AudioTrack.cpp", "AudioTrackShared.cpp", diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp index 3ead6cb1ac..73b96abd3b 100644 --- a/media/libaudioclient/AudioEffect.cpp +++ b/media/libaudioclient/AudioEffect.cpp @@ -36,64 +36,10 @@ namespace android { // --------------------------------------------------------------------------- AudioEffect::AudioEffect(const String16& opPackageName) - : mStatus(NO_INIT), mProbe(false), mOpPackageName(opPackageName) + : mOpPackageName(opPackageName) { } - -AudioEffect::AudioEffect(const effect_uuid_t *type, - const String16& opPackageName, - const effect_uuid_t *uuid, - int32_t priority, - effect_callback_t cbf, - void* user, - audio_session_t sessionId, - audio_io_handle_t io, - const AudioDeviceTypeAddr& device, - bool probe - ) - : mStatus(NO_INIT), mProbe(false), mOpPackageName(opPackageName) -{ - AutoMutex lock(mConstructLock); - mStatus = set(type, uuid, priority, cbf, user, sessionId, io, device, probe); -} - -AudioEffect::AudioEffect(const char *typeStr, - const String16& opPackageName, - const char *uuidStr, - int32_t priority, - effect_callback_t cbf, - void* user, - audio_session_t sessionId, - audio_io_handle_t io, - const AudioDeviceTypeAddr& device, - bool probe - ) - : mStatus(NO_INIT), mProbe(false), mOpPackageName(opPackageName) -{ - effect_uuid_t type; - effect_uuid_t *pType = NULL; - effect_uuid_t uuid; - effect_uuid_t *pUuid = NULL; - - ALOGV("Constructor string\n - type: %s\n - uuid: %s", typeStr, uuidStr); - - if (typeStr != NULL) { - if (stringToGuid(typeStr, &type) == NO_ERROR) { - pType = &type; - } - } - - if (uuidStr != NULL) { - if (stringToGuid(uuidStr, &uuid) == NO_ERROR) { - pUuid = &uuid; - } - } - - AutoMutex lock(mConstructLock); - mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io, device, probe); -} - status_t AudioEffect::set(const effect_uuid_t *type, const effect_uuid_t *uuid, int32_t priority, @@ -194,6 +140,34 @@ status_t AudioEffect::set(const effect_uuid_t *type, return mStatus; } +status_t AudioEffect::set(const char *typeStr, + const char *uuidStr, + int32_t priority, + effect_callback_t cbf, + void* user, + audio_session_t sessionId, + audio_io_handle_t io, + const AudioDeviceTypeAddr& device, + bool probe) +{ + effect_uuid_t type; + effect_uuid_t *pType = nullptr; + effect_uuid_t uuid; + effect_uuid_t *pUuid = nullptr; + + ALOGV("AudioEffect::set string\n - type: %s\n - uuid: %s", + typeStr ? typeStr : "nullptr", uuidStr ? uuidStr : "nullptr"); + + if (stringToGuid(typeStr, &type) == NO_ERROR) { + pType = &type; + } + if (stringToGuid(uuidStr, &uuid) == NO_ERROR) { + pUuid = &uuid; + } + + return set(pType, pUuid, priority, cbf, user, sessionId, io, device, probe); +} + AudioEffect::~AudioEffect() { diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp index df47def100..9568e83506 100644 --- a/media/libaudioclient/AudioRecord.cpp +++ b/media/libaudioclient/AudioRecord.cpp @@ -742,6 +742,8 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch, const String void *iMemPointer; audio_track_cblk_t* cblk; status_t status; + static const int32_t kMaxCreateAttempts = 3; + int32_t remainingAttempts = kMaxCreateAttempts; if (audioFlinger == 0) { ALOGE("%s(%d): Could not get audioflinger", __func__, mPortId); @@ -803,15 +805,24 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch, const String input.sessionId = mSessionId; originalSessionId = mSessionId; - record = audioFlinger->createRecord(input, - output, - &status); + do { + record = audioFlinger->createRecord(input, output, &status); + if (status == NO_ERROR) { + break; + } + if (status != FAILED_TRANSACTION || --remainingAttempts <= 0) { + ALOGE("%s(%d): AudioFlinger could not create record track, status: %d", + __func__, mPortId, status); + goto exit; + } + // FAILED_TRANSACTION happens under very specific conditions causing a state mismatch + // between audio policy manager and audio flinger during the input stream open sequence + // and can be recovered by retrying. + // Leave time for race condition to clear before retrying and randomize delay + // to reduce the probability of concurrent retries in locked steps. + usleep((20 + rand() % 30) * 10000); + } while (1); - if (status != NO_ERROR) { - ALOGE("%s(%d): AudioFlinger could not create record track, status: %d", - __func__, mPortId, status); - goto exit; - } ALOG_ASSERT(record != 0); // AudioFlinger now owns the reference to the I/O handle, diff --git a/media/libaudioclient/AudioSanitizer.cpp b/media/libaudioclient/AudioSanitizer.cpp new file mode 100644 index 0000000000..44ca956107 --- /dev/null +++ b/media/libaudioclient/AudioSanitizer.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <media/AudioSanitizer.h> + +namespace android { + + /** returns true if string overflow was prevented by zero termination */ +template <size_t size> +bool preventStringOverflow(char (&s)[size]) { + if (strnlen(s, size) < size) return false; + s[size - 1] = '\0'; + return true; +} + +status_t safetyNetLog(status_t status, const char *bugNumber) { + if (status != NO_ERROR && bugNumber != nullptr) { + android_errorWriteLog(0x534e4554, bugNumber); // SafetyNet logging + } + return status; +} + +status_t AudioSanitizer::sanitizeAudioAttributes( + audio_attributes_t *attr, const char *bugNumber) +{ + status_t status = NO_ERROR; + const size_t tagsMaxSize = AUDIO_ATTRIBUTES_TAGS_MAX_SIZE; + if (strnlen(attr->tags, tagsMaxSize) >= tagsMaxSize) { + status = BAD_VALUE; + } + attr->tags[tagsMaxSize - 1] = '\0'; + return safetyNetLog(status, bugNumber); +} + +/** returns BAD_VALUE if sanitization was required. */ +status_t AudioSanitizer::sanitizeEffectDescriptor( + effect_descriptor_t *desc, const char *bugNumber) +{ + status_t status = NO_ERROR; + if (preventStringOverflow(desc->name) + | /* always */ preventStringOverflow(desc->implementor)) { + status = BAD_VALUE; + } + return safetyNetLog(status, bugNumber); +} + +/** returns BAD_VALUE if sanitization was required. */ +status_t AudioSanitizer::sanitizeAudioPortConfig( + struct audio_port_config *config, const char *bugNumber) +{ + status_t status = NO_ERROR; + if (config->type == AUDIO_PORT_TYPE_DEVICE && + preventStringOverflow(config->ext.device.address)) { + status = BAD_VALUE; + } + return safetyNetLog(status, bugNumber); +} + +/** returns BAD_VALUE if sanitization was required. */ +status_t AudioSanitizer::sanitizeAudioPort( + struct audio_port *port, const char *bugNumber) +{ + status_t status = NO_ERROR; + if (preventStringOverflow(port->name)) { + status = BAD_VALUE; + } + if (sanitizeAudioPortConfig(&port->active_config) != NO_ERROR) { + status = BAD_VALUE; + } + if (port->type == AUDIO_PORT_TYPE_DEVICE && + preventStringOverflow(port->ext.device.address)) { + status = BAD_VALUE; + } + return safetyNetLog(status, bugNumber); +} + +/** returns BAD_VALUE if sanitization was required. */ +status_t AudioSanitizer::sanitizeAudioPatch( + struct audio_patch *patch, const char *bugNumber) +{ + status_t status = NO_ERROR; + if (patch->num_sources > AUDIO_PATCH_PORTS_MAX) { + patch->num_sources = AUDIO_PATCH_PORTS_MAX; + status = BAD_VALUE; + } + if (patch->num_sinks > AUDIO_PATCH_PORTS_MAX) { + patch->num_sinks = AUDIO_PATCH_PORTS_MAX; + status = BAD_VALUE; + } + for (size_t i = 0; i < patch->num_sources; i++) { + if (sanitizeAudioPortConfig(&patch->sources[i]) != NO_ERROR) { + status = BAD_VALUE; + } + } + for (size_t i = 0; i < patch->num_sinks; i++) { + if (sanitizeAudioPortConfig(&patch->sinks[i]) != NO_ERROR) { + status = BAD_VALUE; + } + } + return safetyNetLog(status, bugNumber); +} + +}; // namespace android diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp index 6357da4316..e26a83160a 100644 --- a/media/libaudioclient/AudioSystem.cpp +++ b/media/libaudioclient/AudioSystem.cpp @@ -47,8 +47,9 @@ dynamic_policy_callback AudioSystem::gDynPolicyCallback = NULL; record_config_callback AudioSystem::gRecordConfigCallback = NULL; // Required to be held while calling into gSoundTriggerCaptureStateListener. +class CaptureStateListenerImpl; Mutex gSoundTriggerCaptureStateListenerLock; -sp<AudioSystem::CaptureStateListener> gSoundTriggerCaptureStateListener = nullptr; +sp<CaptureStateListenerImpl> gSoundTriggerCaptureStateListener = nullptr; // establish binder interface to AudioFlinger service const sp<IAudioFlinger> AudioSystem::get_audio_flinger() @@ -1634,42 +1635,54 @@ status_t AudioSystem::getPreferredDeviceForStrategy(product_strategy_t strategy, class CaptureStateListenerImpl : public media::BnCaptureStateListener, public IBinder::DeathRecipient { public: + CaptureStateListenerImpl( + const sp<IAudioPolicyService>& aps, + const sp<AudioSystem::CaptureStateListener>& listener) + : mAps(aps), mListener(listener) {} + + void init() { + bool active; + status_t status = mAps->registerSoundTriggerCaptureStateListener(this, &active); + if (status != NO_ERROR) { + mListener->onServiceDied(); + return; + } + mListener->onStateChanged(active); + IInterface::asBinder(mAps)->linkToDeath(this); + } + binder::Status setCaptureState(bool active) override { Mutex::Autolock _l(gSoundTriggerCaptureStateListenerLock); - gSoundTriggerCaptureStateListener->onStateChanged(active); + mListener->onStateChanged(active); return binder::Status::ok(); } void binderDied(const wp<IBinder>&) override { Mutex::Autolock _l(gSoundTriggerCaptureStateListenerLock); - gSoundTriggerCaptureStateListener->onServiceDied(); + mListener->onServiceDied(); gSoundTriggerCaptureStateListener = nullptr; } + +private: + // Need this in order to keep the death receipent alive. + sp<IAudioPolicyService> mAps; + sp<AudioSystem::CaptureStateListener> mListener; }; status_t AudioSystem::registerSoundTriggerCaptureStateListener( const sp<CaptureStateListener>& listener) { + LOG_ALWAYS_FATAL_IF(listener == nullptr); + const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) { return PERMISSION_DENIED; } - sp<CaptureStateListenerImpl> wrapper = new CaptureStateListenerImpl(); - Mutex::Autolock _l(gSoundTriggerCaptureStateListenerLock); + gSoundTriggerCaptureStateListener = new CaptureStateListenerImpl(aps, listener); + gSoundTriggerCaptureStateListener->init(); - bool active; - status_t status = - aps->registerSoundTriggerCaptureStateListener(wrapper, &active); - if (status != NO_ERROR) { - listener->onServiceDied(); - return NO_ERROR; - } - gSoundTriggerCaptureStateListener = listener; - listener->onStateChanged(active); - sp<IBinder> binder = IInterface::asBinder(aps); - binder->linkToDeath(wrapper); return NO_ERROR; } diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp index 32129f09bb..68d11d45ca 100644 --- a/media/libaudioclient/AudioTrack.cpp +++ b/media/libaudioclient/AudioTrack.cpp @@ -210,7 +210,11 @@ status_t AudioTrack::getMetrics(mediametrics::Item * &item) return NO_ERROR; } -AudioTrack::AudioTrack() +AudioTrack::AudioTrack() : AudioTrack("" /*opPackageName*/) +{ +} + +AudioTrack::AudioTrack(const std::string& opPackageName) : mStatus(NO_INIT), mState(STATE_STOPPED), mPreviousPriority(ANDROID_PRIORITY_NORMAL), @@ -218,6 +222,7 @@ AudioTrack::AudioTrack() mPausedPosition(0), mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE), + mOpPackageName(opPackageName), mAudioTrackCallback(new AudioTrackCallback()) { mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN; @@ -244,12 +249,14 @@ AudioTrack::AudioTrack( const audio_attributes_t* pAttributes, bool doNotReconnect, float maxRequiredSpeed, - audio_port_handle_t selectedDeviceId) + audio_port_handle_t selectedDeviceId, + const std::string& opPackageName) : mStatus(NO_INIT), mState(STATE_STOPPED), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mPausedPosition(0), + mOpPackageName(opPackageName), mAudioTrackCallback(new AudioTrackCallback()) { mAttributes = AUDIO_ATTRIBUTES_INITIALIZER; @@ -277,13 +284,15 @@ AudioTrack::AudioTrack( pid_t pid, const audio_attributes_t* pAttributes, bool doNotReconnect, - float maxRequiredSpeed) + float maxRequiredSpeed, + const std::string& opPackageName) : mStatus(NO_INIT), mState(STATE_STOPPED), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mPausedPosition(0), mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), + mOpPackageName(opPackageName), mAudioTrackCallback(new AudioTrackCallback()) { mAttributes = AUDIO_ATTRIBUTES_INITIALIZER; @@ -1555,6 +1564,7 @@ status_t AudioTrack::createTrack_l() input.selectedDeviceId = mSelectedDeviceId; input.sessionId = mSessionId; input.audioTrackCallback = mAudioTrackCallback; + input.opPackageName = mOpPackageName; IAudioFlinger::CreateTrackOutput output; diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp index 16d2232a50..d3a037c268 100644 --- a/media/libaudioclient/IAudioFlinger.cpp +++ b/media/libaudioclient/IAudioFlinger.cpp @@ -24,6 +24,7 @@ #include <binder/IPCThreadState.h> #include <binder/Parcel.h> +#include <media/AudioSanitizer.h> #include <mediautils/ServiceUtilities.h> #include <mediautils/TimeCheck.h> #include "IAudioFlinger.h" @@ -1483,10 +1484,15 @@ status_t BnAudioFlinger::onTransact( case GET_AUDIO_PORT: { CHECK_INTERFACE(IAudioFlinger, data, reply); struct audio_port port = {}; - if (data.read(&port, sizeof(struct audio_port)) != NO_ERROR) { + status_t status = data.read(&port, sizeof(struct audio_port)); + if (status != NO_ERROR) { ALOGE("b/23905951"); + return status; + } + status = AudioSanitizer::sanitizeAudioPort(&port); + if (status == NO_ERROR) { + status = getAudioPort(&port); } - status_t status = getAudioPort(&port); reply->writeInt32(status); if (status == NO_ERROR) { reply->write(&port, sizeof(struct audio_port)); @@ -1496,12 +1502,20 @@ status_t BnAudioFlinger::onTransact( case CREATE_AUDIO_PATCH: { CHECK_INTERFACE(IAudioFlinger, data, reply); struct audio_patch patch; - data.read(&patch, sizeof(struct audio_patch)); + status_t status = data.read(&patch, sizeof(struct audio_patch)); + if (status != NO_ERROR) { + return status; + } audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE; - if (data.read(&handle, sizeof(audio_patch_handle_t)) != NO_ERROR) { + status = data.read(&handle, sizeof(audio_patch_handle_t)); + if (status != NO_ERROR) { ALOGE("b/23905951"); + return status; + } + status = AudioSanitizer::sanitizeAudioPatch(&patch); + if (status == NO_ERROR) { + status = createAudioPatch(&patch, &handle); } - status_t status = createAudioPatch(&patch, &handle); reply->writeInt32(status); if (status == NO_ERROR) { reply->write(&handle, sizeof(audio_patch_handle_t)); @@ -1546,8 +1560,14 @@ status_t BnAudioFlinger::onTransact( case SET_AUDIO_PORT_CONFIG: { CHECK_INTERFACE(IAudioFlinger, data, reply); struct audio_port_config config; - data.read(&config, sizeof(struct audio_port_config)); - status_t status = setAudioPortConfig(&config); + status_t status = data.read(&config, sizeof(struct audio_port_config)); + if (status != NO_ERROR) { + return status; + } + status = AudioSanitizer::sanitizeAudioPortConfig(&config); + if (status == NO_ERROR) { + status = setAudioPortConfig(&config); + } reply->writeInt32(status); return NO_ERROR; } break; diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp index 60af84bab2..43a5369220 100644 --- a/media/libaudioclient/IAudioPolicyService.cpp +++ b/media/libaudioclient/IAudioPolicyService.cpp @@ -26,6 +26,7 @@ #include <binder/IPCThreadState.h> #include <binder/Parcel.h> #include <media/AudioEffect.h> +#include <media/AudioSanitizer.h> #include <media/IAudioPolicyService.h> #include <mediautils/ServiceUtilities.h> #include <mediautils/TimeCheck.h> @@ -1685,7 +1686,6 @@ status_t BnAudioPolicyService::onTransact( if (status != NO_ERROR) { return status; } - sanetizeAudioAttributes(&attr); audio_session_t session = (audio_session_t)data.readInt32(); audio_stream_type_t stream = AUDIO_STREAM_DEFAULT; bool hasStream = data.readInt32() != 0; @@ -1703,10 +1703,14 @@ status_t BnAudioPolicyService::onTransact( audio_port_handle_t portId = (audio_port_handle_t)data.readInt32(); audio_io_handle_t output = 0; std::vector<audio_io_handle_t> secondaryOutputs; - status = getOutputForAttr(&attr, - &output, session, &stream, pid, uid, - &config, - flags, &selectedDeviceId, &portId, &secondaryOutputs); + + status = AudioSanitizer::sanitizeAudioAttributes(&attr, "68953950"); + if (status == NO_ERROR) { + status = getOutputForAttr(&attr, + &output, session, &stream, pid, uid, + &config, + flags, &selectedDeviceId, &portId, &secondaryOutputs); + } reply->writeInt32(status); status = reply->write(&attr, sizeof(audio_attributes_t)); if (status != NO_ERROR) { @@ -1745,8 +1749,11 @@ status_t BnAudioPolicyService::onTransact( case GET_INPUT_FOR_ATTR: { CHECK_INTERFACE(IAudioPolicyService, data, reply); audio_attributes_t attr = {}; - data.read(&attr, sizeof(audio_attributes_t)); - sanetizeAudioAttributes(&attr); + status_t status = data.read(&attr, sizeof(audio_attributes_t)); + if (status != NO_ERROR) { + return status; + } + audio_io_handle_t input = (audio_io_handle_t)data.readInt32(); audio_unique_id_t riid = (audio_unique_id_t)data.readInt32(); audio_session_t session = (audio_session_t)data.readInt32(); @@ -1759,9 +1766,13 @@ status_t BnAudioPolicyService::onTransact( audio_input_flags_t flags = (audio_input_flags_t) data.readInt32(); audio_port_handle_t selectedDeviceId = (audio_port_handle_t) data.readInt32(); audio_port_handle_t portId = (audio_port_handle_t)data.readInt32(); - status_t status = getInputForAttr(&attr, &input, riid, session, pid, uid, - opPackageName, &config, - flags, &selectedDeviceId, &portId); + + status = AudioSanitizer::sanitizeAudioAttributes(&attr, "68953950"); + if (status == NO_ERROR) { + status = getInputForAttr(&attr, &input, riid, session, pid, uid, + opPackageName, &config, + flags, &selectedDeviceId, &portId); + } reply->writeInt32(status); if (status == NO_ERROR) { reply->writeInt32(input); @@ -1842,11 +1853,15 @@ status_t BnAudioPolicyService::onTransact( if (status != NO_ERROR) { return status; } + int index = data.readInt32(); audio_devices_t device = static_cast <audio_devices_t>(data.readInt32()); - reply->writeInt32(static_cast <uint32_t>(setVolumeIndexForAttributes(attributes, - index, device))); + status = AudioSanitizer::sanitizeAudioAttributes(&attributes, "169572641"); + if (status == NO_ERROR) { + status = setVolumeIndexForAttributes(attributes, index, device); + } + reply->writeInt32(static_cast <int32_t>(status)); return NO_ERROR; } break; @@ -1860,8 +1875,11 @@ status_t BnAudioPolicyService::onTransact( audio_devices_t device = static_cast <audio_devices_t>(data.readInt32()); int index = 0; - status = getVolumeIndexForAttributes(attributes, index, device); - reply->writeInt32(static_cast <uint32_t>(status)); + status = AudioSanitizer::sanitizeAudioAttributes(&attributes, "169572641"); + if (status == NO_ERROR) { + status = getVolumeIndexForAttributes(attributes, index, device); + } + reply->writeInt32(static_cast <int32_t>(status)); if (status == NO_ERROR) { reply->writeInt32(index); } @@ -1877,8 +1895,11 @@ status_t BnAudioPolicyService::onTransact( } int index = 0; - status = getMinVolumeIndexForAttributes(attributes, index); - reply->writeInt32(static_cast <uint32_t>(status)); + status = AudioSanitizer::sanitizeAudioAttributes(&attributes, "169572641"); + if (status == NO_ERROR) { + status = getMinVolumeIndexForAttributes(attributes, index); + } + reply->writeInt32(static_cast <int32_t>(status)); if (status == NO_ERROR) { reply->writeInt32(index); } @@ -1894,8 +1915,11 @@ status_t BnAudioPolicyService::onTransact( } int index = 0; - status = getMaxVolumeIndexForAttributes(attributes, index); - reply->writeInt32(static_cast <uint32_t>(status)); + status = AudioSanitizer::sanitizeAudioAttributes(&attributes, "169572641"); + if (status == NO_ERROR) { + status = getMaxVolumeIndexForAttributes(attributes, index); + } + reply->writeInt32(static_cast <int32_t>(status)); if (status == NO_ERROR) { reply->writeInt32(index); } @@ -1913,31 +1937,37 @@ status_t BnAudioPolicyService::onTransact( case GET_OUTPUT_FOR_EFFECT: { CHECK_INTERFACE(IAudioPolicyService, data, reply); effect_descriptor_t desc = {}; - if (data.read(&desc, sizeof(desc)) != NO_ERROR) { + status_t status = data.read(&desc, sizeof(desc)); + if (status != NO_ERROR) { android_errorWriteLog(0x534e4554, "73126106"); + return status; } - (void)sanitizeEffectDescriptor(&desc); - audio_io_handle_t output = getOutputForEffect(&desc); - reply->writeInt32(static_cast <int>(output)); + audio_io_handle_t output = AUDIO_IO_HANDLE_NONE; + status = AudioSanitizer::sanitizeEffectDescriptor(&desc, "73126106"); + if (status == NO_ERROR) { + output = getOutputForEffect(&desc); + } + reply->writeInt32(static_cast <int32_t>(output)); return NO_ERROR; } break; case REGISTER_EFFECT: { CHECK_INTERFACE(IAudioPolicyService, data, reply); effect_descriptor_t desc = {}; - if (data.read(&desc, sizeof(desc)) != NO_ERROR) { + status_t status = data.read(&desc, sizeof(desc)); + if (status != NO_ERROR) { android_errorWriteLog(0x534e4554, "73126106"); + return status; } - (void)sanitizeEffectDescriptor(&desc); audio_io_handle_t io = data.readInt32(); uint32_t strategy = data.readInt32(); audio_session_t session = (audio_session_t) data.readInt32(); int id = data.readInt32(); - reply->writeInt32(static_cast <int32_t>(registerEffect(&desc, - io, - strategy, - session, - id))); + status = AudioSanitizer::sanitizeEffectDescriptor(&desc, "73126106"); + if (status == NO_ERROR) { + status = registerEffect(&desc, io, strategy, session, id); + } + reply->writeInt32(static_cast <int32_t>(status)); return NO_ERROR; } break; @@ -2046,7 +2076,11 @@ status_t BnAudioPolicyService::onTransact( if (status != NO_ERROR) return status; status = data.read(&attributes, sizeof(audio_attributes_t)); if (status != NO_ERROR) return status; - reply->writeInt32(isDirectOutputSupported(config, attributes)); + status = AudioSanitizer::sanitizeAudioAttributes(&attributes, "169572641"); + if (status == NO_ERROR) { + status = isDirectOutputSupported(config, attributes); + } + reply->writeInt32(static_cast <int32_t>(status)); return NO_ERROR; } @@ -2085,10 +2119,15 @@ status_t BnAudioPolicyService::onTransact( case GET_AUDIO_PORT: { CHECK_INTERFACE(IAudioPolicyService, data, reply); struct audio_port port = {}; - if (data.read(&port, sizeof(struct audio_port)) != NO_ERROR) { + status_t status = data.read(&port, sizeof(struct audio_port)); + if (status != NO_ERROR) { ALOGE("b/23912202"); + return status; + } + status = AudioSanitizer::sanitizeAudioPort(&port); + if (status == NO_ERROR) { + status = getAudioPort(&port); } - status_t status = getAudioPort(&port); reply->writeInt32(status); if (status == NO_ERROR) { reply->write(&port, sizeof(struct audio_port)); @@ -2099,12 +2138,20 @@ status_t BnAudioPolicyService::onTransact( case CREATE_AUDIO_PATCH: { CHECK_INTERFACE(IAudioPolicyService, data, reply); struct audio_patch patch = {}; - data.read(&patch, sizeof(struct audio_patch)); + status_t status = data.read(&patch, sizeof(struct audio_patch)); + if (status != NO_ERROR) { + return status; + } audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE; - if (data.read(&handle, sizeof(audio_patch_handle_t)) != NO_ERROR) { + status = data.read(&handle, sizeof(audio_patch_handle_t)); + if (status != NO_ERROR) { ALOGE("b/23912202"); + return status; + } + status = AudioSanitizer::sanitizeAudioPatch(&patch); + if (status == NO_ERROR) { + status = createAudioPatch(&patch, &handle); } - status_t status = createAudioPatch(&patch, &handle); reply->writeInt32(status); if (status == NO_ERROR) { reply->write(&handle, sizeof(audio_patch_handle_t)); @@ -2154,9 +2201,12 @@ status_t BnAudioPolicyService::onTransact( case SET_AUDIO_PORT_CONFIG: { CHECK_INTERFACE(IAudioPolicyService, data, reply); struct audio_port_config config = {}; - data.read(&config, sizeof(struct audio_port_config)); - (void)sanitizeAudioPortConfig(&config); - status_t status = setAudioPortConfig(&config); + status_t status = data.read(&config, sizeof(struct audio_port_config)); + if (status != NO_ERROR) { + return status; + } + (void)AudioSanitizer::sanitizeAudioPortConfig(&config); + status = setAudioPortConfig(&config); reply->writeInt32(status); return NO_ERROR; } @@ -2232,13 +2282,25 @@ status_t BnAudioPolicyService::onTransact( case START_AUDIO_SOURCE: { CHECK_INTERFACE(IAudioPolicyService, data, reply); struct audio_port_config source = {}; - data.read(&source, sizeof(struct audio_port_config)); - (void)sanitizeAudioPortConfig(&source); + status_t status = data.read(&source, sizeof(struct audio_port_config)); + if (status != NO_ERROR) { + return status; + } audio_attributes_t attributes = {}; - data.read(&attributes, sizeof(audio_attributes_t)); - sanetizeAudioAttributes(&attributes); + status = data.read(&attributes, sizeof(audio_attributes_t)); + if (status != NO_ERROR) { + return status; + } + status = AudioSanitizer::sanitizeAudioPortConfig(&source); + if (status == NO_ERROR) { + // OK to not always sanitize attributes as startAudioSource() is not called if + // the port config is invalid. + status = AudioSanitizer::sanitizeAudioAttributes(&attributes, "68953950"); + } audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE; - status_t status = startAudioSource(&source, &attributes, &portId); + if (status == NO_ERROR) { + status = startAudioSource(&source, &attributes, &portId); + } reply->writeInt32(status); reply->writeInt32(portId); return NO_ERROR; @@ -2762,44 +2824,6 @@ status_t BnAudioPolicyService::onTransact( } } -/** returns true if string overflow was prevented by zero termination */ -template <size_t size> -static bool preventStringOverflow(char (&s)[size]) { - if (strnlen(s, size) < size) return false; - s[size - 1] = '\0'; - return true; -} - -void BnAudioPolicyService::sanetizeAudioAttributes(audio_attributes_t* attr) -{ - const size_t tagsMaxSize = AUDIO_ATTRIBUTES_TAGS_MAX_SIZE; - if (strnlen(attr->tags, tagsMaxSize) >= tagsMaxSize) { - android_errorWriteLog(0x534e4554, "68953950"); // SafetyNet logging - } - attr->tags[tagsMaxSize - 1] = '\0'; -} - -/** returns BAD_VALUE if sanitization was required. */ -status_t BnAudioPolicyService::sanitizeEffectDescriptor(effect_descriptor_t* desc) -{ - if (preventStringOverflow(desc->name) - | /* always */ preventStringOverflow(desc->implementor)) { - android_errorWriteLog(0x534e4554, "73126106"); // SafetyNet logging - return BAD_VALUE; - } - return NO_ERROR; -} - -/** returns BAD_VALUE if sanitization was required. */ -status_t BnAudioPolicyService::sanitizeAudioPortConfig(struct audio_port_config* config) -{ - if (config->type == AUDIO_PORT_TYPE_DEVICE && - preventStringOverflow(config->ext.device.address)) { - return BAD_VALUE; - } - return NO_ERROR; -} - // ---------------------------------------------------------------------------- } // namespace android diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp index 050ad65657..ee78a2d47c 100644 --- a/media/libaudioclient/ToneGenerator.cpp +++ b/media/libaudioclient/ToneGenerator.cpp @@ -853,6 +853,11 @@ const ToneGenerator::ToneDescriptor ToneGenerator::sToneDescriptors[] = { { .duration = 0 , .waveFreq = { 0 }, 0, 0}}, .repeatCnt = ToneGenerator::TONEGEN_INF, .repeatSegment = 0 }, // TONE_INDIA_RINGTONE + { .segments = { { .duration = 1000, .waveFreq = { 440, 480, 0 }, 0, 0 }, + { .duration = 2000, .waveFreq = { 0 }, 0, 0 }, + { .duration = 0 , .waveFreq = { 0 }, 0, 0}}, + .repeatCnt = ToneGenerator::TONEGEN_INF, + .repeatSegment = 0 }, // TONE_TW_RINGTONE }; // Used by ToneGenerator::getToneForRegion() to convert user specified supervisory tone type @@ -937,6 +942,16 @@ const unsigned char /*tone_type*/ ToneGenerator::sToneMappingTable[NUM_REGIONS-1 TONE_SUP_ERROR, // TONE_SUP_ERROR TONE_INDIA_CALL_WAITING, // TONE_SUP_CALL_WAITING TONE_INDIA_RINGTONE // TONE_SUP_RINGTONE + }, + { // TAIWAN + TONE_SUP_DIAL, // TONE_SUP_DIAL + TONE_SUP_BUSY, // TONE_SUP_BUSY + TONE_SUP_CONGESTION, // TONE_SUP_CONGESTION + TONE_SUP_RADIO_ACK, // TONE_SUP_RADIO_ACK + TONE_SUP_RADIO_NOTAVAIL, // TONE_SUP_RADIO_NOTAVAIL + TONE_SUP_ERROR, // TONE_SUP_ERROR + TONE_SUP_CALL_WAITING, // TONE_SUP_CALL_WAITING + TONE_TW_RINGTONE // TONE_SUP_RINGTONE } }; @@ -1010,6 +1025,8 @@ ToneGenerator::ToneGenerator(audio_stream_type_t streamType, float volume, bool mRegion = IRELAND; } else if (strstr(value, "in") != NULL) { mRegion = INDIA; + } else if (strstr(value, "tw") != NULL) { + mRegion = TAIWAN; } else { mRegion = CEPT; } diff --git a/media/libaudioclient/include/media/AudioEffect.h b/media/libaudioclient/include/media/AudioEffect.h index cb76252e34..3d4bb4ea3f 100644 --- a/media/libaudioclient/include/media/AudioEffect.h +++ b/media/libaudioclient/include/media/AudioEffect.h @@ -339,16 +339,21 @@ public: * * opPackageName: The package name used for app op checks. */ - AudioEffect(const String16& opPackageName); + explicit AudioEffect(const String16& opPackageName); + /* Terminates the AudioEffect and unregisters it from AudioFlinger. + * The effect engine is also destroyed if this AudioEffect was the last controlling + * the engine. + */ + ~AudioEffect(); - /* Constructor. + /** + * Initialize an uninitialized AudioEffect. * * Parameters: * * type: type of effect created: can be null if uuid is specified. This corresponds to * the OpenSL ES interface implemented by this effect. - * opPackageName: The package name used for app op checks. * uuid: Uuid of effect created: can be null if type is specified. This uuid corresponds to * a particular implementation of an effect type. * priority: requested priority for effect control: the priority level corresponds to the @@ -356,7 +361,7 @@ public: * higher priorities, 0 being the normal priority. * cbf: optional callback function (see effect_callback_t) * user: pointer to context for use by the callback receiver. - * sessionID: audio session this effect is associated to. + * sessionId: audio session this effect is associated to. * If equal to AUDIO_SESSION_OUTPUT_MIX, the effect will be global to * the output mix. Otherwise, the effect will be applied to all players * (AudioTrack or MediaPLayer) within the same audio session. @@ -369,46 +374,13 @@ public: * In this mode, no IEffect interface to AudioFlinger is created and all actions * besides getters implemented in client AudioEffect object are no ops * after effect creation. + * + * Returned status (from utils/Errors.h) can be: + * - NO_ERROR or ALREADY_EXISTS: successful initialization + * - INVALID_OPERATION: AudioEffect is already initialized + * - BAD_VALUE: invalid parameter + * - NO_INIT: audio flinger or audio hardware not initialized */ - - AudioEffect(const effect_uuid_t *type, - const String16& opPackageName, - const effect_uuid_t *uuid = NULL, - int32_t priority = 0, - effect_callback_t cbf = NULL, - void* user = NULL, - audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX, - audio_io_handle_t io = AUDIO_IO_HANDLE_NONE, - const AudioDeviceTypeAddr& device = {}, - bool probe = false); - - /* Constructor. - * Same as above but with type and uuid specified by character strings - */ - AudioEffect(const char *typeStr, - const String16& opPackageName, - const char *uuidStr = NULL, - int32_t priority = 0, - effect_callback_t cbf = NULL, - void* user = NULL, - audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX, - audio_io_handle_t io = AUDIO_IO_HANDLE_NONE, - const AudioDeviceTypeAddr& device = {}, - bool probe = false); - - /* Terminates the AudioEffect and unregisters it from AudioFlinger. - * The effect engine is also destroyed if this AudioEffect was the last controlling - * the engine. - */ - ~AudioEffect(); - - /* Initialize an uninitialized AudioEffect. - * Returned status (from utils/Errors.h) can be: - * - NO_ERROR or ALREADY_EXISTS: successful initialization - * - INVALID_OPERATION: AudioEffect is already initialized - * - BAD_VALUE: invalid parameter - * - NO_INIT: audio flinger or audio hardware not initialized - * */ status_t set(const effect_uuid_t *type, const effect_uuid_t *uuid = NULL, int32_t priority = 0, @@ -418,6 +390,18 @@ public: audio_io_handle_t io = AUDIO_IO_HANDLE_NONE, const AudioDeviceTypeAddr& device = {}, bool probe = false); + /* + * Same as above but with type and uuid specified by character strings. + */ + status_t set(const char *typeStr, + const char *uuidStr = NULL, + int32_t priority = 0, + effect_callback_t cbf = NULL, + void* user = NULL, + audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX, + audio_io_handle_t io = AUDIO_IO_HANDLE_NONE, + const AudioDeviceTypeAddr& device = {}, + bool probe = false); /* Result of constructing the AudioEffect. This must be checked * before using any AudioEffect API. @@ -547,21 +531,20 @@ public: static const uint32_t kMaxPreProcessing = 10; protected: - bool mEnabled; // enable state - audio_session_t mSessionId; // audio session ID - int32_t mPriority; // priority for effect control - status_t mStatus; // effect status - bool mProbe; // effect created in probe mode: all commands + const String16 mOpPackageName; // The package name used for app op checks. + bool mEnabled = false; // enable state + audio_session_t mSessionId = AUDIO_SESSION_OUTPUT_MIX; // audio session ID + int32_t mPriority = 0; // priority for effect control + status_t mStatus = NO_INIT; // effect status + bool mProbe = false; // effect created in probe mode: all commands // are no ops because mIEffect is NULL - effect_callback_t mCbf; // callback function for status, control and + effect_callback_t mCbf = nullptr; // callback function for status, control and // parameter changes notifications - void* mUserData; // client context for callback function - effect_descriptor_t mDescriptor; // effect descriptor - int32_t mId; // system wide unique effect engine instance ID + void* mUserData = nullptr;// client context for callback function + effect_descriptor_t mDescriptor = {}; // effect descriptor + int32_t mId = -1; // system wide unique effect engine instance ID Mutex mLock; // Mutex for mEnabled access - Mutex mConstructLock; // Mutex for integrality construction - String16 mOpPackageName; // The package name used for app op checks. // IEffectClient virtual void controlStatusChanged(bool controlGranted); @@ -586,22 +569,12 @@ private: virtual void controlStatusChanged(bool controlGranted) { sp<AudioEffect> effect = mEffect.promote(); if (effect != 0) { - { - // Got the mConstructLock means the construction of AudioEffect - // has finished, we should release the mConstructLock immediately. - AutoMutex lock(effect->mConstructLock); - } effect->controlStatusChanged(controlGranted); } } virtual void enableStatusChanged(bool enabled) { sp<AudioEffect> effect = mEffect.promote(); if (effect != 0) { - { - // Got the mConstructLock means the construction of AudioEffect - // has finished, we should release the mConstructLock immediately. - AutoMutex lock(effect->mConstructLock); - } effect->enableStatusChanged(enabled); } } @@ -612,11 +585,6 @@ private: void *pReplyData) { sp<AudioEffect> effect = mEffect.promote(); if (effect != 0) { - { - // Got the mConstructLock means the construction of AudioEffect - // has finished, we should release the mConstructLock immediately. - AutoMutex lock(effect->mConstructLock); - } effect->commandExecuted( cmdCode, cmdSize, pCmdData, replySize, pReplyData); } @@ -626,11 +594,6 @@ private: virtual void binderDied(const wp<IBinder>& /*who*/) { sp<AudioEffect> effect = mEffect.promote(); if (effect != 0) { - { - // Got the mConstructLock means the construction of AudioEffect - // has finished, we should release the mConstructLock immediately. - AutoMutex lock(effect->mConstructLock); - } effect->binderDied(); } } @@ -644,7 +607,7 @@ private: sp<IEffect> mIEffect; // IEffect binder interface sp<EffectClient> mIEffectClient; // IEffectClient implementation sp<IMemory> mCblkMemory; // shared memory for deferred parameter setting - effect_param_cblk_t* mCblk; // control block for deferred parameter setting + effect_param_cblk_t* mCblk = nullptr; // control block for deferred parameter setting pid_t mClientPid = (pid_t)-1; uid_t mClientUid = (uid_t)-1; }; diff --git a/media/libaudioclient/include/media/AudioSanitizer.h b/media/libaudioclient/include/media/AudioSanitizer.h new file mode 100644 index 0000000000..1475c7b3ee --- /dev/null +++ b/media/libaudioclient/include/media/AudioSanitizer.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_AUDIO_SANITIZER_H_ +#define ANDROID_AUDIO_SANITIZER_H_ + +#include <system/audio.h> +#include <system/audio_effect.h> +#include <utils/Errors.h> +#include <utils/Log.h> + +namespace android { + +class AudioSanitizer { +public: + static status_t sanitizeAudioAttributes( + audio_attributes_t *attr, const char *bugNumber = nullptr); + + static status_t sanitizeEffectDescriptor( + effect_descriptor_t *desc, const char *bugNumber = nullptr); + + static status_t sanitizeAudioPortConfig( + struct audio_port_config *config, const char *bugNumber = nullptr); + + static status_t sanitizeAudioPort( + struct audio_port *port, const char *bugNumber = nullptr); + + static status_t sanitizeAudioPatch( + struct audio_patch *patch, const char *bugNumber = nullptr); +}; + +}; // namespace android + +#endif /*ANDROID_AUDIO_SANITIZER_H_*/ diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h index 0dbd842d49..a9946da78c 100644 --- a/media/libaudioclient/include/media/AudioTrack.h +++ b/media/libaudioclient/include/media/AudioTrack.h @@ -26,6 +26,8 @@ #include <media/Modulo.h> #include <utils/threads.h> +#include <string> + #include "android/media/BnAudioTrackCallback.h" #include "android/media/IAudioTrackCallback.h" @@ -177,6 +179,8 @@ public: */ AudioTrack(); + AudioTrack(const std::string& opPackageName); + /* Creates an AudioTrack object and registers it with AudioFlinger. * Once created, the track needs to be started before it can be used. * Unspecified values are set to appropriate default values. @@ -258,7 +262,8 @@ public: const audio_attributes_t* pAttributes = NULL, bool doNotReconnect = false, float maxRequiredSpeed = 1.0f, - audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE); + audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE, + const std::string& opPackageName = ""); /* Creates an audio track and registers it with AudioFlinger. * With this constructor, the track is configured for static buffer mode. @@ -288,7 +293,8 @@ public: pid_t pid = -1, const audio_attributes_t* pAttributes = NULL, bool doNotReconnect = false, - float maxRequiredSpeed = 1.0f); + float maxRequiredSpeed = 1.0f, + const std::string& opPackageName = ""); /* Terminates the AudioTrack and unregisters it from AudioFlinger. * Also destroys all resources associated with the AudioTrack. @@ -1236,6 +1242,8 @@ public: sp<media::VolumeHandler> mVolumeHandler; + const std::string mOpPackageName; + private: class DeathNotifier : public IBinder::DeathRecipient { public: diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h index 612ce7a188..bcc11f4e78 100644 --- a/media/libaudioclient/include/media/IAudioFlinger.h +++ b/media/libaudioclient/include/media/IAudioFlinger.h @@ -37,6 +37,7 @@ #include <media/IEffectClient.h> #include <utils/String8.h> #include <media/MicrophoneInfo.h> +#include <string> #include <vector> #include "android/media/IAudioRecord.h" @@ -85,6 +86,11 @@ public: speed = parcel->readFloat(); audioTrackCallback = interface_cast<media::IAudioTrackCallback>( parcel->readStrongBinder()); + const char* opPackageNamePtr = parcel->readCString(); + if (opPackageNamePtr == nullptr) { + return FAILED_TRANSACTION; + } + opPackageName = opPackageNamePtr; /* input/output arguments*/ (void)parcel->read(&flags, sizeof(audio_output_flags_t)); @@ -109,6 +115,7 @@ public: (void)parcel->writeInt32(notificationsPerBuffer); (void)parcel->writeFloat(speed); (void)parcel->writeStrongBinder(IInterface::asBinder(audioTrackCallback)); + (void)parcel->writeCString(opPackageName.c_str()); /* input/output arguments*/ (void)parcel->write(&flags, sizeof(audio_output_flags_t)); @@ -127,6 +134,7 @@ public: uint32_t notificationsPerBuffer; float speed; sp<media::IAudioTrackCallback> audioTrackCallback; + std::string opPackageName; /* input/output */ audio_output_flags_t flags; diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h index bb1c07fff8..376c6eb6e6 100644 --- a/media/libaudioclient/include/media/IAudioPolicyService.h +++ b/media/libaudioclient/include/media/IAudioPolicyService.h @@ -266,10 +266,6 @@ public: const Parcel& data, Parcel* reply, uint32_t flags = 0); -private: - void sanetizeAudioAttributes(audio_attributes_t* attr); - status_t sanitizeEffectDescriptor(effect_descriptor_t* desc); - status_t sanitizeAudioPortConfig(struct audio_port_config* config); }; // ---------------------------------------------------------------------------- diff --git a/media/libaudioclient/include/media/ToneGenerator.h b/media/libaudioclient/include/media/ToneGenerator.h index 5b0689a924..04357a8482 100644 --- a/media/libaudioclient/include/media/ToneGenerator.h +++ b/media/libaudioclient/include/media/ToneGenerator.h @@ -218,6 +218,7 @@ private: TONE_INDIA_CONGESTION, // Congestion tone: 400 Hz, 250ms ON, 250ms OFF... TONE_INDIA_CALL_WAITING, // Call waiting tone: 400 Hz, tone repeated in a 0.2s on, 0.1s off, 0.2s on, 7.5s off pattern. TONE_INDIA_RINGTONE, // Ring tone: 400 Hz tone modulated with 25Hz, 0.4 on 0.2 off 0.4 on 2..0 off + TONE_TW_RINGTONE, // Ring Tone: 440 Hz + 480 Hz repeated with pattern 1s on, 3s off. NUM_ALTERNATE_TONES }; @@ -230,6 +231,7 @@ private: HONGKONG, IRELAND, INDIA, + TAIWAN, CEPT, NUM_REGIONS }; diff --git a/media/libaudioprocessing/AudioMixerOps.h b/media/libaudioprocessing/AudioMixerOps.h index 80bd093efd..8d374c95e5 100644 --- a/media/libaudioprocessing/AudioMixerOps.h +++ b/media/libaudioprocessing/AudioMixerOps.h @@ -234,17 +234,20 @@ void stereoVolumeHelper(TO*& out, const TI*& in, const TV *vol, F f) { static_assert(NCHAN > 0 && NCHAN <= 8); static_assert(MIXTYPE == MIXTYPE_MULTI_STEREOVOL || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL - || MIXTYPE == MIXTYPE_STEREOEXPAND); + || MIXTYPE == MIXTYPE_STEREOEXPAND + || MIXTYPE == MIXTYPE_MONOEXPAND); auto proc = [](auto& a, const auto& b) { if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL - || MIXTYPE == MIXTYPE_STEREOEXPAND) { + || MIXTYPE == MIXTYPE_STEREOEXPAND + || MIXTYPE == MIXTYPE_MONOEXPAND) { a += b; } else { a = b; } }; auto inp = [&in]() -> const TI& { - if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) { + if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND + || MIXTYPE == MIXTYPE_MONOEXPAND) { return *in; } else { return *in++; @@ -312,6 +315,8 @@ void stereoVolumeHelper(TO*& out, const TI*& in, const TV *vol, F f) { * TV/TAV: int32_t (U4.28) or int16_t (U4.12) or float * Input channel count is 1. * vol: represents volume array. + * This uses stereo balanced volume vol[0] and vol[1]. + * Before R, this was a full volume array but was called only for channels <= 2. * * This accumulates into the out pointer. * @@ -356,17 +361,13 @@ inline void volumeRampMulti(TO* out, size_t frameCount, do { TA auxaccum = 0; if constexpr (MIXTYPE == MIXTYPE_MULTI) { + static_assert(NCHAN <= 2); for (int i = 0; i < NCHAN; ++i) { *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum); vol[i] += volinc[i]; } - } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) { - for (int i = 0; i < NCHAN; ++i) { - *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum); - vol[i] += volinc[i]; - } - in++; } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) { + static_assert(NCHAN <= 2); for (int i = 0; i < NCHAN; ++i) { *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum); vol[i] += volinc[i]; @@ -383,11 +384,13 @@ inline void volumeRampMulti(TO* out, size_t frameCount, vol[0] += volinc[0]; } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL + || MIXTYPE == MIXTYPE_MONOEXPAND || MIXTYPE == MIXTYPE_STEREOEXPAND) { stereoVolumeHelper<MIXTYPE, NCHAN>( out, in, vol, [&auxaccum] (auto &a, const auto &b) { return MixMulAux<TO, TI, TV, TA>(a, b, &auxaccum); }); + if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) in += 1; if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2; vol[0] += volinc[0]; vol[1] += volinc[1]; @@ -401,17 +404,13 @@ inline void volumeRampMulti(TO* out, size_t frameCount, } else { do { if constexpr (MIXTYPE == MIXTYPE_MULTI) { + static_assert(NCHAN <= 2); for (int i = 0; i < NCHAN; ++i) { *out++ += MixMul<TO, TI, TV>(*in++, vol[i]); vol[i] += volinc[i]; } - } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) { - for (int i = 0; i < NCHAN; ++i) { - *out++ += MixMul<TO, TI, TV>(*in, vol[i]); - vol[i] += volinc[i]; - } - in++; } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) { + static_assert(NCHAN <= 2); for (int i = 0; i < NCHAN; ++i) { *out++ = MixMul<TO, TI, TV>(*in++, vol[i]); vol[i] += volinc[i]; @@ -428,10 +427,12 @@ inline void volumeRampMulti(TO* out, size_t frameCount, vol[0] += volinc[0]; } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL + || MIXTYPE == MIXTYPE_MONOEXPAND || MIXTYPE == MIXTYPE_STEREOEXPAND) { stereoVolumeHelper<MIXTYPE, NCHAN>(out, in, vol, [] (auto &a, const auto &b) { return MixMul<TO, TI, TV>(a, b); }); + if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) in += 1; if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2; vol[0] += volinc[0]; vol[1] += volinc[1]; @@ -454,15 +455,12 @@ inline void volumeMulti(TO* out, size_t frameCount, do { TA auxaccum = 0; if constexpr (MIXTYPE == MIXTYPE_MULTI) { + static_assert(NCHAN <= 2); for (int i = 0; i < NCHAN; ++i) { *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum); } - } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) { - for (int i = 0; i < NCHAN; ++i) { - *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum); - } - in++; } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) { + static_assert(NCHAN <= 2); for (int i = 0; i < NCHAN; ++i) { *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum); } @@ -476,11 +474,13 @@ inline void volumeMulti(TO* out, size_t frameCount, } } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL + || MIXTYPE == MIXTYPE_MONOEXPAND || MIXTYPE == MIXTYPE_STEREOEXPAND) { stereoVolumeHelper<MIXTYPE, NCHAN>( out, in, vol, [&auxaccum] (auto &a, const auto &b) { return MixMulAux<TO, TI, TV, TA>(a, b, &auxaccum); }); + if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) in += 1; if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2; } else /* constexpr */ { static_assert(dependent_false<MIXTYPE>, "invalid mixtype"); @@ -490,16 +490,14 @@ inline void volumeMulti(TO* out, size_t frameCount, } while (--frameCount); } else { do { + // ALOGD("Mixtype:%d NCHAN:%d", MIXTYPE, NCHAN); if constexpr (MIXTYPE == MIXTYPE_MULTI) { + static_assert(NCHAN <= 2); for (int i = 0; i < NCHAN; ++i) { *out++ += MixMul<TO, TI, TV>(*in++, vol[i]); } - } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) { - for (int i = 0; i < NCHAN; ++i) { - *out++ += MixMul<TO, TI, TV>(*in, vol[i]); - } - in++; } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) { + static_assert(NCHAN <= 2); for (int i = 0; i < NCHAN; ++i) { *out++ = MixMul<TO, TI, TV>(*in++, vol[i]); } @@ -513,10 +511,12 @@ inline void volumeMulti(TO* out, size_t frameCount, } } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL + || MIXTYPE == MIXTYPE_MONOEXPAND || MIXTYPE == MIXTYPE_STEREOEXPAND) { stereoVolumeHelper<MIXTYPE, NCHAN>(out, in, vol, [] (auto &a, const auto &b) { return MixMul<TO, TI, TV>(a, b); }); + if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) in += 1; if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2; } else /* constexpr */ { static_assert(dependent_false<MIXTYPE>, "invalid mixtype"); diff --git a/media/libaudioprocessing/tests/mixerops_benchmark.cpp b/media/libaudioprocessing/tests/mixerops_benchmark.cpp index 86f5429248..7a4c5c706f 100644 --- a/media/libaudioprocessing/tests/mixerops_benchmark.cpp +++ b/media/libaudioprocessing/tests/mixerops_benchmark.cpp @@ -74,28 +74,32 @@ static void BM_VolumeMulti(benchmark::State& state) { } } -BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI, 2); -BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY, 2); +// MULTI mode and MULTI_SAVEONLY mode are not used by AudioMixer for channels > 2, +// which is ensured by a static_assert (won't compile for those configurations). +// So we benchmark MIXTYPE_MULTI_MONOVOL and MIXTYPE_MULTI_SAVEONLY_MONOVOL compared +// with MIXTYPE_MULTI_STEREOVOL and MIXTYPE_MULTI_SAVEONLY_STEREOVOL. +BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_MONOVOL, 2); +BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_MONOVOL, 2); BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_STEREOVOL, 2); BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 2); -BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI, 4); -BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY, 4); +BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_MONOVOL, 4); +BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_MONOVOL, 4); BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_STEREOVOL, 4); BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 4); -BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI, 5); -BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY, 5); +BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_MONOVOL, 5); +BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_MONOVOL, 5); BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_STEREOVOL, 5); BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 5); -BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI, 8); -BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY, 8); +BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_MONOVOL, 8); +BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_MONOVOL, 8); BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_STEREOVOL, 8); BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 8); -BENCHMARK_TEMPLATE(BM_VolumeMulti, MIXTYPE_MULTI, 8); -BENCHMARK_TEMPLATE(BM_VolumeMulti, MIXTYPE_MULTI_SAVEONLY, 8); +BENCHMARK_TEMPLATE(BM_VolumeMulti, MIXTYPE_MULTI_MONOVOL, 8); +BENCHMARK_TEMPLATE(BM_VolumeMulti, MIXTYPE_MULTI_SAVEONLY_MONOVOL, 8); BENCHMARK_TEMPLATE(BM_VolumeMulti, MIXTYPE_MULTI_STEREOVOL, 8); BENCHMARK_TEMPLATE(BM_VolumeMulti, MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 8); diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp index 39caf53004..7ed76d8b20 100644 --- a/media/libmedia/IMediaExtractor.cpp +++ b/media/libmedia/IMediaExtractor.cpp @@ -38,7 +38,8 @@ enum { FLAGS, SETMEDIACAS, NAME, - GETMETRICS + GETMETRICS, + SETENTRYPOINT }; class BpMediaExtractor : public BpInterface<IMediaExtractor> { @@ -142,6 +143,13 @@ public: } return nm; } + + virtual status_t setEntryPoint(EntryPoint entryPoint) { + Parcel data, reply; + data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor()); + data.writeInt32(static_cast<int32_t>(entryPoint)); + return remote()->transact(SETENTRYPOINT, data, &reply); + } }; IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor"); @@ -232,6 +240,16 @@ status_t BnMediaExtractor::onTransact( reply->writeString8(nm); return NO_ERROR; } + case SETENTRYPOINT: { + ALOGV("setEntryPoint"); + CHECK_INTERFACE(IMediaExtractor, data, reply); + int32_t entryPoint; + status_t err = data.readInt32(&entryPoint); + if (err == OK) { + setEntryPoint(EntryPoint(entryPoint)); + } + return err; + } default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp index bd18a40d63..11005c6cdf 100644 --- a/media/libmedia/IMediaPlayerService.cpp +++ b/media/libmedia/IMediaPlayerService.cpp @@ -62,11 +62,13 @@ public: } virtual sp<IMediaPlayer> create( - const sp<IMediaPlayerClient>& client, audio_session_t audioSessionId) { + const sp<IMediaPlayerClient>& client, audio_session_t audioSessionId, + const std::string opPackageName) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); data.writeStrongBinder(IInterface::asBinder(client)); data.writeInt32(audioSessionId); + data.writeCString(opPackageName.c_str()); remote()->transact(CREATE, data, &reply); return interface_cast<IMediaPlayer>(reply.readStrongBinder()); @@ -127,7 +129,12 @@ status_t BnMediaPlayerService::onTransact( sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder()); audio_session_t audioSessionId = (audio_session_t) data.readInt32(); - sp<IMediaPlayer> player = create(client, audioSessionId); + const char* opPackageName = data.readCString(); + if (opPackageName == nullptr) { + return FAILED_TRANSACTION; + } + std::string opPackageNameStr(opPackageName); + sp<IMediaPlayer> player = create(client, audioSessionId, opPackageNameStr); reply->writeStrongBinder(IInterface::asBinder(player)); return NO_ERROR; } break; diff --git a/media/libmedia/aidl/android/media/IResourceManagerService.aidl b/media/libmedia/aidl/android/media/IResourceManagerService.aidl index 1b2d522700..621bd84059 100644 --- a/media/libmedia/aidl/android/media/IResourceManagerService.aidl +++ b/media/libmedia/aidl/android/media/IResourceManagerService.aidl @@ -102,4 +102,11 @@ interface IResourceManagerService { * @param clientId clientId within the pid that will be removed. */ void markClientForPendingRemoval(int pid, long clientId); + + /** + * Reclaim resources from clients pending removal, if any. + * + * @param pid pid from which resources will be reclaimed. + */ + void reclaimResourcesFromClientsPendingRemoval(int pid); } diff --git a/media/libmedia/include/android/IMediaExtractor.h b/media/libmedia/include/android/IMediaExtractor.h index 3e035ad304..f9cafdeafd 100644 --- a/media/libmedia/include/android/IMediaExtractor.h +++ b/media/libmedia/include/android/IMediaExtractor.h @@ -63,6 +63,15 @@ public: virtual status_t setMediaCas(const HInterfaceToken &casToken) = 0; virtual String8 name() = 0; + + enum class EntryPoint { + SDK = 1, + NDK_WITH_JVM = 2, + NDK_NO_JVM = 3, + OTHER = 4, + }; + + virtual status_t setEntryPoint(EntryPoint entryPoint) = 0; }; diff --git a/media/libmedia/include/media/IMediaPlayerService.h b/media/libmedia/include/media/IMediaPlayerService.h index f2e2060349..a4207eb533 100644 --- a/media/libmedia/include/media/IMediaPlayerService.h +++ b/media/libmedia/include/media/IMediaPlayerService.h @@ -28,6 +28,8 @@ #include <media/IMediaPlayerClient.h> #include <media/IMediaMetadataRetriever.h> +#include <string> + namespace android { class IMediaPlayer; @@ -47,7 +49,8 @@ public: virtual sp<IMediaRecorder> createMediaRecorder(const String16 &opPackageName) = 0; virtual sp<IMediaMetadataRetriever> createMetadataRetriever() = 0; virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client, - audio_session_t audioSessionId = AUDIO_SESSION_ALLOCATE) = 0; + audio_session_t audioSessionId = AUDIO_SESSION_ALLOCATE, + const std::string opPackage = "") = 0; virtual sp<IMediaCodecList> getCodecList() const = 0; // Connects to a remote display. diff --git a/media/libmedia/include/media/mediaplayer.h b/media/libmedia/include/media/mediaplayer.h index 2335c5a255..7c29e50d8c 100644 --- a/media/libmedia/include/media/mediaplayer.h +++ b/media/libmedia/include/media/mediaplayer.h @@ -33,6 +33,8 @@ #include <utils/KeyedVector.h> #include <utils/String8.h> +#include <string> + struct ANativeWindow; namespace android { @@ -205,7 +207,7 @@ class MediaPlayer : public BnMediaPlayerClient, public virtual IMediaDeathNotifier { public: - MediaPlayer(); + MediaPlayer(const std::string opPackageName = ""); ~MediaPlayer(); void died(); void disconnect(); @@ -308,6 +310,7 @@ private: float mSendLevel; struct sockaddr_in mRetransmitEndpoint; bool mRetransmitEndpointValid; + const std::string mOpPackageName; }; }; // namespace android diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 1fadc94570..6079a2dbe1 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -41,7 +41,7 @@ namespace android { using media::VolumeShaper; -MediaPlayer::MediaPlayer() +MediaPlayer::MediaPlayer(const std::string opPackageName) : mOpPackageName(opPackageName) { ALOGV("constructor"); mListener = NULL; @@ -152,7 +152,7 @@ status_t MediaPlayer::setDataSource( if (url != NULL) { const sp<IMediaPlayerService> service(getMediaPlayerService()); if (service != 0) { - sp<IMediaPlayer> player(service->create(this, mAudioSessionId)); + sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName)); if ((NO_ERROR != doSetRetransmitEndpoint(player)) || (NO_ERROR != player->setDataSource(httpService, url, headers))) { player.clear(); @@ -169,7 +169,7 @@ status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length) status_t err = UNKNOWN_ERROR; const sp<IMediaPlayerService> service(getMediaPlayerService()); if (service != 0) { - sp<IMediaPlayer> player(service->create(this, mAudioSessionId)); + sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName)); if ((NO_ERROR != doSetRetransmitEndpoint(player)) || (NO_ERROR != player->setDataSource(fd, offset, length))) { player.clear(); @@ -185,7 +185,7 @@ status_t MediaPlayer::setDataSource(const sp<IDataSource> &source) status_t err = UNKNOWN_ERROR; const sp<IMediaPlayerService> service(getMediaPlayerService()); if (service != 0) { - sp<IMediaPlayer> player(service->create(this, mAudioSessionId)); + sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName)); if ((NO_ERROR != doSetRetransmitEndpoint(player)) || (NO_ERROR != player->setDataSource(source))) { player.clear(); diff --git a/media/libmediahelper/Android.bp b/media/libmediahelper/Android.bp index 6fcbc7bb49..fbe7f8764f 100644 --- a/media/libmediahelper/Android.bp +++ b/media/libmediahelper/Android.bp @@ -12,7 +12,10 @@ cc_library { enabled: true, }, double_loadable: true, - srcs: ["AudioParameter.cpp", "TypeConverter.cpp"], + srcs: [ + "AudioParameter.cpp", + "TypeConverter.cpp", + ], cflags: [ "-Werror", "-Wextra", diff --git a/media/libmediametrics/Android.bp b/media/libmediametrics/Android.bp index 03068c7fb0..a63b8b4339 100644 --- a/media/libmediametrics/Android.bp +++ b/media/libmediametrics/Android.bp @@ -53,6 +53,7 @@ cc_library_shared { visibility: [ "//cts/tests/tests/nativemedia/mediametrics", "//frameworks/av:__subpackages__", + "//frameworks/base/apex/media/framework", "//frameworks/base/core/jni", "//frameworks/base/media/jni", ], diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index c0da0ce3b2..016f622fb2 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -480,14 +480,14 @@ sp<IMediaMetadataRetriever> MediaPlayerService::createMetadataRetriever() } sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client, - audio_session_t audioSessionId) + audio_session_t audioSessionId, std::string opPackageName) { pid_t pid = IPCThreadState::self()->getCallingPid(); int32_t connId = android_atomic_inc(&mNextConnId); sp<Client> c = new Client( this, pid, connId, client, audioSessionId, - IPCThreadState::self()->getCallingUid()); + IPCThreadState::self()->getCallingUid(), opPackageName); ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid, IPCThreadState::self()->getCallingUid()); @@ -733,7 +733,8 @@ bool MediaPlayerService::hasClient(wp<Client> client) MediaPlayerService::Client::Client( const sp<MediaPlayerService>& service, pid_t pid, int32_t connId, const sp<IMediaPlayerClient>& client, - audio_session_t audioSessionId, uid_t uid) + audio_session_t audioSessionId, uid_t uid, const std::string& opPackageName) + : mOpPackageName(opPackageName) { ALOGV("Client(%d) constructor", connId); mPid = pid; @@ -922,7 +923,7 @@ sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre( if (!p->hardwareOutput()) { mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(), - mPid, mAudioAttributes, mAudioDeviceUpdatedListener); + mPid, mAudioAttributes, mAudioDeviceUpdatedListener, mOpPackageName); static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput); } @@ -1761,7 +1762,8 @@ int Antagonizer::callbackThread(void* user) #undef LOG_TAG #define LOG_TAG "AudioSink" MediaPlayerService::AudioOutput::AudioOutput(audio_session_t sessionId, uid_t uid, int pid, - const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback) + const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback, + const std::string& opPackageName) : mCallback(NULL), mCallbackCookie(NULL), mCallbackData(NULL), @@ -1782,7 +1784,8 @@ MediaPlayerService::AudioOutput::AudioOutput(audio_session_t sessionId, uid_t ui mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE), mDeviceCallbackEnabled(false), - mDeviceCallback(deviceCallback) + mDeviceCallback(deviceCallback), + mOpPackageName(opPackageName) { ALOGV("AudioOutput(%d)", sessionId); if (attr != NULL) { @@ -2176,7 +2179,8 @@ status_t MediaPlayerService::AudioOutput::open( mAttributes, doNotReconnect, 1.0f, // default value for maxRequiredSpeed - mSelectedDeviceId); + mSelectedDeviceId, + mOpPackageName); } else { // TODO: Due to buffer memory concerns, we use a max target playback speed // based on mPlaybackRate at the time of open (instead of kMaxRequiredSpeed), @@ -2204,7 +2208,8 @@ status_t MediaPlayerService::AudioOutput::open( mAttributes, doNotReconnect, targetSpeed, - mSelectedDeviceId); + mSelectedDeviceId, + mOpPackageName); } // Set caller name so it can be logged in destructor. // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_MEDIA diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 6431ca1d04..a7de3f3bbf 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -19,6 +19,7 @@ #define ANDROID_MEDIAPLAYERSERVICE_H #include <arpa/inet.h> +#include <string> #include <utils/threads.h> #include <utils/Errors.h> @@ -81,7 +82,8 @@ class MediaPlayerService : public BnMediaPlayerService uid_t uid, int pid, const audio_attributes_t * attr, - const sp<AudioSystem::AudioDeviceCallback>& deviceCallback); + const sp<AudioSystem::AudioDeviceCallback>& deviceCallback, + const std::string& opPackageName); virtual ~AudioOutput(); virtual bool ready() const { return mTrack != 0; } @@ -178,6 +180,7 @@ class MediaPlayerService : public BnMediaPlayerService bool mDeviceCallbackEnabled; wp<AudioSystem::AudioDeviceCallback> mDeviceCallback; mutable Mutex mLock; + const std::string mOpPackageName; // static variables below not protected by mutex static bool mIsOnEmulator; @@ -235,7 +238,8 @@ public: virtual sp<IMediaMetadataRetriever> createMetadataRetriever(); virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client, - audio_session_t audioSessionId); + audio_session_t audioSessionId, + const std::string opPackageName); virtual sp<IMediaCodecList> getCodecList() const; @@ -410,7 +414,8 @@ private: int32_t connId, const sp<IMediaPlayerClient>& client, audio_session_t audioSessionId, - uid_t uid); + uid_t uid, + const std::string& opPackageName); Client(); virtual ~Client(); @@ -467,6 +472,7 @@ private: bool mRetransmitEndpointValid; sp<Client> mNextClient; sp<MediaPlayerBase::Listener> mListener; + const std::string mOpPackageName; // Metadata filters. media::Metadata::Filter mMetadataAllow; // protected by mLock diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp index 9b1974b09a..1cc255d802 100644 --- a/media/libmediaplayerservice/MediaRecorderClient.cpp +++ b/media/libmediaplayerservice/MediaRecorderClient.cpp @@ -28,6 +28,7 @@ #include <binder/IServiceManager.h> #include <binder/MemoryHeapBase.h> #include <binder/MemoryBase.h> +#include <camera/CameraUtils.h> #include <codec2/hidl/client.h> #include <cutils/atomic.h> #include <cutils/properties.h> // for property_get @@ -423,30 +424,35 @@ status_t MediaRecorderClient::setListener(const sp<IMediaRecorderClient>& listen sp<IServiceManager> sm = defaultServiceManager(); - // WORKAROUND: We don't know if camera exists here and getService might block for 5 seconds. - // Use checkService for camera if we don't know it exists. - static std::atomic<bool> sCameraChecked(false); // once true never becomes false. - static std::atomic<bool> sCameraVerified(false); // once true never becomes false. - sp<IBinder> binder = (sCameraVerified || !sCameraChecked) - ? sm->getService(String16("media.camera")) : sm->checkService(String16("media.camera")); - // If the device does not have a camera, do not create a death listener for it. - if (binder != NULL) { - sCameraVerified = true; - mDeathNotifiers.emplace_back( - binder, [l = wp<IMediaRecorderClient>(listener)](){ - sp<IMediaRecorderClient> listener = l.promote(); - if (listener) { - ALOGV("media.camera service died. " - "Sending death notification."); - listener->notify( - MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, - MediaPlayerService::CAMERA_PROCESS_DEATH); - } else { - ALOGW("media.camera service died without a death handler."); - } - }); + static const bool sCameraDisabled = CameraUtils::isCameraServiceDisabled(); + + if (!sCameraDisabled) { + // WORKAROUND: We don't know if camera exists here and getService might block for 5 seconds. + // Use checkService for camera if we don't know it exists. + static std::atomic<bool> sCameraChecked(false); // once true never becomes false. + static std::atomic<bool> sCameraVerified(false); // once true never becomes false. + + sp<IBinder> binder = (sCameraVerified || !sCameraChecked) + ? sm->getService(String16("media.camera")) : sm->checkService(String16("media.camera")); + // If the device does not have a camera, do not create a death listener for it. + if (binder != NULL) { + sCameraVerified = true; + mDeathNotifiers.emplace_back( + binder, [l = wp<IMediaRecorderClient>(listener)](){ + sp<IMediaRecorderClient> listener = l.promote(); + if (listener) { + ALOGV("media.camera service died. " + "Sending death notification."); + listener->notify( + MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, + MediaPlayerService::CAMERA_PROCESS_DEATH); + } else { + ALOGW("media.camera service died without a death handler."); + } + }); + } + sCameraChecked = true; } - sCameraChecked = true; { using ::android::hidl::base::V1_0::IBase; diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp index 83da092506..9533ae5279 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp @@ -146,7 +146,9 @@ void NuPlayer::RTSPSource::stop() { } // Close socket before posting message to RTSPSource message handler. - close(mHandler->getARTSPConnection()->getSocket()); + if (mHandler != NULL) { + close(mHandler->getARTSPConnection()->getSocket()); + } sp<AMessage> msg = new AMessage(kWhatDisconnect, this); diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 63ab6548b4..8e480bff14 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -5283,6 +5283,34 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> ¬ify) { if (mChannelMaskPresent) { notify->setInt32("channel-mask", mChannelMask); } + + if (!mIsEncoder && portIndex == kPortIndexOutput) { + AString mime; + if (mConfigFormat->findString("mime", &mime) + && !strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime.c_str())) { + + OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE presentation; + InitOMXParams(&presentation); + err = mOMXNode->getParameter( + (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAacDrcPresentation, + &presentation, sizeof(presentation)); + if (err != OK) { + return err; + } + notify->setInt32("aac-encoded-target-level", + presentation.nEncodedTargetLevel); + notify->setInt32("aac-drc-cut-level", presentation.nDrcCut); + notify->setInt32("aac-drc-boost-level", presentation.nDrcBoost); + notify->setInt32("aac-drc-heavy-compression", + presentation.nHeavyCompression); + notify->setInt32("aac-target-ref-level", + presentation.nTargetReferenceLevel); + notify->setInt32("aac-drc-effect-type", presentation.nDrcEffectType); + notify->setInt32("aac-drc-album-mode", presentation.nDrcAlbumMode); + notify->setInt32("aac-drc-output-loudness", + presentation.nDrcOutputLoudness); + } + } break; } @@ -6947,10 +6975,9 @@ status_t ACodec::LoadedState::setupInputSurface() { return err; } - using hardware::media::omx::V1_0::utils::TWOmxNode; err = statusFromBinderStatus( mCodec->mGraphicBufferSource->configure( - new TWOmxNode(mCodec->mOMXNode), + mCodec->mOMXNode->getHalInterface<IOmxNode>(), static_cast<hardware::graphics::common::V1_0::Dataspace>(dataSpace))); if (err != OK) { ALOGE("[%s] Unable to configure for node (err %d)", @@ -7704,6 +7731,58 @@ status_t ACodec::setParameters(const sp<AMessage> ¶ms) { // Ignore errors as failure is expected for codecs that aren't video encoders. (void)configureTemporalLayers(params, false /* inConfigure */, mOutputFormat); + AString mime; + if (!mIsEncoder + && (mConfigFormat->findString("mime", &mime)) + && !strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime.c_str())) { + OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE presentation; + InitOMXParams(&presentation); + mOMXNode->getParameter( + (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAacDrcPresentation, + &presentation, sizeof(presentation)); + int32_t value32 = 0; + bool updated = false; + if (params->findInt32("aac-pcm-limiter-enable", &value32)) { + presentation.nPCMLimiterEnable = value32; + updated = true; + } + if (params->findInt32("aac-encoded-target-level", &value32)) { + presentation.nEncodedTargetLevel = value32; + updated = true; + } + if (params->findInt32("aac-drc-cut-level", &value32)) { + presentation.nDrcCut = value32; + updated = true; + } + if (params->findInt32("aac-drc-boost-level", &value32)) { + presentation.nDrcBoost = value32; + updated = true; + } + if (params->findInt32("aac-drc-heavy-compression", &value32)) { + presentation.nHeavyCompression = value32; + updated = true; + } + if (params->findInt32("aac-target-ref-level", &value32)) { + presentation.nTargetReferenceLevel = value32; + updated = true; + } + if (params->findInt32("aac-drc-effect-type", &value32)) { + presentation.nDrcEffectType = value32; + updated = true; + } + if (params->findInt32("aac-drc-album-mode", &value32)) { + presentation.nDrcAlbumMode = value32; + updated = true; + } + if (!params->findInt32("aac-drc-output-loudness", &value32)) { + presentation.nDrcOutputLoudness = value32; + updated = true; + } + if (updated) { + mOMXNode->setParameter((OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAacDrcPresentation, + &presentation, sizeof(presentation)); + } + } return setVendorParameters(params); } diff --git a/media/libstagefright/FrameCaptureProcessor.cpp b/media/libstagefright/FrameCaptureProcessor.cpp index 96c1195cc6..63238bc921 100644 --- a/media/libstagefright/FrameCaptureProcessor.cpp +++ b/media/libstagefright/FrameCaptureProcessor.cpp @@ -171,6 +171,8 @@ status_t FrameCaptureProcessor::onCapture(const sp<Layer> &layer, if (err != OK) { ALOGW("wait for fence returned err %d", err); } + + mRE->cleanupPostRender(renderengine::RenderEngine::CleanupMode::CLEAN_ALL); return OK; } diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 8f7d4bf0d0..d99596e3f1 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -2774,7 +2774,7 @@ status_t MPEG4Writer::Track::start(MetaData *params) { // even if the file is well-formed and the primary picture is correct. // Reserve item ids for samples + grid - size_t numItemsToReserve = mNumTiles + (mNumTiles > 1); + size_t numItemsToReserve = mNumTiles + (mNumTiles > 0); status_t err = mOwner->reserveItemId_l(numItemsToReserve, &mItemIdBase); if (err != OK) { return err; diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 40d8ba25e4..553f59a41f 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -258,6 +258,9 @@ void MediaCodec::ResourceManagerServiceProxy::init() { // after this, require mLock whenever using mService AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this); + + // Kill clients pending removal. + mService->reclaimResourcesFromClientsPendingRemoval(mPid); } //static @@ -651,7 +654,10 @@ sp<PersistentSurface> MediaCodec::CreatePersistentInputSurface() { return new PersistentSurface(bufferProducer, bufferSource); } -MediaCodec::MediaCodec(const sp<ALooper> &looper, pid_t pid, uid_t uid) +MediaCodec::MediaCodec( + const sp<ALooper> &looper, pid_t pid, uid_t uid, + std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase, + std::function<status_t(const AString &, sp<MediaCodecInfo> *)> getCodecInfo) : mState(UNINITIALIZED), mReleasedByResourceManager(false), mLooper(looper), @@ -676,7 +682,9 @@ MediaCodec::MediaCodec(const sp<ALooper> &looper, pid_t pid, uid_t uid) mNumLowLatencyDisables(0), mIsLowLatencyModeOn(false), mIndexOfFirstFrameWhenLowLatencyOn(-1), - mInputBufferCounter(0) { + mInputBufferCounter(0), + mGetCodecBase(getCodecBase), + mGetCodecInfo(getCodecInfo) { if (uid == kNoUid) { mUid = AIBinder_getCallingUid(); } else { @@ -684,6 +692,33 @@ MediaCodec::MediaCodec(const sp<ALooper> &looper, pid_t pid, uid_t uid) } mResourceManagerProxy = new ResourceManagerServiceProxy(pid, mUid, ::ndk::SharedRefBase::make<ResourceManagerClient>(this)); + if (!mGetCodecBase) { + mGetCodecBase = [](const AString &name, const char *owner) { + return GetCodecBase(name, owner); + }; + } + if (!mGetCodecInfo) { + mGetCodecInfo = [](const AString &name, sp<MediaCodecInfo> *info) -> status_t { + *info = nullptr; + const sp<IMediaCodecList> mcl = MediaCodecList::getInstance(); + if (!mcl) { + return NO_INIT; // if called from Java should raise IOException + } + AString tmp = name; + if (tmp.endsWith(".secure")) { + tmp.erase(tmp.size() - 7, 7); + } + for (const AString &codecName : { name, tmp }) { + ssize_t codecIdx = mcl->findCodecByName(codecName.c_str()); + if (codecIdx < 0) { + continue; + } + *info = mcl->getCodecInfo(codecIdx); + return OK; + } + return NAME_NOT_FOUND; + }; + } initMediametrics(); } @@ -1045,6 +1080,12 @@ status_t MediaCodec::PostAndAwaitResponse( return err; } +void MediaCodec::PostReplyWithError(const sp<AMessage> &msg, int32_t err) { + sp<AReplyToken> replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + PostReplyWithError(replyID, err); +} + void MediaCodec::PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err) { int32_t finalErr = err; if (mReleasedByResourceManager) { @@ -1121,40 +1162,30 @@ status_t MediaCodec::init(const AString &name) { bool secureCodec = false; const char *owner = ""; if (!name.startsWith("android.filter.")) { - AString tmp = name; - if (tmp.endsWith(".secure")) { - secureCodec = true; - tmp.erase(tmp.size() - 7, 7); - } - const sp<IMediaCodecList> mcl = MediaCodecList::getInstance(); - if (mcl == NULL) { + status_t err = mGetCodecInfo(name, &mCodecInfo); + if (err != OK) { mCodec = NULL; // remove the codec. - return NO_INIT; // if called from Java should raise IOException - } - for (const AString &codecName : { name, tmp }) { - ssize_t codecIdx = mcl->findCodecByName(codecName.c_str()); - if (codecIdx < 0) { - continue; - } - mCodecInfo = mcl->getCodecInfo(codecIdx); - Vector<AString> mediaTypes; - mCodecInfo->getSupportedMediaTypes(&mediaTypes); - for (size_t i = 0; i < mediaTypes.size(); i++) { - if (mediaTypes[i].startsWith("video/")) { - mIsVideo = true; - break; - } - } - break; + return err; } if (mCodecInfo == nullptr) { + ALOGE("Getting codec info with name '%s' failed", name.c_str()); return NAME_NOT_FOUND; } + secureCodec = name.endsWith(".secure"); + Vector<AString> mediaTypes; + mCodecInfo->getSupportedMediaTypes(&mediaTypes); + for (size_t i = 0; i < mediaTypes.size(); ++i) { + if (mediaTypes[i].startsWith("video/")) { + mIsVideo = true; + break; + } + } owner = mCodecInfo->getOwnerName(); } - mCodec = GetCodecBase(name, owner); + mCodec = mGetCodecBase(name, owner); if (mCodec == NULL) { + ALOGE("Getting codec base with name '%s' (owner='%s') failed", name.c_str(), owner); return NAME_NOT_FOUND; } @@ -1548,7 +1579,6 @@ status_t MediaCodec::reset() { mStickyError = OK; // reset state not reset by setState(UNINITIALIZED) - mReplyID = 0; mDequeueInputReplyID = 0; mDequeueOutputReplyID = 0; mDequeueInputTimeoutGeneration = 0; @@ -2080,20 +2110,25 @@ bool MediaCodec::handleDequeueOutputBuffer(const sp<AReplyToken> &replyID, bool } else if (mFlags & kFlagOutputBuffersChanged) { PostReplyWithError(replyID, INFO_OUTPUT_BUFFERS_CHANGED); mFlags &= ~kFlagOutputBuffersChanged; - } else if (mFlags & kFlagOutputFormatChanged) { - PostReplyWithError(replyID, INFO_FORMAT_CHANGED); - mFlags &= ~kFlagOutputFormatChanged; } else { sp<AMessage> response = new AMessage; - ssize_t index = dequeuePortBuffer(kPortIndexOutput); - - if (index < 0) { - CHECK_EQ(index, -EAGAIN); + BufferInfo *info = peekNextPortBuffer(kPortIndexOutput); + if (!info) { return false; } - const sp<MediaCodecBuffer> &buffer = - mPortBuffers[kPortIndexOutput][index].mData; + // In synchronous mode, output format change should be handled + // at dequeue to put the event at the correct order. + + const sp<MediaCodecBuffer> &buffer = info->mData; + handleOutputFormatChangeIfNeeded(buffer); + if (mFlags & kFlagOutputFormatChanged) { + PostReplyWithError(replyID, INFO_FORMAT_CHANGED); + mFlags &= ~kFlagOutputFormatChanged; + return true; + } + + ssize_t index = dequeuePortBuffer(kPortIndexOutput); response->setSize("index", index); response->setSize("offset", buffer->offset()); @@ -2138,6 +2173,8 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { } bool sendErrorResponse = true; + std::string origin{"kWhatError:"}; + origin += stateString(mState); switch (mState) { case INITIALIZING: @@ -2189,14 +2226,14 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { // be a shutdown complete notification after // all. - // note that we're directly going from + // note that we may be directly going from // STOPPING->UNINITIALIZED, instead of the // usual STOPPING->INITIALIZED state. setState(UNINITIALIZED); if (mState == RELEASING) { mComponentName.clear(); } - (new AMessage)->postReply(mReplyID); + postPendingRepliesAndDeferredMessages(origin + ":dead"); sendErrorResponse = false; } break; @@ -2222,7 +2259,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case FLUSHED: case STARTED: { - sendErrorResponse = false; + sendErrorResponse = (mReplyID != nullptr); setStickyError(err); postActivityNotificationIfPossible(); @@ -2252,7 +2289,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { default: { - sendErrorResponse = false; + sendErrorResponse = (mReplyID != nullptr); setStickyError(err); postActivityNotificationIfPossible(); @@ -2279,7 +2316,15 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { } if (sendErrorResponse) { - PostReplyWithError(mReplyID, err); + // TRICKY: replicate PostReplyWithError logic for + // err code override + int32_t finalErr = err; + if (mReleasedByResourceManager) { + // override the err code if MediaCodec has been + // released by ResourceManager. + finalErr = DEAD_OBJECT; + } + postPendingRepliesAndDeferredMessages(origin, finalErr); } break; } @@ -2327,7 +2372,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo)); } - (new AMessage)->postReply(mReplyID); + postPendingRepliesAndDeferredMessages("kWhatComponentAllocated"); break; } @@ -2366,7 +2411,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { mFlags |= kFlagUsesSoftwareRenderer; } setState(CONFIGURED); - (new AMessage)->postReply(mReplyID); + postPendingRepliesAndDeferredMessages("kWhatComponentConfigured"); // augment our media metrics info, now that we know more things // such as what the codec extracted from any CSD passed in. @@ -2411,6 +2456,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatInputSurfaceCreated: { + if (mState != CONFIGURED) { + // state transitioned unexpectedly; we should have replied already. + ALOGD("received kWhatInputSurfaceCreated message in state %s", + stateString(mState).c_str()); + break; + } // response to initiateCreateInputSurface() status_t err = NO_ERROR; sp<AMessage> response = new AMessage; @@ -2429,12 +2480,18 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { } else { response->setInt32("err", err); } - response->postReply(mReplyID); + postPendingRepliesAndDeferredMessages("kWhatInputSurfaceCreated", response); break; } case kWhatInputSurfaceAccepted: { + if (mState != CONFIGURED) { + // state transitioned unexpectedly; we should have replied already. + ALOGD("received kWhatInputSurfaceAccepted message in state %s", + stateString(mState).c_str()); + break; + } // response to initiateSetInputSurface() status_t err = NO_ERROR; sp<AMessage> response = new AMessage(); @@ -2445,19 +2502,25 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { } else { response->setInt32("err", err); } - response->postReply(mReplyID); + postPendingRepliesAndDeferredMessages("kWhatInputSurfaceAccepted", response); break; } case kWhatSignaledInputEOS: { + if (!isExecuting()) { + // state transitioned unexpectedly; we should have replied already. + ALOGD("received kWhatSignaledInputEOS message in state %s", + stateString(mState).c_str()); + break; + } // response to signalEndOfInputStream() sp<AMessage> response = new AMessage; status_t err; if (msg->findInt32("err", &err)) { response->setInt32("err", err); } - response->postReply(mReplyID); + postPendingRepliesAndDeferredMessages("kWhatSignaledInputEOS", response); break; } @@ -2476,7 +2539,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { MediaResource::GraphicMemoryResource(getGraphicBufferSize())); } setState(STARTED); - (new AMessage)->postReply(mReplyID); + postPendingRepliesAndDeferredMessages("kWhatStartCompleted"); break; } @@ -2577,107 +2640,13 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { break; } - sp<RefBase> obj; - CHECK(msg->findObject("buffer", &obj)); - sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get()); - - if (mOutputFormat != buffer->format()) { - if (mFlags & kFlagUseBlockModel) { - sp<AMessage> diff1 = mOutputFormat->changesFrom(buffer->format()); - sp<AMessage> diff2 = buffer->format()->changesFrom(mOutputFormat); - std::set<std::string> keys; - size_t numEntries = diff1->countEntries(); - AMessage::Type type; - for (size_t i = 0; i < numEntries; ++i) { - keys.emplace(diff1->getEntryNameAt(i, &type)); - } - numEntries = diff2->countEntries(); - for (size_t i = 0; i < numEntries; ++i) { - keys.emplace(diff2->getEntryNameAt(i, &type)); - } - sp<WrapperObject<std::set<std::string>>> changedKeys{ - new WrapperObject<std::set<std::string>>{std::move(keys)}}; - buffer->meta()->setObject("changedKeys", changedKeys); - } - mOutputFormat = buffer->format(); - ALOGV("[%s] output format changed to: %s", - mComponentName.c_str(), mOutputFormat->debugString(4).c_str()); - - if (mSoftRenderer == NULL && - mSurface != NULL && - (mFlags & kFlagUsesSoftwareRenderer)) { - AString mime; - CHECK(mOutputFormat->findString("mime", &mime)); - - // TODO: propagate color aspects to software renderer to allow better - // color conversion to RGB. For now, just mark dataspace for YUV - // rendering. - int32_t dataSpace; - if (mOutputFormat->findInt32("android._dataspace", &dataSpace)) { - ALOGD("[%s] setting dataspace on output surface to #%x", - mComponentName.c_str(), dataSpace); - int err = native_window_set_buffers_data_space( - mSurface.get(), (android_dataspace)dataSpace); - ALOGW_IF(err != 0, "failed to set dataspace on surface (%d)", err); - } - if (mOutputFormat->contains("hdr-static-info")) { - HDRStaticInfo info; - if (ColorUtils::getHDRStaticInfoFromFormat(mOutputFormat, &info)) { - setNativeWindowHdrMetadata(mSurface.get(), &info); - } - } - - sp<ABuffer> hdr10PlusInfo; - if (mOutputFormat->findBuffer("hdr10-plus-info", &hdr10PlusInfo) - && hdr10PlusInfo != nullptr && hdr10PlusInfo->size() > 0) { - native_window_set_buffers_hdr10_plus_metadata(mSurface.get(), - hdr10PlusInfo->size(), hdr10PlusInfo->data()); - } - - if (mime.startsWithIgnoreCase("video/")) { - mSurface->setDequeueTimeout(-1); - mSoftRenderer = new SoftwareRenderer(mSurface, mRotationDegrees); - } - } - - requestCpuBoostIfNeeded(); - - if (mFlags & kFlagIsEncoder) { - // Before we announce the format change we should - // collect codec specific data and amend the output - // format as necessary. - int32_t flags = 0; - (void) buffer->meta()->findInt32("flags", &flags); - if ((flags & BUFFER_FLAG_CODECCONFIG) && !(mFlags & kFlagIsSecure)) { - status_t err = - amendOutputFormatWithCodecSpecificData(buffer); - - if (err != OK) { - ALOGE("Codec spit out malformed codec " - "specific data!"); - } - } - } - if (mFlags & kFlagIsAsync) { - onOutputFormatChanged(); - } else { - mFlags |= kFlagOutputFormatChanged; - postActivityNotificationIfPossible(); - } - - // Notify mCrypto of video resolution changes - if (mCrypto != NULL) { - int32_t left, top, right, bottom, width, height; - if (mOutputFormat->findRect("crop", &left, &top, &right, &bottom)) { - mCrypto->notifyResolution(right - left + 1, bottom - top + 1); - } else if (mOutputFormat->findInt32("width", &width) - && mOutputFormat->findInt32("height", &height)) { - mCrypto->notifyResolution(width, height); - } - } - } - if (mFlags & kFlagIsAsync) { + sp<RefBase> obj; + CHECK(msg->findObject("buffer", &obj)); + sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get()); + + // In asynchronous mode, output format change is processed immediately. + handleOutputFormatChangeIfNeeded(buffer); onOutputBufferAvailable(); } else if (mFlags & kFlagDequeueOutputPending) { CHECK(handleDequeueOutputBuffer(mDequeueOutputReplyID)); @@ -2706,7 +2675,13 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { break; } setState(INITIALIZED); - (new AMessage)->postReply(mReplyID); + if (mReplyID) { + postPendingRepliesAndDeferredMessages("kWhatStopCompleted"); + } else { + ALOGW("kWhatStopCompleted: presumably an error occurred earlier, " + "but the operation completed anyway. (last reply origin=%s)", + mLastReplyOrigin.c_str()); + } break; } @@ -2730,7 +2705,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { mReleaseSurface.reset(); if (mReplyID != nullptr) { - (new AMessage)->postReply(mReplyID); + postPendingRepliesAndDeferredMessages("kWhatReleaseCompleted"); } if (mAsyncReleaseCompleteNotification != nullptr) { flushMediametrics(); @@ -2755,7 +2730,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { mCodec->signalResume(); } - (new AMessage)->postReply(mReplyID); + postPendingRepliesAndDeferredMessages("kWhatFlushCompleted"); break; } @@ -2767,14 +2742,18 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatInit: { - sp<AReplyToken> replyID; - CHECK(msg->senderAwaitsResponse(&replyID)); - if (mState != UNINITIALIZED) { - PostReplyWithError(replyID, INVALID_OPERATION); + PostReplyWithError(msg, INVALID_OPERATION); break; } + if (mReplyID) { + mDeferredMessages.push_back(msg); + break; + } + sp<AReplyToken> replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + mReplyID = replyID; setState(INITIALIZING); @@ -2836,14 +2815,18 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatConfigure: { - sp<AReplyToken> replyID; - CHECK(msg->senderAwaitsResponse(&replyID)); - if (mState != INITIALIZED) { - PostReplyWithError(replyID, INVALID_OPERATION); + PostReplyWithError(msg, INVALID_OPERATION); break; } + if (mReplyID) { + mDeferredMessages.push_back(msg); + break; + } + sp<AReplyToken> replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + sp<RefBase> obj; CHECK(msg->findObject("surface", &obj)); @@ -2981,14 +2964,18 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatCreateInputSurface: case kWhatSetInputSurface: { - sp<AReplyToken> replyID; - CHECK(msg->senderAwaitsResponse(&replyID)); - // Must be configured, but can't have been started yet. if (mState != CONFIGURED) { - PostReplyWithError(replyID, INVALID_OPERATION); + PostReplyWithError(msg, INVALID_OPERATION); + break; + } + + if (mReplyID) { + mDeferredMessages.push_back(msg); break; } + sp<AReplyToken> replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); mReplyID = replyID; if (msg->what() == kWhatCreateInputSurface) { @@ -3004,9 +2991,6 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { } case kWhatStart: { - sp<AReplyToken> replyID; - CHECK(msg->senderAwaitsResponse(&replyID)); - if (mState == FLUSHED) { setState(STARTED); if (mHavePendingInputBuffers) { @@ -3014,12 +2998,19 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { mHavePendingInputBuffers = false; } mCodec->signalResume(); - PostReplyWithError(replyID, OK); + PostReplyWithError(msg, OK); break; } else if (mState != CONFIGURED) { - PostReplyWithError(replyID, INVALID_OPERATION); + PostReplyWithError(msg, INVALID_OPERATION); + break; + } + + if (mReplyID) { + mDeferredMessages.push_back(msg); break; } + sp<AReplyToken> replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); mReplyID = replyID; setState(STARTING); @@ -3028,15 +3019,42 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { break; } - case kWhatStop: + case kWhatStop: { + if (mReplyID) { + mDeferredMessages.push_back(msg); + break; + } + [[fallthrough]]; + } case kWhatRelease: { State targetState = (msg->what() == kWhatStop) ? INITIALIZED : UNINITIALIZED; + if ((mState == RELEASING && targetState == UNINITIALIZED) + || (mState == STOPPING && targetState == INITIALIZED)) { + mDeferredMessages.push_back(msg); + break; + } + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); + sp<AMessage> asyncNotify; + (void)msg->findMessage("async", &asyncNotify); + // post asyncNotify if going out of scope. + struct AsyncNotifyPost { + AsyncNotifyPost(const sp<AMessage> &asyncNotify) : mAsyncNotify(asyncNotify) {} + ~AsyncNotifyPost() { + if (mAsyncNotify) { + mAsyncNotify->post(); + } + } + void clear() { mAsyncNotify.clear(); } + private: + sp<AMessage> mAsyncNotify; + } asyncNotifyPost{asyncNotify}; + // already stopped/released if (mState == UNINITIALIZED && mReleasedByResourceManager) { sp<AMessage> response = new AMessage; @@ -3100,12 +3118,15 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { // after this, and we'll no longer be able to reply. if (mState == FLUSHING || mState == STOPPING || mState == CONFIGURING || mState == STARTING) { - (new AMessage)->postReply(mReplyID); + // mReply is always set if in these states. + postPendingRepliesAndDeferredMessages( + std::string("kWhatRelease:") + stateString(mState)); } if (mFlags & kFlagSawMediaServerDie) { // It's dead, Jim. Don't expect initiateShutdown to yield // any useful results now... + // Any pending reply would have been handled at kWhatError. setState(UNINITIALIZED); if (targetState == UNINITIALIZED) { mComponentName.clear(); @@ -3119,12 +3140,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { // reply now with an error to unblock the client, client can // release after the failure (instead of ANR). if (msg->what() == kWhatStop && (mFlags & kFlagStickyError)) { + // Any pending reply would have been handled at kWhatError. PostReplyWithError(replyID, getStickyError()); break; } - sp<AMessage> asyncNotify; - if (msg->findMessage("async", &asyncNotify) && asyncNotify != nullptr) { + if (asyncNotify != nullptr) { if (mSurface != NULL) { if (!mReleaseSurface) { uint64_t usage = 0; @@ -3148,6 +3169,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { } } + if (mReplyID) { + // State transition replies are handled above, so this reply + // would not be related to state transition. As we are + // shutting down the component, just fail the operation. + postPendingRepliesAndDeferredMessages("kWhatRelease:reply", UNKNOWN_ERROR); + } mReplyID = replyID; setState(msg->what() == kWhatStop ? STOPPING : RELEASING); @@ -3162,8 +3189,8 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { if (asyncNotify != nullptr) { mResourceManagerProxy->markClientForPendingRemoval(); - (new AMessage)->postReply(mReplyID); - mReplyID = 0; + postPendingRepliesAndDeferredMessages("kWhatRelease:async"); + asyncNotifyPost.clear(); mAsyncReleaseCompleteNotification = asyncNotify; } @@ -3334,17 +3361,21 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatSignalEndOfInputStream: { - sp<AReplyToken> replyID; - CHECK(msg->senderAwaitsResponse(&replyID)); - if (!isExecuting() || !mHaveInputSurface) { - PostReplyWithError(replyID, INVALID_OPERATION); + PostReplyWithError(msg, INVALID_OPERATION); break; } else if (mFlags & kFlagStickyError) { - PostReplyWithError(replyID, getStickyError()); + PostReplyWithError(msg, getStickyError()); break; } + if (mReplyID) { + mDeferredMessages.push_back(msg); + break; + } + sp<AReplyToken> replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + mReplyID = replyID; mCodec->signalEndOfInputStream(); break; @@ -3386,17 +3417,21 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatFlush: { - sp<AReplyToken> replyID; - CHECK(msg->senderAwaitsResponse(&replyID)); - if (!isExecuting()) { - PostReplyWithError(replyID, INVALID_OPERATION); + PostReplyWithError(msg, INVALID_OPERATION); break; } else if (mFlags & kFlagStickyError) { - PostReplyWithError(replyID, getStickyError()); + PostReplyWithError(msg, getStickyError()); break; } + if (mReplyID) { + mDeferredMessages.push_back(msg); + break; + } + sp<AReplyToken> replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + mReplyID = replyID; // TODO: skip flushing if already FLUSHED setState(FLUSHING); @@ -3510,6 +3545,106 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { } } +void MediaCodec::handleOutputFormatChangeIfNeeded(const sp<MediaCodecBuffer> &buffer) { + sp<AMessage> format = buffer->format(); + if (mOutputFormat == format) { + return; + } + if (mFlags & kFlagUseBlockModel) { + sp<AMessage> diff1 = mOutputFormat->changesFrom(format); + sp<AMessage> diff2 = format->changesFrom(mOutputFormat); + std::set<std::string> keys; + size_t numEntries = diff1->countEntries(); + AMessage::Type type; + for (size_t i = 0; i < numEntries; ++i) { + keys.emplace(diff1->getEntryNameAt(i, &type)); + } + numEntries = diff2->countEntries(); + for (size_t i = 0; i < numEntries; ++i) { + keys.emplace(diff2->getEntryNameAt(i, &type)); + } + sp<WrapperObject<std::set<std::string>>> changedKeys{ + new WrapperObject<std::set<std::string>>{std::move(keys)}}; + buffer->meta()->setObject("changedKeys", changedKeys); + } + mOutputFormat = format; + ALOGV("[%s] output format changed to: %s", + mComponentName.c_str(), mOutputFormat->debugString(4).c_str()); + + if (mSoftRenderer == NULL && + mSurface != NULL && + (mFlags & kFlagUsesSoftwareRenderer)) { + AString mime; + CHECK(mOutputFormat->findString("mime", &mime)); + + // TODO: propagate color aspects to software renderer to allow better + // color conversion to RGB. For now, just mark dataspace for YUV + // rendering. + int32_t dataSpace; + if (mOutputFormat->findInt32("android._dataspace", &dataSpace)) { + ALOGD("[%s] setting dataspace on output surface to #%x", + mComponentName.c_str(), dataSpace); + int err = native_window_set_buffers_data_space( + mSurface.get(), (android_dataspace)dataSpace); + ALOGW_IF(err != 0, "failed to set dataspace on surface (%d)", err); + } + if (mOutputFormat->contains("hdr-static-info")) { + HDRStaticInfo info; + if (ColorUtils::getHDRStaticInfoFromFormat(mOutputFormat, &info)) { + setNativeWindowHdrMetadata(mSurface.get(), &info); + } + } + + sp<ABuffer> hdr10PlusInfo; + if (mOutputFormat->findBuffer("hdr10-plus-info", &hdr10PlusInfo) + && hdr10PlusInfo != nullptr && hdr10PlusInfo->size() > 0) { + native_window_set_buffers_hdr10_plus_metadata(mSurface.get(), + hdr10PlusInfo->size(), hdr10PlusInfo->data()); + } + + if (mime.startsWithIgnoreCase("video/")) { + mSurface->setDequeueTimeout(-1); + mSoftRenderer = new SoftwareRenderer(mSurface, mRotationDegrees); + } + } + + requestCpuBoostIfNeeded(); + + if (mFlags & kFlagIsEncoder) { + // Before we announce the format change we should + // collect codec specific data and amend the output + // format as necessary. + int32_t flags = 0; + (void) buffer->meta()->findInt32("flags", &flags); + if ((flags & BUFFER_FLAG_CODECCONFIG) && !(mFlags & kFlagIsSecure)) { + status_t err = + amendOutputFormatWithCodecSpecificData(buffer); + + if (err != OK) { + ALOGE("Codec spit out malformed codec " + "specific data!"); + } + } + } + if (mFlags & kFlagIsAsync) { + onOutputFormatChanged(); + } else { + mFlags |= kFlagOutputFormatChanged; + postActivityNotificationIfPossible(); + } + + // Notify mCrypto of video resolution changes + if (mCrypto != NULL) { + int32_t left, top, right, bottom, width, height; + if (mOutputFormat->findRect("crop", &left, &top, &right, &bottom)) { + mCrypto->notifyResolution(right - left + 1, bottom - top + 1); + } else if (mOutputFormat->findInt32("width", &width) + && mOutputFormat->findInt32("height", &height)) { + mCrypto->notifyResolution(width, height); + } + } +} + void MediaCodec::extractCSD(const sp<AMessage> &format) { mCSD.clear(); @@ -3975,19 +4110,31 @@ status_t MediaCodec::onReleaseOutputBuffer(const sp<AMessage> &msg) { return OK; } -ssize_t MediaCodec::dequeuePortBuffer(int32_t portIndex) { +MediaCodec::BufferInfo *MediaCodec::peekNextPortBuffer(int32_t portIndex) { CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput); List<size_t> *availBuffers = &mAvailPortBuffers[portIndex]; if (availBuffers->empty()) { + return nullptr; + } + + return &mPortBuffers[portIndex][*availBuffers->begin()]; +} + +ssize_t MediaCodec::dequeuePortBuffer(int32_t portIndex) { + CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput); + + BufferInfo *info = peekNextPortBuffer(portIndex); + if (!info) { return -EAGAIN; } + List<size_t> *availBuffers = &mAvailPortBuffers[portIndex]; size_t index = *availBuffers->begin(); + CHECK_EQ(info, &mPortBuffers[portIndex][index]); availBuffers->erase(availBuffers->begin()); - BufferInfo *info = &mPortBuffers[portIndex][index]; CHECK(!info->mOwnedByClient); { Mutex::Autolock al(mBufferLock); @@ -4229,6 +4376,33 @@ status_t MediaCodec::amendOutputFormatWithCodecSpecificData( return OK; } +void MediaCodec::postPendingRepliesAndDeferredMessages( + std::string origin, status_t err /* = OK */) { + sp<AMessage> response{new AMessage}; + if (err != OK) { + response->setInt32("err", err); + } + postPendingRepliesAndDeferredMessages(origin, response); +} + +void MediaCodec::postPendingRepliesAndDeferredMessages( + std::string origin, const sp<AMessage> &response) { + LOG_ALWAYS_FATAL_IF( + !mReplyID, + "postPendingRepliesAndDeferredMessages: mReplyID == null, from %s following %s", + origin.c_str(), + mLastReplyOrigin.c_str()); + mLastReplyOrigin = origin; + response->postReply(mReplyID); + mReplyID.clear(); + ALOGV_IF(!mDeferredMessages.empty(), + "posting %zu deferred messages", mDeferredMessages.size()); + for (sp<AMessage> msg : mDeferredMessages) { + msg->post(); + } + mDeferredMessages.clear(); +} + std::string MediaCodec::stateString(State state) { const char *rval = NULL; char rawbuffer[16]; // room for "%d" diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp index 1395c275c5..c6ae1596de 100644 --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -168,9 +168,7 @@ status_t MediaCodecSource::Puller::postSynchronouslyAndReturnError( } status_t MediaCodecSource::Puller::setStopTimeUs(int64_t stopTimeUs) { - sp<AMessage> msg = new AMessage(kWhatSetStopTimeUs, this); - msg->setInt64("stop-time-us", stopTimeUs); - return postSynchronouslyAndReturnError(msg); + return mSource->setStopTimeUs(stopTimeUs); } status_t MediaCodecSource::Puller::start(const sp<MetaData> &meta, const sp<AMessage> ¬ify) { @@ -188,19 +186,11 @@ status_t MediaCodecSource::Puller::start(const sp<MetaData> &meta, const sp<AMes } void MediaCodecSource::Puller::stop() { - bool interrupt = false; - { - // mark stopping before actually reaching kWhatStop on the looper, so the pulling will - // stop. - Mutexed<Queue>::Locked queue(mQueue); - queue->mPulling = false; - interrupt = queue->mReadPendingSince && (queue->mReadPendingSince < ALooper::GetNowUs() - 1000000); - queue->flush(); // flush any unprocessed pulled buffers - } - - if (interrupt) { - interruptSource(); - } + // mark stopping before actually reaching kWhatStop on the looper, so the pulling will + // stop. + Mutexed<Queue>::Locked queue(mQueue); + queue->mPulling = false; + queue->flush(); // flush any unprocessed pulled buffers } void MediaCodecSource::Puller::interruptSource() { @@ -660,9 +650,9 @@ void MediaCodecSource::signalEOS(status_t err) { if (mStopping && reachedEOS) { ALOGI("encoder (%s) stopped", mIsVideo ? "video" : "audio"); if (mPuller != NULL) { - mPuller->stopSource(); + mPuller->interruptSource(); } - ALOGV("source (%s) stopped", mIsVideo ? "video" : "audio"); + ALOGI("source (%s) stopped", mIsVideo ? "video" : "audio"); // posting reply to everyone that's waiting List<sp<AReplyToken>>::iterator it; for (it = mStopReplyIDQueue.begin(); @@ -851,7 +841,7 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) { { int32_t eos = 0; if (msg->findInt32("eos", &eos) && eos) { - ALOGV("puller (%s) reached EOS", mIsVideo ? "video" : "audio"); + ALOGI("puller (%s) reached EOS", mIsVideo ? "video" : "audio"); signalEOS(); break; } @@ -1069,12 +1059,7 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) { if (generation != mGeneration) { break; } - - if (!(mFlags & FLAG_USE_SURFACE_INPUT)) { - ALOGV("source (%s) stopping", mIsVideo ? "video" : "audio"); - mPuller->interruptSource(); - ALOGV("source (%s) stopped", mIsVideo ? "video" : "audio"); - } + ALOGD("source (%s) stopping stalled", mIsVideo ? "video" : "audio"); signalEOS(); break; } diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp index cab4ebd292..8d9bc06378 100644 --- a/media/libstagefright/MediaMuxer.cpp +++ b/media/libstagefright/MediaMuxer.cpp @@ -92,7 +92,9 @@ ssize_t MediaMuxer::addTrack(const sp<AMessage> &format) { } sp<MetaData> trackMeta = new MetaData; - convertMessageToMetaData(format, trackMeta); + if (convertMessageToMetaData(format, trackMeta) != OK) { + return BAD_VALUE; + } sp<MediaAdapter> newTrack = new MediaAdapter(trackMeta); status_t result = mWriter->addSource(newTrack); diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp index 050d7c2e65..c6385079dd 100644 --- a/media/libstagefright/NuMediaExtractor.cpp +++ b/media/libstagefright/NuMediaExtractor.cpp @@ -50,8 +50,9 @@ NuMediaExtractor::Sample::Sample(MediaBufferBase *buffer, int64_t timeUs) mSampleTimeUs(timeUs) { } -NuMediaExtractor::NuMediaExtractor() - : mTotalBitrate(-1LL), +NuMediaExtractor::NuMediaExtractor(EntryPoint entryPoint) + : mEntryPoint(entryPoint), + mTotalBitrate(-1LL), mDurationUs(-1LL) { } @@ -93,6 +94,7 @@ status_t NuMediaExtractor::setDataSource( if (mImpl == NULL) { return ERROR_UNSUPPORTED; } + setEntryPointToRemoteMediaExtractor(); status_t err = OK; if (!mCasToken.empty()) { @@ -134,6 +136,7 @@ status_t NuMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) { if (mImpl == NULL) { return ERROR_UNSUPPORTED; } + setEntryPointToRemoteMediaExtractor(); if (!mCasToken.empty()) { err = mImpl->setMediaCas(mCasToken); @@ -168,6 +171,7 @@ status_t NuMediaExtractor::setDataSource(const sp<DataSource> &source) { if (mImpl == NULL) { return ERROR_UNSUPPORTED; } + setEntryPointToRemoteMediaExtractor(); if (!mCasToken.empty()) { err = mImpl->setMediaCas(mCasToken); @@ -468,6 +472,16 @@ void NuMediaExtractor::releaseAllTrackSamples() { } } +void NuMediaExtractor::setEntryPointToRemoteMediaExtractor() { + if (mImpl == NULL) { + return; + } + status_t err = mImpl->setEntryPoint(mEntryPoint); + if (err != OK) { + ALOGW("Failed to set entry point with error %d.", err); + } +} + ssize_t NuMediaExtractor::fetchAllTrackSamples( int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) { TrackInfo *minInfo = NULL; diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp index 25e43c28e1..381eb1ad95 100644 --- a/media/libstagefright/RemoteMediaExtractor.cpp +++ b/media/libstagefright/RemoteMediaExtractor.cpp @@ -39,6 +39,12 @@ static const char *kKeyExtractor = "extractor"; static const char *kExtractorFormat = "android.media.mediaextractor.fmt"; static const char *kExtractorMime = "android.media.mediaextractor.mime"; static const char *kExtractorTracks = "android.media.mediaextractor.ntrk"; +static const char *kExtractorEntryPoint = "android.media.mediaextractor.entry"; + +static const char *kEntryPointSdk = "sdk"; +static const char *kEntryPointWithJvm = "ndk-with-jvm"; +static const char *kEntryPointNoJvm = "ndk-no-jvm"; +static const char *kEntryPointOther = "other"; RemoteMediaExtractor::RemoteMediaExtractor( MediaExtractor *extractor, @@ -74,6 +80,9 @@ RemoteMediaExtractor::RemoteMediaExtractor( } // what else is interesting and not already available? } + // By default, we set the entry point to be "other". Clients of this + // class will override this value by calling setEntryPoint. + mMetricsItem->setCString(kExtractorEntryPoint, kEntryPointOther); } } @@ -143,6 +152,28 @@ String8 RemoteMediaExtractor::name() { return String8(mExtractor->name()); } +status_t RemoteMediaExtractor::setEntryPoint(EntryPoint entryPoint) { + const char* entryPointString; + switch (entryPoint) { + case EntryPoint::SDK: + entryPointString = kEntryPointSdk; + break; + case EntryPoint::NDK_WITH_JVM: + entryPointString = kEntryPointWithJvm; + break; + case EntryPoint::NDK_NO_JVM: + entryPointString = kEntryPointNoJvm; + break; + case EntryPoint::OTHER: + entryPointString = kEntryPointOther; + break; + default: + return BAD_VALUE; + } + mMetricsItem->setCString(kExtractorEntryPoint, entryPointString); + return OK; +} + //////////////////////////////////////////////////////////////////////////////// // static diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp index 4c94baabe0..c284ef7d06 100644 --- a/media/libstagefright/SurfaceUtils.cpp +++ b/media/libstagefright/SurfaceUtils.cpp @@ -132,37 +132,47 @@ status_t setNativeWindowSizeFormatAndUsage( } void setNativeWindowHdrMetadata(ANativeWindow *nativeWindow, HDRStaticInfo *info) { - struct android_smpte2086_metadata smpte2086_meta = { - .displayPrimaryRed = { - info->sType1.mR.x * 0.00002f, - info->sType1.mR.y * 0.00002f - }, - .displayPrimaryGreen = { - info->sType1.mG.x * 0.00002f, - info->sType1.mG.y * 0.00002f - }, - .displayPrimaryBlue = { - info->sType1.mB.x * 0.00002f, - info->sType1.mB.y * 0.00002f - }, - .whitePoint = { - info->sType1.mW.x * 0.00002f, - info->sType1.mW.y * 0.00002f - }, - .maxLuminance = (float) info->sType1.mMaxDisplayLuminance, - .minLuminance = info->sType1.mMinDisplayLuminance * 0.0001f - }; - - int err = native_window_set_buffers_smpte2086_metadata(nativeWindow, &smpte2086_meta); - ALOGW_IF(err != 0, "failed to set smpte2086 metadata on surface (%d)", err); - - struct android_cta861_3_metadata cta861_meta = { - .maxContentLightLevel = (float) info->sType1.mMaxContentLightLevel, - .maxFrameAverageLightLevel = (float) info->sType1.mMaxFrameAverageLightLevel - }; - - err = native_window_set_buffers_cta861_3_metadata(nativeWindow, &cta861_meta); - ALOGW_IF(err != 0, "failed to set cta861_3 metadata on surface (%d)", err); + // If mastering max and min luminance fields are 0, do not use them. + // It indicates the value may not be present in the stream. + if ((float)info->sType1.mMaxDisplayLuminance > 0.0f && + (info->sType1.mMinDisplayLuminance * 0.0001f) > 0.0f) { + struct android_smpte2086_metadata smpte2086_meta = { + .displayPrimaryRed = { + info->sType1.mR.x * 0.00002f, + info->sType1.mR.y * 0.00002f + }, + .displayPrimaryGreen = { + info->sType1.mG.x * 0.00002f, + info->sType1.mG.y * 0.00002f + }, + .displayPrimaryBlue = { + info->sType1.mB.x * 0.00002f, + info->sType1.mB.y * 0.00002f + }, + .whitePoint = { + info->sType1.mW.x * 0.00002f, + info->sType1.mW.y * 0.00002f + }, + .maxLuminance = (float) info->sType1.mMaxDisplayLuminance, + .minLuminance = info->sType1.mMinDisplayLuminance * 0.0001f + }; + + int err = native_window_set_buffers_smpte2086_metadata(nativeWindow, &smpte2086_meta); + ALOGW_IF(err != 0, "failed to set smpte2086 metadata on surface (%d)", err); + } + + // If the content light level fields are 0, do not use them, it + // indicates the value may not be present in the stream. + if ((float)info->sType1.mMaxContentLightLevel > 0.0f && + (float)info->sType1.mMaxFrameAverageLightLevel > 0.0f) { + struct android_cta861_3_metadata cta861_meta = { + .maxContentLightLevel = (float) info->sType1.mMaxContentLightLevel, + .maxFrameAverageLightLevel = (float) info->sType1.mMaxFrameAverageLightLevel + }; + + int err = native_window_set_buffers_cta861_3_metadata(nativeWindow, &cta861_meta); + ALOGW_IF(err != 0, "failed to set cta861_3 metadata on surface (%d)", err); + } } status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */) { diff --git a/media/libstagefright/TEST_MAPPING b/media/libstagefright/TEST_MAPPING index 8b36ea5d99..5e537dd490 100644 --- a/media/libstagefright/TEST_MAPPING +++ b/media/libstagefright/TEST_MAPPING @@ -17,6 +17,9 @@ "exclude-filter": "android.media.cts.AudioRecordTest" } ] + }, + { + "name": "mediacodecTest" } ], "postsubmit": [ diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index a1e4d438ec..ece79c4b02 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -1663,13 +1663,16 @@ static void convertMessageToMetaDataColorAspects(const sp<AMessage> &msg, sp<Met meta->setInt32(kKeyColorMatrix, colorAspects.mMatrixCoeffs); } } - -void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) { +/* Converts key and value pairs in AMessage format to MetaData format. + * Also checks for the presence of required keys. + */ +status_t convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) { AString mime; if (msg->findString("mime", &mime)) { meta->setCString(kKeyMIMEType, mime.c_str()); } else { - ALOGW("did not find mime type"); + ALOGE("did not find mime type"); + return BAD_VALUE; } convertMessageToMetaDataFromMappings(msg, meta); @@ -1718,7 +1721,8 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) { meta->setInt32(kKeyWidth, width); meta->setInt32(kKeyHeight, height); } else { - ALOGV("did not find width and/or height"); + ALOGE("did not find width and/or height"); + return BAD_VALUE; } int32_t sarWidth, sarHeight; @@ -1803,14 +1807,14 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) { } } } else if (mime.startsWith("audio/")) { - int32_t numChannels; - if (msg->findInt32("channel-count", &numChannels)) { - meta->setInt32(kKeyChannelCount, numChannels); - } - int32_t sampleRate; - if (msg->findInt32("sample-rate", &sampleRate)) { - meta->setInt32(kKeySampleRate, sampleRate); + int32_t numChannels, sampleRate; + if (!msg->findInt32("channel-count", &numChannels) || + !msg->findInt32("sample-rate", &sampleRate)) { + ALOGE("did not find channel-count and/or sample-rate"); + return BAD_VALUE; } + meta->setInt32(kKeyChannelCount, numChannels); + meta->setInt32(kKeySampleRate, sampleRate); int32_t bitsPerSample; if (msg->findInt32("bits-per-sample", &bitsPerSample)) { meta->setInt32(kKeyBitsPerSample, bitsPerSample); @@ -1925,7 +1929,8 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) { } } } else { - ALOGW("We need csd-2!!. %s", msg->debugString().c_str()); + ALOGE("We need csd-2!!. %s", msg->debugString().c_str()); + return BAD_VALUE; } } else if (mime == MEDIA_MIMETYPE_VIDEO_VP9) { meta->setData(kKeyVp9CodecPrivate, 0, csd0->data(), csd0->size()); @@ -1991,6 +1996,7 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) { ALOGI("converted %s to:", msg->debugString(0).c_str()); meta->dumpToLog(); #endif + return OK; } status_t sendMetaDataToHal(sp<MediaPlayerBase::AudioSink>& sink, diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 2aeddd7850..28a7a1e351 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -38,6 +38,7 @@ #define DRC_DEFAULT_MOBILE_DRC_HEAVY 1 /* switch for heavy compression for mobile conf */ #define DRC_DEFAULT_MOBILE_DRC_EFFECT 3 /* MPEG-D DRC effect type; 3 => Limited playback range */ #define DRC_DEFAULT_MOBILE_DRC_ALBUM 0 /* MPEG-D DRC album mode; 0 => album mode is disabled, 1 => album mode is enabled */ +#define DRC_DEFAULT_MOBILE_OUTPUT_LOUDNESS -1 /* decoder output loudness; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */ #define DRC_DEFAULT_MOBILE_ENC_LEVEL (-1) /* encoder target level; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */ #define MAX_CHANNEL_COUNT 8 /* maximum number of audio channels that can be decoded */ // names of properties that can be used to override the default DRC settings @@ -230,6 +231,15 @@ status_t SoftAAC2::initDecoder() { // For seven and eight channel input streams, enable 6.1 and 7.1 channel output aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, -1); + mDrcCompressMode = DRC_DEFAULT_MOBILE_DRC_HEAVY; + mDrcTargetRefLevel = DRC_DEFAULT_MOBILE_REF_LEVEL; + mDrcEncTargetLevel = DRC_DEFAULT_MOBILE_ENC_LEVEL; + mDrcBoostFactor = DRC_DEFAULT_MOBILE_DRC_BOOST; + mDrcAttenuationFactor = DRC_DEFAULT_MOBILE_DRC_CUT; + mDrcEffectType = DRC_DEFAULT_MOBILE_DRC_EFFECT; + mDrcAlbumMode = DRC_DEFAULT_MOBILE_DRC_ALBUM; + mDrcOutputLoudness = DRC_DEFAULT_MOBILE_OUTPUT_LOUDNESS; + return status; } @@ -358,6 +368,27 @@ OMX_ERRORTYPE SoftAAC2::internalGetParameter( return OMX_ErrorNone; } + case OMX_IndexParamAudioAndroidAacDrcPresentation: + { + OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE *aacPresParams = + (OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE *)params; + + ALOGD("get OMX_IndexParamAudioAndroidAacDrcPresentation"); + + if (!isValidOMXParam(aacPresParams)) { + return OMX_ErrorBadParameter; + } + aacPresParams->nDrcEffectType = mDrcEffectType; + aacPresParams->nDrcAlbumMode = mDrcAlbumMode; + aacPresParams->nDrcBoost = mDrcBoostFactor; + aacPresParams->nDrcCut = mDrcAttenuationFactor; + aacPresParams->nHeavyCompression = mDrcCompressMode; + aacPresParams->nTargetReferenceLevel = mDrcTargetRefLevel; + aacPresParams->nEncodedTargetLevel = mDrcEncTargetLevel; + aacPresParams ->nDrcOutputLoudness = mDrcOutputLoudness; + return OMX_ErrorNone; + } + default: return SimpleSoftOMXComponent::internalGetParameter(index, params); } @@ -464,11 +495,13 @@ OMX_ERRORTYPE SoftAAC2::internalSetParameter( if (aacPresParams->nDrcEffectType >= -1) { ALOGV("set nDrcEffectType=%d", aacPresParams->nDrcEffectType); aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_SET_EFFECT, aacPresParams->nDrcEffectType); + mDrcEffectType = aacPresParams->nDrcEffectType; } if (aacPresParams->nDrcAlbumMode >= -1) { ALOGV("set nDrcAlbumMode=%d", aacPresParams->nDrcAlbumMode); aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_ALBUM_MODE, aacPresParams->nDrcAlbumMode); + mDrcAlbumMode = aacPresParams->nDrcAlbumMode; } bool updateDrcWrapper = false; if (aacPresParams->nDrcBoost >= 0) { @@ -476,34 +509,42 @@ OMX_ERRORTYPE SoftAAC2::internalSetParameter( mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR, aacPresParams->nDrcBoost); updateDrcWrapper = true; + mDrcBoostFactor = aacPresParams->nDrcBoost; } if (aacPresParams->nDrcCut >= 0) { ALOGV("set nDrcCut=%d", aacPresParams->nDrcCut); mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR, aacPresParams->nDrcCut); updateDrcWrapper = true; + mDrcAttenuationFactor = aacPresParams->nDrcCut; } if (aacPresParams->nHeavyCompression >= 0) { ALOGV("set nHeavyCompression=%d", aacPresParams->nHeavyCompression); mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_HEAVY, aacPresParams->nHeavyCompression); updateDrcWrapper = true; + mDrcCompressMode = aacPresParams->nHeavyCompression; } if (aacPresParams->nTargetReferenceLevel >= -1) { ALOGV("set nTargetReferenceLevel=%d", aacPresParams->nTargetReferenceLevel); mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_TARGET, aacPresParams->nTargetReferenceLevel); updateDrcWrapper = true; + mDrcTargetRefLevel = aacPresParams->nTargetReferenceLevel; } if (aacPresParams->nEncodedTargetLevel >= 0) { ALOGV("set nEncodedTargetLevel=%d", aacPresParams->nEncodedTargetLevel); mDrcWrap.setParam(DRC_PRES_MODE_WRAP_ENCODER_TARGET, aacPresParams->nEncodedTargetLevel); updateDrcWrapper = true; + mDrcEncTargetLevel = aacPresParams->nEncodedTargetLevel; } if (aacPresParams->nPCMLimiterEnable >= 0) { aacDecoder_SetParam(mAACDecoder, AAC_PCM_LIMITER_ENABLE, (aacPresParams->nPCMLimiterEnable != 0)); } + if (aacPresParams ->nDrcOutputLoudness != DRC_DEFAULT_MOBILE_OUTPUT_LOUDNESS) { + mDrcOutputLoudness = aacPresParams ->nDrcOutputLoudness; + } if (updateDrcWrapper) { mDrcWrap.update(); } @@ -854,6 +895,11 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { // fall through } + if ( mDrcOutputLoudness != mStreamInfo->outputLoudness) { + ALOGD("update Loudness, before = %d, now = %d", mDrcOutputLoudness, mStreamInfo->outputLoudness); + mDrcOutputLoudness = mStreamInfo->outputLoudness; + } + /* * AAC+/eAAC+ streams can be signalled in two ways: either explicitly * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h index 5bee710792..9f98aa196a 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.h +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h @@ -85,6 +85,17 @@ private: int32_t mOutputDelayRingBufferWritePos; int32_t mOutputDelayRingBufferReadPos; int32_t mOutputDelayRingBufferFilled; + + //drc + int32_t mDrcCompressMode; + int32_t mDrcTargetRefLevel; + int32_t mDrcEncTargetLevel; + int32_t mDrcBoostFactor; + int32_t mDrcAttenuationFactor; + int32_t mDrcEffectType; + int32_t mDrcAlbumMode; + int32_t mDrcOutputLoudness; + bool outputDelayRingBufferPutSamples(INT_PCM *samples, int numSamples); int32_t outputDelayRingBufferGetSamples(INT_PCM *samples, int numSamples); int32_t outputDelayRingBufferSamplesAvailable(); diff --git a/media/libstagefright/codecs/amrnb/enc/src/pitch_fr.cpp b/media/libstagefright/codecs/amrnb/enc/src/pitch_fr.cpp index 5a846fa624..584f79b727 100644 --- a/media/libstagefright/codecs/amrnb/enc/src/pitch_fr.cpp +++ b/media/libstagefright/codecs/amrnb/enc/src/pitch_fr.cpp @@ -570,12 +570,14 @@ static void searchFrac( Word16 corr[], /* i : normalized correlation */ Word16 flag3, /* i : subsample resolution (3: =1 / 6: =0) */ - Flag *pOverflow + Flag *pOverflow, + enum Mode mode ) { Word16 i; Word16 max; Word16 corr_int; + Word16 minPitch; /* Test the fractions around T0 and choose the one which maximizes */ /* the interpolated normalized correlation. */ @@ -593,14 +595,22 @@ static void searchFrac( } } + minPitch = (mode == MR122) ? PIT_MIN_MR122 : PIT_MIN; if (flag3 == 0) { /* Limit the fraction value in the interval [-2,-1,0,1,2,3] */ if (*frac == -3) { - *frac = 3; - (*lag)--; + if (*lag > minPitch) + { + *frac = 3; + (*lag)--; + } + else + { + *frac = -2; + } } } else @@ -609,13 +619,27 @@ static void searchFrac( if (*frac == -2) { - *frac = 1; - (*lag)--; + if (*lag > minPitch) + { + *frac = 1; + (*lag)--; + } + else + { + *frac = -1; + } } - if (*frac == 2) + else if (*frac == 2) { - *frac = -1; - (*lag)++; + if (*lag < PIT_MAX) + { + *frac = -1; + (*lag)++; + } + else + { + *frac = 1; + } } } } @@ -1533,20 +1557,20 @@ Word16 Pitch_fr( /* o : pitch period (integer) */ /* normal search in fractions around T0 */ - searchFrac(&lag, &frac, last_frac, corr, flag3, pOverflow); + searchFrac(&lag, &frac, last_frac, corr, flag3, pOverflow, mode); } else if (lag == (tmp_lag - 2)) { /* limit search around T0 to the right side */ frac = 0; - searchFrac(&lag, &frac, last_frac, corr, flag3, pOverflow); + searchFrac(&lag, &frac, last_frac, corr, flag3, pOverflow, mode); } else if (lag == (tmp_lag + 1)) { /* limit search around T0 to the left side */ last_frac = 0; - searchFrac(&lag, &frac, last_frac, corr, flag3, pOverflow); + searchFrac(&lag, &frac, last_frac, corr, flag3, pOverflow, mode); } else { @@ -1556,7 +1580,7 @@ Word16 Pitch_fr( /* o : pitch period (integer) */ } else /* test the fractions around T0 */ - searchFrac(&lag, &frac, last_frac, corr, flag3, pOverflow); + searchFrac(&lag, &frac, last_frac, corr, flag3, pOverflow, mode); } /*-----------------------------------------------------------------------* diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/bitstream.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/bitstream.cpp index 37250f3a69..5b19db4b75 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/src/bitstream.cpp +++ b/media/libstagefright/codecs/m4v_h263/dec/src/bitstream.cpp @@ -649,8 +649,11 @@ PV_STATUS PVSearchNextM4VFrame(BitstreamDecVideo *stream) -void PVLocateM4VFrameBoundary(BitstreamDecVideo *stream) +PV_STATUS PVLocateM4VFrameBoundary(BitstreamDecVideo *stream) { + PV_STATUS status = BitstreamCheckEndBuffer(stream); + if (status == PV_END_OF_VOP) return status; + uint8 *ptr; int32 byte_pos = (stream->bitcnt >> 3); @@ -658,10 +661,14 @@ void PVLocateM4VFrameBoundary(BitstreamDecVideo *stream) ptr = stream->bitstreamBuffer + byte_pos; stream->data_end_pos = PVLocateFrameHeader(ptr, (int32)stream->data_end_pos - byte_pos) + byte_pos; + return PV_SUCCESS; } -void PVLocateH263FrameBoundary(BitstreamDecVideo *stream) +PV_STATUS PVLocateH263FrameBoundary(BitstreamDecVideo *stream) { + PV_STATUS status = BitstreamCheckEndBuffer(stream); + if (status == PV_END_OF_VOP) return status; + uint8 *ptr; int32 byte_pos = (stream->bitcnt >> 3); @@ -669,6 +676,7 @@ void PVLocateH263FrameBoundary(BitstreamDecVideo *stream) ptr = stream->bitstreamBuffer + byte_pos; stream->data_end_pos = PVLocateH263FrameHeader(ptr, (int32)stream->data_end_pos - byte_pos) + byte_pos; + return PV_SUCCESS; } /* ======================================================================== */ @@ -687,7 +695,8 @@ PV_STATUS quickSearchVideoPacketHeader(BitstreamDecVideo *stream, int marker_len if (stream->searched_frame_boundary == 0) { - PVLocateM4VFrameBoundary(stream); + status = PVLocateM4VFrameBoundary(stream); + if (status != PV_SUCCESS) return status; } do @@ -711,7 +720,8 @@ PV_STATUS quickSearchH263SliceHeader(BitstreamDecVideo *stream) if (stream->searched_frame_boundary == 0) { - PVLocateH263FrameBoundary(stream); + status = PVLocateH263FrameBoundary(stream); + if (status != PV_SUCCESS) return status; } do @@ -789,7 +799,8 @@ PV_STATUS quickSearchMotionMarker(BitstreamDecVideo *stream) if (stream->searched_frame_boundary == 0) { - PVLocateM4VFrameBoundary(stream); + status = PVLocateM4VFrameBoundary(stream); + if (status != PV_SUCCESS) return status; } while (TRUE) @@ -880,7 +891,8 @@ PV_STATUS quickSearchDCM(BitstreamDecVideo *stream) if (stream->searched_frame_boundary == 0) { - PVLocateM4VFrameBoundary(stream); + status = PVLocateM4VFrameBoundary(stream); + if (status != PV_SUCCESS) return status; } while (TRUE) @@ -956,7 +968,8 @@ PV_STATUS quickSearchGOBHeader(BitstreamDecVideo *stream) if (stream->searched_frame_boundary == 0) { - PVLocateH263FrameBoundary(stream); + status = PVLocateH263FrameBoundary(stream); + if (status != PV_SUCCESS) return status; } while (TRUE) diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/bitstream.h b/media/libstagefright/codecs/m4v_h263/dec/src/bitstream.h index d52fa87327..0cf903d5e6 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/src/bitstream.h +++ b/media/libstagefright/codecs/m4v_h263/dec/src/bitstream.h @@ -156,8 +156,8 @@ extern "C" /* for error concealment & soft-decoding */ - void PVLocateM4VFrameBoundary(BitstreamDecVideo *stream); - void PVSearchH263FrameBoundary(BitstreamDecVideo *stream); + PV_STATUS PVLocateM4VFrameBoundary(BitstreamDecVideo *stream); + PV_STATUS PVSearchH263FrameBoundary(BitstreamDecVideo *stream); PV_STATUS quickSearchMotionMarker(BitstreamDecVideo *stream); PV_STATUS quickSearchDCM(BitstreamDecVideo *stream); diff --git a/media/libstagefright/codecs/m4v_h263/enc/src/motion_est.cpp b/media/libstagefright/codecs/m4v_h263/enc/src/motion_est.cpp index 997b78d229..9deb02367b 100644 --- a/media/libstagefright/codecs/m4v_h263/enc/src/motion_est.cpp +++ b/media/libstagefright/codecs/m4v_h263/enc/src/motion_est.cpp @@ -1576,7 +1576,7 @@ void RasterIntraUpdate(UChar *intraArray, UChar *Mode, Int totalMB, Int numRefre /* find the last refresh MB */ indx = 0; - while (intraArray[indx] == 1 && indx < totalMB) + while (indx < totalMB && intraArray[indx] == 1) indx++; /* add more */ diff --git a/media/libstagefright/codecs/m4v_h263/enc/src/mp4enc_api.cpp b/media/libstagefright/codecs/m4v_h263/enc/src/mp4enc_api.cpp index 7ab8f451e7..30e4fda2df 100644 --- a/media/libstagefright/codecs/m4v_h263/enc/src/mp4enc_api.cpp +++ b/media/libstagefright/codecs/m4v_h263/enc/src/mp4enc_api.cpp @@ -491,6 +491,9 @@ OSCL_EXPORT_REF Bool PVInitVideoEncoder(VideoEncControls *encoderControl, Vid } for (i = 0; i < encParams->nLayers; i++) { + if (encOption->encHeight[i] == 0 || encOption->encWidth[i] == 0 || + encOption->encHeight[i] % 16 != 0 || encOption->encWidth[i] % 16 != 0) + goto CLEAN_UP; encParams->LayerHeight[i] = encOption->encHeight[i]; encParams->LayerWidth[i] = encOption->encWidth[i]; } diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp index a5c7f5ee5c..5cf1ed3aa3 100644 --- a/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp +++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp @@ -219,6 +219,11 @@ ERROR_CODE pvmp3_framedecoder(tPVMP3DecoderExternal *pExt, if (info->error_protection) { + if (!bitsAvailable(&pVars->inputStream, 16)) + { + return SIDE_INFO_ERROR; + } + /* * Get crc content */ @@ -593,18 +598,10 @@ void fillMainDataBuf(void *pMem, int32 temp) } else { - int32 tmp1 = *(ptr++); - for (int32 nBytes = temp >> 1; nBytes != 0; nBytes--) /* read main data. */ + for (int32 nBytes = temp; nBytes != 0; nBytes--) /* read main data. */ { - int32 tmp2 = *(ptr++); - fillDataBuf(&pVars->mainDataStream, tmp1); - fillDataBuf(&pVars->mainDataStream, tmp2); - tmp1 = *(ptr++); - } - - if (temp&1) - { - fillDataBuf(&pVars->mainDataStream, tmp1); + int32 tmp = *(ptr++); + fillDataBuf(&pVars->mainDataStream, tmp); } /* adjust circular buffer counter */ @@ -613,14 +610,9 @@ void fillMainDataBuf(void *pMem, int32 temp) } else { - for (int32 nBytes = temp >> 1; nBytes != 0; nBytes--) /* read main data. */ + for (int32 nBytes = temp; nBytes != 0; nBytes--) /* read main data. */ { fillDataBuf(&pVars->mainDataStream, *(pVars->inputStream.pBuffer + module(offset++ , BUFSIZE))); - fillDataBuf(&pVars->mainDataStream, *(pVars->inputStream.pBuffer + module(offset++ , BUFSIZE))); - } - if (temp&1) - { - fillDataBuf(&pVars->mainDataStream, *(pVars->inputStream.pBuffer + module(offset , BUFSIZE))); } } diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_get_side_info.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_get_side_info.cpp index d644207924..1a3fca5edd 100644 --- a/media/libstagefright/codecs/mp3dec/src/pvmp3_get_side_info.cpp +++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_get_side_info.cpp @@ -73,6 +73,7 @@ Input #include "pvmp3_get_side_info.h" #include "pvmp3_crc.h" +#include "pvmp3_getbits.h" /*---------------------------------------------------------------------------- @@ -125,12 +126,22 @@ ERROR_CODE pvmp3_get_side_info(tmp3Bits *inputStream, { if (stereo == 1) { + if (!bitsAvailable(inputStream, 14)) + { + return SIDE_INFO_ERROR; + } + tmp = getbits_crc(inputStream, 14, crc, info->error_protection); si->main_data_begin = (tmp << 18) >> 23; /* 9 */ si->private_bits = (tmp << 27) >> 27; /* 5 */ } else { + if (!bitsAvailable(inputStream, 12)) + { + return SIDE_INFO_ERROR; + } + tmp = getbits_crc(inputStream, 12, crc, info->error_protection); si->main_data_begin = (tmp << 20) >> 23; /* 9 */ si->private_bits = (tmp << 29) >> 29; /* 3 */ @@ -139,6 +150,11 @@ ERROR_CODE pvmp3_get_side_info(tmp3Bits *inputStream, for (ch = 0; ch < stereo; ch++) { + if (!bitsAvailable(inputStream, 4)) + { + return SIDE_INFO_ERROR; + } + tmp = getbits_crc(inputStream, 4, crc, info->error_protection); si->ch[ch].scfsi[0] = (tmp << 28) >> 31; /* 1 */ si->ch[ch].scfsi[1] = (tmp << 29) >> 31; /* 1 */ @@ -150,6 +166,11 @@ ERROR_CODE pvmp3_get_side_info(tmp3Bits *inputStream, { for (ch = 0; ch < stereo; ch++) { + if (!bitsAvailable(inputStream, 34)) + { + return SIDE_INFO_ERROR; + } + si->ch[ch].gran[gr].part2_3_length = getbits_crc(inputStream, 12, crc, info->error_protection); tmp = getbits_crc(inputStream, 22, crc, info->error_protection); @@ -160,6 +181,11 @@ ERROR_CODE pvmp3_get_side_info(tmp3Bits *inputStream, if (si->ch[ch].gran[gr].window_switching_flag) { + if (!bitsAvailable(inputStream, 22)) + { + return SIDE_INFO_ERROR; + } + tmp = getbits_crc(inputStream, 22, crc, info->error_protection); si->ch[ch].gran[gr].block_type = (tmp << 10) >> 30; /* 2 */; @@ -192,6 +218,11 @@ ERROR_CODE pvmp3_get_side_info(tmp3Bits *inputStream, } else { + if (!bitsAvailable(inputStream, 22)) + { + return SIDE_INFO_ERROR; + } + tmp = getbits_crc(inputStream, 22, crc, info->error_protection); si->ch[ch].gran[gr].table_select[0] = (tmp << 10) >> 27; /* 5 */; @@ -204,6 +235,11 @@ ERROR_CODE pvmp3_get_side_info(tmp3Bits *inputStream, si->ch[ch].gran[gr].block_type = 0; } + if (!bitsAvailable(inputStream, 3)) + { + return SIDE_INFO_ERROR; + } + tmp = getbits_crc(inputStream, 3, crc, info->error_protection); si->ch[ch].gran[gr].preflag = (tmp << 29) >> 31; /* 1 */ si->ch[ch].gran[gr].scalefac_scale = (tmp << 30) >> 31; /* 1 */ @@ -213,11 +249,21 @@ ERROR_CODE pvmp3_get_side_info(tmp3Bits *inputStream, } else /* Layer 3 LSF */ { + if (!bitsAvailable(inputStream, 8 + stereo)) + { + return SIDE_INFO_ERROR; + } + si->main_data_begin = getbits_crc(inputStream, 8, crc, info->error_protection); si->private_bits = getbits_crc(inputStream, stereo, crc, info->error_protection); for (ch = 0; ch < stereo; ch++) { + if (!bitsAvailable(inputStream, 39)) + { + return SIDE_INFO_ERROR; + } + tmp = getbits_crc(inputStream, 21, crc, info->error_protection); si->ch[ch].gran[0].part2_3_length = (tmp << 11) >> 20; /* 12 */ si->ch[ch].gran[0].big_values = (tmp << 23) >> 23; /* 9 */ @@ -230,6 +276,11 @@ ERROR_CODE pvmp3_get_side_info(tmp3Bits *inputStream, if (si->ch[ch].gran[0].window_switching_flag) { + if (!bitsAvailable(inputStream, 22)) + { + return SIDE_INFO_ERROR; + } + tmp = getbits_crc(inputStream, 22, crc, info->error_protection); si->ch[ch].gran[0].block_type = (tmp << 10) >> 30; /* 2 */; @@ -262,6 +313,11 @@ ERROR_CODE pvmp3_get_side_info(tmp3Bits *inputStream, } else { + if (!bitsAvailable(inputStream, 22)) + { + return SIDE_INFO_ERROR; + } + tmp = getbits_crc(inputStream, 22, crc, info->error_protection); si->ch[ch].gran[0].table_select[0] = (tmp << 10) >> 27; /* 5 */; @@ -274,6 +330,11 @@ ERROR_CODE pvmp3_get_side_info(tmp3Bits *inputStream, si->ch[ch].gran[0].block_type = 0; } + if (!bitsAvailable(inputStream, 2)) + { + return SIDE_INFO_ERROR; + } + tmp = getbits_crc(inputStream, 2, crc, info->error_protection); si->ch[ch].gran[0].scalefac_scale = tmp >> 1; /* 1 */ si->ch[ch].gran[0].count1table_select = tmp & 1; /* 1 */ diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.cpp index 8ff79538b5..4d252efdbe 100644 --- a/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.cpp +++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.cpp @@ -113,10 +113,11 @@ uint32 getNbits(tmp3Bits *ptBitStream, uint32 offset; uint32 bitIndex; - uint8 Elem; /* Needs to be same type as pInput->pBuffer */ - uint8 Elem1; - uint8 Elem2; - uint8 Elem3; + uint32 bytesToFetch; + uint8 Elem = 0; /* Needs to be same type as pInput->pBuffer */ + uint8 Elem1 = 0; + uint8 Elem2 = 0; + uint8 Elem3 = 0; uint32 returnValue = 0; if (!neededBits) @@ -126,10 +127,25 @@ uint32 getNbits(tmp3Bits *ptBitStream, offset = (ptBitStream->usedBits) >> INBUF_ARRAY_INDEX_SHIFT; - Elem = *(ptBitStream->pBuffer + module(offset , BUFSIZE)); - Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE)); - Elem2 = *(ptBitStream->pBuffer + module(offset + 2, BUFSIZE)); - Elem3 = *(ptBitStream->pBuffer + module(offset + 3, BUFSIZE)); + /* Remove extra high bits by shifting up */ + bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH); + + bytesToFetch = (bitIndex + neededBits + 7 ) >> 3 ; + + switch (bytesToFetch) + { + case 4: + Elem3 = *(ptBitStream->pBuffer + module(offset + 3, BUFSIZE)); + [[fallthrough]]; + case 3: + Elem2 = *(ptBitStream->pBuffer + module(offset + 2, BUFSIZE)); + [[fallthrough]]; + case 2: + Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE)); + [[fallthrough]]; + case 1: + Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE)); + } returnValue = (((uint32)(Elem)) << 24) | @@ -137,9 +153,6 @@ uint32 getNbits(tmp3Bits *ptBitStream, (((uint32)(Elem2)) << 8) | ((uint32)(Elem3)); - /* Remove extra high bits by shifting up */ - bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH); - /* This line is faster than to mask off the high bits. */ returnValue <<= bitIndex; @@ -161,22 +174,32 @@ uint16 getUpTo9bits(tmp3Bits *ptBitStream, uint32 offset; uint32 bitIndex; - uint8 Elem; /* Needs to be same type as pInput->pBuffer */ - uint8 Elem1; + uint32 bytesToFetch; + uint8 Elem = 0; /* Needs to be same type as pInput->pBuffer */ + uint8 Elem1 = 0; uint16 returnValue; offset = (ptBitStream->usedBits) >> INBUF_ARRAY_INDEX_SHIFT; - Elem = *(ptBitStream->pBuffer + module(offset , BUFSIZE)); - Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE)); + /* Remove extra high bits by shifting up */ + bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH); + + bytesToFetch = (bitIndex + neededBits + 7 ) >> 3 ; + + if (bytesToFetch > 1) + { + Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE)); + Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE)); + } + else if (bytesToFetch > 0) + { + Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE)); + } returnValue = (((uint16)(Elem)) << 8) | ((uint16)(Elem1)); - /* Remove extra high bits by shifting up */ - bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH); - ptBitStream->usedBits += neededBits; /* This line is faster than to mask off the high bits. */ returnValue = (returnValue << (bitIndex)); @@ -197,25 +220,40 @@ uint32 getUpTo17bits(tmp3Bits *ptBitStream, uint32 offset; uint32 bitIndex; - uint8 Elem; /* Needs to be same type as pInput->pBuffer */ - uint8 Elem1; - uint8 Elem2; + uint32 bytesToFetch; + uint8 Elem = 0; /* Needs to be same type as pInput->pBuffer */ + uint8 Elem1 = 0; + uint8 Elem2 = 0; uint32 returnValue; offset = (ptBitStream->usedBits) >> INBUF_ARRAY_INDEX_SHIFT; - Elem = *(ptBitStream->pBuffer + module(offset , BUFSIZE)); - Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE)); - Elem2 = *(ptBitStream->pBuffer + module(offset + 2, BUFSIZE)); + /* Remove extra high bits by shifting up */ + bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH); + + bytesToFetch = (bitIndex + neededBits + 7 ) >> 3 ; + + if (bytesToFetch > 2) + { + Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE)); + Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE)); + Elem2 = *(ptBitStream->pBuffer + module(offset + 2, BUFSIZE)); + } + else if (bytesToFetch > 1) + { + Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE)); + Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE)); + } + else if (bytesToFetch > 0) + { + Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE)); + } returnValue = (((uint32)(Elem)) << 16) | (((uint32)(Elem1)) << 8) | ((uint32)(Elem2)); - /* Remove extra high bits by shifting up */ - bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH); - ptBitStream->usedBits += neededBits; /* This line is faster than to mask off the high bits. */ returnValue = 0xFFFFFF & (returnValue << (bitIndex)); diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.h b/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.h index b058b007c8..b04fe6d7ea 100644 --- a/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.h +++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.h @@ -104,6 +104,11 @@ extern "C" ; Function Prototype declaration ----------------------------------------------------------------------------*/ +static inline bool bitsAvailable(tmp3Bits *inputStream, uint32 neededBits) +{ + return (inputStream->inputBufferCurrentLength << 3) >= (neededBits + inputStream->usedBits); +} + /*---------------------------------------------------------------------------- ; END ----------------------------------------------------------------------------*/ diff --git a/media/libstagefright/foundation/ABuffer.cpp b/media/libstagefright/foundation/ABuffer.cpp index c8965d9109..c79384cb0f 100644 --- a/media/libstagefright/foundation/ABuffer.cpp +++ b/media/libstagefright/foundation/ABuffer.cpp @@ -67,7 +67,7 @@ ABuffer::~ABuffer() { void ABuffer::setRange(size_t offset, size_t size) { CHECK_LE(offset, mCapacity); - CHECK_LE(offset + size, mCapacity); + CHECK_LE(size, mCapacity - offset); mRangeOffset = offset; mRangeLength = size; diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h index f7e6c27e0c..7614ba5e6b 100644 --- a/media/libstagefright/include/media/stagefright/MediaCodec.h +++ b/media/libstagefright/include/media/stagefright/MediaCodec.h @@ -366,6 +366,8 @@ private: AString mOwnerName; sp<MediaCodecInfo> mCodecInfo; sp<AReplyToken> mReplyID; + std::string mLastReplyOrigin; + std::vector<sp<AMessage>> mDeferredMessages; uint32_t mFlags; status_t mStickyError; sp<Surface> mSurface; @@ -428,13 +430,17 @@ private: std::shared_ptr<BufferChannelBase> mBufferChannel; - MediaCodec(const sp<ALooper> &looper, pid_t pid, uid_t uid); + MediaCodec( + const sp<ALooper> &looper, pid_t pid, uid_t uid, + std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase = nullptr, + std::function<status_t(const AString &, sp<MediaCodecInfo> *)> getCodecInfo = nullptr); static sp<CodecBase> GetCodecBase(const AString &name, const char *owner = nullptr); static status_t PostAndAwaitResponse( const sp<AMessage> &msg, sp<AMessage> *response); + void PostReplyWithError(const sp<AMessage> &msg, int32_t err); void PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err); status_t init(const AString &name); @@ -445,6 +451,7 @@ private: size_t updateBuffers(int32_t portIndex, const sp<AMessage> &msg); status_t onQueueInputBuffer(const sp<AMessage> &msg); status_t onReleaseOutputBuffer(const sp<AMessage> &msg); + BufferInfo *peekNextPortBuffer(int32_t portIndex); ssize_t dequeuePortBuffer(int32_t portIndex); status_t getBufferAndFormat( @@ -476,6 +483,7 @@ private: status_t onSetParameters(const sp<AMessage> ¶ms); status_t amendOutputFormatWithCodecSpecificData(const sp<MediaCodecBuffer> &buffer); + void handleOutputFormatChangeIfNeeded(const sp<MediaCodecBuffer> &buffer); bool isExecuting() const; uint64_t getGraphicBufferSize(); @@ -484,6 +492,9 @@ private: bool hasPendingBuffer(int portIndex); bool hasPendingBuffer(); + void postPendingRepliesAndDeferredMessages(std::string origin, status_t err = OK); + void postPendingRepliesAndDeferredMessages(std::string origin, const sp<AMessage> &response); + /* called to get the last codec error when the sticky flag is set. * if no such codec error is found, returns UNKNOWN_ERROR. */ @@ -569,6 +580,10 @@ private: Histogram mLatencyHist; + std::function<sp<CodecBase>(const AString &, const char *)> mGetCodecBase; + std::function<status_t(const AString &, sp<MediaCodecInfo> *)> mGetCodecInfo; + friend class MediaTestHelper; + DISALLOW_EVIL_CONSTRUCTORS(MediaCodec); }; diff --git a/media/libstagefright/include/media/stagefright/MediaCodecListWriter.h b/media/libstagefright/include/media/stagefright/MediaCodecListWriter.h index f53b23e95c..bf85d7eb3c 100644 --- a/media/libstagefright/include/media/stagefright/MediaCodecListWriter.h +++ b/media/libstagefright/include/media/stagefright/MediaCodecListWriter.h @@ -19,7 +19,6 @@ #define MEDIA_CODEC_LIST_WRITER_H_ #include <media/stagefright/foundation/ABase.h> -#include <media/stagefright/MediaCodecListWriter.h> #include <media/MediaCodecInfo.h> #include <utils/Errors.h> @@ -65,6 +64,7 @@ private: std::vector<sp<MediaCodecInfo>> mCodecInfos; friend struct MediaCodecList; + friend class MediaTestHelper; }; /** diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h index 227cead0e8..d8f2b001b9 100644 --- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h +++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h @@ -47,12 +47,14 @@ struct NuMediaExtractor : public RefBase { SAMPLE_FLAG_ENCRYPTED = 2, }; + typedef IMediaExtractor::EntryPoint EntryPoint; + // identical to IMediaExtractor::GetTrackMetaDataFlags enum GetTrackFormatFlags { kIncludeExtensiveMetaData = 1, // reads sample table and possibly stream headers }; - NuMediaExtractor(); + explicit NuMediaExtractor(EntryPoint entryPoint); status_t setDataSource( const sp<MediaHTTPService> &httpService, @@ -128,6 +130,8 @@ private: uint32_t mTrackFlags; // bitmask of "TrackFlags" }; + const EntryPoint mEntryPoint; + mutable Mutex mLock; sp<DataSource> mDataSource; @@ -139,6 +143,8 @@ private: int64_t mTotalBitrate; // in bits/sec int64_t mDurationUs; + void setEntryPointToRemoteMediaExtractor(); + ssize_t fetchAllTrackSamples( int64_t seekTimeUs = -1ll, MediaSource::ReadOptions::SeekMode mode = diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h index 2ce7bc7b6f..25125f2659 100644 --- a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h +++ b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h @@ -42,6 +42,7 @@ public: virtual uint32_t flags() const; virtual status_t setMediaCas(const HInterfaceToken &casToken); virtual String8 name(); + virtual status_t setEntryPoint(EntryPoint entryPoint); private: MediaExtractor *mExtractor; diff --git a/media/libstagefright/include/media/stagefright/Utils.h b/media/libstagefright/include/media/stagefright/Utils.h index 2b9b7596c5..1673120721 100644 --- a/media/libstagefright/include/media/stagefright/Utils.h +++ b/media/libstagefright/include/media/stagefright/Utils.h @@ -33,7 +33,7 @@ status_t convertMetaDataToMessage( const MetaDataBase *meta, sp<AMessage> *format); status_t convertMetaDataToMessage( const sp<MetaData> &meta, sp<AMessage> *format); -void convertMessageToMetaData( +status_t convertMessageToMetaData( const sp<AMessage> &format, sp<MetaData> &meta); // Returns a pointer to the next NAL start code in buffer of size |length| starting at |data|, or diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp index ddb459f54c..44415aa8c5 100644 --- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp +++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp @@ -17,6 +17,10 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "SimpleSoftOMXComponent" #include <utils/Log.h> +#include <OMX_Core.h> +#include <OMX_Audio.h> +#include <OMX_IndexExt.h> +#include <OMX_AudioExt.h> #include <media/stagefright/omx/SimpleSoftOMXComponent.h> #include <media/stagefright/foundation/ADebug.h> @@ -74,7 +78,7 @@ bool SimpleSoftOMXComponent::isSetParameterAllowed( OMX_U32 portIndex; - switch (index) { + switch ((int)index) { case OMX_IndexParamPortDefinition: { const OMX_PARAM_PORTDEFINITIONTYPE *portDefs = @@ -108,6 +112,19 @@ bool SimpleSoftOMXComponent::isSetParameterAllowed( break; } + case OMX_IndexParamAudioAndroidAacDrcPresentation: + { + if (mState == OMX_StateInvalid) { + return false; + } + const OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE *aacPresParams = + (const OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE *)params; + if (!isValidOMXParam(aacPresParams)) { + return false; + } + return true; + } + default: return false; } diff --git a/media/libstagefright/tests/mediacodec/Android.bp b/media/libstagefright/tests/mediacodec/Android.bp new file mode 100644 index 0000000000..0bd0639092 --- /dev/null +++ b/media/libstagefright/tests/mediacodec/Android.bp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2020 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. + */ + +cc_test { + name: "mediacodecTest", + gtest: true, + + srcs: [ + "MediaCodecTest.cpp", + "MediaTestHelper.cpp", + ], + + header_libs: [ + "libmediadrm_headers", + ], + + shared_libs: [ + "libgui", + "libmedia", + "libmedia_codeclist", + "libmediametrics", + "libmediandk", + "libstagefright", + "libstagefright_codecbase", + "libstagefright_foundation", + "libutils", + ], + + static_libs: [ + "libgmock", + ], + + cflags: [ + "-Werror", + "-Wall", + ], + + sanitize: { + cfi: true, + misc_undefined: [ + "unsigned-integer-overflow", + "signed-integer-overflow", + ], + }, + + test_suites: [ + "general-tests", + ], +} diff --git a/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp b/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp new file mode 100644 index 0000000000..d00a50ff05 --- /dev/null +++ b/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <future> +#include <thread> + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <gui/Surface.h> +#include <mediadrm/ICrypto.h> +#include <media/stagefright/CodecBase.h> +#include <media/stagefright/MediaCodec.h> +#include <media/stagefright/MediaCodecListWriter.h> +#include <media/MediaCodecInfo.h> + +#include "MediaTestHelper.h" + +namespace android { + +class MockBufferChannel : public BufferChannelBase { +public: + ~MockBufferChannel() override = default; + + MOCK_METHOD(void, setCrypto, (const sp<ICrypto> &crypto), (override)); + MOCK_METHOD(void, setDescrambler, (const sp<IDescrambler> &descrambler), (override)); + MOCK_METHOD(status_t, queueInputBuffer, (const sp<MediaCodecBuffer> &buffer), (override)); + MOCK_METHOD(status_t, queueSecureInputBuffer, + (const sp<MediaCodecBuffer> &buffer, + bool secure, + const uint8_t *key, + const uint8_t *iv, + CryptoPlugin::Mode mode, + CryptoPlugin::Pattern pattern, + const CryptoPlugin::SubSample *subSamples, + size_t numSubSamples, + AString *errorDetailMsg), + (override)); + MOCK_METHOD(status_t, attachBuffer, + (const std::shared_ptr<C2Buffer> &c2Buffer, const sp<MediaCodecBuffer> &buffer), + (override)); + MOCK_METHOD(status_t, attachEncryptedBuffer, + (const sp<hardware::HidlMemory> &memory, + bool secure, + const uint8_t *key, + const uint8_t *iv, + CryptoPlugin::Mode mode, + CryptoPlugin::Pattern pattern, + size_t offset, + const CryptoPlugin::SubSample *subSamples, + size_t numSubSamples, + const sp<MediaCodecBuffer> &buffer), + (override)); + MOCK_METHOD(status_t, renderOutputBuffer, + (const sp<MediaCodecBuffer> &buffer, int64_t timestampNs), + (override)); + MOCK_METHOD(status_t, discardBuffer, (const sp<MediaCodecBuffer> &buffer), (override)); + MOCK_METHOD(void, getInputBufferArray, (Vector<sp<MediaCodecBuffer>> *array), (override)); + MOCK_METHOD(void, getOutputBufferArray, (Vector<sp<MediaCodecBuffer>> *array), (override)); +}; + +class MockCodec : public CodecBase { +public: + MockCodec(std::function<void(const std::shared_ptr<MockBufferChannel> &)> mock) { + mMockBufferChannel = std::make_shared<MockBufferChannel>(); + mock(mMockBufferChannel); + } + ~MockCodec() override = default; + + MOCK_METHOD(void, initiateAllocateComponent, (const sp<AMessage> &msg), (override)); + MOCK_METHOD(void, initiateConfigureComponent, (const sp<AMessage> &msg), (override)); + MOCK_METHOD(void, initiateCreateInputSurface, (), (override)); + MOCK_METHOD(void, initiateSetInputSurface, (const sp<PersistentSurface> &surface), (override)); + MOCK_METHOD(void, initiateStart, (), (override)); + MOCK_METHOD(void, initiateShutdown, (bool keepComponentAllocated), (override)); + MOCK_METHOD(void, onMessageReceived, (const sp<AMessage> &msg), (override)); + MOCK_METHOD(status_t, setSurface, (const sp<Surface> &surface), (override)); + MOCK_METHOD(void, signalFlush, (), (override)); + MOCK_METHOD(void, signalResume, (), (override)); + MOCK_METHOD(void, signalRequestIDRFrame, (), (override)); + MOCK_METHOD(void, signalSetParameters, (const sp<AMessage> &msg), (override)); + MOCK_METHOD(void, signalEndOfInputStream, (), (override)); + + std::shared_ptr<BufferChannelBase> getBufferChannel() override { + return mMockBufferChannel; + } + + const std::unique_ptr<CodecCallback> &callback() { + return mCallback; + } + + std::shared_ptr<MockBufferChannel> mMockBufferChannel; +}; + +class Counter { +public: + Counter() = default; + explicit Counter(int32_t initCount) : mCount(initCount) {} + ~Counter() = default; + + int32_t advance() { + std::unique_lock<std::mutex> lock(mMutex); + ++mCount; + mCondition.notify_all(); + return mCount; + } + + template <typename Rep, typename Period, typename ...Args> + int32_t waitFor(const std::chrono::duration<Rep, Period> &duration, Args... values) { + std::initializer_list<int32_t> list = {values...}; + std::unique_lock<std::mutex> lock(mMutex); + mCondition.wait_for( + lock, + duration, + [&list, this]{ + return std::find(list.begin(), list.end(), mCount) != list.end(); + }); + return mCount; + } + + template <typename ...Args> + int32_t wait(Args... values) { + std::initializer_list<int32_t> list = {values...}; + std::unique_lock<std::mutex> lock(mMutex); + mCondition.wait( + lock, + [&list, this]{ + return std::find(list.begin(), list.end(), mCount) != list.end(); + }); + return mCount; + } + +private: + std::mutex mMutex; + std::condition_variable mCondition; + int32_t mCount = 0; +}; + +} // namespace android + +using namespace android; +using ::testing::_; + +static sp<MediaCodec> SetupMediaCodec( + const AString &owner, + const AString &codecName, + const AString &mediaType, + const sp<ALooper> &looper, + std::function<sp<CodecBase>(const AString &name, const char *owner)> getCodecBase) { + std::shared_ptr<MediaCodecListWriter> listWriter = + MediaTestHelper::CreateCodecListWriter(); + std::unique_ptr<MediaCodecInfoWriter> infoWriter = listWriter->addMediaCodecInfo(); + infoWriter->setName(codecName.c_str()); + infoWriter->setOwner(owner.c_str()); + infoWriter->addMediaType(mediaType.c_str()); + std::vector<sp<MediaCodecInfo>> codecInfos; + MediaTestHelper::WriteCodecInfos(listWriter, &codecInfos); + std::function<status_t(const AString &, sp<MediaCodecInfo> *)> getCodecInfo = + [codecInfos](const AString &name, sp<MediaCodecInfo> *info) -> status_t { + auto it = std::find_if( + codecInfos.begin(), codecInfos.end(), + [&name](const sp<MediaCodecInfo> &info) { + return name.equalsIgnoreCase(info->getCodecName()); + }); + + *info = (it == codecInfos.end()) ? nullptr : *it; + return (*info) ? OK : NAME_NOT_FOUND; + }; + + looper->start(); + return MediaTestHelper::CreateCodec( + codecName, looper, getCodecBase, getCodecInfo); +} + +TEST(MediaCodecTest, ReclaimReleaseRace) { + // Test scenario: + // + // 1) ResourceManager thread calls reclaim(), message posted to + // MediaCodec looper thread. + // 2) MediaCodec looper thread calls initiateShutdown(), shutdown being + // handled at the component thread. + // 3) Client thread calls release(), message posted to & handle at + // MediaCodec looper thread. + // 4) MediaCodec looper thread may call initiateShutdown(). + // 5) initiateShutdown() from 2) is handled at onReleaseComplete() event + // posted to MediaCodec looper thread. + // 6) If called, initiateShutdown() from 4) is handled and + // onReleaseComplete() event posted to MediaCodec looper thread. + + static const AString kCodecName{"test.codec"}; + static const AString kCodecOwner{"nobody"}; + static const AString kMediaType{"video/x-test"}; + + enum { + kInit, + kShutdownFromReclaimReceived, + kReleaseCalled, + }; + Counter counter{kInit}; + sp<MockCodec> mockCodec; + std::function<sp<CodecBase>(const AString &name, const char *owner)> getCodecBase = + [&mockCodec, &counter](const AString &, const char *) { + mockCodec = new MockCodec([](const std::shared_ptr<MockBufferChannel> &) { + // No mock setup, as we don't expect any buffer operations + // in this scenario. + }); + ON_CALL(*mockCodec, initiateAllocateComponent(_)) + .WillByDefault([mockCodec](const sp<AMessage> &) { + mockCodec->callback()->onComponentAllocated(kCodecName.c_str()); + }); + ON_CALL(*mockCodec, initiateShutdown(_)) + .WillByDefault([mockCodec, &counter](bool) { + int32_t stage = counter.wait(kInit, kReleaseCalled); + if (stage == kInit) { + // Mark that 2) happened, so test can proceed to 3) + counter.advance(); + } else if (stage == kReleaseCalled) { + // Handle 6) + mockCodec->callback()->onReleaseCompleted(); + } + }); + return mockCodec; + }; + + sp<ALooper> looper{new ALooper}; + sp<MediaCodec> codec = SetupMediaCodec( + kCodecOwner, kCodecName, kMediaType, looper, getCodecBase); + ASSERT_NE(nullptr, codec) << "Codec must not be null"; + ASSERT_NE(nullptr, mockCodec) << "MockCodec must not be null"; + std::promise<void> reclaimCompleted; + std::promise<void> releaseCompleted; + Counter threadExitCounter; + std::thread([codec, &reclaimCompleted]{ + // Simulate ResourceManager thread. Proceed with 1) + MediaTestHelper::Reclaim(codec, true /* force */); + reclaimCompleted.set_value(); + }).detach(); + std::thread([codec, &counter, &releaseCompleted]{ + // Simulate client thread. Wait until 2) is complete + (void)counter.wait(kShutdownFromReclaimReceived); + // Proceed to 3), and mark that 5) is ready to happen. + // NOTE: it's difficult to pinpoint when 4) happens, so we will sleep + // to meet the timing. + counter.advance(); + codec->release(); + releaseCompleted.set_value(); + }).detach(); + std::thread([mockCodec, &counter]{ + // Simulate component thread. Wait until 3) is complete + (void)counter.wait(kReleaseCalled); + // We want 4) to complete before moving forward, but it is hard to + // wait for this exact event. Just sleep so that the other thread can + // proceed and complete 4). + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + // Proceed to 5). + mockCodec->callback()->onReleaseCompleted(); + }).detach(); + EXPECT_EQ( + std::future_status::ready, + reclaimCompleted.get_future().wait_for(std::chrono::seconds(5))) + << "reclaim timed out"; + EXPECT_EQ( + std::future_status::ready, + releaseCompleted.get_future().wait_for(std::chrono::seconds(5))) + << "release timed out"; + looper->stop(); +} + +TEST(MediaCodecTest, ErrorWhileStopping) { + // Test scenario: + // + // 1) Client thread calls stop(); MediaCodec looper thread calls + // initiateShutdown(); shutdown is being handled at the component thread. + // 2) Error occurred, but the shutdown operation is still being done. + // 3) MediaCodec looper thread handles the error. + // 4) Component thread completes shutdown and posts onStopCompleted() + + static const AString kCodecName{"test.codec"}; + static const AString kCodecOwner{"nobody"}; + static const AString kMediaType{"video/x-test"}; + + std::promise<void> errorOccurred; + sp<MockCodec> mockCodec; + std::function<sp<CodecBase>(const AString &name, const char *owner)> getCodecBase = + [&mockCodec, &errorOccurred](const AString &, const char *) { + mockCodec = new MockCodec([](const std::shared_ptr<MockBufferChannel> &) { + // No mock setup, as we don't expect any buffer operations + // in this scenario. + }); + ON_CALL(*mockCodec, initiateAllocateComponent(_)) + .WillByDefault([mockCodec](const sp<AMessage> &) { + mockCodec->callback()->onComponentAllocated(kCodecName.c_str()); + }); + ON_CALL(*mockCodec, initiateConfigureComponent(_)) + .WillByDefault([mockCodec](const sp<AMessage> &msg) { + mockCodec->callback()->onComponentConfigured( + msg->dup(), msg->dup()); + }); + ON_CALL(*mockCodec, initiateStart()) + .WillByDefault([mockCodec]() { + mockCodec->callback()->onStartCompleted(); + }); + ON_CALL(*mockCodec, initiateShutdown(true)) + .WillByDefault([mockCodec, &errorOccurred](bool) { + mockCodec->callback()->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); + // Mark that 1) and 2) are complete. + errorOccurred.set_value(); + }); + ON_CALL(*mockCodec, initiateShutdown(false)) + .WillByDefault([mockCodec](bool) { + mockCodec->callback()->onReleaseCompleted(); + }); + return mockCodec; + }; + + sp<ALooper> looper{new ALooper}; + sp<MediaCodec> codec = SetupMediaCodec( + kCodecOwner, kCodecName, kMediaType, looper, getCodecBase); + ASSERT_NE(nullptr, codec) << "Codec must not be null"; + ASSERT_NE(nullptr, mockCodec) << "MockCodec must not be null"; + + std::thread([mockCodec, &errorOccurred]{ + // Simulate component thread that handles stop() + errorOccurred.get_future().wait(); + // Error occurred but shutdown request still got processed. + mockCodec->callback()->onStopCompleted(); + }).detach(); + + codec->configure(new AMessage, nullptr, nullptr, 0); + codec->start(); + codec->stop(); + // Sleep here to give time for the MediaCodec looper thread + // to process the messages. + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + codec->release(); + looper->stop(); +} diff --git a/media/libstagefright/tests/mediacodec/MediaTestHelper.cpp b/media/libstagefright/tests/mediacodec/MediaTestHelper.cpp new file mode 100644 index 0000000000..bbe3c05783 --- /dev/null +++ b/media/libstagefright/tests/mediacodec/MediaTestHelper.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <media/stagefright/MediaCodec.h> +#include <media/stagefright/MediaCodecListWriter.h> + +#include "MediaTestHelper.h" + +namespace android { + +// static +sp<MediaCodec> MediaTestHelper::CreateCodec( + const AString &name, + const sp<ALooper> &looper, + std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase, + std::function<status_t(const AString &, sp<MediaCodecInfo> *)> getCodecInfo) { + sp<MediaCodec> codec = new MediaCodec( + looper, MediaCodec::kNoPid, MediaCodec::kNoUid, getCodecBase, getCodecInfo); + if (codec->init(name) != OK) { + return nullptr; + } + return codec; +} + +// static +void MediaTestHelper::Reclaim(const sp<MediaCodec> &codec, bool force) { + codec->reclaim(force); +} + +// static +std::shared_ptr<MediaCodecListWriter> MediaTestHelper::CreateCodecListWriter() { + return std::shared_ptr<MediaCodecListWriter>(new MediaCodecListWriter); +} + +// static +void MediaTestHelper::WriteCodecInfos( + const std::shared_ptr<MediaCodecListWriter> &writer, + std::vector<sp<MediaCodecInfo>> *codecInfos) { + writer->writeCodecInfos(codecInfos); +} + +} // namespace android diff --git a/media/libstagefright/tests/mediacodec/MediaTestHelper.h b/media/libstagefright/tests/mediacodec/MediaTestHelper.h new file mode 100644 index 0000000000..f3d61106ba --- /dev/null +++ b/media/libstagefright/tests/mediacodec/MediaTestHelper.h @@ -0,0 +1,51 @@ +/* + * Copyright 2020, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MEDIA_TEST_HELPER_H_ + +#define MEDIA_TEST_HELPER_H_ + +#include <media/stagefright/foundation/AString.h> +#include <utils/StrongPointer.h> + +namespace android { + +struct ALooper; +struct CodecBase; +struct MediaCodec; +struct MediaCodecInfo; +struct MediaCodecListWriter; + +class MediaTestHelper { +public: + // MediaCodec + static sp<MediaCodec> CreateCodec( + const AString &name, + const sp<ALooper> &looper, + std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase, + std::function<status_t(const AString &, sp<MediaCodecInfo> *)> getCodecInfo); + static void Reclaim(const sp<MediaCodec> &codec, bool force); + + // MediaCodecListWriter + static std::shared_ptr<MediaCodecListWriter> CreateCodecListWriter(); + static void WriteCodecInfos( + const std::shared_ptr<MediaCodecListWriter> &writer, + std::vector<sp<MediaCodecInfo>> *codecInfos); +}; + +} // namespace android + +#endif // MEDIA_TEST_HELPER_H_ diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp index 0da0740fc9..0c65e9e552 100644 --- a/media/ndk/NdkMediaExtractor.cpp +++ b/media/ndk/NdkMediaExtractor.cpp @@ -22,6 +22,7 @@ #include <media/NdkMediaExtractor.h> #include <media/NdkMediaErrorPriv.h> #include <media/NdkMediaFormatPriv.h> +#include "NdkJavaVMHelperPriv.h" #include "NdkMediaDataSourcePriv.h" @@ -63,7 +64,10 @@ EXPORT AMediaExtractor* AMediaExtractor_new() { ALOGV("ctor"); AMediaExtractor *mData = new AMediaExtractor(); - mData->mImpl = new NuMediaExtractor(); + mData->mImpl = new NuMediaExtractor( + NdkJavaVMHelper::getJNIEnv() != nullptr + ? NuMediaExtractor::EntryPoint::NDK_WITH_JVM + : NuMediaExtractor::EntryPoint::NDK_NO_JVM ); return mData; } diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp index 87ea084811..7699700b14 100644 --- a/media/utils/ServiceUtilities.cpp +++ b/media/utils/ServiceUtilities.cpp @@ -62,7 +62,7 @@ static String16 resolveCallingPackage(PermissionController& permissionController } static bool checkRecordingInternal(const String16& opPackageName, pid_t pid, - uid_t uid, bool start) { + uid_t uid, bool start, bool isHotwordSource) { // Okay to not track in app ops as audio server or media server is us and if // device is rooted security model is considered compromised. // system_server loses its RECORD_AUDIO permission when a secondary @@ -87,16 +87,21 @@ static bool checkRecordingInternal(const String16& opPackageName, pid_t pid, } AppOpsManager appOps; - const int32_t op = appOps.permissionToOpCode(sAndroidPermissionRecordAudio); + const int32_t opRecordAudio = appOps.permissionToOpCode(sAndroidPermissionRecordAudio); + if (start) { + const int32_t op = isHotwordSource ? + AppOpsManager::OP_RECORD_AUDIO_HOTWORD : opRecordAudio; if (appOps.startOpNoThrow(op, uid, resolvedOpPackageName, /*startIfModeDefault*/ false) != AppOpsManager::MODE_ALLOWED) { ALOGE("Request denied by app op: %d", op); return false; } } else { - if (appOps.checkOp(op, uid, resolvedOpPackageName) != AppOpsManager::MODE_ALLOWED) { - ALOGE("Request denied by app op: %d", op); + // Always use OP_RECORD_AUDIO for checks at creation time. + if (appOps.checkOp(opRecordAudio, uid, resolvedOpPackageName) + != AppOpsManager::MODE_ALLOWED) { + ALOGE("Request denied by app op: %d", opRecordAudio); return false; } } @@ -105,14 +110,15 @@ static bool checkRecordingInternal(const String16& opPackageName, pid_t pid, } bool recordingAllowed(const String16& opPackageName, pid_t pid, uid_t uid) { - return checkRecordingInternal(opPackageName, pid, uid, /*start*/ false); + return checkRecordingInternal(opPackageName, pid, uid, /*start*/ false, + /*is_hotword_source*/ false); } -bool startRecording(const String16& opPackageName, pid_t pid, uid_t uid) { - return checkRecordingInternal(opPackageName, pid, uid, /*start*/ true); +bool startRecording(const String16& opPackageName, pid_t pid, uid_t uid, bool isHotwordSource) { + return checkRecordingInternal(opPackageName, pid, uid, /*start*/ true, isHotwordSource); } -void finishRecording(const String16& opPackageName, uid_t uid) { +void finishRecording(const String16& opPackageName, uid_t uid, bool isHotwordSource) { // Okay to not track in app ops as audio server is us and if // device is rooted security model is considered compromised. if (isAudioServerOrRootUid(uid)) return; @@ -125,7 +131,8 @@ void finishRecording(const String16& opPackageName, uid_t uid) { } AppOpsManager appOps; - const int32_t op = appOps.permissionToOpCode(sAndroidPermissionRecordAudio); + const int32_t op = isHotwordSource ? AppOpsManager::OP_RECORD_AUDIO_HOTWORD + : appOps.permissionToOpCode(sAndroidPermissionRecordAudio); appOps.finishOp(op, uid, resolvedOpPackageName); } diff --git a/media/utils/TimeCheck.cpp b/media/utils/TimeCheck.cpp index 59d74de942..819e1468ea 100644 --- a/media/utils/TimeCheck.cpp +++ b/media/utils/TimeCheck.cpp @@ -39,10 +39,9 @@ void TimeCheck::accessAudioHalPids(std::vector<pid_t>* pids, bool update) { static std::atomic<int> curAudioHalPids = 0; if (update) { - audioHalPids[(curAudioHalPids + 1) % kNumAudioHalPidsVectors] = *pids; - curAudioHalPids++; + audioHalPids[(curAudioHalPids++ + 1) % kNumAudioHalPidsVectors] = *pids; } else { - *pids = audioHalPids[curAudioHalPids]; + *pids = audioHalPids[curAudioHalPids % kNumAudioHalPidsVectors]; } } diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h index 212599a159..431dd7ae76 100644 --- a/media/utils/include/mediautils/ServiceUtilities.h +++ b/media/utils/include/mediautils/ServiceUtilities.h @@ -79,8 +79,8 @@ static inline bool isAudioServerOrMediaServerUid(uid_t uid) { } bool recordingAllowed(const String16& opPackageName, pid_t pid, uid_t uid); -bool startRecording(const String16& opPackageName, pid_t pid, uid_t uid); -void finishRecording(const String16& opPackageName, uid_t uid); +bool startRecording(const String16& opPackageName, pid_t pid, uid_t uid, bool isHotwordSource); +void finishRecording(const String16& opPackageName, uid_t uid, bool isHotwordSource); bool captureAudioOutputAllowed(pid_t pid, uid_t uid); bool captureMediaOutputAllowed(pid_t pid, uid_t uid); bool captureVoiceCommunicationOutputAllowed(pid_t pid, uid_t uid); diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index f0142096e5..764fdc33c0 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -852,7 +852,8 @@ sp<IAudioTrack> AudioFlinger::createTrack(const CreateTrackInput& input, input.notificationsPerBuffer, input.speed, input.sharedBuffer, sessionId, &output.flags, callingPid, input.clientInfo.clientTid, clientUid, - &lStatus, portId, input.audioTrackCallback); + &lStatus, portId, input.audioTrackCallback, + input.opPackageName); LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (track == 0)); // we don't abort yet if lStatus != NO_ERROR; there is still work to be done regardless @@ -2068,8 +2069,8 @@ sp<media::IAudioRecord> AudioFlinger::createRecord(const CreateRecordInput& inpu Mutex::Autolock _l(mLock); RecordThread *thread = checkRecordThread_l(output.inputId); if (thread == NULL) { - ALOGE("createRecord() checkRecordThread_l failed, input handle %d", output.inputId); - lStatus = BAD_VALUE; + ALOGW("createRecord() checkRecordThread_l failed, input handle %d", output.inputId); + lStatus = FAILED_TRANSACTION; goto Exit; } diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h index d8eebf3f61..a2df29b29b 100644 --- a/services/audioflinger/PlaybackTracks.h +++ b/services/audioflinger/PlaybackTracks.h @@ -26,10 +26,11 @@ public: bool hasOpPlayAudio() const; static sp<OpPlayAudioMonitor> createIfNeeded( - uid_t uid, const audio_attributes_t& attr, int id, audio_stream_type_t streamType); + uid_t uid, const audio_attributes_t& attr, int id, audio_stream_type_t streamType, + const std::string& opPackageName); private: - OpPlayAudioMonitor(uid_t uid, audio_usage_t usage, int id); + OpPlayAudioMonitor(uid_t uid, audio_usage_t usage, int id, const String16& opPackageName); void onFirstRef() override; static void getPackagesForUid(uid_t uid, Vector<String16>& packages); @@ -49,10 +50,10 @@ private: void checkPlayAudioForUsage(); std::atomic_bool mHasOpPlayAudio; - Vector<String16> mPackages; const uid_t mUid; const int32_t mUsage; // on purpose not audio_usage_t because always checked in appOps as int32_t const int mId; // for logging purposes only + const String16 mOpPackageName; }; // playback track @@ -77,7 +78,8 @@ public: audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE, /** default behaviour is to start when there are as many frames * ready as possible (aka. Buffer is full). */ - size_t frameCountToBeReady = SIZE_MAX); + size_t frameCountToBeReady = SIZE_MAX, + const std::string opPackageName = ""); virtual ~Track(); virtual status_t initCheck() const; diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 2af27d8a30..1d0147d56b 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -2067,7 +2067,8 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac uid_t uid, status_t *status, audio_port_handle_t portId, - const sp<media::IAudioTrackCallback>& callback) + const sp<media::IAudioTrackCallback>& callback, + const std::string& opPackageName) { size_t frameCount = *pFrameCount; size_t notificationFrameCount = *pNotificationFrameCount; @@ -2348,7 +2349,8 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac track = new Track(this, client, streamType, attr, sampleRate, format, channelMask, frameCount, nullptr /* buffer */, (size_t)0 /* bufferSize */, sharedBuffer, - sessionId, creatorPid, uid, *flags, TrackBase::TYPE_DEFAULT, portId); + sessionId, creatorPid, uid, *flags, TrackBase::TYPE_DEFAULT, portId, + SIZE_MAX /*frameCountToBeReady*/, opPackageName); lStatus = track != 0 ? track->initCheck() : (status_t) NO_MEMORY; if (lStatus != NO_ERROR) { @@ -2360,7 +2362,7 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac { Mutex::Autolock _atCbL(mAudioTrackCbLock); if (callback.get() != nullptr) { - mAudioTrackCallbacks.emplace(callback); + mAudioTrackCallbacks.emplace(track, callback); } } @@ -2588,6 +2590,10 @@ void AudioFlinger::PlaybackThread::removeTrack_l(const sp<Track>& track) mLocalLog.log("removeTrack_l (%p) %s", track.get(), result.string()); mTracks.remove(track); + { + Mutex::Autolock _atCbL(mAudioTrackCbLock); + mAudioTrackCallbacks.erase(track); + } if (track->isFastTrack()) { int index = track->mFastIndex; ALOG_ASSERT(0 < index && index < (int)FastMixerState::sMaxFastTracks); @@ -2683,8 +2689,8 @@ void AudioFlinger::PlaybackThread::onCodecFormatChanged( audio_utils::metadata::byteStringFromData(metadata); std::vector metadataVec(metaDataStr.begin(), metaDataStr.end()); Mutex::Autolock _l(mAudioTrackCbLock); - for (const auto& callback : mAudioTrackCallbacks) { - callback->onCodecFormatChanged(metadataVec); + for (const auto& callbackPair : mAudioTrackCallbacks) { + callbackPair.second->onCodecFormatChanged(metadataVec); } }).detach(); } @@ -7869,7 +7875,8 @@ status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrac AutoMutex lock(mLock); if (recordTrack->isInvalid()) { recordTrack->clearSyncStartEvent(); - return INVALID_OPERATION; + ALOGW("%s track %d: invalidated before startInput", __func__, recordTrack->portId()); + return DEAD_OBJECT; } if (mActiveTracks.indexOf(recordTrack) >= 0) { if (recordTrack->mState == TrackBase::PAUSING) { @@ -7899,7 +7906,8 @@ status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrac recordTrack->mState = TrackBase::STARTING_2; // STARTING_2 forces destroy to call stopInput. } - return INVALID_OPERATION; + ALOGW("%s track %d: invalidated after startInput", __func__, recordTrack->portId()); + return DEAD_OBJECT; } if (recordTrack->mState != TrackBase::STARTING_1) { ALOGW("%s(%d): unsynchronized mState:%d change", diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index c1ac2e45b3..6b33ad5c2e 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -864,7 +864,8 @@ public: uid_t uid, status_t *status /*non-NULL*/, audio_port_handle_t portId, - const sp<media::IAudioTrackCallback>& callback); + const sp<media::IAudioTrackCallback>& callback, + const std::string& opPackageName); AudioStreamOut* getOutput() const; AudioStreamOut* clearOutput(); @@ -1186,7 +1187,7 @@ private: Mutex mAudioTrackCbLock; // Record of IAudioTrackCallback - std::set<sp<media::IAudioTrackCallback>> mAudioTrackCallbacks; + std::map<sp<Track>, sp<media::IAudioTrackCallback>> mAudioTrackCallbacks; private: // The HAL output sink is treated as non-blocking, but current implementation is blocking diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 126015ffc7..f286d8a61d 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -386,11 +386,12 @@ status_t AudioFlinger::TrackHandle::onTransact( // static sp<AudioFlinger::PlaybackThread::OpPlayAudioMonitor> AudioFlinger::PlaybackThread::OpPlayAudioMonitor::createIfNeeded( - uid_t uid, const audio_attributes_t& attr, int id, audio_stream_type_t streamType) + uid_t uid, const audio_attributes_t& attr, int id, audio_stream_type_t streamType, + const std::string& opPackageName) { + Vector <String16> packages; + getPackagesForUid(uid, packages); if (isServiceUid(uid)) { - Vector <String16> packages; - getPackagesForUid(uid, packages); if (packages.isEmpty()) { ALOGD("OpPlayAudio: not muting track:%d usage:%d for service UID %d", id, @@ -410,12 +411,32 @@ AudioFlinger::PlaybackThread::OpPlayAudioMonitor::createIfNeeded( id, attr.flags); return nullptr; } - return new OpPlayAudioMonitor(uid, attr.usage, id); + + String16 opPackageNameStr(opPackageName.c_str()); + if (opPackageName.empty()) { + // If no package name is provided by the client, use the first associated with the uid + if (!packages.isEmpty()) { + opPackageNameStr = packages[0]; + } + } else { + // If the provided package name is invalid, we force app ops denial by clearing the package + // name passed to OpPlayAudioMonitor + if (std::find_if(packages.begin(), packages.end(), + [&opPackageNameStr](const auto& package) { + return opPackageNameStr == package; }) == packages.end()) { + ALOGW("The package name(%s) provided does not correspond to the uid %d, " + "force muting the track", opPackageName.c_str(), uid); + // Set package name as an empty string so that hasOpPlayAudio will always return false. + opPackageNameStr = String16(""); + } + } + return new OpPlayAudioMonitor(uid, attr.usage, id, opPackageNameStr); } AudioFlinger::PlaybackThread::OpPlayAudioMonitor::OpPlayAudioMonitor( - uid_t uid, audio_usage_t usage, int id) - : mHasOpPlayAudio(true), mUid(uid), mUsage((int32_t) usage), mId(id) + uid_t uid, audio_usage_t usage, int id, const String16& opPackageName) + : mHasOpPlayAudio(true), mUid(uid), mUsage((int32_t) usage), mId(id), + mOpPackageName(opPackageName) { } @@ -429,11 +450,10 @@ AudioFlinger::PlaybackThread::OpPlayAudioMonitor::~OpPlayAudioMonitor() void AudioFlinger::PlaybackThread::OpPlayAudioMonitor::onFirstRef() { - getPackagesForUid(mUid, mPackages); checkPlayAudioForUsage(); - if (!mPackages.isEmpty()) { + if (mOpPackageName.size() != 0) { mOpCallback = new PlayAudioOpCallback(this); - mAppOpsManager.startWatchingMode(AppOpsManager::OP_PLAY_AUDIO, mPackages[0], mOpCallback); + mAppOpsManager.startWatchingMode(AppOpsManager::OP_PLAY_AUDIO, mOpPackageName, mOpCallback); } } @@ -446,18 +466,11 @@ bool AudioFlinger::PlaybackThread::OpPlayAudioMonitor::hasOpPlayAudio() const { // - not called from PlayAudioOpCallback because the callback is not installed in this case void AudioFlinger::PlaybackThread::OpPlayAudioMonitor::checkPlayAudioForUsage() { - if (mPackages.isEmpty()) { + if (mOpPackageName.size() == 0) { mHasOpPlayAudio.store(false); } else { - bool hasIt = true; - for (const String16& packageName : mPackages) { - const int32_t mode = mAppOpsManager.checkAudioOpNoThrow(AppOpsManager::OP_PLAY_AUDIO, - mUsage, mUid, packageName); - if (mode != AppOpsManager::MODE_ALLOWED) { - hasIt = false; - break; - } - } + bool hasIt = mAppOpsManager.checkAudioOpNoThrow(AppOpsManager::OP_PLAY_AUDIO, + mUsage, mUid, mOpPackageName) == AppOpsManager::MODE_ALLOWED; ALOGD("OpPlayAudio: track:%d usage:%d %smuted", mId, mUsage, hasIt ? "not " : ""); mHasOpPlayAudio.store(hasIt); } @@ -511,7 +524,8 @@ AudioFlinger::PlaybackThread::Track::Track( audio_output_flags_t flags, track_type type, audio_port_handle_t portId, - size_t frameCountToBeReady) + size_t frameCountToBeReady, + const std::string opPackageName) : TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount, // TODO: Using unsecurePointer() has some associated security pitfalls // (see declaration for details). @@ -534,7 +548,8 @@ AudioFlinger::PlaybackThread::Track::Track( mPresentationCompleteFrames(0), mFrameMap(16 /* sink-frame-to-track-frame map memory */), mVolumeHandler(new media::VolumeHandler(sampleRate)), - mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded(uid, attr, id(), streamType)), + mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded( + uid, attr, id(), streamType, opPackageName)), // mSinkTimestamp mFrameCountToBeReady(frameCountToBeReady), mFastIndex(-1), @@ -598,7 +613,7 @@ AudioFlinger::PlaybackThread::Track::Track( if (channelMask & AUDIO_CHANNEL_HAPTIC_ALL) { mAudioVibrationController = new AudioVibrationController(this); mExternalVibration = new os::ExternalVibration( - mUid, "" /* pkg */, mAttr, mAudioVibrationController); + mUid, opPackageName, mAttr, mAudioVibrationController); } // Once this item is logged by the server, the client can add properties. @@ -2207,7 +2222,8 @@ status_t AudioFlinger::RecordThread::RecordTrack::start(AudioSystem::sync_event_ RecordThread *recordThread = (RecordThread *)thread.get(); return recordThread->start(this, event, triggerSession); } else { - return BAD_VALUE; + ALOGW("%s track %d: thread was destroyed", __func__, portId()); + return DEAD_OBJECT; } } diff --git a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h index 981582e022..1821140f17 100644 --- a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h +++ b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h @@ -136,7 +136,7 @@ const engineConfig::ProductStrategies gOrderedSystemStrategies = { {"rerouting", { {"", AUDIO_STREAM_REROUTING, "AUDIO_STREAM_REROUTING", - {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, 0, ""}} + {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_VIRTUAL_SOURCE, AUDIO_SOURCE_DEFAULT, 0, ""}} } }, }, diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index c5c13e9a5a..a592dea65c 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -2256,7 +2256,7 @@ status_t AudioPolicyManager::startInput(audio_port_handle_t portId) sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId); if (inputDesc == 0) { ALOGW("%s no input for client %d", __FUNCTION__, portId); - return BAD_VALUE; + return DEAD_OBJECT; } audio_io_handle_t input = inputDesc->mIoHandle; sp<RecordClientDescriptor> client = inputDesc->getClient(portId); @@ -3161,6 +3161,8 @@ void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) { DeviceVector newDevices = getNewOutputDevices(mPrimaryOutput, true /*fromCache*/); waitMs = updateCallRouting(newDevices, delayMs); + // Only apply special touch sound delay once + delayMs = 0; } for (size_t i = 0; i < mOutputs.size(); i++) { sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(i); @@ -3170,6 +3172,8 @@ void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint // preventing the force re-routing in case of default dev that distinguishes on address. // Let's give back to engine full device choice decision however. waitMs = setOutputDevices(outputDesc, newDevices, !newDevices.isEmpty(), delayMs); + // Only apply special touch sound delay once + delayMs = 0; } if (forceVolumeReeval && !newDevices.isEmpty()) { applyStreamVolumes(outputDesc, newDevices.types(), waitMs, true); @@ -5648,7 +5652,7 @@ uint32_t AudioPolicyManager::setBeaconMute(bool mute) { sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); setVolumeSourceMute(ttsVolumeSource, mute/*on*/, desc, 0 /*delay*/, DeviceTypeSet()); const uint32_t latency = desc->latency() * 2; - if (latency > maxLatency) { + if (desc->isActive(latency * 2) && latency > maxLatency) { maxLatency = latency; } } @@ -6143,9 +6147,8 @@ status_t AudioPolicyManager::checkAndSetVolume(IVolumeCurves &curves, float volumeDb = computeVolume(curves, volumeSource, index, deviceTypes); if (outputDesc->isFixedVolume(deviceTypes) || - // Force VoIP volume to max for bluetooth SCO - - ((isVoiceVolSrc || isBtScoVolSrc) && + // Force VoIP volume to max for bluetooth SCO device except if muted + (index != 0 && (isVoiceVolSrc || isBtScoVolSrc) && isSingleDeviceType(deviceTypes, audio_is_bluetooth_out_sco_device))) { volumeDb = 0.0f; } diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp index 1ec0c5e3ba..b738633924 100644 --- a/services/audiopolicy/service/AudioPolicyEffects.cpp +++ b/services/audiopolicy/service/AudioPolicyEffects.cpp @@ -121,8 +121,8 @@ status_t AudioPolicyEffects::addInputEffects(audio_io_handle_t input, Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects; for (size_t i = 0; i < effects.size(); i++) { EffectDesc *effect = effects[i]; - sp<AudioEffect> fx = new AudioEffect(NULL, String16("android"), &effect->mUuid, -1, 0, - 0, audioSession, input); + sp<AudioEffect> fx = new AudioEffect(String16("android")); + fx->set(NULL, &effect->mUuid, -1, 0, 0, audioSession, input); status_t status = fx->initCheck(); if (status != NO_ERROR && status != ALREADY_EXISTS) { ALOGW("addInputEffects(): failed to create Fx %s on source %d", @@ -270,8 +270,8 @@ status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output, Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects; for (size_t i = 0; i < effects.size(); i++) { EffectDesc *effect = effects[i]; - sp<AudioEffect> fx = new AudioEffect(NULL, String16("android"), &effect->mUuid, 0, 0, 0, - audioSession, output); + sp<AudioEffect> fx = new AudioEffect(String16("android")); + fx->set(NULL, &effect->mUuid, 0, 0, 0, audioSession, output); status_t status = fx->initCheck(); if (status != NO_ERROR && status != ALREADY_EXISTS) { ALOGE("addOutputSessionEffects(): failed to create Fx %s on session %d", @@ -970,11 +970,11 @@ void AudioPolicyEffects::initDefaultDeviceEffects() for (const auto& deviceEffectsIter : mDeviceEffects) { const auto& deviceEffects = deviceEffectsIter.second; for (const auto& effectDesc : deviceEffects->mEffectDescriptors->mEffects) { - auto fx = std::make_unique<AudioEffect>( - EFFECT_UUID_NULL, String16("android"), &effectDesc->mUuid, 0, nullptr, - nullptr, AUDIO_SESSION_DEVICE, AUDIO_IO_HANDLE_NONE, - AudioDeviceTypeAddr{deviceEffects->getDeviceType(), - deviceEffects->getDeviceAddress()}); + auto fx = std::make_unique<AudioEffect>(String16("android")); + fx->set(EFFECT_UUID_NULL, &effectDesc->mUuid, 0, nullptr, + nullptr, AUDIO_SESSION_DEVICE, AUDIO_IO_HANDLE_NONE, + AudioDeviceTypeAddr{deviceEffects->getDeviceType(), + deviceEffects->getDeviceAddress()}); status_t status = fx->initCheck(); if (status != NO_ERROR && status != ALREADY_EXISTS) { ALOGE("%s(): failed to create Fx %s on port type=%d address=%s", __func__, diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index 34d07b6d76..df27f6e519 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -572,7 +572,8 @@ status_t AudioPolicyService::startInput(audio_port_handle_t portId) } // check calling permissions - if (!(startRecording(client->opPackageName, client->pid, client->uid) + if (!(startRecording(client->opPackageName, client->pid, client->uid, + client->attributes.source == AUDIO_SOURCE_HOTWORD) || client->attributes.source == AUDIO_SOURCE_FM_TUNER)) { ALOGE("%s permission denied: recording not allowed for uid %d pid %d", __func__, client->uid, client->pid); @@ -660,7 +661,8 @@ status_t AudioPolicyService::startInput(audio_port_handle_t portId) client->active = false; client->startTimeNs = 0; updateUidStates_l(); - finishRecording(client->opPackageName, client->uid); + finishRecording(client->opPackageName, client->uid, + client->attributes.source == AUDIO_SOURCE_HOTWORD); } return status; @@ -686,7 +688,8 @@ status_t AudioPolicyService::stopInput(audio_port_handle_t portId) updateUidStates_l(); // finish the recording app op - finishRecording(client->opPackageName, client->uid); + finishRecording(client->opPackageName, client->uid, + client->attributes.source == AUDIO_SOURCE_HOTWORD); AutoCallerClear acc; return mAudioPolicyManager->stopInput(portId); } diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp index e847f9f9c9..a6e8989722 100644 --- a/services/audiopolicy/service/AudioPolicyService.cpp +++ b/services/audiopolicy/service/AudioPolicyService.cpp @@ -488,9 +488,9 @@ void AudioPolicyService::updateUidStates_l() } bool isAccessibility = mUidPolicy->isA11yUid(current->uid); - // Clients capturing for Accessibility services are not considered + // Clients capturing for Accessibility services or virtual sources are not considered // for top or latest active to avoid masking regular clients started before - if (!isAccessibility) { + if (!isAccessibility && !isVirtualSource(current->attributes.source)) { bool isAssistant = mUidPolicy->isAssistantUid(current->uid); bool isPrivacySensitive = (current->attributes.flags & AUDIO_FLAG_CAPTURE_PRIVATE) != 0; diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index af1e01d8e1..24288d6baf 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -3751,9 +3751,14 @@ void CameraService::updateStatus(StatusInternal status, const String8& cameraId, __FUNCTION__, cameraId.string()); return; } + + // Collect the logical cameras without holding mStatusLock in updateStatus + // as that can lead to a deadlock(b/162192331). + auto logicalCameraIds = getLogicalCameras(cameraId); // Update the status for this camera state, then send the onStatusChangedCallbacks to each // of the listeners with both the mStatusLock and mStatusListenerLock held - state->updateStatus(status, cameraId, rejectSourceStates, [this, &deviceKind, &supportsHAL3] + state->updateStatus(status, cameraId, rejectSourceStates, [this, &deviceKind, &supportsHAL3, + &logicalCameraIds] (const String8& cameraId, StatusInternal status) { if (status != StatusInternal::ENUMERATING) { @@ -3773,8 +3778,8 @@ void CameraService::updateStatus(StatusInternal status, const String8& cameraId, } Mutex::Autolock lock(mStatusListenerLock); - - notifyPhysicalCameraStatusLocked(mapToInterface(status), cameraId, deviceKind); + notifyPhysicalCameraStatusLocked(mapToInterface(status), String16(cameraId), + logicalCameraIds, deviceKind); for (auto& listener : mListenerList) { bool isVendorListener = listener->isVendorListener(); @@ -3892,8 +3897,9 @@ status_t CameraService::setTorchStatusLocked(const String8& cameraId, return OK; } -void CameraService::notifyPhysicalCameraStatusLocked(int32_t status, const String8& cameraId, - SystemCameraKind deviceKind) { +std::list<String16> CameraService::getLogicalCameras( + const String8& physicalCameraId) { + std::list<String16> retList; Mutex::Autolock lock(mCameraStatesLock); for (const auto& state : mCameraStates) { std::vector<std::string> physicalCameraIds; @@ -3901,26 +3907,39 @@ void CameraService::notifyPhysicalCameraStatusLocked(int32_t status, const Strin // This is not a logical multi-camera. continue; } - if (std::find(physicalCameraIds.begin(), physicalCameraIds.end(), cameraId.c_str()) + if (std::find(physicalCameraIds.begin(), physicalCameraIds.end(), physicalCameraId.c_str()) == physicalCameraIds.end()) { // cameraId is not a physical camera of this logical multi-camera. continue; } - String16 id16(state.first), physicalId16(cameraId); + retList.emplace_back(String16(state.first)); + } + return retList; +} + +void CameraService::notifyPhysicalCameraStatusLocked(int32_t status, + const String16& physicalCameraId, const std::list<String16>& logicalCameraIds, + SystemCameraKind deviceKind) { + // mStatusListenerLock is expected to be locked + for (const auto& logicalCameraId : logicalCameraIds) { for (auto& listener : mListenerList) { + // Note: we check only the deviceKind of the physical camera id + // since, logical camera ids and their physical camera ids are + // guaranteed to have the same system camera kind. if (shouldSkipStatusUpdates(deviceKind, listener->isVendorListener(), listener->getListenerPid(), listener->getListenerUid())) { ALOGV("Skipping discovery callback for system-only camera device %s", - cameraId.c_str()); + String8(physicalCameraId).c_str()); continue; } listener->getListener()->onPhysicalCameraStatusChanged(status, - id16, physicalId16); + logicalCameraId, physicalCameraId); } } } + void CameraService::blockClientsForUid(uid_t uid) { const auto clients = mActiveClientManager.getAll(); for (auto& current : clients) { diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 4321201100..685ed5ee1d 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -49,6 +49,7 @@ #include <set> #include <string> +#include <list> #include <map> #include <memory> #include <utility> @@ -1005,8 +1006,13 @@ private: hardware::camera::common::V1_0::TorchModeStatus status); // notify physical camera status when the physical camera is public. - void notifyPhysicalCameraStatusLocked(int32_t status, const String8& cameraId, - SystemCameraKind deviceKind); + // Expects mStatusListenerLock to be locked. + void notifyPhysicalCameraStatusLocked(int32_t status, const String16& physicalCameraId, + const std::list<String16>& logicalCameraIds, SystemCameraKind deviceKind); + + // get list of logical cameras which are backed by physicalCameraId + std::list<String16> getLogicalCameras(const String8& physicalCameraId); + // IBinder::DeathRecipient implementation virtual void binderDied(const wp<IBinder> &who); diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp index a63f402bb2..2462fd5295 100644 --- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp +++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp @@ -65,7 +65,6 @@ HeicCompositeStream::HeicCompositeStream(sp<CameraDeviceBase> device, mYuvBufferAcquired(false), mProducerListener(new ProducerListener()), mDequeuedOutputBufferCnt(0), - mLockedAppSegmentBufferCnt(0), mCodecOutputCounter(0), mQuality(-1), mGridTimestampUs(0), @@ -634,7 +633,6 @@ void HeicCompositeStream::compilePendingInputLocked() { mAppSegmentConsumer->unlockBuffer(imgBuffer); } else { mPendingInputFrames[frameNumber].appSegmentBuffer = imgBuffer; - mLockedAppSegmentBufferCnt++; } mInputAppSegmentBuffers.erase(it); mAppSegmentFrameNumbers.pop(); @@ -897,10 +895,6 @@ status_t HeicCompositeStream::processInputFrame(int64_t frameNumber, strerror(-res), res); return res; } - } else if (mLockedAppSegmentBufferCnt == kMaxAcquiredAppSegment) { - ALOGE("%s: Out-of-order app segment buffers reaches limit %u", __FUNCTION__, - kMaxAcquiredAppSegment); - return INVALID_OPERATION; } } @@ -1038,7 +1032,6 @@ status_t HeicCompositeStream::processAppSegment(int64_t frameNumber, InputFrame mAppSegmentConsumer->unlockBuffer(inputFrame.appSegmentBuffer); inputFrame.appSegmentBuffer.data = nullptr; inputFrame.exifError = false; - mLockedAppSegmentBufferCnt--; return OK; } diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.h b/services/camera/libcameraservice/api2/HeicCompositeStream.h index 33ca69a40b..a3731273f8 100644 --- a/services/camera/libcameraservice/api2/HeicCompositeStream.h +++ b/services/camera/libcameraservice/api2/HeicCompositeStream.h @@ -253,7 +253,6 @@ private: // Keep all incoming APP segment Blob buffer pending further processing. std::vector<int64_t> mInputAppSegmentBuffers; - int32_t mLockedAppSegmentBufferCnt; // Keep all incoming HEIC blob buffer pending further processing. std::vector<CodecOutputBufferInfo> mCodecOutputBuffers; diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp index 32d118d6b0..876d70d7cf 100644 --- a/services/camera/libcameraservice/common/CameraProviderManager.cpp +++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp @@ -1344,6 +1344,20 @@ status_t CameraProviderManager::ProviderInfo::initialize( } } + // cameraDeviceStatusChange callbacks may be called (and causing new devices added) + // before setCallback returns + hardware::Return<Status> status = interface->setCallback(this); + if (!status.isOk()) { + ALOGE("%s: Transaction error setting up callbacks with camera provider '%s': %s", + __FUNCTION__, mProviderName.c_str(), status.description().c_str()); + return DEAD_OBJECT; + } + if (status != Status::OK) { + ALOGE("%s: Unable to register callbacks with camera provider '%s'", + __FUNCTION__, mProviderName.c_str()); + return mapToStatusT(status); + } + hardware::Return<bool> linked = interface->linkToDeath(this, /*cookie*/ mId); if (!linked.isOk()) { ALOGE("%s: Transaction error in linking to camera provider '%s' death: %s", @@ -1372,7 +1386,6 @@ status_t CameraProviderManager::ProviderInfo::initialize( return res; } - Status status; // Get initial list of camera devices, if any std::vector<std::string> devices; hardware::Return<void> ret = interface->getCameraIdList([&status, this, &devices]( @@ -1437,26 +1450,43 @@ status_t CameraProviderManager::ProviderInfo::initialize( } } - // cameraDeviceStatusChange callbacks may be called (and causing new devices added) - // before setCallback returns. setCallback must be called after addDevice so that - // the physical camera status callback can look up available regular - // cameras. - hardware::Return<Status> st = interface->setCallback(this); - if (!st.isOk()) { - ALOGE("%s: Transaction error setting up callbacks with camera provider '%s': %s", - __FUNCTION__, mProviderName.c_str(), st.description().c_str()); - return DEAD_OBJECT; - } - if (st != Status::OK) { - ALOGE("%s: Unable to register callbacks with camera provider '%s'", - __FUNCTION__, mProviderName.c_str()); - return mapToStatusT(st); - } - ALOGI("Camera provider %s ready with %zu camera devices", mProviderName.c_str(), mDevices.size()); - mInitialized = true; + // Process cached status callbacks + std::unique_ptr<std::vector<CameraStatusInfoT>> cachedStatus = + std::make_unique<std::vector<CameraStatusInfoT>>(); + { + std::lock_guard<std::mutex> lock(mInitLock); + + for (auto& statusInfo : mCachedStatus) { + std::string id, physicalId; + status_t res = OK; + if (statusInfo.isPhysicalCameraStatus) { + res = physicalCameraDeviceStatusChangeLocked(&id, &physicalId, + statusInfo.cameraId, statusInfo.physicalCameraId, statusInfo.status); + } else { + res = cameraDeviceStatusChangeLocked(&id, statusInfo.cameraId, statusInfo.status); + } + if (res == OK) { + cachedStatus->emplace_back(statusInfo.isPhysicalCameraStatus, + id.c_str(), physicalId.c_str(), statusInfo.status); + } + } + mCachedStatus.clear(); + + mInitialized = true; + } + + // The cached status change callbacks cannot be fired directly from this + // function, due to same-thread deadlock trying to acquire mInterfaceMutex + // twice. + if (listener != nullptr) { + mInitialStatusCallbackFuture = std::async(std::launch::async, + &CameraProviderManager::ProviderInfo::notifyInitialStatusChange, this, + listener, std::move(cachedStatus)); + } + return OK; } @@ -1734,104 +1764,139 @@ hardware::Return<void> CameraProviderManager::ProviderInfo::cameraDeviceStatusCh CameraDeviceStatus newStatus) { sp<StatusListener> listener; std::string id; - bool initialized = false; + std::lock_guard<std::mutex> lock(mInitLock); + + if (!mInitialized) { + mCachedStatus.emplace_back(false /*isPhysicalCameraStatus*/, + cameraDeviceName.c_str(), std::string().c_str(), newStatus); + return hardware::Void(); + } + { std::lock_guard<std::mutex> lock(mLock); - bool known = false; - for (auto& deviceInfo : mDevices) { - if (deviceInfo->mName == cameraDeviceName) { - ALOGI("Camera device %s status is now %s, was %s", cameraDeviceName.c_str(), - deviceStatusToString(newStatus), deviceStatusToString(deviceInfo->mStatus)); - deviceInfo->mStatus = newStatus; - // TODO: Handle device removal (NOT_PRESENT) - id = deviceInfo->mId; - known = true; - break; - } - } - // Previously unseen device; status must not be NOT_PRESENT - if (!known) { - if (newStatus == CameraDeviceStatus::NOT_PRESENT) { - ALOGW("Camera provider %s says an unknown camera device %s is not present. Curious.", - mProviderName.c_str(), cameraDeviceName.c_str()); - return hardware::Void(); - } - addDevice(cameraDeviceName, newStatus, &id); - } else if (newStatus == CameraDeviceStatus::NOT_PRESENT) { - removeDevice(id); + if (OK != cameraDeviceStatusChangeLocked(&id, cameraDeviceName, newStatus)) { + return hardware::Void(); } listener = mManager->getStatusListener(); - initialized = mInitialized; - if (reCacheConcurrentStreamingCameraIdsLocked() != OK) { - ALOGE("%s: CameraProvider %s could not re-cache concurrent streaming camera id list ", - __FUNCTION__, mProviderName.c_str()); - } } + // Call without lock held to allow reentrancy into provider manager - // Don't send the callback if providerInfo hasn't been initialized. - // CameraService will initialize device status after provider is - // initialized - if (listener != nullptr && initialized) { + if (listener != nullptr) { listener->onDeviceStatusChanged(String8(id.c_str()), newStatus); } + return hardware::Void(); } +status_t CameraProviderManager::ProviderInfo::cameraDeviceStatusChangeLocked( + std::string* id, const hardware::hidl_string& cameraDeviceName, + CameraDeviceStatus newStatus) { + bool known = false; + std::string cameraId; + for (auto& deviceInfo : mDevices) { + if (deviceInfo->mName == cameraDeviceName) { + ALOGI("Camera device %s status is now %s, was %s", cameraDeviceName.c_str(), + deviceStatusToString(newStatus), deviceStatusToString(deviceInfo->mStatus)); + deviceInfo->mStatus = newStatus; + // TODO: Handle device removal (NOT_PRESENT) + cameraId = deviceInfo->mId; + known = true; + break; + } + } + // Previously unseen device; status must not be NOT_PRESENT + if (!known) { + if (newStatus == CameraDeviceStatus::NOT_PRESENT) { + ALOGW("Camera provider %s says an unknown camera device %s is not present. Curious.", + mProviderName.c_str(), cameraDeviceName.c_str()); + return BAD_VALUE; + } + addDevice(cameraDeviceName, newStatus, &cameraId); + } else if (newStatus == CameraDeviceStatus::NOT_PRESENT) { + removeDevice(cameraId); + } + if (reCacheConcurrentStreamingCameraIdsLocked() != OK) { + ALOGE("%s: CameraProvider %s could not re-cache concurrent streaming camera id list ", + __FUNCTION__, mProviderName.c_str()); + } + *id = cameraId; + return OK; +} + hardware::Return<void> CameraProviderManager::ProviderInfo::physicalCameraDeviceStatusChange( const hardware::hidl_string& cameraDeviceName, const hardware::hidl_string& physicalCameraDeviceName, CameraDeviceStatus newStatus) { sp<StatusListener> listener; std::string id; - bool initialized = false; + std::string physicalId; + std::lock_guard<std::mutex> lock(mInitLock); + + if (!mInitialized) { + mCachedStatus.emplace_back(true /*isPhysicalCameraStatus*/, cameraDeviceName, + physicalCameraDeviceName, newStatus); + return hardware::Void(); + } + { std::lock_guard<std::mutex> lock(mLock); - bool known = false; - for (auto& deviceInfo : mDevices) { - if (deviceInfo->mName == cameraDeviceName) { - id = deviceInfo->mId; - if (!deviceInfo->mIsLogicalCamera) { - ALOGE("%s: Invalid combination of camera id %s, physical id %s", - __FUNCTION__, id.c_str(), physicalCameraDeviceName.c_str()); - return hardware::Void(); - } - if (std::find(deviceInfo->mPhysicalIds.begin(), deviceInfo->mPhysicalIds.end(), - physicalCameraDeviceName) == deviceInfo->mPhysicalIds.end()) { - ALOGE("%s: Invalid combination of camera id %s, physical id %s", - __FUNCTION__, id.c_str(), physicalCameraDeviceName.c_str()); - return hardware::Void(); - } - ALOGI("Camera device %s physical device %s status is now %s, was %s", - cameraDeviceName.c_str(), physicalCameraDeviceName.c_str(), - deviceStatusToString(newStatus), deviceStatusToString( - deviceInfo->mPhysicalStatus[physicalCameraDeviceName])); - known = true; - break; - } - } - // Previously unseen device; status must not be NOT_PRESENT - if (!known) { - ALOGW("Camera provider %s says an unknown camera device %s-%s is not present. Curious.", - mProviderName.c_str(), cameraDeviceName.c_str(), - physicalCameraDeviceName.c_str()); + if (OK != physicalCameraDeviceStatusChangeLocked(&id, &physicalId, cameraDeviceName, + physicalCameraDeviceName, newStatus)) { return hardware::Void(); } + listener = mManager->getStatusListener(); - initialized = mInitialized; } // Call without lock held to allow reentrancy into provider manager - // Don't send the callback if providerInfo hasn't been initialized. - // CameraService will initialize device status after provider is - // initialized - if (listener != nullptr && initialized) { - String8 physicalId(physicalCameraDeviceName.c_str()); + if (listener != nullptr) { listener->onDeviceStatusChanged(String8(id.c_str()), - physicalId, newStatus); + String8(physicalId.c_str()), newStatus); } return hardware::Void(); } +status_t CameraProviderManager::ProviderInfo::physicalCameraDeviceStatusChangeLocked( + std::string* id, std::string* physicalId, + const hardware::hidl_string& cameraDeviceName, + const hardware::hidl_string& physicalCameraDeviceName, + CameraDeviceStatus newStatus) { + bool known = false; + std::string cameraId; + for (auto& deviceInfo : mDevices) { + if (deviceInfo->mName == cameraDeviceName) { + cameraId = deviceInfo->mId; + if (!deviceInfo->mIsLogicalCamera) { + ALOGE("%s: Invalid combination of camera id %s, physical id %s", + __FUNCTION__, cameraId.c_str(), physicalCameraDeviceName.c_str()); + return BAD_VALUE; + } + if (std::find(deviceInfo->mPhysicalIds.begin(), deviceInfo->mPhysicalIds.end(), + physicalCameraDeviceName) == deviceInfo->mPhysicalIds.end()) { + ALOGE("%s: Invalid combination of camera id %s, physical id %s", + __FUNCTION__, cameraId.c_str(), physicalCameraDeviceName.c_str()); + return BAD_VALUE; + } + ALOGI("Camera device %s physical device %s status is now %s", + cameraDeviceName.c_str(), physicalCameraDeviceName.c_str(), + deviceStatusToString(newStatus)); + known = true; + break; + } + } + // Previously unseen device; status must not be NOT_PRESENT + if (!known) { + ALOGW("Camera provider %s says an unknown camera device %s-%s is not present. Curious.", + mProviderName.c_str(), cameraDeviceName.c_str(), + physicalCameraDeviceName.c_str()); + return BAD_VALUE; + } + + *id = cameraId; + *physicalId = physicalCameraDeviceName.c_str(); + return OK; +} + hardware::Return<void> CameraProviderManager::ProviderInfo::torchModeStatusChange( const hardware::hidl_string& cameraDeviceName, TorchModeStatus newStatus) { @@ -1986,6 +2051,20 @@ status_t CameraProviderManager::ProviderInfo::isConcurrentSessionConfigurationSu return INVALID_OPERATION; } +void CameraProviderManager::ProviderInfo::notifyInitialStatusChange( + sp<StatusListener> listener, + std::unique_ptr<std::vector<CameraStatusInfoT>> cachedStatus) { + for (auto& statusInfo : *cachedStatus) { + if (statusInfo.isPhysicalCameraStatus) { + listener->onDeviceStatusChanged(String8(statusInfo.cameraId.c_str()), + String8(statusInfo.physicalCameraId.c_str()), statusInfo.status); + } else { + listener->onDeviceStatusChanged( + String8(statusInfo.cameraId.c_str()), statusInfo.status); + } + } +} + template<class DeviceInfoT> std::unique_ptr<CameraProviderManager::ProviderInfo::DeviceInfo> CameraProviderManager::ProviderInfo::initializeDeviceInfo( @@ -2689,9 +2768,11 @@ status_t CameraProviderManager::ProviderInfo::parseDeviceName(const std::string& CameraProviderManager::ProviderInfo::~ProviderInfo() { + if (mInitialStatusCallbackFuture.valid()) { + mInitialStatusCallbackFuture.wait(); + } // Destruction of ProviderInfo is only supposed to happen when the respective // CameraProvider interface dies, so do not unregister callbacks. - } status_t CameraProviderManager::mapToStatusT(const Status& s) { diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h index 25d36393ac..a0e5f8fb51 100644 --- a/services/camera/libcameraservice/common/CameraProviderManager.h +++ b/services/camera/libcameraservice/common/CameraProviderManager.h @@ -22,6 +22,7 @@ #include <unordered_set> #include <string> #include <mutex> +#include <future> #include <camera/camera2/ConcurrentCamera.h> #include <camera/CameraParameters2.h> @@ -403,6 +404,15 @@ private: const hardware::hidl_string& physicalCameraDeviceName, hardware::camera::common::V1_0::CameraDeviceStatus newStatus) override; + status_t cameraDeviceStatusChangeLocked( + std::string* id, const hardware::hidl_string& cameraDeviceName, + hardware::camera::common::V1_0::CameraDeviceStatus newStatus); + status_t physicalCameraDeviceStatusChangeLocked( + std::string* id, std::string* physicalId, + const hardware::hidl_string& cameraDeviceName, + const hardware::hidl_string& physicalCameraDeviceName, + hardware::camera::common::V1_0::CameraDeviceStatus newStatus); + // hidl_death_recipient interface - this locks the parent mInterfaceMutex virtual void serviceDied(uint64_t cookie, const wp<hidl::base::V1_0::IBase>& who) override; @@ -444,8 +454,6 @@ private: const hardware::camera::common::V1_0::CameraResourceCost mResourceCost; hardware::camera::common::V1_0::CameraDeviceStatus mStatus; - std::map<std::string, hardware::camera::common::V1_0::CameraDeviceStatus> - mPhysicalStatus; wp<ProviderInfo> mParentProvider; @@ -600,7 +608,27 @@ private: CameraProviderManager *mManager; + struct CameraStatusInfoT { + bool isPhysicalCameraStatus = false; + hardware::hidl_string cameraId; + hardware::hidl_string physicalCameraId; + hardware::camera::common::V1_0::CameraDeviceStatus status; + CameraStatusInfoT(bool isForPhysicalCamera, const hardware::hidl_string& id, + const hardware::hidl_string& physicalId, + hardware::camera::common::V1_0::CameraDeviceStatus s) : + isPhysicalCameraStatus(isForPhysicalCamera), cameraId(id), + physicalCameraId(physicalId), status(s) {} + }; + + // Lock to synchronize between initialize() and camera status callbacks + std::mutex mInitLock; bool mInitialized = false; + std::vector<CameraStatusInfoT> mCachedStatus; + // End of scope for mInitLock + + std::future<void> mInitialStatusCallbackFuture; + void notifyInitialStatusChange(sp<StatusListener> listener, + std::unique_ptr<std::vector<CameraStatusInfoT>> cachedStatus); std::vector<std::unordered_set<std::string>> mConcurrentCameraIdCombinations; diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 4a509aa745..d5f136b84d 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -1833,10 +1833,12 @@ status_t Camera3Device::waitUntilStateThenRelock(bool active, nsecs_t timeout) { mStatusWaiters++; + bool signalPipelineDrain = false; if (!active && mUseHalBufManager) { auto streamIds = mOutputStreams.getStreamIds(); if (mStatus == STATUS_ACTIVE) { mRequestThread->signalPipelineDrain(streamIds); + signalPipelineDrain = true; } mRequestBufferSM.onWaitUntilIdle(); } @@ -1866,6 +1868,10 @@ status_t Camera3Device::waitUntilStateThenRelock(bool active, nsecs_t timeout) { } } while (!stateSeen); + if (signalPipelineDrain) { + mRequestThread->resetPipelineDrain(); + } + mStatusWaiters--; return res; @@ -2306,6 +2312,15 @@ sp<Camera3Device::CaptureRequest> Camera3Device::createCaptureRequest( newRequest->mRotateAndCropAuto = false; } + auto zoomRatioEntry = + newRequest->mSettingsList.begin()->metadata.find(ANDROID_CONTROL_ZOOM_RATIO); + if (zoomRatioEntry.count > 0 && + zoomRatioEntry.data.f[0] == 1.0f) { + newRequest->mZoomRatioIs1x = true; + } else { + newRequest->mZoomRatioIs1x = false; + } + return newRequest; } @@ -4426,13 +4441,17 @@ status_t Camera3Device::RequestThread::prepareHalRequests() { parent->mDistortionMappers.end()) { continue; } - res = parent->mDistortionMappers[it->cameraId].correctCaptureRequest( - &(it->metadata)); - if (res != OK) { - SET_ERR("RequestThread: Unable to correct capture requests " - "for lens distortion for request %d: %s (%d)", - halRequest->frame_number, strerror(-res), res); - return INVALID_OPERATION; + + if (!captureRequest->mDistortionCorrectionUpdated) { + res = parent->mDistortionMappers[it->cameraId].correctCaptureRequest( + &(it->metadata)); + if (res != OK) { + SET_ERR("RequestThread: Unable to correct capture requests " + "for lens distortion for request %d: %s (%d)", + halRequest->frame_number, strerror(-res), res); + return INVALID_OPERATION; + } + captureRequest->mDistortionCorrectionUpdated = true; } } @@ -4443,21 +4462,24 @@ status_t Camera3Device::RequestThread::prepareHalRequests() { continue; } - camera_metadata_entry_t e = it->metadata.find(ANDROID_CONTROL_ZOOM_RATIO); - if (e.count > 0 && e.data.f[0] != 1.0f) { + if (!captureRequest->mZoomRatioIs1x) { cameraIdsWithZoom.insert(it->cameraId); } - res = parent->mZoomRatioMappers[it->cameraId].updateCaptureRequest( - &(it->metadata)); - if (res != OK) { - SET_ERR("RequestThread: Unable to correct capture requests " - "for zoom ratio for request %d: %s (%d)", - halRequest->frame_number, strerror(-res), res); - return INVALID_OPERATION; + if (!captureRequest->mZoomRatioUpdated) { + res = parent->mZoomRatioMappers[it->cameraId].updateCaptureRequest( + &(it->metadata)); + if (res != OK) { + SET_ERR("RequestThread: Unable to correct capture requests " + "for zoom ratio for request %d: %s (%d)", + halRequest->frame_number, strerror(-res), res); + return INVALID_OPERATION; + } + captureRequest->mZoomRatioUpdated = true; } } - if (captureRequest->mRotateAndCropAuto) { + if (captureRequest->mRotateAndCropAuto && + !captureRequest->mRotationAndCropUpdated) { for (it = captureRequest->mSettingsList.begin(); it != captureRequest->mSettingsList.end(); it++) { auto mapper = parent->mRotateAndCropMappers.find(it->cameraId); @@ -4471,6 +4493,7 @@ status_t Camera3Device::RequestThread::prepareHalRequests() { } } } + captureRequest->mRotationAndCropUpdated = true; } } } @@ -4785,6 +4808,12 @@ void Camera3Device::RequestThread::signalPipelineDrain(const std::vector<int>& s mStreamIdsToBeDrained = streamIds; } +void Camera3Device::RequestThread::resetPipelineDrain() { + Mutex::Autolock pl(mPauseLock); + mNotifyPipelineDrain = false; + mStreamIdsToBeDrained.clear(); +} + void Camera3Device::RequestThread::clearPreviousRequest() { Mutex::Autolock l(mRequestLock); mPrevRequest.clear(); diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index 408f1f9be2..e10da2c41b 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -517,6 +517,19 @@ class Camera3Device : // overriding of ROTATE_AND_CROP value and adjustment of coordinates // in several other controls in both the request and the result bool mRotateAndCropAuto; + // Whether this capture request has its zoom ratio set to 1.0x before + // the framework overrides it for camera HAL consumption. + bool mZoomRatioIs1x; + + + // Whether this capture request's distortion correction update has + // been done. + bool mDistortionCorrectionUpdated = false; + // Whether this capture request's rotation and crop update has been + // done. + bool mRotationAndCropUpdated = false; + // Whether this capture request's zoom ratio update has been done. + bool mZoomRatioUpdated = false; }; typedef List<sp<CaptureRequest> > RequestList; @@ -832,6 +845,7 @@ class Camera3Device : } void signalPipelineDrain(const std::vector<int>& streamIds); + void resetPipelineDrain(); status_t switchToOffline( const std::vector<int32_t>& streamsToKeep, diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp index eea5ef158d..08cde5dc16 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp +++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp @@ -1218,13 +1218,13 @@ void requestStreamBuffers(RequestBufferStates& states, return; } + bufRet.streamId = streamId; if (outputStream->isAbandoned()) { bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED); allReqsSucceeds = false; continue; } - bufRet.streamId = streamId; size_t handOutBufferCount = outputStream->getOutstandingBuffersCount(); uint32_t numBuffersRequested = bufReq.numBuffersRequested; size_t totalHandout = handOutBufferCount + numBuffersRequested; diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp index a87de7742c..4e98bf6c59 100644 --- a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp +++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp @@ -153,6 +153,19 @@ status_t ZoomRatioMapper::updateCaptureRequest(CameraMetadata* request) { entry = request->find(ANDROID_CONTROL_ZOOM_RATIO); if (entry.count == 1 && entry.data.f[0] != 1.0f) { zoomRatioIs1 = false; + + // If cropRegion is windowboxing, override it with activeArray + camera_metadata_entry_t cropRegionEntry = request->find(ANDROID_SCALER_CROP_REGION); + if (cropRegionEntry.count == 4) { + int cropWidth = cropRegionEntry.data.i32[2]; + int cropHeight = cropRegionEntry.data.i32[3]; + if (cropWidth < mArrayWidth && cropHeight < mArrayHeight) { + cropRegionEntry.data.i32[0] = 0; + cropRegionEntry.data.i32[1] = 0; + cropRegionEntry.data.i32[2] = mArrayWidth; + cropRegionEntry.data.i32[3] = mArrayHeight; + } + } } if (mHalSupportsZoomRatio && zoomRatioIs1) { diff --git a/services/mediametrics/Android.bp b/services/mediametrics/Android.bp index f033d5cabe..91590e1136 100644 --- a/services/mediametrics/Android.bp +++ b/services/mediametrics/Android.bp @@ -131,6 +131,7 @@ cc_library_shared { "statsd_codec.cpp", "statsd_drm.cpp", "statsd_extractor.cpp", + "statsd_mediaparser.cpp", "statsd_nuplayer.cpp", "statsd_recorder.cpp", "StringUtils.cpp" diff --git a/services/mediametrics/AudioPowerUsage.cpp b/services/mediametrics/AudioPowerUsage.cpp index cca6b41edc..33dfa8fa0f 100644 --- a/services/mediametrics/AudioPowerUsage.cpp +++ b/services/mediametrics/AudioPowerUsage.cpp @@ -200,6 +200,34 @@ bool AudioPowerUsage::saveAsItem_l( return true; } +bool AudioPowerUsage::saveAsItems_l( + int32_t device, int64_t duration_ns, int32_t type, double average_vol) +{ + ALOGV("%s: (%#x, %d, %lld, %f)", __func__, device, type, + (long long)duration_ns, average_vol ); + if (duration_ns == 0) { + return true; // skip duration 0 usage + } + if (device == 0) { + return true; //ignore unknown device + } + + bool ret = false; + const int32_t input_bit = device & INPUT_DEVICE_BIT; + int32_t device_bits = device ^ input_bit; + + while (device_bits != 0) { + int32_t tmp_device = device_bits & -device_bits; // get lowest bit + device_bits ^= tmp_device; // clear lowest bit + tmp_device |= input_bit; // restore input bit + ret = saveAsItem_l(tmp_device, duration_ns, type, average_vol); + + ALOGV("%s: device %#x recorded, remaining device_bits = %#x", __func__, + tmp_device, device_bits); + } + return ret; +} + void AudioPowerUsage::checkTrackRecord( const std::shared_ptr<const mediametrics::Item>& item, bool isTrack) { @@ -245,7 +273,7 @@ void AudioPowerUsage::checkTrackRecord( ALOGV("device = %s => %d", device_strings.c_str(), device); } std::lock_guard l(mLock); - saveAsItem_l(device, deviceTimeNs, type, deviceVolume); + saveAsItems_l(device, deviceTimeNs, type, deviceVolume); } void AudioPowerUsage::checkMode(const std::shared_ptr<const mediametrics::Item>& item) @@ -262,7 +290,7 @@ void AudioPowerUsage::checkMode(const std::shared_ptr<const mediametrics::Item>& if (durationNs > 0) { mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) + mVoiceVolume * double(endCallNs - mVolumeTimeNs)) / durationNs; - saveAsItem_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume); + saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume); } } else if (mode == "AUDIO_MODE_IN_CALL") { // entering call mode mStartCallNs = item->getTimestamp(); // advisory only @@ -321,7 +349,7 @@ void AudioPowerUsage::checkCreatePatch(const std::shared_ptr<const mediametrics: if (durationNs > 0) { mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) + mVoiceVolume * double(endDeviceNs - mVolumeTimeNs)) / durationNs; - saveAsItem_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume); + saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume); } // reset statistics mDeviceVolume = 0; diff --git a/services/mediametrics/AudioPowerUsage.h b/services/mediametrics/AudioPowerUsage.h index 446ff4f8bd..b705a6a234 100644 --- a/services/mediametrics/AudioPowerUsage.h +++ b/services/mediametrics/AudioPowerUsage.h @@ -85,6 +85,8 @@ private: REQUIRES(mLock); static void sendItem(const std::shared_ptr<const mediametrics::Item>& item); void collect(); + bool saveAsItems_l(int32_t device, int64_t duration, int32_t type, double average_vol) + REQUIRES(mLock); AudioAnalytics * const mAudioAnalytics; const bool mDisabled; diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp index 48e766ef21..bf6e4289fa 100644 --- a/services/mediametrics/MediaMetricsService.cpp +++ b/services/mediametrics/MediaMetricsService.cpp @@ -468,6 +468,7 @@ bool MediaMetricsService::isContentValid(const mediametrics::Item *item, bool is "codec", "extractor", "mediadrm", + "mediaparser", "nuplayer", }) { if (key == allowedKey) { diff --git a/services/mediametrics/iface_statsd.cpp b/services/mediametrics/iface_statsd.cpp index 6e51f7222e..16204deef0 100644 --- a/services/mediametrics/iface_statsd.cpp +++ b/services/mediametrics/iface_statsd.cpp @@ -64,6 +64,7 @@ static constexpr struct statsd_hooks statsd_handlers[] = { "drmmanager", statsd_drmmanager }, { "extractor", statsd_extractor }, { "mediadrm", statsd_mediadrm }, + { "mediaparser", statsd_mediaparser }, { "nuplayer", statsd_nuplayer }, { "nuplayer2", statsd_nuplayer }, { "recorder", statsd_recorder }, diff --git a/services/mediametrics/iface_statsd.h b/services/mediametrics/iface_statsd.h index 19505a400a..9b4955602b 100644 --- a/services/mediametrics/iface_statsd.h +++ b/services/mediametrics/iface_statsd.h @@ -25,6 +25,7 @@ extern bool statsd_audiothread(const mediametrics::Item *); extern bool statsd_audiotrack(const mediametrics::Item *); extern bool statsd_codec(const mediametrics::Item *); extern bool statsd_extractor(const mediametrics::Item *); +extern bool statsd_mediaparser(const mediametrics::Item *); extern bool statsd_nuplayer(const mediametrics::Item *); extern bool statsd_recorder(const mediametrics::Item *); diff --git a/services/mediametrics/statsd_extractor.cpp b/services/mediametrics/statsd_extractor.cpp index 3d5739fc8b..fb0924cafb 100644 --- a/services/mediametrics/statsd_extractor.cpp +++ b/services/mediametrics/statsd_extractor.cpp @@ -71,6 +71,22 @@ bool statsd_extractor(const mediametrics::Item *item) metrics_proto.set_tracks(ntrk); } + // android.media.mediaextractor.entry string + std::string entry_point_string; + if (item->getString("android.media.mediaextractor.entry", &entry_point_string)) { + stats::mediametrics::ExtractorData::EntryPoint entry_point; + if (entry_point_string == "sdk") { + entry_point = stats::mediametrics::ExtractorData_EntryPoint_SDK; + } else if (entry_point_string == "ndk-with-jvm") { + entry_point = stats::mediametrics::ExtractorData_EntryPoint_NDK_WITH_JVM; + } else if (entry_point_string == "ndk-no-jvm") { + entry_point = stats::mediametrics::ExtractorData_EntryPoint_NDK_NO_JVM; + } else { + entry_point = stats::mediametrics::ExtractorData_EntryPoint_OTHER; + } + metrics_proto.set_entry_point(entry_point); + } + std::string serialized; if (!metrics_proto.SerializeToString(&serialized)) { ALOGE("Failed to serialize extractor metrics"); diff --git a/services/mediametrics/statsd_mediaparser.cpp b/services/mediametrics/statsd_mediaparser.cpp new file mode 100644 index 0000000000..3258ebf9f3 --- /dev/null +++ b/services/mediametrics/statsd_mediaparser.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "statsd_mediaparser" +#include <utils/Log.h> + +#include <dirent.h> +#include <inttypes.h> +#include <pthread.h> +#include <pwd.h> +#include <stdint.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> + +#include <statslog.h> + +#include "MediaMetricsService.h" +#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h" +#include "iface_statsd.h" + +namespace android { + +bool statsd_mediaparser(const mediametrics::Item *item) +{ + if (item == nullptr) { + return false; + } + + // statsd wrapper data. + const nsecs_t timestamp = MediaMetricsService::roundTime(item->getTimestamp()); + std::string pkgName = item->getPkgName(); + int64_t pkgVersionCode = item->getPkgVersionCode(); + + std::string parserName; + item->getString("android.media.mediaparser.parserName", &parserName); + + int32_t createdByName = -1; + item->getInt32("android.media.mediaparser.createdByName", &createdByName); + + std::string parserPool; + item->getString("android.media.mediaparser.parserPool", &parserPool); + + std::string lastException; + item->getString("android.media.mediaparser.lastException", &lastException); + + int64_t resourceByteCount = -1; + item->getInt64("android.media.mediaparser.resourceByteCount", &resourceByteCount); + + int64_t durationMillis = -1; + item->getInt64("android.media.mediaparser.durationMillis", &durationMillis); + + std::string trackMimeTypes; + item->getString("android.media.mediaparser.trackMimeTypes", &trackMimeTypes); + + std::string trackCodecs; + item->getString("android.media.mediaparser.trackCodecs", &trackCodecs); + + std::string alteredParameters; + item->getString("android.media.mediaparser.alteredParameters", &alteredParameters); + + int32_t videoWidth = -1; + item->getInt32("android.media.mediaparser.videoWidth", &videoWidth); + + int32_t videoHeight = -1; + item->getInt32("android.media.mediaparser.videoHeight", &videoHeight); + + if (enabled_statsd) { + (void) android::util::stats_write(android::util::MEDIAMETRICS_MEDIAPARSER_REPORTED, + timestamp, + pkgName.c_str(), + pkgVersionCode, + parserName.c_str(), + createdByName, + parserPool.c_str(), + lastException.c_str(), + resourceByteCount, + durationMillis, + trackMimeTypes.c_str(), + trackCodecs.c_str(), + alteredParameters.c_str(), + videoWidth, + videoHeight); + } else { + ALOGV("NOT sending MediaParser media metrics."); + } + + return true; +} + +} // namespace android diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp index 3d36f8ea93..db06a36217 100644 --- a/services/mediaresourcemanager/ResourceManagerService.cpp +++ b/services/mediaresourcemanager/ResourceManagerService.cpp @@ -575,13 +575,19 @@ Status ResourceManagerService::reclaimResource( } } + *_aidl_return = reclaimInternal(clients); + return Status::ok(); +} + +bool ResourceManagerService::reclaimInternal( + const Vector<std::shared_ptr<IResourceManagerClient>> &clients) { if (clients.size() == 0) { - return Status::ok(); + return false; } std::shared_ptr<IResourceManagerClient> failedClient; for (size_t i = 0; i < clients.size(); ++i) { - log = String8::format("reclaimResource from client %p", clients[i].get()); + String8 log = String8::format("reclaimResource from client %p", clients[i].get()); mServiceLog->add(log); bool success; Status status = clients[i]->reclaimResource(&success); @@ -592,8 +598,7 @@ Status ResourceManagerService::reclaimResource( } if (failedClient == NULL) { - *_aidl_return = true; - return Status::ok(); + return true; } { @@ -618,7 +623,7 @@ Status ResourceManagerService::reclaimResource( } } - return Status::ok(); + return false; } Status ResourceManagerService::overridePid( @@ -681,6 +686,36 @@ Status ResourceManagerService::markClientForPendingRemoval(int32_t pid, int64_t return Status::ok(); } +Status ResourceManagerService::reclaimResourcesFromClientsPendingRemoval(int32_t pid) { + String8 log = String8::format("reclaimResourcesFromClientsPendingRemoval(pid %d)", pid); + mServiceLog->add(log); + + Vector<std::shared_ptr<IResourceManagerClient>> clients; + { + Mutex::Autolock lock(mLock); + if (!mProcessInfo->isValidPid(pid)) { + ALOGE("Rejected reclaimResourcesFromClientsPendingRemoval call with invalid pid."); + return Status::fromServiceSpecificError(BAD_VALUE); + } + + for (MediaResource::Type type : {MediaResource::Type::kSecureCodec, + MediaResource::Type::kNonSecureCodec, + MediaResource::Type::kGraphicMemory, + MediaResource::Type::kDrmSession}) { + std::shared_ptr<IResourceManagerClient> client; + if (getBiggestClient_l(pid, type, &client, true /* pendingRemovalOnly */)) { + clients.add(client); + break; + } + } + } + + if (!clients.empty()) { + reclaimInternal(clients); + } + return Status::ok(); +} + bool ResourceManagerService::getPriority_l(int pid, int* priority) { int newPid = pid; @@ -804,7 +839,8 @@ bool ResourceManagerService::getBiggestClient_l( bool pendingRemovalOnly) { ssize_t index = mMap.indexOfKey(pid); if (index < 0) { - ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid); + ALOGE_IF(!pendingRemovalOnly, + "getBiggestClient_l: can't find resource info for pid %d", pid); return false; } @@ -828,7 +864,9 @@ bool ResourceManagerService::getBiggestClient_l( } if (clientTemp == NULL) { - ALOGE("getBiggestClient_l: can't find resource type %s for pid %d", asString(type), pid); + ALOGE_IF(!pendingRemovalOnly, + "getBiggestClient_l: can't find resource type %s for pid %d", + asString(type), pid); return false; } diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h index ee982b722c..3972d2365c 100644 --- a/services/mediaresourcemanager/ResourceManagerService.h +++ b/services/mediaresourcemanager/ResourceManagerService.h @@ -127,11 +127,18 @@ public: Status markClientForPendingRemoval(int32_t pid, int64_t clientId) override; + Status reclaimResourcesFromClientsPendingRemoval(int32_t pid) override; + Status removeResource(int pid, int64_t clientId, bool checkValid); private: friend class ResourceManagerServiceTest; + // Reclaims resources from |clients|. Returns true if reclaim succeeded + // for all clients. + bool reclaimInternal( + const Vector<std::shared_ptr<IResourceManagerClient>> &clients); + // Gets the list of all the clients who own the specified resource type. // Returns false if any client belongs to a process with higher priority than the // calling process. The clients will remain unchanged if returns false. diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp index 702935d25b..a6ecc09eff 100644 --- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp +++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp @@ -520,6 +520,30 @@ protected: // clean up client 3 which still left mService->removeClient(kTestPid2, getId(mTestClient3)); } + + { + addResource(); + mService->mSupportsSecureWithNonSecureCodec = true; + + mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient2)); + + // client marked for pending removal got reclaimed + EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(kTestPid2).isOk()); + verifyClients(false /* c1 */, true /* c2 */, false /* c3 */); + + // No more clients marked for removal + EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(kTestPid2).isOk()); + verifyClients(false /* c1 */, false /* c2 */, false /* c3 */); + + mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient3)); + + // client marked for pending removal got reclaimed + EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(kTestPid2).isOk()); + verifyClients(false /* c1 */, false /* c2 */, true /* c3 */); + + // clean up client 1 which still left + mService->removeClient(kTestPid1, getId(mTestClient1)); + } } void testRemoveClient() { diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h index a171cb0b0c..04b906a7cc 100644 --- a/services/oboeservice/AAudioServiceEndpoint.h +++ b/services/oboeservice/AAudioServiceEndpoint.h @@ -47,7 +47,11 @@ public: virtual aaudio_result_t open(const aaudio::AAudioStreamRequest &request) = 0; - virtual aaudio_result_t close() = 0; + /* + * Perform any cleanup necessary before deleting the stream. + * This might include releasing and closing internal streams. + */ + virtual void close() = 0; aaudio_result_t registerStream(android::sp<AAudioServiceStreamBase> stream); diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp index 37d105bf5e..3ba3c28018 100644 --- a/services/oboeservice/AAudioServiceEndpointCapture.cpp +++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp @@ -36,18 +36,18 @@ using namespace android; // TODO just import names needed using namespace aaudio; // TODO just import names needed AAudioServiceEndpointCapture::AAudioServiceEndpointCapture(AAudioService &audioService) - : mStreamInternalCapture(audioService, true) { - mStreamInternal = &mStreamInternalCapture; + : AAudioServiceEndpointShared( + (AudioStreamInternal *)(new AudioStreamInternalCapture(audioService, true))) { } AAudioServiceEndpointCapture::~AAudioServiceEndpointCapture() { - delete mDistributionBuffer; + delete[] mDistributionBuffer; } aaudio_result_t AAudioServiceEndpointCapture::open(const aaudio::AAudioStreamRequest &request) { aaudio_result_t result = AAudioServiceEndpointShared::open(request); if (result == AAUDIO_OK) { - delete mDistributionBuffer; + delete[] mDistributionBuffer; int distributionBufferSizeBytes = getStreamInternal()->getFramesPerBurst() * getStreamInternal()->getBytesPerFrame(); mDistributionBuffer = new uint8_t[distributionBufferSizeBytes]; @@ -69,7 +69,9 @@ void *AAudioServiceEndpointCapture::callbackLoop() { // Read audio data from stream using a blocking read. result = getStreamInternal()->read(mDistributionBuffer, getFramesPerBurst(), timeoutNanos); if (result == AAUDIO_ERROR_DISCONNECTED) { - disconnectRegisteredStreams(); + ALOGD("%s() read() returned AAUDIO_ERROR_DISCONNECTED", __func__); + // We do not need the returned vector. + (void) AAudioServiceEndpointShared::disconnectRegisteredStreams(); break; } else if (result != getFramesPerBurst()) { ALOGW("callbackLoop() read %d / %d", diff --git a/services/oboeservice/AAudioServiceEndpointCapture.h b/services/oboeservice/AAudioServiceEndpointCapture.h index 971da9addd..2bbe81d34c 100644 --- a/services/oboeservice/AAudioServiceEndpointCapture.h +++ b/services/oboeservice/AAudioServiceEndpointCapture.h @@ -36,8 +36,7 @@ public: void *callbackLoop() override; private: - AudioStreamInternalCapture mStreamInternalCapture; - uint8_t *mDistributionBuffer = nullptr; + uint8_t *mDistributionBuffer = nullptr; }; } /* namespace aaudio */ diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp index 0843e0b5cf..04c64536e0 100644 --- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp +++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp @@ -226,7 +226,7 @@ error: return result; } -aaudio_result_t AAudioServiceEndpointMMAP::close() { +void AAudioServiceEndpointMMAP::close() { if (mMmapStream != nullptr) { // Needs to be explicitly cleared or CTS will fail but it is not clear why. mMmapStream.clear(); @@ -235,8 +235,6 @@ aaudio_result_t AAudioServiceEndpointMMAP::close() { // FIXME Make closing synchronous. AudioClock::sleepForNanos(100 * AAUDIO_NANOS_PER_MILLISECOND); } - - return AAUDIO_OK; } aaudio_result_t AAudioServiceEndpointMMAP::startStream(sp<AAudioServiceStreamBase> stream, diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.h b/services/oboeservice/AAudioServiceEndpointMMAP.h index 3d10861505..b6003b6b7d 100644 --- a/services/oboeservice/AAudioServiceEndpointMMAP.h +++ b/services/oboeservice/AAudioServiceEndpointMMAP.h @@ -50,7 +50,7 @@ public: aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override; - aaudio_result_t close() override; + void close() override; aaudio_result_t startStream(android::sp<AAudioServiceStreamBase> stream, audio_port_handle_t *clientHandle) override; diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp index bda4b902de..89aa70d135 100644 --- a/services/oboeservice/AAudioServiceEndpointPlay.cpp +++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp @@ -42,8 +42,8 @@ using namespace aaudio; // TODO just import names needed #define BURSTS_PER_BUFFER_DEFAULT 2 AAudioServiceEndpointPlay::AAudioServiceEndpointPlay(AAudioService &audioService) - : mStreamInternalPlay(audioService, true) { - mStreamInternal = &mStreamInternalPlay; + : AAudioServiceEndpointShared( + (AudioStreamInternal *)(new AudioStreamInternalPlay(audioService, true))) { } aaudio_result_t AAudioServiceEndpointPlay::open(const aaudio::AAudioStreamRequest &request) { @@ -145,7 +145,9 @@ void *AAudioServiceEndpointPlay::callbackLoop() { result = getStreamInternal()->write(mMixer.getOutputBuffer(), getFramesPerBurst(), timeoutNanos); if (result == AAUDIO_ERROR_DISCONNECTED) { - AAudioServiceEndpointShared::disconnectRegisteredStreams(); + ALOGD("%s() write() returned AAUDIO_ERROR_DISCONNECTED", __func__); + // We do not need the returned vector. + (void) AAudioServiceEndpointShared::disconnectRegisteredStreams(); break; } else if (result != getFramesPerBurst()) { ALOGW("callbackLoop() wrote %d / %d", diff --git a/services/oboeservice/AAudioServiceEndpointPlay.h b/services/oboeservice/AAudioServiceEndpointPlay.h index 981e43073a..160a1de074 100644 --- a/services/oboeservice/AAudioServiceEndpointPlay.h +++ b/services/oboeservice/AAudioServiceEndpointPlay.h @@ -45,7 +45,6 @@ public: void *callbackLoop() override; private: - AudioStreamInternalPlay mStreamInternalPlay; // for playing output of mixer bool mLatencyTuningEnabled = false; // TODO implement tuning AAudioMixer mMixer; // }; diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp index dc21886d86..f5de59ffbc 100644 --- a/services/oboeservice/AAudioServiceEndpointShared.cpp +++ b/services/oboeservice/AAudioServiceEndpointShared.cpp @@ -40,6 +40,9 @@ using namespace aaudio; // This is the maximum size in frames. The effective size can be tuned smaller at runtime. #define DEFAULT_BUFFER_CAPACITY (48 * 8) +AAudioServiceEndpointShared::AAudioServiceEndpointShared(AudioStreamInternal *streamInternal) + : mStreamInternal(streamInternal) {} + std::string AAudioServiceEndpointShared::dump() const { std::stringstream result; @@ -84,8 +87,8 @@ aaudio_result_t AAudioServiceEndpointShared::open(const aaudio::AAudioStreamRequ return result; } -aaudio_result_t AAudioServiceEndpointShared::close() { - return getStreamInternal()->releaseCloseFinal(); +void AAudioServiceEndpointShared::close() { + getStreamInternal()->releaseCloseFinal(); } // Glue between C and C++ callbacks. diff --git a/services/oboeservice/AAudioServiceEndpointShared.h b/services/oboeservice/AAudioServiceEndpointShared.h index bfc1744253..020b926717 100644 --- a/services/oboeservice/AAudioServiceEndpointShared.h +++ b/services/oboeservice/AAudioServiceEndpointShared.h @@ -35,12 +35,13 @@ namespace aaudio { class AAudioServiceEndpointShared : public AAudioServiceEndpoint { public: + explicit AAudioServiceEndpointShared(AudioStreamInternal *streamInternal); std::string dump() const override; aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override; - aaudio_result_t close() override; + void close() override; aaudio_result_t startStream(android::sp<AAudioServiceStreamBase> stream, audio_port_handle_t *clientHandle) override; @@ -57,15 +58,15 @@ public: protected: AudioStreamInternal *getStreamInternal() const { - return mStreamInternal; + return mStreamInternal.get(); }; aaudio_result_t startSharingThread_l(); aaudio_result_t stopSharingThread(); - // pointer to object statically allocated in subclasses - AudioStreamInternal *mStreamInternal = nullptr; + // An MMAP stream that is shared by multiple clients. + android::sp<AudioStreamInternal> mStreamInternal; std::atomic<bool> mCallbackEnabled{false}; |