diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp index cd58d019293..afc9ddeb537 100644 --- a/camera/CameraParameters.cpp +++ b/camera/CameraParameters.cpp @@ -238,6 +238,9 @@ void CameraParameters::unflatten(const String8 ¶ms) void CameraParameters::set(const char *key, const char *value) { + if (key == NULL || value == NULL) + return; + // XXX i think i can do this with strspn() if (strchr(key, '=') || strchr(key, ';')) { //XXX ALOGE("Key \"%s\"contains invalid character (= or ;)", key); diff --git a/camera/CameraSessionStats.cpp b/camera/CameraSessionStats.cpp index 450bdd870c3..4ec76244f98 100644 --- a/camera/CameraSessionStats.cpp +++ b/camera/CameraSessionStats.cpp @@ -260,6 +260,10 @@ const int CameraSessionStats::CAMERA_STATE_ACTIVE = 1; const int CameraSessionStats::CAMERA_STATE_IDLE = 2; const int CameraSessionStats::CAMERA_STATE_CLOSED = 3; +const int CameraSessionStats::CAMERA_STATE_EXCEPTION = 4; +const int CameraSessionStats::CAMERA_STATE_SESSION_CONFIGURED = 5; +const int CameraSessionStats::CAMERA_STATE_FIRST_FRAME_ARRIVED = 6; + const int CameraSessionStats::CAMERA_FACING_BACK = 0; const int CameraSessionStats::CAMERA_FACING_FRONT = 1; const int CameraSessionStats::CAMERA_FACING_EXTERNAL = 2; diff --git a/camera/ICameraClient.cpp b/camera/ICameraClient.cpp index bef2ea0acdd..f4212b7726e 100644 --- a/camera/ICameraClient.cpp +++ b/camera/ICameraClient.cpp @@ -51,7 +51,12 @@ class BpCameraClient: public BpInterface data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); data.writeInt32(msgType); data.writeInt32(ext1); - data.writeInt32(ext2); + if ((msgType == CAMERA_MSG_PREVIEW_FRAME) && (ext1 == CAMERA_FRAME_DATA_FD)) { + ALOGD("notifyCallback: CAMERA_MSG_PREVIEW_FRAME fd = %d", ext2); + data.writeFileDescriptor(ext2); + } else { + data.writeInt32(ext2); + } remote()->transact(NOTIFY_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); } @@ -129,8 +134,14 @@ status_t BnCameraClient::onTransact( ALOGV("NOTIFY_CALLBACK"); CHECK_INTERFACE(ICameraClient, data, reply); int32_t msgType = data.readInt32(); - int32_t ext1 = data.readInt32(); - int32_t ext2 = data.readInt32(); + int32_t ext1 = data.readInt32(); + int32_t ext2 = 0; + if ((msgType == CAMERA_MSG_PREVIEW_FRAME) && (ext1 == CAMERA_FRAME_DATA_FD)) { + ext2 = data.readFileDescriptor(); + ALOGD("onTransact: CAMERA_MSG_PREVIEW_FRAME fd = %d", ext2); + } else { + ext2 = data.readInt32(); + } notifyCallback(msgType, ext1, ext2); return NO_ERROR; } break; diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp index d0df90b8334..d6b7b159a1f 100644 --- a/camera/cameraserver/Android.bp +++ b/camera/cameraserver/Android.bp @@ -52,17 +52,31 @@ cc_binary { "android.hardware.camera.device@1.0", "android.hardware.camera.device@3.2", "android.hardware.camera.device@3.4", - ], + ] + select(soong_config_variable("camera", "needs_client_info_lib"), { + true: ["//hardware/oneplus:vendor.oneplus.hardware.camera@1.0"], + false: [], + default: [], + }) + select(soong_config_variable("camera", "needs_client_info_lib_oplus"), { + true: ["vendor.oplus.hardware.cameraMDM@2.0"], + false: [], + default: [], + }), + static_libs: [ "libcameraservice", ], + compile_multilib: "first", + cflags: [ "-Wall", "-Wextra", "-Werror", "-Wno-unused-parameter", - ], + ] + select(soong_config_variable("camera", "package_name"), { + any @ flag_val: ["-DCAMERA_PACKAGE_NAME=\"" + flag_val + "\""], + default: [], + }), init_rc: ["cameraserver.rc"], diff --git a/camera/include/camera/CameraSessionStats.h b/camera/include/camera/CameraSessionStats.h index 34ee882d609..f9e960b9dea 100644 --- a/camera/include/camera/CameraSessionStats.h +++ b/camera/include/camera/CameraSessionStats.h @@ -109,6 +109,9 @@ class CameraSessionStats : public android::Parcelable { static const int CAMERA_STATE_ACTIVE; static const int CAMERA_STATE_IDLE; static const int CAMERA_STATE_CLOSED; + static const int CAMERA_STATE_EXCEPTION; + static const int CAMERA_STATE_SESSION_CONFIGURED; + static const int CAMERA_STATE_FIRST_FRAME_ARRIVED; /** * Values for notifyCameraState facing diff --git a/include/media/AppVolume.h b/include/media/AppVolume.h new file mode 100644 index 00000000000..5c12c11ae79 --- /dev/null +++ b/include/media/AppVolume.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2022 Project Kaleidoscope + * + * 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 APP_VOLUME_H +#define APP_VOLUME_H + +#include +#include +#include +#include +#include + +namespace android { +namespace media { + class AppVolume : public Parcelable { + public: + String8 packageName; + bool muted; + float volume; + bool active; + + bool operator <(const AppVolume &obj) const { + if (active != obj.active) return active < obj.active; + return packageName < obj.packageName; + } + + virtual status_t writeToParcel(Parcel* parcel) const { + AppVolumeData parcelable; + return writeToParcelable(&parcelable) + ?: parcelable.writeToParcel(parcel); + } + + virtual status_t writeToParcelable(AppVolumeData* parcelable) const { + parcelable->packageName = packageName.c_str(); + parcelable->muted = muted; + parcelable->volume = volume; + parcelable->active = active; + return OK; + } + + virtual status_t readFromParcel(const Parcel* parcel) { + AppVolumeData data; + return data.readFromParcel(parcel) + ?: readFromParcelable(data); + } + + virtual status_t readFromParcelable(const AppVolumeData& parcelable) { + packageName = parcelable.packageName.c_str(); + muted = parcelable.muted; + volume = parcelable.volume; + active = parcelable.active; + return OK; + } + }; + + inline ConversionResult + aidl2legacy_AppVolume(const AppVolumeData& aidl) { + AppVolume legacy; + RETURN_IF_ERROR(legacy.readFromParcelable(aidl)); + return legacy; + } + + inline ConversionResult + legacy2aidl_AppVolume(const AppVolume& legacy) { + AppVolumeData aidl; + RETURN_IF_ERROR(legacy.writeToParcelable(&aidl)); + return aidl; + } +} // namespace media +}; // namespace android + +#endif // APP_VOLUME_H diff --git a/media/aidl/Android.bp b/media/aidl/Android.bp index cf0f8399f19..7eef94229e3 100644 --- a/media/aidl/Android.bp +++ b/media/aidl/Android.bp @@ -43,6 +43,7 @@ aidl_interface { double_loadable: true, local_include_dir: ".", srcs: [ + "android/media/AppVolumeData.aidl", "android/media/IAudioManagerNative.aidl", "android/media/InterpolatorConfig.aidl", "android/media/InterpolatorType.aidl", diff --git a/media/aidl/android/media/AppVolumeData.aidl b/media/aidl/android/media/AppVolumeData.aidl new file mode 100644 index 00000000000..e0e38e84267 --- /dev/null +++ b/media/aidl/android/media/AppVolumeData.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2022 Project Kaleidoscope + * + * 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. + */ + +package android.media; + +/** + * {@hide} + */ +parcelable AppVolumeData { + @utf8InCpp String packageName; + int muted; + float volume; + int active; +} diff --git a/media/codec2/components/aom/Android.bp b/media/codec2/components/aom/Android.bp index 83066c74bd5..067e7596940 100644 --- a/media/codec2/components/aom/Android.bp +++ b/media/codec2/components/aom/Android.bp @@ -12,7 +12,6 @@ cc_library { defaults: [ "libcodec2_soft-defaults", "libcodec2_soft_sanitize_all-defaults", - "libcodec2_soft_sanitize_cfi-defaults", ], // coordinated with frameworks/av/media/codec2/components/gav1/Android.bp @@ -23,6 +22,10 @@ cc_library { srcs: ["C2SoftAomDec.cpp"], static_libs: ["libaom"], + + sanitize: { + cfi: false, + }, } cc_library { @@ -30,7 +33,6 @@ cc_library { defaults: [ "libcodec2_soft-defaults", "libcodec2_soft_sanitize_all-defaults", - "libcodec2_soft_sanitize_cfi-defaults", ], static_libs: ["libaom"], @@ -44,4 +46,7 @@ cc_library { "com.android.media.swcodec", ], + sanitize: { + cfi: false, + }, } diff --git a/media/codec2/hal/aidl/ComponentStore.cpp b/media/codec2/hal/aidl/ComponentStore.cpp index 4daa6c8d4ff..adb0b6a3762 100644 --- a/media/codec2/hal/aidl/ComponentStore.cpp +++ b/media/codec2/hal/aidl/ComponentStore.cpp @@ -156,13 +156,6 @@ ComponentStore::ComponentStore(const std::shared_ptr& store) mParamReflectors.push_back(paramReflector); } #endif - // MultiAccessUnit reflector helper is allocated once per store. - // All components in this store can reuse this reflector helper. - if (MultiAccessUnitHelper::isEnabledOnPlatform()) { - std::shared_ptr helper = std::make_shared(); - mParamReflectors.push_back(helper); - mMultiAccessUnitReflector = helper; - } // Retrieve supported parameters from store using namespace std::placeholders; @@ -250,9 +243,11 @@ std::shared_ptr ComponentStore::tryCreateMultiAccessUn // param reflectors. Currently filters work on video domain only, // and the MultiAccessUnitHelper is only enabled on audio domain; // thus we pass the component's param reflector, which is mParamReflectors[0]. + std::shared_ptr multiAccessReflector(new C2ReflectorHelper()); multiAccessUnitIntf = std::make_shared( c2interface, - mMultiAccessUnitReflector); + multiAccessReflector); + mParamReflectors.push_back(multiAccessReflector); } } } diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h index bb4c596cba7..0e8ac41dce8 100644 --- a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h +++ b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h @@ -127,9 +127,6 @@ struct ComponentStore : public BnComponentStore { std::shared_ptr mStore; std::vector> mParamReflectors; - // Reflector helper for MultiAccessUnitHelper - std::shared_ptr mMultiAccessUnitReflector; - std::map> mStructDescriptors; std::set mUnsupportedStructDescriptors; std::set mLoadedInterfaces; diff --git a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp index 664088a8965..1584d6269b1 100644 --- a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp +++ b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp @@ -146,14 +146,6 @@ ComponentStore::ComponentStore(const std::shared_ptr& store) } #endif - // MultiAccessUnit reflector helper is allocated once per store. - // All components in this store can reuse this reflector helper. - if (MultiAccessUnitHelper::isEnabledOnPlatform()) { - std::shared_ptr helper = std::make_shared(); - mParamReflectors.push_back(helper); - mMultiAccessUnitReflector = helper; - } - // Retrieve supported parameters from store using namespace std::placeholders; mInit = mConfigurable->init(mParameterCache); @@ -236,9 +228,12 @@ std::shared_ptr ComponentStore::tryCreateMultiAccessUn } } if (!isComponentSupportsLargeAudioFrame) { + std::shared_ptr multiAccessReflector(new C2ReflectorHelper()); multiAccessUnitIntf = std::make_shared( c2interface, - mMultiAccessUnitReflector); + multiAccessReflector); + mParamReflectors.push_back(multiAccessReflector); + } } } diff --git a/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h b/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h index 028238bd24a..07ffa219ecd 100644 --- a/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h +++ b/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h @@ -131,9 +131,6 @@ struct ComponentStore : public IComponentStore { std::shared_ptr mStore; std::vector> mParamReflectors; - // Reflector helper for MultiAccessUnitHelper - std::shared_ptr mMultiAccessUnitReflector; - std::map> mStructDescriptors; std::set mUnsupportedStructDescriptors; std::set mLoadedInterfaces; diff --git a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp index 15f4d68b896..a715fdc7f6e 100644 --- a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp +++ b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp @@ -146,14 +146,6 @@ ComponentStore::ComponentStore(const std::shared_ptr& store) } #endif - // MultiAccessUnit reflector helper is allocated once per store. - // All components in this store can reuse this reflector helper. - if (MultiAccessUnitHelper::isEnabledOnPlatform()) { - std::shared_ptr helper = std::make_shared(); - mParamReflectors.push_back(helper); - mMultiAccessUnitReflector = helper; - } - // Retrieve supported parameters from store using namespace std::placeholders; mInit = mConfigurable->init(mParameterCache); @@ -235,10 +227,13 @@ std::shared_ptr ComponentStore::tryCreateMultiAccessUn break; } } + if (!isComponentSupportsLargeAudioFrame) { + std::shared_ptr multiAccessReflector(new C2ReflectorHelper()); multiAccessUnitIntf = std::make_shared( c2interface, - mMultiAccessUnitReflector); + multiAccessReflector); + mParamReflectors.push_back(multiAccessReflector); } } } diff --git a/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h b/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h index b0231151b38..5dcb359d4df 100644 --- a/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h +++ b/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h @@ -139,9 +139,6 @@ struct ComponentStore : public IComponentStore { std::shared_ptr mStore; std::vector> mParamReflectors; - // Reflector helper for MultiAccessUnitHelper - std::shared_ptr mMultiAccessUnitReflector; - std::map> mStructDescriptors; std::set mUnsupportedStructDescriptors; std::set mLoadedInterfaces; diff --git a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp index aa498191851..ca047b043aa 100644 --- a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp +++ b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp @@ -146,14 +146,6 @@ ComponentStore::ComponentStore(const std::shared_ptr& store) } #endif - // MultiAccessUnit reflector helper is allocated once per store. - // All components in this store can reuse this reflector helper. - if (MultiAccessUnitHelper::isEnabledOnPlatform()) { - std::shared_ptr helper = std::make_shared(); - mParamReflectors.push_back(helper); - mMultiAccessUnitReflector = helper; - } - // Retrieve supported parameters from store using namespace std::placeholders; mInit = mConfigurable->init(mParameterCache); @@ -236,9 +228,11 @@ std::shared_ptr ComponentStore::tryCreateMultiAccessUn } } if (!isComponentSupportsLargeAudioFrame) { + std::shared_ptr multiAccessReflector(new C2ReflectorHelper()); multiAccessUnitIntf = std::make_shared( c2interface, - mMultiAccessUnitReflector); + multiAccessReflector); + mParamReflectors.push_back(multiAccessReflector); } } } diff --git a/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h b/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h index a7e043bc5f0..16a524093c8 100644 --- a/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h +++ b/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h @@ -146,9 +146,6 @@ struct ComponentStore : public IComponentStore { std::shared_ptr mStore; std::vector> mParamReflectors; - // Reflector helper for MultiAccessUnitHelper - std::shared_ptr mMultiAccessUnitReflector; - std::map> mStructDescriptors; std::set mUnsupportedStructDescriptors; std::set mLoadedInterfaces; diff --git a/media/codec2/vndk/C2Fence.cpp b/media/codec2/vndk/C2Fence.cpp index fe8a9eb3748..c095035c1dc 100644 --- a/media/codec2/vndk/C2Fence.cpp +++ b/media/codec2/vndk/C2Fence.cpp @@ -472,6 +472,10 @@ std::vector ExtractFdsFromCodec2SyncFence(const C2Fence& fence) { return retFds; } +C2Fence _C2FenceFactory::CreateSyncFence(int fenceFd) { + return CreateSyncFence(fenceFd, true); +} + C2Fence _C2FenceFactory::CreateSyncFence(int fenceFd, bool validate) { std::shared_ptr p; if (fenceFd >= 0) { @@ -812,4 +816,3 @@ C2Fence _C2FenceFactory::CreateFromNativeHandle( } return C2Fence(p); } - diff --git a/media/codec2/vndk/include/C2FenceFactory.h b/media/codec2/vndk/include/C2FenceFactory.h index cabd5d91cd6..d8e1bb3f261 100644 --- a/media/codec2/vndk/include/C2FenceFactory.h +++ b/media/codec2/vndk/include/C2FenceFactory.h @@ -67,7 +67,10 @@ struct _C2FenceFactory { * \param validate If true, the fence fd will be validated to ensure * it is a valid pending sync fence fd. */ - static C2Fence CreateSyncFence(int fenceFd, bool validate = true); + // Keep the legacy one-argument ABI for vendor Codec2 implementations that + // were built before fence validation became an explicit parameter. + static C2Fence CreateSyncFence(int fenceFd); + static C2Fence CreateSyncFence(int fenceFd, bool validate); /* * Create C2Fence from list of sync fence fds, while also merging them to diff --git a/media/img_utils/include/img_utils/TagDefinitions.h b/media/img_utils/include/img_utils/TagDefinitions.h index 1cc98669cb8..4f481f4e940 100644 --- a/media/img_utils/include/img_utils/TagDefinitions.h +++ b/media/img_utils/include/img_utils/TagDefinitions.h @@ -181,6 +181,8 @@ enum { TAG_EXPOSURETIME = 0x829Au, TAG_ISOSPEEDRATINGS = 0x8827u, TAG_FOCALLENGTH = 0x920Au, + TAG_FOCALLLENGTHIN35MMFILM = 0xA405u, + TAG_XIAOMI_PRODUCT = 0x9A00u, TAG_FNUMBER = 0x829Du, TAG_GPSINFO = 0x8825u, TAG_GPSVERSIONID = 0x0u, @@ -280,6 +282,14 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { 0, UNDEFINED_ENDIAN }, + { // FocalLengthIn35mmFilm + "FocalLengthIn35mmFilm", + 0xA405u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, { // FNumber "FNumber", 0x829Du, @@ -1396,6 +1406,14 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { 1, UNDEFINED_ENDIAN }, + { // Product + "Product", + 0x9A00u, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, }; } /*namespace img_utils*/ diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp index 98e4ee21ca2..443d3a2b1fc 100644 --- a/media/libaaudio/src/utility/AAudioUtilities.cpp +++ b/media/libaaudio/src/utility/AAudioUtilities.cpp @@ -303,7 +303,7 @@ audio_flags_mask_t AAudio_computeAudioFlagsMask( bool isContentSpatialized, audio_output_flags_t outputFlags) { audio_flags_mask_t flagsMask = AUDIO_FLAG_NONE; - switch (policy) { + /*switch (policy) { case AAUDIO_UNSPECIFIED: case AAUDIO_ALLOW_CAPTURE_BY_ALL: // flagsMask is not modified @@ -318,7 +318,7 @@ audio_flags_mask_t AAudio_computeAudioFlagsMask( default: ALOGE("%s() 0x%08X unrecognized capture policy", __func__, policy); // flagsMask is not modified - } + }*/ switch (spatializationBehavior) { case AAUDIO_UNSPECIFIED: diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp index 7e59d9e6070..13509d93beb 100644 --- a/media/libaudioclient/AudioSystem.cpp +++ b/media/libaudioclient/AudioSystem.cpp @@ -2916,6 +2916,27 @@ status_t AudioSystem::registerSoundTriggerCaptureStateListener( return NO_ERROR; } +status_t AudioSystem::setAppVolume(const String8& packageName, const float volume) +{ + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->setAppVolume(packageName, volume); +} + +status_t AudioSystem::setAppMute(const String8& packageName, const bool mute) +{ + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->setAppMute(packageName, mute); +} + +status_t AudioSystem::listAppVolumes(std::vector *vols) +{ + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->listAppVolumes(vols); +} + status_t AudioSystem::setVibratorInfos( const std::vector& vibratorInfos) { const sp af = get_audio_flinger(); diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp index 5d4e8b46d64..0fada5231a2 100644 --- a/media/libaudioclient/IAudioFlinger.cpp +++ b/media/libaudioclient/IAudioFlinger.cpp @@ -336,6 +336,28 @@ status_t AudioFlingerClientAdapter::getMasterBalance(float* balance) const{ return statusTFromBinderStatus(mDelegate->getMasterBalance(balance)); } +status_t AudioFlingerClientAdapter::setAppVolume(const String8& packageName, const float value) { + std::string packageNameAidl = VALUE_OR_RETURN_STATUS( + legacy2aidl_String8_string(packageName)); + return mDelegate->setAppVolume(packageNameAidl, value).transactionError(); +} + +status_t AudioFlingerClientAdapter::setAppMute(const String8& packageName, const bool value) { + std::string packageNameAidl = VALUE_OR_RETURN_STATUS( + legacy2aidl_String8_string(packageName)); + return mDelegate->setAppMute(packageNameAidl, value).transactionError(); +} + +status_t AudioFlingerClientAdapter::listAppVolumes(std::vector* vols) { + std::vector aidlRet; + RETURN_STATUS_IF_ERROR(mDelegate->listAppVolumes(&aidlRet).transactionError()); + if (vols != nullptr) { + *vols = VALUE_OR_RETURN_STATUS( + convertContainer>(aidlRet, media::aidl2legacy_AppVolume)); + } + return OK; +} + status_t AudioFlingerClientAdapter::setPortsVolume( const std::vector &portIds, float volume, bool muted, audio_io_handle_t output) { @@ -1000,6 +1022,26 @@ Status AudioFlingerServerAdapter::getMasterBalance(float* _aidl_return) { return Status::fromStatusT(mDelegate->getMasterBalance(_aidl_return)); } +Status AudioFlingerServerAdapter::setAppVolume(const std::string& packageName, const float value) { + String8 packageNameLegacy = VALUE_OR_RETURN_BINDER( + aidl2legacy_string_view_String8(packageName)); + return Status::fromStatusT(mDelegate->setAppVolume(packageNameLegacy, value)); +} + +Status AudioFlingerServerAdapter::setAppMute(const std::string& packageName, const bool value) { + String8 packageNameLegacy = VALUE_OR_RETURN_BINDER( + aidl2legacy_string_view_String8(packageName)); + return Status::fromStatusT(mDelegate->setAppMute(packageNameLegacy, value)); +} + +Status AudioFlingerServerAdapter::listAppVolumes(std::vector* _aidl_return) { + std::vector resultLegacy; + RETURN_BINDER_IF_ERROR(mDelegate->listAppVolumes(&resultLegacy)); + *_aidl_return = VALUE_OR_RETURN_BINDER(convertContainer>( + resultLegacy, media::legacy2aidl_AppVolume)); + return Status::ok(); +} + Status AudioFlingerServerAdapter::setPortsVolume( const std::vector& portIds, float volume, bool muted, int32_t output) { std::vector portIdsLegacy = VALUE_OR_RETURN_BINDER( diff --git a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl index 7ea947fd6e4..4999a79525a 100644 --- a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl +++ b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl @@ -16,6 +16,7 @@ package android.media; +import android.media.AppVolumeData; import android.media.AudioPatchFw; import android.media.AudioPolicyConfig; import android.media.AudioPortFw; @@ -98,6 +99,10 @@ interface IAudioFlingerService { void setMasterBalance(float balance); float getMasterBalance(); + void setAppVolume(@utf8InCpp String packageName, float value); + void setAppMute(@utf8InCpp String packageName, boolean muted); + AppVolumeData[] listAppVolumes(); + /* * Set AudioTrack port ids volume attribute. This is the new way of controlling volume from * AudioPolicyManager to AudioFlinger. diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h index a7c7a39265b..389e671455f 100644 --- a/media/libaudioclient/include/media/AudioSystem.h +++ b/media/libaudioclient/include/media/AudioSystem.h @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -866,6 +867,10 @@ class AudioSystem media::audio::common::AudioMMapPolicyType policyType, audio_devices_t device, media::audio::common::AudioMMapPolicyInfo *policyInfo); + static status_t setAppVolume(const String8& packageName, const float value); + static status_t setAppMute(const String8& packageName, const bool value); + static status_t listAppVolumes(std::vector *vols); + class AudioFlingerClient: public media::BnAudioFlingerClient { public: diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h index f12e8f47258..67c115cce43 100644 --- a/media/libaudioclient/include/media/IAudioFlinger.h +++ b/media/libaudioclient/include/media/IAudioFlinger.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -399,6 +400,10 @@ class IAudioFlinger : public virtual RefBase { const std::vector& tracksInternalMute) = 0; virtual status_t resetReferencesForTest() = 0; + + virtual status_t setAppVolume(const String8& packageName, const float value) = 0; + virtual status_t setAppMute(const String8& packageName, const bool value) = 0; + virtual status_t listAppVolumes(std::vector *vols) = 0; }; /** @@ -520,6 +525,10 @@ class AudioFlingerClientAdapter : public IAudioFlinger { const std::vector& tracksInternalMute) override; status_t resetReferencesForTest() override; + status_t setAppVolume(const String8& packageName, const float value) override; + status_t setAppMute(const String8& packageName, const bool value) override; + status_t listAppVolumes(std::vector *vols) override; + private: const sp mDelegate; }; @@ -621,6 +630,9 @@ class AudioFlingerServerAdapter : public media::BnAudioFlingerService { SET_TRACKS_INTERNAL_MUTE = media::BnAudioFlingerService::TRANSACTION_setTracksInternalMute, RESET_REFERENCES_FOR_TEST = media::BnAudioFlingerService::TRANSACTION_resetReferencesForTest, + SET_APP_VOLUME = media::BnAudioFlingerService::TRANSACTION_setAppVolume, + SET_APP_MUTE = media::BnAudioFlingerService::TRANSACTION_setAppMute, + LIST_APP_VOLUMES = media::BnAudioFlingerService::TRANSACTION_listAppVolumes, }; protected: @@ -759,6 +771,10 @@ class AudioFlingerServerAdapter : public media::BnAudioFlingerService { Status setTracksInternalMute( const std::vector& tracksInternalMute) override; Status resetReferencesForTest() override; + + Status setAppVolume(const std::string& packageName, const float value) override; + Status setAppMute(const std::string& packageName, const bool value) override; + Status listAppVolumes(std::vector *vols) override; private: const sp mDelegate; }; diff --git a/media/libdatasource/MediaHTTP.cpp b/media/libdatasource/MediaHTTP.cpp index b1f214096fb..99c34e6a0f3 100644 --- a/media/libdatasource/MediaHTTP.cpp +++ b/media/libdatasource/MediaHTTP.cpp @@ -68,6 +68,7 @@ status_t MediaHTTP::connect( if (success) { AString sanitized = uriDebugString(mLastURI); + Mutex::Autolock autoLock(mLock); mName = String8::format("MediaHTTP(%s)", sanitized.c_str()); } @@ -79,7 +80,10 @@ void MediaHTTP::close() { } void MediaHTTP::disconnect() { - mName = String8("MediaHTTP()"); + { + Mutex::Autolock autoLock(mLock); + mName = String8("MediaHTTP()"); + } if (mInitCheck != OK) { return; } @@ -87,6 +91,11 @@ void MediaHTTP::disconnect() { mHTTPConnection->disconnect(); } +String8 MediaHTTP::toString() { + Mutex::Autolock autoLock(mLock); + return mName; +} + status_t MediaHTTP::initCheck() const { return mInitCheck; } diff --git a/media/libdatasource/include/datasource/MediaHTTP.h b/media/libdatasource/include/datasource/MediaHTTP.h index a8d203b2454..2591905e3b1 100644 --- a/media/libdatasource/include/datasource/MediaHTTP.h +++ b/media/libdatasource/include/datasource/MediaHTTP.h @@ -38,6 +38,8 @@ struct MediaHTTP : public HTTPBase { virtual void disconnect(); + virtual String8 toString(); + virtual status_t initCheck() const; virtual ssize_t readAt(off64_t offset, void *data, size_t size); @@ -65,6 +67,8 @@ struct MediaHTTP : public HTTPBase { bool mCachedSizeValid; off64_t mCachedSize; + Mutex mLock; + DISALLOW_EVIL_CONSTRUCTORS(MediaHTTP); }; diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp index 04388067c39..1246fb32a32 100644 --- a/media/libmedia/MediaProfiles.cpp +++ b/media/libmedia/MediaProfiles.cpp @@ -973,6 +973,7 @@ void MediaProfiles::checkAndAddRequiredProfilesIfNecessary() { /*static*/ MediaProfiles* MediaProfiles::getInstance() { + char platform[PROPERTY_VALUE_MAX] = {0}; ALOGV("getInstance"); Mutex::Autolock lock(sLock); if (!sIsInitialized) { @@ -993,6 +994,53 @@ MediaProfiles::getInstance() sInstance = createInstanceFromXmlFile(xmlFile); } } else { + if (!strncmp(value, "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/vendor/etc", strlen("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/vendor/etc"))) { + property_get("ro.board.platform", platform, NULL); + if (!strcmp(platform, "msm8953")){ + if (property_get("vendor.media.target.version", value, "0") && + (atoi(value) == 1) && + checkXmlFile("/vendor/etc/media_profiles_8953_v1.xml")){ + strlcpy(value, "/vendor/etc/media_profiles_8953_v1.xml", + PROPERTY_VALUE_MAX); + } else { + strlcpy(value, "/vendor/etc/media_profiles_vendor.xml", + PROPERTY_VALUE_MAX); + } + } else if (!strcmp(platform, "sdm660")) { + property_get("vendor.media.target.version", value, "0"); + if (atoi(value) == 1 && + checkXmlFile("/vendor/etc/media_profiles_sdm660_v1.xml")) { + strlcpy(value, "/vendor/etc/media_profiles_sdm660_v1.xml", + PROPERTY_VALUE_MAX); + } else { + strlcpy(value, "/vendor/etc/media_profiles_vendor.xml", + PROPERTY_VALUE_MAX); + } + } else if (!strcmp(platform, "bengal")) { + property_get("vendor.sys.media.target.version", value, "0"); + if (atoi(value) == 3 && + checkXmlFile("/vendor/etc/media_profiles_khaje.xml")) { + strlcpy(value, "/vendor/etc/media_profiles_khaje.xml", + PROPERTY_VALUE_MAX); + } else if (atoi(value) == 2 && + checkXmlFile("/vendor/etc/media_profiles_scuba.xml")) { + strlcpy(value, "/vendor/etc/media_profiles_scuba.xml", + PROPERTY_VALUE_MAX); + } else { + strlcpy(value, "/vendor/etc/media_profiles_vendor.xml", + PROPERTY_VALUE_MAX); + } + } + char variant[PROPERTY_VALUE_MAX]; + if (property_get("ro.media.xml_variant.codecs", variant, NULL) > 0) { + std::string xmlPath = std::string("/vendor/etc/media_profiles") + + std::string(variant) + std::string(".xml"); + if (checkXmlFile(xmlPath.c_str())) { + strlcpy(value, xmlPath.c_str(), PROPERTY_VALUE_MAX); + ALOGI("Profiles xml path: %s", value); + } + } + } sInstance = createInstanceFromXmlFile(value); } CHECK(sInstance != NULL); diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 2aba3261e79..eb4d05d5415 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -555,7 +555,7 @@ status_t StagefrightRecorder::setParamAudioSamplingRate(int32_t sampleRate) { status_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) { ALOGV("setParamAudioNumberOfChannels: %d", channels); - if (channels <= 0 || channels >= 3) { + if (channels <= 0 || channels > 6) { ALOGE("Invalid number of audio channels: %d", channels); return BAD_VALUE; } @@ -1127,6 +1127,8 @@ status_t StagefrightRecorder::setParameter( } } else if (key == "log-session-id") { return setLogSessionId(value); + } else if (key == "set-title") { + return OK; } else { ALOGE("setParameter: failed to find key %s", key.c_str()); } @@ -1941,7 +1943,7 @@ status_t StagefrightRecorder::setupCameraSource( pid_t pid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_pid_t(mAttributionSource.pid)); String16 clientName = VALUE_OR_RETURN_STATUS( aidl2legacy_string_view_String16(mAttributionSource.packageName.value_or(""))); - if (mCaptureFpsEnable) { + if (mCaptureFpsEnable && mCaptureFps != mFrameRate) { if (!(mCaptureFps > 0.)) { ALOGE("Invalid mCaptureFps value: %lf", mCaptureFps); return BAD_VALUE; @@ -2111,6 +2113,7 @@ status_t StagefrightRecorder::setupVideoEncoder( preferBFrames = false; tsLayers = 2; // use at least two layers as resulting video will likely be sped up } else if (mCaptureFps > maxPlaybackFps) { // slow-mo + format->setInt32("high-frame-rate", 1); maxPlaybackFps = mCaptureFps; // assume video will be played back at full capture speed preferBFrames = false; } diff --git a/media/libmediaplayerservice/nuplayer/AWakeLock.cpp b/media/libmediaplayerservice/nuplayer/AWakeLock.cpp index e8556ddec5f..ef6e71a3748 100644 --- a/media/libmediaplayerservice/nuplayer/AWakeLock.cpp +++ b/media/libmediaplayerservice/nuplayer/AWakeLock.cpp @@ -37,6 +37,11 @@ AWakeLock::AWakeLock() : mDeathRecipient(new PMDeathRecipient(this)){} AWakeLock::~AWakeLock() { + // Clear the back-pointer in PMDeathRecipient first to prevent a + // use-after-free race: if binderDied() fires on a binder thread after + // this object is destroyed, promote() will return NULL and the callback + // will be safely ignored. + mDeathRecipient->clearWakeLock(); if (mPowerManager != NULL) { sp binder = IInterface::asBinder(mPowerManager); binder->unlinkToDeath(mDeathRecipient); @@ -107,12 +112,15 @@ void AWakeLock::release(bool force) { void AWakeLock::clearPowerManager() { release(true); - mPowerManager.clear(); + if (mPowerManager != NULL) { + mPowerManager.clear(); + } } void AWakeLock::PMDeathRecipient::binderDied(const wp& who __unused) { - if (mWakeLock != NULL) { - mWakeLock->clearPowerManager(); + sp wakeLock = mWakeLock.promote(); + if (wakeLock != NULL) { + wakeLock->clearPowerManager(); } } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 65de591bf09..4a1b6064c13 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1144,6 +1144,13 @@ void NuPlayer::onMessageReceived(const sp &msg) { sp inputFormat = mSource->getFormat(false /* audio */); + int32_t sarWidth = 0, sarHeight = 0; + if (format->findInt32("sar-width", &sarWidth) && format->findInt32("sar-height", &sarHeight) && sarWidth > 0 + && sarHeight > 0) { + inputFormat->setInt32("sar-width", sarWidth); + inputFormat->setInt32("sar-height", sarHeight); + } + setVideoScalingMode(mVideoScalingMode); updateVideoSize(inputFormat, format); } else if (what == DecoderBase::kWhatShutdownCompleted) { @@ -2410,9 +2417,6 @@ void NuPlayer::performDecoderFlush(FlushCommand audio, FlushCommand video) { void NuPlayer::performReset() { ALOGV("performReset"); - CHECK(mAudioDecoder == NULL); - CHECK(mVideoDecoder == NULL); - updatePlaybackTimer(true /* stopping */, "performReset"); updateRebufferingTimer(true /* stopping */, true /* exiting */); diff --git a/media/libmediaplayerservice/nuplayer/include/nuplayer/AWakeLock.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/AWakeLock.h index 8aa3b41a703..8cf9d05a554 100644 --- a/media/libmediaplayerservice/nuplayer/include/nuplayer/AWakeLock.h +++ b/media/libmediaplayerservice/nuplayer/include/nuplayer/AWakeLock.h @@ -49,11 +49,14 @@ class AWakeLock : public RefBase { // IBinder::DeathRecipient virtual void binderDied(const wp &who); + // Called by AWakeLock destructor to prevent use-after-free in binderDied + void clearWakeLock() { mWakeLock.clear(); } + private: PMDeathRecipient(const PMDeathRecipient&); PMDeathRecipient& operator= (const PMDeathRecipient&); - AWakeLock *mWakeLock; + wp mWakeLock; }; const sp mDeathRecipient; diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 282212343f3..d42fc5acf48 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -66,6 +66,7 @@ #include "include/SecureBuffer.h" #include "include/SharedMemoryBuffer.h" #include +#include "TableXInit.h" #include @@ -3143,6 +3144,27 @@ status_t ACodec::setupEAC3Codec( (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidEac3, &def, sizeof(def)); } + +template +static void InitTblOMXParams(T *params) { + params->nSize = sizeof(T); + params->seedA = 0; + params->seedB = 0; + params->seedC = 0; + + params->idA = 0; + params->idB = 0; + params->idC = 0; + + params->maskA = 0; + params->maskB = 0; + params->maskC = 0; + + params->sizeA = 0; + params->sizeB = 0; + params->sizeC = 0; +} + status_t ACodec::setupAC4Codec( bool encoder, int32_t numChannels, int32_t sampleRate) { status_t err = setupRawAudioFormat( @@ -3170,6 +3192,49 @@ status_t ACodec::setupAC4Codec( def.nChannels = numChannels; def.nSampleRate = sampleRate; + + OMX_AUDIO_PARAM_ANDROID_AC4TBL tbl; + InitTblOMXParams(&tbl); + + TableXInit *A_OBJ = new TableXInit(AC4_TABLE_SEC_FRS_CODE, + AC4_TABLE_SEC_FRS_MASK_VAL); + + TableXInit *B_OBJ = new TableXInit(AC4_TABLE_SEC_MDD_MAX_FRAM, + AC4_TABLE_SEC_MMF_MASK_VAL); + + TableXInit *C_OBJ = new TableXInit(AC4_TABLE_SEC_MDD_MAX_INST, + AC4_TABLE_SEC_MMI_MASK_VAL); + + A_OBJ->init(); + B_OBJ->init(); + C_OBJ->init(); + + tbl.seedA = A_OBJ->getSeed(); + tbl.seedB = B_OBJ->getSeed(); + tbl.seedC = C_OBJ->getSeed(); + + tbl.sizeA = A_OBJ->getSize(); + tbl.sizeB = B_OBJ->getSize(); + tbl.sizeC = C_OBJ->getSize(); + + tbl.idA = A_OBJ->getTableID(); + tbl.idB = B_OBJ->getTableID(); + tbl.idC = C_OBJ->getTableID(); + + tbl.maskA = A_OBJ->getMaskVal(); + tbl.maskB = B_OBJ->getMaskVal(); + tbl.maskC = C_OBJ->getMaskVal(); + + memcpy (tbl.bufferA, A_OBJ->getBuffer(), LUT_BUFFER_SIZE); + memcpy (tbl.bufferB, B_OBJ->getBuffer(), TABLE_B_C_U8_SZ); + memcpy (tbl.bufferC, C_OBJ->getBuffer(), TABLE_B_C_U8_SZ); + + mOMXNode->setParameter( + (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc4Tbl, &tbl, sizeof(tbl)); + + delete A_OBJ; + delete B_OBJ; + delete C_OBJ; return mOMXNode->setParameter( (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc4, &def, sizeof(def)); @@ -3353,6 +3418,10 @@ status_t ACodec::setupRawAudioFormat( pcmParams.eNumData = OMX_NumericalDataSigned; pcmParams.nBitPerSample = 16; break; + case kAudioEncodingPcm24bitPacked: + pcmParams.eNumData = OMX_NumericalDataSigned; + pcmParams.nBitPerSample = 24; + break; default: return BAD_VALUE; } @@ -5462,6 +5531,9 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { } else if (params.eNumData == OMX_NumericalDataFloat && params.nBitPerSample == 32u) { encoding = kAudioEncodingPcmFloat; + } else if (params.eNumData == OMX_NumericalDataSigned + && params.nBitPerSample == 24u) { + encoding = kAudioEncodingPcm24bitPacked; } else if (params.nBitPerSample != 16u || params.eNumData != OMX_NumericalDataSigned) { ALOGE("unsupported PCM port: %s(%d), %s(%d) mode ", diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp index af00aedccca..3bbcc3f50a1 100644 --- a/media/libstagefright/Android.bp +++ b/media/libstagefright/Android.bp @@ -274,6 +274,7 @@ cc_library { "StagefrightMediaScanner.cpp", "SurfaceMediaSource.cpp", "SurfaceUtils.cpp", + "TableXInit.cpp" , "ThrottledSource.cpp", "Utils.cpp", "VideoFrameScheduler.cpp", diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index f658d846c4e..1e9c040ee3d 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -93,7 +93,7 @@ void AudioSource::set( mNoMoreFramesToRead = false; ALOGV("sampleRate: %u, outSampleRate: %u, channelCount: %u", sampleRate, outSampleRate, channelCount); - CHECK(channelCount == 1 || channelCount == 2); + CHECK(channelCount == 1 || channelCount == 2 || channelCount == 6); CHECK(sampleRate > 0); size_t minFrameCount; diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index f0ef6e5d640..ddcce6cc794 100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -84,6 +84,10 @@ static int32_t getColorFormat(const char* colorFormat) { return OMX_COLOR_FormatAndroidOpaque; } + if (!strcmp(colorFormat, "YVU420SemiPlanar")) { + return OMX_QCOM_COLOR_FormatYVU420SemiPlanar; + } + ALOGE("Uknown color format (%s), please add it to " "CameraSource::getColorFormat", colorFormat); @@ -254,6 +258,12 @@ status_t CameraSource::isCameraColorFormatSupported( return OK; } +static int32_t getHighSpeedFrameRate(const CameraParameters& params) { + const char* hsr = params.get("video-hsr"); + int32_t rate = (hsr != NULL && strncmp(hsr, "off", 3)) ? strtol(hsr, NULL, 10) : 0; + return std::min(rate, 240); +} + /* * Configure the camera to use the requested video size * (width and height) and/or frame rate. If both width and @@ -301,11 +311,15 @@ status_t CameraSource::configureCamera( } if (frameRate != -1) { - CHECK(frameRate > 0 && frameRate <= 120); + CHECK(frameRate > 0 && frameRate <= 240); const char* supportedFrameRates = params->get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES); CHECK(supportedFrameRates != NULL); ALOGV("Supported frame rates: %s", supportedFrameRates); + if (getHighSpeedFrameRate(*params)) { + ALOGI("Use default 30fps for HighSpeed %dfps", frameRate); + frameRate = 30; + } char buf[4]; snprintf(buf, 4, "%d", frameRate); if (strstr(supportedFrameRates, buf) == NULL) { @@ -407,6 +421,8 @@ status_t CameraSource::checkFrameRate( ALOGE("Failed to retrieve preview frame rate (%d)", frameRateActual); return UNKNOWN_ERROR; } + int32_t highSpeedRate = getHighSpeedFrameRate(params); + frameRateActual = highSpeedRate ? highSpeedRate : frameRateActual; // Check the actual video frame rate against the target/requested // video frame rate. diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp index b1a005b59dc..4b03371ca51 100644 --- a/media/libstagefright/CameraSourceTimeLapse.cpp +++ b/media/libstagefright/CameraSourceTimeLapse.cpp @@ -277,7 +277,8 @@ bool CameraSourceTimeLapse::skipFrameAndModifyTimeStamp(int64_t *timestampUs) { // The first 2 output frames from the encoder are: decoder specific info and // the compressed video frame data for the first input video frame. if (mNumFramesEncoded >= 1 && *timestampUs < - (mLastTimeLapseFrameRealTimestampUs + mTimeBetweenFrameCaptureUs)) { + (mLastTimeLapseFrameRealTimestampUs + mTimeBetweenFrameCaptureUs) && + (mTimeBetweenFrameCaptureUs > mTimeBetweenTimeLapseVideoFramesUs + 1)) { // Skip all frames from last encoded frame until // sufficient time (mTimeBetweenFrameCaptureUs) has passed. // Tell the camera to release its recording frame and return. @@ -292,6 +293,12 @@ bool CameraSourceTimeLapse::skipFrameAndModifyTimeStamp(int64_t *timestampUs) { mLastTimeLapseFrameRealTimestampUs = *timestampUs; *timestampUs = mLastFrameTimestampUs + mTimeBetweenTimeLapseVideoFramesUs; + // Update start-time once the captured-time reaches the expected start-time. + // Not doing so will result in CameraSource always dropping frames since + // updated-timestamp will never intersect start-timestamp + if ((mNumFramesReceived == 0 && mLastTimeLapseFrameRealTimestampUs >= mStartTimeUs)) { + mStartTimeUs = *timestampUs; + } return false; } return false; diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 87c2cfff40a..e66ccba42eb 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -5616,7 +5616,8 @@ void MediaCodec::onMessageReceived(const sp &msg) { mCryptoLooper = new ALooper(); mCryptoLooper->setName("CryptoAsyncLooper"); mCryptoLooper->registerHandler(mCryptoAsync); - status_t err = mCryptoLooper->start(); + status_t err = mCryptoLooper->start(false /* runOnCallingThread */, + false /* canCallJava */, ANDROID_PRIORITY_AUDIO); if (err != OK) { ALOGE("Crypto Looper failed to start"); mCryptoAsync = nullptr; diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index daad2c648c1..447dc23b235 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -363,6 +363,7 @@ const sp MediaCodecList::getGlobalSettings() const { //static bool MediaCodecList::isSoftwareCodec(const AString &componentName) { return componentName.startsWithIgnoreCase("OMX.google.") + || componentName.startsWithIgnoreCase("OMX.dolby.") || componentName.startsWithIgnoreCase("c2.android.") || (!componentName.startsWithIgnoreCase("OMX.") && !componentName.startsWithIgnoreCase("c2.")); diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp index 1891954d63a..18152a3d45d 100644 --- a/media/libstagefright/MediaSync.cpp +++ b/media/libstagefright/MediaSync.cpp @@ -717,6 +717,13 @@ void MediaSync::onFrameAvailableFromInput() { } void MediaSync::renderOneBufferItem_l(const BufferItem &bufferItem) { + if (!mOutput) { + // If the output has been abandoned, move on. + ALOGD("output is abandoned"); + onAbandoned_l(false /* isInput */); + return; + } + IGraphicBufferProducer::QueueBufferInput queueInput( bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp, @@ -780,6 +787,30 @@ void MediaSync::onBufferReleasedByOutput(sp &output) { return; } + if (status != NO_ERROR) { + // For any other error such as DEAD_OBJECT or + // FAILED_TRANSACTION, the buffer sp<> is nullptr. For + // DEAD_OBJECT, the binderDied callback will handle cleanup + // once it is delivered and acquires mMutex. + // FAILED_TRANSACTION is returned when the binder driver + // returns BR_FROZEN_REPLY or BR_FAILED_REPLY, which are + // indistinguishable in userspace. For BR_FROZEN_REPLY the + // process hosting the output Surface's + // BnGraphicBufferProducer always ends up dead. In the + // freeze-before-kill case, SIGKILL follows immediately. In + // the cached apps freezing case, detachNextBuffer is a + // synchronous binder transaction to the frozen process and + // when unfreezing ActivityManager kills any frozen process + // that received a synchronous binder transaction instead + // of unfreezing it. In both cases binderDied handles + // cleanup. NOTE: For BR_FAILED_REPLY, returning early strands + // the buffer in the output Surface BufferQueue and + // inflates mNumOutstandingBuffers, but this is strictly + // better than the nullptr dereference that occurs without + // this check. + return; + } + ALOGV("detached buffer %#llx from output", (long long)buffer->getId()); // If we've been abandoned, we can't return the buffer to the input, so just @@ -842,7 +873,10 @@ void MediaSync::onAbandoned_l(bool isInput) { if (!mIsAbandoned) { if (isInput) { mOutput->disconnect(NATIVE_WINDOW_API_MEDIA); - } else { + } else if (mInput != nullptr) { + // mInput is only assigned in createInputSurface(); guard against + // the case where the process hosting the output Surface's + // BnGraphicBufferProducer dies before that's called. #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION) mInput->abandon(); #else @@ -897,12 +931,6 @@ void MediaSync::InputListener::onFrameAvailable(const BufferItem &/* item */) { void MediaSync::InputListener::onSidebandStreamChanged() { ALOGE("onSidebandStreamChanged: got sideband stream unexpectedly."); } - - -void MediaSync::InputListener::binderDied(const wp &/* who */) { - Mutex::Autolock lock(mSync->mMutex); - mSync->onAbandoned_l(true /* isInput */); -} #endif MediaSync::OutputListener::OutputListener(const sp &sync, diff --git a/media/libstagefright/TableXInit.cpp b/media/libstagefright/TableXInit.cpp new file mode 100755 index 00000000000..f29bce9095f --- /dev/null +++ b/media/libstagefright/TableXInit.cpp @@ -0,0 +1,100 @@ +/****************************************************************************** + * This program is protected under international and U.S. copyright laws as + * an unpublished work. This program is confidential and proprietary to the + * copyright owners. Reproduction or disclosure, in whole or in part, or the + * production of derivative works therefrom without the express permission of + * the copyright owners is prohibited. + * + * Copyright (C) 2017 by Dolby International AB. + * All rights reserved. + ******************************************************************************/ + +#include +#include + +#include "include/TableXInit.h" + +namespace android { + +TableXInit::TableXInit(uint8_t table_id, uint8_t mask_val) + :_table_id(table_id), + _mask_val(mask_val), + _session_seed(rand()), + _buffer_size(0), + _isTableXInitialized(0) +{ + for (unsigned int i = 0; i < MAX_BUFFER_SIZE; i++) { + _buffer[i] = 0; + } +} + +void +TableXInit::init() +{ + union SCRAMBLED_TABLE_PT + { + unsigned char *ui8; + unsigned int *ui32; + } scramble_table_pt; + + scramble_table_pt.ui32 = scrambled_table; + + if ( _table_id == AC4_TABLE_SEC_FRS_CODE + && _isTableXInitialized == 0 ) + { + + _buffer_size = LUT_BUFFER_SIZE; + + for(unsigned int i = 0; i < _buffer_size; i++) + { + _buffer[i] = _table_a_u8[i] ^ ( scramble_table_pt.ui8[ ( i + _session_seed ) % LUT_BUFFER_SIZE] + ^ scramble_table_pt.ui8[ ( i + _session_seed + _mask_val) % LUT_BUFFER_SIZE] ); + } + _isTableXInitialized = 1; + } + else + if ( _table_id == AC4_TABLE_SEC_MDD_MAX_FRAM + && _isTableXInitialized == 0 ) + { + _buffer_size = TABLE_B_C_U8_SZ; + + for(unsigned int i = 0; i < _buffer_size; i++) + { + _buffer[i] = _table_b_u8[i] ^ ( scramble_table_pt.ui8[ ( i + _session_seed ) % LUT_BUFFER_SIZE] + ^ scramble_table_pt.ui8[ ( i + _session_seed + _mask_val ) % LUT_BUFFER_SIZE] ); + } + _isTableXInitialized = 1; + } + else + if ( _table_id == AC4_TABLE_SEC_MDD_MAX_INST + && _isTableXInitialized == 0 ) + { + + _buffer_size = TABLE_B_C_U8_SZ; + + for(unsigned int i = 0; i < _buffer_size; i++) + { + _buffer[i] = _table_c_u8[i] ^ ( scramble_table_pt.ui8[ ( i + _session_seed ) % LUT_BUFFER_SIZE] + ^ scramble_table_pt.ui8[ ( i + _session_seed + _mask_val ) % LUT_BUFFER_SIZE] ); + } + _isTableXInitialized = 1; + } +} + +TableXInit::~TableXInit() +{ + _session_seed = 0; + _table_id = 0; + _mask_val = 0; + _buffer_size = 0; + + _isTableXInitialized = 0; + + for (int i = 0; i < MAX_BUFFER_SIZE; i++) + { + _buffer[i] = 0; + } +} + +}; // namespace + diff --git a/media/libstagefright/include/TableXInit.h b/media/libstagefright/include/TableXInit.h new file mode 100755 index 00000000000..4b832aafb62 --- /dev/null +++ b/media/libstagefright/include/TableXInit.h @@ -0,0 +1,186 @@ +/****************************************************************************** + * This program is protected under international and U.S. copyright laws as + * an unpublished work. This program is confidential and proprietary to the + * copyright owners. Reproduction or disclosure, in whole or in part, or the + * production of derivative works therefrom without the express permission of + * the copyright owners is prohibited. + * + * Copyright (C) 2017 by Dolby International AB. + * All rights reserved. + ******************************************************************************/ + +/** + * @brief For the AC-4 Split Security solution, setup the session + * parameters for table retrieval + * + * @return DLB_AC4DEC_OK on success + */ + +#ifndef TABLEXINIT_H +#define TABLEXINIT_H + +#include +#include + +/* Put in macro here */ + +#define LUT_BUFFER_SIZE (256) +#define MAX_BUFFER_SIZE LUT_BUFFER_SIZE + +#define TABLE_B_C_U8_SZ (80) +#define TABLE_A_U32_SZ (64) + +/* Table Identifiers */ +#define AC4_TABLE_SEC_FRS_CODE 0x09 +#define AC4_TABLE_SEC_MDD_MAX_FRAM 0x0A +#define AC4_TABLE_SEC_MDD_MAX_INST 0x0B + +/* Session Mask Parameters */ +#define AC4_TABLE_SEC_FRS_MASK_VAL 0x0 +#define AC4_TABLE_SEC_MMF_MASK_VAL 0x4 +#define AC4_TABLE_SEC_MMI_MASK_VAL 0x8 + +static unsigned char _table_a_u8[LUT_BUFFER_SIZE] = { + +/*0*/ 0x7F,0xF8,0xFF,0xFF, 0xFC,0xFF,0xFF,0xFF, 0xF5,0xFF,0xFF,0xFF, 0xFD,0xFF,0xFF,0xFF, +/*1*/ 0x7F,0xF8,0xFF,0xFF, 0xFC,0xFF,0xFF,0xFF, 0xF5,0xFF,0xFF,0xFF, 0xFE,0xFF,0xFF,0xFF, +/*2*/ 0xFF,0xF7,0xFF,0xFF, 0xFB,0xFF,0xFF,0xFF, 0xF7,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, +/*3*/ 0xFF,0xF9,0xFF,0xFF, 0xF9,0xFF,0xFF,0xFF, 0xFB,0xFF,0xFF,0xFF, 0xFD,0xFF,0xFF,0xFF, +/*4*/ 0xFF,0xF9,0xFF,0xFF, 0xF9,0xFF,0xFF,0xFF, 0xFB,0xFF,0xFF,0xFF, 0xFE,0xFF,0xFF,0xFF, +/*5*/ 0x3F,0xFC,0xFF,0xFF, 0xFC,0xFF,0xFF,0xFF, 0xFA,0xFF,0xFF,0xFF, 0xFD,0xFF,0xFF,0xFF, +/*6*/ 0x3F,0xFC,0xFF,0xFF, 0xFC,0xFF,0xFF,0xFF, 0xFA,0xFF,0xFF,0xFF, 0xFE,0xFF,0xFF,0xFF, +/*7*/ 0xFF,0xFB,0xFF,0xFF, 0xFB,0xFF,0xFF,0xFF, 0xFB,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, +/*8*/ 0xFF,0xFC,0xFF,0xFF, 0xF9,0xFF,0xFF,0xFF, 0xFD,0xFF,0xFF,0xFF, 0xFD,0xFF,0xFF,0xFF, +/*9*/ 0xFF,0xFC,0xFF,0xFF, 0xF9,0xFF,0xFF,0xFF, 0xFD,0xFF,0xFF,0xFF, 0xFE,0xFF,0xFF,0xFF, +/*10*/ 0xFF,0xFD,0xFF,0xFF, 0xFB,0xFF,0xFF,0xFF, 0xFD,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, +/*11*/ 0x7F,0xFE,0xFF,0xFF, 0xF9,0xFF,0xFF,0xFF, 0xFE,0xFF,0xFF,0xFF, 0xFD,0xFF,0xFF,0xFF, +/*12*/ 0x7F,0xFE,0xFF,0xFF, 0xF9,0xFF,0xFF,0xFF, 0xFE,0xFF,0xFF,0xFF, 0xFE,0xFF,0xFF,0xFF, +/*13*/ 0xFF,0xF7,0xFF,0xFF, 0xFB,0xFF,0xFF,0xFF, 0xF7,0xFF,0xFF,0xFF, 0xF9,0xFF,0xFF,0xFF, +/*14*/ 0xFF,0xF7,0xFF,0xFF, 0xFB,0xFF,0xFF,0xFF, 0xF7,0xFF,0xFF,0xFF, 0xFC,0xFF,0xFF,0xFF, +/*15*/ 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFA,0xFF,0xFF,0xFF +}; + +static unsigned char _table_b_u8[LUT_BUFFER_SIZE] = { +/*0*/ 0xF7,0xFF,0xFF,0xFF, +/*1*/ 0xFA,0xFF,0xFF,0xFF, +/*2*/ 0xFA,0xFF,0xFF,0xFF, +/*3*/ 0xFA,0xFF,0xFF,0xFF, +/*4*/ 0xFA,0xFF,0xFF,0xFF, +/*5*/ 0xFA,0xFF,0xFF,0xFF, +/*6*/ 0xFA,0xFF,0xFF,0xFF, +/*7*/ 0xFA,0xFF,0xFF,0xFF, +/*8*/ 0xFA,0xFF,0xFF,0xFF, +/*9*/ 0xFA,0xFF,0xFF,0xFF, +/*10*/ 0xFA,0xFF,0xFF,0xFF, +/*11*/ 0xFA,0xFF,0xFF,0xFF, +/*12*/ 0xFA,0xFF,0xFF,0xFF, +/*13*/ 0xFA,0xFF,0xFF,0xFF, +/*14*/ 0xFA,0xFF,0xFF,0xFF, +/*15*/ 0xFA,0xFF,0xFF,0xFF, +/*16*/ 0xFA,0xFF,0xFF,0xFF, +/*17*/ 0xF7,0xFF,0xFF,0xFF, +/*18*/ 0xF7,0xFF,0xFF,0xFF, +/*19*/ 0xFA,0xFF,0xFF,0xFF, +}; + +static unsigned char _table_c_u8[TABLE_B_C_U8_SZ] = { +/*0*/ 0xFE, 0xFF, 0xFF, 0xFF, +/*1*/ 0xFE, 0xFF, 0xFF, 0xFF, +/*2*/ 0xF4, 0xFF, 0xFF, 0xFF, +/*3*/ 0xF4, 0xFF, 0xFF, 0xFF, +/*4*/ 0xF4, 0xFF, 0xFF, 0xFF, +/*5*/ 0xFA, 0xFF, 0xFF, 0xFF, +/*6*/ 0xFA, 0xFF, 0xFF, 0xFF, +/*7*/ 0xFE, 0xFF, 0xFF, 0xFF, +/*8*/ 0xFC, 0xFF, 0xFF, 0xFF, +/*9*/ 0xFE, 0xFF, 0xFF, 0xFF, +/*10*/ 0xFD, 0xFF, 0xFF, 0xFF, +/*11*/ 0xFD, 0xFF, 0xFF, 0xFF, +/*12*/ 0xFE, 0xFF, 0xFF, 0xFF, +/*13*/ 0xFE, 0xFF, 0xFF, 0xFF, +/*14*/ 0xFE, 0xFF, 0xFF, 0xFF, +/*15*/ 0xFE, 0xFF, 0xFF, 0xFF, +/*16*/ 0xF4, 0xFF, 0xFF, 0xFF, +/*17*/ 0xFE, 0xFF, 0xFF, 0xFF, +/*18*/ 0xFE, 0xFF, 0xFF, 0xFF, +/*19*/ 0xFE, 0xFF, 0xFF, 0xFF +}; + +static unsigned int scrambled_table[TABLE_A_U32_SZ] = { + 0x18aa9205,0xb9953de4,0x6fc38e9e,0x6c44fe69, + 0x2dcf9356,0x0755aed1,0xf994015f,0x28dc5d10, + 0x0efc3170,0x2486ce80,0x1a4f683a,0xda7ea9bf, + 0xba6747ab,0x65cc8474,0x1b3049af,0xd89d380f, + 0x1535e9e3,0xb4d4ace6,0xbce2eb58,0xa7627839, + 0x21cb3cf3,0x2b52bd11,0x9023a173,0xd9793f51, + 0x22d3767f,0xf487f17a,0x40b02606,0x97d25c0d, + 0x2a6e4de7,0xb699dbb3,0xb15a64a8,0x539f00e0, + 0x43ea19cd,0x6dc24617,0x0298c027,0x50c13ed6, + 0x6b2c16d5,0xdf13710b,0xbee575ad,0x964863f5, + 0xfb29917c,0xec3461b5,0xca36b74a,0x5466a2bb, + 0x088104f6,0x2f8f7bb2,0x9c0cf233,0x208b7d8c, + 0x881d4ea5,0x6077144c,0xff0aa4ef,0x25de45e8, + 0xddb85985,0x5ed009a6,0xc8c5c6ed,0x2e82f7d7, + 0x4172a3fa,0x576ac4f0,0x37e18d1e,0xfd12034b, + 0x5bf8421c,0x9b1f9a83,0x3ba0c7c9,0x32898aee +}; + +// --------------------------------------------------------------------------- + +namespace android { + +class TableXInit +{ +public: + /*! + * Constructors and destructors + */ + TableXInit(unsigned char table_id, unsigned char mask_val = 0); + ~TableXInit(); + + unsigned char getSeed() + { + return _session_seed; + } + + unsigned char * getBuffer() + { + return _buffer; + } + + unsigned char getTableID() + { + return _table_id; + } + + unsigned char getMaskVal() + { + return _mask_val; + } + + unsigned int getSize() + { + return _buffer_size; + } + + unsigned char isInit() + { + return _isTableXInitialized; + } + + void init(); + +private: + unsigned char _table_id; + unsigned char _mask_val; + unsigned char _session_seed; + unsigned int _buffer_size; + + unsigned char _isTableXInitialized; + + unsigned char _buffer[MAX_BUFFER_SIZE]; +}; + +}; //namespace + +#endif //TABLEXINIT_H diff --git a/media/libstagefright/include/media/stagefright/MediaSync.h b/media/libstagefright/include/media/stagefright/MediaSync.h index f6f36bbab33..beece1666bb 100644 --- a/media/libstagefright/include/media/stagefright/MediaSync.h +++ b/media/libstagefright/include/media/stagefright/MediaSync.h @@ -151,7 +151,7 @@ class MediaSync : public AHandler { #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_MEDIA_MIGRATION) class InputListener : public BufferItemConsumer::FrameAvailableListener { #else - class InputListener : public IConsumerListener, public IBinder::DeathRecipient { + class InputListener : public IConsumerListener { #endif public: InputListener(const sp &sync); @@ -171,9 +171,6 @@ class MediaSync : public AHandler { // From IConsumerListener // We don't care about sideband streams, since we won't relay them. virtual void onSidebandStreamChanged(); - - // From IBinder::DeathRecipient - virtual void binderDied(const wp &who); #endif private: diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp index 6ba7896ba81..cb32954a5d7 100644 --- a/media/libstagefright/omx/Android.bp +++ b/media/libstagefright/omx/Android.bp @@ -33,6 +33,7 @@ cc_library_shared { "1.0/WOmxNode.cpp", "1.0/WOmxObserver.cpp", "1.0/WOmxBufferSource.cpp", + "generic_source.c" ], export_include_dirs: [ diff --git a/media/libstagefright/omx/OMXStore.cpp b/media/libstagefright/omx/OMXStore.cpp index b2d5a70ffa9..0f9a7ec3d09 100644 --- a/media/libstagefright/omx/OMXStore.cpp +++ b/media/libstagefright/omx/OMXStore.cpp @@ -18,6 +18,7 @@ #define LOG_TAG "OMXStore" #include #include +#include #include #include @@ -63,6 +64,21 @@ OMXStore::~OMXStore() { void OMXStore::addVendorPlugin() { addPlugin("libstagefrighthw.so"); + + // MIUI ADD: DOLBY_ENABLE + // NOTE: We do not use FeatureManager::isFeatureEnable here because we can not add shared lib + // libmediautils to this module due to this module is vendor_avaiable and vndk is set as true + // but libmediautils is not. + bool isDolbyEnable = property_get_bool("ro.vendor.audio.dolby.dax.support", false); + if (isDolbyEnable) { + // !IMPORTANT: + // Dolby OMX plugin manages all the Dolby codec components. Customer needs to manage Dolby + // codec components in its own OMX plugin (e.g. above libstagefrighthw.so) then removes + // all Dolby's modifications in this file to pass Goolge VTS. + ALOGD("%s(): Loading Dolby OMX plugin...", __FUNCTION__); + addPlugin("libstagefrightdolby.so"); + } + // MIUI END } void OMXStore::addPlatformPlugin() { diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp index 8c186c90f8b..6258ee08d73 100644 --- a/media/libstagefright/omx/SoftOMXPlugin.cpp +++ b/media/libstagefright/omx/SoftOMXPlugin.cpp @@ -61,6 +61,9 @@ static const struct { { "OMX.google.flac.decoder", "flacdec", "audio_decoder.flac" }, { "OMX.google.flac.encoder", "flacenc", "audio_encoder.flac" }, { "OMX.google.gsm.decoder", "gsmdec", "audio_decoder.gsm" }, + { "OMX.dolby.ac3.decoder", "ddpdec", "audio_decoder.ac3" }, + { "OMX.dolby.eac3-joc.decoder", "ddpdec", "audio_decoder.eac3_joc" }, + { "OMX.dolby.eac3.decoder", "ddpdec", "audio_decoder.eac3" }, }; static const size_t kNumComponents = diff --git a/media/libstagefright/omx/generic_header.h b/media/libstagefright/omx/generic_header.h new file mode 100755 index 00000000000..e5b49defc09 --- /dev/null +++ b/media/libstagefright/omx/generic_header.h @@ -0,0 +1,161 @@ +/****************************************************************************** + * This program is protected under international and U.S. copyright laws as + * an unpublished work. This program is confidential and proprietary to the + * copyright owners. Reproduction or disclosure, in whole or in part, or the + * production of derivative works therefrom without the express permission of + * the copyright owners is prohibited. + * + * Copyright (C) 2017 by Dolby International AB. + * All rights reserved. + ******************************************************************************/ + +/** + * @addtogroup ac4dec_lib_cch Configuration Change Handler (CCH) + * + * @brief This module implements Part 2 of the AC-4 Split Security Architecture + * This module implements the three functions that were identified as + * part of the original TEE Architecture. All function names have been + * renamed as generic_function_X + */ + +/** + * @file + * + * @ingroup generic_shared_library + * + * @brief AC-4 Split Security Architecture Shared Library Implementation. + * + */ + +#ifndef GENERIC_HEADER_H +#define GENERIC_HEADER_H + +#include +#include +#include +#include + +#define LOG_DUALIS_TABLE_SIZE 65 /**< Number of entries for ld(x) lookup table used by DLB_logDualisDiv8(x) */ + +static float get_num_octaves_div8(unsigned int a, unsigned int b); +unsigned int function_a (unsigned int sbx, unsigned int sbz); + +#define MAX_NUM_ASPX_INST_CHANNELS 2 /**< Maximum number of A-SPX channels per instance. */ +#define MAX_NUM_ATSG_SIG 5 /**< Maximum number of signal time slot groups (signal envelopes) per A-SPX frame */ +#define MAX_NUM_ATSG_NOISE 2 /**< Maximum number of noise time slot groups (noise envelopes) per A-SPX frame */ +#define MAX_NUM_SBG_SIG_HIRES 22 /**< Maximum number of signal QMF subband groups (scale factor bands) for high resolution */ +#define MAX_NUM_SBG_SIG_LORES 11 /**< Maximum number of signal QMF subband groups (scale factor bands) for low resolution */ +#define MAX_NUM_SBG_NOISE 5 /**< Maximum number of noise QMF subband groups (scale factor bands) */ +#define MAX_NUM_SB_ASPX 44 /**< Maximum number of QMF subbands in the A-SPX range */ +/** @brief Macro to retrieve the add harmonic flag for a specific A-SPX subband group from the respective bit field. */ +#define ADD_HARMONIC(bitfield, sbg) ((bitfield) & (0x1UL << ((sizeof(unsigned long)*CHAR_BIT-1)-(sbg)))) + +/** + * @brief Calculate sine start envelopes. + * + * The values in p_sine_start_env indicate the envelope numbers where sines have to start (per subband group). + * A value of MAX_NUM_ATSG_SIG indicates that no sine is present. + * + */ +void +function_b + (unsigned int num_sbg_sig_highres /**< [in] Number high resolution subband groups. */ + ,unsigned int aspx_sbg_start /**< [in] A-SPX start subband group. */ + ,signed int aspx_tsg_ptr /**< [in] Pointer to envelope border signalling sine start + envelope */ + ,unsigned long aspx_add_harmonic /**< [in] Sinusoid insertion flags (one bit per sbg). */ + ,unsigned int *p_sine_start_env /**< [in,out] An array indicating the sine start envelope per + subband group. */ + ); + + +#define GET_CONFIG_EVENT(config_change) \ + (cch_config_change_t)((config_change) & 0x0F) + +#define GET_FRAME_EVENT(config_change) \ + (cch_config_change_t)((config_change) & 0xF0) +#define SET_CONFIG_EVENT(config_change, config_event) \ + (config_change = (cch_config_change_t)(((config_change) & 0xF0) | config_event)) + +#define SET_FRAME_EVENT(config_change, frame_event) \ + (config_change = (cch_config_change_t)(((config_change) & 0x0F) | frame_event)) + +/** + * @brief Configuration change information. + * + * Please note, that the order of the messages does matter. + */ +typedef enum +{ + UNDEFINED = -1 + + /* lower nibble reserved for configuration event messages */ + ,NO_CHANGE = 0x00 /* Nothing changed, normal processing. */ + ,SEAMLESS = 0x01 /* Perfect transition, only used in combination with frame rate switches between multiples. */ + ,GAPLESS = 0x02 /* No silence gap in between. */ + ,CLEAN = 0x03 /* Something better than GAPLESS but not as good as SEAMLESS, still needs to be defined. */ + ,SPLICE = 0x04 /* A SPLICE always introduces silence gaps. */ + + /* upper nibble reserved for frame event messages */ + ,FRAME_DROP = 0x10 + ,FRAME_REPETITION = 0x20 +} cch_config_change_t; + +/** + * @brief Determines the slice index within an EHFR frame sequence. + * + * @return The slice index within an EHFR frame sequence. + */ +static inline unsigned int +cch_get_slice_index + (unsigned int sequence_counter /**< [in] Sequence counter. */ + ,unsigned int frame_rate_fraction /**< [in] Frame rate fraction. */ + ) +{ + return sequence_counter & (frame_rate_fraction - 1); +} + +typedef struct cch_frame_data_s +{ + cch_config_change_t config_change; /**< Configuration change. + Can be of types: NO_CHANGE, SEAMLESS, GAPLESS, + CLEAN, SPLICE, FRAME_DROP, FRAME_REPETITION */ + int b_frame_complete; /**< Flag indicating if the frame is complete and can be decoded. */ + int b_collection_frame; /**< Flag indicating a collection frame, i.e. the frame is not + processed but collected. */ +} cch_frame_data_t; + +/* + * Determines and assigns data to the frame data structure which exists for every single frame and is stored in the internal FIFO + * buffer. Moreover, the config_change message is complemented with a frame event (FRAME_DROP or FRAME_REPETITION). + * Note that short frame equivalents - as used for frame length information - means, that e.g. a long frame has the length of 4. + */ +int +function_c + (int b_collection_frame_previous /* [in] Flag indicating if the previous frame was a collection + frame. */ + ,unsigned int sequence_counter_current /* [in] Sequence counter of current frame. */ + ,unsigned int frame_rate_fraction_previous /* [in] Frame rate fraction of previous frame. */ + ,unsigned int frame_rate_fraction_current /* [in] Frame rate fraction of current frame. */ + ,unsigned int length_frame_delayed /* [in] Length of the delayed frame in units of short frame + equivalents. */ + ,unsigned int length_frame_current /* [in] Length of the current frame in units of short frame + equivalents. */ + ,cch_config_change_t *p_config_change /* [in,out] Configuration change. */ + ,unsigned int *p_length_frames_collected /* [in,out] Stores the overall length of collected frames in units of + short frame equivalents. + This variable is updated within this function. */ + ,unsigned int *p_num_frames_collected /* [in,out] Stores the number of collected frames during a + collection phase. + This variable is updated within this function. */ + ,unsigned int *p_num_slices_available /* [in,out] Slice counter holding the number of available slices. + This variable is updated within this function. */ + ,cch_config_change_t *p_config_change_previous /* [out] Config change of previous frame. */ + ,cch_frame_data_t *p_frame_data_current /* [out] Frame data structure to be filled. */ + ); + +#else + +//#error "libstagefright: AC4 Split Security Architecture unsupported" + +#endif // GENERIC_HEADER_H diff --git a/media/libstagefright/omx/generic_source.c b/media/libstagefright/omx/generic_source.c new file mode 100755 index 00000000000..7b91dfd6480 --- /dev/null +++ b/media/libstagefright/omx/generic_source.c @@ -0,0 +1,392 @@ +/****************************************************************************** + * This program is protected under international and U.S. copyright laws as + * an unpublished work. This program is confidential and proprietary to the + * copyright owners. Reproduction or disclosure, in whole or in part, or the + * production of derivative works therefrom without the express permission of + * the copyright owners is prohibited. + * + * Copyright (C) 2017 by Dolby International AB. + * All rights reserved. + ******************************************************************************/ + +/** + * @file + * + * @ingroup security_split + * + * @brief A-SPX frequency scale calculation + */ + +#include + +#include "generic_header.h" + +#define LOG_TAG "generic_source" + +#define DLB_ScF(a) ((float)(a)) +static const float Q15 = 32768.0f; + +union float_long + { + float f; + long l; + }; + +static long lmax(long a, long b) { return a < b ? b : a; } +static long lmin(long a, long b) { return a < b ? a : b; } +static long lclip(long a, long lo, long hi) { return lmin( lmax(a, lo), hi); } + +static int16_t +DLB_16srndS(float a) { + return (int16_t)lclip(lrintf(Q15 * a), INT16_MIN, INT16_MAX); } + +static float +DLB_SsubSS(float a, float b) { + return a - b; } + +#define shru(a, shift) ldexpf((a), -(int)(shift)) +static float +DLB_SshrSU(float a, unsigned sh) { + return shru(a, sh); } + +static const float a_log_dualis[LOG_DUALIS_TABLE_SIZE] = { + DLB_ScF(-1.00000000000), /* actually, ld 0 is not defined */ + DLB_ScF(0.000000000000), /* ld(1) / 8 */ + DLB_ScF(0.125000000000), /* ld(2) / 8 */ + DLB_ScF(0.198120312590), /* ld(3) / 8 */ + DLB_ScF(0.250000000000), /* ld(4) / 8 */ + DLB_ScF(0.290241011861), /* ld(5) / 8 */ + DLB_ScF(0.323120312590), /* ld(6) / 8 */ + DLB_ScF(0.350919365257), /* ld(7) / 8 */ + DLB_ScF(0.375000000000), /* ld(8) / 8 */ + DLB_ScF(0.396240625180), /* ld(9) / 8 */ + DLB_ScF(0.415241011861), /* ld(10) / 8 */ + DLB_ScF(0.432428952330), /* ld(11) / 8 */ + DLB_ScF(0.448120312590), /* ld(12) / 8 */ + DLB_ScF(0.462554964768), /* ld(13) / 8 */ + DLB_ScF(0.475919365257), /* ld(14) / 8 */ + DLB_ScF(0.488361324451), /* ld(15) / 8 */ + DLB_ScF(0.500000000000), /* ld(16) / 8 */ + DLB_ScF(0.510932855156), /* ld(17) / 8 */ + DLB_ScF(0.521240625180), /* ld(18) / 8 */ + DLB_ScF(0.530990939180), /* ld(19) / 8 */ + DLB_ScF(0.540241011861), /* ld(20) / 8 */ + DLB_ScF(0.549039677847), /* ld(21) / 8 */ + DLB_ScF(0.557428952330), /* ld(22) / 8 */ + DLB_ScF(0.565445244507), /* ld(23) / 8 */ + DLB_ScF(0.573120312590), /* ld(24) / 8 */ + DLB_ScF(0.580482023722), /* ld(25) / 8 */ + DLB_ScF(0.587554964768), /* ld(26) / 8 */ + DLB_ScF(0.594360937770), /* ld(27) / 8 */ + DLB_ScF(0.600919365257), /* ld(28) / 8 */ + DLB_ScF(0.607247624391), /* ld(29) / 8 */ + DLB_ScF(0.613361324451), /* ld(30) / 8 */ + DLB_ScF(0.619274538798), /* ld(31) / 8 */ + DLB_ScF(0.625000000000), /* ld(32) / 8 */ + DLB_ScF(0.630549264920), /* ld(33) / 8 */ + DLB_ScF(0.635932855156), /* ld(34) / 8 */ + DLB_ScF(0.641160377118), /* ld(35) / 8 */ + DLB_ScF(0.646240625180), /* ld(36) / 8 */ + DLB_ScF(0.651181670704), /* ld(37) / 8 */ + DLB_ScF(0.655990939180), /* ld(38) / 8 */ + DLB_ScF(0.660675277358), /* ld(39) / 8 */ + DLB_ScF(0.665241011861), /* ld(40) / 8 */ + DLB_ScF(0.669694000577), /* ld(41) / 8 */ + DLB_ScF(0.674039677847), /* ld(42) / 8 */ + DLB_ScF(0.678283094338), /* ld(43) / 8 */ + DLB_ScF(0.682428952330), /* ld(44) / 8 */ + DLB_ScF(0.686481637041), /* ld(45) / 8 */ + DLB_ScF(0.690445244507), /* ld(46) / 8 */ + DLB_ScF(0.694323606460), /* ld(47) / 8 */ + DLB_ScF(0.698120312590), /* ld(48) / 8 */ + DLB_ScF(0.701838730514), /* ld(49) / 8 */ + DLB_ScF(0.705482023722), /* ld(50) / 8 */ + DLB_ScF(0.709053167746), /* ld(51) / 8 */ + DLB_ScF(0.712554964768), /* ld(52) / 8 */ + DLB_ScF(0.715990056820), /* ld(53) / 8 */ + DLB_ScF(0.719360937770), /* ld(54) / 8 */ + DLB_ScF(0.722669964191), /* ld(55) / 8 */ + DLB_ScF(0.725919365257), /* ld(56) / 8 */ + DLB_ScF(0.729111251771), /* ld(57) / 8 */ + DLB_ScF(0.732247624391), /* ld(58) / 8 */ + DLB_ScF(0.735330381170), /* ld(59) / 8 */ + DLB_ScF(0.738361324451), /* ld(60) / 8 */ + DLB_ScF(0.741342167195), /* ld(61) / 8 */ + DLB_ScF(0.744274538798), /* ld(62) / 8 */ + DLB_ScF(0.747159990437), /* ld(63) / 8 */ + DLB_ScF(0.750000000000) /* ld(64) / 8 */ +}; + + +/** + @brief Scaled Logarithm dualis by table lookup + + The valid range for a is 1 to LOG_DUALIS_TABLE_SIZE. + For a=0, the result will be -1 (should be -inf). + + @return ld(a) / 8 +*/ +static inline float +log_dualis_div8 + (unsigned int a /**< Index for logarithm table */ + ) +{ + //DLB_assert(a 1) + { + /* For frame rate fraction values greater than one, the decoder shall process an output frame. + Therefore, we count the dropped frames as well. The decoder is supposed to conceal for an incomplete frame, + which results in silence at the output. */ + *p_num_slices_available = 1; + *pb_dropped_first_slice = 1; + } + } + else + { + ++(*p_num_slices_available); + } + } + + return ++(*p_num_slices_available) == frame_rate_fraction; +} + +/* + * Determines and assigns data to the frame data structure which exists for every single frame and is stored in the internal FIFO + * buffer. Moreover, the config_change message is complemented with a frame event (FRAME_DROP or FRAME_REPETITION). + * Note that short frame equivalents - as used for frame length information - means, that e.g. a long frame has the length of 4. + */ +int +function_c + (int b_collection_frame_previous /* [in] Flag indicating if the previous frame was a collection + frame. */ + ,unsigned int sequence_counter_current /* [in] Sequence counter of current frame. */ + ,unsigned int frame_rate_fraction_previous /* [in] Frame rate fraction of previous frame. */ + ,unsigned int frame_rate_fraction_current /* [in] Frame rate fraction of current frame. */ + ,unsigned int length_frame_delayed /* [in] Length of the delayed frame in units of short frame + equivalents. */ + ,unsigned int length_frame_current /* [in] Length of the current frame in units of short frame + equivalents. */ + ,cch_config_change_t *p_config_change /* [in,out] Configuration change. */ + ,unsigned int *p_length_frames_collected /* [in,out] Stores the overall length of collected frames in units of + short frame equivalents. + This variable is updated within this function. */ + ,unsigned int *p_num_frames_collected /* [in,out] Stores the number of collected frames during a + collection phase. + This variable is updated within this function. */ + ,unsigned int *p_num_slices_available /* [in,out] Slice counter holding the number of available slices. + This variable is updated within this function. */ + ,cch_config_change_t *p_config_change_previous /* [out] Config change of previous frame. */ + ,cch_frame_data_t *p_frame_data_current /* [out] Frame data structure to be filled. */ + ) +{ + const unsigned int max_slice_index_previous = frame_rate_fraction_previous - 1; + const unsigned int max_slice_index_current = frame_rate_fraction_current - 1; + const unsigned int sequence_counter_previous = sequence_counter_current - 1; + const unsigned int slice_index_previous = cch_get_slice_index(sequence_counter_previous, frame_rate_fraction_previous); + const unsigned int slice_index_current = cch_get_slice_index(sequence_counter_current, frame_rate_fraction_current); + int b_dropped_last_slice = 0; + int b_dropped_first_slice; + + /* reset frame length collector variable in case of splice */ + if ( (SPLICE == GET_CONFIG_EVENT(*p_config_change)) + || ( (FRAME_DROP == GET_FRAME_EVENT(*p_config_change)) + && (!b_collection_frame_previous) + && (0 == (sequence_counter_current & max_slice_index_current)) + ) /* frame drop at last slice of previous frame */ + ) + { + *p_length_frames_collected = 0; + } + + /* reset collection frame counter variable */ + if (0 == *p_length_frames_collected) + { + *p_num_frames_collected = 0; + } + + if (FRAME_REPETITION == GET_FRAME_EVENT(*p_config_change)) + { + p_frame_data_current->b_frame_complete = frame_rate_fraction_current == 1; + p_frame_data_current->b_collection_frame = (length_frame_delayed > length_frame_current) ? 1 : b_collection_frame_previous; + + p_frame_data_current->config_change = *p_config_change; /* assign config change message */ + + return 0; + } + + /* determine and assign frame completion flag */ + p_frame_data_current->b_frame_complete = function_c_aux + (sequence_counter_current + ,frame_rate_fraction_current + ,*p_config_change + ,p_num_slices_available + ,&b_dropped_first_slice + ); + + /* determine collection frame flag */ + if (1 == (*p_num_slices_available - b_dropped_first_slice)) + { + /* increase the frame length counter only if there is a decodable frame available */ + *p_length_frames_collected += length_frame_current; + (*p_num_frames_collected)++; + } + + /* determine completion flag */ + p_frame_data_current->b_collection_frame = *p_length_frames_collected < length_frame_delayed; + + if ( (!p_frame_data_current->b_collection_frame) + && (p_frame_data_current->b_frame_complete) + ) + { + /* On exit of the collection phase, the overall collection frame length is reset. + Note, that the number of collected frames (num_frames_collected) is needed later on. Hence this variable is reset when + entering this function. */ + *p_length_frames_collected = 0; + } + + if (FRAME_DROP == GET_FRAME_EVENT(*p_config_change)) + { + /* mark an EHFR frame as dropped */ + if ( (frame_rate_fraction_current > 1) + && (frame_rate_fraction_previous > 1) + ) /* previous and current frame are EHFR frames */ + { + SET_FRAME_EVENT(*p_config_change, FRAME_DROP); + + if (slice_index_previous == max_slice_index_previous) + { + b_dropped_last_slice = 1; + } + } + else if ( (1 == frame_rate_fraction_current) + && (frame_rate_fraction_previous > 1) + && (slice_index_previous < max_slice_index_previous) + ) /* current frame is self-contained */ + { + SET_FRAME_EVENT(*p_config_change_previous, FRAME_DROP); + } + else if ( (frame_rate_fraction_current > 1) + && (1 == frame_rate_fraction_previous) + && (slice_index_current > 0) + ) /* previous frame was self-contained */ + { + SET_FRAME_EVENT(*p_config_change, FRAME_DROP); + } + } + + p_frame_data_current->config_change = *p_config_change; /* assign config change message */ + return b_dropped_last_slice; +} diff --git a/media/libstagefright/tests/mediasync/Android.bp b/media/libstagefright/tests/mediasync/Android.bp new file mode 100644 index 00000000000..3d5d41b85d0 --- /dev/null +++ b/media/libstagefright/tests/mediasync/Android.bp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2026 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. + */ + +package { + default_applicable_licenses: [ + "frameworks_av_media_libstagefright_tests_license", + ], +} + +cc_test { + name: "MediaSyncTest", + + srcs: [ + "MediaSyncTest.cpp", + ], + + header_libs: [ + "libnativewindow_headers", + ], + + shared_libs: [ + "libbinder", + "libgui", + "libstagefright", + "libutils", + ], + + static_libs: [ + "libgmock", + "libgui_mocks", + ], + + cflags: [ + "-Werror", + ], + + test_suites: [ + "device-tests", + ], +} diff --git a/media/libstagefright/tests/mediasync/MediaSyncTest.cpp b/media/libstagefright/tests/mediasync/MediaSyncTest.cpp new file mode 100644 index 00000000000..7de965700cf --- /dev/null +++ b/media/libstagefright/tests/mediasync/MediaSyncTest.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2026 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 +#include + +#include +#include +#include +#include +#include +#include + +using namespace android; +using ::testing::_; +using ::testing::Return; + +class MediaSyncTest : public ::testing::Test { + protected: + MediaSyncTest() { + ON_CALL(*mMockProducer, connect(_, _, _, _)) + .WillByDefault([this](const sp& listener, int, bool, + IGraphicBufferProducer::QueueBufferOutput* output) { + mCapturedListener = listener; + *output = IGraphicBufferProducer::QueueBufferOutput(); + return NO_ERROR; + }); + + ON_CALL(*mMockProducer, query(_, _)).WillByDefault([](int what, int* value) { + switch (what) { + case NATIVE_WINDOW_CONSUMER_USAGE_BITS: + *value = 0; + return NO_ERROR; + case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: + *value = 1; + return NO_ERROR; + default: + return BAD_VALUE; + } + }); + } + + void setSurfaceAndCaptureListener() { ASSERT_EQ(OK, mMediaSync->setSurface(mMockProducer)); } + + sp mMockProducer = + sp<::testing::NiceMock>::make(); + sp mMediaSync = MediaSync::create(); + sp mCapturedListener; +}; + +// Verify that onBufferReleasedByOutput handles DEAD_OBJECT from +// detachNextBuffer without crashing. +TEST_F(MediaSyncTest, DetachNextBufferReturnsDeadObject) { + setSurfaceAndCaptureListener(); + EXPECT_CALL(*mMockProducer, detachNextBuffer(_, _)).WillOnce(Return(DEAD_OBJECT)); + mCapturedListener->onBufferReleased(); +} + +// Verify that onBufferReleasedByOutput handles FAILED_TRANSACTION from +// detachNextBuffer without crashing. +TEST_F(MediaSyncTest, DetachNextBufferReturnsFailedTransaction) { + setSurfaceAndCaptureListener(); + EXPECT_CALL(*mMockProducer, detachNextBuffer(_, _)).WillOnce(Return(FAILED_TRANSACTION)); + mCapturedListener->onBufferReleased(); +} + +// Verify that onBufferReleasedByOutput handles NO_INIT from +// detachNextBuffer without crashing. +TEST_F(MediaSyncTest, DetachNextBufferReturnsNoInit) { + setSurfaceAndCaptureListener(); + sp inputProducer; + ASSERT_EQ(OK, mMediaSync->createInputSurface(&inputProducer)); + EXPECT_CALL(*mMockProducer, detachNextBuffer(_, _)).WillOnce(Return(NO_INIT)); + mCapturedListener->onBufferReleased(); +} diff --git a/media/libstagefright/xmlparser/Android.bp b/media/libstagefright/xmlparser/Android.bp index 2c5e81a8191..c1fca4f4350 100644 --- a/media/libstagefright/xmlparser/Android.bp +++ b/media/libstagefright/xmlparser/Android.bp @@ -31,8 +31,15 @@ cc_library_shared { "libexpat", "liblog", "libstagefright_omx_utils", + "libcutils" ], + target: { + vendor: { + cflags: ["-D__ANDROID_VNDK__"], + }, + }, + cflags: [ "-Werror", "-Wall", diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp index ae7147c1612..0281427b481 100644 --- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp +++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp @@ -14,7 +14,8 @@ * limitations under the License. */ -//#define LOG_NDEBUG 0 +#define LOG_NDEBUG 0 +#define PROP_VALUE_MAX 92 #define LOG_TAG "MediaCodecsXmlParser" #include @@ -42,6 +43,7 @@ #include #include #include +#include namespace android { @@ -123,6 +125,57 @@ status_t combineStatus(status_t a, status_t b) { } } +std::string getVendorXmlPath(const std::string &path) { + std::string vendorPath; + std::string result = path; + + if (!strncmp(path.c_str(), "/vendor/etc/media_codecs.xml", + strlen("/vendor/etc/media_codecs.xml"))) { + vendorPath = "/vendor/etc/media_codecs_vendor"; + } else if (!strncmp(path.c_str(), "/vendor/etc/media_codecs_performance.xml", + strlen("/vendor/etc/media_codecs_performance.xml"))) { + vendorPath = "/vendor/etc/media_codecs_performance"; + } + + if (!vendorPath.empty()) { + if (fileExists(vendorPath + std::string(".xml"))) { + char version[PROP_VALUE_MAX] = {0}; + result = vendorPath + std::string(".xml"); +#ifdef __ANDROID_VNDK__ + property_get("vendor.media.target.version", version, "0"); +#else + property_get("vendor.sys.media.target.version", version, "0"); +#endif + if (atoi(version) > 0) { + std::string versionedXml = vendorPath + std::string("_v") + + std::string(version) + std::string(".xml"); + if(fileExists(versionedXml)) { + result = versionedXml; + } + } + } + ALOGI("getVendorXmlPath (%s)", result.c_str()); + } + + // Choose different xmls based on system (if needed) + if (!android::base::GetProperty("ro.media.xml_variant.codecs", "").empty()){ + const std::vector &xmlFiles = MediaCodecsXmlParser::getDefaultXmlNames(); + for (const std::string &xmlName : xmlFiles) { + vendorPath = "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/vendor/etc/" + xmlName; + if (!strncmp(path.c_str(), vendorPath.c_str(), vendorPath.size())) { + vendorPath = vendorPath.substr(0,vendorPath.size()-4) + "_vendor.xml"; + if (fileExists(vendorPath)) { + result = vendorPath; + } + ALOGI("getVendorXmlPath %s", result.c_str()); + break; + } + } + } + + return result; +} + MediaCodecsXmlParser::StringSet parseCommaSeparatedStringSet(const char *s) { MediaCodecsXmlParser::StringSet result; for (const char *ptr = s ? : ""; *ptr; ) { @@ -448,20 +501,22 @@ status_t MediaCodecsXmlParser::Impl::parseXmlFilesInSearchDirs( status_t MediaCodecsXmlParser::Impl::parseXmlPath(const std::string &path) { std::lock_guard guard(mLock); - if (!fileExists(path)) { - ALOGV("Cannot find %s", path.c_str()); + std::string vendorPath = getVendorXmlPath(path); + + if (!fileExists(vendorPath)) { + ALOGV("Cannot find %s", vendorPath.c_str()); mParsingStatus = combineStatus(mParsingStatus, NAME_NOT_FOUND); return NAME_NOT_FOUND; } // save state (even though we should always be at toplevel here) State::RestorePoint rp = mState.createRestorePoint(); - Parser parser(&mState, path); + Parser parser(&mState, vendorPath); parser.parseXmlFile(); mState.restore(rp); if (parser.getStatus() != OK) { - ALOGD("parseXmlPath(%s) failed with %s", path.c_str(), asString(parser.getStatus())); + ALOGD("parseXmlPath(%s) failed with %s", vendorPath.c_str(), asString(parser.getStatus())); } mParsingStatus = combineStatus(mParsingStatus, parser.getStatus()); return parser.getStatus(); diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp index 8966544108a..51eb726c73e 100644 --- a/media/utils/ServiceUtilities.cpp +++ b/media/utils/ServiceUtilities.cpp @@ -169,6 +169,9 @@ static int checkRecordingInternal(const AttributionSourceState &attributionSourc return PERMISSION_HARD_DENIED; } + auto permission = source == AUDIO_SOURCE_REMOTE_SUBMIX ? + sModifyAudioRouting : sAndroidPermissionRecordAudio; + permission::PermissionChecker permissionChecker; int permitted; if (start) { @@ -182,7 +185,7 @@ static int checkRecordingInternal(const AttributionSourceState &attributionSourc // // TODO(b/294609684) To be removed when the pause state for an OP is removed. permitted = permissionChecker.checkPermissionForPreflightFromDatasource( - sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg, + permission, resolvedAttributionSource.value(), msg, attributedOpCode); if (permitted == PERMISSION_GRANTED) { permitted = permissionChecker.checkPermissionForStartDataDeliveryFromDatasource( @@ -196,7 +199,7 @@ static int checkRecordingInternal(const AttributionSourceState &attributionSourc } } else { permitted = permissionChecker.checkPermissionForPreflightFromDatasource( - sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg, + permission, resolvedAttributionSource.value(), msg, attributedOpCode); } diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 1c19c2bc23c..ff472f44bff 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -101,6 +101,7 @@ using com::android::media::permission::IPermissionProvider; using com::android::media::permission::NativePermissionController; using com::android::media::permission::PermissionEnum; using com::android::media::permission::PermissionEnum::MODIFY_AUDIO_SETTINGS; +using com::android::media::permission::PermissionEnum::MODIFY_AUDIO_ROUTING; using com::android::media::permission::ValidatedAttributionSourceState; static const AudioHalVersionInfo kMaxAAudioPropertyDeviceHalVersion = @@ -1167,6 +1168,15 @@ status_t AudioFlinger::createTrack(const media::CreateTrackRequest& _input, output.portId = portId; if (lStatus == NO_ERROR) { + // set volume + String8 trackCreatorPackage = track->getPackageName(); + if (!trackCreatorPackage.empty() && + mAppVolumeConfigs.find(trackCreatorPackage) != mAppVolumeConfigs.end()) { + media::AppVolume config = mAppVolumeConfigs[trackCreatorPackage]; + track->setAppMute(config.muted); + track->setAppVolume(config.volume); + } + // no risk of deadlock because AudioFlinger::mutex() is held audio_utils::lock_guard _dl(thread->mutex()); // Connect secondary outputs. Failure on a secondary output must not imped the primary @@ -2016,6 +2026,69 @@ uint32_t AudioFlinger::getInputFramesLost(audio_io_handle_t ioHandle) const return 0; } +status_t AudioFlinger::listAppVolumes(std::vector *vols) +{ + std::set volSet; + audio_utils::lock_guard _l(mutex()); + + for (auto& [ioHandle, thread] : mPlaybackThreads) { + if (thread != nullptr) { + thread->listAppVolumes(volSet); + } + } + + vols->insert(vols->begin(), volSet.begin(), volSet.end()); + return NO_ERROR; +} + +status_t AudioFlinger::setAppVolume(const String8& packageName, const float value) +{ + audio_utils::lock_guard _l(mutex()); + + for (auto& [ioHandle, thread] : mPlaybackThreads) { + if (thread != nullptr) { + thread->setAppVolume(packageName, value); + } + } + + auto it = mAppVolumeConfigs.find(packageName); + if (it == mAppVolumeConfigs.end()) { + media::AppVolume vol; + vol.packageName = packageName; + vol.volume = value; + vol.muted = false; + mAppVolumeConfigs[packageName] = vol; + } else { + it->second.volume = value; + } + + return NO_ERROR; +} + +status_t AudioFlinger::setAppMute(const String8& packageName, const bool value) +{ + audio_utils::lock_guard _l(mutex()); + + for (auto& [ioHandle, thread] : mPlaybackThreads) { + if (thread != nullptr) { + thread->setAppMute(packageName, value); + } + } + + auto it = mAppVolumeConfigs.find(packageName); + if (it == mAppVolumeConfigs.end()) { + media::AppVolume vol; + vol.packageName = packageName; + vol.volume = 1.0f; + vol.muted = value; + mAppVolumeConfigs[packageName] = vol; + } else { + it->second.muted = value; + } + + return NO_ERROR; +} + status_t AudioFlinger::setVoiceVolume(float value) { status_t ret = initCheck(); @@ -5103,6 +5176,24 @@ status_t AudioFlinger::onTransactWrapper(TransactionCode code, break; } + // make sure the following transactions require MODIFY_AUDIO_ROUTING permission + switch (code) { + case TransactionCode::SET_APP_VOLUME: + case TransactionCode::SET_APP_MUTE: { + const uid_t callingUid = IPCThreadState::self()->getCallingUid(); + const auto res = getPermissionProvider().checkPermission(MODIFY_AUDIO_ROUTING, callingUid); + if (!res.ok() || !res.value()) { + ALOGW("%s: transaction %d received from PID %d UID %d does not have " + "MODIFY_AUDIO_ROUTING permission", + __func__, static_cast(code), IPCThreadState::self()->getCallingPid(), + callingUid); + return INVALID_OPERATION; + } + } break; + default: + break; + } + const std::string methodName = getIAudioFlingerStatistics().getMethodForCode(code); mediautils::TimeCheck check( std::string("IAudioFlinger::").append(methodName), diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index ca9e19d87ab..35c4c8c1dbc 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -441,6 +442,15 @@ class AudioFlinger return mStartupFinishedTime.load(std::memory_order_acquire); } +public: + status_t setAppVolume(const String8& packageName, const float value); + status_t setAppMute(const String8& packageName, const bool value); + status_t listAppVolumes(std::vector *vols); + +private: + std::map mAppVolumeConfigs; + +public: status_t openMmapStreamImpl(bool isOutput, const audio_attributes_t& attr, audio_config_base_t* config, diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index 4af8f06d9c0..e7ff0a8356a 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -171,6 +171,9 @@ status_t EffectBase::setEnabled(bool enabled, bool fromHandle) getCallback()->onEffectDisable(this); } } + if (status != NO_ERROR) { + status = updatePolicyState(); + } return status; } @@ -1913,12 +1916,6 @@ Status EffectHandle::enable(int32_t* _aidl_return) mEnabled = true; - status_t status = effect->updatePolicyState(); - if (status != NO_ERROR) { - mEnabled = false; - RETURN(status); - } - effect->checkSuspendOnEffectEnabled(true, false /*threadLocked*/); // checkSuspendOnEffectEnabled() can suspend this same effect when enabled @@ -1926,7 +1923,7 @@ Status EffectHandle::enable(int32_t* _aidl_return) RETURN(NO_ERROR); } - status = effect->setEnabled(true, true /*fromHandle*/); + status_t status = effect->setEnabled(true, true /*fromHandle*/); if (status != NO_ERROR) { mEnabled = false; } @@ -1950,8 +1947,6 @@ Status EffectHandle::disable(int32_t* _aidl_return) } mEnabled = false; - effect->updatePolicyState(); - if (effect->suspended()) { RETURN(NO_ERROR); } @@ -2976,6 +2971,16 @@ static const effect_uuid_t SL_IID_DAP_ = { 0x46d279d9, 0x9be7, 0x453d, 0x9d7c, { 0xef, 0x93, 0x7f, 0x67, 0x55, 0x87 } }; const effect_uuid_t * const SL_IID_DAP = &SL_IID_DAP_; +// Dolby Atmos SW +static const effect_uuid_t SL_IID_DAP_SW_ = // 9d4921da-8225-4f29-aefa-39537a04bcaa +{ 0x9d4921da, 0x8225, 0x4f29, 0xaefa, {0x39, 0x53, 0x7a, 0x04, 0xbc, 0xaa} }; +const effect_uuid_t * const SL_IID_DAP_SW = &SL_IID_DAP_SW_; + +// ViperFx +static const effect_uuid_t SL_V4A_RE_ = // 90380da3-8536-4744-a6a3-5731970e640f +{ 0x90380da3, 0x8536, 0x4744, 0xa6a3, {0x57, 0x31, 0x97, 0x0e, 0x64, 0x0f} }; +const effect_uuid_t * const SL_V4A_RE = &SL_V4A_RE_; + /* static */ bool EffectChain::isEffectEligibleForBtNrecSuspend_l(const effect_uuid_t* type) { // Only NS and AEC are suspended when BtNRec is off @@ -2994,6 +2999,8 @@ bool EffectChain::isEffectEligibleForSuspend(const effect_descriptor_t& desc) (memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) || (memcmp(&desc.type, SL_IID_VOLUME, sizeof(effect_uuid_t)) == 0) || (memcmp(&desc.type, SL_IID_DAP, sizeof(effect_uuid_t)) == 0) || + (memcmp(&desc.type, SL_IID_DAP_SW, sizeof(effect_uuid_t)) == 0) || + (memcmp(&desc.type, SL_V4A_RE, sizeof(effect_uuid_t)) == 0) || (memcmp(&desc.type, SL_IID_DYNAMICSPROCESSING, sizeof(effect_uuid_t)) == 0))) { return false; } diff --git a/services/audioflinger/IAfThread.h b/services/audioflinger/IAfThread.h index 893d7416b4d..0fb97ef149a 100644 --- a/services/audioflinger/IAfThread.h +++ b/services/audioflinger/IAfThread.h @@ -544,6 +544,10 @@ class IAfPlaybackThread : public virtual IAfThreadBase { // Return the asynchronous signal wait time. virtual int64_t computeWaitTimeNs_l() const REQUIRES(mutex()) = 0; + virtual status_t setAppVolume(const String8& packageName, const float value) = 0; + virtual status_t setAppMute(const String8& packageName, const bool muted) = 0; + virtual void listAppVolumes(std::set &container) = 0; + // returns true if the track is allowed to be added to the thread. virtual bool isTrackAllowed_l( audio_channel_mask_t channelMask, audio_format_t format, audio_session_t sessionId, diff --git a/services/audioflinger/IAfTrack.h b/services/audioflinger/IAfTrack.h index f52fc52ef7c..6c5c3ee993e 100644 --- a/services/audioflinger/IAfTrack.h +++ b/services/audioflinger/IAfTrack.h @@ -207,6 +207,12 @@ class IAfTrackBase : public VolumePortInterface { virtual bool isPatchTrack() const = 0; virtual bool isExternalTrack() const = 0; + virtual void setAppVolume(float volume) { (void)volume; } + virtual void setAppMute(bool val) { (void)val; } + virtual float getAppVolume() const { return 1.0f; } + virtual bool isAppMuted() const { return false; } + virtual String8 getPackageName() const { return String8(); } + virtual void invalidate() = 0; virtual bool isInvalid() const = 0; @@ -520,11 +526,17 @@ class IAfTrack : public virtual IAfTrackBase, public virtual AfPlaybackCommon { virtual sp getVolumeShaperState(int id) const = 0; virtual sp getVolumeHandler() const = 0; /** Set the computed normalized final volume of the track. - * !masterMute * masterVolume * portVolume * averageLRVolume */ + * !masterMute * !appMuted * masterVolume * streamVolume * averageLRVolume * appVolume */ virtual void setFinalVolume(float volumeLeft, float volumeRight) = 0; virtual float getFinalVolume() const = 0; virtual void getFinalVolume(float* left, float* right) const = 0; + void setAppVolume(float volume) override { IAfTrackBase::setAppVolume(volume); } + float getAppVolume() const override { return IAfTrackBase::getAppVolume(); } + void setAppMute(bool val) override { IAfTrackBase::setAppMute(val); } + bool isAppMuted() const override { return IAfTrackBase::isAppMuted(); } + String8 getPackageName() const override { return IAfTrackBase::getPackageName(); } + using SourceMetadatas = std::vector; using MetadataInserter = std::back_insert_iterator; /** Copy the track metadata in the provided iterator. Thread safe. */ diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h index 8451417ebc6..661586662e8 100644 --- a/services/audioflinger/PlaybackTracks.h +++ b/services/audioflinger/PlaybackTracks.h @@ -154,7 +154,7 @@ class Track : public TrackBase, public virtual IAfTrack, public VolumeProvider { sp getVolumeShaperState(int id) const final; sp getVolumeHandler() const final{ return mVolumeHandler; } /** Set the computed normalized final volume of the track. - * !masterMute * masterVolume * streamVolume * averageLRVolume */ + * !masterMute * !appMuted * masterVolume * streamVolume * averageLRVolume * appVolume */ void setFinalVolume(float volumeLeft, float volumeRight) final; float getFinalVolume() const final { return mFinalVolume; } void getFinalVolume(float* left, float* right) const final { @@ -162,6 +162,12 @@ class Track : public TrackBase, public virtual IAfTrack, public VolumeProvider { *right = mFinalVolumeRight; } + void setAppVolume(float volume) override { mAppVolume = volume; } + float getAppVolume() const override { return mAppVolume; } + void setAppMute(bool val) override { mAppMuted = val; } + bool isAppMuted() const override { return mAppMuted; } + String8 getPackageName() const override { return mPackageName; } + using SourceMetadatas = std::vector; using MetadataInserter = std::back_insert_iterator; /** Copy the track metadata in the provided iterator. Thread safe. */ @@ -383,6 +389,8 @@ class Track : public TrackBase, public virtual IAfTrack, public VolumeProvider { void populateUsageAndContentTypeFromStreamType(); + String8 mPackageName; + size_t mPresentationCompleteFrames = 0; // (Used for Mixed tracks) // The number of frames written to the // audio HAL when this track is considered fully rendered. @@ -408,6 +416,8 @@ class Track : public TrackBase, public virtual IAfTrack, public VolumeProvider { // volume float mFinalVolumeRight; // combine master volume, stream type volume and track // volume + float mAppVolume = 1.0f; // volume control for separate processes + bool mAppMuted = false; sp mAudioTrackServerProxy; bool mResumeToStopping; // track was paused in stopping state. bool mFlushHwPending; // track requests for thread flush diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 2cd715ccda0..7b54613e847 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -2252,6 +2252,49 @@ void ThreadBase::checkUpdateTrackMetadataForUid(uid_t uid) { } } +void PlaybackThread::listAppVolumes(std::set &container) +{ + audio_utils::lock_guard _l(mutex()); + + for (const sp& track : mTracks) { + if (!track->getPackageName().empty()) { + media::AppVolume av; + av.packageName = track->getPackageName(); + av.muted = track->isAppMuted(); + av.volume = track->getAppVolume(); + av.active = mActiveTracks.count(track) > 0; + + container.insert(av); + } + } +} + +status_t PlaybackThread::setAppVolume(const String8& packageName, const float value) +{ + audio_utils::lock_guard _l(mutex()); + + for (const sp& track : mTracks) { + if (packageName == track->getPackageName()) { + track->setAppVolume(value); + } + } + + return NO_ERROR; +} + +status_t PlaybackThread::setAppMute(const String8& packageName, const bool value) +{ + audio_utils::lock_guard _l(mutex()); + + for (const sp& track : mTracks) { + if (packageName == track->getPackageName()) { + track->setAppMute(value); + } + } + + return NO_ERROR; +} + // ---------------------------------------------------------------------------- // Playback // ---------------------------------------------------------------------------- @@ -5760,16 +5803,16 @@ PlaybackThread::mixer_state MixerThread::prepareTracks_l( if (com_android_media_audio_ring_my_car()) { if (!track->canBypassMute() - && (track->isPlaybackRestricted() || track->getPortMute())) { + && (track->isPlaybackRestricted() || track->getPortMute() || track->isAppMuted())) { volume = 0.f; } else { - volume = masterVolume * track->getPortVolume(); + volume = masterVolume * track->getPortVolume() * track->getAppVolume(); } } else { - if (track->isPlaybackRestricted() || track->getPortMute()) { + if (track->isPlaybackRestricted() || track->getPortMute() || track->isAppMuted()) { volume = 0.f; } else { - volume = masterVolume * track->getPortVolume(); + volume = masterVolume * track->getPortVolume() * track->getAppVolume(); } } @@ -5969,16 +6012,16 @@ PlaybackThread::mixer_state MixerThread::prepareTracks_l( if (com_android_media_audio_ring_my_car()) { if (!track->canBypassMute() - && (track->isPlaybackRestricted() || track->getPortMute())) { + && (track->isPlaybackRestricted() || track->getPortMute() || track->isAppMuted())) { v = 0; } else { - v = masterVolume * track->getPortVolume(); + v = masterVolume * track->getPortVolume() * track->getAppVolume(); } } else { - if (track->isPlaybackRestricted() || track->getPortMute()) { + if (track->isPlaybackRestricted() || track->getPortMute() || track->isAppMuted()) { v = 0; } else { - v = masterVolume * track->getPortVolume(); + v = masterVolume * track->getPortVolume() * track->getAppVolume(); } } @@ -6758,11 +6801,12 @@ void DirectOutputThread::processVolume_l(const sp& track, bool lastTra const auto amn = mAfThreadCallback->getAudioManagerNative(); - if (mMasterMute || track->isPlaybackRestricted()) { + if (mMasterMute || track->isPlaybackRestricted() || track->isAppMuted()) { left = right = 0; } else { float typeVolume = track->getPortVolume(); - const float v = mMasterVolume * typeVolume * shaperVolume; + float appVolume = track->getAppVolume(); + const float v = mMasterVolume * typeVolume * shaperVolume * appVolume; if (left > GAIN_FLOAT_UNITY) { left = GAIN_FLOAT_UNITY; @@ -7593,7 +7637,11 @@ PlaybackThread::mixer_state OffloadThread::prepareTracks_l( if ((mDrainSequence & 1) == 0) { mSleepTimeUs = 0; mStandbyTimeNs = systemTime() + mStandbyDelayNs; - mixerStatus = MIXER_DRAIN_TRACK; + if (!mUseAsyncWrite) { + mixerStatus = MIXER_DRAIN_ALL; + } else { + mixerStatus = MIXER_DRAIN_TRACK; + } mDrainSequence += 2; } if (mHwPaused) { diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 203672508da..cfba6fbde4e 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -1173,6 +1173,10 @@ class PlaybackThread : public ThreadBase, public virtual IAfPlaybackThread, void setVolumeForOutput_l(float left, float right) const final; + status_t setAppVolume(const String8& packageName, const float value) final; + status_t setAppMute(const String8& packageName, const bool muted) final; + void listAppVolumes(std::set &container) final; + sp createTrack_l( const sp& client, audio_stream_type_t streamType, diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 3e395b11ad3..fef8a7d9ee2 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -951,6 +951,19 @@ Track::Track( ALOGV_IF(sharedBuffer != 0, "%s(%d): sharedBuffer: %p, size: %zu", __func__, mId, sharedBuffer->unsecurePointer(), sharedBuffer->size()); + /* get package name */ + if (attributionSource.packageName.has_value() && !attributionSource.packageName.value().empty()) { + mPackageName = String8(String16(attributionSource.packageName.value().c_str())); + } else { + const auto& provider = thread->afThreadCallback()->getPermissionProvider(); + const auto res = provider.getPackagesForUid(attributionSource.uid); + if (res.ok() && !res->empty()) { + mPackageName = String8(String16(res->at(0).c_str())); + } else { + mPackageName = ""; + } + } + if (mCblk == NULL) { return; } diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp index 3e9ef25e91f..5cf20baafb5 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp @@ -416,30 +416,6 @@ bool AudioPolicyMixCollection::mixMatch(const AudioMix* mix, size_t mixIndex, const audio_config_base_t& config, uid_t uid, audio_session_t session) { if (mix->mMixType == MIX_TYPE_PLAYERS) { - // Loopback render mixes are created from a public API and thus restricted - // to non sensible audio that have not opted out. - if (is_mix_loopback_render(mix->mRouteFlags)) { - if (!(attributes.usage == AUDIO_USAGE_UNKNOWN || - attributes.usage == AUDIO_USAGE_MEDIA || - attributes.usage == AUDIO_USAGE_GAME || - attributes.usage == AUDIO_USAGE_VOICE_COMMUNICATION)) { - return false; - } - auto hasFlag = [](auto flags, auto flag) { return (flags & flag) == flag; }; - if (hasFlag(attributes.flags, AUDIO_FLAG_NO_SYSTEM_CAPTURE)) { - return false; - } - - if (attributes.usage == AUDIO_USAGE_VOICE_COMMUNICATION) { - if (!mix->mVoiceCommunicationCaptureAllowed) { - return false; - } - } else if (!mix->mAllowPrivilegedMediaPlaybackCapture && - hasFlag(attributes.flags, AUDIO_FLAG_NO_MEDIA_PROJECTION)) { - return false; - } - } - // Permit match only if requested format and mix format are PCM and can be format // adapted by the mixer, or are the same format on direct output. if (!is_mix_loopback(mix->mRouteFlags) && diff --git a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp index a49d588b04b..c81cf11a9ca 100644 --- a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp @@ -22,6 +22,7 @@ #include "AudioInputDescriptor.h" #include "EffectDescriptor.h" #include +#include #include #include @@ -175,6 +176,14 @@ bool EffectDescriptorCollection::isNonOffloadableEffectEnabled( effectDesc->mSession); return true; } + // Also check for Visualizer effects on global session (AUDIO_SESSION_OUTPUT_MIX = 0) + // Visualizer needs audio to go through the mixer to capture it, so block offload + if (effectDesc->mEnabled && + effectDesc->mSession == AUDIO_SESSION_OUTPUT_MIX && + memcmp(&effectDesc->mDesc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) { + ALOGV("%s: visualizer effect enabled on global session, blocking offload", __func__); + return true; + } } return false; } diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index abf76554703..8d91d994de3 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -301,12 +301,6 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(const spsetEncodedFormat(AUDIO_FORMAT_DEFAULT); - - // remove device from mReportedFormatsMap cache - mReportedFormatsMap.erase(device); - // remove preferred mixer configurations mPreferredMixerAttrInfos.erase(device->getId()); @@ -415,6 +409,9 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(const spsetEncodedFormat(AUDIO_FORMAT_DEFAULT); + mReportedFormatsMap.erase(device); + cleanUpForDevice(device); } diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp index f9cbc0e6d8b..4175e8ad7a0 100644 --- a/services/camera/libcameraservice/Android.bp +++ b/services/camera/libcameraservice/Android.bp @@ -141,6 +141,7 @@ cc_library { "common/Camera2ClientBase.cpp", "common/CameraDeviceBase.cpp", "common/CameraOfflineSessionBase.cpp", + "common/CameraProviderExtension.cpp", "common/CameraProviderManager.cpp", "common/FrameProcessorBase.cpp", "common/hidl/HidlProviderInfo.cpp", @@ -210,6 +211,8 @@ cc_library { "utils/LatencyHistogram.cpp", "utils/Utils.cpp", "utils/VirtualDeviceCameraIdMapper.cpp", + "ext/ICameraServiceExt.cpp", + "ext/CameraServiceExtFactory.cpp", ], header_libs: [ @@ -219,6 +222,17 @@ cc_library { "libmediametrics_headers", ], + shared_libs: [ + ] + select(soong_config_variable("camera", "needs_client_info_lib"), { + true: ["//hardware/oneplus:vendor.oneplus.hardware.camera@1.0"], + false: [], + default: [], + }) + select(soong_config_variable("camera", "needs_client_info_lib_oplus"), { + true: ["vendor.oplus.hardware.cameraMDM@2.0"], + false: [], + default: [], + }), + export_shared_lib_headers: [ "libbinder", "libactivitymanager_aidl", @@ -232,6 +246,7 @@ cc_library { include_dirs: [ "system/media/private/camera/include", "frameworks/native/include/media/openmax", + "frameworks/av/services/camera/libcameraservice/ext/include", ], export_include_dirs: ["."], @@ -241,7 +256,30 @@ cc_library { "-Wextra", "-Werror", "-Wno-ignored-qualifiers", - ], + ] + select(soong_config_variable("camera", "package_name"), { + any @ flag_val: ["-DCAMERA_PACKAGE_NAME=\"" + flag_val + "\""], + default: [], + }) + select(soong_config_variable("camera", "needs_client_info_lib"), { + true: ["-DCAMERA_NEEDS_CLIENT_INFO_LIB"], + false: [], + default: [], + }) + select(soong_config_variable("camera", "needs_client_info_lib_oplus"), { + true: ["-DCAMERA_NEEDS_CLIENT_INFO_LIB_OPLUS"], + false: [], + default: [], + }) + select(soong_config_variable("camera", "disable_torch_control"), { + true: ["-DDISABLE_TORCH_CONTROL"], + false: [], + default: [], + }) + select(soong_config_variable("camera", "ext_lib"), { + any @ flag_val: ["-DTARGET_PROVIDES_CAMERA_PROVIDER_EXT_LIB"], + default: [], + }), + + whole_static_libs: select(soong_config_variable("libcameraservice", "ext_lib"), { + any @ flag_val: [flag_val], + default: ["libcameraservice_ext_lib"], + }), } cc_library_static { @@ -305,3 +343,11 @@ cc_library_static { "-Wno-ignored-qualifiers", ], } + +cc_library_static { + name: "libcameraservice_ext_lib", + srcs: [ + "common/CameraProviderExtension.cpp", + ], + export_include_dirs: ["."], +} diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 988803b6ea2..562081cded8 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -90,6 +91,16 @@ #include "utils/TagMonitor.h" #include "utils/Utils.h" +#include "ext/include/CameraServiceExtFactory.h" + +#ifdef CAMERA_NEEDS_CLIENT_INFO_LIB +#include +#endif + +#ifdef CAMERA_NEEDS_CLIENT_INFO_LIB_OPLUS +#include +#endif + namespace { const char* kActivityServiceName = "activity"; const char* kSensorPrivacyServiceName = "sensor_privacy"; @@ -138,6 +149,12 @@ using hardware::camera2::ICameraInjectionCallback; using hardware::camera2::ICameraInjectionSession; using hardware::camera2::utils::CameraIdAndSessionConfiguration; using hardware::camera2::utils::ConcurrentCameraIdCombination; +#ifdef CAMERA_NEEDS_CLIENT_INFO_LIB +using ::vendor::oneplus::hardware::camera::V1_0::IOnePlusCameraProvider; +#endif +#ifdef CAMERA_NEEDS_CLIENT_INFO_LIB_OPLUS +using ::vendor::oplus::hardware::cameraMDM::V2_0::IOPlusCameraMDM; +#endif namespace flags = com::android::internal::camera::flags; namespace vd_flags = android::companion::virtualdevice::flags; @@ -173,6 +190,12 @@ static const std::string &sCameraInjectExternalCameraPermission = // Constant integer for FGS Logging, used to denote the API type for logger static const int LOG_FGS_CAMERA_API = 1; const char *sFileName = "lastOpenSessionDumpFile"; +#ifdef CAMERA_NEEDS_CLIENT_INFO_LIB +static const sp gVendorCameraProviderService = IOnePlusCameraProvider::getService(); +#endif +#ifdef CAMERA_NEEDS_CLIENT_INFO_LIB_OPLUS +static const sp gVendorCameraProviderService = IOPlusCameraMDM::getService(); +#endif static constexpr int32_t kSystemNativeClientScore = resource_policy::PERCEPTIBLE_APP_ADJ; static constexpr int32_t kSystemNativeClientState = ActivityManager::PROCESS_STATE_PERSISTENT_UI; @@ -186,6 +209,9 @@ constexpr int32_t kInvalidDeviceId = -1; // Set to keep track of logged service error events. static std::set sServiceErrorEventSet; +// Current camera package name +static std::string sCurrPackageName; + CameraService::CameraService( std::shared_ptr cameraServiceProxyWrapper, std::shared_ptr attributionAndPermissionUtils) : @@ -1520,6 +1546,10 @@ Status CameraService::filterGetInfoErrorCode(status_t err) { } } +std::string CameraService::getCurrPackageName() { + return sCurrPackageName; +} + Status CameraService::makeClient( const sp& cameraService, const sp& cameraCb, const AttributionSourceState& clientAttribution, int callingPid, bool systemNativeClient, @@ -1930,6 +1960,14 @@ status_t CameraService::checkIfDeviceIsUsable(const std::string& cameraId) const return NO_ERROR; } +bool isPrivilegedClient(const std::string &packageName) { + std::vector privilegedClientList = android::base::Split( + android::base::GetProperty("persist.vendor.camera.privapp.list", ""), ","); + auto it = std::find(privilegedClientList.begin(), privilegedClientList.end(), + packageName); + return it != privilegedClientList.end(); +} + void CameraService::finishConnectLocked(const sp& client, const CameraService::DescriptorPtr& desc, int oomScoreOffset, bool systemNativeClient) { @@ -1939,6 +1977,10 @@ void CameraService::finishConnectLocked(const sp& client, oomScoreOffset, systemNativeClient); auto evicted = mActiveClientManager.addAndEvict(clientDescriptor); + if (isPrivilegedClient(client->getPackageName())) { + evicted.clear(); + } + logConnected(desc->getKey(), static_cast(desc->getOwnerId()), client->getPackageName()); @@ -2086,6 +2128,10 @@ status_t CameraService::handleEvictionsLocked(const std::string& cameraId, int c // Find clients that would be evicted auto evicted = mActiveClientManager.wouldEvict(clientDescriptor); + if (isPrivilegedClient(packageName)) { + evicted.clear(); + } + // If the incoming client was 'evicted,' higher priority clients have the camera in the // background, so we cannot do evictions if (std::find(evicted.begin(), evicted.end(), clientDescriptor) != evicted.end()) { @@ -2542,6 +2588,8 @@ Status CameraService::connectHelper(const sp& cameraCb, const std::str const std::string clientPackageName = clientAttribution.packageName.value_or(kUnknownPackageName); + sCurrPackageName = clientPackageName; + { // Acquire mServiceLock and prevent other clients from connecting std::unique_ptr lock = @@ -3011,11 +3059,15 @@ Status CameraService::turnOnTorchWithStrengthLevel(const std::string& unresolved Mutex::Autolock al(mTorchUidMapMutex); updateTorchUidMapLocked(cameraId, uid); } +#ifdef DISABLE_TORCH_CONTROL + bool shouldSkipTorchStrengthUpdates = false; + status_t err = mFlashlight->setTorchMode(cameraId, (torchStrength > 0) ? 1 : 0); +#else // Check if the current torch strength level is same as the new one. bool shouldSkipTorchStrengthUpdates = mCameraProviderManager->shouldSkipTorchStrengthUpdate( cameraId, torchStrength); - status_t err = mFlashlight->turnOnTorchWithStrengthLevel(cameraId, torchStrength); +#endif if (err != OK) { int32_t errorCode; @@ -3870,7 +3922,8 @@ bool CameraService::evictClientIdByRemote(const wp& remote) { ret = true; } } - + //clear the evicted client list before acquring service lock again. + evicted.clear(); // Reacquire mServiceLock mServiceLock.lock(); @@ -4092,6 +4145,7 @@ void CameraService::logServiceError(const std::string &msg, int errorCode) { status_t CameraService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { + ALOGI("CameraService::onTransact: code=0x%x (%d)", code, code); // Permission checks switch (code) { case SHELL_COMMAND_TRANSACTION: { @@ -4120,6 +4174,11 @@ status_t CameraService::onTransact(uint32_t code, const Parcel& data, Parcel* re } } + // Let the extension handle it first + if (CameraServiceExtFactory::onTransact(code, data, reply, flags) == 0) { + return NO_ERROR; + } + return BnCameraService::onTransact(code, data, reply, flags); } @@ -4470,6 +4529,10 @@ status_t CameraService::BasicClient::notifyCameraOpening() { sCameraService->updateOpenCloseStatus(mCameraIdStr, true /*open*/, getPackageName(), mSharedMode); +#if defined (CAMERA_NEEDS_CLIENT_INFO_LIB) || defined (CAMERA_NEEDS_CLIENT_INFO_LIB_OPLUS) + gVendorCameraProviderService->setPackageName(getPackageName().c_str()); +#endif + return OK; } diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index e2d2e5437d5..fe64b7ce65c 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -345,6 +345,8 @@ class CameraService : */ bool isAutomotiveExteriorSystemCamera(const std::string& cameraId) const; + static std::string getCurrPackageName(); + ///////////////////////////////////////////////////////////////////// // CameraClient functionality diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp index 5766b5584aa..3c75d45c76d 100644 --- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp +++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp @@ -290,14 +290,6 @@ binder::Status Camera2ClientBase::disconnectImpl() { ALOGD("Camera %s: Shutting down", TClientBase::mCameraIdStr.c_str()); - // Before detaching the device, cache the info from current open session. - // The disconnected check avoids duplication of info and also prevents - // deadlock while acquiring service lock in cacheDump. - if (!TClientBase::mDisconnected) { - ALOGV("Camera %s: start to cacheDump", TClientBase::mCameraIdStr.c_str()); - Camera2ClientBase::getCameraService()->cacheDump(TClientBase::mCameraIdStr); - } - detachDevice(); CameraService::BasicClient::disconnect(); diff --git a/services/camera/libcameraservice/common/CameraProviderExtension.cpp b/services/camera/libcameraservice/common/CameraProviderExtension.cpp new file mode 100644 index 00000000000..65435a4d23f --- /dev/null +++ b/services/camera/libcameraservice/common/CameraProviderExtension.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 2024 The LibreMobileOS Foundation + * + * 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 "common/CameraProviderExtension.h" + +__attribute__((weak)) bool supportsTorchStrengthControlExt() { + return false; +} + +__attribute__((weak)) int32_t getTorchDefaultStrengthLevelExt() { + // Without extension, assume only one level of torch strength + return 1; +} + +__attribute__((weak)) int32_t getTorchMaxStrengthLevelExt() { + // Without extension, assume only one level of torch strength + return 1; +} + +__attribute__((weak)) int32_t getTorchStrengthLevelExt() { + return 0; +} + +__attribute__((weak)) void setTorchStrengthLevelExt(__unused int32_t torchStrength, __unused bool enabled) { + // Nothing +} diff --git a/services/camera/libcameraservice/common/CameraProviderExtension.h b/services/camera/libcameraservice/common/CameraProviderExtension.h new file mode 100644 index 00000000000..693400b7592 --- /dev/null +++ b/services/camera/libcameraservice/common/CameraProviderExtension.h @@ -0,0 +1,23 @@ +/* + * Copyright 2024 The LibreMobileOS Foundation + * + * 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 + +extern bool supportsTorchStrengthControlExt(); +extern int32_t getTorchDefaultStrengthLevelExt(); +extern int32_t getTorchMaxStrengthLevelExt(); +extern int32_t getTorchStrengthLevelExt(); +extern void setTorchStrengthLevelExt(int32_t torchStrength, bool enabled); diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp index 7032db04aa7..fa468f87e45 100644 --- a/services/camera/libcameraservice/common/CameraProviderManager.cpp +++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp @@ -57,6 +57,11 @@ #include "device3/ZoomRatioMapper.h" #include "utils/Utils.h" +#include "common/CameraProviderExtension.h" + +#include "CameraServiceExtFactory.h" +#include "ICameraServiceExt.h" + namespace android { using namespace ::android::hardware::camera; @@ -544,7 +549,11 @@ status_t CameraProviderManager::getCameraCharacteristics(const std::string &id, std::lock_guard lock(mInterfaceMutex); return getCameraCharacteristicsLocked(id, overrideForPerfClass, characteristics, compatInfo); } - +status_t CameraProviderManager::getCameraCharacteristics( const std::string &id, bool overrideForPerfClass, + CameraMetadata* characteristics, int /*unused*/) const { + return getCameraCharacteristics(id, overrideForPerfClass, characteristics, + CameraCompatibilityInfo()); +} status_t CameraProviderManager::getHighestSupportedVersion(const std::string &id, hardware::hidl_version *v, IPCTransport *transport) { if (v == nullptr || transport == nullptr) { @@ -581,7 +590,15 @@ status_t CameraProviderManager::getTorchStrengthLevel(const std::string &id, auto deviceInfo = findDeviceInfoLocked(id); if (deviceInfo == nullptr) return NAME_NOT_FOUND; - return deviceInfo->getTorchStrengthLevel(torchStrength); + // Use the extension only for the camera that has flash unit + // Otherwise fallback to the default impl. + if (deviceInfo->hasFlashUnit() && supportsTorchStrengthControlExt()) { + int32_t strength = getTorchStrengthLevelExt(); + *torchStrength = strength; + return OK; + } else { + return deviceInfo->getTorchStrengthLevel(torchStrength); + } } status_t CameraProviderManager::turnOnTorchWithStrengthLevel(const std::string &id, @@ -591,7 +608,23 @@ status_t CameraProviderManager::turnOnTorchWithStrengthLevel(const std::string & auto deviceInfo = findDeviceInfoLocked(id); if (deviceInfo == nullptr) return NAME_NOT_FOUND; - return deviceInfo->turnOnTorchWithStrengthLevel(torchStrength); + // Use the extension only for the camera that has flash unit + // Otherwise fallback to the default impl. + if (deviceInfo->hasFlashUnit() && supportsTorchStrengthControlExt()) { + // Return BAD_VALUE if the strength is not in the supported + // range. + if (torchStrength <= 0 || torchStrength > getTorchMaxStrengthLevelExt()) { + ALOGE("%s: Invalid torch strength level %d", __FUNCTION__, torchStrength); + return BAD_VALUE; + } + + deviceInfo->setTorchMode(torchStrength > 0); + setTorchStrengthLevelExt(torchStrength, true); + deviceInfo->mTorchStrengthLevel = torchStrength; + return OK; + } else { + return deviceInfo->turnOnTorchWithStrengthLevel(torchStrength); + } } bool CameraProviderManager::shouldSkipTorchStrengthUpdate(const std::string &id, @@ -615,7 +648,13 @@ int32_t CameraProviderManager::getTorchDefaultStrengthLevel(const std::string &i auto deviceInfo = findDeviceInfoLocked(id); if (deviceInfo == nullptr) return NAME_NOT_FOUND; - return deviceInfo->mTorchDefaultStrengthLevel; + // Use the extension only for the camera that has flash unit + // Otherwise fallback to the default impl. + if (deviceInfo->hasFlashUnit() && supportsTorchStrengthControlExt()) { + return getTorchDefaultStrengthLevelExt(); + } else { + return deviceInfo->mTorchDefaultStrengthLevel; + } } bool CameraProviderManager::supportSetTorchMode(const std::string &id) const { @@ -679,7 +718,14 @@ status_t CameraProviderManager::setTorchMode(const std::string &id, bool enabled } saveRef(DeviceMode::TORCH, deviceInfo->mId, halCameraProvider); - return deviceInfo->setTorchMode(enabled); + res = deviceInfo->setTorchMode(enabled); + if (deviceInfo->hasFlashUnit() && supportsTorchStrengthControlExt()) { + // Need to reset torch strength back to default when torch is turned off + int32_t defaultLevel = getTorchDefaultStrengthLevelExt(); + setTorchStrengthLevelExt(defaultLevel, enabled); + deviceInfo->mTorchStrengthLevel = defaultLevel; + } + return res; } status_t CameraProviderManager::setUpVendorTags() { @@ -727,7 +773,11 @@ status_t CameraProviderManager::notifyUsbDeviceEvent(int32_t eventId, } } else if (eventId == android::hardware::ICameraService::EVENT_USB_DEVICE_DETACHED) { + size_t usbNum = mExternalUsbDevicesForProvider.first.size(); usbDeviceDetached(usbDeviceId); + if (usbNum > 1) { + startExternalLazyProvider(); + } } return OK; @@ -1732,8 +1782,8 @@ status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fixupTorchStrengthTag status_t res = OK; auto& c = mCameraCharacteristics; auto flashInfoStrengthDefaultLevelEntry = c.find(ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL); - if (flashInfoStrengthDefaultLevelEntry.count == 0) { - int32_t flashInfoStrengthDefaultLevel = 1; + if (flashInfoStrengthDefaultLevelEntry.count == 0 || supportsTorchStrengthControlExt()) { + int32_t flashInfoStrengthDefaultLevel = getTorchDefaultStrengthLevelExt(); res = c.update(ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL, &flashInfoStrengthDefaultLevel, 1); if (res != OK) { @@ -1743,8 +1793,8 @@ status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fixupTorchStrengthTag } } auto flashInfoStrengthMaximumLevelEntry = c.find(ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL); - if (flashInfoStrengthMaximumLevelEntry.count == 0) { - int32_t flashInfoStrengthMaximumLevel = 1; + if (flashInfoStrengthMaximumLevelEntry.count == 0 || supportsTorchStrengthControlExt()) { + int32_t flashInfoStrengthMaximumLevel = getTorchMaxStrengthLevelExt(); res = c.update(ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL, &flashInfoStrengthMaximumLevel, 1); if (res != OK) { diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h index 40a4254725d..a2231d6f263 100644 --- a/services/camera/libcameraservice/common/CameraProviderManager.h +++ b/services/camera/libcameraservice/common/CameraProviderManager.h @@ -315,6 +315,8 @@ class CameraProviderManager : virtual public hidl::manager::V1_0::IServiceNotifi status_t getCameraCharacteristics(const std::string &id, bool overrideForPerfClass, CameraMetadata* characteristics, const CameraCompatibilityInfo& compatInfo) const; + status_t getCameraCharacteristics(const std::string &id, bool overrideForPerfClass, + CameraMetadata* characteristics, int) const; status_t isConcurrentSessionConfigurationSupported( const std::vector diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 86efe37f9ad..91dae4a38b3 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -1746,14 +1746,23 @@ status_t Camera3Device::waitUntilStateThenRelock(bool active, nsecs_t timeout, status_t Camera3Device::setNotifyCallback(wp listener) { ATRACE_CALL(); - std::lock_guard l(mOutputLock); + { + std::lock_guard l(mOutputLock); - if (listener != NULL && mListener != NULL) { - ALOGW("%s: Replacing old callback listener", __FUNCTION__); + if (listener != NULL && mListener != NULL) { + ALOGW("%s: Replacing old callback listener", __FUNCTION__); + } + mListener = listener; + } + { + Mutex::Autolock l(mLock); + if (mRequestThread) { + mRequestThread->setNotificationListener(listener); + } + if (mPreparerThread) { + mPreparerThread->setNotificationListener(listener); + } } - mListener = listener; - mRequestThread->setNotificationListener(listener); - mPreparerThread->setNotificationListener(listener); return OK; } @@ -2492,6 +2501,27 @@ status_t Camera3Device::configureStreamsLocked(int operatingMode, return BAD_VALUE; } +#ifdef CAMERA_PACKAGE_NAME + sp vTags; + sp vCache = VendorTagDescriptorCache::getGlobalVendorTagCache(); + if (vCache.get()) { + const camera_metadata_t *metaBuffer = sessionParams.getAndLock(); + metadata_vendor_id_t vendorId = get_camera_metadata_vendor_id(metaBuffer); + sessionParams.unlock(metaBuffer); + vCache->getVendorTagDescriptor(vendorId, &vTags); + uint32_t tag; + if (CameraMetadata::getTagFromName(CAMERA_PACKAGE_NAME, vTags.get(), &tag)) { + ALOGE("%s: Unable to get %s tag", __FUNCTION__, CAMERA_PACKAGE_NAME); + } else { + std::string pkgName = CameraService::getCurrPackageName(); + status_t res = const_cast(sessionParams).update(tag, String8(pkgName.c_str())); + if (res) { + ALOGE("%s: metadata update failed, res = %d", __FUNCTION__, res); + } + } + } +#endif + bool isConstrainedHighSpeed = CAMERA_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED_MODE == operatingMode; @@ -3424,9 +3454,15 @@ status_t Camera3Device::RequestThread::clear( status_t Camera3Device::RequestThread::flush() { ATRACE_CALL(); + status_t flush_status; Mutex::Autolock l(mFlushLock); - return mInterface->flush(); + flush_status = mInterface->flush(); + // We have completed flush, signal RequestThread::waitForNextRequestLocked() to no longer wait for + // new requests + mRequestSignal.signal(); + + return flush_status; } void Camera3Device::RequestThread::setPaused(bool paused) { diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp index cd965e37f48..094395c797e 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp +++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp @@ -1057,6 +1057,38 @@ void collectAndRemovePendingOutputBuffers(bool useHalBufManager, } } +void collectReturnableOutputBuffers( + bool useHalBufManager, + const std::set& halBufferManagedStreams, + sp listener, + const camera_stream_buffer_t* outputBuffers, + size_t numBuffers, + int64_t timestamp, + int64_t readoutTimestamp, + bool requested, + int64_t requestTimeNs, + SessionStatsBuilder& sessionStatsBuilder, + std::vector* returnableBuffers, + bool timestampIncreasing, + const std::unordered_map>& outputSurfaces, + const CaptureResultExtras& resultExtras, + ERROR_BUF_STRATEGY errorBufStrategy, + int /*extraParam*/) { + + // Convert the OxygenOS map (uint64_t) to AOSP map (size_t) + std::unordered_map> surfacesSizeT; + for (const auto& pair : outputSurfaces) { + surfacesSizeT[pair.first].assign(pair.second.begin(), pair.second.end()); + } + + // Call the AOSP overload (which takes sp by value) + collectReturnableOutputBuffers(useHalBufManager, halBufferManagedStreams, listener, + outputBuffers, numBuffers, timestamp, readoutTimestamp, requested, requestTimeNs, + sessionStatsBuilder, returnableBuffers, timestampIncreasing, surfacesSizeT, + resultExtras, errorBufStrategy, TransformationMap{}); +} + + void notifyShutter(CaptureOutputStates& states, const camera_shutter_msg_t &msg) { ATRACE_CALL(); ssize_t idx; diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.h b/services/camera/libcameraservice/device3/Camera3OutputUtils.h index 82ca6c80c3e..986a9766a58 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputUtils.h +++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.h @@ -96,6 +96,25 @@ namespace camera3 { ERROR_BUF_STRATEGY errorBufStrategy = ERROR_BUF_RETURN, const TransformationMap &transform = TransformationMap{}); + // OxygenOS-compatible overload for libcsextimpl.so + void collectReturnableOutputBuffers( + bool useHalBufManager, + const std::set &halBufferManagedStreams, + sp listener, + const camera_stream_buffer_t *outputBuffers, + size_t numBuffers, + nsecs_t timestamp, + nsecs_t readoutTimestamp, + bool requested, + nsecs_t requestTimeNs, + SessionStatsBuilder& sessionStatsBuilder, + std::vector *returnableBuffers, + bool timestampIncreasing, + const std::unordered_map> &outputSurfaces, + const CaptureResultExtras &resultExtras, + ERROR_BUF_STRATEGY errorBufStrategy, + int extraParam); + // helper function to collect the output buffers ready to be // returned to output streams, and to remove these buffers from // the inflight request's pending buffers vector. Does not make diff --git a/services/camera/libcameraservice/ext/CameraServiceExtFactory.cpp b/services/camera/libcameraservice/ext/CameraServiceExtFactory.cpp new file mode 100644 index 00000000000..df12292b7bf --- /dev/null +++ b/services/camera/libcameraservice/ext/CameraServiceExtFactory.cpp @@ -0,0 +1,103 @@ +#include "CameraServiceExtFactory.h" +#include +#include + +namespace android { + +void* CameraServiceExtFactory::sFunctionTable = nullptr; +void* CameraServiceExtFactory::sExtObject = nullptr; +int (*CameraServiceExtFactory::sOnTransactFunc)(void*, uint32_t, const Parcel&, Parcel*, uint32_t) = nullptr; + +void CameraServiceExtFactory::ensureLoaded() { + if (sFunctionTable != nullptr) return; + + const char* libPath = "system_ext/lib64/libcsextimpl.so"; + void* handle = dlopen(libPath, RTLD_NOW); + if (handle == nullptr) { + ALOGE("CameraServiceExtFactory: dlopen failed: %s", dlerror()); + return; + } + ALOGI("CameraServiceExtFactory: dlopen succeeded, handle=%p", handle); + + typedef void* (*GetFactoryFunc)(); + GetFactoryFunc getExtFactoryImpl = (GetFactoryFunc)dlsym(handle, "getExtFactoryImpl"); + if (getExtFactoryImpl == nullptr) { + ALOGE("CameraServiceExtFactory: dlsym getExtFactoryImpl failed: %s", dlerror()); + dlclose(handle); + return; + } + ALOGI("CameraServiceExtFactory: getExtFactoryImpl at %p", getExtFactoryImpl); + + // Triple indirection as determined from logs: getExtFactoryImpl returns ptr to ptr to ptr to function + void* ptrToPtr = getExtFactoryImpl(); + if (ptrToPtr == nullptr) { + ALOGE("CameraServiceExtFactory: getExtFactoryImpl returned null"); + dlclose(handle); + return; + } + + void* ptrToFunc = *(void**)ptrToPtr; + if (ptrToFunc == nullptr) { + ALOGE("CameraServiceExtFactory: first deref gave null"); + dlclose(handle); + return; + } + + void* actualFunc = *(void**)ptrToFunc; + if (actualFunc == nullptr) { + ALOGE("CameraServiceExtFactory: second deref gave null"); + dlclose(handle); + return; + } + ALOGI("CameraServiceExtFactory: actual factory function at %p", actualFunc); + + sFunctionTable = operator new(8); + *(void**)sFunctionTable = actualFunc; + ALOGI("CameraServiceExtFactory: function table at %p", sFunctionTable); + + // Resolve onTransact (for direct call via vtable) + sOnTransactFunc = (int (*)(void*, uint32_t, const Parcel&, Parcel*, uint32_t)) + dlsym(handle, "_ZN7android20CameraServiceExtImpl10onTransactEjRKNS_6ParcelEPS1_j"); + if (sOnTransactFunc == nullptr) { + ALOGE("CameraServiceExtFactory: dlsym onTransact failed: %s", dlerror()); + } else { + ALOGI("CameraServiceExtFactory: onTransact found at %p", sOnTransactFunc); + } +} + +void* CameraServiceExtFactory::getInstance() { + ensureLoaded(); + return sFunctionTable; // may be null +} + +int CameraServiceExtFactory::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { + ensureLoaded(); + if (sExtObject == nullptr) { + if (sFunctionTable == nullptr) { + ALOGE("CameraServiceExtFactory::onTransact: extension not loaded"); + return -1; + } + void* actualFunc = *(void**)sFunctionTable; + if (actualFunc == nullptr) return -1; + typedef void* (*GetObjectFunc)(); + sExtObject = ((GetObjectFunc)actualFunc)(); + if (sExtObject == nullptr) { + ALOGE("CameraServiceExtFactory: factory returned null"); + return -1; + } + ALOGI("CameraServiceExtFactory: real extension object at %p", sExtObject); + } + + if (sOnTransactFunc == nullptr) { + ALOGE("CameraServiceExtFactory::onTransact: no function pointer"); + return -1; + } + return sOnTransactFunc(sExtObject, code, data, reply, flags); +} + +CameraServiceExtFactory::~CameraServiceExtFactory() { + // No cleanup needed – the extension library manages its own singleton. + ALOGV("CameraServiceExtFactory destructor (stub)"); +} + +} // namespace android diff --git a/services/camera/libcameraservice/ext/ICameraServiceExt.cpp b/services/camera/libcameraservice/ext/ICameraServiceExt.cpp new file mode 100644 index 00000000000..d691995a42d --- /dev/null +++ b/services/camera/libcameraservice/ext/ICameraServiceExt.cpp @@ -0,0 +1,16 @@ +#include "ICameraServiceExt.h" +#include + +namespace android { + + ICameraServiceExt::ICameraServiceExt() { + // Do nothing – the real object will call this as part of its construction. + // No member initialisation to avoid corrupting the real object's memory. + ALOGV("ICameraServiceExt constructor (stub, no-op)"); + } + + ICameraServiceExt::~ICameraServiceExt() { + ALOGV("ICameraServiceExt destructor (stub, no-op)"); + } + +} // namespace android diff --git a/services/camera/libcameraservice/ext/include/CameraServiceExtFactory.h b/services/camera/libcameraservice/ext/include/CameraServiceExtFactory.h new file mode 100644 index 00000000000..f7ab9c68596 --- /dev/null +++ b/services/camera/libcameraservice/ext/include/CameraServiceExtFactory.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace android { + +// Forward declaration – we will not define this class +class ICameraServiceExt; + +class CameraServiceExtFactory { +public: + // Returns a pointer to a function table (as required by OxygenOS) + static void* getInstance(); + static int onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); + virtual ~CameraServiceExtFactory(); + +private: + static void ensureLoaded(); + static void* sFunctionTable; // pointer to function pointer + static void* sExtObject; // the real extension object (as void*) + static int (*sOnTransactFunc)(void*, uint32_t, const Parcel&, Parcel*, uint32_t); +}; + +} // namespace android diff --git a/services/camera/libcameraservice/ext/include/ICameraServiceExt.h b/services/camera/libcameraservice/ext/include/ICameraServiceExt.h new file mode 100644 index 00000000000..daf72d5b5d1 --- /dev/null +++ b/services/camera/libcameraservice/ext/include/ICameraServiceExt.h @@ -0,0 +1,14 @@ +#pragma once + +namespace android { + + // Empty placeholder class – no members, no base classes. + // The real implementation from the extension library will provide its own. + class ICameraServiceExt { + public: + ICameraServiceExt(); + ~ICameraServiceExt(); + // No other methods – the real object's vtable will be used. + }; + +} // namespace android diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp index a989ab1c004..dfab38a36ba 100644 --- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp +++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp @@ -237,7 +237,7 @@ bool roundBufferDimensionNearest(int32_t width, int32_t height, // those are not populated in static capabilities. if (isPriviledgedClient == true && (format == HAL_PIXEL_FORMAT_YCbCr_420_888 || format == HAL_PIXEL_FORMAT_BLOB || - format == HAL_PIXEL_FORMAT_Y8)) { + format == HAL_PIXEL_FORMAT_Y8 || format == HAL_PIXEL_FORMAT_Y16)) { ALOGI("Bypass roundBufferDimensionNearest for privilegedClient YUV streams " "width %d height %d for format %d", width, height, format); @@ -514,7 +514,7 @@ binder::Status createConfiguredSurface( uint64_t allowedFlags = GraphicBuffer::USAGE_SW_READ_MASK | GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_HW_COMPOSER; - bool flexibleConsumer = (consumerUsage & disallowedFlags) == 0 && + bool flexibleConsumer = !isPriviledgedClient && (consumerUsage & disallowedFlags) == 0 && (consumerUsage & allowedFlags) != 0; out_surface = new Surface(flagtools::surfaceTypeToIGBP(surface), useAsync); diff --git a/services/camera/virtualcamera/VirtualCameraDevice.cc b/services/camera/virtualcamera/VirtualCameraDevice.cc index dd0d73ea014..3db0409d57a 100644 --- a/services/camera/virtualcamera/VirtualCameraDevice.cc +++ b/services/camera/virtualcamera/VirtualCameraDevice.cc @@ -163,7 +163,7 @@ std::optional getMaxResolution( auto itMax = std::max_element(configs.begin(), configs.end(), [](const SupportedStreamConfiguration& a, const SupportedStreamConfiguration& b) { - return a.width * b.height < a.width * b.height; + return a.width * a.height < b.width * b.height; }); if (itMax == configs.end()) { ALOGE( diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.cc b/services/camera/virtualcamera/VirtualCameraRenderThread.cc index d1b1ff46c4c..ad4502a03dd 100644 --- a/services/camera/virtualcamera/VirtualCameraRenderThread.cc +++ b/services/camera/virtualcamera/VirtualCameraRenderThread.cc @@ -292,6 +292,11 @@ VirtualCameraRenderThread::VirtualCameraRenderThread( mInputSurfaceSize(inputSurfaceSize), mReportedSensorSize(reportedSensorSize), mSessionContext(sessionContext), + mLastAcquisitionTimestampNanoseconds( + std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count()), + mLastSurfaceTimestampNanoseconds(0), mInputSurfaceFuture(mInputSurfacePromise.get_future()) { } diff --git a/services/camera/virtualcamera/util/Util.cc b/services/camera/virtualcamera/util/Util.cc index 26015d1d5c5..b9ba1bb088b 100644 --- a/services/camera/virtualcamera/util/Util.cc +++ b/services/camera/virtualcamera/util/Util.cc @@ -99,6 +99,7 @@ PlanesLockGuard::PlanesLockGuard(std::shared_ptr hwBuffer, if (rawFence >= 0) { close(rawFence); } + mHwBuffer = hwBuffer; } PlanesLockGuard::~PlanesLockGuard() { @@ -108,7 +109,7 @@ PlanesLockGuard::~PlanesLockGuard() { AHardwareBuffer_unlock(mHwBuffer.get(), /*fence=*/nullptr); } -int PlanesLockGuard::getStatus() const { +status_t PlanesLockGuard::getStatus() const { return mLockStatus; } diff --git a/services/camera/virtualcamera/util/Util.h b/services/camera/virtualcamera/util/Util.h index 1ebcc6d08c9..ff0622b1601 100644 --- a/services/camera/virtualcamera/util/Util.h +++ b/services/camera/virtualcamera/util/Util.h @@ -92,7 +92,7 @@ class PlanesLockGuard { // Disable copy. PlanesLockGuard(const PlanesLockGuard&) = delete; - PlanesLockGuard& operator=(const YCbCrLockGuard&) = delete; + PlanesLockGuard& operator=(const PlanesLockGuard&) = delete; private: std::shared_ptr mHwBuffer; diff --git a/services/mediametrics/statsd_codec.cpp b/services/mediametrics/statsd_codec.cpp index 256ce8b9f33..bcc2a828ae3 100644 --- a/services/mediametrics/statsd_codec.cpp +++ b/services/mediametrics/statsd_codec.cpp @@ -180,7 +180,8 @@ static void parseVector(const std::string &str, std::vector *vector) { bool statsd_codec(const std::shared_ptr& item, const std::shared_ptr& statsdLog) { - if (item == nullptr) return false; + bool statsd_enabled = false; + if (item == nullptr || !statsd_enabled) return false; AStatsEvent* event = AStatsEvent_obtain(); AStatsEvent_setAtomId(event, stats::media_metrics::MEDIA_CODEC_REPORTED);