diff options
580 files changed, 13747 insertions, 7611 deletions
diff --git a/Android.bp b/Android.bp index 53f8bec1aa..b207a968d5 100644 --- a/Android.bp +++ b/Android.bp @@ -1,20 +1,7 @@ -ndk_headers { - name: "libcamera2ndk_headers", - from: "include/camera/ndk/", - to: "camera", - srcs: ["include/camera/ndk/**/*.h"], - license: "NOTICE", -} - -ndk_headers { - name: "libmediandk_headers", - from: "include/ndk/", - to: "media", - srcs: ["include/ndk/**/*.h"], - license: "NOTICE", -} - subdirs = [ - "camera/ndk", + "camera", + "drm/*", "media/*", + "radio", + "soundtrigger", ] diff --git a/CleanSpec.mk b/CleanSpec.mk index 361686cc07..5e4d81d7b6 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -77,6 +77,7 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/soundfx/libvisualizer.so $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/soundfx/libreverbwrapper.so) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/soundfx/libbundlewrapper.so) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/soundfx/libaudiopreprocessing.so) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libmediacodecservice.so) # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST diff --git a/camera/Android.bp b/camera/Android.bp new file mode 100644 index 0000000000..c76ae507fd --- /dev/null +++ b/camera/Android.bp @@ -0,0 +1,83 @@ +// Copyright 2010 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. + +subdirs = ["ndk"] + +cc_library_shared { + name: "libcamera_client", + + aidl: { + export_aidl_headers: true, + local_include_dirs: ["aidl"], + include_dirs: [ + "frameworks/native/aidl/gui", + ], + }, + + srcs: [ + // AIDL files for camera interfaces + // The headers for these interfaces will be available to any modules that + // include libcamera_client, at the path "aidl/package/path/BnFoo.h" + "aidl/android/hardware/ICameraService.aidl", + "aidl/android/hardware/ICameraServiceListener.aidl", + "aidl/android/hardware/ICameraServiceProxy.aidl", + "aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl", + "aidl/android/hardware/camera2/ICameraDeviceUser.aidl", + + + // Source for camera interface parcelables, and manually-written interfaces + "Camera.cpp", + "CameraMetadata.cpp", + "CameraParameters.cpp", + "CaptureResult.cpp", + "CameraParameters2.cpp", + "ICamera.cpp", + "ICameraClient.cpp", + "ICameraRecordingProxy.cpp", + "ICameraRecordingProxyListener.cpp", + "camera2/CaptureRequest.cpp", + "camera2/OutputConfiguration.cpp", + "camera2/SubmitInfo.cpp", + "CameraBase.cpp", + "CameraUtils.cpp", + "VendorTagDescriptor.cpp", + ], + + shared_libs: [ + "libcutils", + "libutils", + "liblog", + "libbinder", + "libgui", + "libcamera_metadata", + "libnativewindow", + ], + + include_dirs: [ + "system/media/private/camera/include", + "frameworks/native/include/media/openmax", + ], + export_include_dirs: [ + "include", + "include/camera" + ], + export_shared_lib_headers: ["libcamera_metadata"], + + cflags: [ + "-Werror", + "-Wall", + "-Wextra", + ], + +} diff --git a/camera/Android.mk b/camera/Android.mk index 91d87edad5..d9068c0ab9 100644 --- a/camera/Android.mk +++ b/camera/Android.mk @@ -12,67 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -CAMERA_CLIENT_LOCAL_PATH:= $(call my-dir) include $(call all-subdir-makefiles) -include $(CLEAR_VARS) - -LOCAL_PATH := $(CAMERA_CLIENT_LOCAL_PATH) - -LOCAL_AIDL_INCLUDES := \ - frameworks/av/camera/aidl \ - frameworks/base/core/java \ - frameworks/native/aidl/gui - -# AIDL files for camera interfaces -# The headers for these interfaces will be available to any modules that -# include libcamera_client, at the path "aidl/package/path/BnFoo.h" - -LOCAL_SRC_FILES := \ - aidl/android/hardware/ICameraService.aidl \ - aidl/android/hardware/ICameraServiceListener.aidl \ - aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl \ - aidl/android/hardware/camera2/ICameraDeviceUser.aidl - -# Source for camera interface parcelables, and manually-written interfaces - -LOCAL_SRC_FILES += \ - Camera.cpp \ - CameraMetadata.cpp \ - CameraParameters.cpp \ - CaptureResult.cpp \ - CameraParameters2.cpp \ - ICamera.cpp \ - ICameraClient.cpp \ - ICameraServiceProxy.cpp \ - ICameraRecordingProxy.cpp \ - ICameraRecordingProxyListener.cpp \ - camera2/CaptureRequest.cpp \ - camera2/OutputConfiguration.cpp \ - camera2/SubmitInfo.cpp \ - CameraBase.cpp \ - CameraUtils.cpp \ - VendorTagDescriptor.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - liblog \ - libbinder \ - libgui \ - libcamera_metadata \ - -LOCAL_C_INCLUDES += \ - system/media/camera/include \ - system/media/private/camera/include \ - frameworks/native/include/media/openmax \ - $(LOCAL_PATH)/include/camera - -LOCAL_EXPORT_C_INCLUDE_DIRS := \ - system/media/camera/include \ - $(LOCAL_PATH)/include/camera - -LOCAL_CFLAGS += -Werror -Wall -Wextra - -LOCAL_MODULE:= libcamera_client - -include $(BUILD_SHARED_LIBRARY) diff --git a/camera/ICameraServiceProxy.cpp b/camera/ICameraServiceProxy.cpp deleted file mode 100644 index a9d08360d3..0000000000 --- a/camera/ICameraServiceProxy.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "BpCameraServiceProxy" - -#include <stdint.h> - -#include <binder/Parcel.h> - -#include <camera/ICameraServiceProxy.h> - -namespace android { - -class BpCameraServiceProxy: public BpInterface<ICameraServiceProxy> { -public: - explicit BpCameraServiceProxy(const sp<IBinder>& impl) - : BpInterface<ICameraServiceProxy>(impl) {} - - virtual void pingForUserUpdate() { - Parcel data; - data.writeInterfaceToken(ICameraServiceProxy::getInterfaceDescriptor()); - remote()->transact(BnCameraServiceProxy::PING_FOR_USER_UPDATE, data, nullptr, - IBinder::FLAG_ONEWAY); - } - - virtual void notifyCameraState(String16 cameraId, CameraState newCameraState) { - Parcel data; - data.writeInterfaceToken(ICameraServiceProxy::getInterfaceDescriptor()); - data.writeString16(cameraId); - data.writeInt32(newCameraState); - remote()->transact(BnCameraServiceProxy::NOTIFY_CAMERA_STATE, data, nullptr, - IBinder::FLAG_ONEWAY); - } - -}; - - -IMPLEMENT_META_INTERFACE(CameraServiceProxy, "android.hardware.ICameraServiceProxy"); - -status_t BnCameraServiceProxy::onTransact(uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags) { - switch(code) { - case PING_FOR_USER_UPDATE: { - CHECK_INTERFACE(ICameraServiceProxy, data, reply); - pingForUserUpdate(); - return NO_ERROR; - } break; - case NOTIFY_CAMERA_STATE: { - CHECK_INTERFACE(ICameraServiceProxy, data, reply); - String16 cameraId = data.readString16(); - CameraState newCameraState = - static_cast<CameraState>(data.readInt32()); - notifyCameraState(cameraId, newCameraState); - return NO_ERROR; - } break; - default: - return BBinder::onTransact(code, data, reply, flags); - } -} -}; // namespace android diff --git a/camera/aidl/android/hardware/ICameraServiceProxy.aidl b/camera/aidl/android/hardware/ICameraServiceProxy.aidl index 0e654d5083..5dc23eb477 100644 --- a/camera/aidl/android/hardware/ICameraServiceProxy.aidl +++ b/camera/aidl/android/hardware/ICameraServiceProxy.aidl @@ -31,7 +31,23 @@ interface ICameraServiceProxy oneway void pingForUserUpdate(); /** - * Update the status of a camera device + * Values for notifyCameraState newCameraState */ - oneway void notifyCameraState(String cameraId, int newCameraState); + const int CAMERA_STATE_OPEN = 0; + const int CAMERA_STATE_ACTIVE = 1; + const int CAMERA_STATE_IDLE = 2; + const int CAMERA_STATE_CLOSED = 3; + + /** + * Values for notifyCameraState facing + */ + const int CAMERA_FACING_BACK = 0; + const int CAMERA_FACING_FRONT = 1; + const int CAMERA_FACING_EXTERNAL = 2; + + /** + * Update the status of a camera device. + */ + oneway void notifyCameraState(String cameraId, int facing, int newCameraState, + String clientName); } diff --git a/camera/cameraserver/Android.mk b/camera/cameraserver/Android.mk index d32e2526b0..b8c94e64e3 100644 --- a/camera/cameraserver/Android.mk +++ b/camera/cameraserver/Android.mk @@ -30,8 +30,7 @@ LOCAL_SHARED_LIBRARIES := \ android.hardware.camera.common@1.0 \ android.hardware.camera.provider@2.4 \ android.hardware.camera.device@1.0 \ - android.hardware.camera.device@3.2 \ - android.hidl.manager@1.0 + android.hardware.camera.device@3.2 LOCAL_MODULE:= cameraserver LOCAL_32_BIT_ONLY := true diff --git a/camera/include/camera/ICameraServiceProxy.h b/camera/include/camera/ICameraServiceProxy.h deleted file mode 100644 index 2613c015b7..0000000000 --- a/camera/include/camera/ICameraServiceProxy.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HARDWARE_ICAMERASERVICEPROXY_H -#define ANDROID_HARDWARE_ICAMERASERVICEPROXY_H - -#include <utils/RefBase.h> -#include <binder/IInterface.h> -#include <binder/Parcel.h> - -namespace android { - -/** - * Interface from native camera service to managed-side camera service proxy. - * - * Keep in sync with frameworks/base/core/java/android/hardware/ICameraServiceProxy.aidl - * - */ -class ICameraServiceProxy : public IInterface { -public: - enum { - PING_FOR_USER_UPDATE = IBinder::FIRST_CALL_TRANSACTION, - NOTIFY_CAMERA_STATE - }; - - enum CameraState { - CAMERA_STATE_OPEN, - CAMERA_STATE_ACTIVE, - CAMERA_STATE_IDLE, - CAMERA_STATE_CLOSED - }; - - DECLARE_META_INTERFACE(CameraServiceProxy); - - virtual void pingForUserUpdate() = 0; - virtual void notifyCameraState(String16 cameraId, CameraState newCameraState) = 0; -}; - -class BnCameraServiceProxy: public BnInterface<ICameraServiceProxy> -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - - - -}; // namespace android - -#endif // ANDROID_HARDWARE_ICAMERASERVICEPROXY_H diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp index ade0d726b7..97cf6bfaf8 100644 --- a/camera/ndk/Android.bp +++ b/camera/ndk/Android.bp @@ -22,3 +22,11 @@ ndk_library { first_version: "24", unversioned_until: "current", } + +ndk_headers { + name: "libcamera2ndk_headers", + from: "include/camera", + to: "camera", + srcs: ["include/camera/**/*.h"], + license: "NOTICE", +} diff --git a/camera/ndk/Android.mk b/camera/ndk/Android.mk index 591dfc2e18..f5ff69dbde 100644 --- a/camera/ndk/Android.mk +++ b/camera/ndk/Android.mk @@ -33,9 +33,8 @@ LOCAL_SRC_FILES:= \ LOCAL_MODULE:= libcamera2ndk -LOCAL_C_INCLUDES := \ - frameworks/av/include/camera/ndk \ - frameworks/av/include/ndk +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))' LOCAL_CFLAGS += -Wall -Wextra -Werror @@ -49,7 +48,8 @@ LOCAL_SHARED_LIBRARIES := \ libcamera_client \ libstagefright_foundation \ libcutils \ - libcamera_metadata + libcamera_metadata \ + libmediandk include $(BUILD_SHARED_LIBRARY) diff --git a/camera/ndk/NOTICE b/camera/ndk/NOTICE new file mode 100644 index 0000000000..152be20595 --- /dev/null +++ b/camera/ndk/NOTICE @@ -0,0 +1,324 @@ + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the Android-specific code. == + ========================================================================= + +Android Code +Copyright 2005-2008 The Android Open Source Project + +This product includes software developed as part of +The Android Open Source Project (http://source.android.com). + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for Apache Commons code. == + ========================================================================= + +Apache Commons +Copyright 1999-2006 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for Jakarta Commons Logging. == + ========================================================================= + +Jakarta Commons Logging (JCL) +Copyright 2005,2006 The Apache Software Foundation. + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the Nuance code. == + ========================================================================= + +These files are Copyright 2007 Nuance Communications, but released under +the Apache2 License. + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the Media Codecs code. == + ========================================================================= + +Media Codecs +These files are Copyright 1998 - 2009 PacketVideo, but released under +the Apache2 License. + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the TagSoup code. == + ========================================================================= + +This file is part of TagSoup and is Copyright 2002-2008 by John Cowan. + +TagSoup is licensed under the Apache License, +Version 2.0. You may obtain a copy of this license at +http://www.apache.org/licenses/LICENSE-2.0 . You may also have +additional legal rights not granted by this license. + +TagSoup is distributed in the hope that it will be useful, but +unless required by applicable law or agreed to in writing, TagSoup +is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +OF ANY KIND, either express or implied; not even the implied warranty +of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for Additional Codecs code. == + ========================================================================= + +Additional Codecs +These files are Copyright 2003-2010 VisualOn, but released under +the Apache2 License. + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the Audio Effects code. == + ========================================================================= + +Audio Effects +These files are Copyright (C) 2004-2010 NXP Software and +Copyright (C) 2010 The Android Open Source Project, but released under +the Apache2 License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + + +UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE + +Unicode Data Files include all data files under the directories +http://www.unicode.org/Public/, http://www.unicode.org/reports/, +and http://www.unicode.org/cldr/data/ . Unicode Software includes any +source code published in the Unicode Standard or under the directories +http://www.unicode.org/Public/, http://www.unicode.org/reports/, and +http://www.unicode.org/cldr/data/. + +NOTICE TO USER: Carefully read the following legal agreement. BY +DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA +FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY +ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF +THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, +DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2008 Unicode, Inc. All rights reserved. Distributed +under the Terms of Use in http://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation (the +"Data Files") or Unicode software and any associated documentation (the +"Software") to deal in the Data Files or Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, and/or sell copies of the Data Files or Software, +and to permit persons to whom the Data Files or Software are furnished to +do so, provided that (a) the above copyright notice(s) and this permission +notice appear with all copies of the Data Files or Software, (b) both the +above copyright notice(s) and this permission notice appear in associated +documentation, and (c) there is clear notice in each modified Data File +or in the Software as well as in the documentation associated with the +Data File(s) or Software that the data or software has been modified. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS +INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT +OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE +OR PERFORMANCE OF THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in these Data Files or Software without prior written +authorization of the copyright holder. diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp index d6eff24104..2a6b18200f 100644 --- a/camera/ndk/NdkCameraCaptureSession.cpp +++ b/camera/ndk/NdkCameraCaptureSession.cpp @@ -23,9 +23,9 @@ #include <utils/StrongPointer.h> #include <utils/Trace.h> -#include "NdkCameraDevice.h" -#include <NdkCaptureRequest.h> -#include <NdkCameraCaptureSession.h> +#include <camera/NdkCameraDevice.h> +#include <camera/NdkCaptureRequest.h> +#include <camera/NdkCameraCaptureSession.h> #include "impl/ACameraCaptureSession.h" using namespace android; diff --git a/camera/ndk/NdkCameraDevice.cpp b/camera/ndk/NdkCameraDevice.cpp index 281d3e75ab..9f6d1f7c6d 100644 --- a/camera/ndk/NdkCameraDevice.cpp +++ b/camera/ndk/NdkCameraDevice.cpp @@ -21,7 +21,7 @@ #include <utils/Log.h> #include <utils/Trace.h> -#include <NdkCameraDevice.h> +#include <camera/NdkCameraDevice.h> #include "impl/ACameraCaptureSession.h" using namespace android; diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp index ff15263211..60b4763d85 100644 --- a/camera/ndk/NdkCameraManager.cpp +++ b/camera/ndk/NdkCameraManager.cpp @@ -21,7 +21,7 @@ #include <utils/Log.h> #include <utils/Trace.h> -#include <NdkCameraManager.h> +#include <camera/NdkCameraManager.h> #include "impl/ACameraManager.h" using namespace android; diff --git a/camera/ndk/NdkCameraMetadata.cpp b/camera/ndk/NdkCameraMetadata.cpp index 85fe75b050..65de81ff81 100644 --- a/camera/ndk/NdkCameraMetadata.cpp +++ b/camera/ndk/NdkCameraMetadata.cpp @@ -21,7 +21,7 @@ #include <utils/Log.h> #include <utils/Trace.h> -#include "NdkCameraMetadata.h" +#include <camera/NdkCameraMetadata.h> #include "impl/ACameraMetadata.h" using namespace android; diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp index 7c37955027..5b4c1809f7 100644 --- a/camera/ndk/NdkCaptureRequest.cpp +++ b/camera/ndk/NdkCaptureRequest.cpp @@ -21,7 +21,7 @@ #include <utils/Log.h> #include <utils/Trace.h> -#include "NdkCaptureRequest.h" +#include <camera/NdkCaptureRequest.h> #include "impl/ACameraMetadata.h" #include "impl/ACaptureRequest.h" diff --git a/camera/ndk/impl/ACameraCaptureSession.h b/camera/ndk/impl/ACameraCaptureSession.h index f56219cbf1..339c66577c 100644 --- a/camera/ndk/impl/ACameraCaptureSession.h +++ b/camera/ndk/impl/ACameraCaptureSession.h @@ -18,7 +18,7 @@ #include <set> #include <hardware/camera3.h> -#include <NdkCameraDevice.h> +#include <camera/NdkCameraDevice.h> #include "ACameraDevice.h" using namespace android; diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h index eb8028b658..c566cd295c 100644 --- a/camera/ndk/impl/ACameraDevice.h +++ b/camera/ndk/impl/ACameraDevice.h @@ -36,7 +36,7 @@ #include <camera/camera2/OutputConfiguration.h> #include <camera/camera2/CaptureRequest.h> -#include <NdkCameraDevice.h> +#include <camera/NdkCameraDevice.h> #include "ACameraMetadata.h" namespace android { diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h index 97e4fd996b..4a172f38e5 100644 --- a/camera/ndk/impl/ACameraManager.h +++ b/camera/ndk/impl/ACameraManager.h @@ -17,7 +17,7 @@ #ifndef _ACAMERA_MANAGER_H #define _ACAMERA_MANAGER_H -#include "NdkCameraManager.h" +#include <camera/NdkCameraManager.h> #include <android/hardware/ICameraService.h> #include <android/hardware/BnCameraServiceListener.h> diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp index c0da592a29..7b33c32ce6 100644 --- a/camera/ndk/impl/ACameraMetadata.cpp +++ b/camera/ndk/impl/ACameraMetadata.cpp @@ -20,7 +20,7 @@ #include "ACameraMetadata.h" #include <utils/Vector.h> #include <system/graphics.h> -#include "NdkImage.h" +#include <media/NdkImage.h> using namespace android; diff --git a/camera/ndk/impl/ACameraMetadata.h b/camera/ndk/impl/ACameraMetadata.h index 8d050c4e3f..143efc7e12 100644 --- a/camera/ndk/impl/ACameraMetadata.h +++ b/camera/ndk/impl/ACameraMetadata.h @@ -24,7 +24,7 @@ #include <utils/Vector.h> #include <camera/CameraMetadata.h> -#include "NdkCameraMetadata.h" +#include <camera/NdkCameraMetadata.h> using namespace android; diff --git a/camera/ndk/impl/ACaptureRequest.h b/camera/ndk/impl/ACaptureRequest.h index 3ef6a840f1..e5b453e32c 100644 --- a/camera/ndk/impl/ACaptureRequest.h +++ b/camera/ndk/impl/ACaptureRequest.h @@ -16,7 +16,7 @@ #ifndef _ACAPTURE_REQUEST_H #define _ACAPTURE_REQUEST_H -#include "NdkCaptureRequest.h" +#include <camera/NdkCaptureRequest.h> #include <set> using namespace android; diff --git a/camera/include/camera/ndk/NdkCameraCaptureSession.h b/camera/ndk/include/camera/NdkCameraCaptureSession.h index d96f5386b7..d96f5386b7 100644 --- a/camera/include/camera/ndk/NdkCameraCaptureSession.h +++ b/camera/ndk/include/camera/NdkCameraCaptureSession.h diff --git a/camera/include/camera/ndk/NdkCameraDevice.h b/camera/ndk/include/camera/NdkCameraDevice.h index 9b7f6f46f6..9b7f6f46f6 100644 --- a/camera/include/camera/ndk/NdkCameraDevice.h +++ b/camera/ndk/include/camera/NdkCameraDevice.h diff --git a/camera/include/camera/ndk/NdkCameraError.h b/camera/ndk/include/camera/NdkCameraError.h index 6b5815502b..6b5815502b 100644 --- a/camera/include/camera/ndk/NdkCameraError.h +++ b/camera/ndk/include/camera/NdkCameraError.h diff --git a/camera/include/camera/ndk/NdkCameraManager.h b/camera/ndk/include/camera/NdkCameraManager.h index 5b5c98b74c..5b5c98b74c 100644 --- a/camera/include/camera/ndk/NdkCameraManager.h +++ b/camera/ndk/include/camera/NdkCameraManager.h diff --git a/camera/include/camera/ndk/NdkCameraMetadata.h b/camera/ndk/include/camera/NdkCameraMetadata.h index f2aec98617..f2aec98617 100644 --- a/camera/include/camera/ndk/NdkCameraMetadata.h +++ b/camera/ndk/include/camera/NdkCameraMetadata.h diff --git a/camera/include/camera/ndk/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h index 629d75afae..629d75afae 100644 --- a/camera/include/camera/ndk/NdkCameraMetadataTags.h +++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h diff --git a/camera/include/camera/ndk/NdkCaptureRequest.h b/camera/ndk/include/camera/NdkCaptureRequest.h index c62ba2c45b..c62ba2c45b 100644 --- a/camera/include/camera/ndk/NdkCaptureRequest.h +++ b/camera/ndk/include/camera/NdkCaptureRequest.h diff --git a/cmds/screenrecord/Android.mk b/cmds/screenrecord/Android.mk index a3b1a346df..7aa684a30a 100644 --- a/cmds/screenrecord/Android.mk +++ b/cmds/screenrecord/Android.mk @@ -31,7 +31,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES := \ frameworks/av/media/libstagefright \ frameworks/av/media/libstagefright/include \ - $(TOP)/frameworks/native/include/media/openmax \ + frameworks/native/include/media/openmax \ external/jpeg LOCAL_CFLAGS := -Werror -Wall diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk index ff5e5d303b..f647ffd9e0 100644 --- a/cmds/stagefright/Android.mk +++ b/cmds/stagefright/Android.mk @@ -16,7 +16,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES:= \ frameworks/av/media/libstagefright \ frameworks/av/media/libstagefright/include \ - $(TOP)/frameworks/native/include/media/openmax \ + frameworks/native/include/media/openmax \ external/jpeg \ LOCAL_CFLAGS += -Wno-multichar -Werror -Wall @@ -40,8 +40,8 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES:= \ frameworks/av/media/libstagefright \ - $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/frameworks/native/include/media/hardware + frameworks/native/include/media/openmax \ + frameworks/native/include/media/hardware LOCAL_CFLAGS += -Wno-multichar -Werror -Wall @@ -64,8 +64,8 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES:= \ frameworks/av/media/libstagefright \ - $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/frameworks/native/include/media/hardware + frameworks/native/include/media/openmax \ + frameworks/native/include/media/hardware LOCAL_CFLAGS += -Wno-multichar -Werror -Wall @@ -89,7 +89,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES:= \ frameworks/av/media/libstagefright \ - $(TOP)/frameworks/native/include/media/openmax + frameworks/native/include/media/openmax LOCAL_CFLAGS += -Wno-multichar -Werror -Wall @@ -112,7 +112,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES:= \ frameworks/av/media/libstagefright \ - $(TOP)/frameworks/native/include/media/openmax + frameworks/native/include/media/openmax LOCAL_CFLAGS += -Wno-multichar -Werror -Wall @@ -136,7 +136,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES:= \ frameworks/av/media/libstagefright \ - $(TOP)/frameworks/native/include/media/openmax + frameworks/native/include/media/openmax LOCAL_CFLAGS += -Wno-multichar -Werror -Wall @@ -168,10 +168,10 @@ LOCAL_SHARED_LIBRARIES := \ libRScpp \ LOCAL_C_INCLUDES:= \ - $(TOP)/frameworks/av/media/libstagefright \ - $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/frameworks/rs/cpp \ - $(TOP)/frameworks/rs \ + frameworks/av/media/libstagefright \ + frameworks/native/include/media/openmax \ + frameworks/rs/cpp \ + frameworks/rs \ intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,) LOCAL_C_INCLUDES += $(intermediates) @@ -185,6 +185,9 @@ LOCAL_MODULE_TAGS := optional LOCAL_MODULE:= mediafilter +LOCAL_SANITIZE := cfi +LOCAL_SANITIZE_DIAG := cfi + include $(BUILD_EXECUTABLE) ################################################################################ @@ -200,7 +203,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES:= \ frameworks/av/media/libstagefright \ - $(TOP)/frameworks/native/include/media/openmax + frameworks/native/include/media/openmax LOCAL_CFLAGS += -Wno-multichar -Werror -Wall diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp index dfd5df710b..d7c2e87da9 100644 --- a/cmds/stagefright/stagefright.cpp +++ b/cmds/stagefright/stagefright.cpp @@ -162,7 +162,7 @@ static void dumpSource(const sp<IMediaSource> &source, const String8 &filename) 1, mbuf->range_length(), out), - (ssize_t)mbuf->range_length()); + mbuf->range_length()); mbuf->release(); mbuf = NULL; diff --git a/drm/common/Android.bp b/drm/common/Android.bp new file mode 100644 index 0000000000..0098c89630 --- /dev/null +++ b/drm/common/Android.bp @@ -0,0 +1,39 @@ +// +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_library_static { + name: "libdrmframeworkcommon", + + srcs: [ + "DrmConstraints.cpp", + "DrmMetadata.cpp", + "DrmConvertedStatus.cpp", + "DrmEngineBase.cpp", + "DrmInfo.cpp", + "DrmInfoRequest.cpp", + "DrmInfoStatus.cpp", + "DrmRights.cpp", + "DrmSupportInfo.cpp", + "IDrmManagerService.cpp", + "IDrmServiceListener.cpp", + "DrmInfoEvent.cpp", + "ReadWriteUtils.cpp", + ], + + static_libs: ["libbinder"], + + export_include_dirs: ["include"], +} diff --git a/drm/common/Android.mk b/drm/common/Android.mk deleted file mode 100644 index ca3d2cd7fb..0000000000 --- a/drm/common/Android.mk +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright (C) 2010 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. -# -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - DrmConstraints.cpp \ - DrmMetadata.cpp \ - DrmConvertedStatus.cpp \ - DrmEngineBase.cpp \ - DrmInfo.cpp \ - DrmInfoRequest.cpp \ - DrmInfoStatus.cpp \ - DrmRights.cpp \ - DrmSupportInfo.cpp \ - IDrmManagerService.cpp \ - IDrmServiceListener.cpp \ - DrmInfoEvent.cpp \ - ReadWriteUtils.cpp - -LOCAL_STATIC_LIBRARIES := libbinder - -LOCAL_C_INCLUDES := \ - $(TOP)/frameworks/av/include \ - $(TOP)/frameworks/av/drm/libdrmframework/include \ - $(TOP)/frameworks/av/drm/libdrmframework/plugins/common/include - -LOCAL_MODULE:= libdrmframeworkcommon - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_STATIC_LIBRARY) diff --git a/drm/libdrmframework/plugins/common/include/DrmEngineBase.h b/drm/common/include/DrmEngineBase.h index 417107f1bd..417107f1bd 100644 --- a/drm/libdrmframework/plugins/common/include/DrmEngineBase.h +++ b/drm/common/include/DrmEngineBase.h diff --git a/drm/libdrmframework/plugins/common/include/IDrmEngine.h b/drm/common/include/IDrmEngine.h index acc8ed9433..acc8ed9433 100644 --- a/drm/libdrmframework/plugins/common/include/IDrmEngine.h +++ b/drm/common/include/IDrmEngine.h diff --git a/drm/libdrmframework/include/IDrmManagerService.h b/drm/common/include/IDrmManagerService.h index 0376b492d8..0376b492d8 100644 --- a/drm/libdrmframework/include/IDrmManagerService.h +++ b/drm/common/include/IDrmManagerService.h diff --git a/drm/libdrmframework/include/IDrmServiceListener.h b/drm/common/include/IDrmServiceListener.h index 78c5d1a34f..78c5d1a34f 100644 --- a/drm/libdrmframework/include/IDrmServiceListener.h +++ b/drm/common/include/IDrmServiceListener.h diff --git a/drm/libdrmframework/include/ReadWriteUtils.h b/drm/common/include/ReadWriteUtils.h index 529b342457..529b342457 100644 --- a/drm/libdrmframework/include/ReadWriteUtils.h +++ b/drm/common/include/ReadWriteUtils.h diff --git a/drm/drmserver/Android.bp b/drm/drmserver/Android.bp new file mode 100644 index 0000000000..c25a0a172f --- /dev/null +++ b/drm/drmserver/Android.bp @@ -0,0 +1,46 @@ +// +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_binary { + name: "drmserver", + + srcs: [ + "main_drmserver.cpp", + "DrmManager.cpp", + "DrmManagerService.cpp", + ], + + shared_libs: [ + "libmedia", + "libutils", + "liblog", + "libbinder", + "libdl", + "libselinux", + ], + + static_libs: ["libdrmframeworkcommon"], + + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], + + compile_multilib: "32", + + init_rc: ["drmserver.rc"], +} diff --git a/drm/drmserver/Android.mk b/drm/drmserver/Android.mk deleted file mode 100644 index 3b8bb04e0d..0000000000 --- a/drm/drmserver/Android.mk +++ /dev/null @@ -1,49 +0,0 @@ -# -# Copyright (C) 2010 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. -# -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - main_drmserver.cpp \ - DrmManager.cpp \ - DrmManagerService.cpp - -LOCAL_SHARED_LIBRARIES := \ - libmedia \ - libutils \ - liblog \ - libbinder \ - libdl \ - libselinux - -LOCAL_STATIC_LIBRARIES := libdrmframeworkcommon - -LOCAL_C_INCLUDES := \ - $(TOP)/frameworks/av/include \ - $(TOP)/frameworks/av/drm/libdrmframework/include \ - $(TOP)/frameworks/av/drm/libdrmframework/plugins/common/include - -LOCAL_CFLAGS += -Wall -Wextra -Werror - -LOCAL_MODULE:= drmserver - -LOCAL_MODULE_TAGS := optional - -LOCAL_32_BIT_ONLY := true - -LOCAL_INIT_RC := drmserver.rc - -include $(BUILD_EXECUTABLE) diff --git a/drm/libdrmframework/include/DrmManager.h b/drm/drmserver/DrmManager.h index e7cdd36b76..e7cdd36b76 100644 --- a/drm/libdrmframework/include/DrmManager.h +++ b/drm/drmserver/DrmManager.h diff --git a/drm/libdrmframework/include/DrmManagerService.h b/drm/drmserver/DrmManagerService.h index 45cee2e203..45cee2e203 100644 --- a/drm/libdrmframework/include/DrmManagerService.h +++ b/drm/drmserver/DrmManagerService.h diff --git a/drm/libdrmframework/include/PlugInManager.h b/drm/drmserver/PlugInManager.h index 466844d8ee..466844d8ee 100644 --- a/drm/libdrmframework/include/PlugInManager.h +++ b/drm/drmserver/PlugInManager.h diff --git a/drm/libdrmframework/Android.bp b/drm/libdrmframework/Android.bp new file mode 100644 index 0000000000..43ba72bcb3 --- /dev/null +++ b/drm/libdrmframework/Android.bp @@ -0,0 +1,42 @@ +// +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_library_shared { + name: "libdrmframework", + + srcs: [ + "DrmManagerClientImpl.cpp", + "DrmManagerClient.cpp", + "NoOpDrmManagerClientImpl.cpp", + ], + + shared_libs: [ + "libutils", + "libcutils", + "liblog", + "libbinder", + "libdl", + ], + + static_libs: ["libdrmframeworkcommon"], + + export_include_dirs: ["include"], + export_static_lib_headers: ["libdrmframeworkcommon"], + + cflags: ["-Werror"], +} + +subdirs = ["plugins/*"] diff --git a/drm/libdrmframework/Android.mk b/drm/libdrmframework/Android.mk deleted file mode 100644 index cafcb9419f..0000000000 --- a/drm/libdrmframework/Android.mk +++ /dev/null @@ -1,48 +0,0 @@ -# -# Copyright (C) 2010 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. -# -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - DrmManagerClientImpl.cpp \ - DrmManagerClient.cpp \ - NoOpDrmManagerClientImpl.cpp - -LOCAL_MODULE:= libdrmframework - -LOCAL_SHARED_LIBRARIES := \ - libutils \ - libcutils \ - liblog \ - libbinder \ - libdl - -LOCAL_STATIC_LIBRARIES := \ - libdrmframeworkcommon - -LOCAL_C_INCLUDES += \ - $(TOP)/frameworks/av/drm/libdrmframework/include \ - $(TOP)/frameworks/av/include - -LOCAL_CFLAGS += -Werror - - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/drm/libdrmframework/plugins/Android.mk b/drm/libdrmframework/plugins/Android.mk deleted file mode 100644 index 9ee79618c2..0000000000 --- a/drm/libdrmframework/plugins/Android.mk +++ /dev/null @@ -1,16 +0,0 @@ -# -# Copyright (C) 2010 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 $(call all-subdir-makefiles) diff --git a/drm/libdrmframework/plugins/common/Android.bp b/drm/libdrmframework/plugins/common/Android.bp new file mode 100644 index 0000000000..213e57f859 --- /dev/null +++ b/drm/libdrmframework/plugins/common/Android.bp @@ -0,0 +1 @@ +subdirs = ["util"] diff --git a/drm/libdrmframework/plugins/common/Android.mk b/drm/libdrmframework/plugins/common/Android.mk deleted file mode 100644 index 9ee79618c2..0000000000 --- a/drm/libdrmframework/plugins/common/Android.mk +++ /dev/null @@ -1,16 +0,0 @@ -# -# Copyright (C) 2010 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 $(call all-subdir-makefiles) diff --git a/drm/libdrmframework/plugins/common/util/Android.bp b/drm/libdrmframework/plugins/common/util/Android.bp new file mode 100644 index 0000000000..0c0b6f26fa --- /dev/null +++ b/drm/libdrmframework/plugins/common/util/Android.bp @@ -0,0 +1,23 @@ +// +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_library_static { + name: "libdrmutility", + + srcs: ["src/MimeTypeUtil.cpp"], + + export_include_dirs: ["include"], +} diff --git a/drm/libdrmframework/plugins/common/util/Android.mk b/drm/libdrmframework/plugins/common/util/Android.mk deleted file mode 100644 index 2a7b01fdd9..0000000000 --- a/drm/libdrmframework/plugins/common/util/Android.mk +++ /dev/null @@ -1,42 +0,0 @@ -# -# Copyright (C) 2010 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. -# -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - src/MimeTypeUtil.cpp - -LOCAL_MODULE := libdrmutility - -base := frameworks/av - -LOCAL_C_INCLUDES += \ - $(base)/include \ - $(base)/include/drm \ - $(base)/include/drm/plugins \ - $(LOCAL_PATH)/include - - -ifneq ($(TARGET_BUILD_VARIANT),user) -LOCAL_C_INCLUDES += \ - $(LOCAL_PATH)/tools - -endif - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_STATIC_LIBRARY) diff --git a/drm/libdrmframework/plugins/forward-lock/Android.bp b/drm/libdrmframework/plugins/forward-lock/Android.bp new file mode 100644 index 0000000000..f884c14986 --- /dev/null +++ b/drm/libdrmframework/plugins/forward-lock/Android.bp @@ -0,0 +1,4 @@ +subdirs = [ + "FwdLockEngine", + "internal-format", +] diff --git a/drm/libdrmframework/plugins/forward-lock/Android.mk b/drm/libdrmframework/plugins/forward-lock/Android.mk deleted file mode 100644 index 9ee79618c2..0000000000 --- a/drm/libdrmframework/plugins/forward-lock/Android.mk +++ /dev/null @@ -1,16 +0,0 @@ -# -# Copyright (C) 2010 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 $(call all-subdir-makefiles) diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp new file mode 100644 index 0000000000..3f0f5f78e0 --- /dev/null +++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp @@ -0,0 +1,50 @@ +// +// Copyright (C) 2010 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 +//2 +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_library_shared { + name: "libfwdlockengine", + + cflags: [ + "-DUSE_64BIT_DRM_API", + // The flag below turns on local debug printouts + //"-DDRM_OMA_FL_ENGINE_DEBUG", + ], + + srcs: ["src/FwdLockEngine.cpp"], + + shared_libs: [ + "libicui18n", + "libicuuc", + "libutils", + "liblog", + "libdl", + "libcrypto", + "libssl", + "libdrmframework", + ], + + static_libs: [ + "libdrmutility", + "libdrmframeworkcommon", + "libfwdlock-common", + "libfwdlock-converter", + "libfwdlock-decoder", + ], + + local_include_dirs: ["include"], + + relative_install_path: "drm", +} diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk deleted file mode 100644 index 933464ff56..0000000000 --- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk +++ /dev/null @@ -1,67 +0,0 @@ -# -# Copyright (C) 2010 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. -# -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -# The flag below turns on local debug printouts -#LOCAL_CFLAGS += -DDRM_OMA_FL_ENGINE_DEBUG - -base := frameworks/av - -# Determine whether the DRM framework uses 64-bit data types for file offsets and do the same. -ifneq ($(shell grep -c 'off64_t offset' $(base)/drm/libdrmframework/plugins/common/include/IDrmEngine.h), 0) -LOCAL_CFLAGS += -DUSE_64BIT_DRM_API -endif - -LOCAL_SRC_FILES:= \ - src/FwdLockEngine.cpp - -LOCAL_MODULE := libfwdlockengine - -LOCAL_SHARED_LIBRARIES := \ - libicui18n \ - libicuuc \ - libutils \ - liblog \ - libdl \ - libcrypto \ - libssl \ - libdrmframework - -LOCAL_STATIC_LIBRARIES := \ - libdrmutility \ - libdrmframeworkcommon \ - libfwdlock-common \ - libfwdlock-converter \ - libfwdlock-decoder - - - -LOCAL_C_INCLUDES += \ - $(base)/include/drm \ - $(base)/drm/libdrmframework/plugins/common/include \ - $(base)/drm/libdrmframework/plugins/common/util/include \ - $(base)/drm/libdrmframework/plugins/forward-lock/internal-format/common \ - $(base)/drm/libdrmframework/plugins/forward-lock/internal-format/converter \ - $(base)/drm/libdrmframework/plugins/forward-lock/internal-format/decoder \ - $(LOCAL_PATH)/include - -LOCAL_MODULE_RELATIVE_PATH := drm - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h index d222703497..a571b3aa1f 100644 --- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h +++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h @@ -18,14 +18,14 @@ #define __FWDLOCKENGINE_H__ #include <DrmEngineBase.h> -#include <DrmConstraints.h> -#include <DrmRights.h> -#include <DrmInfo.h> -#include <DrmInfoStatus.h> -#include <DrmConvertedStatus.h> -#include <DrmInfoRequest.h> -#include <DrmSupportInfo.h> -#include <DrmInfoEvent.h> +#include <drm/DrmConstraints.h> +#include <drm/DrmRights.h> +#include <drm/DrmInfo.h> +#include <drm/DrmInfoStatus.h> +#include <drm/DrmConvertedStatus.h> +#include <drm/DrmInfoRequest.h> +#include <drm/DrmSupportInfo.h> +#include <drm/DrmInfoEvent.h> #include "SessionMap.h" #include "FwdLockConv.h" diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp index a495616a38..830def931c 100644 --- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp +++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp @@ -20,17 +20,17 @@ #include <errno.h> #include <stdio.h> #include <unistd.h> -#include "drm_framework_common.h" +#include <drm/drm_framework_common.h> #include <fcntl.h> #include <limits.h> -#include <DrmRights.h> -#include <DrmConstraints.h> -#include <DrmMetadata.h> -#include <DrmInfo.h> -#include <DrmInfoStatus.h> -#include <DrmInfoRequest.h> -#include <DrmSupportInfo.h> -#include <DrmConvertedStatus.h> +#include <drm/DrmRights.h> +#include <drm/DrmConstraints.h> +#include <drm/DrmMetadata.h> +#include <drm/DrmInfo.h> +#include <drm/DrmInfoStatus.h> +#include <drm/DrmInfoRequest.h> +#include <drm/DrmSupportInfo.h> +#include <drm/DrmConvertedStatus.h> #include <utils/String8.h> #include "FwdLockConv.h" #include "FwdLockFile.h" diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/Android.bp new file mode 100644 index 0000000000..9f58e264fd --- /dev/null +++ b/drm/libdrmframework/plugins/forward-lock/internal-format/Android.bp @@ -0,0 +1,5 @@ +subdirs = [ + "common", + "converter", + "decoder", +] diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/Android.mk b/drm/libdrmframework/plugins/forward-lock/internal-format/Android.mk deleted file mode 100644 index 9ee79618c2..0000000000 --- a/drm/libdrmframework/plugins/forward-lock/internal-format/Android.mk +++ /dev/null @@ -1,16 +0,0 @@ -# -# Copyright (C) 2010 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 $(call all-subdir-makefiles) diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp new file mode 100644 index 0000000000..698f278058 --- /dev/null +++ b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp @@ -0,0 +1,25 @@ +// +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_library_static { + name: "libfwdlock-common", + + srcs: ["FwdLockGlue.c"], + + shared_libs: ["libcrypto"], + + export_include_dirs: ["."], +} diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.mk b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.mk deleted file mode 100644 index 3b4c8b4c36..0000000000 --- a/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.mk +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (C) 2010 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. -# -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - FwdLockGlue.c - -LOCAL_SHARED_LIBRARIES := libcrypto - -LOCAL_MODULE := libfwdlock-common - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_STATIC_LIBRARY) diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp new file mode 100644 index 0000000000..33f2fe0702 --- /dev/null +++ b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp @@ -0,0 +1,26 @@ +// +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_library_static { + name: "libfwdlock-converter", + + srcs: ["FwdLockConv.c"], + + shared_libs: ["libcrypto"], + static_libs: ["libfwdlock-common"], + + export_include_dirs: ["."], +} diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.mk b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.mk deleted file mode 100644 index 2f51f0c90c..0000000000 --- a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.mk +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (C) 2010 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. -# -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - FwdLockConv.c - -LOCAL_C_INCLUDES := \ - frameworks/av/drm/libdrmframework/plugins/forward-lock/internal-format/common - -LOCAL_SHARED_LIBRARIES := libcrypto - -LOCAL_MODULE := libfwdlock-converter - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_STATIC_LIBRARY) diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp new file mode 100644 index 0000000000..b6d7a06e84 --- /dev/null +++ b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp @@ -0,0 +1,26 @@ +// +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_library_static { + name: "libfwdlock-decoder", + + srcs: ["FwdLockFile.c"], + + shared_libs: ["libcrypto"], + static_libs: ["libfwdlock-common"], + + export_include_dirs: ["."], +} diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.mk b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.mk deleted file mode 100644 index 3399ae5641..0000000000 --- a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.mk +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (C) 2010 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. -# -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - FwdLockFile.c - -LOCAL_C_INCLUDES := \ - frameworks/av/drm/libdrmframework/plugins/forward-lock/internal-format/common - -LOCAL_SHARED_LIBRARIES := libcrypto - -LOCAL_MODULE := libfwdlock-decoder - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_STATIC_LIBRARY) diff --git a/drm/libdrmframework/plugins/passthru/Android.bp b/drm/libdrmframework/plugins/passthru/Android.bp new file mode 100644 index 0000000000..1dcf89cc07 --- /dev/null +++ b/drm/libdrmframework/plugins/passthru/Android.bp @@ -0,0 +1,36 @@ +// +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_library_shared { + name: "libdrmpassthruplugin", + + srcs: ["src/DrmPassthruPlugIn.cpp"], + + static_libs: ["libdrmframeworkcommon"], + + shared_libs: [ + "libutils", + "liblog", + "libdl", + ], + + local_include_dirs: ["include"], + + cflags: [ + // Set the following flag to enable the decryption passthru flow + //"-DENABLE_PASSTHRU_DECRYPTION", + ], +} diff --git a/drm/libdrmframework/plugins/passthru/Android.mk b/drm/libdrmframework/plugins/passthru/Android.mk deleted file mode 100644 index cb3a2e2374..0000000000 --- a/drm/libdrmframework/plugins/passthru/Android.mk +++ /dev/null @@ -1,43 +0,0 @@ -# -# Copyright (C) 2010 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. -# -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - src/DrmPassthruPlugIn.cpp - -LOCAL_MODULE := libdrmpassthruplugin - -LOCAL_STATIC_LIBRARIES := libdrmframeworkcommon - -LOCAL_SHARED_LIBRARIES := \ - libutils \ - liblog \ - libdl - - -LOCAL_C_INCLUDES += \ - $(TOP)/frameworks/av/drm/libdrmframework/include \ - $(TOP)/frameworks/av/drm/libdrmframework/plugins/passthru/include \ - $(TOP)/frameworks/av/drm/libdrmframework/plugins/common/include \ - $(TOP)/frameworks/av/include - -# Set the following flag to enable the decryption passthru flow -#LOCAL_CFLAGS += -DENABLE_PASSTHRU_DECRYPTION - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) diff --git a/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp b/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp index 7f5b0ec0dd..d7f2d287c0 100644 --- a/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp +++ b/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp @@ -245,6 +245,8 @@ status_t DrmPassthruPlugIn::onOpenDecryptSession( decryptHandle->status = DRM_NO_ERROR; decryptHandle->decryptInfo = NULL; return DRM_NO_ERROR; +#else + (void)(decryptHandle); // unused #endif return DRM_ERROR_CANNOT_HANDLE; diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp new file mode 100644 index 0000000000..66f5fc24ce --- /dev/null +++ b/drm/libmediadrm/Android.bp @@ -0,0 +1,51 @@ +// +// libmediadrm +// + +cc_library_shared { + name: "libmediadrm", + + aidl: { + local_include_dirs: ["aidl"], + export_aidl_headers: true, + }, + + srcs: [ + "aidl/android/media/ICas.aidl", + "aidl/android/media/ICasListener.aidl", + "aidl/android/media/IDescrambler.aidl", + "aidl/android/media/IMediaCasService.aidl", + + "CasImpl.cpp", + "DescramblerImpl.cpp", + "DrmPluginPath.cpp", + "DrmSessionManager.cpp", + "ICrypto.cpp", + "IDrm.cpp", + "IDrmClient.cpp", + "IMediaDrmService.cpp", + "MediaCasDefs.cpp", + "SharedLibrary.cpp", + "DrmHal.cpp", + "CryptoHal.cpp", + ], + + shared_libs: [ + "libbinder", + "libcutils", + "libdl", + "liblog", + "libmediautils", + "libstagefright_foundation", + "libutils", + "android.hardware.drm@1.0", + "libhidlbase", + "libhidlmemory", + "libhidltransport", + ], + + cflags: [ + "-Werror", + "-Wall", + ], +} diff --git a/drm/libmediadrm/Android.mk b/drm/libmediadrm/Android.mk deleted file mode 100644 index 5b56501a7b..0000000000 --- a/drm/libmediadrm/Android.mk +++ /dev/null @@ -1,62 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -# -# libmediadrm -# - -include $(CLEAR_VARS) - -LOCAL_AIDL_INCLUDES := \ - frameworks/av/drm/libmediadrm/aidl - -LOCAL_SRC_FILES := \ - aidl/android/media/ICas.aidl \ - aidl/android/media/ICasListener.aidl \ - aidl/android/media/IDescrambler.aidl \ - aidl/android/media/IMediaCasService.aidl \ - -LOCAL_SRC_FILES += \ - CasImpl.cpp \ - DescramblerImpl.cpp \ - DrmPluginPath.cpp \ - DrmSessionManager.cpp \ - ICrypto.cpp \ - IDrm.cpp \ - IDrmClient.cpp \ - IMediaDrmService.cpp \ - MediaCasDefs.cpp \ - SharedLibrary.cpp -ifneq ($(DISABLE_TREBLE_DRM), true) -LOCAL_SRC_FILES += \ - DrmHal.cpp \ - CryptoHal.cpp -else -LOCAL_SRC_FILES += \ - Drm.cpp \ - Crypto.cpp -endif - -LOCAL_SHARED_LIBRARIES := \ - libbinder \ - libcutils \ - libdl \ - liblog \ - libmediautils \ - libstagefright_foundation \ - libutils -ifneq ($(DISABLE_TREBLE_DRM), true) -LOCAL_SHARED_LIBRARIES += \ - android.hidl.base@1.0 \ - android.hardware.drm@1.0 \ - libhidlbase \ - libhidlmemory \ - libhidltransport -endif - -LOCAL_CFLAGS += -Werror -Wno-error=deprecated-declarations -Wall - -LOCAL_MODULE:= libmediadrm - -include $(BUILD_SHARED_LIBRARY) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/drm/libmediadrm/Crypto.cpp b/drm/libmediadrm/Crypto.cpp deleted file mode 100644 index a5d7346619..0000000000 --- a/drm/libmediadrm/Crypto.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "Crypto" -#include <utils/Log.h> -#include <dirent.h> -#include <dlfcn.h> - -#include <binder/IMemory.h> -#include <media/Crypto.h> -#include <media/DrmPluginPath.h> -#include <media/hardware/CryptoAPI.h> -#include <media/stagefright/foundation/ADebug.h> -#include <media/stagefright/foundation/AString.h> -#include <media/stagefright/foundation/hexdump.h> -#include <media/stagefright/MediaErrors.h> - -namespace android { - -KeyedVector<Vector<uint8_t>, String8> Crypto::mUUIDToLibraryPathMap; -KeyedVector<String8, wp<SharedLibrary> > Crypto::mLibraryPathToOpenLibraryMap; -Mutex Crypto::mMapLock; - -static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) { - if (lhs.size() < rhs.size()) { - return true; - } else if (lhs.size() > rhs.size()) { - return false; - } - - return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0; -} - -Crypto::Crypto() - : mInitCheck(NO_INIT), - mFactory(NULL), - mPlugin(NULL) { -} - -Crypto::~Crypto() { - delete mPlugin; - mPlugin = NULL; - closeFactory(); -} - -void Crypto::closeFactory() { - delete mFactory; - mFactory = NULL; - mLibrary.clear(); -} - -status_t Crypto::initCheck() const { - return mInitCheck; -} - -/* - * Search the plugins directory for a plugin that supports the scheme - * specified by uuid - * - * If found: - * mLibrary holds a strong pointer to the dlopen'd library - * mFactory is set to the library's factory method - * mInitCheck is set to OK - * - * If not found: - * mLibrary is cleared and mFactory are set to NULL - * mInitCheck is set to an error (!OK) - */ -void Crypto::findFactoryForScheme(const uint8_t uuid[16]) { - - closeFactory(); - - // lock static maps - Mutex::Autolock autoLock(mMapLock); - - // first check cache - Vector<uint8_t> uuidVector; - uuidVector.appendArray(uuid, sizeof(uuid[0]) * 16); - ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector); - if (index >= 0) { - if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) { - mInitCheck = OK; - return; - } else { - ALOGE("Failed to load from cached library path!"); - mInitCheck = ERROR_UNSUPPORTED; - return; - } - } - - // no luck, have to search - String8 dirPath(getDrmPluginPath()); - String8 pluginPath; - - DIR* pDir = opendir(dirPath.string()); - if (pDir) { - struct dirent* pEntry; - while ((pEntry = readdir(pDir))) { - - pluginPath = dirPath + "/" + pEntry->d_name; - - if (pluginPath.getPathExtension() == ".so") { - - if (loadLibraryForScheme(pluginPath, uuid)) { - mUUIDToLibraryPathMap.add(uuidVector, pluginPath); - mInitCheck = OK; - closedir(pDir); - return; - } - } - } - - closedir(pDir); - } - - // try the legacy libdrmdecrypt.so - pluginPath = "libdrmdecrypt.so"; - if (loadLibraryForScheme(pluginPath, uuid)) { - mUUIDToLibraryPathMap.add(uuidVector, pluginPath); - mInitCheck = OK; - return; - } - - mInitCheck = ERROR_UNSUPPORTED; -} - -bool Crypto::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) { - - // get strong pointer to open shared library - ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path); - if (index >= 0) { - mLibrary = mLibraryPathToOpenLibraryMap[index].promote(); - } else { - index = mLibraryPathToOpenLibraryMap.add(path, NULL); - } - - if (!mLibrary.get()) { - mLibrary = new SharedLibrary(path); - if (!*mLibrary) { - ALOGE("loadLibraryForScheme failed:%s", mLibrary->lastError()); - return false; - } - - mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary); - } - - typedef CryptoFactory *(*CreateCryptoFactoryFunc)(); - - CreateCryptoFactoryFunc createCryptoFactory = - (CreateCryptoFactoryFunc)mLibrary->lookup("createCryptoFactory"); - - if (createCryptoFactory == NULL || - (mFactory = createCryptoFactory()) == NULL || - !mFactory->isCryptoSchemeSupported(uuid)) { - ALOGE("createCryptoFactory failed:%s", mLibrary->lastError()); - closeFactory(); - return false; - } - return true; -} - -bool Crypto::isCryptoSchemeSupported(const uint8_t uuid[16]) { - Mutex::Autolock autoLock(mLock); - - if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) { - return true; - } - - findFactoryForScheme(uuid); - return (mInitCheck == OK); -} - -status_t Crypto::createPlugin( - const uint8_t uuid[16], const void *data, size_t size) { - Mutex::Autolock autoLock(mLock); - - if (mPlugin != NULL) { - return -EINVAL; - } - - if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) { - findFactoryForScheme(uuid); - } - - if (mInitCheck != OK) { - return mInitCheck; - } - - return mFactory->createPlugin(uuid, data, size, &mPlugin); -} - -status_t Crypto::destroyPlugin() { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - delete mPlugin; - mPlugin = NULL; - - return OK; -} - -bool Crypto::requiresSecureDecoderComponent(const char *mime) const { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - return mPlugin->requiresSecureDecoderComponent(mime); -} - -ssize_t Crypto::decrypt(const uint8_t key[16], const uint8_t iv[16], - CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern, - const sp<IMemory> &source, size_t offset, - const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, - const ICrypto::DestinationBuffer &destination, AString *errorDetailMsg) { - - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - const void *srcPtr = static_cast<uint8_t *>(source->pointer()) + offset; - - void *destPtr; - bool secure = false; - if (destination.mType == kDestinationTypeNativeHandle) { - destPtr = static_cast<void *>(destination.mHandle); - secure = true; - } else { - destPtr = destination.mSharedMemory->pointer(); - } - - ssize_t result = mPlugin->decrypt(secure, key, iv, mode, pattern, srcPtr, subSamples, - numSubSamples, destPtr, errorDetailMsg); - - return result; -} - -void Crypto::notifyResolution(uint32_t width, uint32_t height) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck == OK && mPlugin != NULL) { - mPlugin->notifyResolution(width, height); - } -} - -status_t Crypto::setMediaDrmSession(const Vector<uint8_t> &sessionId) { - Mutex::Autolock autoLock(mLock); - - status_t result = NO_INIT; - if (mInitCheck == OK && mPlugin != NULL) { - result = mPlugin->setMediaDrmSession(sessionId); - } - return result; -} - -} // namespace android diff --git a/drm/libmediadrm/Drm.cpp b/drm/libmediadrm/Drm.cpp deleted file mode 100644 index 1004eb8b15..0000000000 --- a/drm/libmediadrm/Drm.cpp +++ /dev/null @@ -1,799 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "Drm" -#include <utils/Log.h> - -#include <dirent.h> -#include <dlfcn.h> - -#include <media/DrmPluginPath.h> -#include <media/DrmSessionClientInterface.h> -#include <media/DrmSessionManager.h> -#include <media/Drm.h> -#include <media/drm/DrmAPI.h> -#include <media/stagefright/foundation/ADebug.h> -#include <media/stagefright/foundation/AString.h> -#include <media/stagefright/foundation/hexdump.h> -#include <media/stagefright/MediaErrors.h> -#include <binder/IServiceManager.h> -#include <binder/IPCThreadState.h> - -namespace android { - -static inline int getCallingPid() { - return IPCThreadState::self()->getCallingPid(); -} - -static bool checkPermission(const char* permissionString) { - if (getpid() == IPCThreadState::self()->getCallingPid()) return true; - bool ok = checkCallingPermission(String16(permissionString)); - if (!ok) ALOGE("Request requires %s", permissionString); - return ok; -} - -KeyedVector<Vector<uint8_t>, String8> Drm::mUUIDToLibraryPathMap; -KeyedVector<String8, wp<SharedLibrary> > Drm::mLibraryPathToOpenLibraryMap; -Mutex Drm::mMapLock; -Mutex Drm::mLock; - -static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) { - if (lhs.size() < rhs.size()) { - return true; - } else if (lhs.size() > rhs.size()) { - return false; - } - - return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0; -} - -struct DrmSessionClient : public DrmSessionClientInterface { - explicit DrmSessionClient(Drm* drm) : mDrm(drm) {} - - virtual bool reclaimSession(const Vector<uint8_t>& sessionId) { - sp<Drm> drm = mDrm.promote(); - if (drm == NULL) { - return true; - } - status_t err = drm->closeSession(sessionId); - if (err != OK) { - return false; - } - drm->sendEvent(DrmPlugin::kDrmPluginEventSessionReclaimed, 0, &sessionId, NULL); - return true; - } - -protected: - virtual ~DrmSessionClient() {} - -private: - wp<Drm> mDrm; - - DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient); -}; - -Drm::Drm() - : mInitCheck(NO_INIT), - mDrmSessionClient(new DrmSessionClient(this)), - mListener(NULL), - mFactory(NULL), - mPlugin(NULL) { -} - -Drm::~Drm() { - DrmSessionManager::Instance()->removeDrm(mDrmSessionClient); - delete mPlugin; - mPlugin = NULL; - closeFactory(); -} - -void Drm::closeFactory() { - delete mFactory; - mFactory = NULL; - mLibrary.clear(); -} - -status_t Drm::initCheck() const { - return mInitCheck; -} - -status_t Drm::setListener(const sp<IDrmClient>& listener) -{ - Mutex::Autolock lock(mEventLock); - if (mListener != NULL){ - IInterface::asBinder(mListener)->unlinkToDeath(this); - } - if (listener != NULL) { - IInterface::asBinder(listener)->linkToDeath(this); - } - mListener = listener; - return NO_ERROR; -} - -void Drm::sendEvent(DrmPlugin::EventType eventType, int extra, - Vector<uint8_t> const *sessionId, - Vector<uint8_t> const *data) -{ - mEventLock.lock(); - sp<IDrmClient> listener = mListener; - mEventLock.unlock(); - - if (listener != NULL) { - Parcel obj; - writeByteArray(obj, sessionId); - writeByteArray(obj, data); - - Mutex::Autolock lock(mNotifyLock); - listener->notify(eventType, extra, &obj); - } -} - -void Drm::sendExpirationUpdate(Vector<uint8_t> const *sessionId, - int64_t expiryTimeInMS) -{ - mEventLock.lock(); - sp<IDrmClient> listener = mListener; - mEventLock.unlock(); - - if (listener != NULL) { - Parcel obj; - writeByteArray(obj, sessionId); - obj.writeInt64(expiryTimeInMS); - - Mutex::Autolock lock(mNotifyLock); - listener->notify(DrmPlugin::kDrmPluginEventExpirationUpdate, 0, &obj); - } -} - -void Drm::sendKeysChange(Vector<uint8_t> const *sessionId, - Vector<DrmPlugin::KeyStatus> const *keyStatusList, - bool hasNewUsableKey) -{ - mEventLock.lock(); - sp<IDrmClient> listener = mListener; - mEventLock.unlock(); - - if (listener != NULL) { - Parcel obj; - writeByteArray(obj, sessionId); - - size_t nkeys = keyStatusList->size(); - obj.writeInt32(keyStatusList->size()); - for (size_t i = 0; i < nkeys; ++i) { - const DrmPlugin::KeyStatus *keyStatus = &keyStatusList->itemAt(i); - writeByteArray(obj, &keyStatus->mKeyId); - obj.writeInt32(keyStatus->mType); - } - obj.writeInt32(hasNewUsableKey); - - Mutex::Autolock lock(mNotifyLock); - listener->notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &obj); - } -} - -/* - * Search the plugins directory for a plugin that supports the scheme - * specified by uuid - * - * If found: - * mLibrary holds a strong pointer to the dlopen'd library - * mFactory is set to the library's factory method - * mInitCheck is set to OK - * - * If not found: - * mLibrary is cleared and mFactory are set to NULL - * mInitCheck is set to an error (!OK) - */ -void Drm::findFactoryForScheme(const uint8_t uuid[16]) { - - closeFactory(); - - // lock static maps - Mutex::Autolock autoLock(mMapLock); - - // first check cache - Vector<uint8_t> uuidVector; - uuidVector.appendArray(uuid, sizeof(uuid[0]) * 16); - ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector); - if (index >= 0) { - if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) { - mInitCheck = OK; - return; - } else { - ALOGE("Failed to load from cached library path!"); - mInitCheck = ERROR_UNSUPPORTED; - return; - } - } - - // no luck, have to search - String8 dirPath(getDrmPluginPath()); - DIR* pDir = opendir(dirPath.string()); - - if (pDir == NULL) { - mInitCheck = ERROR_UNSUPPORTED; - ALOGE("Failed to open plugin directory %s", dirPath.string()); - return; - } - - - struct dirent* pEntry; - while ((pEntry = readdir(pDir))) { - - String8 pluginPath = dirPath + "/" + pEntry->d_name; - - if (pluginPath.getPathExtension() == ".so") { - - if (loadLibraryForScheme(pluginPath, uuid)) { - mUUIDToLibraryPathMap.add(uuidVector, pluginPath); - mInitCheck = OK; - closedir(pDir); - return; - } - } - } - - closedir(pDir); - - ALOGE("Failed to find drm plugin"); - mInitCheck = ERROR_UNSUPPORTED; -} - -bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) { - - // get strong pointer to open shared library - ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path); - if (index >= 0) { - mLibrary = mLibraryPathToOpenLibraryMap[index].promote(); - } else { - index = mLibraryPathToOpenLibraryMap.add(path, NULL); - } - - if (!mLibrary.get()) { - mLibrary = new SharedLibrary(path); - if (!*mLibrary) { - return false; - } - - mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary); - } - - typedef DrmFactory *(*CreateDrmFactoryFunc)(); - - CreateDrmFactoryFunc createDrmFactory = - (CreateDrmFactoryFunc)mLibrary->lookup("createDrmFactory"); - - if (createDrmFactory == NULL || - (mFactory = createDrmFactory()) == NULL || - !mFactory->isCryptoSchemeSupported(uuid)) { - closeFactory(); - return false; - } - return true; -} - -bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) { - - Mutex::Autolock autoLock(mLock); - - if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) { - findFactoryForScheme(uuid); - if (mInitCheck != OK) { - return false; - } - } - - if (mimeType != "") { - return mFactory->isContentTypeSupported(mimeType); - } - - return true; -} - -status_t Drm::createPlugin(const uint8_t uuid[16], - const String8& /* appPackageName */) { - Mutex::Autolock autoLock(mLock); - - if (mPlugin != NULL) { - return -EINVAL; - } - - if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) { - findFactoryForScheme(uuid); - } - - if (mInitCheck != OK) { - return mInitCheck; - } - - status_t result = mFactory->createDrmPlugin(uuid, &mPlugin); - if (mPlugin) { - mPlugin->setListener(this); - } else { - ALOGE("Failed to create plugin"); - return UNEXPECTED_NULL; - } - return result; -} - -status_t Drm::destroyPlugin() { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - setListener(NULL); - delete mPlugin; - mPlugin = NULL; - - return OK; -} - -status_t Drm::openSession(Vector<uint8_t> &sessionId) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - status_t err = mPlugin->openSession(sessionId); - if (err == ERROR_DRM_RESOURCE_BUSY) { - bool retry = false; - mLock.unlock(); - // reclaimSession may call back to closeSession, since mLock is shared between Drm - // instances, we should unlock here to avoid deadlock. - retry = DrmSessionManager::Instance()->reclaimSession(getCallingPid()); - mLock.lock(); - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - if (retry) { - err = mPlugin->openSession(sessionId); - } - } - if (err == OK) { - DrmSessionManager::Instance()->addSession(getCallingPid(), mDrmSessionClient, sessionId); - } - return err; -} - -status_t Drm::closeSession(Vector<uint8_t> const &sessionId) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - status_t err = mPlugin->closeSession(sessionId); - if (err == OK) { - DrmSessionManager::Instance()->removeSession(sessionId); - } - return err; -} - -status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId, - Vector<uint8_t> const &initData, - String8 const &mimeType, DrmPlugin::KeyType keyType, - KeyedVector<String8, String8> const &optionalParameters, - Vector<uint8_t> &request, String8 &defaultUrl, - DrmPlugin::KeyRequestType *keyRequestType) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - DrmSessionManager::Instance()->useSession(sessionId); - - return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType, - optionalParameters, request, defaultUrl, - keyRequestType); -} - -status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId, - Vector<uint8_t> const &response, - Vector<uint8_t> &keySetId) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - DrmSessionManager::Instance()->useSession(sessionId); - - return mPlugin->provideKeyResponse(sessionId, response, keySetId); -} - -status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - return mPlugin->removeKeys(keySetId); -} - -status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId, - Vector<uint8_t> const &keySetId) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - DrmSessionManager::Instance()->useSession(sessionId); - - return mPlugin->restoreKeys(sessionId, keySetId); -} - -status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId, - KeyedVector<String8, String8> &infoMap) const { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - DrmSessionManager::Instance()->useSession(sessionId); - - return mPlugin->queryKeyStatus(sessionId, infoMap); -} - -status_t Drm::getProvisionRequest(String8 const &certType, String8 const &certAuthority, - Vector<uint8_t> &request, String8 &defaultUrl) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - return mPlugin->getProvisionRequest(certType, certAuthority, - request, defaultUrl); -} - -status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response, - Vector<uint8_t> &certificate, - Vector<uint8_t> &wrappedKey) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - return mPlugin->provideProvisionResponse(response, certificate, wrappedKey); -} - -status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - return mPlugin->getSecureStops(secureStops); -} - -status_t Drm::getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - return mPlugin->getSecureStop(ssid, secureStop); -} - -status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - return mPlugin->releaseSecureStops(ssRelease); -} - -status_t Drm::releaseAllSecureStops() { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - return mPlugin->releaseAllSecureStops(); -} - -status_t Drm::getPropertyString(String8 const &name, String8 &value ) const { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - return mPlugin->getPropertyString(name, value); -} - -status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - return mPlugin->getPropertyByteArray(name, value); -} - -status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - return mPlugin->setPropertyString(name, value); -} - -status_t Drm::setPropertyByteArray(String8 const &name, - Vector<uint8_t> const &value ) const { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - return mPlugin->setPropertyByteArray(name, value); -} - - -status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId, - String8 const &algorithm) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - DrmSessionManager::Instance()->useSession(sessionId); - - return mPlugin->setCipherAlgorithm(sessionId, algorithm); -} - -status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId, - String8 const &algorithm) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - DrmSessionManager::Instance()->useSession(sessionId); - - return mPlugin->setMacAlgorithm(sessionId, algorithm); -} - -status_t Drm::encrypt(Vector<uint8_t> const &sessionId, - Vector<uint8_t> const &keyId, - Vector<uint8_t> const &input, - Vector<uint8_t> const &iv, - Vector<uint8_t> &output) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - DrmSessionManager::Instance()->useSession(sessionId); - - return mPlugin->encrypt(sessionId, keyId, input, iv, output); -} - -status_t Drm::decrypt(Vector<uint8_t> const &sessionId, - Vector<uint8_t> const &keyId, - Vector<uint8_t> const &input, - Vector<uint8_t> const &iv, - Vector<uint8_t> &output) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - DrmSessionManager::Instance()->useSession(sessionId); - - return mPlugin->decrypt(sessionId, keyId, input, iv, output); -} - -status_t Drm::sign(Vector<uint8_t> const &sessionId, - Vector<uint8_t> const &keyId, - Vector<uint8_t> const &message, - Vector<uint8_t> &signature) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - DrmSessionManager::Instance()->useSession(sessionId); - - return mPlugin->sign(sessionId, keyId, message, signature); -} - -status_t Drm::verify(Vector<uint8_t> const &sessionId, - Vector<uint8_t> const &keyId, - Vector<uint8_t> const &message, - Vector<uint8_t> const &signature, - bool &match) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - DrmSessionManager::Instance()->useSession(sessionId); - - return mPlugin->verify(sessionId, keyId, message, signature, match); -} - -status_t Drm::signRSA(Vector<uint8_t> const &sessionId, - String8 const &algorithm, - Vector<uint8_t> const &message, - Vector<uint8_t> const &wrappedKey, - Vector<uint8_t> &signature) { - Mutex::Autolock autoLock(mLock); - - if (mInitCheck != OK) { - return mInitCheck; - } - - if (mPlugin == NULL) { - return -EINVAL; - } - - if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) { - return -EPERM; - } - - DrmSessionManager::Instance()->useSession(sessionId); - - return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature); -} - -void Drm::binderDied(const wp<IBinder> &the_late_who __unused) -{ - mEventLock.lock(); - mListener.clear(); - mEventLock.unlock(); - - Mutex::Autolock autoLock(mLock); - delete mPlugin; - mPlugin = NULL; - closeFactory(); -} - -void Drm::writeByteArray(Parcel &obj, Vector<uint8_t> const *array) -{ - if (array && array->size()) { - obj.writeInt32(array->size()); - obj.write(array->array(), array->size()); - } else { - obj.writeInt32(0); - } -} - -} // namespace android diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp index 386546f2ab..074489a93f 100644 --- a/drm/libmediadrm/DrmHal.cpp +++ b/drm/libmediadrm/DrmHal.cpp @@ -245,6 +245,11 @@ sp<IDrmPlugin> DrmHal::makeDrmPlugin(const sp<IDrmFactory>& factory, plugin = hPlugin; } ); + + if (!hResult.isOk()) { + ALOGE("createPlugin remote call failed"); + } + return plugin; } @@ -396,8 +401,11 @@ status_t DrmHal::createPlugin(const uint8_t uuid[16], if (mPlugin == NULL) { mInitCheck = ERROR_UNSUPPORTED; } else { - mInitCheck = OK; - mPlugin->setListener(this); + if (!mPlugin->setListener(this).isOk()) { + mInitCheck = DEAD_OBJECT; + } else { + mInitCheck = OK; + } } return mInitCheck; @@ -411,12 +419,14 @@ status_t DrmHal::destroyPlugin() { } setListener(NULL); + mInitCheck = NO_INIT; + if (mPlugin != NULL) { - mPlugin->setListener(NULL); + if (!mPlugin->setListener(NULL).isOk()) { + mInitCheck = DEAD_OBJECT; + } } mPlugin.clear(); - mInitCheck = NO_INIT; - return OK; } @@ -472,11 +482,14 @@ status_t DrmHal::closeSession(Vector<uint8_t> const &sessionId) { return mInitCheck; } - Status status = mPlugin->closeSession(toHidlVec(sessionId)); - if (status == Status::OK) { - DrmSessionManager::Instance()->removeSession(sessionId); + Return<Status> status = mPlugin->closeSession(toHidlVec(sessionId)); + if (status.isOk()) { + if (status == Status::OK) { + DrmSessionManager::Instance()->removeSession(sessionId); + } + return toStatusT(status); } - return toStatusT(status); + return DEAD_OBJECT; } status_t DrmHal::getKeyRequest(Vector<uint8_t> const &sessionId, @@ -962,12 +975,16 @@ status_t DrmHal::signRSA(Vector<uint8_t> const &sessionId, void DrmHal::binderDied(const wp<IBinder> &the_late_who __unused) { Mutex::Autolock autoLock(mLock); + setListener(NULL); + mInitCheck = NO_INIT; + if (mPlugin != NULL) { - mPlugin->setListener(NULL); + if (!mPlugin->setListener(NULL).isOk()) { + mInitCheck = DEAD_OBJECT; + } } mPlugin.clear(); - mInitCheck = NO_INIT; } void DrmHal::writeByteArray(Parcel &obj, hidl_vec<uint8_t> const &vec) diff --git a/drm/mediadrm/Android.bp b/drm/mediadrm/Android.bp new file mode 100644 index 0000000000..b9f07f1ecd --- /dev/null +++ b/drm/mediadrm/Android.bp @@ -0,0 +1 @@ +subdirs = ["plugins/*"] diff --git a/drm/mediadrm/plugins/clearkey/Android.bp b/drm/mediadrm/plugins/clearkey/Android.bp new file mode 100644 index 0000000000..2973fcff54 --- /dev/null +++ b/drm/mediadrm/plugins/clearkey/Android.bp @@ -0,0 +1,59 @@ +// +// Copyright (C) 2014 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_library_shared { + name: "libdrmclearkeyplugin", + + srcs: [ + "AesCtrDecryptor.cpp", + "ClearKeyUUID.cpp", + "CreatePluginFactories.cpp", + "CryptoFactory.cpp", + "CryptoPlugin.cpp", + "DrmFactory.cpp", + "DrmPlugin.cpp", + "InitDataParser.cpp", + "JsonWebKey.cpp", + "Session.cpp", + "SessionLibrary.cpp", + "Utils.cpp", + ], + + vendor: true, + relative_install_path: "mediadrm", + + shared_libs: [ + "libcrypto", + "liblog", + "libstagefright_foundation", + "libutils", + ], + + static_libs: ["libjsmn"], + + include_dirs: [ + "frameworks/native/include", + "frameworks/av/include", + ], + + export_include_dirs: ["."], + export_static_lib_headers: ["libjsmn"], +} + +//######################################################################## +// Build unit tests + +subdirs = ["tests"] diff --git a/drm/mediadrm/plugins/clearkey/Android.mk b/drm/mediadrm/plugins/clearkey/Android.mk deleted file mode 100644 index 2efdcf59f7..0000000000 --- a/drm/mediadrm/plugins/clearkey/Android.mk +++ /dev/null @@ -1,60 +0,0 @@ -# -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - AesCtrDecryptor.cpp \ - ClearKeyUUID.cpp \ - CreatePluginFactories.cpp \ - CryptoFactory.cpp \ - CryptoPlugin.cpp \ - DrmFactory.cpp \ - DrmPlugin.cpp \ - InitDataParser.cpp \ - JsonWebKey.cpp \ - Session.cpp \ - SessionLibrary.cpp \ - Utils.cpp \ - -LOCAL_C_INCLUDES := \ - external/jsmn \ - frameworks/av/drm/mediadrm/plugins/clearkey \ - frameworks/av/include \ - frameworks/native/include \ - -LOCAL_MODULE := libdrmclearkeyplugin - -LOCAL_PROPRIETARY_MODULE := true -LOCAL_MODULE_RELATIVE_PATH := mediadrm - -LOCAL_SHARED_LIBRARIES := \ - libcrypto \ - liblog \ - libstagefright_foundation \ - libutils \ - -LOCAL_STATIC_LIBRARIES := \ - libjsmn \ - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) - -######################################################################### -# Build unit tests - -include $(LOCAL_PATH)/tests/Android.mk diff --git a/drm/mediadrm/plugins/clearkey/tests/Android.bp b/drm/mediadrm/plugins/clearkey/tests/Android.bp new file mode 100644 index 0000000000..ac57d653c6 --- /dev/null +++ b/drm/mediadrm/plugins/clearkey/tests/Android.bp @@ -0,0 +1,37 @@ +// +// Copyright (C) 2014 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ---------------------------------------------------------------- +// Builds ClearKey Drm Tests +// + +cc_test { + name: "ClearKeyDrmUnitTest", + vendor: true, + + srcs: [ + "AesCtrDecryptorUnittest.cpp", + "InitDataParserUnittest.cpp", + "JsonWebKeyUnittest.cpp", + ], + + shared_libs: [ + "libcrypto", + "libdrmclearkeyplugin", + "liblog", + "libstagefright_foundation", + "libutils", + ], +} diff --git a/drm/mediadrm/plugins/clearkey/tests/Android.mk b/drm/mediadrm/plugins/clearkey/tests/Android.mk deleted file mode 100644 index 392f218816..0000000000 --- a/drm/mediadrm/plugins/clearkey/tests/Android.mk +++ /dev/null @@ -1,43 +0,0 @@ -# -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ---------------------------------------------------------------- -# Builds ClearKey Drm Tests -# -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE := ClearKeyDrmUnitTest -LOCAL_MODULE_TAGS := tests - -LOCAL_SRC_FILES := \ - AesCtrDecryptorUnittest.cpp \ - InitDataParserUnittest.cpp \ - JsonWebKeyUnittest.cpp \ - -LOCAL_C_INCLUDES := \ - external/jsmn \ - frameworks/av/drm/mediadrm/plugins/clearkey \ - frameworks/av/include \ - frameworks/native/include \ - -LOCAL_SHARED_LIBRARIES := \ - libcrypto \ - libdrmclearkeyplugin \ - liblog \ - libstagefright_foundation \ - libutils \ - -include $(BUILD_NATIVE_TEST) diff --git a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp index e2751084d1..84ed242246 100644 --- a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp +++ b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp @@ -56,7 +56,7 @@ class InitDataParserTest : public ::testing::Test { request.size()); EXPECT_EQ(0, requestString.find(kRequestPrefix)); EXPECT_EQ(requestString.size() - kRequestSuffix.size(), - requestString.find(kRequestSuffix)); + (size_t)requestString.find(kRequestSuffix)); for (size_t i = 0; i < expectedKeys.size(); ++i) { AString encodedIdAString; android::encodeBase64(expectedKeys[i], kKeyIdSize, @@ -71,7 +71,7 @@ class InitDataParserTest : public ::testing::Test { const String8& mimeType) { Vector<uint8_t> request; ASSERT_NE(android::OK, attemptParse(initData, mimeType, &request)); - EXPECT_EQ(0, request.size()); + EXPECT_EQ(0u, request.size()); } }; diff --git a/drm/mediadrm/plugins/mock/Android.bp b/drm/mediadrm/plugins/mock/Android.bp new file mode 100644 index 0000000000..7f448195c5 --- /dev/null +++ b/drm/mediadrm/plugins/mock/Android.bp @@ -0,0 +1,34 @@ +// +// Copyright (C) 2013 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_library_shared { + name: "libmockdrmcryptoplugin", + + srcs: ["MockDrmCryptoPlugin.cpp"], + + vendor: true, + relative_install_path: "mediadrm", + + shared_libs: [ + "libutils", + "liblog", + ], + + cflags: [ + // Set the following flag to enable the decryption passthru flow + //"-DENABLE_PASSTHRU_DECRYPTION", + ], +} diff --git a/drm/mediadrm/plugins/mock/Android.mk b/drm/mediadrm/plugins/mock/Android.mk deleted file mode 100644 index 26c245b817..0000000000 --- a/drm/mediadrm/plugins/mock/Android.mk +++ /dev/null @@ -1,39 +0,0 @@ -# -# Copyright (C) 2013 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. -# -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - MockDrmCryptoPlugin.cpp - -LOCAL_MODULE := libmockdrmcryptoplugin - -LOCAL_PROPRIETARY_MODULE := true -LOCAL_MODULE_RELATIVE_PATH := mediadrm - -LOCAL_SHARED_LIBRARIES := \ - libutils liblog - -LOCAL_C_INCLUDES += \ - $(TOP)/frameworks/av/include \ - $(TOP)/frameworks/native/include/media - -# Set the following flag to enable the decryption passthru flow -#LOCAL_CFLAGS += -DENABLE_PASSTHRU_DECRYPTION - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp index c82b9d9147..3b4145f402 100644 --- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp +++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp @@ -19,7 +19,7 @@ #include <utils/Log.h> -#include "drm/DrmAPI.h" +#include "media/drm/DrmAPI.h" #include "MockDrmCryptoPlugin.h" #include "media/stagefright/MediaErrors.h" @@ -730,7 +730,7 @@ namespace android { ssize_t MockDrmPlugin::findSession(Vector<uint8_t> const &sessionId) const { - ALOGD("findSession: nsessions=%u, size=%u", mSessions.size(), sessionId.size()); + ALOGD("findSession: nsessions=%zu, size=%zu", mSessions.size(), sessionId.size()); for (size_t i = 0; i < mSessions.size(); ++i) { if (memcmp(mSessions[i].array(), sessionId.array(), sessionId.size()) == 0) { return i; @@ -741,7 +741,7 @@ namespace android { ssize_t MockDrmPlugin::findKeySet(Vector<uint8_t> const &keySetId) const { - ALOGD("findKeySet: nkeySets=%u, size=%u", mKeySets.size(), keySetId.size()); + ALOGD("findKeySet: nkeySets=%zu, size=%zu", mKeySets.size(), keySetId.size()); for (size_t i = 0; i < mKeySets.size(); ++i) { if (memcmp(mKeySets[i].array(), keySetId.array(), keySetId.size()) == 0) { return i; @@ -792,8 +792,9 @@ namespace android { } ssize_t - MockCryptoPlugin::decrypt(bool secure, const uint8_t key[16], const uint8_t iv[16], - Mode mode, const Pattern &pattern, const void *srcPtr, + MockCryptoPlugin::decrypt(bool secure, const uint8_t key[DECRYPT_KEY_SIZE], + const uint8_t iv[DECRYPT_KEY_SIZE], Mode mode, + const Pattern &pattern, const void *srcPtr, const SubSample *subSamples, size_t numSubSamples, void *dstPtr, AString * /* errorDetailMsg */) { @@ -801,8 +802,8 @@ namespace android { "pattern:{encryptBlocks=%d, skipBlocks=%d} src=%p, " "subSamples=%s, dst=%p)", (int)secure, - arrayToString(key, sizeof(key)).string(), - arrayToString(iv, sizeof(iv)).string(), + arrayToString(key, DECRYPT_KEY_SIZE).string(), + arrayToString(iv, DECRYPT_KEY_SIZE).string(), (int)mode, pattern.mEncryptBlocks, pattern.mSkipBlocks, srcPtr, subSamplesToString(subSamples, numSubSamples).string(), dstPtr); diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h index 9f8db17932..4178c0350d 100644 --- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h +++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h @@ -16,8 +16,8 @@ #include <utils/Mutex.h> -#include "drm/DrmAPI.h" -#include "hardware/CryptoAPI.h" +#include "media/drm/DrmAPI.h" +#include "media/hardware/CryptoAPI.h" extern "C" { android::DrmFactory *createDrmFactory(); @@ -158,9 +158,12 @@ namespace android { bool requiresSecureDecoderComponent(const char *mime) const; + static constexpr size_t DECRYPT_KEY_SIZE = 16; + ssize_t decrypt(bool secure, - const uint8_t key[16], const uint8_t iv[16], - Mode mode, const Pattern &pattern, const void *srcPtr, + const uint8_t key[DECRYPT_KEY_SIZE], + const uint8_t iv[DECRYPT_KEY_SIZE], Mode mode, + const Pattern &pattern, const void *srcPtr, const SubSample *subSamples, size_t numSubSamples, void *dstPtr, AString *errorDetailMsg); private: diff --git a/include/media/AudioClient.h b/include/media/AudioClient.h new file mode 120000 index 0000000000..a0530e4440 --- /dev/null +++ b/include/media/AudioClient.h @@ -0,0 +1 @@ +../../media/libaudioclient/include/media/AudioClient.h
\ No newline at end of file diff --git a/include/media/CasImpl.h b/include/media/CasImpl.h index 0dd506c58b..726f1ce146 100644 --- a/include/media/CasImpl.h +++ b/include/media/CasImpl.h @@ -27,7 +27,7 @@ class ICasListener; using namespace media; using namespace MediaCas; using binder::Status; -class CasPlugin; +struct CasPlugin; class SharedLibrary; class CasImpl : public BnCas { diff --git a/include/media/DescramblerImpl.h b/include/media/DescramblerImpl.h index c1c79b3e64..9f212ac8dc 100644 --- a/include/media/DescramblerImpl.h +++ b/include/media/DescramblerImpl.h @@ -24,7 +24,7 @@ namespace android { using namespace media; using namespace MediaDescrambler; using binder::Status; -class DescramblerPlugin; +struct DescramblerPlugin; class SharedLibrary; class DescramblerImpl : public BnDescrambler { diff --git a/include/media/Interpolator.h b/include/media/Interpolator.h index 45a0585834..703cf77117 100644 --- a/include/media/Interpolator.h +++ b/include/media/Interpolator.h @@ -278,7 +278,7 @@ public: if (res != NO_ERROR) { return res; } - if (i > 0 && !(x > lastx) /* handle nan */ + if ((i > 0 && !(x > lastx)) /* handle nan */ || y != y /* handle nan */) { // This is a std::map object which imposes sorted order // automatically on emplace. diff --git a/include/media/MmapStreamInterface.h b/include/media/MmapStreamInterface.h index 7dbc19e0ec..d689e25e1c 100644 --- a/include/media/MmapStreamInterface.h +++ b/include/media/MmapStreamInterface.h @@ -18,6 +18,7 @@ #define ANDROID_AUDIO_MMAP_STREAM_INTERFACE_H #include <system/audio.h> +#include <media/AudioClient.h> #include <utils/Errors.h> #include <utils/RefBase.h> @@ -37,12 +38,6 @@ class MmapStreamInterface : public virtual RefBase DIRECTION_INPUT, /**< open a capture mmap stream */ } stream_direction_t; - class Client { - public: - uid_t clientUid; - pid_t clientPid; - String16 packageName; - }; /** * Open a playback or capture stream in MMAP mode at the audio HAL. * @@ -53,13 +48,14 @@ class MmapStreamInterface : public virtual RefBase * \param[in,out] config audio parameters (sampling rate, format ...) for the stream. * Requested parameters as input, * Actual parameters as output - * \param[in] client a Client struct describing the first client using this stream. + * \param[in] client a AudioClient struct describing the first client using this stream. * \param[in,out] deviceId audio device the stream should preferably be routed to/from * Requested as input, * Actual as output * \param[in] callback the MmapStreamCallback interface used by AudioFlinger to notify * condition changes affecting the stream operation * \param[out] interface the MmapStreamInterface interface controlling the created stream + * \param[out] same unique handle as the one used for the first client stream started. * \return OK if the stream was successfully created. * NO_INIT if AudioFlinger is not properly initialized * BAD_VALUE if the stream cannot be opened because of invalid arguments @@ -68,10 +64,11 @@ class MmapStreamInterface : public virtual RefBase static status_t openMmapStream(stream_direction_t direction, const audio_attributes_t *attr, audio_config_base_t *config, - const Client& client, + const AudioClient& client, audio_port_handle_t *deviceId, const sp<MmapStreamCallback>& callback, - sp<MmapStreamInterface>& interface); + sp<MmapStreamInterface>& interface, + audio_port_handle_t *handle); /** * Retrieve information on the mmap buffer used for audio samples transfer. @@ -105,13 +102,13 @@ class MmapStreamInterface : public virtual RefBase * Start a stream operating in mmap mode. * createMmapBuffer() must be called before calling start() * - * \param[in] client a Client struct describing the client starting on this stream. + * \param[in] client a AudioClient struct describing the client starting on this stream. * \param[out] handle unique handle for this instance. Used with stop(). * \return OK in case of success. * NO_INIT in case of initialization error * INVALID_OPERATION if called out of sequence */ - virtual status_t start(const Client& client, audio_port_handle_t *handle) = 0; + virtual status_t start(const AudioClient& client, audio_port_handle_t *handle) = 0; /** * Stop a stream operating in mmap mode. diff --git a/include/media/VolumeShaper.h b/include/media/VolumeShaper.h index e4c0b5bcbf..302641ff14 100644 --- a/include/media/VolumeShaper.h +++ b/include/media/VolumeShaper.h @@ -32,11 +32,8 @@ #define LOG_TAG "VolumeShaper" // turn on VolumeShaper logging -#if 0 -#define VS_LOG ALOGD -#else -#define VS_LOG(...) -#endif +#define VS_LOGGING 0 +#define VS_LOG(...) ALOGD_IF(VS_LOGGING, __VA_ARGS__) namespace android { @@ -128,18 +125,18 @@ public: : Interpolator<S, T>() , RefBase() , mType(TYPE_SCALE) + , mId(-1) , mOptionFlags(OPTION_FLAG_NONE) - , mDurationMs(1000.) - , mId(-1) { + , mDurationMs(1000.) { } explicit Configuration(const Configuration &configuration) : Interpolator<S, T>(*static_cast<const Interpolator<S, T> *>(&configuration)) , RefBase() , mType(configuration.mType) + , mId(configuration.mId) , mOptionFlags(configuration.mOptionFlags) - , mDurationMs(configuration.mDurationMs) - , mId(configuration.mId) { + , mDurationMs(configuration.mDurationMs) { } Type getType() const { diff --git a/include/media/omx/1.0/WGraphicBufferSource.h b/include/media/omx/1.0/WGraphicBufferSource.h index 397e57640f..bf3be9ac52 100644 --- a/include/media/omx/1.0/WGraphicBufferSource.h +++ b/include/media/omx/1.0/WGraphicBufferSource.h @@ -74,6 +74,7 @@ struct LWGraphicBufferSource : public BnGraphicBufferSource { BnStatus setTimeLapseConfig(double fps, double captureFps) override; BnStatus setStartTimeUs(int64_t startTimeUs) override; BnStatus setStopTimeUs(int64_t stopTimeUs) override; + BnStatus getStopTimeOffsetUs(int64_t *stopTimeOffsetUs) override; BnStatus setColorAspects(int32_t aspects) override; BnStatus setTimeOffsetUs(int64_t timeOffsetsUs) override; BnStatus signalEndOfInputStream() override; diff --git a/include/media/stagefright b/include/media/stagefright index ae324a8bd0..5393f68995 120000 --- a/include/media/stagefright +++ b/include/media/stagefright @@ -1 +1 @@ -../../media/libstagefright/include
\ No newline at end of file +../../media/libstagefright/include/media/stagefright/
\ No newline at end of file diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h index 7becf57dec..9da5ef3b54 100644 --- a/include/private/media/AudioTrackShared.h +++ b/include/private/media/AudioTrackShared.h @@ -172,7 +172,7 @@ private: // client write-only, server read-only uint16_t mSendLevel; // Fixed point U4.12 so 0x1000 means 1.0 - uint16_t mPad2; // unused + uint16_t mPad2 __attribute__((__unused__)); // unused // server write-only, client read ExtendedTimestampQueue::Shared mExtendedTimestampQueue; diff --git a/include/private/media/VideoFrame.h b/include/private/media/VideoFrame.h index 5193d000cf..51050cde1f 100644 --- a/include/private/media/VideoFrame.h +++ b/include/private/media/VideoFrame.h @@ -30,8 +30,8 @@ namespace android { class VideoFrame { public: - VideoFrame(): mWidth(0), mHeight(0), mDisplayWidth(0), mDisplayHeight(0), mSize(0), mData(0), - mRotationAngle(0) {} + VideoFrame(): mWidth(0), mHeight(0), mDisplayWidth(0), mDisplayHeight(0), mSize(0), + mRotationAngle(0), mData(0) {} VideoFrame(const VideoFrame& copy) { mWidth = copy.mWidth; diff --git a/include/radio/Radio.h b/include/radio/Radio.h index a4dfdd1813..fb4dd2f54c 100644 --- a/include/radio/Radio.h +++ b/include/radio/Radio.h @@ -79,7 +79,6 @@ private: Mutex mLock; sp<IRadio> mIRadio; - const radio_handle_t mHandle; sp<RadioCallback> mCallback; }; diff --git a/include/soundtrigger/SoundTrigger.h b/include/soundtrigger/SoundTrigger.h index 9a05cac1da..7a29e31ca3 100644 --- a/include/soundtrigger/SoundTrigger.h +++ b/include/soundtrigger/SoundTrigger.h @@ -72,7 +72,6 @@ private: Mutex mLock; sp<ISoundTrigger> mISoundTrigger; - const sound_trigger_module_handle_t mModule; sp<SoundTriggerCallback> mCallback; }; diff --git a/media/img_utils/Android.bp b/media/img_utils/Android.bp new file mode 100644 index 0000000000..64530e198a --- /dev/null +++ b/media/img_utils/Android.bp @@ -0,0 +1,60 @@ +// Copyright 2014 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_library_shared { + name: "libimg_utils", + + srcs: [ + "src/EndianUtils.cpp", + "src/FileInput.cpp", + "src/FileOutput.cpp", + "src/SortedEntryVector.cpp", + "src/Input.cpp", + "src/Output.cpp", + "src/Orderable.cpp", + "src/TiffIfd.cpp", + "src/TiffWritable.cpp", + "src/TiffWriter.cpp", + "src/TiffEntry.cpp", + "src/TiffEntryImpl.cpp", + "src/ByteArrayOutput.cpp", + "src/DngUtils.cpp", + "src/StripSource.cpp", + ], + + shared_libs: [ + "liblog", + "libutils", + "libcutils", + ], + + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + "-fvisibility=hidden", + ], + + product_variables: { + debuggable: { + // Enable assert() in eng builds + cflags: [ + "-UNDEBUG", + "-DLOG_NDEBUG=1", + ], + }, + }, + + export_include_dirs: ["include"], +} diff --git a/media/img_utils/Android.mk b/media/img_utils/Android.mk deleted file mode 100644 index 1cd00bd24f..0000000000 --- a/media/img_utils/Android.mk +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -include $(call all-subdir-makefiles) diff --git a/media/img_utils/src/Android.mk b/media/img_utils/src/Android.mk deleted file mode 100644 index 4c6fe70a05..0000000000 --- a/media/img_utils/src/Android.mk +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - EndianUtils.cpp \ - FileInput.cpp \ - FileOutput.cpp \ - SortedEntryVector.cpp \ - Input.cpp \ - Output.cpp \ - Orderable.cpp \ - TiffIfd.cpp \ - TiffWritable.cpp \ - TiffWriter.cpp \ - TiffEntry.cpp \ - TiffEntryImpl.cpp \ - ByteArrayOutput.cpp \ - DngUtils.cpp \ - StripSource.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - liblog \ - libutils \ - libcutils \ - -LOCAL_C_INCLUDES += \ - $(LOCAL_PATH)/../include \ - system/media/camera/include - -LOCAL_CFLAGS += \ - -Wall \ - -Wextra \ - -Werror \ - -fvisibility=hidden - -ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),) - # Enable assert() in eng builds - LOCAL_CFLAGS += -UNDEBUG -DLOG_NDEBUG=1 -endif - -LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include - -LOCAL_MODULE := libimg_utils - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/libaaudio/examples/input_monitor/Android.mk b/media/libaaudio/examples/input_monitor/Android.mk index b56328bc77..5053e7d643 100644 --- a/media/libaaudio/examples/input_monitor/Android.mk +++ b/media/libaaudio/examples/input_monitor/Android.mk @@ -1,6 +1 @@ -# include $(call all-subdir-makefiles) - -# Just include static/ for now. -LOCAL_PATH := $(call my-dir) -#include $(LOCAL_PATH)/jni/Android.mk -include $(LOCAL_PATH)/static/Android.mk +include $(call all-subdir-makefiles) diff --git a/media/libaaudio/examples/input_monitor/jni/Android.mk b/media/libaaudio/examples/input_monitor/jni/Android.mk index 3e24f9f3a6..9b1ce2c7af 100644 --- a/media/libaaudio/examples/input_monitor/jni/Android.mk +++ b/media/libaaudio/examples/input_monitor/jni/Android.mk @@ -11,7 +11,7 @@ LOCAL_C_INCLUDES := \ # NDK recommends using this kind of relative path instead of an absolute path. LOCAL_SRC_FILES:= ../src/input_monitor.cpp LOCAL_SHARED_LIBRARIES := libaaudio -LOCAL_MODULE := input_monitor_ndk +LOCAL_MODULE := input_monitor include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) @@ -23,11 +23,11 @@ LOCAL_C_INCLUDES := \ LOCAL_SRC_FILES:= ../src/input_monitor_callback.cpp LOCAL_SHARED_LIBRARIES := libaaudio -LOCAL_MODULE := input_monitor_callback_ndk +LOCAL_MODULE := input_monitor_callback include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) LOCAL_MODULE := libaaudio_prebuilt LOCAL_SRC_FILES := libaaudio.so LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include -include $(PREBUILT_SHARED_LIBRARY)
\ No newline at end of file +include $(PREBUILT_SHARED_LIBRARY) diff --git a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp index 715c5f86f4..910b10ccef 100644 --- a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp +++ b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp @@ -22,33 +22,22 @@ #include <stdlib.h> #include <math.h> #include <aaudio/AAudio.h> +#include <aaudio/AAudioTesting.h> #include "AAudioExampleUtils.h" #include "AAudioSimpleRecorder.h" -#define SAMPLE_RATE 48000 - -#define NUM_SECONDS 10 - +// TODO support FLOAT +#define REQUIRED_FORMAT AAUDIO_FORMAT_PCM_I16 #define MIN_FRAMES_TO_READ 48 /* arbitrary, 1 msec at 48000 Hz */ -int main(int argc, char **argv) +int main(int argc, const char **argv) { - (void)argc; // unused - + AAudioArgsParser argParser; aaudio_result_t result; AAudioSimpleRecorder recorder; int actualSamplesPerFrame; int actualSampleRate; - const aaudio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM_I16; - aaudio_format_t actualDataFormat; - - const int requestedInputChannelCount = 1; // Can affect whether we get a FAST path. - - //aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE; - const aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY; - //aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING; - const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_SHARED; - //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE; + aaudio_format_t actualDataFormat; aaudio_sharing_mode_t actualSharingMode; AAudioStream *aaudioStream = nullptr; @@ -61,6 +50,7 @@ int main(int argc, char **argv) int16_t *data = nullptr; float peakLevel = 0.0; int loopCounter = 0; + int32_t deviceId; // Make printf print immediately so that debug info is not stuck // in a buffer if we hang or crash. @@ -68,27 +58,27 @@ int main(int argc, char **argv) printf("%s - Monitor input level using AAudio\n", argv[0]); - recorder.setPerformanceMode(requestedPerformanceMode); - recorder.setSharingMode(requestedSharingMode); + argParser.setFormat(REQUIRED_FORMAT); + if (argParser.parseArgs(argc, argv)) { + return EXIT_FAILURE; + } - result = recorder.open(requestedInputChannelCount, 48000, requestedDataFormat, - nullptr, nullptr, nullptr); + result = recorder.open(argParser); if (result != AAUDIO_OK) { fprintf(stderr, "ERROR - recorder.open() returned %d\n", result); goto finish; } aaudioStream = recorder.getStream(); + argParser.compareWithStream(aaudioStream); + + deviceId = AAudioStream_getDeviceId(aaudioStream); + printf("deviceId = %d\n", deviceId); actualSamplesPerFrame = AAudioStream_getSamplesPerFrame(aaudioStream); printf("SamplesPerFrame = %d\n", actualSamplesPerFrame); actualSampleRate = AAudioStream_getSampleRate(aaudioStream); printf("SamplesPerFrame = %d\n", actualSampleRate); - actualSharingMode = AAudioStream_getSharingMode(aaudioStream); - printf("SharingMode: requested = %s, actual = %s\n", - getSharingModeText(requestedSharingMode), - getSharingModeText(actualSharingMode)); - // This is the number of frames that are written in one chunk by a DMA controller // or a DSP. framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream); @@ -103,14 +93,12 @@ int main(int argc, char **argv) printf("DataFormat: framesPerRead = %d\n",framesPerRead); actualDataFormat = AAudioStream_getFormat(aaudioStream); - printf("DataFormat: requested = %d, actual = %d\n", requestedDataFormat, actualDataFormat); + printf("DataFormat: requested = %d, actual = %d\n", + REQUIRED_FORMAT, actualDataFormat); // TODO handle other data formats - assert(actualDataFormat == AAUDIO_FORMAT_PCM_I16); + assert(actualDataFormat == REQUIRED_FORMAT); - printf("PerformanceMode: requested = %d, actual = %d\n", requestedPerformanceMode, - AAudioStream_getPerformanceMode(aaudioStream)); - - // Allocate a buffer for the audio data. + // Allocate a buffer for the PCM_16 audio data. data = new(std::nothrow) int16_t[framesPerRead * actualSamplesPerFrame]; if (data == nullptr) { fprintf(stderr, "ERROR - could not allocate data buffer\n"); @@ -129,11 +117,11 @@ int main(int argc, char **argv) printf("after start, state = %s\n", AAudio_convertStreamStateToText(state)); // Record for a while. - framesToRecord = actualSampleRate * NUM_SECONDS; + framesToRecord = actualSampleRate * argParser.getDurationSeconds(); framesLeft = framesToRecord; while (framesLeft > 0) { // Read audio data from the stream. - const int64_t timeoutNanos = 100 * NANOS_PER_MILLISECOND; + const int64_t timeoutNanos = 1000 * NANOS_PER_MILLISECOND; int minFrames = (framesToRecord < framesPerRead) ? framesToRecord : framesPerRead; int actual = AAudioStream_read(aaudioStream, data, minFrames, timeoutNanos); if (actual < 0) { @@ -169,6 +157,8 @@ int main(int argc, char **argv) goto finish; } + argParser.compareWithStream(aaudioStream); + finish: recorder.close(); delete[] data; diff --git a/media/libaaudio/examples/input_monitor/static/Android.mk b/media/libaaudio/examples/input_monitor/static/Android.mk deleted file mode 100644 index 61fc3b803f..0000000000 --- a/media/libaaudio/examples/input_monitor/static/Android.mk +++ /dev/null @@ -1,37 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE_TAGS := examples -LOCAL_C_INCLUDES := \ - $(call include-path-for, audio-utils) \ - frameworks/av/media/libaaudio/include \ - frameworks/av/media/libaaudio/examples/utils - -# TODO reorganize folders to avoid using ../ -LOCAL_SRC_FILES:= ../src/input_monitor.cpp - -LOCAL_SHARED_LIBRARIES := libaudioutils libmedia \ - libbinder libcutils libutils \ - libaudioclient liblog libtinyalsa libaudiomanager -LOCAL_STATIC_LIBRARIES := libaaudio - -LOCAL_MODULE := input_monitor -include $(BUILD_EXECUTABLE) - - -include $(CLEAR_VARS) -LOCAL_MODULE_TAGS := tests -LOCAL_C_INCLUDES := \ - $(call include-path-for, audio-utils) \ - frameworks/av/media/libaaudio/include \ - frameworks/av/media/libaaudio/examples/utils - -LOCAL_SRC_FILES:= ../src/input_monitor_callback.cpp - -LOCAL_SHARED_LIBRARIES := libaudioutils libmedia \ - libbinder libcutils libutils \ - libaudioclient liblog libaudiomanager -LOCAL_STATIC_LIBRARIES := libaaudio - -LOCAL_MODULE := input_monitor_callback -include $(BUILD_EXECUTABLE) diff --git a/media/libaaudio/examples/input_monitor/static/README.md b/media/libaaudio/examples/input_monitor/static/README.md deleted file mode 100644 index 6e26d7b3c5..0000000000 --- a/media/libaaudio/examples/input_monitor/static/README.md +++ /dev/null @@ -1,2 +0,0 @@ -Makefile for building simple command line examples. -They link with AAudio as a static library. diff --git a/media/libaaudio/examples/loopback/jni/Android.mk b/media/libaaudio/examples/loopback/jni/Android.mk index dc933e3a7c..d78f286b93 100644 --- a/media/libaaudio/examples/loopback/jni/Android.mk +++ b/media/libaaudio/examples/loopback/jni/Android.mk @@ -4,7 +4,8 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_C_INCLUDES := \ $(call include-path-for, audio-utils) \ - frameworks/av/media/libaaudio/include + frameworks/av/media/libaaudio/include \ + frameworks/av/media/libaaudio/examples/utils # NDK recommends using this kind of relative path instead of an absolute path. LOCAL_SRC_FILES:= ../src/loopback.cpp diff --git a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h new file mode 100644 index 0000000000..21cf341cec --- /dev/null +++ b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h @@ -0,0 +1,794 @@ +/* + * Copyright (C) 2017 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. + */ + +/** + * Tools for measuring latency and for detecting glitches. + * These classes are pure math and can be used with any audio system. + */ + +#ifndef AAUDIO_EXAMPLES_LOOPBACK_ANALYSER_H +#define AAUDIO_EXAMPLES_LOOPBACK_ANALYSER_H + +#include <algorithm> +#include <assert.h> +#include <cctype> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +// Tag for machine readable results as property = value pairs +#define LOOPBACK_RESULT_TAG "RESULT: " +#define LOOPBACK_SAMPLE_RATE 48000 + +#define MILLIS_PER_SECOND 1000 + +#define MAX_ZEROTH_PARTIAL_BINS 40 + +static const float s_Impulse[] = { + 0.0f, 0.0f, 0.0f, 0.0f, 0.2f, // silence on each side of the impulse + 0.5f, 0.9999f, 0.0f, -0.9999, -0.5f, // bipolar + -0.2f, 0.0f, 0.0f, 0.0f, 0.0f +}; + +class PseudoRandom { +public: + PseudoRandom() {} + PseudoRandom(int64_t seed) + : mSeed(seed) + {} + + /** + * Returns the next random double from -1.0 to 1.0 + * + * @return value from -1.0 to 1.0 + */ + double nextRandomDouble() { + return nextRandomInteger() * (0.5 / (((int32_t)1) << 30)); + } + + /** Calculate random 32 bit number using linear-congruential method. */ + int32_t nextRandomInteger() { + // Use values for 64-bit sequence from MMIX by Donald Knuth. + mSeed = (mSeed * (int64_t)6364136223846793005) + (int64_t)1442695040888963407; + return (int32_t) (mSeed >> 32); // The higher bits have a longer sequence. + } + +private: + int64_t mSeed = 99887766; +}; + +static double calculateCorrelation(const float *a, + const float *b, + int windowSize) +{ + double correlation = 0.0; + double sumProducts = 0.0; + double sumSquares = 0.0; + + // Correlate a against b. + for (int i = 0; i < windowSize; i++) { + float s1 = a[i]; + float s2 = b[i]; + // Use a normalized cross-correlation. + sumProducts += s1 * s2; + sumSquares += ((s1 * s1) + (s2 * s2)); + } + + if (sumSquares >= 0.00000001) { + correlation = (float) (2.0 * sumProducts / sumSquares); + } + return correlation; +} + +static int calculateCorrelations(const float *haystack, int haystackSize, + const float *needle, int needleSize, + float *results, int resultSize) +{ + int maxCorrelations = haystackSize - needleSize; + int numCorrelations = std::min(maxCorrelations, resultSize); + + for (int ic = 0; ic < numCorrelations; ic++) { + double correlation = calculateCorrelation(&haystack[ic], needle, needleSize); + results[ic] = correlation; + } + + return numCorrelations; +} + +/*==========================================================================================*/ +/** + * Scan until we get a correlation of a single scan that goes over the tolerance level, + * peaks then drops back down. + */ +static double findFirstMatch(const float *haystack, int haystackSize, + const float *needle, int needleSize, double threshold ) +{ + int ic; + // How many correlations can we calculate? + int numCorrelations = haystackSize - needleSize; + double maxCorrelation = 0.0; + int peakIndex = -1; + double location = -1.0; + const double backThresholdScaler = 0.5; + + for (ic = 0; ic < numCorrelations; ic++) { + double correlation = calculateCorrelation(&haystack[ic], needle, needleSize); + + if( (correlation > maxCorrelation) ) { + maxCorrelation = correlation; + peakIndex = ic; + } + + //printf("PaQa_FindFirstMatch: ic = %4d, correlation = %8f, maxSum = %8f\n", + // ic, correlation, maxSum ); + // Are we past what we were looking for? + if((maxCorrelation > threshold) && (correlation < backThresholdScaler * maxCorrelation)) { + location = peakIndex; + break; + } + } + + return location; +} + +typedef struct LatencyReport_s { + double latencyInFrames; + double confidence; +} LatencyReport; + +// Apply a technique similar to Harmonic Product Spectrum Analysis to find echo fundamental. +// Using first echo instead of the original impulse for a better match. +static int measureLatencyFromEchos(const float *haystack, int haystackSize, + const float *needle, int needleSize, + LatencyReport *report) { + const double threshold = 0.1; + + // Find first peak + int first = (int) (findFirstMatch(haystack, + haystackSize, + needle, + needleSize, + threshold) + 0.5); + + // Use first echo as the needle for the other echos because + // it will be more similar. + needle = &haystack[first]; + int again = (int) (findFirstMatch(haystack, + haystackSize, + needle, + needleSize, + threshold) + 0.5); + + printf("first = %d, again at %d\n", first, again); + first = again; + + // Allocate results array + int remaining = haystackSize - first; + const int maxReasonableLatencyFrames = 48000 * 2; // arbitrary but generous value + int numCorrelations = std::min(remaining, maxReasonableLatencyFrames); + float *correlations = new float[numCorrelations]; + float *harmonicSums = new float[numCorrelations](); // set to zero + + // Generate correlation for every position. + numCorrelations = calculateCorrelations(&haystack[first], remaining, + needle, needleSize, + correlations, numCorrelations); + + // Add higher harmonics mapped onto lower harmonics. + // This reinforces the "fundamental" echo. + const int numEchoes = 10; + for (int partial = 1; partial < numEchoes; partial++) { + for (int i = 0; i < numCorrelations; i++) { + harmonicSums[i / partial] += correlations[i] / partial; + } + } + + // Find highest peak in correlation array. + float maxCorrelation = 0.0; + float sumOfPeaks = 0.0; + int peakIndex = 0; + const int skip = MAX_ZEROTH_PARTIAL_BINS; // skip low bins + for (int i = skip; i < numCorrelations; i++) { + if (harmonicSums[i] > maxCorrelation) { + maxCorrelation = harmonicSums[i]; + sumOfPeaks += maxCorrelation; + peakIndex = i; + printf("maxCorrelation = %f at %d\n", maxCorrelation, peakIndex); + } + } + + report->latencyInFrames = peakIndex; + if (sumOfPeaks < 0.0001) { + report->confidence = 0.0; + } else { + report->confidence = maxCorrelation / sumOfPeaks; + } + + delete[] correlations; + delete[] harmonicSums; + return 0; +} + +class AudioRecording +{ +public: + AudioRecording() { + } + ~AudioRecording() { + delete[] mData; + } + + void allocate(int maxFrames) { + delete[] mData; + mData = new float[maxFrames]; + mMaxFrames = maxFrames; + } + + // Write SHORT data from the first channel. + int write(int16_t *inputData, int inputChannelCount, int numFrames) { + // stop at end of buffer + if ((mFrameCounter + numFrames) > mMaxFrames) { + numFrames = mMaxFrames - mFrameCounter; + } + for (int i = 0; i < numFrames; i++) { + mData[mFrameCounter++] = inputData[i * inputChannelCount] * (1.0f / 32768); + } + return numFrames; + } + + // Write FLOAT data from the first channel. + int write(float *inputData, int inputChannelCount, int numFrames) { + // stop at end of buffer + if ((mFrameCounter + numFrames) > mMaxFrames) { + numFrames = mMaxFrames - mFrameCounter; + } + for (int i = 0; i < numFrames; i++) { + mData[mFrameCounter++] = inputData[i * inputChannelCount]; + } + return numFrames; + } + + int size() { + return mFrameCounter; + } + + float *getData() { + return mData; + } + + int save(const char *fileName, bool writeShorts = true) { + int written = 0; + const int chunkSize = 64; + FILE *fid = fopen(fileName, "wb"); + if (fid == NULL) { + return -errno; + } + + if (writeShorts) { + int16_t buffer[chunkSize]; + int32_t framesLeft = mFrameCounter; + int32_t cursor = 0; + while (framesLeft) { + int32_t framesToWrite = framesLeft < chunkSize ? framesLeft : chunkSize; + for (int i = 0; i < framesToWrite; i++) { + buffer[i] = (int16_t) (mData[cursor++] * 32767); + } + written += fwrite(buffer, sizeof(int16_t), framesToWrite, fid); + framesLeft -= framesToWrite; + } + } else { + written = (int) fwrite(mData, sizeof(float), mFrameCounter, fid); + } + fclose(fid); + return written; + } + +private: + float *mData = nullptr; + int32_t mFrameCounter = 0; + int32_t mMaxFrames = 0; +}; + +// ==================================================================================== +class LoopbackProcessor { +public: + virtual ~LoopbackProcessor() = default; + + + virtual void reset() {} + + virtual void process(float *inputData, int inputChannelCount, + float *outputData, int outputChannelCount, + int numFrames) = 0; + + + virtual void report() = 0; + + virtual void printStatus() {}; + + virtual bool isDone() { + return false; + } + + void setSampleRate(int32_t sampleRate) { + mSampleRate = sampleRate; + } + + int32_t getSampleRate() { + return mSampleRate; + } + + // Measure peak amplitude of buffer. + static float measurePeakAmplitude(float *inputData, int inputChannelCount, int numFrames) { + float peak = 0.0f; + for (int i = 0; i < numFrames; i++) { + float pos = fabs(*inputData); + if (pos > peak) { + peak = pos; + } + inputData += inputChannelCount; + } + return peak; + } + + +private: + int32_t mSampleRate = LOOPBACK_SAMPLE_RATE; +}; + +class PeakDetector { +public: + float process(float input) { + float output = mPrevious * mDecay; + if (input > output) { + output = input; + } + mPrevious = output; + return output; + } + +private: + float mDecay = 0.99f; + float mPrevious = 0.0f; +}; + + +static void printAudioScope(float sample) { + const int maxStars = 80 + ; // arbitrary, fits on one line + char c = '*'; + if (sample < -1.0) { + sample = -1.0; + c = '$'; + } else if (sample > 1.0) { + sample = 1.0; + c = '$'; + } + int numSpaces = (int) (((sample + 1.0) * 0.5) * maxStars); + for (int i = 0; i < numSpaces; i++) { + putchar(' '); + } + printf("%c\n", c); +} + +// ==================================================================================== +/** + * Measure latency given a loopback stream data. + * Uses a state machine to cycle through various stages including: + * + */ +class EchoAnalyzer : public LoopbackProcessor { +public: + + EchoAnalyzer() : LoopbackProcessor() { + audioRecorder.allocate(2 * LOOPBACK_SAMPLE_RATE); + } + + void reset() override { + mDownCounter = 200; + mLoopCounter = 0; + mMeasuredLoopGain = 0.0f; + mEchoGain = 1.0f; + mState = STATE_INITIAL_SILENCE; + } + + virtual bool isDone() { + return mState == STATE_DONE; + } + + void setGain(float gain) { + mEchoGain = gain; + } + + float getGain() { + return mEchoGain; + } + + void report() override { + + printf("EchoAnalyzer ---------------\n"); + printf(LOOPBACK_RESULT_TAG "measured.gain = %f\n", mMeasuredLoopGain); + printf(LOOPBACK_RESULT_TAG "echo.gain = %f\n", mEchoGain); + printf(LOOPBACK_RESULT_TAG "frame.count = %d\n", mFrameCounter); + printf(LOOPBACK_RESULT_TAG "test.state = %d\n", mState); + if (mMeasuredLoopGain >= 0.9999) { + printf(" ERROR - clipping, turn down volume slightly\n"); + } else { + const float *needle = s_Impulse; + int needleSize = (int) (sizeof(s_Impulse) / sizeof(float)); + float *haystack = audioRecorder.getData(); + int haystackSize = audioRecorder.size(); + int result = measureLatencyFromEchos(haystack, haystackSize, + needle, needleSize, + &latencyReport); + if (latencyReport.confidence < 0.01) { + printf(" ERROR - confidence too low = %f\n", latencyReport.confidence); + } else { + double latencyMillis = 1000.0 * latencyReport.latencyInFrames / getSampleRate(); + printf(LOOPBACK_RESULT_TAG "latency.frames = %8.2f\n", latencyReport.latencyInFrames); + printf(LOOPBACK_RESULT_TAG "latency.msec = %8.2f\n", latencyMillis); + printf(LOOPBACK_RESULT_TAG "latency.confidence = %8.6f\n", latencyReport.confidence); + } + } + + { +#define ECHO_FILENAME "/data/oboe_echo.raw" + int written = audioRecorder.save(ECHO_FILENAME); + printf("Echo wrote %d mono samples to %s on Android device\n", written, ECHO_FILENAME); + } + } + + void printStatus() override { + printf("state = %d, echo gain = %f ", mState, mEchoGain); + } + + static void sendImpulse(float *outputData, int outputChannelCount) { + for (float sample : s_Impulse) { + *outputData = sample; + outputData += outputChannelCount; + } + } + + void process(float *inputData, int inputChannelCount, + float *outputData, int outputChannelCount, + int numFrames) override { + int channelsValid = std::min(inputChannelCount, outputChannelCount); + float peak = 0.0f; + int numWritten; + int numSamples; + + echo_state_t nextState = mState; + + switch (mState) { + case STATE_INITIAL_SILENCE: + // Output silence at the beginning. + numSamples = numFrames * outputChannelCount; + for (int i = 0; i < numSamples; i++) { + outputData[i] = 0; + } + if (mDownCounter-- <= 0) { + nextState = STATE_MEASURING_GAIN; + //printf("%5d: switch to STATE_MEASURING_GAIN\n", mLoopCounter); + mDownCounter = 8; + } + break; + + case STATE_MEASURING_GAIN: + sendImpulse(outputData, outputChannelCount); + peak = measurePeakAmplitude(inputData, inputChannelCount, numFrames); + // If we get several in a row then go to next state. + if (peak > mPulseThreshold) { + if (mDownCounter-- <= 0) { + nextState = STATE_WAITING_FOR_SILENCE; + //printf("%5d: switch to STATE_WAITING_FOR_SILENCE, measured peak = %f\n", + // mLoopCounter, peak); + mDownCounter = 8; + mMeasuredLoopGain = peak; // assumes original pulse amplitude is one + // Calculate gain that will give us a nice decaying echo. + mEchoGain = mDesiredEchoGain / mMeasuredLoopGain; + } + } else { + mDownCounter = 8; + } + break; + + case STATE_WAITING_FOR_SILENCE: + // Output silence. + numSamples = numFrames * outputChannelCount; + for (int i = 0; i < numSamples; i++) { + outputData[i] = 0; + } + peak = measurePeakAmplitude(inputData, inputChannelCount, numFrames); + // If we get several in a row then go to next state. + if (peak < mSilenceThreshold) { + if (mDownCounter-- <= 0) { + nextState = STATE_SENDING_PULSE; + //printf("%5d: switch to STATE_SENDING_PULSE\n", mLoopCounter); + mDownCounter = 8; + } + } else { + mDownCounter = 8; + } + break; + + case STATE_SENDING_PULSE: + audioRecorder.write(inputData, inputChannelCount, numFrames); + sendImpulse(outputData, outputChannelCount); + nextState = STATE_GATHERING_ECHOS; + //printf("%5d: switch to STATE_GATHERING_ECHOS\n", mLoopCounter); + break; + + case STATE_GATHERING_ECHOS: + numWritten = audioRecorder.write(inputData, inputChannelCount, numFrames); + peak = measurePeakAmplitude(inputData, inputChannelCount, numFrames); + if (peak > mMeasuredLoopGain) { + mMeasuredLoopGain = peak; // AGC might be raising gain so adjust it on the fly. + // Recalculate gain that will give us a nice decaying echo. + mEchoGain = mDesiredEchoGain / mMeasuredLoopGain; + } + // Echo input to output. + for (int i = 0; i < numFrames; i++) { + int ic; + for (ic = 0; ic < channelsValid; ic++) { + outputData[ic] = inputData[ic] * mEchoGain; + } + for (; ic < outputChannelCount; ic++) { + outputData[ic] = 0; + } + inputData += inputChannelCount; + outputData += outputChannelCount; + } + if (numWritten < numFrames) { + nextState = STATE_DONE; + //printf("%5d: switch to STATE_DONE\n", mLoopCounter); + } + break; + + case STATE_DONE: + default: + break; + } + + mState = nextState; + mLoopCounter++; + } + +private: + + enum echo_state_t { + STATE_INITIAL_SILENCE, + STATE_MEASURING_GAIN, + STATE_WAITING_FOR_SILENCE, + STATE_SENDING_PULSE, + STATE_GATHERING_ECHOS, + STATE_DONE + }; + + int mDownCounter = 500; + int mLoopCounter = 0; + int mLoopStart = 1000; + float mPulseThreshold = 0.02f; + float mSilenceThreshold = 0.002f; + float mMeasuredLoopGain = 0.0f; + float mDesiredEchoGain = 0.95f; + float mEchoGain = 1.0f; + echo_state_t mState = STATE_INITIAL_SILENCE; + int32_t mFrameCounter = 0; + + AudioRecording audioRecorder; + LatencyReport latencyReport; + PeakDetector mPeakDetector; +}; + + +// ==================================================================================== +/** + * Output a steady sinewave and analyze the return signal. + * + * Use a cosine transform to measure the predicted magnitude and relative phase of the + * looped back sine wave. Then generate a predicted signal and compare with the actual signal. + */ +class SineAnalyzer : public LoopbackProcessor { +public: + + void report() override { + printf("SineAnalyzer ------------------\n"); + printf(LOOPBACK_RESULT_TAG "peak.amplitude = %7.5f\n", mPeakAmplitude); + printf(LOOPBACK_RESULT_TAG "sine.magnitude = %7.5f\n", mMagnitude); + printf(LOOPBACK_RESULT_TAG "phase.offset = %7.5f\n", mPhaseOffset); + printf(LOOPBACK_RESULT_TAG "ref.phase = %7.5f\n", mPhase); + printf(LOOPBACK_RESULT_TAG "frames.accumulated = %6d\n", mFramesAccumulated); + printf(LOOPBACK_RESULT_TAG "sine.period = %6d\n", mPeriod); + printf(LOOPBACK_RESULT_TAG "test.state = %6d\n", mState); + printf(LOOPBACK_RESULT_TAG "frame.count = %6d\n", mFrameCounter); + // Did we ever get a lock? + bool gotLock = (mState == STATE_LOCKED) || (mGlitchCount > 0); + if (!gotLock) { + printf("ERROR - failed to lock on reference sine tone\n"); + } else { + // Only print if meaningful. + printf(LOOPBACK_RESULT_TAG "glitch.count = %6d\n", mGlitchCount); + } + } + + void printStatus() override { + printf(" state = %d, glitches = %d,", mState, mGlitchCount); + } + + double calculateMagnitude(double *phasePtr = NULL) { + if (mFramesAccumulated == 0) { + return 0.0; + } + double sinMean = mSinAccumulator / mFramesAccumulated; + double cosMean = mCosAccumulator / mFramesAccumulated; + double magnitude = 2.0 * sqrt( (sinMean * sinMean) + (cosMean * cosMean )); + if( phasePtr != NULL ) + { + double phase = M_PI_2 - atan2( sinMean, cosMean ); + *phasePtr = phase; + } + return magnitude; + } + + /** + * @param inputData contains microphone data with sine signal feedback + * @param outputData contains the reference sine wave + */ + void process(float *inputData, int inputChannelCount, + float *outputData, int outputChannelCount, + int numFrames) override { + float sample; + float peak = measurePeakAmplitude(inputData, inputChannelCount, numFrames); + if (peak > mPeakAmplitude) { + mPeakAmplitude = peak; + } + + for (int i = 0; i < numFrames; i++) { + float sample = inputData[i * inputChannelCount]; + + float sinOut = sinf(mPhase); + + switch (mState) { + case STATE_IMMUNE: + case STATE_WAITING_FOR_SIGNAL: + break; + case STATE_WAITING_FOR_LOCK: + mSinAccumulator += sample * sinOut; + mCosAccumulator += sample * cosf(mPhase); + mFramesAccumulated++; + // Must be a multiple of the period or the calculation will not be accurate. + if (mFramesAccumulated == mPeriod * 4) { + mPhaseOffset = 0.0; + mMagnitude = calculateMagnitude(&mPhaseOffset); + if (mMagnitude > mThreshold) { + if (fabs(mPreviousPhaseOffset - mPhaseOffset) < 0.001) { + mState = STATE_LOCKED; + //printf("%5d: switch to STATE_LOCKED\n", mFrameCounter); + } + mPreviousPhaseOffset = mPhaseOffset; + } + resetAccumulator(); + } + break; + + case STATE_LOCKED: { + // Predict next sine value + float predicted = sinf(mPhase + mPhaseOffset) * mMagnitude; + // printf(" predicted = %f, actual = %f\n", predicted, sample); + + float diff = predicted - sample; + if (fabs(diff) > mTolerance) { + mGlitchCount++; + //printf("%5d: Got a glitch # %d, predicted = %f, actual = %f\n", + // mFrameCounter, mGlitchCount, predicted, sample); + mState = STATE_IMMUNE; + //printf("%5d: switch to STATE_IMMUNE\n", mFrameCounter); + mDownCounter = mPeriod; // Set duration of IMMUNE state. + } + } break; + } + + // Output sine wave so we can measure it. + outputData[i * outputChannelCount] = (sinOut * mOutputAmplitude) + + (mWhiteNoise.nextRandomDouble() * mNoiseAmplitude); + // printf("%5d: sin(%f) = %f, %f\n", i, mPhase, sinOut, mPhaseIncrement); + + // advance and wrap phase + mPhase += mPhaseIncrement; + if (mPhase > M_PI) { + mPhase -= (2.0 * M_PI); + } + + mFrameCounter++; + } + + // Do these once per buffer. + switch (mState) { + case STATE_IMMUNE: + mDownCounter -= numFrames; + if (mDownCounter <= 0) { + mState = STATE_WAITING_FOR_SIGNAL; + //printf("%5d: switch to STATE_WAITING_FOR_SIGNAL\n", mFrameCounter); + } + break; + case STATE_WAITING_FOR_SIGNAL: + if (peak > mThreshold) { + mState = STATE_WAITING_FOR_LOCK; + //printf("%5d: switch to STATE_WAITING_FOR_LOCK\n", mFrameCounter); + resetAccumulator(); + } + break; + case STATE_WAITING_FOR_LOCK: + case STATE_LOCKED: + break; + } + + } + + void resetAccumulator() { + mFramesAccumulated = 0; + mSinAccumulator = 0.0; + mCosAccumulator = 0.0; + } + + void reset() override { + mGlitchCount = 0; + mState = STATE_IMMUNE; + mPhaseIncrement = 2.0 * M_PI / mPeriod; + printf("phaseInc = %f for period %d\n", mPhaseIncrement, mPeriod); + resetAccumulator(); + } + +private: + + enum sine_state_t { + STATE_IMMUNE, + STATE_WAITING_FOR_SIGNAL, + STATE_WAITING_FOR_LOCK, + STATE_LOCKED + }; + + int mPeriod = 79; + double mPhaseIncrement = 0.0; + double mPhase = 0.0; + double mPhaseOffset = 0.0; + double mPreviousPhaseOffset = 0.0; + double mMagnitude = 0.0; + double mThreshold = 0.005; + double mTolerance = 0.01; + int32_t mFramesAccumulated = 0; + double mSinAccumulator = 0.0; + double mCosAccumulator = 0.0; + int32_t mGlitchCount = 0; + double mPeakAmplitude = 0.0; + int mDownCounter = 4000; + int32_t mFrameCounter = 0; + float mOutputAmplitude = 0.75; + + int32_t mZeroCrossings = 0; + + PseudoRandom mWhiteNoise; + float mNoiseAmplitude = 0.00; // Used to experiment with warbling caused by DRC. + + sine_state_t mState = STATE_IMMUNE; +}; + + +#undef LOOPBACK_SAMPLE_RATE +#undef LOOPBACK_RESULT_TAG + +#endif /* AAUDIO_EXAMPLES_LOOPBACK_ANALYSER_H */ diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp index 9f06ee7ae7..144c941846 100644 --- a/media/libaaudio/examples/loopback/src/loopback.cpp +++ b/media/libaaudio/examples/loopback/src/loopback.cpp @@ -14,219 +14,52 @@ * limitations under the License. */ -// Play an impulse and then record it. -// Measure the round trip latency. +// Audio loopback tests to measure the round trip latency and glitches. +#include <algorithm> #include <assert.h> #include <cctype> #include <math.h> -#include <stdlib.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <aaudio/AAudio.h> +#include <aaudio/AAudioTesting.h> + +#include "AAudioSimplePlayer.h" +#include "AAudioSimpleRecorder.h" +#include "AAudioExampleUtils.h" +#include "LoopbackAnalyzer.h" -#define INPUT_PEAK_THRESHOLD 0.1f -#define SILENCE_FRAMES 10000 +// Tag for machine readable results as property = value pairs +#define RESULT_TAG "RESULT: " #define SAMPLE_RATE 48000 -#define NUM_SECONDS 7 +#define NUM_SECONDS 5 +#define NUM_INPUT_CHANNELS 1 #define FILENAME "/data/oboe_input.raw" +#define APP_VERSION "0.1.22" -#define NANOS_PER_MICROSECOND ((int64_t)1000) -#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000) -#define MILLIS_PER_SECOND 1000 -#define NANOS_PER_SECOND (NANOS_PER_MILLISECOND * MILLIS_PER_SECOND) - -class AudioRecorder -{ -public: - AudioRecorder() { - } - ~AudioRecorder() { - delete[] mData; - } - - void allocate(int maxFrames) { - delete[] mData; - mData = new float[maxFrames]; - mMaxFrames = maxFrames; - } - - void record(int16_t *inputData, int inputChannelCount, int numFrames) { - // stop at end of buffer - if ((mFrameCounter + numFrames) > mMaxFrames) { - numFrames = mMaxFrames - mFrameCounter; - } - for (int i = 0; i < numFrames; i++) { - mData[mFrameCounter++] = inputData[i * inputChannelCount] * (1.0f / 32768); - } - } - - void record(float *inputData, int inputChannelCount, int numFrames) { - // stop at end of buffer - if ((mFrameCounter + numFrames) > mMaxFrames) { - numFrames = mMaxFrames - mFrameCounter; - } - for (int i = 0; i < numFrames; i++) { - mData[mFrameCounter++] = inputData[i * inputChannelCount]; - } - } - - int save(const char *fileName) { - FILE *fid = fopen(fileName, "wb"); - if (fid == NULL) { - return errno; - } - int written = fwrite(mData, sizeof(float), mFrameCounter, fid); - fclose(fid); - return written; - } - -private: - float *mData = NULL; - int32_t mFrameCounter = 0; - int32_t mMaxFrames = 0; -}; - -// ==================================================================================== -// ========================= Loopback Processor ======================================= -// ==================================================================================== -class LoopbackProcessor { -public: - - // Calculate mean and standard deviation. - double calculateAverageLatency(double *deviation) { - if (mLatencyCount <= 0) { - return -1.0; - } - double sum = 0.0; - for (int i = 0; i < mLatencyCount; i++) { - sum += mLatencyArray[i]; - } - double average = sum / mLatencyCount; - sum = 0.0; - for (int i = 0; i < mLatencyCount; i++) { - double error = average - mLatencyArray[i]; - sum += error * error; // squared - } - *deviation = sqrt(sum / mLatencyCount); - return average; - } - - float getMaxAmplitude() const { return mMaxAmplitude; } - int getMeasurementCount() const { return mLatencyCount; } - float getAverageAmplitude() const { return mAmplitudeTotal / mAmplitudeCount; } - - // TODO Convert this to a feedback circuit and then use auto-correlation to measure the period. - void process(float *inputData, int inputChannelCount, - float *outputData, int outputChannelCount, - int numFrames) { - (void) outputChannelCount; - - // Measure peak and average amplitude. - for (int i = 0; i < numFrames; i++) { - float sample = inputData[i * inputChannelCount]; - if (sample > mMaxAmplitude) { - mMaxAmplitude = sample; - } - if (sample < 0) { - sample = 0 - sample; - } - mAmplitudeTotal += sample; - mAmplitudeCount++; - } - - // Clear output. - memset(outputData, 0, numFrames * outputChannelCount * sizeof(float)); - - // Wait a while between hearing the pulse and starting a new one. - if (mState == STATE_SILENT) { - mCounter += numFrames; - if (mCounter > SILENCE_FRAMES) { - //printf("LoopbackProcessor send impulse, burst #%d\n", mBurstCounter); - // copy impulse - for (float sample : mImpulse) { - *outputData = sample; - outputData += outputChannelCount; - } - mState = STATE_LISTENING; - mCounter = 0; - } - } - // Start listening as soon as we send the impulse. - if (mState == STATE_LISTENING) { - for (int i = 0; i < numFrames; i++) { - float sample = inputData[i * inputChannelCount]; - if (sample >= INPUT_PEAK_THRESHOLD) { - mLatencyArray[mLatencyCount++] = mCounter; - if (mLatencyCount >= MAX_LATENCY_VALUES) { - mState = STATE_DONE; - } else { - mState = STATE_SILENT; - } - mCounter = 0; - break; - } else { - mCounter++; - } - } - } - } - - void echo(float *inputData, int inputChannelCount, - float *outputData, int outputChannelCount, - int numFrames) { - int channelsValid = (inputChannelCount < outputChannelCount) - ? inputChannelCount : outputChannelCount; - for (int i = 0; i < numFrames; i++) { - int ic; - for (ic = 0; ic < channelsValid; ic++) { - outputData[ic] = inputData[ic]; - } - for (ic = 0; ic < outputChannelCount; ic++) { - outputData[ic] = 0; - } - inputData += inputChannelCount; - outputData += outputChannelCount; - } - } -private: - enum { - STATE_SILENT, - STATE_LISTENING, - STATE_DONE - }; - - enum { - MAX_LATENCY_VALUES = 64 - }; - - int mState = STATE_SILENT; - int32_t mCounter = 0; - int32_t mLatencyArray[MAX_LATENCY_VALUES]; - int32_t mLatencyCount = 0; - float mMaxAmplitude = 0; - float mAmplitudeTotal = 0; - int32_t mAmplitudeCount = 0; - static const float mImpulse[5]; -}; - -const float LoopbackProcessor::mImpulse[5] = {0.5f, 0.9f, 0.0f, -0.9f, -0.5f}; - -// TODO make this a class that manages its own buffer allocation struct LoopbackData { - AAudioStream *inputStream = nullptr; - int32_t inputFramesMaximum = 0; - int16_t *inputData = nullptr; - float *conversionBuffer = nullptr; - int32_t actualInputChannelCount = 0; - int32_t actualOutputChannelCount = 0; - int32_t inputBuffersToDiscard = 10; - - aaudio_result_t inputError; - LoopbackProcessor loopbackProcessor; - AudioRecorder audioRecorder; + AAudioStream *inputStream = nullptr; + int32_t inputFramesMaximum = 0; + int16_t *inputData = nullptr; + int16_t peakShort = 0; + float *conversionBuffer = nullptr; + int32_t actualInputChannelCount = 0; + int32_t actualOutputChannelCount = 0; + int32_t inputBuffersToDiscard = 10; + int32_t minNumFrames = INT32_MAX; + int32_t maxNumFrames = 0; + bool isDone = false; + + aaudio_result_t inputError = AAUDIO_OK; + aaudio_result_t outputError = AAUDIO_OK; + + SineAnalyzer sineAnalyzer; + EchoAnalyzer echoAnalyzer; + AudioRecording audioRecorder; + LoopbackProcessor *loopbackProcessor; }; static void convertPcm16ToFloat(const int16_t *source, @@ -249,6 +82,7 @@ static aaudio_data_callback_result_t MyDataCallbackProc( int32_t numFrames ) { (void) outputStream; + aaudio_data_callback_result_t result = AAUDIO_CALLBACK_RESULT_CONTINUE; LoopbackData *myData = (LoopbackData *) userData; float *outputData = (float *) audioData; @@ -260,6 +94,13 @@ static aaudio_data_callback_result_t MyDataCallbackProc( return AAUDIO_CALLBACK_RESULT_STOP; } + if (numFrames > myData->maxNumFrames) { + myData->maxNumFrames = numFrames; + } + if (numFrames < myData->minNumFrames) { + myData->minNumFrames = numFrames; + } + if (myData->inputBuffersToDiscard > 0) { // Drain the input. do { @@ -267,6 +108,8 @@ static aaudio_data_callback_result_t MyDataCallbackProc( numFrames, 0); if (framesRead < 0) { myData->inputError = framesRead; + printf("ERROR in read = %d", framesRead); + result = AAUDIO_CALLBACK_RESULT_STOP; } else if (framesRead > 0) { myData->inputBuffersToDiscard--; } @@ -276,39 +119,62 @@ static aaudio_data_callback_result_t MyDataCallbackProc( numFrames, 0); if (framesRead < 0) { myData->inputError = framesRead; + printf("ERROR in read = %d", framesRead); + result = AAUDIO_CALLBACK_RESULT_STOP; } else if (framesRead > 0) { - // Process valid input data. - myData->audioRecorder.record(myData->inputData, - myData->actualInputChannelCount, - framesRead); + + myData->audioRecorder.write(myData->inputData, + myData->actualInputChannelCount, + numFrames); int32_t numSamples = framesRead * myData->actualInputChannelCount; convertPcm16ToFloat(myData->inputData, myData->conversionBuffer, numSamples); - myData->loopbackProcessor.process(myData->conversionBuffer, + myData->loopbackProcessor->process(myData->conversionBuffer, myData->actualInputChannelCount, outputData, myData->actualOutputChannelCount, framesRead); + myData->isDone = myData->loopbackProcessor->isDone(); + if (myData->isDone) { + result = AAUDIO_CALLBACK_RESULT_STOP; + } } } - return AAUDIO_CALLBACK_RESULT_CONTINUE; + return result; +} + +static void MyErrorCallbackProc( + AAudioStream *stream __unused, + void *userData __unused, + aaudio_result_t error) +{ + printf("Error Callback, error: %d\n",(int)error); + LoopbackData *myData = (LoopbackData *) userData; + myData->outputError = error; } static void usage() { - printf("loopback: -b{burstsPerBuffer} -p{outputPerfMode} -P{inputPerfMode}\n"); - printf(" -b{burstsPerBuffer} for example 2 for double buffered\n"); - printf(" -p{outputPerfMode} set output AAUDIO_PERFORMANCE_MODE*\n"); - printf(" -P{inputPerfMode} set input AAUDIO_PERFORMANCE_MODE*\n"); + printf("loopback: -n{numBursts} -p{outPerf} -P{inPerf} -t{test} -g{gain} -f{freq}\n"); + printf(" -c{inputChannels}\n"); + printf(" -f{freq} sine frequency\n"); + printf(" -g{gain} recirculating loopback gain\n"); + printf(" -m enable MMAP mode\n"); + printf(" -n{numBursts} buffer size, for example 2 for double buffered\n"); + printf(" -p{outPerf} set output AAUDIO_PERFORMANCE_MODE*\n"); + printf(" -P{inPerf} set input AAUDIO_PERFORMANCE_MODE*\n"); printf(" n for _NONE\n"); printf(" l for _LATENCY\n"); printf(" p for _POWER_SAVING;\n"); + printf(" -t{test} select test mode\n"); + printf(" m for sine magnitude\n"); + printf(" e for echo latency (default)\n"); printf("For example: loopback -b2 -pl -Pn\n"); } static aaudio_performance_mode_t parsePerformanceMode(char c) { - aaudio_performance_mode_t mode = AAUDIO_PERFORMANCE_MODE_NONE; + aaudio_performance_mode_t mode = AAUDIO_ERROR_ILLEGAL_ARGUMENT; c = tolower(c); switch (c) { case 'n': @@ -321,208 +187,281 @@ static aaudio_performance_mode_t parsePerformanceMode(char c) { mode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING; break; default: - printf("ERROR invalue performance mode %c\n", c); + printf("ERROR in value performance mode %c\n", c); break; } return mode; } +enum { + TEST_SINE_MAGNITUDE = 0, + TEST_ECHO_LATENCY, +}; + +static int parseTestMode(char c) { + int testMode = TEST_ECHO_LATENCY; + c = tolower(c); + switch (c) { + case 'm': + testMode = TEST_SINE_MAGNITUDE; + break; + case 'e': + testMode = TEST_ECHO_LATENCY; + break; + default: + printf("ERROR in value test mode %c\n", c); + break; + } + return testMode; +} + +void printAudioGraph(AudioRecording &recording, int numSamples) { + int32_t start = recording.size() / 2; + int32_t end = start + numSamples; + if (end >= recording.size()) { + end = recording.size() - 1; + } + float *data = recording.getData(); + // Normalize data so we can see it better. + float maxSample = 0.01; + for (int32_t i = start; i < end; i++) { + float samplePos = fabs(data[i]); + if (samplePos > maxSample) { + maxSample = samplePos; + } + } + float gain = 0.98f / maxSample; + for (int32_t i = start; i < end; i++) { + float sample = data[i]; + printf("%5.3f ", sample); // actual value + sample *= gain; + printAudioScope(sample); + } +} + + // ==================================================================================== // TODO break up this large main() function into smaller functions int main(int argc, const char **argv) { - aaudio_result_t result = AAUDIO_OK; - LoopbackData loopbackData; - AAudioStream *outputStream = nullptr; - - const int requestedInputChannelCount = 1; - const int requestedOutputChannelCount = AAUDIO_UNSPECIFIED; - const int requestedSampleRate = SAMPLE_RATE; - int actualSampleRate = 0; + + AAudioArgsParser argParser; + AAudioSimplePlayer player; + AAudioSimpleRecorder recorder; + LoopbackData loopbackData; + AAudioStream *outputStream = nullptr; + + aaudio_result_t result = AAUDIO_OK; + aaudio_sharing_mode_t requestedInputSharingMode = AAUDIO_SHARING_MODE_SHARED; + int requestedInputChannelCount = NUM_INPUT_CHANNELS; + const int requestedOutputChannelCount = AAUDIO_UNSPECIFIED; + int actualSampleRate = 0; const aaudio_format_t requestedInputFormat = AAUDIO_FORMAT_PCM_I16; const aaudio_format_t requestedOutputFormat = AAUDIO_FORMAT_PCM_FLOAT; - aaudio_format_t actualInputFormat; - aaudio_format_t actualOutputFormat; + aaudio_format_t actualInputFormat; + aaudio_format_t actualOutputFormat; + aaudio_performance_mode_t outputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY; + aaudio_performance_mode_t inputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY; - const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE; - //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_SHARED; - aaudio_sharing_mode_t actualSharingMode; + int testMode = TEST_ECHO_LATENCY; + double gain = 1.0; - AAudioStreamBuilder *builder = nullptr; aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED; int32_t framesPerBurst = 0; float *outputData = NULL; double deviation; double latency; - aaudio_performance_mode_t outputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY; - aaudio_performance_mode_t inputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY; - int32_t burstsPerBuffer = 1; // single buffered + // Make printf print immediately so that debug info is not stuck + // in a buffer if we hang or crash. + setvbuf(stdout, NULL, _IONBF, (size_t) 0); + + printf("%s - Audio loopback using AAudio V" APP_VERSION "\n", argv[0]); + for (int i = 1; i < argc; i++) { const char *arg = argv[i]; - if (arg[0] == '-') { - char option = arg[1]; - switch (option) { - case 'b': - burstsPerBuffer = atoi(&arg[2]); - break; - case 'p': - outputPerformanceLevel = parsePerformanceMode(arg[2]); - break; - case 'P': - inputPerformanceLevel = parsePerformanceMode(arg[2]); - break; - default: - usage(); - break; + if (argParser.parseArg(arg)) { + // Handle options that are not handled by the ArgParser + if (arg[0] == '-') { + char option = arg[1]; + switch (option) { + case 'C': + requestedInputChannelCount = atoi(&arg[2]); + break; + case 'g': + gain = atof(&arg[2]); + break; + case 'P': + inputPerformanceLevel = parsePerformanceMode(arg[2]); + break; + case 'X': + requestedInputSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE; + break; + case 't': + testMode = parseTestMode(arg[2]); + break; + default: + usage(); + exit(EXIT_FAILURE); + break; + } + } else { + usage(); + exit(EXIT_FAILURE); + break; } - } else { - break; } - } - - loopbackData.audioRecorder.allocate(NUM_SECONDS * SAMPLE_RATE); - - // Make printf print immediately so that debug info is not stuck - // in a buffer if we hang or crash. - setvbuf(stdout, NULL, _IONBF, (size_t) 0); - printf("%s - Audio loopback using AAudio\n", argv[0]); + } - // Use an AAudioStreamBuilder to contain requested parameters. - result = AAudio_createStreamBuilder(&builder); - if (result < 0) { - goto finish; + if (inputPerformanceLevel < 0) { + printf("illegal inputPerformanceLevel = %d\n", inputPerformanceLevel); + exit(EXIT_FAILURE); } - // Request common stream properties. - AAudioStreamBuilder_setSampleRate(builder, requestedSampleRate); - AAudioStreamBuilder_setFormat(builder, requestedInputFormat); - AAudioStreamBuilder_setSharingMode(builder, requestedSharingMode); + int32_t requestedDuration = argParser.getDurationSeconds(); + int32_t recordingDuration = std::min(60, requestedDuration); + loopbackData.audioRecorder.allocate(recordingDuration * SAMPLE_RATE); - // Open the input stream. - AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_INPUT); - AAudioStreamBuilder_setPerformanceMode(builder, inputPerformanceLevel); - AAudioStreamBuilder_setChannelCount(builder, requestedInputChannelCount); + switch(testMode) { + case TEST_SINE_MAGNITUDE: + loopbackData.loopbackProcessor = &loopbackData.sineAnalyzer; + break; + case TEST_ECHO_LATENCY: + loopbackData.echoAnalyzer.setGain(gain); + loopbackData.loopbackProcessor = &loopbackData.echoAnalyzer; + break; + default: + exit(1); + break; + } - result = AAudioStreamBuilder_openStream(builder, &loopbackData.inputStream); - printf("AAudioStreamBuilder_openStream(input) returned %d = %s\n", - result, AAudio_convertResultToText(result)); - if (result < 0) { + printf("OUTPUT stream ----------------------------------------\n"); + argParser.setFormat(requestedOutputFormat); + result = player.open(argParser, MyDataCallbackProc, MyErrorCallbackProc, &loopbackData); + if (result != AAUDIO_OK) { + fprintf(stderr, "ERROR - player.open() returned %d\n", result); goto finish; } + outputStream = player.getStream(); + argParser.compareWithStream(outputStream); - // Create an output stream using the Builder. - AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT); - AAudioStreamBuilder_setFormat(builder, requestedOutputFormat); - AAudioStreamBuilder_setPerformanceMode(builder, outputPerformanceLevel); - AAudioStreamBuilder_setChannelCount(builder, requestedOutputChannelCount); - AAudioStreamBuilder_setDataCallback(builder, MyDataCallbackProc, &loopbackData); + actualOutputFormat = AAudioStream_getFormat(outputStream); + assert(actualOutputFormat == AAUDIO_FORMAT_PCM_FLOAT); - result = AAudioStreamBuilder_openStream(builder, &outputStream); - printf("AAudioStreamBuilder_openStream(output) returned %d = %s\n", - result, AAudio_convertResultToText(result)); + printf("INPUT stream ----------------------------------------\n"); + // Use different parameters for the input. + argParser.setNumberOfBursts(AAUDIO_UNSPECIFIED); + argParser.setFormat(requestedInputFormat); + argParser.setPerformanceMode(inputPerformanceLevel); + argParser.setChannelCount(requestedInputChannelCount); + argParser.setSharingMode(requestedInputSharingMode); + result = recorder.open(argParser); if (result != AAUDIO_OK) { + fprintf(stderr, "ERROR - recorder.open() returned %d\n", result); goto finish; } - - printf("Stream INPUT ---------------------\n"); - loopbackData.actualInputChannelCount = AAudioStream_getChannelCount(loopbackData.inputStream); - printf(" channelCount: requested = %d, actual = %d\n", requestedInputChannelCount, - loopbackData.actualInputChannelCount); - printf(" framesPerBurst = %d\n", AAudioStream_getFramesPerBurst(loopbackData.inputStream)); - - actualInputFormat = AAudioStream_getFormat(loopbackData.inputStream); - printf(" dataFormat: requested = %d, actual = %d\n", requestedInputFormat, actualInputFormat); - assert(actualInputFormat == AAUDIO_FORMAT_PCM_I16); - - printf("Stream OUTPUT ---------------------\n"); - // Check to see what kind of stream we actually got. - actualSampleRate = AAudioStream_getSampleRate(outputStream); - printf(" sampleRate: requested = %d, actual = %d\n", requestedSampleRate, actualSampleRate); - - loopbackData.actualOutputChannelCount = AAudioStream_getChannelCount(outputStream); - printf(" channelCount: requested = %d, actual = %d\n", requestedOutputChannelCount, - loopbackData.actualOutputChannelCount); - - actualSharingMode = AAudioStream_getSharingMode(outputStream); - printf(" sharingMode: requested = %d, actual = %d\n", requestedSharingMode, actualSharingMode); + loopbackData.inputStream = recorder.getStream(); + argParser.compareWithStream(loopbackData.inputStream); // This is the number of frames that are read in one chunk by a DMA controller // or a DSP or a mixer. framesPerBurst = AAudioStream_getFramesPerBurst(outputStream); - printf(" framesPerBurst = %d\n", framesPerBurst); - printf(" bufferCapacity = %d\n", AAudioStream_getBufferCapacityInFrames(outputStream)); + actualInputFormat = AAudioStream_getFormat(outputStream); + assert(actualInputFormat == AAUDIO_FORMAT_PCM_I16); - actualOutputFormat = AAudioStream_getFormat(outputStream); - printf(" dataFormat: requested = %d, actual = %d\n", requestedOutputFormat, actualOutputFormat); - assert(actualOutputFormat == AAUDIO_FORMAT_PCM_FLOAT); + + loopbackData.actualInputChannelCount = recorder.getChannelCount(); + loopbackData.actualOutputChannelCount = player.getChannelCount(); // Allocate a buffer for the audio data. loopbackData.inputFramesMaximum = 32 * framesPerBurst; + loopbackData.inputBuffersToDiscard = 100; - loopbackData.inputData = new int16_t[loopbackData.inputFramesMaximum * loopbackData.actualInputChannelCount]; + loopbackData.inputData = new int16_t[loopbackData.inputFramesMaximum + * loopbackData.actualInputChannelCount]; loopbackData.conversionBuffer = new float[loopbackData.inputFramesMaximum * loopbackData.actualInputChannelCount]; - result = AAudioStream_setBufferSizeInFrames(outputStream, burstsPerBuffer * framesPerBurst); - if (result < 0) { // may be positive buffer size - fprintf(stderr, "ERROR - AAudioStream_setBufferSize() returned %d\n", result); - goto finish; - } - printf("AAudioStream_setBufferSize() actual = %d\n",result); + loopbackData.loopbackProcessor->reset(); - // Start output first so input stream runs low. - result = AAudioStream_requestStart(outputStream); + result = recorder.start(); if (result != AAUDIO_OK) { - fprintf(stderr, "ERROR - AAudioStream_requestStart(output) returned %d = %s\n", - result, AAudio_convertResultToText(result)); + printf("ERROR - AAudioStream_requestStart(input) returned %d = %s\n", + result, AAudio_convertResultToText(result)); goto finish; } - result = AAudioStream_requestStart(loopbackData.inputStream); + result = player.start(); if (result != AAUDIO_OK) { - fprintf(stderr, "ERROR - AAudioStream_requestStart(input) returned %d = %s\n", - result, AAudio_convertResultToText(result)); + printf("ERROR - AAudioStream_requestStart(output) returned %d = %s\n", + result, AAudio_convertResultToText(result)); goto finish; } printf("------- sleep while the callback runs --------------\n"); fflush(stdout); - sleep(NUM_SECONDS); - + for (int i = requestedDuration; i > 0 ; i--) { + if (loopbackData.inputError != AAUDIO_OK) { + printf(" ERROR on input stream\n"); + break; + } else if (loopbackData.outputError != AAUDIO_OK) { + printf(" ERROR on output stream\n"); + break; + } else if (loopbackData.isDone) { + printf(" test says it is done!\n"); + break; + } else { + sleep(1); + printf("%4d: ", i); + loopbackData.loopbackProcessor->printStatus(); + int64_t framesWritten = AAudioStream_getFramesWritten(loopbackData.inputStream); + int64_t framesRead = AAudioStream_getFramesRead(loopbackData.inputStream); + printf(" input written = %lld, read %lld, xruns = %d\n", + (long long) framesWritten, + (long long) framesRead, + AAudioStream_getXRunCount(outputStream) + ); + } + } printf("input error = %d = %s\n", loopbackData.inputError, AAudio_convertResultToText(loopbackData.inputError)); printf("AAudioStream_getXRunCount %d\n", AAudioStream_getXRunCount(outputStream)); - printf("framesRead = %d\n", (int) AAudioStream_getFramesRead(outputStream)); - printf("framesWritten = %d\n", (int) AAudioStream_getFramesWritten(outputStream)); - - latency = loopbackData.loopbackProcessor.calculateAverageLatency(&deviation); - printf("measured peak = %8.5f\n", loopbackData.loopbackProcessor.getMaxAmplitude()); - printf("threshold = %8.5f\n", INPUT_PEAK_THRESHOLD); - printf("measured average = %8.5f\n", loopbackData.loopbackProcessor.getAverageAmplitude()); - printf("# latency measurements = %d\n", loopbackData.loopbackProcessor.getMeasurementCount()); - printf("measured latency = %8.2f +/- %4.5f frames\n", latency, deviation); - printf("measured latency = %8.2f msec <===== !!\n", (1000.0 * latency / actualSampleRate)); + printf("framesRead = %8d\n", (int) AAudioStream_getFramesRead(outputStream)); + printf("framesWritten = %8d\n", (int) AAudioStream_getFramesWritten(outputStream)); + printf("min numFrames = %8d\n", (int) loopbackData.minNumFrames); + printf("max numFrames = %8d\n", (int) loopbackData.maxNumFrames); + + if (loopbackData.inputError == AAUDIO_OK) { + if (testMode == TEST_SINE_MAGNITUDE) { + printAudioGraph(loopbackData.audioRecorder, 200); + } + loopbackData.loopbackProcessor->report(); + } { int written = loopbackData.audioRecorder.save(FILENAME); - printf("wrote %d samples to %s\n", written, FILENAME); + printf("main() wrote %d mono samples to %s on Android device\n", written, FILENAME); } finish: - AAudioStream_close(outputStream); - AAudioStream_close(loopbackData.inputStream); + player.close(); + recorder.close(); delete[] loopbackData.conversionBuffer; delete[] loopbackData.inputData; delete[] outputData; - AAudioStreamBuilder_delete(builder); - printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result)); - return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS; + printf(RESULT_TAG "error = %d = %s\n", result, AAudio_convertResultToText(result)); + if ((result != AAUDIO_OK)) { + printf("error %d = %s\n", result, AAudio_convertResultToText(result)); + return EXIT_FAILURE; + } else { + printf("SUCCESS\n"); + return EXIT_SUCCESS; + } } diff --git a/media/libaaudio/examples/loopback/src/loopback.sh b/media/libaaudio/examples/loopback/src/loopback.sh new file mode 100644 index 0000000000..bc63125d29 --- /dev/null +++ b/media/libaaudio/examples/loopback/src/loopback.sh @@ -0,0 +1,14 @@ +#!/system/bin/sh +# Run a loopback test in the background after a delay. +# To run the script enter: +# adb shell "nohup sh /data/loopback.sh &" + +SLEEP_TIME=10 +TEST_COMMAND="aaudio_loopback -pl -Pl -C1 -n2 -m2 -tm -d5" + +echo "Plug in USB Mir and Fun Plug." +echo "Test will start in ${SLEEP_TIME} seconds: ${TEST_COMMAND}" +sleep ${SLEEP_TIME} +date > /data/loopreport.txt +${TEST_COMMAND} >> /data/loopreport.txt +date >> /data/loopreport.txt diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h new file mode 100644 index 0000000000..46bc99ed98 --- /dev/null +++ b/media/libaaudio/examples/utils/AAudioArgsParser.h @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AAUDIO_EXAMPLE_ARGS_PARSER_H +#define AAUDIO_EXAMPLE_ARGS_PARSER_H + +#include <cctype> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> + +#include <aaudio/AAudio.h> +#include <aaudio/AAudioTesting.h> +#include <AAudioExampleUtils.h> + +// TODO use this as a base class within AAudio +class AAudioParameters { +public: + + /** + * This is also known as samplesPerFrame. + */ + int32_t getChannelCount() const { + return mChannelCount; + } + + void setChannelCount(int32_t channelCount) { + mChannelCount = channelCount; + } + + int32_t getSampleRate() const { + return mSampleRate; + } + + void setSampleRate(int32_t sampleRate) { + mSampleRate = sampleRate; + } + + aaudio_format_t getFormat() const { + return mFormat; + } + + void setFormat(aaudio_format_t format) { + mFormat = format; + } + + aaudio_sharing_mode_t getSharingMode() const { + return mSharingMode; + } + + void setSharingMode(aaudio_sharing_mode_t sharingMode) { + mSharingMode = sharingMode; + } + + int32_t getBufferCapacity() const { + return mBufferCapacity; + } + + void setBufferCapacity(int32_t frames) { + mBufferCapacity = frames; + } + + int32_t getPerformanceMode() const { + return mPerformanceMode; + } + + void setPerformanceMode(aaudio_performance_mode_t performanceMode) { + mPerformanceMode = performanceMode; + } + + int32_t getDeviceId() const { + return mDeviceId; + } + + void setDeviceId(int32_t deviceId) { + mDeviceId = deviceId; + } + + int32_t getNumberOfBursts() const { + return mNumberOfBursts; + } + + void setNumberOfBursts(int32_t numBursts) { + mNumberOfBursts = numBursts; + } + + /** + * Apply these parameters to a stream builder. + * @param builder + */ + void applyParameters(AAudioStreamBuilder *builder) const { + AAudioStreamBuilder_setChannelCount(builder, mChannelCount); + AAudioStreamBuilder_setFormat(builder, mFormat); + AAudioStreamBuilder_setSampleRate(builder, mSampleRate); + AAudioStreamBuilder_setBufferCapacityInFrames(builder, mBufferCapacity); + AAudioStreamBuilder_setDeviceId(builder, mDeviceId); + AAudioStreamBuilder_setSharingMode(builder, mSharingMode); + AAudioStreamBuilder_setPerformanceMode(builder, mPerformanceMode); + } + +private: + int32_t mChannelCount = AAUDIO_UNSPECIFIED; + aaudio_format_t mFormat = AAUDIO_FORMAT_UNSPECIFIED; + int32_t mSampleRate = AAUDIO_UNSPECIFIED; + + int32_t mBufferCapacity = AAUDIO_UNSPECIFIED; + int32_t mDeviceId = AAUDIO_UNSPECIFIED; + aaudio_sharing_mode_t mSharingMode = AAUDIO_SHARING_MODE_SHARED; + aaudio_performance_mode_t mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE; + + int32_t mNumberOfBursts = AAUDIO_UNSPECIFIED; +}; + +class AAudioArgsParser : public AAudioParameters { +public: + AAudioArgsParser() = default; + ~AAudioArgsParser() = default; + + enum { + DEFAULT_DURATION_SECONDS = 5 + }; + + /** + * @param arg + * @return true if the argument was not handled + */ + bool parseArg(const char *arg) { + bool unrecognized = false; + if (arg[0] == '-') { + char option = arg[1]; + switch (option) { + case 'b': + setBufferCapacity(atoi(&arg[2])); + break; + case 'c': + setChannelCount(atoi(&arg[2])); + break; + case 'd': + mDurationSeconds = atoi(&arg[2]); + break; + case 'm': { + aaudio_policy_t policy = AAUDIO_POLICY_AUTO; + if (strlen(arg) > 2) { + policy = atoi(&arg[2]); + } + AAudio_setMMapPolicy(policy); + } break; + case 'n': + setNumberOfBursts(atoi(&arg[2])); + break; + case 'p': + setPerformanceMode(parsePerformanceMode(arg[2])); + break; + case 'r': + setSampleRate(atoi(&arg[2])); + break; + case 'x': + setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE); + break; + default: + unrecognized = true; + break; + } + } + return unrecognized; + } + + /** + * + * @param argc + * @param argv + * @return true if an unrecognized argument was passed + */ + bool parseArgs(int argc, const char **argv) { + for (int i = 1; i < argc; i++) { + const char *arg = argv[i]; + if (parseArg(arg)) { + usage(); + return true; + } + + } + return false; + } + + static void usage() { + printf("-c{channels} -d{duration} -m -n{burstsPerBuffer} -p{perfMode} -r{rate} -x\n"); + printf(" Default values are UNSPECIFIED unless otherwise stated.\n"); + printf(" -b{bufferCapacity} frames\n"); + printf(" -c{channels} for example 2 for stereo\n"); + printf(" -d{duration} in seconds, default is %d\n", DEFAULT_DURATION_SECONDS); + printf(" -m{0|1|2|3} set MMAP policy\n"); + printf(" 0 = _UNSPECIFIED, default\n"); + printf(" 1 = _NEVER\n"); + printf(" 2 = _AUTO, also if -m is used with no number\n"); + printf(" 3 = _ALWAYS\n"); + printf(" -n{numberOfBursts} for setBufferSize\n"); + printf(" -p{performanceMode} set output AAUDIO_PERFORMANCE_MODE*, default NONE\n"); + printf(" n for _NONE\n"); + printf(" l for _LATENCY\n"); + printf(" p for _POWER_SAVING;\n"); + printf(" -r{sampleRate} for example 44100\n"); + printf(" -x to use EXCLUSIVE mode\n"); + } + + static aaudio_performance_mode_t parsePerformanceMode(char c) { + aaudio_performance_mode_t mode = AAUDIO_PERFORMANCE_MODE_NONE; + switch (c) { + case 'n': + mode = AAUDIO_PERFORMANCE_MODE_NONE; + break; + case 'l': + mode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY; + break; + case 'p': + mode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING; + break; + default: + printf("ERROR invalid performance mode %c\n", c); + break; + } + return mode; + } + + /** + * Print stream parameters in comparison with requested values. + * @param stream + */ + void compareWithStream(AAudioStream *stream) { + + printf(" DeviceId: requested = %d, actual = %d\n", + getDeviceId(), AAudioStream_getDeviceId(stream)); + + aaudio_stream_state_t state = AAudioStream_getState(stream); + printf(" State: %s\n", AAudio_convertStreamStateToText(state)); + + // Check to see what kind of stream we actually got. + printf(" SampleRate: requested = %d, actual = %d\n", + getSampleRate(), AAudioStream_getSampleRate(stream)); + + printf(" ChannelCount: requested = %d, actual = %d\n", + getChannelCount(), AAudioStream_getChannelCount(stream)); + + printf(" DataFormat: requested = %d, actual = %d\n", + getFormat(), AAudioStream_getFormat(stream)); + + int32_t framesPerBurst = AAudioStream_getFramesPerBurst(stream); + int32_t sizeFrames = AAudioStream_getBufferSizeInFrames(stream); + printf(" Buffer: burst = %d\n", framesPerBurst); + if (framesPerBurst > 0) { + printf(" Buffer: size = %d = (%d * %d) + %d\n", + sizeFrames, + (sizeFrames / framesPerBurst), + framesPerBurst, + (sizeFrames % framesPerBurst)); + } + printf(" Capacity: requested = %d, actual = %d\n", getBufferCapacity(), + AAudioStream_getBufferCapacityInFrames(stream)); + + printf(" SharingMode: requested = %s, actual = %s\n", + getSharingModeText(getSharingMode()), + getSharingModeText(AAudioStream_getSharingMode(stream))); + + printf(" PerformanceMode: requested = %d, actual = %d\n", + getPerformanceMode(), AAudioStream_getPerformanceMode(stream)); + printf(" Is MMAP used? %s\n", AAudioStream_isMMapUsed(stream) + ? "yes" : "no"); + + } + + int32_t getDurationSeconds() const { + return mDurationSeconds; + } + + void setDurationSeconds(int32_t seconds) { + mDurationSeconds = seconds; + } + +private: + int32_t mDurationSeconds = DEFAULT_DURATION_SECONDS; +}; + +#endif // AAUDIO_EXAMPLE_ARGS_PARSER_H diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h index aaeb25faa5..cc0cb34195 100644 --- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h +++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h @@ -23,12 +23,18 @@ #include <sched.h> #include <aaudio/AAudio.h> +#include "AAudioArgsParser.h" #include "SineGenerator.h" //#define SHARING_MODE AAUDIO_SHARING_MODE_EXCLUSIVE #define SHARING_MODE AAUDIO_SHARING_MODE_SHARED #define PERFORMANCE_MODE AAUDIO_PERFORMANCE_MODE_NONE +// Arbitrary period for glitches, once per second at 48000 Hz. +#define FORCED_UNDERRUN_PERIOD_FRAMES 48000 +// How long to sleep in a callback to cause an intentional glitch. For testing. +#define FORCED_UNDERRUN_SLEEP_MICROS (10 * 1000) + /** * Simple wrapper for AAudio that opens an output stream either in callback or blocking write mode. */ @@ -55,15 +61,23 @@ public: mRequestedPerformanceMode = requestedPerformanceMode; } + // TODO Extract a common base class for record and playback. /** * Also known as "sample rate" * Only call this after open() has been called. */ - int32_t getFramesPerSecond() { + int32_t getFramesPerSecond() const { + return getSampleRate(); // alias + } + + /** + * Only call this after open() has been called. + */ + int32_t getSampleRate() const { if (mStream == nullptr) { return AAUDIO_ERROR_INVALID_STATE; } - return AAudioStream_getSampleRate(mStream);; + return AAudioStream_getSampleRate(mStream); } /** @@ -73,57 +87,83 @@ public: if (mStream == nullptr) { return AAUDIO_ERROR_INVALID_STATE; } - return AAudioStream_getChannelCount(mStream);; + return AAudioStream_getChannelCount(mStream); } /** * Open a stream */ + aaudio_result_t open(const AAudioParameters ¶meters, + AAudioStream_dataCallback dataCallback = nullptr, + AAudioStream_errorCallback errorCallback = nullptr, + void *userContext = nullptr) { + aaudio_result_t result = AAUDIO_OK; + + // Use an AAudioStreamBuilder to contain requested parameters. + AAudioStreamBuilder *builder = nullptr; + result = AAudio_createStreamBuilder(&builder); + if (result != AAUDIO_OK) return result; + + parameters.applyParameters(builder); // apply args + + AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT); + + if (dataCallback != nullptr) { + AAudioStreamBuilder_setDataCallback(builder, dataCallback, userContext); + } + if (errorCallback != nullptr) { + AAudioStreamBuilder_setErrorCallback(builder, errorCallback, userContext); + } + //AAudioStreamBuilder_setFramesPerDataCallback(builder, CALLBACK_SIZE_FRAMES); + //AAudioStreamBuilder_setBufferCapacityInFrames(builder, 48 * 8); + + // Open an AAudioStream using the Builder. + result = AAudioStreamBuilder_openStream(builder, &mStream); + + if (result == AAUDIO_OK) { + int32_t sizeInBursts = parameters.getNumberOfBursts(); + if (sizeInBursts > 0) { + int32_t framesPerBurst = AAudioStream_getFramesPerBurst(mStream); + AAudioStream_setBufferSizeInFrames(mStream, sizeInBursts * framesPerBurst); + } + } + + AAudioStreamBuilder_delete(builder); + return result; + } + aaudio_result_t open(int channelCount, int sampSampleRate, aaudio_format_t format, - AAudioStream_dataCallback dataProc, AAudioStream_errorCallback errorProc, + AAudioStream_dataCallback dataProc, + AAudioStream_errorCallback errorProc, void *userContext) { aaudio_result_t result = AAUDIO_OK; // Use an AAudioStreamBuilder to contain requested parameters. - result = AAudio_createStreamBuilder(&mBuilder); + AAudioStreamBuilder *builder = nullptr; + result = AAudio_createStreamBuilder(&builder); if (result != AAUDIO_OK) return result; - //AAudioStreamBuilder_setSampleRate(mBuilder, 44100); - AAudioStreamBuilder_setPerformanceMode(mBuilder, mRequestedPerformanceMode); - AAudioStreamBuilder_setSharingMode(mBuilder, mRequestedSharingMode); + AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT); + AAudioStreamBuilder_setPerformanceMode(builder, mRequestedPerformanceMode); + AAudioStreamBuilder_setSharingMode(builder, mRequestedSharingMode); + + AAudioStreamBuilder_setChannelCount(builder, channelCount); + AAudioStreamBuilder_setSampleRate(builder, sampSampleRate); + AAudioStreamBuilder_setFormat(builder, format); + if (dataProc != nullptr) { - AAudioStreamBuilder_setDataCallback(mBuilder, dataProc, userContext); + AAudioStreamBuilder_setDataCallback(builder, dataProc, userContext); } if (errorProc != nullptr) { - AAudioStreamBuilder_setErrorCallback(mBuilder, errorProc, userContext); + AAudioStreamBuilder_setErrorCallback(builder, errorProc, userContext); } - AAudioStreamBuilder_setChannelCount(mBuilder, channelCount); - AAudioStreamBuilder_setSampleRate(mBuilder, sampSampleRate); - AAudioStreamBuilder_setFormat(mBuilder, format); - //AAudioStreamBuilder_setFramesPerDataCallback(mBuilder, CALLBACK_SIZE_FRAMES); - AAudioStreamBuilder_setBufferCapacityInFrames(mBuilder, 48 * 8); - - //aaudio_performance_mode_t perfMode = AAUDIO_PERFORMANCE_MODE_NONE; - aaudio_performance_mode_t perfMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY; - //aaudio_performance_mode_t perfMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING; - AAudioStreamBuilder_setPerformanceMode(mBuilder, perfMode); + //AAudioStreamBuilder_setFramesPerDataCallback(builder, CALLBACK_SIZE_FRAMES); + //AAudioStreamBuilder_setBufferCapacityInFrames(builder, 48 * 8); // Open an AAudioStream using the Builder. - result = AAudioStreamBuilder_openStream(mBuilder, &mStream); - if (result != AAUDIO_OK) goto finish1; - - printf("AAudioStream_getFramesPerBurst() = %d\n", - AAudioStream_getFramesPerBurst(mStream)); - printf("AAudioStream_getBufferSizeInFrames() = %d\n", - AAudioStream_getBufferSizeInFrames(mStream)); - printf("AAudioStream_getBufferCapacityInFrames() = %d\n", - AAudioStream_getBufferCapacityInFrames(mStream)); - printf("AAudioStream_getPerformanceMode() = %d, requested %d\n", - AAudioStream_getPerformanceMode(mStream), perfMode); - - finish1: - AAudioStreamBuilder_delete(mBuilder); - mBuilder = nullptr; + result = AAudioStreamBuilder_openStream(builder, &mStream); + + AAudioStreamBuilder_delete(builder); return result; } @@ -132,8 +172,6 @@ public: printf("call AAudioStream_close(%p)\n", mStream); fflush(stdout); AAudioStream_close(mStream); mStream = nullptr; - AAudioStreamBuilder_delete(mBuilder); - mBuilder = nullptr; } return AAUDIO_OK; } @@ -178,7 +216,6 @@ public: } private: - AAudioStreamBuilder *mBuilder = nullptr; AAudioStream *mStream = nullptr; aaudio_sharing_mode_t mRequestedSharingMode = SHARING_MODE; aaudio_performance_mode_t mRequestedPerformanceMode = PERFORMANCE_MODE; @@ -187,8 +224,13 @@ private: typedef struct SineThreadedData_s { SineGenerator sineOsc1; SineGenerator sineOsc2; + int64_t framesTotal = 0; + int64_t nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES; + int32_t minNumFrames = INT32_MAX; + int32_t maxNumFrames = 0; int scheduler; - bool schedulerChecked; + bool schedulerChecked = false; + bool forceUnderruns = false; } SineThreadedData_t; // Callback function that fills the audio output buffer. @@ -201,16 +243,33 @@ aaudio_data_callback_result_t SimplePlayerDataCallbackProc( // should not happen but just in case... if (userData == nullptr) { - fprintf(stderr, "ERROR - SimplePlayerDataCallbackProc needs userData\n"); + printf("ERROR - SimplePlayerDataCallbackProc needs userData\n"); return AAUDIO_CALLBACK_RESULT_STOP; } SineThreadedData_t *sineData = (SineThreadedData_t *) userData; + sineData->framesTotal += numFrames; + + if (sineData->forceUnderruns) { + if (sineData->framesTotal > sineData->nextFrameToGlitch) { + usleep(FORCED_UNDERRUN_SLEEP_MICROS); + printf("Simulate glitch at %lld\n", (long long) sineData->framesTotal); + sineData->nextFrameToGlitch += FORCED_UNDERRUN_PERIOD_FRAMES; + } + } + if (!sineData->schedulerChecked) { sineData->scheduler = sched_getscheduler(gettid()); sineData->schedulerChecked = true; } + if (numFrames > sineData->maxNumFrames) { + sineData->maxNumFrames = numFrames; + } + if (numFrames < sineData->minNumFrames) { + sineData->minNumFrames = numFrames; + } + int32_t samplesPerFrame = AAudioStream_getChannelCount(stream); // This code only plays on the first one or two channels. // TODO Support arbitrary number of channels. diff --git a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h index 9e7c4634b4..5ecac04634 100644 --- a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h +++ b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h @@ -20,10 +20,12 @@ #define AAUDIO_SIMPLE_RECORDER_H #include <aaudio/AAudio.h> +#include "AAudioArgsParser.h" //#define SHARING_MODE AAUDIO_SHARING_MODE_EXCLUSIVE #define SHARING_MODE AAUDIO_SHARING_MODE_SHARED #define PERFORMANCE_MODE AAUDIO_PERFORMANCE_MODE_NONE + /** * Simple wrapper for AAudio that opens an input stream either in callback or blocking read mode. */ @@ -54,22 +56,37 @@ public: * Also known as "sample rate" * Only call this after open() has been called. */ - int32_t getFramesPerSecond() { + int32_t getFramesPerSecond() const { + return getSampleRate(); // alias + } + + /** + * Only call this after open() has been called. + */ + int32_t getSampleRate() const { if (mStream == nullptr) { return AAUDIO_ERROR_INVALID_STATE; } - return AAudioStream_getSampleRate(mStream);; + return AAudioStream_getSampleRate(mStream); } /** * Only call this after open() has been called. */ - int32_t getSamplesPerFrame() { + int32_t getChannelCount() { if (mStream == nullptr) { return AAUDIO_ERROR_INVALID_STATE; } - return AAudioStream_getSamplesPerFrame(mStream);; + return AAudioStream_getChannelCount(mStream); } + + /** + * @deprecated use getChannelCount() + */ + int32_t getSamplesPerFrame() { + return getChannelCount(); + } + /** * Only call this after open() has been called. */ @@ -77,53 +94,85 @@ public: if (mStream == nullptr) { return AAUDIO_ERROR_INVALID_STATE; } - return AAudioStream_getFramesRead(mStream);; + return AAudioStream_getFramesRead(mStream); + } + + aaudio_result_t open(const AAudioParameters ¶meters, + AAudioStream_dataCallback dataCallback = nullptr, + AAudioStream_errorCallback errorCallback = nullptr, + void *userContext = nullptr) { + aaudio_result_t result = AAUDIO_OK; + + // Use an AAudioStreamBuilder to contain requested parameters. + AAudioStreamBuilder *builder = nullptr; + result = AAudio_createStreamBuilder(&builder); + if (result != AAUDIO_OK) return result; + + parameters.applyParameters(builder); // apply args + + AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_INPUT); + + if (dataCallback != nullptr) { + AAudioStreamBuilder_setDataCallback(builder, dataCallback, userContext); + } + if (errorCallback != nullptr) { + AAudioStreamBuilder_setErrorCallback(builder, errorCallback, userContext); + } + + // Open an AAudioStream using the Builder. + result = AAudioStreamBuilder_openStream(builder, &mStream); + if (result != AAUDIO_OK) { + fprintf(stderr, "ERROR - AAudioStreamBuilder_openStream() returned %d %s\n", + result, AAudio_convertResultToText(result)); + } + + if (result == AAUDIO_OK) { + int32_t sizeInBursts = parameters.getNumberOfBursts(); + if (sizeInBursts > 0) { + int32_t framesPerBurst = AAudioStream_getFramesPerBurst(mStream); + AAudioStream_setBufferSizeInFrames(mStream, sizeInBursts * framesPerBurst); + } + } + + AAudioStreamBuilder_delete(builder); + return result; } /** * Open a stream */ aaudio_result_t open(int channelCount, int sampSampleRate, aaudio_format_t format, - AAudioStream_dataCallback dataProc, AAudioStream_errorCallback errorProc, + AAudioStream_dataCallback dataProc, + AAudioStream_errorCallback errorProc, void *userContext) { aaudio_result_t result = AAUDIO_OK; // Use an AAudioStreamBuilder to contain requested parameters. - result = AAudio_createStreamBuilder(&mBuilder); + AAudioStreamBuilder *builder = nullptr; + result = AAudio_createStreamBuilder(&builder); if (result != AAUDIO_OK) return result; - AAudioStreamBuilder_setDirection(mBuilder, AAUDIO_DIRECTION_INPUT); - AAudioStreamBuilder_setPerformanceMode(mBuilder, mRequestedPerformanceMode); - AAudioStreamBuilder_setSharingMode(mBuilder, mRequestedSharingMode); + AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_INPUT); + AAudioStreamBuilder_setPerformanceMode(builder, mRequestedPerformanceMode); + AAudioStreamBuilder_setSharingMode(builder, mRequestedSharingMode); if (dataProc != nullptr) { - AAudioStreamBuilder_setDataCallback(mBuilder, dataProc, userContext); + AAudioStreamBuilder_setDataCallback(builder, dataProc, userContext); } if (errorProc != nullptr) { - AAudioStreamBuilder_setErrorCallback(mBuilder, errorProc, userContext); + AAudioStreamBuilder_setErrorCallback(builder, errorProc, userContext); } - AAudioStreamBuilder_setChannelCount(mBuilder, channelCount); - AAudioStreamBuilder_setSampleRate(mBuilder, sampSampleRate); - AAudioStreamBuilder_setFormat(mBuilder, format); + AAudioStreamBuilder_setChannelCount(builder, channelCount); + AAudioStreamBuilder_setSampleRate(builder, sampSampleRate); + AAudioStreamBuilder_setFormat(builder, format); // Open an AAudioStream using the Builder. - result = AAudioStreamBuilder_openStream(mBuilder, &mStream); + result = AAudioStreamBuilder_openStream(builder, &mStream); if (result != AAUDIO_OK) { fprintf(stderr, "ERROR - AAudioStreamBuilder_openStream() returned %d %s\n", result, AAudio_convertResultToText(result)); - goto finish1; } - printf("AAudioStream_getFramesPerBurst() = %d\n", - AAudioStream_getFramesPerBurst(mStream)); - printf("AAudioStream_getBufferSizeInFrames() = %d\n", - AAudioStream_getBufferSizeInFrames(mStream)); - printf("AAudioStream_getBufferCapacityInFrames() = %d\n", - AAudioStream_getBufferCapacityInFrames(mStream)); - return result; - - finish1: - AAudioStreamBuilder_delete(mBuilder); - mBuilder = nullptr; + AAudioStreamBuilder_delete(builder); return result; } @@ -132,8 +181,6 @@ public: printf("call AAudioStream_close(%p)\n", mStream); fflush(stdout); AAudioStream_close(mStream); mStream = nullptr; - AAudioStreamBuilder_delete(mBuilder); - mBuilder = nullptr; } return AAUDIO_OK; } @@ -186,7 +233,6 @@ public: } private: - AAudioStreamBuilder *mBuilder = nullptr; AAudioStream *mStream = nullptr; aaudio_sharing_mode_t mRequestedSharingMode = SHARING_MODE; aaudio_performance_mode_t mRequestedPerformanceMode = PERFORMANCE_MODE; diff --git a/media/libaaudio/examples/utils/dummy.cpp b/media/libaaudio/examples/utils/dummy.cpp new file mode 100644 index 0000000000..8ef7e36dcb --- /dev/null +++ b/media/libaaudio/examples/utils/dummy.cpp @@ -0,0 +1,5 @@ +/** + * Dummy file needed to get Android Studio to scan this folder. + */ + +int g_DoNotUseThisVariable = 0; diff --git a/media/libaaudio/examples/write_sine/jni/Android.mk b/media/libaaudio/examples/write_sine/jni/Android.mk index c306ed30bb..d630e76872 100644 --- a/media/libaaudio/examples/write_sine/jni/Android.mk +++ b/media/libaaudio/examples/write_sine/jni/Android.mk @@ -11,7 +11,7 @@ LOCAL_C_INCLUDES := \ # NDK recommends using this kind of relative path instead of an absolute path. LOCAL_SRC_FILES:= ../src/write_sine.cpp LOCAL_SHARED_LIBRARIES := libaaudio -LOCAL_MODULE := write_sine_ndk +LOCAL_MODULE := write_sine include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) @@ -23,7 +23,7 @@ LOCAL_C_INCLUDES := \ LOCAL_SRC_FILES:= ../src/write_sine_callback.cpp LOCAL_SHARED_LIBRARIES := libaaudio -LOCAL_MODULE := write_sine_callback_ndk +LOCAL_MODULE := write_sine_callback include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp index 6522ba4722..87fb40b16a 100644 --- a/media/libaaudio/examples/write_sine/src/write_sine.cpp +++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp @@ -16,46 +16,32 @@ // Play sine waves using AAudio. -#include <stdio.h> -#include <stdlib.h> -#include <math.h> #include <aaudio/AAudio.h> #include <aaudio/AAudioTesting.h> +#include <asm/fcntl.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + #include "AAudioExampleUtils.h" #include "AAudioSimplePlayer.h" +#include "AAudioArgsParser.h" -#define SAMPLE_RATE 48000 -#define NUM_SECONDS 20 - -#define MMAP_POLICY AAUDIO_UNSPECIFIED -//#define MMAP_POLICY AAUDIO_POLICY_NEVER -//#define MMAP_POLICY AAUDIO_POLICY_AUTO -//#define MMAP_POLICY AAUDIO_POLICY_ALWAYS - -#define REQUESTED_FORMAT AAUDIO_FORMAT_PCM_I16 +#define NUM_SECONDS 4 -#define REQUESTED_SHARING_MODE AAUDIO_SHARING_MODE_SHARED -//#define REQUESTED_SHARING_MODE AAUDIO_SHARING_MODE_EXCLUSIVE - - -int main(int argc, char **argv) +int main(int argc, const char **argv) { - (void)argc; // unused - + AAudioArgsParser argParser; AAudioSimplePlayer player; SineThreadedData_t myData; - aaudio_result_t result = AAUDIO_OK; + aaudio_result_t result = AAUDIO_OK; - const int requestedChannelCount = 2; - int actualChannelCount = 0; - const int requestedSampleRate = SAMPLE_RATE; - int actualSampleRate = 0; - aaudio_format_t requestedDataFormat = REQUESTED_FORMAT; + int32_t actualChannelCount = 0; + int32_t actualSampleRate = 0; aaudio_format_t actualDataFormat = AAUDIO_FORMAT_UNSPECIFIED; - aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED; AAudioStream *aaudioStream = nullptr; - aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED; int32_t framesPerBurst = 0; int32_t framesPerWrite = 0; int32_t bufferCapacity = 0; @@ -65,56 +51,38 @@ int main(int argc, char **argv) float *floatData = nullptr; int16_t *shortData = nullptr; + int testFd = -1; + // Make printf print immediately so that debug info is not stuck // in a buffer if we hang or crash. setvbuf(stdout, nullptr, _IONBF, (size_t) 0); - printf("%s - Play a sine wave using AAudio\n", argv[0]); + printf("%s - Play a sine wave using AAudio V0.1.1\n", argv[0]); - AAudio_setMMapPolicy(MMAP_POLICY); - printf("requested MMapPolicy = %d\n", AAudio_getMMapPolicy()); - - player.setSharingMode(REQUESTED_SHARING_MODE); + if (argParser.parseArgs(argc, argv)) { + return EXIT_FAILURE; + } - result = player.open(requestedChannelCount, requestedSampleRate, requestedDataFormat, - nullptr, nullptr, &myData); + result = player.open(argParser); if (result != AAUDIO_OK) { fprintf(stderr, "ERROR - player.open() returned %d\n", result); goto finish; } aaudioStream = player.getStream(); - // Request stream properties. - state = AAudioStream_getState(aaudioStream); - printf("after open, state = %s\n", AAudio_convertStreamStateToText(state)); + argParser.compareWithStream(aaudioStream); - // Check to see what kind of stream we actually got. + actualChannelCount = AAudioStream_getChannelCount(aaudioStream); actualSampleRate = AAudioStream_getSampleRate(aaudioStream); - printf("SampleRate: requested = %d, actual = %d\n", requestedSampleRate, actualSampleRate); + actualDataFormat = AAudioStream_getFormat(aaudioStream); myData.sineOsc1.setup(440.0, actualSampleRate); myData.sineOsc2.setup(660.0, actualSampleRate); - actualChannelCount = AAudioStream_getChannelCount(aaudioStream); - printf("ChannelCount: requested = %d, actual = %d\n", - requestedChannelCount, actualChannelCount); - - actualSharingMode = AAudioStream_getSharingMode(aaudioStream); - printf("SharingMode: requested = %s, actual = %s\n", - getSharingModeText(REQUESTED_SHARING_MODE), - getSharingModeText(actualSharingMode)); - - // This is the number of frames that are read in one chunk by a DMA controller - // or a DSP or a mixer. - framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream); - printf("Buffer: bufferSize = %d\n", AAudioStream_getBufferSizeInFrames(aaudioStream)); - bufferCapacity = AAudioStream_getBufferCapacityInFrames(aaudioStream); - printf("Buffer: bufferCapacity = %d, remainder = %d\n", - bufferCapacity, bufferCapacity % framesPerBurst); - // Some DMA might use very short bursts of 16 frames. We don't need to write such small // buffers. But it helps to use a multiple of the burst size for predictable scheduling. + framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream); framesPerWrite = framesPerBurst; while (framesPerWrite < 48) { framesPerWrite *= 2; @@ -122,13 +90,6 @@ int main(int argc, char **argv) printf("Buffer: framesPerBurst = %d\n",framesPerBurst); printf("Buffer: framesPerWrite = %d\n",framesPerWrite); - printf("PerformanceMode = %d\n", AAudioStream_getPerformanceMode(aaudioStream)); - printf("is MMAP used? = %s\n", AAudioStream_isMMapUsed(aaudioStream) ? "yes" : "no"); - - actualDataFormat = AAudioStream_getFormat(aaudioStream); - printf("DataFormat: requested = %d, actual = %d\n", REQUESTED_FORMAT, actualDataFormat); - // TODO handle other data formats - // Allocate a buffer for the audio data. if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) { floatData = new float[framesPerWrite * actualChannelCount]; @@ -139,6 +100,9 @@ int main(int argc, char **argv) goto finish; } + testFd = open("/data/aaudio_temp.raw", O_CREAT | O_RDWR, S_IRWXU); + printf("testFd = %d, pid = %d\n", testFd, getpid()); + // Start the stream. printf("call player.start()\n"); result = player.start(); @@ -147,11 +111,11 @@ int main(int argc, char **argv) goto finish; } - state = AAudioStream_getState(aaudioStream); - printf("after start, state = %s\n", AAudio_convertStreamStateToText(state)); + printf("after start, state = %s\n", + AAudio_convertStreamStateToText(AAudioStream_getState(aaudioStream))); // Play for a while. - framesToPlay = actualSampleRate * NUM_SECONDS; + framesToPlay = actualSampleRate * argParser.getDurationSeconds(); framesLeft = framesToPlay; while (framesLeft > 0) { @@ -220,7 +184,17 @@ int main(int argc, char **argv) } finish: + printf("testFd = %d, fcntl before aaudio close returns 0x%08X\n", + testFd, fcntl(testFd, F_GETFD)); player.close(); + printf("testFd = %d, fcntl after aaudio close returns 0x%08X\n", + testFd, fcntl(testFd, F_GETFD)); + if (::close(testFd) != 0) { + printf("ERROR SharedMemoryParcelable::close() of testFd = %d, errno = %s\n", + testFd, strerror(errno)); + } + printf("testFd = %d, fcntl after close() returns 0x%08X\n", testFd, fcntl(testFd, F_GETFD)); + delete[] floatData; delete[] shortData; printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result)); diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp index 69145aaa6d..b5602e97de 100644 --- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp +++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp @@ -26,37 +26,42 @@ #include <aaudio/AAudio.h> #include "AAudioExampleUtils.h" #include "AAudioSimplePlayer.h" +#include "../../utils/AAudioSimplePlayer.h" -#define NUM_SECONDS 5 - -// Application data that gets passed to the callback. -#define MAX_FRAME_COUNT_RECORDS 256 - -int main(int argc, char **argv) +int main(int argc, const char **argv) { - (void)argc; // unused + AAudioArgsParser argParser; AAudioSimplePlayer player; SineThreadedData_t myData; aaudio_result_t result; + int32_t actualSampleRate; // Make printf print immediately so that debug info is not stuck // in a buffer if we hang or crash. setvbuf(stdout, nullptr, _IONBF, (size_t) 0); - printf("%s - Play a sine sweep using an AAudio callback\n", argv[0]); + + printf("%s - Play a sine sweep using an AAudio callback V0.1.2\n", argv[0]); myData.schedulerChecked = false; + myData.forceUnderruns = false; // set true to test AAudioStream_getXRunCount() + + if (argParser.parseArgs(argc, argv)) { + return EXIT_FAILURE; + } - result = player.open(2, 44100, AAUDIO_FORMAT_PCM_FLOAT, + result = player.open(argParser, SimplePlayerDataCallbackProc, SimplePlayerErrorCallbackProc, &myData); if (result != AAUDIO_OK) { fprintf(stderr, "ERROR - player.open() returned %d\n", result); goto error; } - printf("player.getFramesPerSecond() = %d\n", player.getFramesPerSecond()); - printf("player.getChannelCount() = %d\n", player.getChannelCount()); - myData.sineOsc1.setup(440.0, 48000); + + argParser.compareWithStream(player.getStream()); + + actualSampleRate = player.getSampleRate(); + myData.sineOsc1.setup(440.0, actualSampleRate); myData.sineOsc1.setSweep(300.0, 600.0, 5.0); - myData.sineOsc2.setup(660.0, 48000); + myData.sineOsc2.setup(660.0, actualSampleRate); myData.sineOsc2.setSweep(350.0, 900.0, 7.0); #if 0 @@ -73,8 +78,9 @@ int main(int argc, char **argv) goto error; } - printf("Sleep for %d seconds while audio plays in a callback thread.\n", NUM_SECONDS); - for (int second = 0; second < NUM_SECONDS; second++) + printf("Sleep for %d seconds while audio plays in a callback thread.\n", + argParser.getDurationSeconds()); + for (int second = 0; second < argParser.getDurationSeconds(); second++) { const struct timespec request = { .tv_sec = 1, .tv_nsec = 0 }; (void) clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, &request, NULL /*remain*/); @@ -92,7 +98,10 @@ int main(int argc, char **argv) printf("Stream state is %d %s!\n", state, AAudio_convertStreamStateToText(state)); break; } - printf("framesWritten = %d\n", (int) AAudioStream_getFramesWritten(player.getStream())); + printf("framesWritten = %d, underruns = %d\n", + (int) AAudioStream_getFramesWritten(player.getStream()), + (int) AAudioStream_getXRunCount(player.getStream()) + ); } printf("Woke up now.\n"); @@ -113,6 +122,9 @@ int main(int argc, char **argv) SCHED_FIFO); } + printf("min numFrames = %8d\n", (int) myData.minNumFrames); + printf("max numFrames = %8d\n", (int) myData.maxNumFrames); + printf("SUCCESS\n"); return EXIT_SUCCESS; error: diff --git a/media/libaaudio/examples/write_sine/static/Android.mk b/media/libaaudio/examples/write_sine/static/Android.mk deleted file mode 100644 index 40dca3452c..0000000000 --- a/media/libaaudio/examples/write_sine/static/Android.mk +++ /dev/null @@ -1,38 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE_TAGS := examples -LOCAL_C_INCLUDES := \ - $(call include-path-for, audio-utils) \ - frameworks/av/media/libaaudio/src \ - frameworks/av/media/libaaudio/include \ - frameworks/av/media/libaaudio/examples/utils - -# NDK recommends using this kind of relative path instead of an absolute path. -LOCAL_SRC_FILES:= ../src/write_sine.cpp - -LOCAL_SHARED_LIBRARIES := libaudioutils libmedia \ - libbinder libcutils libutils \ - libaudioclient liblog libtinyalsa libaudiomanager -LOCAL_STATIC_LIBRARIES := libaaudio - -LOCAL_MODULE := write_sine -include $(BUILD_EXECUTABLE) - - -include $(CLEAR_VARS) -LOCAL_MODULE_TAGS := tests -LOCAL_C_INCLUDES := \ - $(call include-path-for, audio-utils) \ - frameworks/av/media/libaaudio/include \ - frameworks/av/media/libaaudio/examples/utils - -LOCAL_SRC_FILES:= ../src/write_sine_callback.cpp - -LOCAL_SHARED_LIBRARIES := libaudioutils libmedia \ - libbinder libcutils libutils \ - libaudioclient liblog libaudiomanager -LOCAL_STATIC_LIBRARIES := libaaudio - -LOCAL_MODULE := write_sine_callback -include $(BUILD_EXECUTABLE) diff --git a/media/libaaudio/examples/write_sine/static/README.md b/media/libaaudio/examples/write_sine/static/README.md deleted file mode 100644 index 6e26d7b3c5..0000000000 --- a/media/libaaudio/examples/write_sine/static/README.md +++ /dev/null @@ -1,2 +0,0 @@ -Makefile for building simple command line examples. -They link with AAudio as a static library. diff --git a/media/libaaudio/src/Android.mk b/media/libaaudio/src/Android.mk index 28c4d7f16f..cfcf27a37a 100644 --- a/media/libaaudio/src/Android.mk +++ b/media/libaaudio/src/Android.mk @@ -32,6 +32,7 @@ LOCAL_SRC_FILES = \ core/AudioStream.cpp \ core/AudioStreamBuilder.cpp \ core/AAudioAudio.cpp \ + core/AAudioStreamParameters.cpp \ legacy/AudioStreamLegacy.cpp \ legacy/AudioStreamRecord.cpp \ legacy/AudioStreamTrack.cpp \ @@ -52,6 +53,7 @@ LOCAL_SRC_FILES = \ binding/AAudioBinderClient.cpp \ binding/AAudioStreamRequest.cpp \ binding/AAudioStreamConfiguration.cpp \ + binding/IAAudioClient.cpp \ binding/IAAudioService.cpp \ binding/RingBufferParcelable.cpp \ binding/SharedMemoryParcelable.cpp \ @@ -89,6 +91,7 @@ LOCAL_C_INCLUDES := \ LOCAL_SRC_FILES = core/AudioStream.cpp \ core/AudioStreamBuilder.cpp \ core/AAudioAudio.cpp \ + core/AAudioStreamParameters.cpp \ legacy/AudioStreamLegacy.cpp \ legacy/AudioStreamRecord.cpp \ legacy/AudioStreamTrack.cpp \ @@ -109,6 +112,7 @@ LOCAL_SRC_FILES = core/AudioStream.cpp \ binding/AAudioBinderClient.cpp \ binding/AAudioStreamRequest.cpp \ binding/AAudioStreamConfiguration.cpp \ + binding/IAAudioClient.cpp \ binding/IAAudioService.cpp \ binding/RingBufferParcelable.cpp \ binding/SharedMemoryParcelable.cpp \ diff --git a/media/libaaudio/src/binding/AAudioBinderClient.cpp b/media/libaaudio/src/binding/AAudioBinderClient.cpp index 435b30fea6..a268e494a3 100644 --- a/media/libaaudio/src/binding/AAudioBinderClient.cpp +++ b/media/libaaudio/src/binding/AAudioBinderClient.cpp @@ -19,75 +19,104 @@ //#define LOG_NDEBUG 0 #include <utils/Log.h> +#include <binder/IInterface.h> #include <binder/IServiceManager.h> +#include <binder/ProcessState.h> #include <utils/Mutex.h> #include <utils/RefBase.h> #include <utils/Singleton.h> +#include <media/AudioSystem.h> #include <aaudio/AAudio.h> #include "AudioEndpointParcelable.h" -#include "binding/AAudioStreamRequest.h" -#include "binding/AAudioStreamConfiguration.h" -#include "binding/IAAudioService.h" -#include "binding/AAudioServiceMessage.h" +#include "binding/AAudioBinderClient.h" +//#include "binding/AAudioStreamRequest.h" +//#include "binding/AAudioStreamConfiguration.h" +//#include "binding/IAAudioService.h" +//#include "binding/AAudioServiceMessage.h" -#include "AAudioBinderClient.h" -#include "AAudioServiceInterface.h" +//#include "AAudioServiceInterface.h" using android::String16; using android::IServiceManager; using android::defaultServiceManager; using android::interface_cast; +using android::IInterface; using android::IAAudioService; using android::Mutex; using android::sp; +using android::wp; using namespace aaudio; -static android::Mutex gServiceLock; -static sp<IAAudioService> gAAudioService; - ANDROID_SINGLETON_STATIC_INSTANCE(AAudioBinderClient); +AAudioBinderClient::AAudioBinderClient() + : AAudioServiceInterface() + , Singleton<AAudioBinderClient>() { + + mAAudioClient = new AAudioClient(this); + ALOGV("AAudioBinderClient() created mAAudioClient = %p", mAAudioClient.get()); +} + +AAudioBinderClient::~AAudioBinderClient() { + Mutex::Autolock _l(mServiceLock); + if (mAAudioService != 0) { + IInterface::asBinder(mAAudioService)->unlinkToDeath(mAAudioClient); + } +} + // TODO Share code with other service clients. // Helper function to get access to the "AAudioService" service. // This code was modeled after frameworks/av/media/libaudioclient/AudioSystem.cpp -static const sp<IAAudioService> getAAudioService() { - sp<IBinder> binder; - Mutex::Autolock _l(gServiceLock); - if (gAAudioService == 0) { - sp<IServiceManager> sm = defaultServiceManager(); - // Try several times to get the service. - int retries = 4; - do { - binder = sm->getService(String16(AAUDIO_SERVICE_NAME)); // This will wait a while. +const sp<IAAudioService> AAudioBinderClient::getAAudioService() { + sp<IAAudioService> aaudioService; + bool needToRegister = false; + { + Mutex::Autolock _l(mServiceLock); + if (mAAudioService == 0) { + sp<IBinder> binder; + sp<IServiceManager> sm = defaultServiceManager(); + // Try several times to get the service. + int retries = 4; + do { + binder = sm->getService(String16(AAUDIO_SERVICE_NAME)); // This will wait a while. + if (binder != 0) { + break; + } + } while (retries-- > 0); + if (binder != 0) { - break; + // Ask for notification if the service dies. + status_t status = binder->linkToDeath(mAAudioClient); + // TODO review what we should do if this fails + if (status != NO_ERROR) { + ALOGE("getAAudioService: linkToDeath(mAAudioClient = %p) returned %d", + mAAudioClient.get(), status); + } + mAAudioService = interface_cast<IAAudioService>(binder); + needToRegister = true; + // Make sure callbacks can be received by mAAudioClient + android::ProcessState::self()->startThreadPool(); + } else { + ALOGE("AAudioBinderClient could not connect to %s", AAUDIO_SERVICE_NAME); } - } while (retries-- > 0); - - if (binder != 0) { - // TODO Add linkToDeath() like in frameworks/av/media/libaudioclient/AudioSystem.cpp - // TODO Create a DeathRecipient that disconnects all active streams. - gAAudioService = interface_cast<IAAudioService>(binder); - } else { - ALOGE("AudioStreamInternal could not get %s", AAUDIO_SERVICE_NAME); } + aaudioService = mAAudioService; } - return gAAudioService; + // Do this outside the mutex lock. + if (needToRegister && aaudioService != 0) { // new client? + aaudioService->registerClient(mAAudioClient); + } + return aaudioService; } -static void dropAAudioService() { - Mutex::Autolock _l(gServiceLock); - gAAudioService.clear(); // force a reconnect +void AAudioBinderClient::dropAAudioService() { + Mutex::Autolock _l(mServiceLock); + mAAudioService.clear(); // force a reconnect } -AAudioBinderClient::AAudioBinderClient() - : AAudioServiceInterface() - , Singleton<AAudioBinderClient>() {} - -AAudioBinderClient::~AAudioBinderClient() {} /** * @param request info needed to create the stream @@ -159,23 +188,19 @@ aaudio_result_t AAudioBinderClient::flushStream(aaudio_handle_t streamHandle) { * Manage the specified thread as a low latency audio thread. */ aaudio_result_t AAudioBinderClient::registerAudioThread(aaudio_handle_t streamHandle, - pid_t clientProcessId, pid_t clientThreadId, int64_t periodNanoseconds) { const sp<IAAudioService> &service = getAAudioService(); if (service == 0) return AAUDIO_ERROR_NO_SERVICE; return service->registerAudioThread(streamHandle, - clientProcessId, clientThreadId, periodNanoseconds); } aaudio_result_t AAudioBinderClient::unregisterAudioThread(aaudio_handle_t streamHandle, - pid_t clientProcessId, pid_t clientThreadId) { const sp<IAAudioService> &service = getAAudioService(); if (service == 0) return AAUDIO_ERROR_NO_SERVICE; return service->unregisterAudioThread(streamHandle, - clientProcessId, clientThreadId); } diff --git a/media/libaaudio/src/binding/AAudioBinderClient.h b/media/libaaudio/src/binding/AAudioBinderClient.h index e223376847..89ae85c2af 100644 --- a/media/libaaudio/src/binding/AAudioBinderClient.h +++ b/media/libaaudio/src/binding/AAudioBinderClient.h @@ -17,6 +17,7 @@ #ifndef ANDROID_AAUDIO_AAUDIO_BINDER_CLIENT_H #define ANDROID_AAUDIO_AAUDIO_BINDER_CLIENT_H +#include <utils/RefBase.h> #include <utils/Singleton.h> #include <aaudio/AAudio.h> @@ -25,14 +26,16 @@ #include "binding/AAudioStreamRequest.h" #include "binding/AAudioStreamConfiguration.h" #include "binding/AudioEndpointParcelable.h" +#include "binding/IAAudioService.h" /** - * Implements the AAudioServiceInterface by talking to the actual service through Binder. + * Implements the AAudioServiceInterface by talking to the service through Binder. */ namespace aaudio { -class AAudioBinderClient : public AAudioServiceInterface +class AAudioBinderClient : public virtual android::RefBase + , public AAudioServiceInterface , public android::Singleton<AAudioBinderClient> { public: @@ -41,6 +44,12 @@ public: virtual ~AAudioBinderClient(); + const android::sp<android::IAAudioService> getAAudioService(); + + void dropAAudioService(); + + void registerClient(const android::sp<android::IAAudioClient>& client __unused) override {} + /** * @param request info needed to create the stream * @param configuration contains resulting information about the created stream @@ -82,13 +91,61 @@ public: * TODO Consider passing this information as part of the startStream() call. */ aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle, - pid_t clientProcessId, pid_t clientThreadId, int64_t periodNanoseconds) override; aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle, - pid_t clientProcessId, pid_t clientThreadId) override; + + aaudio_result_t startClient(aaudio_handle_t streamHandle __unused, + const android::AudioClient& client __unused, + audio_port_handle_t *clientHandle) override { + return AAUDIO_ERROR_UNAVAILABLE; + } + + aaudio_result_t stopClient(aaudio_handle_t streamHandle __unused, + audio_port_handle_t clientHandle __unused) override { + return AAUDIO_ERROR_UNAVAILABLE; + } + + void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) { + // TODO This is just a stub so we can have a client Binder to pass to the service. + // TODO Implemented in a later CL. + ALOGW("onStreamChange called!"); + } + + class AAudioClient : public android::IBinder::DeathRecipient , public android::BnAAudioClient + { + public: + AAudioClient(android::wp<AAudioBinderClient> aaudioBinderClient) + : mBinderClient(aaudioBinderClient) { + } + + // implement DeathRecipient + virtual void binderDied(const android::wp<android::IBinder>& who __unused) { + android::sp<AAudioBinderClient> client = mBinderClient.promote(); + if (client != 0) { + client->dropAAudioService(); + } + ALOGW("AAudio service binderDied()!"); + } + + // implement BnAAudioClient + void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) { + android::sp<AAudioBinderClient> client = mBinderClient.promote(); + if (client != 0) { + client->onStreamChange(handle, opcode, value); + } + } + private: + android::wp<AAudioBinderClient> mBinderClient; + }; + + + android::Mutex mServiceLock; + android::sp<android::IAAudioService> mAAudioService; + android::sp<AAudioClient> mAAudioClient; + }; diff --git a/media/libaaudio/src/binding/AAudioServiceDefinitions.h b/media/libaaudio/src/binding/AAudioServiceDefinitions.h index 638544e253..8a2303c456 100644 --- a/media/libaaudio/src/binding/AAudioServiceDefinitions.h +++ b/media/libaaudio/src/binding/AAudioServiceDefinitions.h @@ -29,8 +29,9 @@ using android::IBinder; namespace android { -enum aaudio_commands_t { - OPEN_STREAM = IBinder::FIRST_CALL_TRANSACTION, +enum aaudio_service_commands_t { + REGISTER_CLIENT = IBinder::FIRST_CALL_TRANSACTION, + OPEN_STREAM, CLOSE_STREAM, GET_STREAM_DESCRIPTION, START_STREAM, @@ -41,6 +42,10 @@ enum aaudio_commands_t { UNREGISTER_AUDIO_THREAD }; +enum aaudio_client_commands_t { + ON_STREAM_CHANGE = IBinder::FIRST_CALL_TRANSACTION +}; + } // namespace android namespace aaudio { diff --git a/media/libaaudio/src/binding/AAudioServiceInterface.h b/media/libaaudio/src/binding/AAudioServiceInterface.h index 824e5bcee7..a64405b1da 100644 --- a/media/libaaudio/src/binding/AAudioServiceInterface.h +++ b/media/libaaudio/src/binding/AAudioServiceInterface.h @@ -17,10 +17,14 @@ #ifndef ANDROID_AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H #define ANDROID_AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H +#include <utils/StrongPointer.h> +#include <media/AudioClient.h> + #include "binding/AAudioServiceDefinitions.h" #include "binding/AAudioStreamRequest.h" #include "binding/AAudioStreamConfiguration.h" #include "binding/AudioEndpointParcelable.h" +#include "binding/IAAudioClient.h" /** * This has the same methods as IAAudioService but without the Binder features. @@ -36,6 +40,8 @@ public: AAudioServiceInterface() {}; virtual ~AAudioServiceInterface() = default; + virtual void registerClient(const android::sp<android::IAAudioClient>& client) = 0; + /** * @param request info needed to create the stream * @param configuration contains information about the created stream @@ -76,13 +82,18 @@ public: * Manage the specified thread as a low latency audio thread. */ virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle, - pid_t clientProcessId, pid_t clientThreadId, int64_t periodNanoseconds) = 0; virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle, - pid_t clientProcessId, pid_t clientThreadId) = 0; + + virtual aaudio_result_t startClient(aaudio_handle_t streamHandle, + const android::AudioClient& client, + audio_port_handle_t *clientHandle) = 0; + + virtual aaudio_result_t stopClient(aaudio_handle_t streamHandle, + audio_port_handle_t clientHandle) = 0; }; } /* namespace aaudio */ diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp index 44edb1dd2d..e7639347e9 100644 --- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp +++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp @@ -36,17 +36,17 @@ AAudioStreamConfiguration::~AAudioStreamConfiguration() {} status_t AAudioStreamConfiguration::writeToParcel(Parcel* parcel) const { status_t status; - status = parcel->writeInt32(mDeviceId); + status = parcel->writeInt32(getDeviceId()); if (status != NO_ERROR) goto error; - status = parcel->writeInt32(mSampleRate); + status = parcel->writeInt32(getSampleRate()); if (status != NO_ERROR) goto error; - status = parcel->writeInt32(mSamplesPerFrame); + status = parcel->writeInt32(getSamplesPerFrame()); if (status != NO_ERROR) goto error; - status = parcel->writeInt32((int32_t) mSharingMode); + status = parcel->writeInt32((int32_t) getSharingMode()); if (status != NO_ERROR) goto error; - status = parcel->writeInt32((int32_t) mAudioFormat); + status = parcel->writeInt32((int32_t) getFormat()); if (status != NO_ERROR) goto error; - status = parcel->writeInt32(mBufferCapacity); + status = parcel->writeInt32(getBufferCapacity()); if (status != NO_ERROR) goto error; return NO_ERROR; error: @@ -55,57 +55,27 @@ error: } status_t AAudioStreamConfiguration::readFromParcel(const Parcel* parcel) { - status_t status = parcel->readInt32(&mDeviceId); + int32_t value; + status_t status = parcel->readInt32(&value); if (status != NO_ERROR) goto error; - status = parcel->readInt32(&mSampleRate); + setDeviceId(value); + status = parcel->readInt32(&value); if (status != NO_ERROR) goto error; - status = parcel->readInt32(&mSamplesPerFrame); + setSampleRate(value); + status = parcel->readInt32(&value); if (status != NO_ERROR) goto error; - status = parcel->readInt32(&mSharingMode); + setSamplesPerFrame(value); + status = parcel->readInt32(&value); if (status != NO_ERROR) goto error; - status = parcel->readInt32(&mAudioFormat); + setSharingMode(value); + status = parcel->readInt32(&value); if (status != NO_ERROR) goto error; - status = parcel->readInt32(&mBufferCapacity); + setFormat(value); + status = parcel->readInt32(&value); if (status != NO_ERROR) goto error; + setBufferCapacity(value); return NO_ERROR; error: ALOGE("AAudioStreamConfiguration.readFromParcel(): read failed = %d", status); return status; -} - -aaudio_result_t AAudioStreamConfiguration::validate() const { - // Validate results of the open. - if (mSampleRate < 0 || mSampleRate >= 8 * 48000) { // TODO review limits - ALOGE("AAudioStreamConfiguration.validate(): invalid sampleRate = %d", mSampleRate); - return AAUDIO_ERROR_INTERNAL; - } - - if (mSamplesPerFrame < 1 || mSamplesPerFrame >= 32) { // TODO review limits - ALOGE("AAudioStreamConfiguration.validate() invalid samplesPerFrame = %d", mSamplesPerFrame); - return AAUDIO_ERROR_INTERNAL; - } - - switch (mAudioFormat) { - case AAUDIO_FORMAT_PCM_I16: - case AAUDIO_FORMAT_PCM_FLOAT: - break; - default: - ALOGE("AAudioStreamConfiguration.validate() invalid audioFormat = %d", mAudioFormat); - return AAUDIO_ERROR_INTERNAL; - } - - if (mBufferCapacity < 0) { - ALOGE("AAudioStreamConfiguration.validate() invalid mBufferCapacity = %d", mBufferCapacity); - return AAUDIO_ERROR_INTERNAL; - } - return AAUDIO_OK; -} - -void AAudioStreamConfiguration::dump() const { - ALOGD("AAudioStreamConfiguration mDeviceId = %d", mDeviceId); - ALOGD("AAudioStreamConfiguration mSampleRate = %d", mSampleRate); - ALOGD("AAudioStreamConfiguration mSamplesPerFrame = %d", mSamplesPerFrame); - ALOGD("AAudioStreamConfiguration mSharingMode = %d", (int)mSharingMode); - ALOGD("AAudioStreamConfiguration mAudioFormat = %d", (int)mAudioFormat); - ALOGD("AAudioStreamConfiguration mBufferCapacity = %d", mBufferCapacity); -} +}
\ No newline at end of file diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.h b/media/libaaudio/src/binding/AAudioStreamConfiguration.h index 144595ae83..b324896118 100644 --- a/media/libaaudio/src/binding/AAudioStreamConfiguration.h +++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.h @@ -22,6 +22,7 @@ #include <aaudio/AAudio.h> #include <binder/Parcel.h> #include <binder/Parcelable.h> +#include "core/AAudioStreamParameters.h" using android::status_t; using android::Parcel; @@ -29,74 +30,14 @@ using android::Parcelable; namespace aaudio { -class AAudioStreamConfiguration : public Parcelable { +class AAudioStreamConfiguration : public AAudioStreamParameters, public Parcelable { public: AAudioStreamConfiguration(); virtual ~AAudioStreamConfiguration(); - int32_t getDeviceId() const { - return mDeviceId; - } - - void setDeviceId(int32_t deviceId) { - mDeviceId = deviceId; - } - - int32_t getSampleRate() const { - return mSampleRate; - } - - void setSampleRate(int32_t sampleRate) { - mSampleRate = sampleRate; - } - - int32_t getSamplesPerFrame() const { - return mSamplesPerFrame; - } - - void setSamplesPerFrame(int32_t samplesPerFrame) { - mSamplesPerFrame = samplesPerFrame; - } - - aaudio_format_t getAudioFormat() const { - return mAudioFormat; - } - - void setAudioFormat(aaudio_format_t audioFormat) { - mAudioFormat = audioFormat; - } - - aaudio_sharing_mode_t getSharingMode() const { - return mSharingMode; - } - - void setSharingMode(aaudio_sharing_mode_t sharingMode) { - mSharingMode = sharingMode; - } - - int32_t getBufferCapacity() const { - return mBufferCapacity; - } - - void setBufferCapacity(int32_t frames) { - mBufferCapacity = frames; - } - virtual status_t writeToParcel(Parcel* parcel) const override; virtual status_t readFromParcel(const Parcel* parcel) override; - - aaudio_result_t validate() const; - - void dump() const; - -private: - int32_t mDeviceId = AAUDIO_UNSPECIFIED; - int32_t mSampleRate = AAUDIO_UNSPECIFIED; - int32_t mSamplesPerFrame = AAUDIO_UNSPECIFIED; - aaudio_sharing_mode_t mSharingMode = AAUDIO_SHARING_MODE_SHARED; - aaudio_format_t mAudioFormat = AAUDIO_FORMAT_UNSPECIFIED; - int32_t mBufferCapacity = AAUDIO_UNSPECIFIED; }; } /* namespace aaudio */ diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.cpp b/media/libaaudio/src/binding/AAudioStreamRequest.cpp index a5c27b90a8..abdcf5b594 100644 --- a/media/libaaudio/src/binding/AAudioStreamRequest.cpp +++ b/media/libaaudio/src/binding/AAudioStreamRequest.cpp @@ -45,16 +45,19 @@ AAudioStreamRequest::~AAudioStreamRequest() {} status_t AAudioStreamRequest::writeToParcel(Parcel* parcel) const { status_t status = parcel->writeInt32((int32_t) mUserId); if (status != NO_ERROR) goto error; - status = parcel->writeInt32((int32_t) mProcessId); - if (status != NO_ERROR) goto error; + status = parcel->writeInt32((int32_t) mDirection); if (status != NO_ERROR) goto error; status = parcel->writeBool(mSharingModeMatchRequired); if (status != NO_ERROR) goto error; + status = parcel->writeBool(mInService); + if (status != NO_ERROR) goto error; + status = mConfiguration.writeToParcel(parcel); if (status != NO_ERROR) goto error; + return NO_ERROR; error: @@ -70,17 +73,17 @@ status_t AAudioStreamRequest::readFromParcel(const Parcel* parcel) { status = parcel->readInt32(&temp); if (status != NO_ERROR) goto error; - mProcessId = (pid_t) temp; - - status = parcel->readInt32(&temp); - if (status != NO_ERROR) goto error; mDirection = (aaudio_direction_t) temp; status = parcel->readBool(&mSharingModeMatchRequired); if (status != NO_ERROR) goto error; + status = parcel->readBool(&mInService); + if (status != NO_ERROR) goto error; + status = mConfiguration.readFromParcel(parcel); if (status != NO_ERROR) goto error; + return NO_ERROR; error: @@ -96,5 +99,7 @@ void AAudioStreamRequest::dump() const { ALOGD("AAudioStreamRequest mUserId = %d", mUserId); ALOGD("AAudioStreamRequest mProcessId = %d", mProcessId); ALOGD("AAudioStreamRequest mDirection = %d", mDirection); + ALOGD("AAudioStreamRequest mSharingModeMatchRequired = %d", mSharingModeMatchRequired); + ALOGD("AAudioStreamRequest mInService = %d", mInService); mConfiguration.dump(); } diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.h b/media/libaaudio/src/binding/AAudioStreamRequest.h index 77138da814..b0fa96a8ad 100644 --- a/media/libaaudio/src/binding/AAudioStreamRequest.h +++ b/media/libaaudio/src/binding/AAudioStreamRequest.h @@ -68,7 +68,6 @@ public: mSharingModeMatchRequired = required; } - const AAudioStreamConfiguration &getConstantConfiguration() const { return mConfiguration; } @@ -77,6 +76,14 @@ public: return mConfiguration; } + bool isInService() const { + return mInService; + } + + void setInService(bool inService) { + mInService = inService; + } + virtual status_t writeToParcel(Parcel* parcel) const override; virtual status_t readFromParcel(const Parcel* parcel) override; @@ -91,6 +98,7 @@ protected: pid_t mProcessId; aaudio_direction_t mDirection; bool mSharingModeMatchRequired = false; + bool mInService = false; // Stream opened by AAudioservice }; } /* namespace aaudio */ diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp index d05abb030d..1a97555dfb 100644 --- a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp +++ b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp @@ -28,6 +28,7 @@ #include "binding/RingBufferParcelable.h" #include "binding/AudioEndpointParcelable.h" +using android::base::unique_fd; using android::NO_ERROR; using android::status_t; using android::Parcel; @@ -49,7 +50,8 @@ AudioEndpointParcelable::~AudioEndpointParcelable() {} * Add the file descriptor to the table. * @return index in table or negative error */ -int32_t AudioEndpointParcelable::addFileDescriptor(int fd, int32_t sizeInBytes) { +int32_t AudioEndpointParcelable::addFileDescriptor(const unique_fd& fd, + int32_t sizeInBytes) { if (mNumSharedMemories >= MAX_SHARED_MEMORIES) { return AAUDIO_ERROR_OUT_OF_RANGE; } diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.h b/media/libaaudio/src/binding/AudioEndpointParcelable.h index 993075c702..aa8573fa4d 100644 --- a/media/libaaudio/src/binding/AudioEndpointParcelable.h +++ b/media/libaaudio/src/binding/AudioEndpointParcelable.h @@ -20,6 +20,7 @@ #include <stdint.h> //#include <sys/mman.h> +#include <android-base/unique_fd.h> #include <binder/Parcel.h> #include <binder/Parcelable.h> @@ -47,7 +48,7 @@ public: * Add the file descriptor to the table. * @return index in table or negative error */ - int32_t addFileDescriptor(int fd, int32_t sizeInBytes); + int32_t addFileDescriptor(const android::base::unique_fd& fd, int32_t sizeInBytes); virtual status_t writeToParcel(Parcel* parcel) const override; diff --git a/media/libaaudio/src/binding/IAAudioClient.cpp b/media/libaaudio/src/binding/IAAudioClient.cpp new file mode 100644 index 0000000000..c69c4e8e0f --- /dev/null +++ b/media/libaaudio/src/binding/IAAudioClient.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AAudio" +//#define LOG_NDEBUG 0 +#include <utils/Log.h> + +#include <aaudio/AAudio.h> + +#include "binding/AAudioBinderClient.h" +#include "binding/AAudioServiceDefinitions.h" +#include "binding/IAAudioClient.h" +#include "utility/AAudioUtilities.h" + +namespace android { + +using aaudio::aaudio_handle_t; + +/** + * This is used by the AAudio Service to talk to an AAudio Client. + * + * The order of parameters in the Parcels must match with code in AAudioClient.cpp. + */ +class BpAAudioClient : public BpInterface<IAAudioClient> +{ +public: + explicit BpAAudioClient(const sp<IBinder>& impl) + : BpInterface<IAAudioClient>(impl) + { + } + + void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) override { + Parcel data, reply; + data.writeInterfaceToken(IAAudioClient::getInterfaceDescriptor()); + data.writeInt32(handle); + data.writeInt32(opcode); + data.writeInt32(value); + remote()->transact(ON_STREAM_CHANGE, data, &reply, IBinder::FLAG_ONEWAY); + } + +}; + +// Implement an interface to the service. +IMPLEMENT_META_INTERFACE(AAudioClient, "IAAudioClient"); + +// The order of parameters in the Parcels must match with code in BpAAudioClient + +status_t BnAAudioClient::onTransact(uint32_t code, const Parcel& data, + Parcel* reply, uint32_t flags) { + aaudio_handle_t streamHandle; + int32_t opcode = 0; + int32_t value = 0; + ALOGV("BnAAudioClient::onTransact(%u) %u", code, flags); + + switch(code) { + case ON_STREAM_CHANGE: { + CHECK_INTERFACE(IAAudioClient, data, reply); + data.readInt32(&streamHandle); + data.readInt32(&opcode); + data.readInt32(&value); + onStreamChange(streamHandle, opcode, value); + ALOGD("BnAAudioClient onStreamChange(%x, %d, %d)", streamHandle, opcode, value); + return NO_ERROR; + } break; + + default: + // ALOGW("BnAAudioClient::onTransact not handled %u", code); + return BBinder::onTransact(code, data, reply, flags); + } +} + +} /* namespace android */ diff --git a/media/libaaudio/src/binding/IAAudioClient.h b/media/libaaudio/src/binding/IAAudioClient.h new file mode 100644 index 0000000000..21cc33b616 --- /dev/null +++ b/media/libaaudio/src/binding/IAAudioClient.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_AAUDIO_IAAUDIO_CLIENT_H +#define ANDROID_AAUDIO_IAAUDIO_CLIENT_H + +#include <stdint.h> +#include <binder/IInterface.h> + +#include <aaudio/AAudio.h> + +#include "utility/HandleTracker.h" + +namespace android { + + +// Interface (our AIDL) - client methods called by service +class IAAudioClient : public IInterface { +public: + + DECLARE_META_INTERFACE(AAudioClient); + + virtual void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) = 0; + +}; + +class BnAAudioClient : public BnInterface<IAAudioClient> { +public: + virtual status_t onTransact(uint32_t code, const Parcel& data, + Parcel* reply, uint32_t flags = 0); +}; + +} /* namespace android */ + +#endif //ANDROID_AAUDIO_IAAUDIO_SERVICE_H diff --git a/media/libaaudio/src/binding/IAAudioService.cpp b/media/libaaudio/src/binding/IAAudioService.cpp index b8ef611781..b3c4934daf 100644 --- a/media/libaaudio/src/binding/IAAudioService.cpp +++ b/media/libaaudio/src/binding/IAAudioService.cpp @@ -14,7 +14,12 @@ * limitations under the License. */ +#define LOG_TAG "AAudio" +//#define LOG_NDEBUG 0 +#include <utils/Log.h> + #include <aaudio/AAudio.h> +#include <binder/IPCThreadState.h> #include "binding/AudioEndpointParcelable.h" #include "binding/AAudioStreamRequest.h" @@ -40,16 +45,22 @@ public: { } - virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request, - aaudio::AAudioStreamConfiguration &configurationOutput) override { + void registerClient(const sp<IAAudioClient>& client) override + { + Parcel data, reply; + data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor()); + data.writeStrongBinder(IInterface::asBinder(client)); + remote()->transact(REGISTER_CLIENT, data, &reply); + } + + aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request, + aaudio::AAudioStreamConfiguration &configurationOutput) override { Parcel data, reply; // send command data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor()); - ALOGV("BpAAudioService::client openStream --------------------"); // request.dump(); request.writeToParcel(&data); status_t err = remote()->transact(OPEN_STREAM, data, &reply); - ALOGV("BpAAudioService::client openStream returned %d", err); if (err != NO_ERROR) { ALOGE("BpAAudioService::client openStream transact failed %d", err); return AAudioConvert_androidToAAudioResult(err); @@ -186,15 +197,13 @@ public: } virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle, - pid_t clientProcessId, - pid_t clientThreadId, - int64_t periodNanoseconds) + pid_t clientThreadId, + int64_t periodNanoseconds) override { Parcel data, reply; // send command data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor()); data.writeInt32(streamHandle); - data.writeInt32((int32_t) clientProcessId); data.writeInt32((int32_t) clientThreadId); data.writeInt64(periodNanoseconds); status_t err = remote()->transact(REGISTER_AUDIO_THREAD, data, &reply); @@ -208,14 +217,12 @@ public: } virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle, - pid_t clientProcessId, pid_t clientThreadId) override { Parcel data, reply; // send command data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor()); data.writeInt32(streamHandle); - data.writeInt32((int32_t) clientProcessId); data.writeInt32((int32_t) clientThreadId); status_t err = remote()->transact(UNREGISTER_AUDIO_THREAD, data, &reply); if (err != NO_ERROR) { @@ -237,43 +244,59 @@ IMPLEMENT_META_INTERFACE(AAudioService, "IAAudioService"); status_t BnAAudioService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { - aaudio_handle_t stream; + aaudio_handle_t streamHandle; aaudio::AAudioStreamRequest request; aaudio::AAudioStreamConfiguration configuration; - pid_t pid; pid_t tid; int64_t nanoseconds; aaudio_result_t result; ALOGV("BnAAudioService::onTransact(%i) %i", code, flags); - data.checkInterface(this); switch(code) { + case REGISTER_CLIENT: { + CHECK_INTERFACE(IAAudioService, data, reply); + sp<IAAudioClient> client = interface_cast<IAAudioClient>( + data.readStrongBinder()); + registerClient(client); + return NO_ERROR; + } break; + case OPEN_STREAM: { + CHECK_INTERFACE(IAAudioService, data, reply); request.readFromParcel(&data); - - //ALOGD("BnAAudioService::client openStream request dump --------------------"); - //request.dump(); - - stream = openStream(request, configuration); - //ALOGD("BnAAudioService::onTransact OPEN_STREAM server handle = 0x%08X", stream); - reply->writeInt32(stream); + result = request.validate(); + if (result != AAUDIO_OK) { + streamHandle = result; + } else { + //ALOGD("BnAAudioService::client openStream request dump --------------------"); + //request.dump(); + // Override the uid and pid from the client in case they are incorrect. + request.setUserId(IPCThreadState::self()->getCallingUid()); + request.setProcessId(IPCThreadState::self()->getCallingPid()); + streamHandle = openStream(request, configuration); + //ALOGD("BnAAudioService::onTransact OPEN_STREAM server handle = 0x%08X", + // streamHandle); + } + reply->writeInt32(streamHandle); configuration.writeToParcel(reply); return NO_ERROR; } break; case CLOSE_STREAM: { - data.readInt32(&stream); - result = closeStream(stream); + CHECK_INTERFACE(IAAudioService, data, reply); + data.readInt32(&streamHandle); + result = closeStream(streamHandle); //ALOGD("BnAAudioService::onTransact CLOSE_STREAM 0x%08X, result = %d", - // stream, result); + // streamHandle, result); reply->writeInt32(result); return NO_ERROR; } break; case GET_STREAM_DESCRIPTION: { - data.readInt32(&stream); + CHECK_INTERFACE(IAAudioService, data, reply); + data.readInt32(&streamHandle); aaudio::AudioEndpointParcelable parcelable; - result = getStreamDescription(stream, parcelable); + result = getStreamDescription(streamHandle, parcelable); if (result != AAUDIO_OK) { return AAudioConvert_aaudioToAndroidStatus(result); } @@ -289,60 +312,64 @@ status_t BnAAudioService::onTransact(uint32_t code, const Parcel& data, } break; case START_STREAM: { - data.readInt32(&stream); - result = startStream(stream); + CHECK_INTERFACE(IAAudioService, data, reply); + data.readInt32(&streamHandle); + result = startStream(streamHandle); ALOGV("BnAAudioService::onTransact START_STREAM 0x%08X, result = %d", - stream, result); + streamHandle, result); reply->writeInt32(result); return NO_ERROR; } break; case PAUSE_STREAM: { - data.readInt32(&stream); - result = pauseStream(stream); + CHECK_INTERFACE(IAAudioService, data, reply); + data.readInt32(&streamHandle); + result = pauseStream(streamHandle); ALOGV("BnAAudioService::onTransact PAUSE_STREAM 0x%08X, result = %d", - stream, result); + streamHandle, result); reply->writeInt32(result); return NO_ERROR; } break; case STOP_STREAM: { - data.readInt32(&stream); - result = stopStream(stream); + CHECK_INTERFACE(IAAudioService, data, reply); + data.readInt32(&streamHandle); + result = stopStream(streamHandle); ALOGV("BnAAudioService::onTransact STOP_STREAM 0x%08X, result = %d", - stream, result); + streamHandle, result); reply->writeInt32(result); return NO_ERROR; } break; case FLUSH_STREAM: { - data.readInt32(&stream); - result = flushStream(stream); + CHECK_INTERFACE(IAAudioService, data, reply); + data.readInt32(&streamHandle); + result = flushStream(streamHandle); ALOGV("BnAAudioService::onTransact FLUSH_STREAM 0x%08X, result = %d", - stream, result); + streamHandle, result); reply->writeInt32(result); return NO_ERROR; } break; case REGISTER_AUDIO_THREAD: { - data.readInt32(&stream); - data.readInt32(&pid); + CHECK_INTERFACE(IAAudioService, data, reply); + data.readInt32(&streamHandle); data.readInt32(&tid); data.readInt64(&nanoseconds); - result = registerAudioThread(stream, pid, tid, nanoseconds); + result = registerAudioThread(streamHandle, tid, nanoseconds); ALOGV("BnAAudioService::onTransact REGISTER_AUDIO_THREAD 0x%08X, result = %d", - stream, result); + streamHandle, result); reply->writeInt32(result); return NO_ERROR; } break; case UNREGISTER_AUDIO_THREAD: { - data.readInt32(&stream); - data.readInt32(&pid); + CHECK_INTERFACE(IAAudioService, data, reply); + data.readInt32(&streamHandle); data.readInt32(&tid); - result = unregisterAudioThread(stream, pid, tid); + result = unregisterAudioThread(streamHandle, tid); ALOGV("BnAAudioService::onTransact UNREGISTER_AUDIO_THREAD 0x%08X, result = %d", - stream, result); + streamHandle, result); reply->writeInt32(result); return NO_ERROR; } break; diff --git a/media/libaaudio/src/binding/IAAudioService.h b/media/libaaudio/src/binding/IAAudioService.h index 44a5e12cf1..30b3eadd4e 100644 --- a/media/libaaudio/src/binding/IAAudioService.h +++ b/media/libaaudio/src/binding/IAAudioService.h @@ -28,18 +28,24 @@ #include "binding/AudioEndpointParcelable.h" #include "binding/AAudioStreamRequest.h" #include "binding/AAudioStreamConfiguration.h" +#include "binding/IAAudioClient.h" #include "utility/HandleTracker.h" namespace android { #define AAUDIO_SERVICE_NAME "media.aaudio" -// Interface (our AIDL) - Shared by server and client +// Interface (our AIDL) - service methods called by client class IAAudioService : public IInterface { public: DECLARE_META_INTERFACE(AAudioService); + // Register an object to receive audio input/output change and track notifications. + // For a given calling pid, AAudio service disregards any registrations after the first. + // Thus the IAAudioClient must be a singleton per process. + virtual void registerClient(const sp<IAAudioClient>& client) = 0; + /** * @param request info needed to create the stream * @param configuration contains information about the created stream @@ -82,15 +88,12 @@ public: /** * Manage the specified thread as a low latency audio thread. - * TODO Consider passing this information as part of the startStream() call. */ virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle, - pid_t clientProcessId, pid_t clientThreadId, int64_t periodNanoseconds) = 0; virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle, - pid_t clientProcessId, pid_t clientThreadId) = 0; }; diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp index 899eb043dd..90217abd6b 100644 --- a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp +++ b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp @@ -24,11 +24,13 @@ #include <sys/mman.h> #include <aaudio/AAudio.h> +#include <android-base/unique_fd.h> #include <binder/Parcelable.h> #include <utility/AAudioUtilities.h> #include "binding/SharedMemoryParcelable.h" +using android::base::unique_fd; using android::NO_ERROR; using android::status_t; using android::Parcel; @@ -39,17 +41,19 @@ using namespace aaudio; SharedMemoryParcelable::SharedMemoryParcelable() {} SharedMemoryParcelable::~SharedMemoryParcelable() {}; -void SharedMemoryParcelable::setup(int fd, int32_t sizeInBytes) { - mFd = fd; +void SharedMemoryParcelable::setup(const unique_fd& fd, int32_t sizeInBytes) { + mFd.reset(dup(fd.get())); // store a duplicate fd + ALOGV("SharedMemoryParcelable::setup(%d -> %d, %d) this = %p\n", + fd.get(), mFd.get(), sizeInBytes, this); mSizeInBytes = sizeInBytes; - } status_t SharedMemoryParcelable::writeToParcel(Parcel* parcel) const { status_t status = parcel->writeInt32(mSizeInBytes); if (status != NO_ERROR) return status; if (mSizeInBytes > 0) { - status = parcel->writeDupFileDescriptor(mFd); + ALOGV("SharedMemoryParcelable::writeToParcel() mFd = %d, this = %p\n", mFd.get(), this); + status = parcel->writeUniqueFileDescriptor(mFd); ALOGE_IF(status != NO_ERROR, "SharedMemoryParcelable writeDupFileDescriptor failed : %d", status); } @@ -62,15 +66,16 @@ status_t SharedMemoryParcelable::readFromParcel(const Parcel* parcel) { return status; } if (mSizeInBytes > 0) { - // Keep the original FD until you are done with the mFd. - // If you close it in here then it will prevent mFd from working. - mOriginalFd = parcel->readFileDescriptor(); - ALOGV("SharedMemoryParcelable::readFromParcel() LEAK? mOriginalFd = %d\n", mOriginalFd); - mFd = fcntl(mOriginalFd, F_DUPFD_CLOEXEC, 0); - ALOGV("SharedMemoryParcelable::readFromParcel() LEAK? mFd = %d\n", mFd); - if (mFd == -1) { - status = -errno; - ALOGE("SharedMemoryParcelable readFromParcel fcntl() failed : %d", status); + // The Parcel owns the file descriptor and will close it later. + unique_fd mmapFd; + status = parcel->readUniqueFileDescriptor(&mmapFd); + if (status != NO_ERROR) { + ALOGE("SharedMemoryParcelable::readFromParcel() readUniqueFileDescriptor() failed : %d", + status); + } else { + // Resolve the memory now while we still have the FD from the Parcel. + // Closing the FD will not affect the shared memory once mmap() has been called. + status = AAudioConvert_androidToAAudioResult(resolveSharedMemory(mmapFd)); } } return status; @@ -85,45 +90,50 @@ aaudio_result_t SharedMemoryParcelable::close() { } mResolvedAddress = MMAP_UNRESOLVED_ADDRESS; } - if (mFd != -1) { - ALOGV("SharedMemoryParcelable::close() LEAK? mFd = %d\n", mFd); - ::close(mFd); - mFd = -1; - } - if (mOriginalFd != -1) { - ALOGV("SharedMemoryParcelable::close() LEAK? mOriginalFd = %d\n", mOriginalFd); - ::close(mOriginalFd); - mOriginalFd = -1; + return AAUDIO_OK; +} + +aaudio_result_t SharedMemoryParcelable::resolveSharedMemory(const unique_fd& fd) { + mResolvedAddress = (uint8_t *) mmap(0, mSizeInBytes, PROT_READ | PROT_WRITE, + MAP_SHARED, fd.get(), 0); + if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) { + ALOGE("SharedMemoryParcelable mmap() failed for fd = %d, errno = %s", + fd.get(), strerror(errno)); + return AAUDIO_ERROR_INTERNAL; } return AAUDIO_OK; } aaudio_result_t SharedMemoryParcelable::resolve(int32_t offsetInBytes, int32_t sizeInBytes, void **regionAddressPtr) { - if (offsetInBytes < 0) { ALOGE("SharedMemoryParcelable illegal offsetInBytes = %d", offsetInBytes); return AAUDIO_ERROR_OUT_OF_RANGE; } else if ((offsetInBytes + sizeInBytes) > mSizeInBytes) { ALOGE("SharedMemoryParcelable out of range, offsetInBytes = %d, " - "sizeInBytes = %d, mSizeInBytes = %d", + "sizeInBytes = %d, mSizeInBytes = %d", offsetInBytes, sizeInBytes, mSizeInBytes); return AAUDIO_ERROR_OUT_OF_RANGE; } + + aaudio_result_t result = AAUDIO_OK; + if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) { - mResolvedAddress = (uint8_t *) mmap(0, mSizeInBytes, PROT_READ|PROT_WRITE, - MAP_SHARED, mFd, 0); - if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) { - ALOGE("SharedMemoryParcelable mmap failed for fd = %d, errno = %s", - mFd, strerror(errno)); - return AAUDIO_ERROR_INTERNAL; + if (mFd.get() != -1) { + result = resolveSharedMemory(mFd); + } else { + ALOGE("SharedMemoryParcelable has no file descriptor for shared memory."); + result = AAUDIO_ERROR_INTERNAL; } } - *regionAddressPtr = mResolvedAddress + offsetInBytes; - ALOGV("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress); - ALOGV("SharedMemoryParcelable offset by %d, *regionAddressPtr = %p", - offsetInBytes, *regionAddressPtr); - return AAUDIO_OK; + + if (result == AAUDIO_OK && mResolvedAddress != MMAP_UNRESOLVED_ADDRESS) { + *regionAddressPtr = mResolvedAddress + offsetInBytes; + ALOGV("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress); + ALOGV("SharedMemoryParcelable offset by %d, *regionAddressPtr = %p", + offsetInBytes, *regionAddressPtr); + } + return result; } int32_t SharedMemoryParcelable::getSizeInBytes() { @@ -135,17 +145,11 @@ aaudio_result_t SharedMemoryParcelable::validate() { ALOGE("SharedMemoryParcelable invalid mSizeInBytes = %d", mSizeInBytes); return AAUDIO_ERROR_OUT_OF_RANGE; } - if (mSizeInBytes > 0) { - if (mFd == -1) { - ALOGE("SharedMemoryParcelable uninitialized mFd = %d", mFd); - return AAUDIO_ERROR_INTERNAL; - } - } return AAUDIO_OK; } void SharedMemoryParcelable::dump() { - ALOGD("SharedMemoryParcelable mFd = %d", mFd); + ALOGD("SharedMemoryParcelable mFd = %d", mFd.get()); ALOGD("SharedMemoryParcelable mSizeInBytes = %d", mSizeInBytes); ALOGD("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress); } diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.h b/media/libaaudio/src/binding/SharedMemoryParcelable.h index 4b94b462b7..2a634e043a 100644 --- a/media/libaaudio/src/binding/SharedMemoryParcelable.h +++ b/media/libaaudio/src/binding/SharedMemoryParcelable.h @@ -18,15 +18,12 @@ #define ANDROID_AAUDIO_SHARED_MEMORY_PARCELABLE_H #include <stdint.h> - #include <sys/mman.h> + +#include <android-base/unique_fd.h> #include <binder/Parcel.h> #include <binder/Parcelable.h> -using android::status_t; -using android::Parcel; -using android::Parcelable; - namespace aaudio { // Arbitrary limits for sanity checks. TODO remove after debugging. @@ -37,17 +34,24 @@ namespace aaudio { /** * This is a parcelable description of a shared memory referenced by a file descriptor. * It may be divided into several regions. + * The memory can be shared using Binder or simply shared between threads. */ -class SharedMemoryParcelable : public Parcelable { +class SharedMemoryParcelable : public android::Parcelable { public: SharedMemoryParcelable(); virtual ~SharedMemoryParcelable(); - void setup(int fd, int32_t sizeInBytes); + /** + * Make a dup() of the fd and store it for later use. + * + * @param fd + * @param sizeInBytes + */ + void setup(const android::base::unique_fd& fd, int32_t sizeInBytes); - virtual status_t writeToParcel(Parcel* parcel) const override; + virtual android::status_t writeToParcel(android::Parcel* parcel) const override; - virtual status_t readFromParcel(const Parcel* parcel) override; + virtual android::status_t readFromParcel(const android::Parcel* parcel) override; // mmap() shared memory aaudio_result_t resolve(int32_t offsetInBytes, int32_t sizeInBytes, void **regionAddressPtr); @@ -55,8 +59,6 @@ public: // munmap() any mapped memory aaudio_result_t close(); - bool isFileDescriptorSafe(); - int32_t getSizeInBytes(); aaudio_result_t validate(); @@ -67,10 +69,11 @@ protected: #define MMAP_UNRESOLVED_ADDRESS reinterpret_cast<uint8_t*>(MAP_FAILED) - int mFd = -1; - int mOriginalFd = -1; - int32_t mSizeInBytes = 0; - uint8_t *mResolvedAddress = MMAP_UNRESOLVED_ADDRESS; + aaudio_result_t resolveSharedMemory(const android::base::unique_fd& fd); + + android::base::unique_fd mFd; + int32_t mSizeInBytes = 0; + uint8_t *mResolvedAddress = MMAP_UNRESOLVED_ADDRESS; }; } /* namespace aaudio */ diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp index 5cb642b74a..6ec285fcfd 100644 --- a/media/libaaudio/src/client/AudioEndpoint.cpp +++ b/media/libaaudio/src/client/AudioEndpoint.cpp @@ -113,7 +113,8 @@ aaudio_result_t AudioEndpoint_validateDescriptor(const EndpointDescriptor *pEndp return result; } -aaudio_result_t AudioEndpoint::configure(const EndpointDescriptor *pEndpointDescriptor) +aaudio_result_t AudioEndpoint::configure(const EndpointDescriptor *pEndpointDescriptor, + aaudio_direction_t direction) { aaudio_result_t result = AudioEndpoint_validateDescriptor(pEndpointDescriptor); if (result != AAUDIO_OK) { @@ -143,12 +144,20 @@ aaudio_result_t AudioEndpoint::configure(const EndpointDescriptor *pEndpointDesc descriptor->dataAddress ); - // ============================ down data queue ============================= + // ============================ data queue ============================= descriptor = &pEndpointDescriptor->dataQueueDescriptor; ALOGV("AudioEndpoint::configure() data framesPerBurst = %d", descriptor->framesPerBurst); - ALOGV("AudioEndpoint::configure() data readCounterAddress = %p", descriptor->readCounterAddress); - mFreeRunning = descriptor->readCounterAddress == nullptr; + ALOGV("AudioEndpoint::configure() data readCounterAddress = %p", + descriptor->readCounterAddress); + + // An example of free running is when the other side is read or written by hardware DMA + // or a DSP. It does not update its counter so we have to update it. + int64_t *remoteCounter = (direction == AAUDIO_DIRECTION_OUTPUT) + ? descriptor->readCounterAddress // read by other side + : descriptor->writeCounterAddress; // written by other side + mFreeRunning = (remoteCounter == nullptr); ALOGV("AudioEndpoint::configure() mFreeRunning = %d", mFreeRunning ? 1 : 0); + int64_t *readCounterAddress = (descriptor->readCounterAddress == nullptr) ? &mDataReadCounter : descriptor->readCounterAddress; @@ -173,13 +182,8 @@ aaudio_result_t AudioEndpoint::readUpCommand(AAudioServiceMessage *commandPtr) return mUpCommandQueue->read(commandPtr, 1); } -aaudio_result_t AudioEndpoint::writeDataNow(const void *buffer, int32_t numFrames) -{ - return mDataQueue->write(buffer, numFrames); -} - -void AudioEndpoint::getEmptyFramesAvailable(WrappingBuffer *wrappingBuffer) { - mDataQueue->getEmptyRoomAvailable(wrappingBuffer); +int32_t AudioEndpoint::getEmptyFramesAvailable(WrappingBuffer *wrappingBuffer) { + return mDataQueue->getEmptyRoomAvailable(wrappingBuffer); } int32_t AudioEndpoint::getEmptyFramesAvailable() @@ -187,7 +191,7 @@ int32_t AudioEndpoint::getEmptyFramesAvailable() return mDataQueue->getFifoControllerBase()->getEmptyFramesAvailable(); } -void AudioEndpoint::getFullFramesAvailable(WrappingBuffer *wrappingBuffer) +int32_t AudioEndpoint::getFullFramesAvailable(WrappingBuffer *wrappingBuffer) { return mDataQueue->getFullDataAvailable(wrappingBuffer); } @@ -246,3 +250,7 @@ int32_t AudioEndpoint::getBufferCapacityInFrames() const return (int32_t)mDataQueue->getBufferCapacityInFrames(); } +void AudioEndpoint::dump() const { + ALOGD("AudioEndpoint: data readCounter = %lld", (long long) mDataQueue->getReadCounter()); + ALOGD("AudioEndpoint: data writeCounter = %lld", (long long) mDataQueue->getWriteCounter()); +} diff --git a/media/libaaudio/src/client/AudioEndpoint.h b/media/libaaudio/src/client/AudioEndpoint.h index 53ba0336c7..81a4f7b7ff 100644 --- a/media/libaaudio/src/client/AudioEndpoint.h +++ b/media/libaaudio/src/client/AudioEndpoint.h @@ -40,7 +40,8 @@ public: /** * Configure based on the EndPointDescriptor_t. */ - aaudio_result_t configure(const EndpointDescriptor *pEndpointDescriptor); + aaudio_result_t configure(const EndpointDescriptor *pEndpointDescriptor, + aaudio_direction_t direction); /** * Read from a command passed up from the Server. @@ -48,17 +49,11 @@ public: */ aaudio_result_t readUpCommand(AAudioServiceMessage *commandPtr); - /** - * Non-blocking write. - * @return framesWritten or a negative error code. - */ - aaudio_result_t writeDataNow(const void *buffer, int32_t numFrames); - - void getEmptyFramesAvailable(android::WrappingBuffer *wrappingBuffer); + int32_t getEmptyFramesAvailable(android::WrappingBuffer *wrappingBuffer); int32_t getEmptyFramesAvailable(); - void getFullFramesAvailable(android::WrappingBuffer *wrappingBuffer); + int32_t getFullFramesAvailable(android::WrappingBuffer *wrappingBuffer); int32_t getFullFramesAvailable(); @@ -91,6 +86,8 @@ public: int32_t getBufferCapacityInFrames() const; + void dump() const; + private: android::FifoBuffer *mUpCommandQueue; android::FifoBuffer *mDataQueue; diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp index 3a827f0633..4c7d0f79ea 100644 --- a/media/libaaudio/src/client/AudioStreamInternal.cpp +++ b/media/libaaudio/src/client/AudioStreamInternal.cpp @@ -16,7 +16,7 @@ // This file is used in both client and server processes. // This is needed to make sense of the logs more easily. -#define LOG_TAG (mInService ? "AAudioService" : "AAudio") +#define LOG_TAG (mInService ? "AudioStreamInternal_Service" : "AudioStreamInternal_Client") //#define LOG_NDEBUG 0 #include <utils/Log.h> @@ -28,10 +28,10 @@ #include <binder/IServiceManager.h> #include <aaudio/AAudio.h> +#include <cutils/properties.h> #include <utils/String16.h> #include <utils/Trace.h> -#include "AudioClock.h" #include "AudioEndpointParcelable.h" #include "binding/AAudioStreamRequest.h" #include "binding/AAudioStreamConfiguration.h" @@ -39,6 +39,7 @@ #include "binding/AAudioServiceMessage.h" #include "core/AudioStreamBuilder.h" #include "fifo/FifoBuffer.h" +#include "utility/AudioClock.h" #include "utility/LinearRamp.h" #include "AudioStreamInternal.h" @@ -62,8 +63,14 @@ AudioStreamInternal::AudioStreamInternal(AAudioServiceInterface &serviceInterfa , mAudioEndpoint() , mServiceStreamHandle(AAUDIO_HANDLE_INVALID) , mFramesPerBurst(16) + , mStreamVolume(1.0f) + , mInService(inService) , mServiceInterface(serviceInterface) - , mInService(inService) { + , mWakeupDelayNanos(AAudioProperty_getWakeupDelayMicros() * AAUDIO_NANOS_PER_MICROSECOND) + , mMinimumSleepNanos(AAudioProperty_getMinimumSleepMicros() * AAUDIO_NANOS_PER_MICROSECOND) + { + ALOGD("AudioStreamInternal(): mWakeupDelayNanos = %d, mMinimumSleepNanos = %d", + mWakeupDelayNanos, mMinimumSleepNanos); } AudioStreamInternal::~AudioStreamInternal() { @@ -85,13 +92,14 @@ aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) { setFormat(AAUDIO_FORMAT_PCM_FLOAT); } // Request FLOAT for the shared mixer. - request.getConfiguration().setAudioFormat(AAUDIO_FORMAT_PCM_FLOAT); + request.getConfiguration().setFormat(AAUDIO_FORMAT_PCM_FLOAT); // Build the request to send to the server. request.setUserId(getuid()); request.setProcessId(getpid()); request.setDirection(getDirection()); request.setSharingModeMatchRequired(isSharingModeMatchRequired()); + request.setInService(mInService); request.getConfiguration().setDeviceId(getDeviceId()); request.getConfiguration().setSampleRate(getSampleRate()); @@ -114,9 +122,10 @@ aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) { setSampleRate(configuration.getSampleRate()); setSamplesPerFrame(configuration.getSamplesPerFrame()); setDeviceId(configuration.getDeviceId()); + setSharingMode(configuration.getSharingMode()); // Save device format so we can do format conversion and volume scaling together. - mDeviceFormat = configuration.getAudioFormat(); + mDeviceFormat = configuration.getFormat(); result = mServiceInterface.getStreamDescription(mServiceStreamHandle, mEndPointParcelable); if (result != AAUDIO_OK) { @@ -132,7 +141,7 @@ aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) { } // Configure endpoint based on descriptor. - mAudioEndpoint.configure(&mEndpointDescriptor); + mAudioEndpoint.configure(&mEndpointDescriptor, getDirection()); mFramesPerBurst = mEndpointDescriptor.dataQueueDescriptor.framesPerBurst; int32_t capacity = mEndpointDescriptor.dataQueueDescriptor.capacityInFrames; @@ -153,13 +162,13 @@ aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) { if (getDataCallbackProc()) { mCallbackFrames = builder.getFramesPerDataCallback(); if (mCallbackFrames > getBufferCapacity() / 2) { - ALOGE("AudioStreamInternal.open(): framesPerCallback too large = %d, capacity = %d", + ALOGE("AudioStreamInternal::open(): framesPerCallback too big = %d, capacity = %d", mCallbackFrames, getBufferCapacity()); mServiceInterface.closeStream(mServiceStreamHandle); return AAUDIO_ERROR_OUT_OF_RANGE; } else if (mCallbackFrames < 0) { - ALOGE("AudioStreamInternal.open(): framesPerCallback negative"); + ALOGE("AudioStreamInternal::open(): framesPerCallback negative"); mServiceInterface.closeStream(mServiceStreamHandle); return AAUDIO_ERROR_OUT_OF_RANGE; @@ -175,12 +184,16 @@ aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) { } setState(AAUDIO_STREAM_STATE_OPEN); + // only connect to AudioManager if this is a playback stream running in client process + if (!mInService && getDirection() == AAUDIO_DIRECTION_OUTPUT) { + init(android::PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA); + } } return result; } aaudio_result_t AudioStreamInternal::close() { - ALOGD("AudioStreamInternal.close(): mServiceStreamHandle = 0x%08X", + ALOGD("AudioStreamInternal::close(): mServiceStreamHandle = 0x%08X", mServiceStreamHandle); if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) { // Don't close a stream while it is running. @@ -196,12 +209,14 @@ aaudio_result_t AudioStreamInternal::close() { result, AAudio_convertResultToText(result)); } } + setState(AAUDIO_STREAM_STATE_CLOSING); aaudio_handle_t serviceStreamHandle = mServiceStreamHandle; mServiceStreamHandle = AAUDIO_HANDLE_INVALID; mServiceInterface.closeStream(serviceStreamHandle); delete[] mCallbackBuffer; mCallbackBuffer = nullptr; + setState(AAUDIO_STREAM_STATE_CLOSED); return mEndPointParcelable.close(); } else { return AAUDIO_ERROR_INVALID_HANDLE; @@ -223,15 +238,20 @@ static void *aaudio_callback_thread_proc(void *context) aaudio_result_t AudioStreamInternal::requestStart() { int64_t startTime; - ALOGD("AudioStreamInternal(): start()"); + ALOGD("AudioStreamInternal()::requestStart()"); if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { return AAUDIO_ERROR_INVALID_STATE; } + if (isActive()) { + return AAUDIO_ERROR_INVALID_STATE; + } + aaudio_stream_state_t originalState = getState(); + + setState(AAUDIO_STREAM_STATE_STARTING); + aaudio_result_t result = AAudioConvert_androidToAAudioResult(startWithStatus()); startTime = AudioClock::getNanoseconds(); mClockModel.start(startTime); - setState(AAUDIO_STREAM_STATE_STARTING); - aaudio_result_t result = mServiceInterface.startStream(mServiceStreamHandle);; if (result == AAUDIO_OK && getDataCallbackProc() != nullptr) { // Launch the callback loop thread. @@ -241,6 +261,9 @@ aaudio_result_t AudioStreamInternal::requestStart() mCallbackEnabled.store(true); result = createThread(periodNanos, aaudio_callback_thread_proc, this); } + if (result != AAUDIO_OK) { + setState(originalState); + } return result; } @@ -271,93 +294,58 @@ aaudio_result_t AudioStreamInternal::stopCallback() } } -aaudio_result_t AudioStreamInternal::requestPauseInternal() +aaudio_result_t AudioStreamInternal::requestStopInternal() { if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { - ALOGE("AudioStreamInternal(): requestPauseInternal() mServiceStreamHandle invalid = 0x%08X", + ALOGE("AudioStreamInternal::requestStopInternal() mServiceStreamHandle invalid = 0x%08X", mServiceStreamHandle); return AAUDIO_ERROR_INVALID_STATE; } mClockModel.stop(AudioClock::getNanoseconds()); - setState(AAUDIO_STREAM_STATE_PAUSING); - return mServiceInterface.pauseStream(mServiceStreamHandle); + setState(AAUDIO_STREAM_STATE_STOPPING); + return AAudioConvert_androidToAAudioResult(stopWithStatus()); } -aaudio_result_t AudioStreamInternal::requestPause() +aaudio_result_t AudioStreamInternal::requestStop() { aaudio_result_t result = stopCallback(); if (result != AAUDIO_OK) { return result; } - result = requestPauseInternal(); + result = requestStopInternal(); return result; } -aaudio_result_t AudioStreamInternal::requestFlush() { +aaudio_result_t AudioStreamInternal::registerThread() { if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { - ALOGE("AudioStreamInternal(): requestFlush() mServiceStreamHandle invalid = 0x%08X", - mServiceStreamHandle); return AAUDIO_ERROR_INVALID_STATE; } - - setState(AAUDIO_STREAM_STATE_FLUSHING); - return mServiceInterface.flushStream(mServiceStreamHandle); -} - -// TODO for Play only -void AudioStreamInternal::onFlushFromServer() { - ALOGD("AudioStreamInternal(): onFlushFromServer()"); - int64_t readCounter = mAudioEndpoint.getDataReadCounter(); - int64_t writeCounter = mAudioEndpoint.getDataWriteCounter(); - - // Bump offset so caller does not see the retrograde motion in getFramesRead(). - int64_t framesFlushed = writeCounter - readCounter; - mFramesOffsetFromService += framesFlushed; - - // Flush written frames by forcing writeCounter to readCounter. - // This is because we cannot move the read counter in the hardware. - mAudioEndpoint.setDataWriteCounter(readCounter); + return mServiceInterface.registerAudioThread(mServiceStreamHandle, + gettid(), + getPeriodNanoseconds()); } -aaudio_result_t AudioStreamInternal::requestStopInternal() -{ +aaudio_result_t AudioStreamInternal::unregisterThread() { if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { - ALOGE("AudioStreamInternal(): requestStopInternal() mServiceStreamHandle invalid = 0x%08X", - mServiceStreamHandle); return AAUDIO_ERROR_INVALID_STATE; } - - mClockModel.stop(AudioClock::getNanoseconds()); - setState(AAUDIO_STREAM_STATE_STOPPING); - return mServiceInterface.stopStream(mServiceStreamHandle); -} - -aaudio_result_t AudioStreamInternal::requestStop() -{ - aaudio_result_t result = stopCallback(); - if (result != AAUDIO_OK) { - return result; - } - result = requestStopInternal(); - return result; + return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, gettid()); } -aaudio_result_t AudioStreamInternal::registerThread() { +aaudio_result_t AudioStreamInternal::startClient(const android::AudioClient& client, + audio_port_handle_t *clientHandle) { if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { return AAUDIO_ERROR_INVALID_STATE; } - return mServiceInterface.registerAudioThread(mServiceStreamHandle, - getpid(), - gettid(), - getPeriodNanoseconds()); + return mServiceInterface.startClient(mServiceStreamHandle, client, clientHandle); } -aaudio_result_t AudioStreamInternal::unregisterThread() { +aaudio_result_t AudioStreamInternal::stopClient(audio_port_handle_t clientHandle) { if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { return AAUDIO_ERROR_INVALID_STATE; } - return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, getpid(), gettid()); + return mServiceInterface.stopClient(mServiceStreamHandle, clientHandle); } aaudio_result_t AudioStreamInternal::getTimestamp(clockid_t clockId, @@ -365,7 +353,7 @@ aaudio_result_t AudioStreamInternal::getTimestamp(clockid_t clockId, int64_t *timeNanoseconds) { // TODO Generate in server and pass to client. Return latest. int64_t time = AudioClock::getNanoseconds(); - *framePosition = mClockModel.convertTimeToPosition(time); + *framePosition = mClockModel.convertTimeToPosition(time) + mFramesOffsetFromService; // TODO Get a more accurate timestamp from the service. This code just adds a fudge factor. *timeNanoseconds = time + (6 * AAUDIO_NANOS_PER_MILLISECOND); return AAUDIO_OK; @@ -378,31 +366,28 @@ aaudio_result_t AudioStreamInternal::updateStateWhileWaiting() { return processCommands(); } -#if LOG_TIMESTAMPS -static void AudioStreamInternal_logTimestamp(AAudioServiceMessage &command) { +void AudioStreamInternal::logTimestamp(AAudioServiceMessage &command) { static int64_t oldPosition = 0; static int64_t oldTime = 0; int64_t framePosition = command.timestamp.position; int64_t nanoTime = command.timestamp.timestamp; - ALOGD("AudioStreamInternal() timestamp says framePosition = %08lld at nanoTime %lld", + ALOGD("AudioStreamInternal: timestamp says framePosition = %08lld at nanoTime %lld", (long long) framePosition, (long long) nanoTime); int64_t nanosDelta = nanoTime - oldTime; if (nanosDelta > 0 && oldTime > 0) { int64_t framesDelta = framePosition - oldPosition; int64_t rate = (framesDelta * AAUDIO_NANOS_PER_SECOND) / nanosDelta; - ALOGD("AudioStreamInternal() - framesDelta = %08lld", (long long) framesDelta); - ALOGD("AudioStreamInternal() - nanosDelta = %08lld", (long long) nanosDelta); - ALOGD("AudioStreamInternal() - measured rate = %lld", (long long) rate); + ALOGD("AudioStreamInternal: framesDelta = %08lld, nanosDelta = %08lld, rate = %lld", + (long long) framesDelta, (long long) nanosDelta, (long long) rate); } oldPosition = framePosition; oldTime = nanoTime; } -#endif aaudio_result_t AudioStreamInternal::onTimestampFromServer(AAudioServiceMessage *message) { #if LOG_TIMESTAMPS - AudioStreamInternal_logTimestamp(*message); + logTimestamp(*message); #endif processTimestamp(message->timestamp.position, message->timestamp.timestamp); return AAUDIO_OK; @@ -412,46 +397,48 @@ aaudio_result_t AudioStreamInternal::onEventFromServer(AAudioServiceMessage *mes aaudio_result_t result = AAUDIO_OK; switch (message->event.event) { case AAUDIO_SERVICE_EVENT_STARTED: - ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_STARTED"); + ALOGD("AudioStreamInternal::onEventFromServergot() AAUDIO_SERVICE_EVENT_STARTED"); if (getState() == AAUDIO_STREAM_STATE_STARTING) { setState(AAUDIO_STREAM_STATE_STARTED); } break; case AAUDIO_SERVICE_EVENT_PAUSED: - ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_PAUSED"); + ALOGD("AudioStreamInternal::onEventFromServergot() AAUDIO_SERVICE_EVENT_PAUSED"); if (getState() == AAUDIO_STREAM_STATE_PAUSING) { setState(AAUDIO_STREAM_STATE_PAUSED); } break; case AAUDIO_SERVICE_EVENT_STOPPED: - ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_STOPPED"); + ALOGD("AudioStreamInternal::onEventFromServergot() AAUDIO_SERVICE_EVENT_STOPPED"); if (getState() == AAUDIO_STREAM_STATE_STOPPING) { setState(AAUDIO_STREAM_STATE_STOPPED); } break; case AAUDIO_SERVICE_EVENT_FLUSHED: - ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_FLUSHED"); + ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_FLUSHED"); if (getState() == AAUDIO_STREAM_STATE_FLUSHING) { setState(AAUDIO_STREAM_STATE_FLUSHED); onFlushFromServer(); } break; case AAUDIO_SERVICE_EVENT_CLOSED: - ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_CLOSED"); + ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_CLOSED"); setState(AAUDIO_STREAM_STATE_CLOSED); break; case AAUDIO_SERVICE_EVENT_DISCONNECTED: result = AAUDIO_ERROR_DISCONNECTED; setState(AAUDIO_STREAM_STATE_DISCONNECTED); - ALOGW("WARNING - processCommands() AAUDIO_SERVICE_EVENT_DISCONNECTED"); + ALOGW("WARNING - AudioStreamInternal::onEventFromServer()" + " AAUDIO_SERVICE_EVENT_DISCONNECTED"); break; case AAUDIO_SERVICE_EVENT_VOLUME: - mVolumeRamp.setTarget((float) message->event.dataDouble); - ALOGD("processCommands() AAUDIO_SERVICE_EVENT_VOLUME %lf", + mStreamVolume = (float)message->event.dataDouble; + doSetVolume(); + ALOGD("AudioStreamInternal::onEventFromServer() AAUDIO_SERVICE_EVENT_VOLUME %lf", message->event.dataDouble); break; default: - ALOGW("WARNING - processCommands() Unrecognized event = %d", + ALOGW("WARNING - AudioStreamInternal::onEventFromServer() Unrecognized event = %d", (int) message->event.event); break; } @@ -491,29 +478,29 @@ aaudio_result_t AudioStreamInternal::processCommands() { aaudio_result_t AudioStreamInternal::processData(void *buffer, int32_t numFrames, int64_t timeoutNanoseconds) { - const char * traceName = (mInService) ? "aaWrtS" : "aaWrtC"; + const char * traceName = "aaProc"; + const char * fifoName = "aaRdy"; ATRACE_BEGIN(traceName); + if (ATRACE_ENABLED()) { + int32_t fullFrames = mAudioEndpoint.getFullFramesAvailable(); + ATRACE_INT(fifoName, fullFrames); + } + aaudio_result_t result = AAUDIO_OK; int32_t loopCount = 0; uint8_t* audioData = (uint8_t*)buffer; int64_t currentTimeNanos = AudioClock::getNanoseconds(); - int64_t deadlineNanos = currentTimeNanos + timeoutNanoseconds; + const int64_t entryTimeNanos = currentTimeNanos; + const int64_t deadlineNanos = currentTimeNanos + timeoutNanoseconds; int32_t framesLeft = numFrames; - int32_t fullFrames = mAudioEndpoint.getFullFramesAvailable(); - if (ATRACE_ENABLED()) { - const char * traceName = (mInService) ? "aaFullS" : "aaFullC"; - ATRACE_INT(traceName, fullFrames); - } - // Loop until all the data has been processed or until a timeout occurs. while (framesLeft > 0) { - // The call to processDataNow() will not block. It will just read as much as it can. + // The call to processDataNow() will not block. It will just process as much as it can. int64_t wakeTimeNanos = 0; aaudio_result_t framesProcessed = processDataNow(audioData, framesLeft, currentTimeNanos, &wakeTimeNanos); if (framesProcessed < 0) { - ALOGE("AudioStreamInternal::processData() loop: framesProcessed = %d", framesProcessed); result = framesProcessed; break; } @@ -524,28 +511,52 @@ aaudio_result_t AudioStreamInternal::processData(void *buffer, int32_t numFrames if (timeoutNanoseconds == 0) { break; // don't block } else if (framesLeft > 0) { - // clip the wake time to something reasonable - if (wakeTimeNanos < currentTimeNanos) { - wakeTimeNanos = currentTimeNanos; + if (!mAudioEndpoint.isFreeRunning()) { + // If there is software on the other end of the FIFO then it may get delayed. + // So wake up just a little after we expect it to be ready. + wakeTimeNanos += mWakeupDelayNanos; } + if (wakeTimeNanos > deadlineNanos) { // If we time out, just return the framesWritten so far. // TODO remove after we fix the deadline bug - ALOGE("AudioStreamInternal::processData(): timed out after %lld nanos", + ALOGW("AudioStreamInternal::processData(): entered at %lld nanos, currently %lld", + (long long) entryTimeNanos, (long long) currentTimeNanos); + ALOGW("AudioStreamInternal::processData(): timed out after %lld nanos", (long long) timeoutNanoseconds); - ALOGE("AudioStreamInternal::processData(): wakeTime = %lld, deadline = %lld nanos", + ALOGW("AudioStreamInternal::processData(): wakeTime = %lld, deadline = %lld nanos", (long long) wakeTimeNanos, (long long) deadlineNanos); - ALOGE("AudioStreamInternal::processData(): past deadline by %d micros", + ALOGW("AudioStreamInternal::processData(): past deadline by %d micros", (int)((wakeTimeNanos - deadlineNanos) / AAUDIO_NANOS_PER_MICROSECOND)); + mClockModel.dump(); + mAudioEndpoint.dump(); break; } - int64_t sleepForNanos = wakeTimeNanos - currentTimeNanos; - AudioClock::sleepForNanos(sleepForNanos); + currentTimeNanos = AudioClock::getNanoseconds(); + int64_t earliestWakeTime = currentTimeNanos + mMinimumSleepNanos; + // Guarantee a minimum sleep time. + if (wakeTimeNanos < earliestWakeTime) { + wakeTimeNanos = earliestWakeTime; + } + + if (ATRACE_ENABLED()) { + int32_t fullFrames = mAudioEndpoint.getFullFramesAvailable(); + ATRACE_INT(fifoName, fullFrames); + int64_t sleepForNanos = wakeTimeNanos - currentTimeNanos; + ATRACE_INT("aaSlpNs", (int32_t)sleepForNanos); + } + + AudioClock::sleepUntilNanoTime(wakeTimeNanos); currentTimeNanos = AudioClock::getNanoseconds(); } } + if (ATRACE_ENABLED()) { + int32_t fullFrames = mAudioEndpoint.getFullFramesAvailable(); + ATRACE_INT(fifoName, fullFrames); + } + // return error or framesProcessed (void) loopCount; ATRACE_END(); @@ -588,3 +599,32 @@ int32_t AudioStreamInternal::getFramesPerBurst() const { aaudio_result_t AudioStreamInternal::joinThread(void** returnArg) { return AudioStream::joinThread(returnArg, calculateReasonableTimeout(getFramesPerBurst())); } + +void AudioStreamInternal::doSetVolume() { + // No pan and only left volume is taken into account from IPLayer interface + mVolumeRamp.setTarget(mStreamVolume * mVolumeMultiplierL /* * mPanMultiplierL */); +} + + +//------------------------------------------------------------------------------ +// Implementation of PlayerBase +status_t AudioStreamInternal::playerStart() { + return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.startStream(mServiceStreamHandle)); +} + +status_t AudioStreamInternal::playerPause() { + return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.pauseStream(mServiceStreamHandle)); +} + +status_t AudioStreamInternal::playerStop() { + return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.stopStream(mServiceStreamHandle)); +} + +status_t AudioStreamInternal::playerSetVolume() { + doSetVolume(); + return NO_ERROR; +} + +void AudioStreamInternal::destroy() { + baseDestroy(); +} diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h index a11f309cdc..1b991de2ab 100644 --- a/media/libaaudio/src/client/AudioStreamInternal.h +++ b/media/libaaudio/src/client/AudioStreamInternal.h @@ -18,6 +18,7 @@ #define ANDROID_AAUDIO_AUDIO_STREAM_INTERNAL_H #include <stdint.h> +#include <media/PlayerBase.h> #include <aaudio/AAudio.h> #include "binding/IAAudioService.h" @@ -26,6 +27,7 @@ #include "client/IsochronousClockModel.h" #include "client/AudioEndpoint.h" #include "core/AudioStream.h" +#include "utility/AudioClock.h" #include "utility/LinearRamp.h" using android::sp; @@ -34,19 +36,14 @@ using android::IAAudioService; namespace aaudio { // A stream that talks to the AAudioService or directly to a HAL. -class AudioStreamInternal : public AudioStream { +class AudioStreamInternal : public AudioStream, public android::PlayerBase { public: AudioStreamInternal(AAudioServiceInterface &serviceInterface, bool inService); virtual ~AudioStreamInternal(); - // =========== Begin ABSTRACT methods =========================== aaudio_result_t requestStart() override; - aaudio_result_t requestPause() override; - - aaudio_result_t requestFlush() override; - aaudio_result_t requestStop() override; aaudio_result_t getTimestamp(clockid_t clockId, @@ -54,7 +51,6 @@ public: int64_t *timeNanoseconds) override; virtual aaudio_result_t updateStateWhileWaiting() override; - // =========== End ABSTRACT methods =========================== aaudio_result_t open(const AudioStreamBuilder &builder) override; @@ -89,6 +85,14 @@ public: // Calculate timeout based on framesPerBurst int64_t calculateReasonableTimeout(); + //PlayerBase virtuals + virtual void destroy(); + + aaudio_result_t startClient(const android::AudioClient& client, + audio_port_handle_t *clientHandle); + + aaudio_result_t stopClient(audio_port_handle_t clientHandle); + protected: aaudio_result_t processData(void *buffer, @@ -109,21 +113,30 @@ protected: aaudio_result_t processCommands(); - aaudio_result_t requestPauseInternal(); aaudio_result_t requestStopInternal(); aaudio_result_t stopCallback(); - void onFlushFromServer(); + virtual void onFlushFromServer() {} aaudio_result_t onEventFromServer(AAudioServiceMessage *message); aaudio_result_t onTimestampFromServer(AAudioServiceMessage *message); + void logTimestamp(AAudioServiceMessage &message); + // Calculate timeout for an operation involving framesPerOperation. int64_t calculateReasonableTimeout(int32_t framesPerOperation); + void doSetVolume(); + + //PlayerBase virtuals + virtual status_t playerStart(); + virtual status_t playerPause(); + virtual status_t playerStop(); + virtual status_t playerSetVolume(); + aaudio_format_t mDeviceFormat = AAUDIO_FORMAT_UNSPECIFIED; IsochronousClockModel mClockModel; // timing model for chasing the HAL @@ -135,6 +148,7 @@ protected: int32_t mXRunCount = 0; // how many underrun events? LinearRamp mVolumeRamp; + float mStreamVolume; // Offset from underlying frame position. int64_t mFramesOffsetFromService = 0; // offset for timestamps @@ -142,6 +156,11 @@ protected: uint8_t *mCallbackBuffer = nullptr; int32_t mCallbackFrames = 0; + // The service uses this for SHARED mode. + bool mInService = false; // Is this running in the client or the service? + + AAudioServiceInterface &mServiceInterface; // abstract interface to the service + private: /* * Asynchronous write with data conversion. @@ -155,12 +174,13 @@ private: // Adjust timing model based on timestamp from service. void processTimestamp(uint64_t position, int64_t time); + // Thread on other side of FIFO will have wakeup jitter. + // By delaying slightly we can avoid waking up before other side is ready. + const int32_t mWakeupDelayNanos; // delay past typical wakeup jitter + const int32_t mMinimumSleepNanos; // minimum sleep while polling + AudioEndpointParcelable mEndPointParcelable; // description of the buffers filled by service EndpointDescriptor mEndpointDescriptor; // buffer description with resolved addresses - AAudioServiceInterface &mServiceInterface; // abstract interface to the service - - // The service uses this for SHARED mode. - bool mInService = false; // Is this running in the client or the service? }; } /* namespace aaudio */ diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp index 93693bdd00..7b1e53e75d 100644 --- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp +++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp @@ -14,15 +14,19 @@ * limitations under the License. */ -#define LOG_TAG "AAudio" +#define LOG_TAG (mInService ? "AAudioService" : "AAudio") //#define LOG_NDEBUG 0 #include <utils/Log.h> +#include <algorithm> #include <aaudio/AAudio.h> #include "client/AudioStreamInternalCapture.h" #include "utility/AudioClock.h" +#define ATRACE_TAG ATRACE_TAG_AUDIO +#include <utils/Trace.h> + using android::WrappingBuffer; using namespace aaudio; @@ -35,7 +39,6 @@ AudioStreamInternalCapture::AudioStreamInternalCapture(AAudioServiceInterface & AudioStreamInternalCapture::~AudioStreamInternalCapture() {} - // Write the data, block if needed and timeoutMillis > 0 aaudio_result_t AudioStreamInternalCapture::read(void *buffer, int32_t numFrames, int64_t timeoutNanoseconds) @@ -51,6 +54,9 @@ aaudio_result_t AudioStreamInternalCapture::processDataNow(void *buffer, int32_t return result; } + const char *traceName = "aaRdNow"; + ATRACE_BEGIN(traceName); + if (mAudioEndpoint.isFreeRunning()) { //ALOGD("AudioStreamInternalCapture::processDataNow() - update remote counter"); // Update data queue based on the timing model. @@ -62,6 +68,9 @@ aaudio_result_t AudioStreamInternalCapture::processDataNow(void *buffer, int32_t // If the write index passed the read index then consider it an overrun. if (mAudioEndpoint.getEmptyFramesAvailable() < 0) { mXRunCount++; + if (ATRACE_ENABLED()) { + ATRACE_INT("aaOverRuns", mXRunCount); + } } // Read some data from the buffer. @@ -69,6 +78,9 @@ aaudio_result_t AudioStreamInternalCapture::processDataNow(void *buffer, int32_t int32_t framesProcessed = readNowWithConversion(buffer, numFrames); //ALOGD("AudioStreamInternalCapture::processDataNow() - tried to read %d frames, read %d", // numFrames, framesProcessed); + if (ATRACE_ENABLED()) { + ATRACE_INT("aaRead", framesProcessed); + } // Calculate an ideal time to wake up. if (wakeTimePtr != nullptr && framesProcessed >= 0) { @@ -81,14 +93,14 @@ aaudio_result_t AudioStreamInternalCapture::processDataNow(void *buffer, int32_t case AAUDIO_STREAM_STATE_OPEN: case AAUDIO_STREAM_STATE_STARTING: break; - case AAUDIO_STREAM_STATE_STARTED: // When do we expect the next read burst to occur? + case AAUDIO_STREAM_STATE_STARTED: { - uint32_t burstSize = mFramesPerBurst; - if (burstSize < 32) { - burstSize = 32; // TODO review - } + // When do we expect the next write burst to occur? - uint64_t nextReadPosition = mAudioEndpoint.getDataWriteCounter() + burstSize; + // Calculate frame position based off of the readCounter because + // the writeCounter might have just advanced in the background, + // causing us to sleep until a later burst. + int64_t nextReadPosition = mAudioEndpoint.getDataReadCounter() + mFramesPerBurst; wakeTime = mClockModel.convertPositionToTime(nextReadPosition); } break; @@ -98,10 +110,8 @@ aaudio_result_t AudioStreamInternalCapture::processDataNow(void *buffer, int32_t *wakeTimePtr = wakeTime; } -// ALOGD("AudioStreamInternalCapture::readNow finished: now = %llu, read# = %llu, wrote# = %llu", -// (unsigned long long)currentNanoTime, -// (unsigned long long)mAudioEndpoint.getDataReadCounter(), -// (unsigned long long)mAudioEndpoint.getDownDataWriteCounter()); + + ATRACE_END(); return framesProcessed; } @@ -155,29 +165,27 @@ aaudio_result_t AudioStreamInternalCapture::readNowWithConversion(void *buffer, int32_t framesProcessed = numFrames - framesLeft; mAudioEndpoint.advanceReadIndex(framesProcessed); - incrementFramesRead(framesProcessed); //ALOGD("AudioStreamInternalCapture::readNowWithConversion() returns %d", framesProcessed); return framesProcessed; } -int64_t AudioStreamInternalCapture::getFramesWritten() -{ - int64_t frames = - mClockModel.convertTimeToPosition(AudioClock::getNanoseconds()) - + mFramesOffsetFromService; - // Prevent retrograde motion. - if (frames < mLastFramesWritten) { - frames = mLastFramesWritten; +int64_t AudioStreamInternalCapture::getFramesWritten() { + int64_t framesWrittenHardware; + if (isActive()) { + framesWrittenHardware = mClockModel.convertTimeToPosition(AudioClock::getNanoseconds()); } else { - mLastFramesWritten = frames; + framesWrittenHardware = mAudioEndpoint.getDataWriteCounter(); } - //ALOGD("AudioStreamInternalCapture::getFramesWritten() returns %lld", (long long)frames); - return frames; + // Prevent retrograde motion. + mLastFramesWritten = std::max(mLastFramesWritten, + framesWrittenHardware + mFramesOffsetFromService); + //ALOGD("AudioStreamInternalCapture::getFramesWritten() returns %lld", + // (long long)mLastFramesWritten); + return mLastFramesWritten; } -int64_t AudioStreamInternalCapture::getFramesRead() -{ +int64_t AudioStreamInternalCapture::getFramesRead() { int64_t frames = mAudioEndpoint.getDataWriteCounter() + mFramesOffsetFromService; //ALOGD("AudioStreamInternalCapture::getFramesRead() returns %lld", (long long)frames); diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp index fc9766fbcb..31e0a4026a 100644 --- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp +++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp @@ -14,10 +14,14 @@ * limitations under the License. */ -#define LOG_TAG "AAudio" +#define LOG_TAG (mInService ? "AAudioService" : "AAudio") //#define LOG_NDEBUG 0 #include <utils/Log.h> +#define ATRACE_TAG ATRACE_TAG_AUDIO + +#include <utils/Trace.h> + #include "client/AudioStreamInternalPlay.h" #include "utility/AudioClock.h" @@ -34,6 +38,55 @@ AudioStreamInternalPlay::AudioStreamInternalPlay(AAudioServiceInterface &servic AudioStreamInternalPlay::~AudioStreamInternalPlay() {} +aaudio_result_t AudioStreamInternalPlay::requestPauseInternal() +{ + if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { + ALOGE("AudioStreamInternal::requestPauseInternal() mServiceStreamHandle invalid = 0x%08X", + mServiceStreamHandle); + return AAUDIO_ERROR_INVALID_STATE; + } + + mClockModel.stop(AudioClock::getNanoseconds()); + setState(AAUDIO_STREAM_STATE_PAUSING); + return AAudioConvert_androidToAAudioResult(pauseWithStatus()); +} + +aaudio_result_t AudioStreamInternalPlay::requestPause() +{ + aaudio_result_t result = stopCallback(); + if (result != AAUDIO_OK) { + return result; + } + result = requestPauseInternal(); + return result; +} + +aaudio_result_t AudioStreamInternalPlay::requestFlush() { + if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { + ALOGE("AudioStreamInternal::requestFlush() mServiceStreamHandle invalid = 0x%08X", + mServiceStreamHandle); + return AAUDIO_ERROR_INVALID_STATE; + } + + setState(AAUDIO_STREAM_STATE_FLUSHING); + return mServiceInterface.flushStream(mServiceStreamHandle); +} + +void AudioStreamInternalPlay::onFlushFromServer() { + int64_t readCounter = mAudioEndpoint.getDataReadCounter(); + int64_t writeCounter = mAudioEndpoint.getDataWriteCounter(); + + // Bump offset so caller does not see the retrograde motion in getFramesRead(). + int64_t framesFlushed = writeCounter - readCounter; + mFramesOffsetFromService += framesFlushed; + ALOGD("AudioStreamInternal::onFlushFromServer() readN = %lld, writeN = %lld, offset = %lld", + (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService); + + // Flush written frames by forcing writeCounter to readCounter. + // This is because we cannot move the read counter in the hardware. + mAudioEndpoint.setDataWriteCounter(readCounter); +} + // Write the data, block if needed and timeoutMillis > 0 aaudio_result_t AudioStreamInternalPlay::write(const void *buffer, int32_t numFrames, int64_t timeoutNanoseconds) @@ -50,17 +103,23 @@ aaudio_result_t AudioStreamInternalPlay::processDataNow(void *buffer, int32_t nu return result; } + const char *traceName = "aaWrNow"; + ATRACE_BEGIN(traceName); + + // If a DMA channel or DSP is reading the other end then we have to update the readCounter. if (mAudioEndpoint.isFreeRunning()) { - //ALOGD("AudioStreamInternal::processDataNow() - update read counter"); // Update data queue based on the timing model. int64_t estimatedReadCounter = mClockModel.convertTimeToPosition(currentNanoTime); + // ALOGD("AudioStreamInternal::processDataNow() - estimatedReadCounter = %d", (int)estimatedReadCounter); mAudioEndpoint.setDataReadCounter(estimatedReadCounter); } - // TODO else query from endpoint cuz set by actual reader, maybe // If the read index passed the write index then consider it an underrun. if (mAudioEndpoint.getFullFramesAvailable() < 0) { mXRunCount++; + if (ATRACE_ENABLED()) { + ATRACE_INT("aaUnderRuns", mXRunCount); + } } // Write some data to the buffer. @@ -68,6 +127,9 @@ aaudio_result_t AudioStreamInternalPlay::processDataNow(void *buffer, int32_t nu int32_t framesWritten = writeNowWithConversion(buffer, numFrames); //ALOGD("AudioStreamInternal::processDataNow() - tried to write %d frames, wrote %d", // numFrames, framesWritten); + if (ATRACE_ENABLED()) { + ATRACE_INT("aaWrote", framesWritten); + } // Calculate an ideal time to wake up. if (wakeTimePtr != nullptr && framesWritten >= 0) { @@ -84,14 +146,15 @@ aaudio_result_t AudioStreamInternalPlay::processDataNow(void *buffer, int32_t nu wakeTime = currentNanoTime; } break; - case AAUDIO_STREAM_STATE_STARTED: // When do we expect the next read burst to occur? + case AAUDIO_STREAM_STATE_STARTED: { - uint32_t burstSize = mFramesPerBurst; - if (burstSize < 32) { - burstSize = 32; // TODO review - } + // When do we expect the next read burst to occur? - uint64_t nextReadPosition = mAudioEndpoint.getDataReadCounter() + burstSize; + // Calculate frame position based off of the writeCounter because + // the readCounter might have just advanced in the background, + // causing us to sleep until a later burst. + int64_t nextReadPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst + - mAudioEndpoint.getBufferSizeInFrames(); wakeTime = mClockModel.convertPositionToTime(nextReadPosition); } break; @@ -101,10 +164,8 @@ aaudio_result_t AudioStreamInternalPlay::processDataNow(void *buffer, int32_t nu *wakeTimePtr = wakeTime; } -// ALOGD("AudioStreamInternal::processDataNow finished: now = %llu, read# = %llu, wrote# = %llu", -// (unsigned long long)currentNanoTime, -// (unsigned long long)mAudioEndpoint.getDataReadCounter(), -// (unsigned long long)mAudioEndpoint.getDownDataWriteCounter()); + + ATRACE_END(); return framesWritten; } @@ -119,7 +180,7 @@ aaudio_result_t AudioStreamInternalPlay::writeNowWithConversion(const void *buff mAudioEndpoint.getEmptyFramesAvailable(&wrappingBuffer); - // Read data in one or two parts. + // Write data in one or two parts. int partIndex = 0; while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) { int32_t framesToWrite = framesLeft; @@ -201,9 +262,6 @@ aaudio_result_t AudioStreamInternalPlay::writeNowWithConversion(const void *buff int32_t framesWritten = numFrames - framesLeft; mAudioEndpoint.advanceWriteIndex(framesWritten); - if (framesWritten > 0) { - incrementFramesWritten(framesWritten); - } // ALOGD("AudioStreamInternal::writeNowWithConversion() returns %d", framesWritten); return framesWritten; } @@ -211,25 +269,29 @@ aaudio_result_t AudioStreamInternalPlay::writeNowWithConversion(const void *buff int64_t AudioStreamInternalPlay::getFramesRead() { - int64_t framesRead = - mClockModel.convertTimeToPosition(AudioClock::getNanoseconds()) - + mFramesOffsetFromService; + int64_t framesReadHardware; + if (isActive()) { + framesReadHardware = mClockModel.convertTimeToPosition(AudioClock::getNanoseconds()); + } else { + framesReadHardware = mAudioEndpoint.getDataReadCounter(); + } + int64_t framesRead = framesReadHardware + mFramesOffsetFromService; // Prevent retrograde motion. if (framesRead < mLastFramesRead) { framesRead = mLastFramesRead; } else { mLastFramesRead = framesRead; } - ALOGD("AudioStreamInternal::getFramesRead() returns %lld", (long long)framesRead); + //ALOGD("AudioStreamInternalPlay::getFramesRead() returns %lld", (long long)framesRead); return framesRead; } int64_t AudioStreamInternalPlay::getFramesWritten() { - int64_t getFramesWritten = mAudioEndpoint.getDataWriteCounter() + int64_t framesWritten = mAudioEndpoint.getDataWriteCounter() + mFramesOffsetFromService; - ALOGD("AudioStreamInternal::getFramesWritten() returns %lld", (long long)getFramesWritten); - return getFramesWritten; + //ALOGD("AudioStreamInternalPlay::getFramesWritten() returns %lld", (long long)framesWritten); + return framesWritten; } @@ -239,6 +301,7 @@ void *AudioStreamInternalPlay::callbackLoop() { aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE; AAudioStream_dataCallback appCallback = getDataCallbackProc(); if (appCallback == nullptr) return NULL; + int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames); // result might be a frame count while (mCallbackEnabled.load() && isActive() && (result >= 0)) { @@ -250,10 +313,7 @@ void *AudioStreamInternalPlay::callbackLoop() { mCallbackFrames); if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) { - // Write audio data to stream. - int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames); - - // This is a BLOCKING WRITE! + // Write audio data to stream. This is a BLOCKING WRITE! result = write(mCallbackBuffer, mCallbackFrames, timeoutNanos); if ((result != mCallbackFrames)) { ALOGE("AudioStreamInternalPlay(): callbackLoop: write() returned %d", result); diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.h b/media/libaaudio/src/client/AudioStreamInternalPlay.h index b043f671f0..e59d02c5c6 100644 --- a/media/libaaudio/src/client/AudioStreamInternalPlay.h +++ b/media/libaaudio/src/client/AudioStreamInternalPlay.h @@ -33,6 +33,10 @@ public: AudioStreamInternalPlay(AAudioServiceInterface &serviceInterface, bool inService = false); virtual ~AudioStreamInternalPlay(); + aaudio_result_t requestPause() override; + + aaudio_result_t requestFlush() override; + aaudio_result_t write(const void *buffer, int32_t numFrames, int64_t timeoutNanoseconds) override; @@ -47,6 +51,11 @@ public: } protected: + + aaudio_result_t requestPauseInternal(); + + void onFlushFromServer() override; + /** * Low level write that will not block. It will just write as much as it can. * diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp index 1de33bb8fa..4d0a7b8a54 100644 --- a/media/libaaudio/src/client/IsochronousClockModel.cpp +++ b/media/libaaudio/src/client/IsochronousClockModel.cpp @@ -41,6 +41,13 @@ IsochronousClockModel::IsochronousClockModel() IsochronousClockModel::~IsochronousClockModel() { } +void IsochronousClockModel::setPositionAndTime(int64_t framePosition, int64_t nanoTime) { + ALOGV("IsochronousClockModel::setPositionAndTime(%lld, %lld)", + (long long) framePosition, (long long) nanoTime); + mMarkerFramePosition = framePosition; + mMarkerNanoTime = nanoTime; +} + void IsochronousClockModel::start(int64_t nanoTime) { ALOGD("IsochronousClockModel::start(nanos = %lld)\n", (long long) nanoTime); mMarkerNanoTime = nanoTime; @@ -49,8 +56,8 @@ void IsochronousClockModel::start(int64_t nanoTime) { void IsochronousClockModel::stop(int64_t nanoTime) { ALOGD("IsochronousClockModel::stop(nanos = %lld)\n", (long long) nanoTime); - mMarkerNanoTime = nanoTime; - mMarkerFramePosition = convertTimeToPosition(nanoTime); // TODO should we do this? + setPositionAndTime(convertTimeToPosition(nanoTime), nanoTime); + // TODO should we set position? mState = STATE_STOPPED; } @@ -79,15 +86,13 @@ void IsochronousClockModel::processTimestamp(int64_t framePosition, int64_t nano case STATE_STOPPED: break; case STATE_STARTING: - mMarkerFramePosition = framePosition; - mMarkerNanoTime = nanoTime; + setPositionAndTime(framePosition, nanoTime); mState = STATE_SYNCING; break; case STATE_SYNCING: // This will handle a burst of rapid transfer at the beginning. if (nanosDelta < expectedNanosDelta) { - mMarkerFramePosition = framePosition; - mMarkerNanoTime = nanoTime; + setPositionAndTime(framePosition, nanoTime); } else { // ALOGD("processTimestamp() - advance to STATE_RUNNING"); mState = STATE_RUNNING; @@ -98,17 +103,15 @@ void IsochronousClockModel::processTimestamp(int64_t framePosition, int64_t nano // Earlier than expected timestamp. // This data is probably more accurate so use it. // or we may be drifting due to a slow HW clock. - mMarkerFramePosition = framePosition; - mMarkerNanoTime = nanoTime; // ALOGD("processTimestamp() - STATE_RUNNING - %d < %d micros - EARLY", // (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000)); + setPositionAndTime(framePosition, nanoTime); } else if (nanosDelta > (expectedNanosDelta + mMaxLatenessInNanos)) { // Later than expected timestamp. - mMarkerFramePosition = framePosition; - mMarkerNanoTime = nanoTime - mMaxLatenessInNanos; // ALOGD("processTimestamp() - STATE_RUNNING - %d > %d + %d micros - LATE", // (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000), // (int) (mMaxLatenessInNanos / 1000)); + setPositionAndTime(framePosition - mFramesPerBurst, nanoTime - mMaxLatenessInNanos); } break; default: @@ -131,8 +134,7 @@ void IsochronousClockModel::update() { mMaxLatenessInNanos = (nanosLate > MIN_LATENESS_NANOS) ? nanosLate : MIN_LATENESS_NANOS; } -int64_t IsochronousClockModel::convertDeltaPositionToTime( - int64_t framesDelta) const { +int64_t IsochronousClockModel::convertDeltaPositionToTime(int64_t framesDelta) const { return (AAUDIO_NANOS_PER_SECOND * framesDelta) / mSampleRate; } @@ -148,7 +150,7 @@ int64_t IsochronousClockModel::convertPositionToTime(int64_t framePosition) cons int64_t nextBurstPosition = mFramesPerBurst * nextBurstIndex; int64_t framesDelta = nextBurstPosition - mMarkerFramePosition; int64_t nanosDelta = convertDeltaPositionToTime(framesDelta); - int64_t time = (int64_t) (mMarkerNanoTime + nanosDelta); + int64_t time = mMarkerNanoTime + nanosDelta; // ALOGD("IsochronousClockModel::convertPositionToTime: pos = %llu --> time = %llu", // (unsigned long long)framePosition, // (unsigned long long)time); @@ -171,3 +173,12 @@ int64_t IsochronousClockModel::convertTimeToPosition(int64_t nanoTime) const { // (long long) framesDelta, mFramesPerBurst); return position; } + +void IsochronousClockModel::dump() const { + ALOGD("IsochronousClockModel::mMarkerFramePosition = %lld", (long long) mMarkerFramePosition); + ALOGD("IsochronousClockModel::mMarkerNanoTime = %lld", (long long) mMarkerNanoTime); + ALOGD("IsochronousClockModel::mSampleRate = %6d", mSampleRate); + ALOGD("IsochronousClockModel::mFramesPerBurst = %6d", mFramesPerBurst); + ALOGD("IsochronousClockModel::mMaxLatenessInNanos = %6d", mMaxLatenessInNanos); + ALOGD("IsochronousClockModel::mState = %6d", mState); +} diff --git a/media/libaaudio/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h index 0314f55e7e..585f53a10f 100644 --- a/media/libaaudio/src/client/IsochronousClockModel.h +++ b/media/libaaudio/src/client/IsochronousClockModel.h @@ -43,6 +43,8 @@ public: */ void setSampleRate(int32_t sampleRate); + void setPositionAndTime(int64_t framePosition, int64_t nanoTime); + int32_t getSampleRate() const { return mSampleRate; } @@ -86,6 +88,8 @@ public: */ int64_t convertDeltaTimeToPosition(int64_t nanosDelta) const; + void dump() const; + private: enum clock_model_state_t { STATE_STOPPED, diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp index 76f98faeb8..3f5de770e6 100644 --- a/media/libaaudio/src/core/AAudioAudio.cpp +++ b/media/libaaudio/src/core/AAudioAudio.cpp @@ -253,8 +253,10 @@ AAUDIO_API aaudio_result_t AAudioStream_close(AAudioStream* stream) AAUDIO_API aaudio_result_t AAudioStream_requestStart(AAudioStream* stream) { AudioStream *audioStream = convertAAudioStreamToAudioStream(stream); - ALOGD("AAudioStream_requestStart(%p)", stream); - return audioStream->requestStart(); + ALOGD("AAudioStream_requestStart(%p) called --------------", stream); + aaudio_result_t result = audioStream->requestStart(); + ALOGD("AAudioStream_requestStart(%p) returned ------------", stream); + return result; } AAUDIO_API aaudio_result_t AAudioStream_requestPause(AAudioStream* stream) diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp new file mode 100644 index 0000000000..65c2b46fe0 --- /dev/null +++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp @@ -0,0 +1,91 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#define LOG_TAG "AAudio" +#include <utils/Log.h> +#include <hardware/audio.h> + +#include "AAudioStreamParameters.h" + +using namespace aaudio; + +// TODO These defines should be moved to a central place in audio. +#define SAMPLES_PER_FRAME_MIN 1 +// TODO Remove 8 channel limitation. +#define SAMPLES_PER_FRAME_MAX FCC_8 +#define SAMPLE_RATE_HZ_MIN 8000 +// HDMI supports up to 32 channels at 1536000 Hz. +#define SAMPLE_RATE_HZ_MAX 1600000 + +AAudioStreamParameters::AAudioStreamParameters() {} +AAudioStreamParameters::~AAudioStreamParameters() {} + +aaudio_result_t AAudioStreamParameters::validate() const { + if (mSamplesPerFrame != AAUDIO_UNSPECIFIED + && (mSamplesPerFrame < SAMPLES_PER_FRAME_MIN || mSamplesPerFrame > SAMPLES_PER_FRAME_MAX)) { + ALOGE("AAudioStreamParameters: channelCount out of range = %d", mSamplesPerFrame); + return AAUDIO_ERROR_OUT_OF_RANGE; + } + + if (mDeviceId < 0) { + ALOGE("AAudioStreamParameters: deviceId out of range = %d", mDeviceId); + return AAUDIO_ERROR_OUT_OF_RANGE; + } + + switch (mSharingMode) { + case AAUDIO_SHARING_MODE_EXCLUSIVE: + case AAUDIO_SHARING_MODE_SHARED: + break; + default: + ALOGE("AAudioStreamParameters: illegal sharingMode = %d", mSharingMode); + return AAUDIO_ERROR_ILLEGAL_ARGUMENT; + // break; + } + + switch (mAudioFormat) { + case AAUDIO_FORMAT_UNSPECIFIED: + case AAUDIO_FORMAT_PCM_I16: + case AAUDIO_FORMAT_PCM_FLOAT: + break; // valid + default: + ALOGE("AAudioStreamParameters: audioFormat not valid = %d", mAudioFormat); + return AAUDIO_ERROR_INVALID_FORMAT; + // break; + } + + if (mSampleRate != AAUDIO_UNSPECIFIED + && (mSampleRate < SAMPLE_RATE_HZ_MIN || mSampleRate > SAMPLE_RATE_HZ_MAX)) { + ALOGE("AAudioStreamParameters: sampleRate out of range = %d", mSampleRate); + return AAUDIO_ERROR_INVALID_RATE; + } + + if (mBufferCapacity < 0) { + ALOGE("AAudioStreamParameters: bufferCapacity out of range = %d", mBufferCapacity); + return AAUDIO_ERROR_OUT_OF_RANGE; + } + + return AAUDIO_OK; +} + +void AAudioStreamParameters::dump() const { + ALOGD("AAudioStreamParameters mDeviceId = %d", mDeviceId); + ALOGD("AAudioStreamParameters mSampleRate = %d", mSampleRate); + ALOGD("AAudioStreamParameters mSamplesPerFrame = %d", mSamplesPerFrame); + ALOGD("AAudioStreamParameters mSharingMode = %d", (int)mSharingMode); + ALOGD("AAudioStreamParameters mAudioFormat = %d", (int)mAudioFormat); + ALOGD("AAudioStreamParameters mBufferCapacity = %d", mBufferCapacity); +}
\ No newline at end of file diff --git a/media/libaaudio/src/core/AAudioStreamParameters.h b/media/libaaudio/src/core/AAudioStreamParameters.h new file mode 100644 index 0000000000..97379cc8e3 --- /dev/null +++ b/media/libaaudio/src/core/AAudioStreamParameters.h @@ -0,0 +1,97 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AAUDIO_STREAM_PARAMETERS_H +#define AAUDIO_STREAM_PARAMETERS_H + +#include <stdint.h> + +#include <aaudio/AAudio.h> + +namespace aaudio { + +class AAudioStreamParameters { +public: + AAudioStreamParameters(); + virtual ~AAudioStreamParameters(); + + int32_t getDeviceId() const { + return mDeviceId; + } + + void setDeviceId(int32_t deviceId) { + mDeviceId = deviceId; + } + + int32_t getSampleRate() const { + return mSampleRate; + } + + void setSampleRate(int32_t sampleRate) { + mSampleRate = sampleRate; + } + + int32_t getSamplesPerFrame() const { + return mSamplesPerFrame; + } + + /** + * This is also known as channelCount. + */ + void setSamplesPerFrame(int32_t samplesPerFrame) { + mSamplesPerFrame = samplesPerFrame; + } + + aaudio_format_t getFormat() const { + return mAudioFormat; + } + + void setFormat(aaudio_format_t audioFormat) { + mAudioFormat = audioFormat; + } + + aaudio_sharing_mode_t getSharingMode() const { + return mSharingMode; + } + + void setSharingMode(aaudio_sharing_mode_t sharingMode) { + mSharingMode = sharingMode; + } + + int32_t getBufferCapacity() const { + return mBufferCapacity; + } + + void setBufferCapacity(int32_t frames) { + mBufferCapacity = frames; + } + + virtual aaudio_result_t validate() const; + + void dump() const; + +private: + int32_t mSamplesPerFrame = AAUDIO_UNSPECIFIED; + int32_t mSampleRate = AAUDIO_UNSPECIFIED; + int32_t mDeviceId = AAUDIO_UNSPECIFIED; + aaudio_sharing_mode_t mSharingMode = AAUDIO_SHARING_MODE_SHARED; + aaudio_format_t mAudioFormat = AAUDIO_FORMAT_UNSPECIFIED; + int32_t mBufferCapacity = AAUDIO_UNSPECIFIED; +}; + +} /* namespace aaudio */ + +#endif //AAUDIO_STREAM_PARAMETERS_H
\ No newline at end of file diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp index e1e3c55b59..4859c69032 100644 --- a/media/libaaudio/src/core/AudioStream.cpp +++ b/media/libaaudio/src/core/AudioStream.cpp @@ -36,8 +36,30 @@ AudioStream::AudioStream() setPeriodNanoseconds(0); } +static const char *AudioStream_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode) { + const char *result; + switch (sharingMode) { + case AAUDIO_SHARING_MODE_EXCLUSIVE: + result = "EX"; + break; + case AAUDIO_SHARING_MODE_SHARED: + result = "SH"; + break; + default: + result = "?!"; + break; + } + return result; +} + aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder) { + // Call here as well because the AAudioService will call this without calling build(). + aaudio_result_t result = builder.validate(); + if (result != AAUDIO_OK) { + return result; + } + // Copy parameters from the Builder because the Builder may be deleted after this call. mSamplesPerFrame = builder.getSamplesPerFrame(); mSampleRate = builder.getSampleRate(); @@ -56,44 +78,14 @@ aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder) mErrorCallbackUserData = builder.getErrorCallbackUserData(); // This is very helpful for debugging in the future. Please leave it in. - ALOGI("AudioStream::open() rate = %d, channels = %d, format = %d, sharing = %d, dir = %s", - mSampleRate, mSamplesPerFrame, mFormat, mSharingMode, + ALOGI("AudioStream::open() rate = %d, channels = %d, format = %d, sharing = %s, dir = %s", + mSampleRate, mSamplesPerFrame, mFormat, + AudioStream_convertSharingModeToShortText(mSharingMode), (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT"); - ALOGI("AudioStream::open() device = %d, perfMode = %d, callbackFrames = %d", - mDeviceId, mPerformanceMode, mFramesPerDataCallback); - - // Check for values that are ridiculously out of range to prevent math overflow exploits. - // The service will do a better check. - if (mSamplesPerFrame < 0 || mSamplesPerFrame > 128) { - ALOGE("AudioStream::open(): samplesPerFrame out of range = %d", mSamplesPerFrame); - return AAUDIO_ERROR_OUT_OF_RANGE; - } - - switch(mFormat) { - case AAUDIO_FORMAT_UNSPECIFIED: - case AAUDIO_FORMAT_PCM_I16: - case AAUDIO_FORMAT_PCM_FLOAT: - break; // valid - default: - ALOGE("AudioStream::open(): audioFormat not valid = %d", mFormat); - return AAUDIO_ERROR_INVALID_FORMAT; - // break; - } - - if (mSampleRate != AAUDIO_UNSPECIFIED && (mSampleRate < 8000 || mSampleRate > 1000000)) { - ALOGE("AudioStream::open(): mSampleRate out of range = %d", mSampleRate); - return AAUDIO_ERROR_INVALID_RATE; - } - - switch(mPerformanceMode) { - case AAUDIO_PERFORMANCE_MODE_NONE: - case AAUDIO_PERFORMANCE_MODE_POWER_SAVING: - case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY: - break; - default: - ALOGE("AudioStream::open(): illegal performanceMode %d", mPerformanceMode); - return AAUDIO_ERROR_ILLEGAL_ARGUMENT; - } + ALOGI("AudioStream::open() device = %d, perfMode = %d, callback: %s with frames = %d", + mDeviceId, mPerformanceMode, + (mDataCallbackProc == nullptr ? "OFF" : "ON"), + mFramesPerDataCallback); return AAUDIO_OK; } diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h index 39c9f9c4f2..e5fdcc64c9 100644 --- a/media/libaaudio/src/core/AudioStream.h +++ b/media/libaaudio/src/core/AudioStream.h @@ -48,8 +48,18 @@ public: * Use waitForStateChange() to wait for completion. */ virtual aaudio_result_t requestStart() = 0; - virtual aaudio_result_t requestPause() = 0; - virtual aaudio_result_t requestFlush() = 0; + + virtual aaudio_result_t requestPause() + { + // Only implement this for OUTPUT streams. + return AAUDIO_ERROR_UNIMPLEMENTED; + } + + virtual aaudio_result_t requestFlush() { + // Only implement this for OUTPUT streams. + return AAUDIO_ERROR_UNIMPLEMENTED; + } + virtual aaudio_result_t requestStop() = 0; virtual aaudio_result_t getTimestamp(clockid_t clockId, @@ -84,9 +94,7 @@ public: return AAUDIO_OK; } - virtual aaudio_result_t setBufferSize(int32_t requestedFrames) { - return AAUDIO_ERROR_UNIMPLEMENTED; - } + virtual aaudio_result_t setBufferSize(int32_t requestedFrames) = 0; virtual aaudio_result_t createThread(int64_t periodNanoseconds, aaudio_audio_thread_proc_t threadProc, @@ -186,13 +194,9 @@ public: return AAudioConvert_formatToSizeInBytes(mFormat); } - virtual int64_t getFramesWritten() { - return mFramesWritten.get(); - } + virtual int64_t getFramesWritten() = 0; - virtual int64_t getFramesRead() { - return mFramesRead.get(); - } + virtual int64_t getFramesRead() = 0; AAudioStream_dataCallback getDataCallbackProc() const { return mDataCallbackProc; @@ -218,27 +222,20 @@ public: // ============== I/O =========================== // A Stream will only implement read() or write() depending on its direction. - virtual aaudio_result_t write(const void *buffer, - int32_t numFrames, - int64_t timeoutNanoseconds) { + virtual aaudio_result_t write(const void *buffer __unused, + int32_t numFrames __unused, + int64_t timeoutNanoseconds __unused) { return AAUDIO_ERROR_UNIMPLEMENTED; } - virtual aaudio_result_t read(void *buffer, - int32_t numFrames, - int64_t timeoutNanoseconds) { + virtual aaudio_result_t read(void *buffer __unused, + int32_t numFrames __unused, + int64_t timeoutNanoseconds __unused) { return AAUDIO_ERROR_UNIMPLEMENTED; } protected: - virtual int64_t incrementFramesWritten(int32_t frames) { - return mFramesWritten.increment(frames); - } - - virtual int64_t incrementFramesRead(int32_t frames) { - return mFramesRead.increment(frames); - } /** * This should not be called after the open() call. @@ -281,8 +278,6 @@ protected: std::atomic<bool> mCallbackEnabled; protected: - MonotonicCounter mFramesWritten; - MonotonicCounter mFramesRead; void setPeriodNanoseconds(int64_t periodNanoseconds) { mPeriodNanoseconds.store(periodNanoseconds, std::memory_order_release); diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp index 4262f27c86..43a1ef19f3 100644 --- a/media/libaaudio/src/core/AudioStreamBuilder.cpp +++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp @@ -37,6 +37,19 @@ using namespace aaudio; #define AAUDIO_MMAP_POLICY_DEFAULT AAUDIO_POLICY_NEVER #define AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT AAUDIO_POLICY_NEVER +// These values are for a pre-check before we ask the lower level service to open a stream. +// So they are just outside the maximum conceivable range of value, +// on the edge of being ridiculous. +// TODO These defines should be moved to a central place in audio. +#define SAMPLES_PER_FRAME_MIN 1 +// TODO Remove 8 channel limitation. +#define SAMPLES_PER_FRAME_MAX FCC_8 +#define SAMPLE_RATE_HZ_MIN 8000 +// HDMI supports up to 32 channels at 1536000 Hz. +#define SAMPLE_RATE_HZ_MAX 1600000 +#define FRAMES_PER_DATA_CALLBACK_MIN 1 +#define FRAMES_PER_DATA_CALLBACK_MAX (1024 * 1024) + /* * AudioStreamBuilder */ @@ -85,8 +98,17 @@ static aaudio_result_t builder_createStream(aaudio_direction_t direction, // Exact behavior is controlled by MMapPolicy. aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) { AudioStream *audioStream = nullptr; + if (streamPtr == nullptr) { + ALOGE("AudioStreamBuilder::build() streamPtr is null"); + return AAUDIO_ERROR_NULL; + } *streamPtr = nullptr; + aaudio_result_t result = validate(); + if (result != AAUDIO_OK) { + return result; + } + // The API setting is the highest priority. aaudio_policy_t mmapPolicy = AAudio_getMMapPolicy(); // If not specified then get from a system property. @@ -116,8 +138,13 @@ aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) { bool allowMMap = mmapPolicy != AAUDIO_POLICY_NEVER; bool allowLegacy = mmapPolicy != AAUDIO_POLICY_ALWAYS; - aaudio_result_t result = builder_createStream(getDirection(), sharingMode, - allowMMap, &audioStream); + // TODO Support other performance settings in MMAP mode. + // Disable MMAP if low latency not requested. + if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_LOW_LATENCY) { + allowMMap = false; + } + + result = builder_createStream(getDirection(), sharingMode, allowMMap, &audioStream); if (result == AAUDIO_OK) { // Open the stream using the parameters from the builder. result = audioStream->open(*this); @@ -147,3 +174,45 @@ aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) { return result; } + +aaudio_result_t AudioStreamBuilder::validate() const { + + // Check for values that are ridiculously out of range to prevent math overflow exploits. + // The service will do a better check. + aaudio_result_t result = AAudioStreamParameters::validate(); + if (result != AAUDIO_OK) { + return result; + } + + switch (mDirection) { + case AAUDIO_DIRECTION_INPUT: + case AAUDIO_DIRECTION_OUTPUT: + break; // valid + default: + ALOGE("AudioStreamBuilder: direction not valid = %d", mDirection); + return AAUDIO_ERROR_ILLEGAL_ARGUMENT; + // break; + } + + switch (mPerformanceMode) { + case AAUDIO_PERFORMANCE_MODE_NONE: + case AAUDIO_PERFORMANCE_MODE_POWER_SAVING: + case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY: + break; + default: + ALOGE("AudioStreamBuilder: illegal performanceMode = %d", mPerformanceMode); + return AAUDIO_ERROR_ILLEGAL_ARGUMENT; + // break; + } + + // Prevent ridiculous values from causing problems. + if (mFramesPerDataCallback != AAUDIO_UNSPECIFIED + && (mFramesPerDataCallback < FRAMES_PER_DATA_CALLBACK_MIN + || mFramesPerDataCallback > FRAMES_PER_DATA_CALLBACK_MAX)) { + ALOGE("AudioStreamBuilder: framesPerDataCallback out of range = %d", + mFramesPerDataCallback); + return AAUDIO_ERROR_OUT_OF_RANGE; + } + + return AAUDIO_OK; +} diff --git a/media/libaaudio/src/core/AudioStreamBuilder.h b/media/libaaudio/src/core/AudioStreamBuilder.h index fd416c46a3..6e548b19be 100644 --- a/media/libaaudio/src/core/AudioStreamBuilder.h +++ b/media/libaaudio/src/core/AudioStreamBuilder.h @@ -21,6 +21,7 @@ #include <aaudio/AAudio.h> +#include "AAudioStreamParameters.h" #include "AudioStream.h" namespace aaudio { @@ -28,24 +29,12 @@ namespace aaudio { /** * Factory class for an AudioStream. */ -class AudioStreamBuilder { +class AudioStreamBuilder : public AAudioStreamParameters { public: AudioStreamBuilder(); ~AudioStreamBuilder(); - int getSamplesPerFrame() const { - return mSamplesPerFrame; - } - - /** - * This is also known as channelCount. - */ - AudioStreamBuilder* setSamplesPerFrame(int samplesPerFrame) { - mSamplesPerFrame = samplesPerFrame; - return this; - } - aaudio_direction_t getDirection() const { return mDirection; } @@ -55,33 +44,6 @@ public: return this; } - int32_t getSampleRate() const { - return mSampleRate; - } - - AudioStreamBuilder* setSampleRate(int32_t sampleRate) { - mSampleRate = sampleRate; - return this; - } - - aaudio_format_t getFormat() const { - return mFormat; - } - - AudioStreamBuilder *setFormat(aaudio_format_t format) { - mFormat = format; - return this; - } - - aaudio_sharing_mode_t getSharingMode() const { - return mSharingMode; - } - - AudioStreamBuilder* setSharingMode(aaudio_sharing_mode_t sharingMode) { - mSharingMode = sharingMode; - return this; - } - bool isSharingModeMatchRequired() const { return mSharingModeMatchRequired; } @@ -91,15 +53,6 @@ public: return this; } - int32_t getBufferCapacity() const { - return mBufferCapacity; - } - - AudioStreamBuilder* setBufferCapacity(int32_t frames) { - mBufferCapacity = frames; - return this; - } - int32_t getPerformanceMode() const { return mPerformanceMode; } @@ -109,15 +62,6 @@ public: return this; } - int32_t getDeviceId() const { - return mDeviceId; - } - - AudioStreamBuilder* setDeviceId(int32_t deviceId) { - mDeviceId = deviceId; - return this; - } - AAudioStream_dataCallback getDataCallbackProc() const { return mDataCallbackProc; } @@ -165,15 +109,11 @@ public: aaudio_result_t build(AudioStream **streamPtr); + virtual aaudio_result_t validate() const override; + private: - int32_t mSamplesPerFrame = AAUDIO_UNSPECIFIED; - int32_t mSampleRate = AAUDIO_UNSPECIFIED; - int32_t mDeviceId = AAUDIO_UNSPECIFIED; - aaudio_sharing_mode_t mSharingMode = AAUDIO_SHARING_MODE_SHARED; bool mSharingModeMatchRequired = false; // must match sharing mode requested - aaudio_format_t mFormat = AAUDIO_FORMAT_UNSPECIFIED; aaudio_direction_t mDirection = AAUDIO_DIRECTION_OUTPUT; - int32_t mBufferCapacity = AAUDIO_UNSPECIFIED; aaudio_performance_mode_t mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE; AAudioStream_dataCallback mDataCallbackProc = nullptr; // external callback functions diff --git a/media/libaaudio/src/fifo/FifoBuffer.cpp b/media/libaaudio/src/fifo/FifoBuffer.cpp index 6b4a772207..8d2c62da95 100644 --- a/media/libaaudio/src/fifo/FifoBuffer.cpp +++ b/media/libaaudio/src/fifo/FifoBuffer.cpp @@ -105,16 +105,18 @@ void FifoBuffer::fillWrappingBuffer(WrappingBuffer *wrappingBuffer, } -void FifoBuffer::getFullDataAvailable(WrappingBuffer *wrappingBuffer) { +fifo_frames_t FifoBuffer::getFullDataAvailable(WrappingBuffer *wrappingBuffer) { fifo_frames_t framesAvailable = mFifo->getFullFramesAvailable(); fifo_frames_t startIndex = mFifo->getReadIndex(); fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex); + return framesAvailable; } -void FifoBuffer::getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer) { +fifo_frames_t FifoBuffer::getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer) { fifo_frames_t framesAvailable = mFifo->getEmptyFramesAvailable(); fifo_frames_t startIndex = mFifo->getWriteIndex(); fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex); + return framesAvailable; } fifo_frames_t FifoBuffer::read(void *buffer, fifo_frames_t numFrames) { diff --git a/media/libaaudio/src/fifo/FifoBuffer.h b/media/libaaudio/src/fifo/FifoBuffer.h index 2b262a1bd6..a94e9b031e 100644 --- a/media/libaaudio/src/fifo/FifoBuffer.h +++ b/media/libaaudio/src/fifo/FifoBuffer.h @@ -64,16 +64,18 @@ public: * if the data is split across the end of the FIFO then set data2 and numFrames2. * Other wise set them to null * @param wrappingBuffer + * @return total full frames available */ - void getFullDataAvailable(WrappingBuffer *wrappingBuffer); + fifo_frames_t getFullDataAvailable(WrappingBuffer *wrappingBuffer); /** * Return pointer to available empty frames in data1 and set size in numFrames1. * if the room is split across the end of the FIFO then set data2 and numFrames2. * Other wise set them to null * @param wrappingBuffer + * @return total empty frames available */ - void getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer); + fifo_frames_t getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer); /** * Copy data from the FIFO into the buffer. diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.h b/media/libaaudio/src/legacy/AudioStreamLegacy.h index 0ded8e1fe6..d2ef3c7fde 100644 --- a/media/libaaudio/src/legacy/AudioStreamLegacy.h +++ b/media/libaaudio/src/legacy/AudioStreamLegacy.h @@ -74,6 +74,15 @@ public: virtual int64_t incrementClientFrameCounter(int32_t frames) = 0; + + virtual int64_t getFramesWritten() override { + return mFramesWritten.get(); + } + + virtual int64_t getFramesRead() override { + return mFramesRead.get(); + } + protected: class StreamDeviceCallback : public android::AudioSystem::AudioDeviceCallback @@ -103,6 +112,17 @@ protected: void onStart() { mCallbackEnabled.store(true); } void onStop() { mCallbackEnabled.store(false); } + int64_t incrementFramesWritten(int32_t frames) { + return mFramesWritten.increment(frames); + } + + int64_t incrementFramesRead(int32_t frames) { + return mFramesRead.increment(frames); + } + + MonotonicCounter mFramesWritten; + MonotonicCounter mFramesRead; + FixedBlockAdapter *mBlockAdapter = nullptr; aaudio_wrapping_frames_t mPositionWhenStarting = 0; int32_t mCallbackBufferSize = 0; diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp index 156e83dd6a..8e8070c922 100644 --- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp +++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp @@ -55,7 +55,7 @@ aaudio_result_t AudioStreamRecord::open(const AudioStreamBuilder& builder) // Try to create an AudioRecord - // TODO Support UNSPECIFIED in AudioTrack. For now, use stereo if unspecified. + // TODO Support UNSPECIFIED in AudioRecord. For now, use stereo if unspecified. int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED) ? 2 : getSamplesPerFrame(); audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(samplesPerFrame); @@ -130,8 +130,8 @@ aaudio_result_t AudioStreamRecord::open(const AudioStreamBuilder& builder) return AAudioConvert_androidToAAudioResult(status); } - // Get the actual rate. - setSampleRate(mAudioRecord->getSampleRate()); + // Get the actual values from the AudioRecord. + setSamplesPerFrame(mAudioRecord->channelCount()); setFormat(AAudioConvert_androidToAAudioDataFormat(mAudioRecord->format())); int32_t actualSampleRate = mAudioRecord->getSampleRate(); @@ -223,18 +223,6 @@ aaudio_result_t AudioStreamRecord::requestStart() return AAUDIO_OK; } -aaudio_result_t AudioStreamRecord::requestPause() -{ - // This does not make sense for an input stream. - // There is no real difference between pause() and stop(). - return AAUDIO_ERROR_UNIMPLEMENTED; -} - -aaudio_result_t AudioStreamRecord::requestFlush() { - // This does not make sense for an input stream. - return AAUDIO_ERROR_UNIMPLEMENTED; -} - aaudio_result_t AudioStreamRecord::requestStop() { if (mAudioRecord.get() == nullptr) { return AAUDIO_ERROR_INVALID_STATE; diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.h b/media/libaaudio/src/legacy/AudioStreamRecord.h index 90000fc1b3..2c6a7ebe14 100644 --- a/media/libaaudio/src/legacy/AudioStreamRecord.h +++ b/media/libaaudio/src/legacy/AudioStreamRecord.h @@ -41,8 +41,6 @@ public: aaudio_result_t close() override; aaudio_result_t requestStart() override; - aaudio_result_t requestPause() override; - aaudio_result_t requestFlush() override; aaudio_result_t requestStop() override; virtual aaudio_result_t getTimestamp(clockid_t clockId, diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp index 7e399083ec..77f31e275c 100644 --- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp +++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp @@ -423,7 +423,7 @@ int64_t AudioStreamTrack::getFramesRead() { default: break; } - return AudioStream::getFramesRead(); + return AudioStreamLegacy::getFramesRead(); } aaudio_result_t AudioStreamTrack::getTimestamp(clockid_t clockId, diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp index 164784dbdd..2450920974 100644 --- a/media/libaaudio/src/utility/AAudioUtilities.cpp +++ b/media/libaaudio/src/utility/AAudioUtilities.cpp @@ -208,9 +208,12 @@ status_t AAudioConvert_aaudioToAndroidStatus(aaudio_result_t result) { status_t status; switch (result) { case AAUDIO_ERROR_DISCONNECTED: - case AAUDIO_ERROR_INVALID_HANDLE: + case AAUDIO_ERROR_NO_SERVICE: status = DEAD_OBJECT; break; + case AAUDIO_ERROR_INVALID_HANDLE: + status = BAD_TYPE; + break; case AAUDIO_ERROR_INVALID_STATE: status = INVALID_OPERATION; break; @@ -226,14 +229,16 @@ status_t AAudioConvert_aaudioToAndroidStatus(aaudio_result_t result) { case AAUDIO_ERROR_NULL: status = UNEXPECTED_NULL; break; + case AAUDIO_ERROR_UNAVAILABLE: + status = NOT_ENOUGH_DATA; + break; + // TODO translate these result codes case AAUDIO_ERROR_INTERNAL: case AAUDIO_ERROR_UNIMPLEMENTED: - case AAUDIO_ERROR_UNAVAILABLE: case AAUDIO_ERROR_NO_FREE_HANDLES: case AAUDIO_ERROR_NO_MEMORY: case AAUDIO_ERROR_TIMEOUT: - case AAUDIO_ERROR_NO_SERVICE: default: status = UNKNOWN_ERROR; break; @@ -257,15 +262,18 @@ aaudio_result_t AAudioConvert_androidToAAudioResult(status_t status) { case INVALID_OPERATION: result = AAUDIO_ERROR_INVALID_STATE; break; - case UNEXPECTED_NULL: - result = AAUDIO_ERROR_NULL; - break; - case BAD_VALUE: - result = AAUDIO_ERROR_ILLEGAL_ARGUMENT; - break; + case UNEXPECTED_NULL: + result = AAUDIO_ERROR_NULL; + break; + case BAD_VALUE: + result = AAUDIO_ERROR_ILLEGAL_ARGUMENT; + break; case WOULD_BLOCK: result = AAUDIO_ERROR_WOULD_BLOCK; break; + case NOT_ENOUGH_DATA: + result = AAUDIO_ERROR_UNAVAILABLE; + break; default: result = AAUDIO_ERROR_INTERNAL; break; @@ -361,12 +369,43 @@ int32_t AAudioProperty_getMixerBursts() { return prop; } +int32_t AAudioProperty_getWakeupDelayMicros() { + const int32_t minMicros = 0; // arbitrary + const int32_t defaultMicros = 200; // arbitrary, based on some observed jitter + const int32_t maxMicros = 5000; // arbitrary, probably don't want more than 500 + int32_t prop = property_get_int32(AAUDIO_PROP_WAKEUP_DELAY_USEC, defaultMicros); + if (prop < minMicros) { + ALOGW("AAudioProperty_getWakeupDelayMicros: clipped %d to %d", prop, minMicros); + prop = minMicros; + } else if (prop > maxMicros) { + ALOGW("AAudioProperty_getWakeupDelayMicros: clipped %d to %d", prop, maxMicros); + prop = maxMicros; + } + return prop; +} + +int32_t AAudioProperty_getMinimumSleepMicros() { + const int32_t minMicros = 20; // arbitrary + const int32_t defaultMicros = 200; // arbitrary + const int32_t maxMicros = 2000; // arbitrary + int32_t prop = property_get_int32(AAUDIO_PROP_MINIMUM_SLEEP_USEC, defaultMicros); + if (prop < minMicros) { + ALOGW("AAudioProperty_getMinimumSleepMicros: clipped %d to %d", prop, minMicros); + prop = minMicros; + } else if (prop > maxMicros) { + ALOGW("AAudioProperty_getMinimumSleepMicros: clipped %d to %d", prop, maxMicros); + prop = maxMicros; + } + return prop; +} + int32_t AAudioProperty_getHardwareBurstMinMicros() { const int32_t defaultMicros = 1000; // arbitrary const int32_t maxMicros = 1000 * 1000; // arbitrary int32_t prop = property_get_int32(AAUDIO_PROP_HW_BURST_MIN_USEC, defaultMicros); if (prop < 1 || prop > maxMicros) { - ALOGE("AAudioProperty_getHardwareBurstMinMicros: invalid = %d", prop); + ALOGE("AAudioProperty_getHardwareBurstMinMicros: invalid = %d, use %d", + prop, defaultMicros); prop = defaultMicros; } return prop; diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h index f894bc061e..acd319bf98 100644 --- a/media/libaaudio/src/utility/AAudioUtilities.h +++ b/media/libaaudio/src/utility/AAudioUtilities.h @@ -17,6 +17,8 @@ #ifndef UTILITY_AAUDIO_UTILITIES_H #define UTILITY_AAUDIO_UTILITIES_H +#include <algorithm> +#include <functional> #include <stdint.h> #include <sys/types.h> @@ -193,13 +195,35 @@ int32_t AAudioProperty_getMMapExclusivePolicy(); /** * Read system property. - * @return number of bursts per mixer cycle + * @return number of bursts per AAudio service mixer cycle */ int32_t AAudioProperty_getMixerBursts(); #define AAUDIO_PROP_HW_BURST_MIN_USEC "aaudio.hw_burst_min_usec" /** + * Read a system property that specifies the number of extra microseconds that a thread + * should sleep when waiting for another thread to service a FIFO. This is used + * to avoid the waking thread from being overly optimistic about the other threads + * wakeup timing. This value should be set high enough to cover typical scheduling jitter + * for a real-time thread. + * + * @return number of microseconds to delay the wakeup. + */ +int32_t AAudioProperty_getWakeupDelayMicros(); + +#define AAUDIO_PROP_WAKEUP_DELAY_USEC "aaudio.wakeup_delay_usec" + +/** + * Read a system property that specifies the minimum sleep time when polling the FIFO. + * + * @return minimum number of microseconds to sleep. + */ +int32_t AAudioProperty_getMinimumSleepMicros(); + +#define AAUDIO_PROP_MINIMUM_SLEEP_USEC "aaudio.minimum_sleep_usec" + +/** * Read system property. * This is handy in case the DMA is bursting too quickly for the CPU to keep up. * For example, there may be a DMA burst every 100 usec but you only @@ -211,4 +235,27 @@ int32_t AAudioProperty_getMixerBursts(); */ int32_t AAudioProperty_getHardwareBurstMinMicros(); +/** + * Try a function f until it returns true. + * + * The function is always called at least once. + * + * @param f the function to evaluate, which returns a bool. + * @param times the number of times to evaluate f. + * @param sleepMs the sleep time per check of f, if greater than 0. + * @return true if f() eventually returns true. + */ +static inline bool AAudio_tryUntilTrue( + std::function<bool()> f, int times, int sleepMs) { + static const useconds_t US_PER_MS = 1000; + + sleepMs = std::max(sleepMs, 0); + for (;;) { + if (f()) return true; + if (times <= 1) return false; + --times; + usleep(sleepMs * US_PER_MS); + } +} + #endif //UTILITY_AAUDIO_UTILITIES_H diff --git a/media/libaaudio/src/utility/HandleTracker.cpp b/media/libaaudio/src/utility/HandleTracker.cpp index f9572348e0..35ce95a1a4 100644 --- a/media/libaaudio/src/utility/HandleTracker.cpp +++ b/media/libaaudio/src/utility/HandleTracker.cpp @@ -20,11 +20,15 @@ #include <utils/Log.h> #include <assert.h> +#include <functional> +#include <iomanip> #include <new> +#include <sstream> #include <stdint.h> #include <utils/Mutex.h> #include <aaudio/AAudio.h> +#include "AAudioUtilities.h" #include "HandleTracker.h" using android::Mutex; @@ -93,6 +97,47 @@ bool HandleTracker::isInitialized() const { return mHandleAddresses != nullptr; } + + +std::string HandleTracker::dump() const { + if (!isInitialized()) { + return "HandleTracker is not initialized\n"; + } + + std::stringstream result; + const bool isLocked = AAudio_tryUntilTrue( + [this]()->bool { return mLock.tryLock(); } /* f */, + 50 /* times */, + 20 /* sleepMs */); + if (!isLocked) { + result << "HandleTracker may be deadlocked\n"; + } + + result << "HandleTracker:\n"; + result << " HandleHeaders:\n"; + // atLineStart() can be changed to support an arbitrary line breaking algorithm; + // it should return true when a new line starts. + // For simplicity, we will use a constant 16 items per line. + const auto atLineStart = [](int index) -> bool { + // Magic constant of 0xf used for mask to detect start every 16 items. + return (index & 0xf) == 0; }; + const auto atLineEnd = [this, &atLineStart](int index) -> bool { + return atLineStart(index + 1) || index == mMaxHandleCount - 1; }; + + for (int i = 0; i < mMaxHandleCount; ++i) { + if (atLineStart(i)) { + result << " "; + } + result << std::hex << std::setw(4) << std::setfill('0') << mHandleHeaders[i] + << (atLineEnd(i) ? "\n" : " "); + } + + if (isLocked) { + mLock.unlock(); + } + return result.str(); +} + handle_tracker_slot_t HandleTracker::allocateSlot_l() { void **allocated = mNextFreeAddress; if (allocated == nullptr) { diff --git a/media/libaaudio/src/utility/HandleTracker.h b/media/libaaudio/src/utility/HandleTracker.h index 23a73edbec..a4c51c01d7 100644 --- a/media/libaaudio/src/utility/HandleTracker.h +++ b/media/libaaudio/src/utility/HandleTracker.h @@ -18,6 +18,7 @@ #define UTILITY_HANDLE_TRACKER_H #include <stdint.h> +#include <string> #include <utils/Mutex.h> typedef int32_t aaudio_handle_t; @@ -53,6 +54,18 @@ public: bool isInitialized() const; /** + * Returns HandleTracker information. + * + * Will attempt to get the object lock, but will proceed + * even if it cannot. + * + * Each line of information ends with a newline. + * + * @return a string representing the HandleTracker info. + */ + std::string dump() const; + + /** * Store a pointer and return a handle that can be used to retrieve the pointer. * * It is safe to call put() or remove() from multiple threads. @@ -99,7 +112,7 @@ private: // This Mutex protects the linked list of free nodes. // The list is managed using mHandleAddresses and mNextFreeAddress. // The data in mHandleHeaders is only changed by put() and remove(). - android::Mutex mLock; + mutable android::Mutex mLock; /** * Pull slot off of a list of empty slots. diff --git a/media/libaaudio/tests/Android.mk b/media/libaaudio/tests/Android.mk index afcdebfd5f..e4eef06354 100644 --- a/media/libaaudio/tests/Android.mk +++ b/media/libaaudio/tests/Android.mk @@ -6,9 +6,7 @@ LOCAL_C_INCLUDES := \ frameworks/av/media/libaaudio/include \ frameworks/av/media/libaaudio/src LOCAL_SRC_FILES:= test_handle_tracker.cpp -LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \ - libcutils liblog libmedia libutils libaudiomanager -LOCAL_STATIC_LIBRARIES := libaaudio +LOCAL_SHARED_LIBRARIES := libaaudio LOCAL_MODULE := test_handle_tracker include $(BUILD_NATIVE_TEST) @@ -18,9 +16,7 @@ LOCAL_C_INCLUDES := \ frameworks/av/media/libaaudio/include \ frameworks/av/media/libaaudio/src LOCAL_SRC_FILES:= test_marshalling.cpp -LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \ - libcutils liblog libmedia libutils libaudiomanager -LOCAL_STATIC_LIBRARIES := libaaudio +LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils LOCAL_MODULE := test_aaudio_marshalling include $(BUILD_NATIVE_TEST) @@ -30,9 +26,7 @@ LOCAL_C_INCLUDES := \ frameworks/av/media/libaaudio/include \ frameworks/av/media/libaaudio/src LOCAL_SRC_FILES:= test_block_adapter.cpp -LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \ - libcutils liblog libmedia libutils libaudiomanager -LOCAL_STATIC_LIBRARIES := libaaudio +LOCAL_SHARED_LIBRARIES := libaaudio LOCAL_MODULE := test_block_adapter include $(BUILD_NATIVE_TEST) @@ -42,9 +36,7 @@ LOCAL_C_INCLUDES := \ frameworks/av/media/libaaudio/include \ frameworks/av/media/libaaudio/src LOCAL_SRC_FILES:= test_linear_ramp.cpp -LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \ - libcutils liblog libmedia libutils libaudiomanager -LOCAL_STATIC_LIBRARIES := libaaudio +LOCAL_SHARED_LIBRARIES := libaaudio LOCAL_MODULE := test_linear_ramp include $(BUILD_NATIVE_TEST) @@ -54,8 +46,36 @@ LOCAL_C_INCLUDES := \ frameworks/av/media/libaaudio/include \ frameworks/av/media/libaaudio/src LOCAL_SRC_FILES:= test_open_params.cpp -LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \ - libcutils liblog libmedia libutils libaudiomanager -LOCAL_STATIC_LIBRARIES := libaaudio +LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils LOCAL_MODULE := test_open_params include $(BUILD_NATIVE_TEST) + +include $(CLEAR_VARS) +LOCAL_C_INCLUDES := \ + $(call include-path-for, audio-utils) \ + frameworks/av/media/libaaudio/include \ + frameworks/av/media/libaaudio/src +LOCAL_SRC_FILES:= test_no_close.cpp +LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils +LOCAL_MODULE := test_no_close +include $(BUILD_NATIVE_TEST) + +include $(CLEAR_VARS) +LOCAL_C_INCLUDES := \ + $(call include-path-for, audio-utils) \ + frameworks/av/media/libaaudio/include \ + frameworks/av/media/libaaudio/src +LOCAL_SRC_FILES:= test_recovery.cpp +LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils +LOCAL_MODULE := test_aaudio_recovery +include $(BUILD_NATIVE_TEST) + +include $(CLEAR_VARS) +LOCAL_C_INCLUDES := \ + $(call include-path-for, audio-utils) \ + frameworks/av/media/libaaudio/include \ + frameworks/av/media/libaaudio/src +LOCAL_SRC_FILES:= test_n_streams.cpp +LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils +LOCAL_MODULE := test_n_streams +include $(BUILD_NATIVE_TEST) diff --git a/media/libaaudio/tests/test_marshalling.cpp b/media/libaaudio/tests/test_marshalling.cpp index 79beed64cf..c51fbce4dc 100644 --- a/media/libaaudio/tests/test_marshalling.cpp +++ b/media/libaaudio/tests/test_marshalling.cpp @@ -19,6 +19,7 @@ #include <stdlib.h> #include <math.h> +#include <android-base/unique_fd.h> #include <binder/Parcel.h> #include <binder/Parcelable.h> #include <cutils/ashmem.h> @@ -28,6 +29,7 @@ #include <aaudio/AAudio.h> #include <binding/AudioEndpointParcelable.h> +using android::base::unique_fd; using namespace android; using namespace aaudio; @@ -48,7 +50,7 @@ TEST(test_marshalling, aaudio_shared_memory) { SharedMemoryParcelable sharedMemoryA; SharedMemoryParcelable sharedMemoryB; const size_t memSizeBytes = 840; - int fd = ashmem_create_region("TestMarshalling", memSizeBytes); + unique_fd fd(ashmem_create_region("TestMarshalling", memSizeBytes)); ASSERT_LE(0, fd); sharedMemoryA.setup(fd, memSizeBytes); void *region1; @@ -81,7 +83,7 @@ TEST(test_marshalling, aaudio_shared_region) { SharedRegionParcelable sharedRegionA; SharedRegionParcelable sharedRegionB; const size_t memSizeBytes = 840; - int fd = ashmem_create_region("TestMarshalling", memSizeBytes); + unique_fd fd(ashmem_create_region("TestMarshalling", memSizeBytes)); ASSERT_LE(0, fd); sharedMemories[0].setup(fd, memSizeBytes); int32_t regionOffset1 = 32; @@ -119,7 +121,7 @@ TEST(test_marshalling, aaudio_ring_buffer_parcelable) { const int32_t counterSizeBytes = sizeof(int64_t); const size_t memSizeBytes = dataSizeBytes + (2 * counterSizeBytes); - int fd = ashmem_create_region("TestMarshalling", memSizeBytes); + unique_fd fd(ashmem_create_region("TestMarshalling Z", memSizeBytes)); ASSERT_LE(0, fd); sharedMemories[0].setup(fd, memSizeBytes); diff --git a/media/libaaudio/tests/test_n_streams.cpp b/media/libaaudio/tests/test_n_streams.cpp new file mode 100644 index 0000000000..271d024d07 --- /dev/null +++ b/media/libaaudio/tests/test_n_streams.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2017 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. + */ + +// Try to create as many streams as possible and report the maximum. + +#include <stdio.h> +#include <stdlib.h> +#include <aaudio/AAudio.h> +#include <aaudio/AAudioTesting.h> + +//#define MMAP_POLICY AAUDIO_UNSPECIFIED +//#define MMAP_POLICY AAUDIO_POLICY_NEVER +#define MMAP_POLICY AAUDIO_POLICY_AUTO +//#define MMAP_POLICY AAUDIO_POLICY_ALWAYS + +#define MAX_STREAMS 200 + +aaudio_result_t testMaxStreams(aaudio_direction_t direction) { + aaudio_result_t result = AAUDIO_OK; + AAudioStreamBuilder *aaudioBuilder = nullptr; + AAudioStream *aaudioStreams[MAX_STREAMS]; + int32_t numStreams = 0; + + result = AAudio_createStreamBuilder(&aaudioBuilder); + if (result != AAUDIO_OK) { + return 1; + } + + AAudioStreamBuilder_setDirection(aaudioBuilder, direction); + + for (int i = 0; i < MAX_STREAMS; i++) { + // Create an AAudioStream using the Builder. + result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStreams[i]); + if (result != AAUDIO_OK) { + printf("ERROR could not open AAudio stream, %d %s\n", + result, AAudio_convertResultToText(result)); + break; + } else { + printf("AAudio stream[%2d] opened successfully. MMAP = %s\n", + i, AAudioStream_isMMapUsed(aaudioStreams[i]) ? "YES" : "NO"); + numStreams++; + } + } + + printf("Created %d streams!\n", numStreams); + + // Close all the streams. + for (int i = 0; i < numStreams; i++) { + result = AAudioStream_close(aaudioStreams[i]); + if (result != AAUDIO_OK) { + printf("ERROR could not close AAudio stream, %d %s\n", + result, AAudio_convertResultToText(result)); + break; + } else { + printf("AAudio stream[%2d] closed successfully.\n", i); + } + } + + AAudioStreamBuilder_delete(aaudioBuilder); + +finish: + return result; +} + +int main(int argc, char **argv) { + (void)argc; // unused + (void)argv; // unused + + // Make printf print immediately so that debug info is not stuck + // in a buffer if we hang or crash. + setvbuf(stdout, NULL, _IONBF, (size_t) 0); + + printf("Try to open a maximum of %d streams.\n", MAX_STREAMS); + + AAudio_setMMapPolicy(MMAP_POLICY); + printf("requested MMapPolicy = %d\n", AAudio_getMMapPolicy()); + + printf("Test AAUDIO_DIRECTION_OUTPUT ---------\n"); + aaudio_result_t result = testMaxStreams(AAUDIO_DIRECTION_OUTPUT); + if (result == AAUDIO_OK) { + printf("Test AAUDIO_DIRECTION_INPUT ---------\n"); + result = testMaxStreams(AAUDIO_DIRECTION_INPUT); + } + + return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/media/libaaudio/tests/test_no_close.cpp b/media/libaaudio/tests/test_no_close.cpp new file mode 100644 index 0000000000..2dbf153656 --- /dev/null +++ b/media/libaaudio/tests/test_no_close.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2017 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. + */ + +// Try to create a resource leak in the server by opening a stream and then not closing it. +// Return 0 if the stream opened, 1 if it failed. + +#include <stdio.h> +#include <stdlib.h> +#include <aaudio/AAudio.h> + +int main(int argc, char **argv) +{ + (void)argc; // unused + (void)argv; // unused + + aaudio_result_t result = AAUDIO_OK; + AAudioStreamBuilder *aaudioBuilder = nullptr; + AAudioStream *aaudioStream = nullptr; + + result = AAudio_createStreamBuilder(&aaudioBuilder); + if (result != AAUDIO_OK) { + goto finish; + } + + // Create an AAudioStream using the Builder. + result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream); + if (result != AAUDIO_OK) { + printf("ERROR could not open AAudio stream, %d\n", result); + goto finish; + } else { + printf("AAudio stream opened successfully.\n"); + } + + printf("Exit without closing the stream!\n"); + +finish: + return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS; +} + diff --git a/media/libaaudio/tests/test_recovery.cpp b/media/libaaudio/tests/test_recovery.cpp new file mode 100644 index 0000000000..7268a30618 --- /dev/null +++ b/media/libaaudio/tests/test_recovery.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2017 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. + */ + +// Play silence and recover from dead servers or disconnected devices. + +#include <stdio.h> + +#include <aaudio/AAudio.h> + + +#define DEFAULT_TIMEOUT_NANOS ((int64_t)1000000000) + +static const char *getSharingModeText(aaudio_sharing_mode_t mode) { + const char *modeText = "unknown"; + switch (mode) { + case AAUDIO_SHARING_MODE_EXCLUSIVE: + modeText = "EXCLUSIVE"; + break; + case AAUDIO_SHARING_MODE_SHARED: + modeText = "SHARED"; + break; + default: + break; + } + return modeText; +} + +int main(int argc, char **argv) { + (void) argc; + (void *)argv; + + aaudio_result_t result = AAUDIO_OK; + + int32_t triesLeft = 3; + int32_t bufferCapacity; + int32_t framesPerBurst = 0; + float *buffer = nullptr; + + int32_t actualChannelCount = 0; + int32_t actualSampleRate = 0; + aaudio_format_t actualDataFormat = AAUDIO_FORMAT_PCM_FLOAT; + aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED; + + AAudioStreamBuilder *aaudioBuilder = nullptr; + AAudioStream *aaudioStream = nullptr; + + // Make printf print immediately so that debug info is not stuck + // in a buffer if we hang or crash. + setvbuf(stdout, nullptr, _IONBF, (size_t) 0); + + printf("TestRecovery:\n"); + + // Use an AAudioStreamBuilder to contain requested parameters. + result = AAudio_createStreamBuilder(&aaudioBuilder); + if (result != AAUDIO_OK) { + printf("AAudio_createStreamBuilder returned %s", + AAudio_convertResultToText(result)); + goto finish; + } + + // Request stream properties. + AAudioStreamBuilder_setFormat(aaudioBuilder, AAUDIO_FORMAT_PCM_FLOAT); + + while (triesLeft-- > 0) { + // Create an AAudioStream using the Builder. + result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream); + if (result != AAUDIO_OK) { + printf("AAudioStreamBuilder_openStream returned %s", + AAudio_convertResultToText(result)); + goto finish; + } + + // Check to see what kind of stream we actually got. + actualSampleRate = AAudioStream_getSampleRate(aaudioStream); + actualChannelCount = AAudioStream_getChannelCount(aaudioStream); + actualDataFormat = AAudioStream_getFormat(aaudioStream); + + printf("-------- chans = %3d, rate = %6d format = %d\n", + actualChannelCount, actualSampleRate, actualDataFormat); + + // This is the number of frames that are read in one chunk by a DMA controller + // or a DSP or a mixer. + framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream); + bufferCapacity = AAudioStream_getBufferCapacityInFrames(aaudioStream); + printf(" bufferCapacity = %d, framesPerBurst = %d\n", + bufferCapacity, framesPerBurst); + + int samplesPerBurst = framesPerBurst * actualChannelCount; + buffer = new float[samplesPerBurst]; + + result = AAudioStream_requestStart(aaudioStream); + if (result != AAUDIO_OK) { + printf("AAudioStream_requestStart returned %s", + AAudio_convertResultToText(result)); + goto finish; + } + + // Play silence for awhile. + int32_t framesMax = actualSampleRate * 20; + int64_t framesTotal = 0; + int64_t printAt = actualSampleRate; + while (result == AAUDIO_OK && framesTotal < framesMax) { + int32_t framesWritten = AAudioStream_write(aaudioStream, + buffer, framesPerBurst, + DEFAULT_TIMEOUT_NANOS); + if (framesWritten < 0) { + result = framesWritten; + printf("write() returned %s, frames = %d\n", + AAudio_convertResultToText(result), (int)framesTotal); + printf(" frames = %d\n", (int)framesTotal); + } else if (framesWritten != framesPerBurst) { + printf("write() returned %d, frames = %d\n", framesWritten, (int)framesTotal); + result = AAUDIO_ERROR_TIMEOUT; + } else { + framesTotal += framesWritten; + if (framesTotal >= printAt) { + printf("frames = %d\n", (int)framesTotal); + printAt += actualSampleRate; + } + } + } + result = AAudioStream_requestStop(aaudioStream); + if (result != AAUDIO_OK) { + printf("AAudioStream_requestStop returned %s\n", + AAudio_convertResultToText(result)); + } + result = AAudioStream_close(aaudioStream); + if (result != AAUDIO_OK) { + printf("AAudioStream_close returned %s\n", + AAudio_convertResultToText(result)); + } + aaudioStream = nullptr; + } + +finish: + if (aaudioStream != nullptr) { + AAudioStream_close(aaudioStream); + } + AAudioStreamBuilder_delete(aaudioBuilder); + delete[] buffer; + printf(" result = %d = %s\n", result, AAudio_convertResultToText(result)); +} diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp index d853946ae6..61c946c89a 100644 --- a/media/libaudioclient/Android.bp +++ b/media/libaudioclient/Android.bp @@ -43,7 +43,6 @@ cc_library_shared { // for memory heap analysis static_libs: [ "libc_malloc_debug_backtrace", - "libc_logging", ], cflags: [ "-Wall", diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp index e749ac4563..611cde7cc2 100644 --- a/media/libaudioclient/AudioRecord.cpp +++ b/media/libaudioclient/AudioRecord.cpp @@ -69,7 +69,8 @@ AudioRecord::AudioRecord(const String16 &opPackageName) : mActive(false), mStatus(NO_INIT), mOpPackageName(opPackageName), mSessionId(AUDIO_SESSION_ALLOCATE), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), - mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mPortId(AUDIO_PORT_HANDLE_NONE) + mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE), + mPortId(AUDIO_PORT_HANDLE_NONE) { } @@ -503,10 +504,29 @@ audio_port_handle_t AudioRecord::getRoutedDeviceId() { if (mInput == AUDIO_IO_HANDLE_NONE) { return AUDIO_PORT_HANDLE_NONE; } - return AudioSystem::getDeviceIdForIo(mInput); + // if the input stream does not have an active audio patch, use either the device initially + // selected by audio policy manager or the last routed device + audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mInput); + if (deviceId == AUDIO_PORT_HANDLE_NONE) { + deviceId = mRoutedDeviceId; + } + mRoutedDeviceId = deviceId; + return deviceId; } // ------------------------------------------------------------------------- +// TODO Move this macro to a common header file for enum to string conversion in audio framework. +#define MEDIA_CASE_ENUM(name) case name: return #name +const char * AudioRecord::convertTransferToText(transfer_type transferType) { + switch (transferType) { + MEDIA_CASE_ENUM(TRANSFER_DEFAULT); + MEDIA_CASE_ENUM(TRANSFER_CALLBACK); + MEDIA_CASE_ENUM(TRANSFER_OBTAIN); + MEDIA_CASE_ENUM(TRANSFER_SYNC); + default: + return "UNRECOGNIZED"; + } +} // must be called with mLock held status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName) @@ -538,13 +558,14 @@ status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16 .channel_mask = mChannelMask, .format = mFormat }; + mRoutedDeviceId = mSelectedDeviceId; status = AudioSystem::getInputForAttr(&mAttributes, &input, mSessionId, // FIXME compare to AudioTrack mClientPid, mClientUid, &config, - mFlags, mSelectedDeviceId, &mPortId); + mFlags, &mRoutedDeviceId, &mPortId); if (status != NO_ERROR || input == AUDIO_IO_HANDLE_NONE) { ALOGE("Could not get audio input for session %d, record source %d, sample rate %u, " @@ -590,12 +611,20 @@ status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16 (mTransfer == TRANSFER_SYNC) || // use case 3: obtain/release mode (mTransfer == TRANSFER_OBTAIN); + if (!useCaseAllowed) { + ALOGW("AUDIO_INPUT_FLAG_FAST denied, incompatible transfer = %s", + convertTransferToText(mTransfer)); + } + // sample rates must also match - bool fastAllowed = useCaseAllowed && (mSampleRate == afSampleRate); + bool sampleRateAllowed = mSampleRate == afSampleRate; + if (!sampleRateAllowed) { + ALOGW("AUDIO_INPUT_FLAG_FAST denied, rates do not match %u Hz, require %u Hz", + mSampleRate, afSampleRate); + } + + bool fastAllowed = useCaseAllowed && sampleRateAllowed; if (!fastAllowed) { - ALOGW("AUDIO_INPUT_FLAG_FAST denied by client; transfer %d, " - "track %u Hz, input %u Hz", - mTransfer, mSampleRate, afSampleRate); mFlags = (audio_input_flags_t) (mFlags & ~(AUDIO_INPUT_FLAG_FAST | AUDIO_INPUT_FLAG_RAW)); AudioSystem::releaseInput(input, mSessionId); @@ -1272,6 +1301,7 @@ bool AudioRecord::AudioRecordThread::threadLoop() { AutoMutex _l(mMyLock); if (mPaused) { + // TODO check return value and handle or log mMyCond.wait(mMyLock); // caller will check for exitPending() return true; @@ -1282,8 +1312,10 @@ bool AudioRecord::AudioRecordThread::threadLoop() } if (mPausedInt) { if (mPausedNs > 0) { + // TODO check return value and handle or log (void) mMyCond.waitRelative(mMyLock, mPausedNs); } else { + // TODO check return value and handle or log mMyCond.wait(mMyLock); } mPausedInt = false; diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp index 9ef1db7f83..2f710bd930 100644 --- a/media/libaudioclient/AudioSystem.cpp +++ b/media/libaudioclient/AudioSystem.cpp @@ -819,7 +819,7 @@ status_t AudioSystem::getOutputForAttr(const audio_attributes_t *attr, uid_t uid, const audio_config_t *config, audio_output_flags_t flags, - audio_port_handle_t selectedDeviceId, + audio_port_handle_t *selectedDeviceId, audio_port_handle_t *portId) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); @@ -863,7 +863,7 @@ status_t AudioSystem::getInputForAttr(const audio_attributes_t *attr, uid_t uid, const audio_config_base_t *config, audio_input_flags_t flags, - audio_port_handle_t selectedDeviceId, + audio_port_handle_t *selectedDeviceId, audio_port_handle_t *portId) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); @@ -1225,6 +1225,13 @@ status_t AudioSystem::getMasterMono(bool *mono) return aps->getMasterMono(mono); } +float AudioSystem::getStreamVolumeDB(audio_stream_type_t stream, int index, audio_devices_t device) +{ + const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return NAN; + return aps->getStreamVolumeDB(stream, index, device); +} + // --------------------------------------------------------------------------- int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback( diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp index ffb77039f7..b0b01db126 100644 --- a/media/libaudioclient/AudioTrack.cpp +++ b/media/libaudioclient/AudioTrack.cpp @@ -184,6 +184,7 @@ AudioTrack::AudioTrack() mPreviousSchedulingGroup(SP_DEFAULT), mPausedPosition(0), mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), + mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE), mPortId(AUDIO_PORT_HANDLE_NONE) { mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN; @@ -908,13 +909,13 @@ status_t AudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) effectiveRate, effectiveSpeed, effectivePitch); if (!isAudioPlaybackRateValid(playbackRateTemp)) { - ALOGV("setPlaybackRate(%f, %f) failed (effective rate out of bounds)", + ALOGW("setPlaybackRate(%f, %f) failed (effective rate out of bounds)", playbackRate.mSpeed, playbackRate.mPitch); return BAD_VALUE; } // Check if the buffer size is compatible. if (!isSampleRateSpeedAllowed_l(effectiveRate, effectiveSpeed)) { - ALOGV("setPlaybackRate(%f, %f) failed (buffer size)", + ALOGW("setPlaybackRate(%f, %f) failed (buffer size)", playbackRate.mSpeed, playbackRate.mPitch); return BAD_VALUE; } @@ -922,13 +923,13 @@ status_t AudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) // Check resampler ratios are within bounds if ((uint64_t)effectiveRate > (uint64_t)mSampleRate * (uint64_t)AUDIO_RESAMPLER_DOWN_RATIO_MAX) { - ALOGV("setPlaybackRate(%f, %f) failed. Resample rate exceeds max accepted value", + ALOGW("setPlaybackRate(%f, %f) failed. Resample rate exceeds max accepted value", playbackRate.mSpeed, playbackRate.mPitch); return BAD_VALUE; } if ((uint64_t)effectiveRate * (uint64_t)AUDIO_RESAMPLER_UP_RATIO_MAX < (uint64_t)mSampleRate) { - ALOGV("setPlaybackRate(%f, %f) failed. Resample rate below min accepted value", + ALOGW("setPlaybackRate(%f, %f) failed. Resample rate below min accepted value", playbackRate.mSpeed, playbackRate.mPitch); return BAD_VALUE; } @@ -1226,7 +1227,14 @@ audio_port_handle_t AudioTrack::getRoutedDeviceId() { if (mOutput == AUDIO_IO_HANDLE_NONE) { return AUDIO_PORT_HANDLE_NONE; } - return AudioSystem::getDeviceIdForIo(mOutput); + // if the output stream does not have an active audio patch, use either the device initially + // selected by audio policy manager or the last routed device + audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mOutput); + if (deviceId == AUDIO_PORT_HANDLE_NONE) { + deviceId = mRoutedDeviceId; + } + mRoutedDeviceId = deviceId; + return deviceId; } status_t AudioTrack::attachAuxEffect(int effectId) @@ -1247,9 +1255,41 @@ audio_stream_type_t AudioTrack::streamType() const return mStreamType; } +uint32_t AudioTrack::latency() +{ + AutoMutex lock(mLock); + updateLatency_l(); + return mLatency; +} + // ------------------------------------------------------------------------- // must be called with mLock held +void AudioTrack::updateLatency_l() +{ + status_t status = AudioSystem::getLatency(mOutput, &mAfLatency); + if (status != NO_ERROR) { + ALOGW("getLatency(%d) failed status %d", mOutput, status); + } else { + // FIXME don't believe this lie + mLatency = mAfLatency + (1000 * mFrameCount) / mSampleRate; + } +} + +// TODO Move this macro to a common header file for enum to string conversion in audio framework. +#define MEDIA_CASE_ENUM(name) case name: return #name +const char * AudioTrack::convertTransferToText(transfer_type transferType) { + switch (transferType) { + MEDIA_CASE_ENUM(TRANSFER_DEFAULT); + MEDIA_CASE_ENUM(TRANSFER_CALLBACK); + MEDIA_CASE_ENUM(TRANSFER_OBTAIN); + MEDIA_CASE_ENUM(TRANSFER_SYNC); + MEDIA_CASE_ENUM(TRANSFER_SHARED); + default: + return "UNRECOGNIZED"; + } +} + status_t AudioTrack::createTrack_l() { const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); @@ -1274,10 +1314,11 @@ status_t AudioTrack::createTrack_l() config.channel_mask = mChannelMask; config.format = mFormat; config.offload_info = mOffloadInfoCopy; + mRoutedDeviceId = mSelectedDeviceId; status = AudioSystem::getOutputForAttr(attr, &output, mSessionId, &streamType, mClientUid, &config, - mFlags, mSelectedDeviceId, &mPortId); + mFlags, &mRoutedDeviceId, &mPortId); if (status != NO_ERROR || output == AUDIO_IO_HANDLE_NONE) { ALOGE("Could not get audio output for session %d, stream type %d, usage %d, sample rate %u," @@ -1325,22 +1366,32 @@ status_t AudioTrack::createTrack_l() // Client can only express a preference for FAST. Server will perform additional tests. if (mFlags & AUDIO_OUTPUT_FLAG_FAST) { - bool useCaseAllowed = - // either of these use cases: - // use case 1: shared buffer - (mSharedBuffer != 0) || + // either of these use cases: + // use case 1: shared buffer + bool sharedBuffer = mSharedBuffer != 0; + bool transferAllowed = // use case 2: callback transfer mode (mTransfer == TRANSFER_CALLBACK) || // use case 3: obtain/release mode (mTransfer == TRANSFER_OBTAIN) || // use case 4: synchronous write ((mTransfer == TRANSFER_SYNC) && mThreadCanCallJava); + + bool useCaseAllowed = sharedBuffer || transferAllowed; + if (!useCaseAllowed) { + ALOGW("AUDIO_OUTPUT_FLAG_FAST denied, not shared buffer and transfer = %s", + convertTransferToText(mTransfer)); + } + // sample rates must also match - bool fastAllowed = useCaseAllowed && (mSampleRate == mAfSampleRate); + bool sampleRateAllowed = mSampleRate == mAfSampleRate; + if (!sampleRateAllowed) { + ALOGW("AUDIO_OUTPUT_FLAG_FAST denied, rates do not match %u Hz, require %u Hz", + mSampleRate, mAfSampleRate); + } + + bool fastAllowed = useCaseAllowed && sampleRateAllowed; if (!fastAllowed) { - ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client; transfer %d, " - "track %u Hz, output %u Hz", - mTransfer, mSampleRate, mAfSampleRate); mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST); } } @@ -1416,6 +1467,9 @@ status_t AudioTrack::createTrack_l() pid_t tid = -1; if (mFlags & AUDIO_OUTPUT_FLAG_FAST) { + // It is currently meaningless to request SCHED_FIFO for a Java thread. Even if the + // application-level code follows all non-blocking design rules, the language runtime + // doesn't also follow those rules, so the thread will not benefit overall. if (mAudioTrackThread != 0 && !mThreadCanCallJava) { tid = mAudioTrackThread->getTid(); } @@ -1541,11 +1595,9 @@ status_t AudioTrack::createTrack_l() } mAudioTrack->attachAuxEffect(mAuxEffectId); - // FIXME doesn't take into account speed or future sample rate changes (until restoreTrack) - // FIXME don't believe this lie - mLatency = mAfLatency + (1000*frameCount) / mSampleRate; - mFrameCount = frameCount; + updateLatency_l(); // this refetches mAfLatency and sets mLatency + // If IAudioTrack is re-created, don't let the requested frameCount // decrease. This can confuse clients that cache frameCount(). if (frameCount > mReqFrameCount) { @@ -2315,8 +2367,9 @@ Modulo<uint32_t> AudioTrack::updateAndGetPosition_l() return mPosition; } -bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const +bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) { + updateLatency_l(); // applicable for mixing tracks only (not offloaded or direct) if (mStaticProxy != 0) { return true; // static tracks do not have issues with buffer sizing. @@ -2324,9 +2377,14 @@ bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) co const size_t minFrameCount = calculateMinFrameCount(mAfLatency, mAfFrameCount, mAfSampleRate, sampleRate, speed /*, 0 mNotificationsPerBufferReq*/); - ALOGV("isSampleRateSpeedAllowed_l mFrameCount %zu minFrameCount %zu", + const bool allowed = mFrameCount >= minFrameCount; + ALOGD_IF(!allowed, + "isSampleRateSpeedAllowed_l denied " + "mAfLatency:%u mAfFrameCount:%zu mAfSampleRate:%u sampleRate:%u speed:%f " + "mFrameCount:%zu < minFrameCount:%zu", + mAfLatency, mAfFrameCount, mAfSampleRate, sampleRate, speed, mFrameCount, minFrameCount); - return mFrameCount >= minFrameCount; + return allowed; } status_t AudioTrack::setParameters(const String8& keyValuePairs) @@ -2470,6 +2528,7 @@ status_t AudioTrack::getTimestamp_l(AudioTimestamp& timestamp) status = ets.getBestTimestamp(×tamp, &location); if (status == OK) { + updateLatency_l(); // It is possible that the best location has moved from the kernel to the server. // In this case we adjust the position from the previous computed latency. if (location == ExtendedTimestamp::LOCATION_SERVER) { @@ -2941,6 +3000,7 @@ bool AudioTrack::AudioTrackThread::threadLoop() { AutoMutex _l(mMyLock); if (mPaused) { + // TODO check return value and handle or log mMyCond.wait(mMyLock); // caller will check for exitPending() return true; @@ -2950,9 +3010,12 @@ bool AudioTrack::AudioTrackThread::threadLoop() mPausedInt = false; } if (mPausedInt) { + // TODO use futex instead of condition, for event flag "or" if (mPausedNs > 0) { + // TODO check return value and handle or log (void) mMyCond.waitRelative(mMyLock, mPausedNs); } else { + // TODO check return value and handle or log mMyCond.wait(mMyLock); } mPausedInt = false; diff --git a/media/libaudioclient/AudioTrackShared.cpp b/media/libaudioclient/AudioTrackShared.cpp index 2ce6c634f5..08c37f8c20 100644 --- a/media/libaudioclient/AudioTrackShared.cpp +++ b/media/libaudioclient/AudioTrackShared.cpp @@ -111,7 +111,8 @@ __attribute__((no_sanitize("integer"))) status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *requested, struct timespec *elapsed) { - LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0); + LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0, + "%s: null or zero frame buffer, buffer:%p", __func__, buffer); struct timespec total; // total elapsed time spent waiting total.tv_sec = 0; total.tv_nsec = 0; @@ -345,7 +346,10 @@ void ClientProxy::releaseBuffer(Buffer* buffer) buffer->mNonContig = 0; return; } - LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount)); + LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount), + "%s: mUnreleased out of range, " + "!(stepCount:%zu <= mUnreleased:%zu <= mFrameCount:%zu), BufferSizeInFrames:%u", + __func__, stepCount, mUnreleased, mFrameCount, getBufferSizeInFrames()); mUnreleased -= stepCount; audio_track_cblk_t* cblk = mCblk; // Both of these barriers are required @@ -674,7 +678,8 @@ void ServerProxy::flushBufferIfNeeded() __attribute__((no_sanitize("integer"))) status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush) { - LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0); + LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0, + "%s: null or zero frame buffer, buffer:%p", __func__, buffer); if (mIsShutdown) { goto no_init; } @@ -760,7 +765,10 @@ void ServerProxy::releaseBuffer(Buffer* buffer) buffer->mNonContig = 0; return; } - LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount)); + LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount), + "%s: mUnreleased out of range, " + "!(stepCount:%zu <= mUnreleased:%zu <= mFrameCount:%zu)", + __func__, stepCount, mUnreleased, mFrameCount); mUnreleased -= stepCount; audio_track_cblk_t* cblk = mCblk; if (mIsOut) { @@ -1029,7 +1037,9 @@ status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush } // As mFramesReady is the total remaining frames in the static audio track, // it is always larger or equal to avail. - LOG_ALWAYS_FATAL_IF(mFramesReady < (int64_t) avail); + LOG_ALWAYS_FATAL_IF(mFramesReady < (int64_t) avail, + "%s: mFramesReady out of range, mFramesReady:%lld < avail:%zu", + __func__, (long long)mFramesReady, avail); buffer->mNonContig = mFramesReady == INT64_MAX ? SIZE_MAX : clampToSize(mFramesReady - avail); if (!ackFlush) { mUnreleased = avail; @@ -1040,8 +1050,14 @@ status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer) { size_t stepCount = buffer->mFrameCount; - LOG_ALWAYS_FATAL_IF(!((int64_t) stepCount <= mFramesReady)); - LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased)); + LOG_ALWAYS_FATAL_IF(!((int64_t) stepCount <= mFramesReady), + "%s: stepCount out of range, " + "!(stepCount:%zu <= mFramesReady:%lld)", + __func__, stepCount, (long long)mFramesReady); + LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased), + "%s: stepCount out of range, " + "!(stepCount:%zu <= mUnreleased:%zu)", + __func__, stepCount, mUnreleased); if (stepCount == 0) { // prevent accidental re-use of buffer buffer->mRaw = NULL; diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp index 858b5cc187..14feada297 100644 --- a/media/libaudioclient/IAudioFlinger.cpp +++ b/media/libaudioclient/IAudioFlinger.cpp @@ -62,7 +62,7 @@ enum { SET_VOICE_VOLUME, GET_RENDER_POSITION, GET_INPUT_FRAMES_LOST, - NEW_AUDIO_SESSION_ID, + NEW_AUDIO_UNIQUE_ID, ACQUIRE_AUDIO_SESSION_ID, RELEASE_AUDIO_SESSION_ID, QUERY_NUM_EFFECTS, @@ -80,7 +80,7 @@ enum { RELEASE_AUDIO_PATCH, LIST_AUDIO_PATCHES, SET_AUDIO_PORT_CONFIG, - GET_AUDIO_HW_SYNC, + GET_AUDIO_HW_SYNC_FOR_SESSION, SYSTEM_READY, FRAME_COUNT_HAL, }; @@ -628,8 +628,8 @@ public: Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); data.writeInt32((int32_t) use); - status_t status = remote()->transact(NEW_AUDIO_SESSION_ID, data, &reply); - audio_unique_id_t id = AUDIO_SESSION_ALLOCATE; + status_t status = remote()->transact(NEW_AUDIO_UNIQUE_ID, data, &reply); + audio_unique_id_t id = AUDIO_UNIQUE_ID_ALLOCATE; if (status == NO_ERROR) { id = reply.readInt32(); } @@ -912,7 +912,7 @@ public: Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); data.writeInt32(sessionId); - status_t status = remote()->transact(GET_AUDIO_HW_SYNC, data, &reply); + status_t status = remote()->transact(GET_AUDIO_HW_SYNC_FOR_SESSION, data, &reply); if (status != NO_ERROR) { return AUDIO_HW_SYNC_INVALID; } @@ -1262,7 +1262,7 @@ status_t BnAudioFlinger::onTransact( reply->writeInt32((int32_t) getInputFramesLost(ioHandle)); return NO_ERROR; } break; - case NEW_AUDIO_SESSION_ID: { + case NEW_AUDIO_UNIQUE_ID: { CHECK_INTERFACE(IAudioFlinger, data, reply); reply->writeInt32(newAudioUniqueId((audio_unique_id_use_t) data.readInt32())); return NO_ERROR; @@ -1466,7 +1466,7 @@ status_t BnAudioFlinger::onTransact( reply->writeInt32(status); return NO_ERROR; } break; - case GET_AUDIO_HW_SYNC: { + case GET_AUDIO_HW_SYNC_FOR_SESSION: { CHECK_INTERFACE(IAudioFlinger, data, reply); reply->writeInt32(getAudioHwSyncForSession((audio_session_t) data.readInt32())); return NO_ERROR; diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp index 300f040dfb..f071a020b1 100644 --- a/media/libaudioclient/IAudioPolicyService.cpp +++ b/media/libaudioclient/IAudioPolicyService.cpp @@ -19,6 +19,7 @@ #include <utils/Log.h> #include <stdint.h> +#include <math.h> #include <sys/types.h> #include <binder/Parcel.h> @@ -77,6 +78,7 @@ enum { SET_AUDIO_PORT_CALLBACK_ENABLED, SET_MASTER_MONO, GET_MASTER_MONO, + GET_STREAM_VOLUME_DB }; #define MAX_ITEMS_PER_LIST 1024 @@ -191,7 +193,7 @@ public: uid_t uid, const audio_config_t *config, audio_output_flags_t flags, - audio_port_handle_t selectedDeviceId, + audio_port_handle_t *selectedDeviceId, audio_port_handle_t *portId) { Parcel data, reply; @@ -210,6 +212,10 @@ public: ALOGE("getOutputForAttr NULL output - shouldn't happen"); return BAD_VALUE; } + if (selectedDeviceId == NULL) { + ALOGE("getOutputForAttr NULL selectedDeviceId - shouldn't happen"); + return BAD_VALUE; + } if (portId == NULL) { ALOGE("getOutputForAttr NULL portId - shouldn't happen"); return BAD_VALUE; @@ -230,7 +236,7 @@ public: data.writeInt32(uid); data.write(config, sizeof(audio_config_t)); data.writeInt32(static_cast <uint32_t>(flags)); - data.writeInt32(selectedDeviceId); + data.writeInt32(*selectedDeviceId); data.writeInt32(*portId); status_t status = remote()->transact(GET_OUTPUT_FOR_ATTR, data, &reply); if (status != NO_ERROR) { @@ -245,6 +251,7 @@ public: if (stream != NULL) { *stream = lStream; } + *selectedDeviceId = (audio_port_handle_t)reply.readInt32(); *portId = (audio_port_handle_t)reply.readInt32(); return status; } @@ -294,7 +301,7 @@ public: uid_t uid, const audio_config_base_t *config, audio_input_flags_t flags, - audio_port_handle_t selectedDeviceId, + audio_port_handle_t *selectedDeviceId, audio_port_handle_t *portId) { Parcel data, reply; @@ -307,17 +314,22 @@ public: ALOGE("getInputForAttr NULL input - shouldn't happen"); return BAD_VALUE; } + if (selectedDeviceId == NULL) { + ALOGE("getInputForAttr NULL selectedDeviceId - shouldn't happen"); + return BAD_VALUE; + } if (portId == NULL) { ALOGE("getInputForAttr NULL portId - shouldn't happen"); return BAD_VALUE; } data.write(attr, sizeof(audio_attributes_t)); + data.writeInt32(*input); data.writeInt32(session); data.writeInt32(pid); data.writeInt32(uid); data.write(config, sizeof(audio_config_base_t)); data.writeInt32(flags); - data.writeInt32(selectedDeviceId); + data.writeInt32(*selectedDeviceId); data.writeInt32(*portId); status_t status = remote()->transact(GET_INPUT_FOR_ATTR, data, &reply); if (status != NO_ERROR) { @@ -328,6 +340,7 @@ public: return status; } *input = (audio_io_handle_t)reply.readInt32(); + *selectedDeviceId = (audio_port_handle_t)reply.readInt32(); *portId = (audio_port_handle_t)reply.readInt32(); return NO_ERROR; } @@ -815,6 +828,20 @@ public: } return status; } + + virtual float getStreamVolumeDB(audio_stream_type_t stream, int index, audio_devices_t device) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeInt32(static_cast <int32_t>(stream)); + data.writeInt32(static_cast <int32_t>(index)); + data.writeUint32(static_cast <uint32_t>(device)); + status_t status = remote()->transact(GET_STREAM_VOLUME_DB, data, &reply); + if (status != NO_ERROR) { + return NAN; + } + return reply.readFloat(); + } }; IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService"); @@ -953,10 +980,11 @@ status_t BnAudioPolicyService::onTransact( status_t status = getOutputForAttr(hasAttributes ? &attr : NULL, &output, session, &stream, uid, &config, - flags, selectedDeviceId, &portId); + flags, &selectedDeviceId, &portId); reply->writeInt32(status); reply->writeInt32(output); reply->writeInt32(stream); + reply->writeInt32(selectedDeviceId); reply->writeInt32(portId); return NO_ERROR; } break; @@ -999,6 +1027,7 @@ status_t BnAudioPolicyService::onTransact( audio_attributes_t attr = {}; data.read(&attr, sizeof(audio_attributes_t)); sanetizeAudioAttributes(&attr); + audio_io_handle_t input = (audio_io_handle_t)data.readInt32(); audio_session_t session = (audio_session_t)data.readInt32(); pid_t pid = (pid_t)data.readInt32(); uid_t uid = (uid_t)data.readInt32(); @@ -1008,13 +1037,13 @@ status_t BnAudioPolicyService::onTransact( audio_input_flags_t flags = (audio_input_flags_t) data.readInt32(); audio_port_handle_t selectedDeviceId = (audio_port_handle_t) data.readInt32(); audio_port_handle_t portId = (audio_port_handle_t)data.readInt32(); - audio_io_handle_t input = AUDIO_IO_HANDLE_NONE; status_t status = getInputForAttr(&attr, &input, session, pid, uid, &config, - flags, selectedDeviceId, &portId); + flags, &selectedDeviceId, &portId); reply->writeInt32(status); if (status == NO_ERROR) { reply->writeInt32(input); + reply->writeInt32(selectedDeviceId); reply->writeInt32(portId); } return NO_ERROR; @@ -1416,6 +1445,17 @@ status_t BnAudioPolicyService::onTransact( return NO_ERROR; } break; + case GET_STREAM_VOLUME_DB: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + audio_stream_type_t stream = + static_cast <audio_stream_type_t>(data.readInt32()); + int index = static_cast <int>(data.readInt32()); + audio_devices_t device = + static_cast <audio_devices_t>(data.readUint32()); + reply->writeFloat(getStreamVolumeDB(stream, index, device)); + return NO_ERROR; + } + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libaudioclient/PlayerBase.cpp b/media/libaudioclient/PlayerBase.cpp index cbef1b34e1..7868318686 100644 --- a/media/libaudioclient/PlayerBase.cpp +++ b/media/libaudioclient/PlayerBase.cpp @@ -79,7 +79,7 @@ void PlayerBase::serviceReleasePlayer() { } } -//FIXME temporary method while some AudioTrack state is outside of this class +//FIXME temporary method while some player state is outside of this class void PlayerBase::reportEvent(player_state_t event) { servicePlayerEvent(event); } @@ -87,10 +87,30 @@ void PlayerBase::reportEvent(player_state_t event) { status_t PlayerBase::startWithStatus() { status_t status = playerStart(); if (status == NO_ERROR) { - ALOGD("PlayerBase::start() from IPlayer"); servicePlayerEvent(PLAYER_STATE_STARTED); } else { - ALOGD("PlayerBase::start() no AudioTrack to start from IPlayer"); + ALOGW("PlayerBase::start() error %d", status); + } + return status; +} + +status_t PlayerBase::pauseWithStatus() { + status_t status = playerPause(); + if (status == NO_ERROR) { + servicePlayerEvent(PLAYER_STATE_PAUSED); + } else { + ALOGW("PlayerBase::pause() error %d", status); + } + return status; +} + + +status_t PlayerBase::stopWithStatus() { + status_t status = playerStop(); + if (status == NO_ERROR) { + servicePlayerEvent(PLAYER_STATE_STOPPED); + } else { + ALOGW("PlayerBase::stop() error %d", status); } return status; } @@ -98,42 +118,36 @@ status_t PlayerBase::startWithStatus() { //------------------------------------------------------------------------------ // Implementation of IPlayer void PlayerBase::start() { + ALOGD("PlayerBase::start() from IPlayer"); (void)startWithStatus(); } void PlayerBase::pause() { - if (playerPause() == NO_ERROR) { - ALOGD("PlayerBase::pause() from IPlayer"); - servicePlayerEvent(PLAYER_STATE_PAUSED); - } else { - ALOGD("PlayerBase::pause() no AudioTrack to pause from IPlayer"); - } + ALOGD("PlayerBase::pause() from IPlayer"); + (void)pauseWithStatus(); } void PlayerBase::stop() { - if (playerStop() == NO_ERROR) { - ALOGD("PlayerBase::stop() from IPlayer"); - servicePlayerEvent(PLAYER_STATE_STOPPED); - } else { - ALOGD("PlayerBase::stop() no AudioTrack to stop from IPlayer"); - } + ALOGD("PlayerBase::stop() from IPlayer"); + (void)stopWithStatus(); } void PlayerBase::setVolume(float vol) { + ALOGD("PlayerBase::setVolume() from IPlayer"); { Mutex::Autolock _l(mSettingsLock); mVolumeMultiplierL = vol; mVolumeMultiplierR = vol; } - if (playerSetVolume() == NO_ERROR) { - ALOGD("PlayerBase::setVolume() from IPlayer"); - } else { - ALOGD("PlayerBase::setVolume() no AudioTrack for volume control from IPlayer"); + status_t status = playerSetVolume(); + if (status != NO_ERROR) { + ALOGW("PlayerBase::setVolume() error %d", status); } } void PlayerBase::setPan(float pan) { + ALOGD("PlayerBase::setPan() from IPlayer"); { Mutex::Autolock _l(mSettingsLock); pan = min(max(-1.0f, pan), 1.0f); @@ -145,10 +159,9 @@ void PlayerBase::setPan(float pan) { mPanMultiplierR = 1.0f + pan; } } - if (playerSetVolume() == NO_ERROR) { - ALOGD("PlayerBase::setPan() from IPlayer"); - } else { - ALOGD("PlayerBase::setPan() no AudioTrack for volume control from IPlayer"); + status_t status = playerSetVolume(); + if (status != NO_ERROR) { + ALOGW("PlayerBase::setPan() error %d", status); } } diff --git a/media/libaudioclient/include/media/AudioClient.h b/media/libaudioclient/include/media/AudioClient.h new file mode 100644 index 0000000000..9efd76dd1d --- /dev/null +++ b/media/libaudioclient/include/media/AudioClient.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef ANDROID_AUDIO_CLIENT_H +#define ANDROID_AUDIO_CLIENT_H + +#include <system/audio.h> +#include <utils/String16.h> + +namespace android { + +class AudioClient { + public: + AudioClient() : + clientUid(-1), clientPid(-1), packageName("") {} + + uid_t clientUid; + pid_t clientPid; + String16 packageName; +}; + +}; // namespace android + +#endif // ANDROID_AUDIO_CLIENT_H diff --git a/media/libaudioclient/include/media/AudioMixer.h b/media/libaudioclient/include/media/AudioMixer.h index 87ada76679..2bd2d01123 100644 --- a/media/libaudioclient/include/media/AudioMixer.h +++ b/media/libaudioclient/include/media/AudioMixer.h @@ -286,7 +286,7 @@ private: process_hook_t hook; // one of process__*, never NULL int32_t *outputTemp; int32_t *resampleTemp; - NBLog::Writer* mLog; + NBLog::Writer* mNBLogWriter; // associated NBLog::Writer or &mDummyLog int32_t reserved[1]; // FIXME allocate dynamically to save some memory when maxNumTracks < MAX_NUM_TRACKS track_t tracks[MAX_NUM_TRACKS] __attribute__((aligned(32))); @@ -301,9 +301,11 @@ private: const uint32_t mSampleRate; - NBLog::Writer mDummyLog; + NBLog::Writer mDummyLogWriter; public: - void setLog(NBLog::Writer* log); + // Called by FastMixer to inform AudioMixer of it's associated NBLog::Writer. + // FIXME It would be safer to use TLS for this, so we don't accidentally use wrong one. + void setNBLogWriter(NBLog::Writer* log); private: state_t mState __attribute__((aligned(32))); diff --git a/media/libaudioclient/include/media/AudioPolicyHelper.h b/media/libaudioclient/include/media/AudioPolicyHelper.h index 854057d071..73ee0a7378 100644 --- a/media/libaudioclient/include/media/AudioPolicyHelper.h +++ b/media/libaudioclient/include/media/AudioPolicyHelper.h @@ -18,9 +18,8 @@ #include <system/audio.h> -// TODO: fix this among dependencies -__attribute__((unused)) -static audio_stream_type_t audio_attributes_to_stream_type(const audio_attributes_t *attr) +static inline +audio_stream_type_t audio_attributes_to_stream_type(const audio_attributes_t *attr) { // flags to stream type mapping if ((attr->flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) == AUDIO_FLAG_AUDIBILITY_ENFORCED) { @@ -65,9 +64,8 @@ static audio_stream_type_t audio_attributes_to_stream_type(const audio_attribute } } -// TODO: fix this among dependencies -__attribute__((unused)) -static void stream_type_to_audio_attributes(audio_stream_type_t streamType, +static inline +void stream_type_to_audio_attributes(audio_stream_type_t streamType, audio_attributes_t *attr) { memset(attr, 0, sizeof(audio_attributes_t)); diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h index 1b034b5488..e6a5efb2a8 100644 --- a/media/libaudioclient/include/media/AudioRecord.h +++ b/media/libaudioclient/include/media/AudioRecord.h @@ -334,6 +334,12 @@ public: */ status_t getTimestamp(ExtendedTimestamp *timestamp); + /** + * @param transferType + * @return text string that matches the enum name + */ + static const char * convertTransferToText(transfer_type transferType); + /* Returns a handle on the audio input used by this AudioRecord. * * Parameters: @@ -655,7 +661,10 @@ private: // For Device Selection API // a value of AUDIO_PORT_HANDLE_NONE indicated default (AudioPolicyManager) routing. - audio_port_handle_t mSelectedDeviceId; + audio_port_handle_t mSelectedDeviceId; // Device requested by the application. + audio_port_handle_t mRoutedDeviceId; // Device actually selected by audio policy manager: + // May not match the app selection depending on other + // activity and connected devices sp<AudioSystem::AudioDeviceCallback> mDeviceCallback; audio_port_handle_t mPortId; // unique ID allocated by audio policy diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h index 853d318b1e..2e39d23ec6 100644 --- a/media/libaudioclient/include/media/AudioSystem.h +++ b/media/libaudioclient/include/media/AudioSystem.h @@ -224,7 +224,7 @@ public: uid_t uid, const audio_config_t *config, audio_output_flags_t flags, - audio_port_handle_t selectedDeviceId, + audio_port_handle_t *selectedDeviceId, audio_port_handle_t *portId); static status_t startOutput(audio_io_handle_t output, audio_stream_type_t stream, @@ -245,7 +245,7 @@ public: uid_t uid, const audio_config_base_t *config, audio_input_flags_t flags, - audio_port_handle_t selectedDeviceId, + audio_port_handle_t *selectedDeviceId, audio_port_handle_t *portId); static status_t startInput(audio_io_handle_t input, @@ -338,6 +338,9 @@ public: static status_t setMasterMono(bool mono); static status_t getMasterMono(bool *mono); + static float getStreamVolumeDB( + audio_stream_type_t stream, int index, audio_devices_t device); + // ---------------------------------------------------------------------------- class AudioPortCallback : public RefBase diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h index a4c8d53fbf..b168fc90c3 100644 --- a/media/libaudioclient/include/media/AudioTrack.h +++ b/media/libaudioclient/include/media/AudioTrack.h @@ -326,7 +326,7 @@ public: * This includes the latency due to AudioTrack buffer size, AudioMixer (if any) * and audio hardware driver. */ - uint32_t latency() const { return mLatency; } + uint32_t latency(); /* Returns the number of application-level buffer underruns * since the AudioTrack was created. @@ -564,6 +564,12 @@ public: */ status_t reload(); + /** + * @param transferType + * @return text string that matches the enum name + */ + static const char * convertTransferToText(transfer_type transferType); + /* Returns a handle on the audio output used by this AudioTrack. * * Parameters: @@ -927,6 +933,8 @@ protected: // caller must hold lock on mLock for all _l methods + void updateLatency_l(); // updates mAfLatency and mLatency from AudioSystem cache + status_t createTrack_l(); // can only be called when mState != STATE_ACTIVE @@ -962,7 +970,7 @@ protected: Modulo<uint32_t> updateAndGetPosition_l(); // check sample rate and speed is compatible with AudioTrack - bool isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const; + bool isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed); void restartIfDisabled(); @@ -1133,7 +1141,10 @@ protected: // For Device Selection API // a value of AUDIO_PORT_HANDLE_NONE indicated default (AudioPolicyManager) routing. - audio_port_handle_t mSelectedDeviceId; + audio_port_handle_t mSelectedDeviceId; // Device requested by the application. + audio_port_handle_t mRoutedDeviceId; // Device actually selected by audio policy manager: + // May not match the app selection depending on other + // activity and connected devices. sp<VolumeHandler> mVolumeHandler; diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h index e8abafbc8a..eec3e881da 100644 --- a/media/libaudioclient/include/media/IAudioPolicyService.h +++ b/media/libaudioclient/include/media/IAudioPolicyService.h @@ -68,7 +68,7 @@ public: uid_t uid, const audio_config_t *config, audio_output_flags_t flags, - audio_port_handle_t selectedDeviceId, + audio_port_handle_t *selectedDeviceId, audio_port_handle_t *portId) = 0; virtual status_t startOutput(audio_io_handle_t output, audio_stream_type_t stream, @@ -86,7 +86,7 @@ public: uid_t uid, const audio_config_base_t *config, audio_input_flags_t flags, - audio_port_handle_t selectedDeviceId, + audio_port_handle_t *selectedDeviceId, audio_port_handle_t *portId) = 0; virtual status_t startInput(audio_io_handle_t input, audio_session_t session) = 0; @@ -169,6 +169,8 @@ public: virtual status_t setMasterMono(bool mono) = 0; virtual status_t getMasterMono(bool *mono) = 0; + virtual float getStreamVolumeDB( + audio_stream_type_t stream, int index, audio_devices_t device) = 0; }; diff --git a/media/libaudioclient/include/media/PlayerBase.h b/media/libaudioclient/include/media/PlayerBase.h index fe1db7b379..e63090b725 100644 --- a/media/libaudioclient/include/media/PlayerBase.h +++ b/media/libaudioclient/include/media/PlayerBase.h @@ -48,6 +48,8 @@ public: status_t startWithStatus(); + status_t pauseWithStatus(); + status_t stopWithStatus(); //FIXME temporary method while some player state is outside of this class void reportEvent(player_state_t event); diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp index 05b726a433..238925dfa3 100644 --- a/media/libaudioprocessing/AudioMixer.cpp +++ b/media/libaudioprocessing/AudioMixer.cpp @@ -27,7 +27,6 @@ #include <utils/Errors.h> #include <utils/Log.h> -#include <cutils/bitops.h> #include <cutils/compiler.h> #include <utils/Debug.h> @@ -115,7 +114,7 @@ AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate, uint32_t maxNumTr mState.hook = process__nop; mState.outputTemp = NULL; mState.resampleTemp = NULL; - mState.mLog = &mDummyLog; + mState.mNBLogWriter = &mDummyLogWriter; // mState.reserved // FIXME Most of the following initialization is probably redundant since @@ -146,9 +145,9 @@ AudioMixer::~AudioMixer() delete [] mState.resampleTemp; } -void AudioMixer::setLog(NBLog::Writer *log) +void AudioMixer::setNBLogWriter(NBLog::Writer *logWriter) { - mState.mLog = log; + mState.mNBLogWriter = logWriter; } static inline audio_format_t selectMixerInFormat(audio_format_t inputFormat __unused) { diff --git a/media/libcpustats/Android.bp b/media/libcpustats/Android.bp new file mode 100644 index 0000000000..8fcd8a4df3 --- /dev/null +++ b/media/libcpustats/Android.bp @@ -0,0 +1,22 @@ +cc_library_static { + name: "libcpustats", + + srcs: [ + "CentralTendencyStatistics.cpp", + "ThreadCpuUsage.cpp", + ], + + cflags: [ + "-Werror", + "-Wall", + ], + + host_supported: true, + + target: { + darwin: { + enabled: false, + }, + }, + +} diff --git a/media/libcpustats/Android.mk b/media/libcpustats/Android.mk deleted file mode 100644 index b2d73ee240..0000000000 --- a/media/libcpustats/Android.mk +++ /dev/null @@ -1,13 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - CentralTendencyStatistics.cpp \ - ThreadCpuUsage.cpp - -LOCAL_MODULE := libcpustats - -LOCAL_CFLAGS := -Werror -Wall - -include $(BUILD_STATIC_LIBRARY) diff --git a/media/libcpustats/ThreadCpuUsage.cpp b/media/libcpustats/ThreadCpuUsage.cpp index b43b36cc33..4b7549f1d1 100644 --- a/media/libcpustats/ThreadCpuUsage.cpp +++ b/media/libcpustats/ThreadCpuUsage.cpp @@ -26,6 +26,11 @@ #include <cpustats/ThreadCpuUsage.h> +// implemented by host, but not declared in <string.h> as FreeBSD does +extern "C" { + extern size_t strlcpy(char *dst, const char *src, size_t dstsize); +} + namespace android { bool ThreadCpuUsage::setEnabled(bool isEnabled) diff --git a/media/libeffects/downmix/Android.mk b/media/libeffects/downmix/Android.mk index 09793d1102..73f6ef57f3 100644 --- a/media/libeffects/downmix/Android.mk +++ b/media/libeffects/downmix/Android.mk @@ -23,4 +23,5 @@ LOCAL_C_INCLUDES := \ LOCAL_CFLAGS += -fvisibility=hidden LOCAL_CFLAGS += -Wall -Werror +LOCAL_HEADER_LIBRARIES += libhardware_headers include $(BUILD_SHARED_LIBRARY) diff --git a/media/libeffects/loudness/Android.mk b/media/libeffects/loudness/Android.mk index 4b1c5840aa..712cbd5f07 100644 --- a/media/libeffects/loudness/Android.mk +++ b/media/libeffects/loudness/Android.mk @@ -5,20 +5,20 @@ include $(CLEAR_VARS) LOCAL_VENDOR_MODULE := true LOCAL_SRC_FILES:= \ - EffectLoudnessEnhancer.cpp \ - dsp/core/dynamic_range_compression.cpp + EffectLoudnessEnhancer.cpp \ + dsp/core/dynamic_range_compression.cpp LOCAL_CFLAGS+= -O2 -fvisibility=hidden LOCAL_CFLAGS += -Wall -Werror LOCAL_SHARED_LIBRARIES := \ - libcutils \ - liblog \ + libcutils \ + liblog \ LOCAL_MODULE_RELATIVE_PATH := soundfx LOCAL_MODULE:= libldnhncr -LOCAL_C_INCLUDES := \ - $(call include-path-for, audio-effects) \ +LOCAL_HEADER_LIBRARIES := \ + libaudioeffects include $(BUILD_SHARED_LIBRARY) diff --git a/media/libeffects/lvm/wrapper/Android.mk b/media/libeffects/lvm/wrapper/Android.mk index f92fb9513e..efd30fbfa7 100644 --- a/media/libeffects/lvm/wrapper/Android.mk +++ b/media/libeffects/lvm/wrapper/Android.mk @@ -30,6 +30,7 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/../lib/Bundle/lib/ \ $(call include-path-for, audio-effects) +LOCAL_HEADER_LIBRARIES += libhardware_headers include $(BUILD_SHARED_LIBRARY) @@ -62,4 +63,5 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/../lib/Reverb/lib/ \ $(call include-path-for, audio-effects) +LOCAL_HEADER_LIBRARIES += libhardware_headers include $(BUILD_SHARED_LIBRARY) diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk index 06d82378cb..358da8b036 100644 --- a/media/libeffects/preprocessing/Android.mk +++ b/media/libeffects/preprocessing/Android.mk @@ -3,6 +3,7 @@ LOCAL_PATH:= $(call my-dir) # audio preprocessing wrapper include $(CLEAR_VARS) +LOCAL_VENDOR_MODULE := true LOCAL_MODULE:= libaudiopreprocessing LOCAL_MODULE_TAGS := optional LOCAL_MODULE_RELATIVE_PATH := soundfx @@ -31,4 +32,5 @@ LOCAL_CFLAGS += \ LOCAL_CFLAGS += -fvisibility=hidden LOCAL_CFLAGS += -Wall -Werror +LOCAL_HEADER_LIBRARIES += libhardware_headers include $(BUILD_SHARED_LIBRARY) diff --git a/media/libeffects/visualizer/Android.mk b/media/libeffects/visualizer/Android.mk index 8687e1b481..70409defd0 100644 --- a/media/libeffects/visualizer/Android.mk +++ b/media/libeffects/visualizer/Android.mk @@ -22,4 +22,5 @@ LOCAL_C_INCLUDES := \ $(call include-path-for, audio-effects) +LOCAL_HEADER_LIBRARIES += libhardware_headers include $(BUILD_SHARED_LIBRARY) diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp index 11a498dc02..bbe97eeb67 100644 --- a/media/libmedia/Android.bp +++ b/media/libmedia/Android.bp @@ -13,8 +13,226 @@ cc_library { "-Wno-error=deprecated-declarations", "-Wall", ], - shared: { - shared_libs: ["libutils", "liblog"], - }, + shared_libs: ["libutils", "liblog", "libgui"], + header_libs: [ + "libmedia_headers", + "libaudioclient_headers", + "libaudio_system_headers", + ], clang: true, } + +// TODO(b/35449087): merge back with libmedia when OMX implementatoins +// no longer use aidl wrappers (or remove OMX component form libmedia) +cc_defaults { + name: "libmedia_omx_defaults", + + srcs: [ + "aidl/android/IGraphicBufferSource.aidl", + "aidl/android/IOMXBufferSource.aidl", + + "IMediaCodecList.cpp", + "IMediaCodecService.cpp", + "IOMX.cpp", + "MediaCodecBuffer.cpp", + "MediaCodecInfo.cpp", + "MediaDefs.cpp", + "OMXBuffer.cpp", + "omx/1.0/WGraphicBufferSource.cpp", + "omx/1.0/WOmx.cpp", + "omx/1.0/WOmxBufferSource.cpp", + "omx/1.0/WOmxNode.cpp", + "omx/1.0/WOmxObserver.cpp", + ], + + aidl: { + local_include_dirs: ["aidl"], + export_aidl_headers: true, + }, + + shared_libs: [ + "android.hidl.memory@1.0", + "android.hidl.token@1.0-utils", + "android.hardware.media.omx@1.0", + "android.hardware.media@1.0", + "libbase", + "libbinder", + "libcutils", + "libgui", + "libhidlbase", + "libhidlmemory", + "libhidltransport", + "libhwbinder", + "liblog", + "libstagefright_foundation", + "libui", + "libutils", + ], + + include_dirs: [ + "frameworks/av/include", // for media/vndk/xmlparser/1.0/MediaCodecsXmlParser.h + "frameworks/av/include/media", + "frameworks/native/include", // for media/hardware/MetadataBufferType.h + "frameworks/native/include/media/openmax", + "frameworks/av/media/libstagefright", + ], + + export_shared_lib_headers: [ + "android.hidl.memory@1.0", + "android.hidl.token@1.0-utils", + "android.hardware.media.omx@1.0", + "android.hardware.media@1.0", + "libhidlmemory", + "libstagefright_foundation", + "libui", + ], + + header_libs: [ + "libmedia_headers", + ], + + export_header_lib_headers: [ + "libmedia_headers", + ], + + export_include_dirs: [ + "aidl", + ], + + cflags: [ + "-Werror", + "-Wno-error=deprecated-declarations", + "-Wall", + ], + + sanitize: { + misc_undefined: [ + "unsigned-integer-overflow", + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, +} + +cc_library_shared { + name: "libmedia_omx", + vendor_available: true, + + defaults: ["libmedia_omx_defaults"], +} + +cc_library_shared { + name: "libmedia", + defaults: ["libmedia_omx_defaults"], + + srcs: [ + "IDataSource.cpp", + "IHDCP.cpp", + "BufferingSettings.cpp", + "mediaplayer.cpp", + "IMediaHTTPConnection.cpp", + "IMediaHTTPService.cpp", + "IMediaExtractor.cpp", + "IMediaExtractorService.cpp", + "IMediaPlayerService.cpp", + "IMediaPlayerClient.cpp", + "IMediaRecorderClient.cpp", + "IMediaPlayer.cpp", + "IMediaRecorder.cpp", + "IMediaSource.cpp", + "IRemoteDisplay.cpp", + "IRemoteDisplayClient.cpp", + "IResourceManagerClient.cpp", + "IResourceManagerService.cpp", + "IStreamSource.cpp", + "MediaUtils.cpp", + "Metadata.cpp", + "mediarecorder.cpp", + "IMediaMetadataRetriever.cpp", + "mediametadataretriever.cpp", + "MidiDeviceInfo.cpp", + "MidiIoWrapper.cpp", + "JetPlayer.cpp", + "MediaScanner.cpp", + "MediaScannerClient.cpp", + "CharacterEncodingDetector.cpp", + "IMediaDeathNotifier.cpp", + "MediaProfiles.cpp", + "MediaResource.cpp", + "MediaResourcePolicy.cpp", + "Visualizer.cpp", + "StringArray.cpp", + ], + + shared_libs: [ + "libui", + "liblog", + "libcutils", + "libutils", + "libbinder", + "libsonivox", + "libicuuc", + "libicui18n", + "libexpat", + "libcamera_client", + "libstagefright_foundation", + "libgui", + "libdl", + "libaudioutils", + "libaudioclient", + "libmedia_helper", + "libmediadrm", + "libmediametrics", + "libbase", + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libhidlmemory", + "android.hidl.memory@1.0", + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.bufferqueue@1.0", + ], + + export_shared_lib_headers: [ + "libbinder", + "libicuuc", + "libicui18n", + "libsonivox", + "libmediadrm", + "android.hidl.memory@1.0", + ], + + // for memory heap analysis + static_libs: [ + "libc_malloc_debug_backtrace", + ], + + include_dirs: [ + "frameworks/native/include/media/openmax", + "frameworks/av/include/media/", + "frameworks/av/media/libstagefright", + ], + + export_include_dirs: [ + "include", + ], + cflags: [ + "-Werror", + "-Wno-error=deprecated-declarations", + "-Wall", + ], + + sanitize: { + misc_undefined: [ + "unsigned-integer-overflow", + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, +} diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk deleted file mode 100644 index e6677866c2..0000000000 --- a/media/libmedia/Android.mk +++ /dev/null @@ -1,115 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_AIDL_INCLUDES := \ - frameworks/av/media/libmedia/aidl - -LOCAL_SRC_FILES:= \ - aidl/android/IGraphicBufferSource.aidl \ - aidl/android/IOMXBufferSource.aidl - -LOCAL_SRC_FILES += \ - IDataSource.cpp \ - IHDCP.cpp \ - BufferingSettings.cpp \ - mediaplayer.cpp \ - IMediaCodecList.cpp \ - IMediaCodecService.cpp \ - IMediaHTTPConnection.cpp \ - IMediaHTTPService.cpp \ - IMediaExtractor.cpp \ - IMediaExtractorService.cpp \ - IMediaPlayerService.cpp \ - IMediaPlayerClient.cpp \ - IMediaRecorderClient.cpp \ - IMediaPlayer.cpp \ - IMediaRecorder.cpp \ - IMediaSource.cpp \ - IRemoteDisplay.cpp \ - IRemoteDisplayClient.cpp \ - IResourceManagerClient.cpp \ - IResourceManagerService.cpp \ - IStreamSource.cpp \ - MediaCodecBuffer.cpp \ - MediaCodecInfo.cpp \ - MediaDefs.cpp \ - MediaUtils.cpp \ - Metadata.cpp \ - mediarecorder.cpp \ - IMediaMetadataRetriever.cpp \ - mediametadataretriever.cpp \ - MidiDeviceInfo.cpp \ - MidiIoWrapper.cpp \ - JetPlayer.cpp \ - IOMX.cpp \ - MediaScanner.cpp \ - MediaScannerClient.cpp \ - CharacterEncodingDetector.cpp \ - IMediaDeathNotifier.cpp \ - MediaProfiles.cpp \ - MediaResource.cpp \ - MediaResourcePolicy.cpp \ - OMXBuffer.cpp \ - Visualizer.cpp \ - StringArray.cpp \ - omx/1.0/WGraphicBufferSource.cpp \ - omx/1.0/WOmx.cpp \ - omx/1.0/WOmxBufferSource.cpp \ - omx/1.0/WOmxNode.cpp \ - omx/1.0/WOmxObserver.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \ - libcamera_client libstagefright_foundation \ - libgui libdl libaudioutils libaudioclient \ - libmedia_helper libmediadrm \ - libmediametrics \ - libbase \ - libhidlbase \ - libhidltransport \ - libhwbinder \ - libhidlmemory \ - android.hidl.base@1.0 \ - android.hidl.memory@1.0 \ - android.hidl.token@1.0-utils \ - android.hardware.graphics.common@1.0 \ - android.hardware.graphics.bufferqueue@1.0 \ - android.hardware.media@1.0 \ - android.hardware.media.omx@1.0 \ - -LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \ - libbinder \ - libsonivox \ - libmediadrm \ - android.hidl.token@1.0-utils \ - android.hardware.media.omx@1.0 \ - android.hidl.memory@1.0 \ - -LOCAL_HEADER_LIBRARIES := libmedia_headers - -# for memory heap analysis -LOCAL_STATIC_LIBRARIES := libc_malloc_debug_backtrace libc_logging - -LOCAL_MODULE:= libmedia - -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -LOCAL_C_INCLUDES := \ - $(TOP)/system/libhidl/base/include \ - $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/frameworks/av/include/media/ \ - $(TOP)/frameworks/av/media/libmedia/aidl \ - $(TOP)/frameworks/av/include \ - $(TOP)/frameworks/native/include \ - $(call include-path-for, audio-utils) - -LOCAL_EXPORT_C_INCLUDE_DIRS := \ - frameworks/av/include/media \ - frameworks/av/media/libmedia/aidl \ - -LOCAL_CFLAGS += -Werror -Wno-error=deprecated-declarations -Wall -LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp index 62a7bdf08d..1f188f355b 100644 --- a/media/libmedia/MediaCodecInfo.cpp +++ b/media/libmedia/MediaCodecInfo.cpp @@ -85,13 +85,13 @@ sp<MediaCodecInfo::Capabilities> MediaCodecInfo::Capabilities::FromParcel( } status_t MediaCodecInfo::Capabilities::writeToParcel(Parcel *parcel) const { - CHECK_LE(mProfileLevels.size(), INT32_MAX); + CHECK_LE(mProfileLevels.size(), static_cast<size_t>(INT32_MAX)); parcel->writeInt32(mProfileLevels.size()); for (size_t i = 0; i < mProfileLevels.size(); i++) { parcel->writeInt32(mProfileLevels.itemAt(i).mProfile); parcel->writeInt32(mProfileLevels.itemAt(i).mLevel); } - CHECK_LE(mColorFormats.size(), INT32_MAX); + CHECK_LE(mColorFormats.size(), static_cast<size_t>(INT32_MAX)); parcel->writeInt32(mColorFormats.size()); for (size_t i = 0; i < mColorFormats.size(); i++) { parcel->writeInt32(mColorFormats.itemAt(i)); diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp index 37bf0bd892..4984b18b71 100644 --- a/media/libmedia/Visualizer.cpp +++ b/media/libmedia/Visualizer.cpp @@ -24,8 +24,6 @@ #include <sys/types.h> #include <limits.h> -#include <cutils/bitops.h> - #include <media/Visualizer.h> #include <audio_utils/fixedfft.h> #include <utils/Thread.h> diff --git a/media/libmedia/aidl/android/IGraphicBufferSource.aidl b/media/libmedia/aidl/android/IGraphicBufferSource.aidl index f3c7abceb8..12c276719f 100644 --- a/media/libmedia/aidl/android/IGraphicBufferSource.aidl +++ b/media/libmedia/aidl/android/IGraphicBufferSource.aidl @@ -31,6 +31,7 @@ interface IGraphicBufferSource { void setTimeLapseConfig(double fps, double captureFps); void setStartTimeUs(long startTimeUs); void setStopTimeUs(long stopTimeUs); + long getStopTimeOffsetUs(); void setColorAspects(int aspects); void setTimeOffsetUs(long timeOffsetsUs); void signalEndOfInputStream(); diff --git a/media/libmedia/include/media/MediaRecorderBase.h b/media/libmedia/include/media/MediaRecorderBase.h index 0b0f9163b9..40dd9f9a12 100644 --- a/media/libmedia/include/media/MediaRecorderBase.h +++ b/media/libmedia/include/media/MediaRecorderBase.h @@ -45,7 +45,7 @@ struct MediaRecorderBase { const sp<ICameraRecordingProxy>& proxy) = 0; virtual status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface) = 0; virtual status_t setOutputFile(int fd) = 0; - virtual status_t setNextOutputFile(int fd) {return INVALID_OPERATION;} + virtual status_t setNextOutputFile(int /*fd*/) {return INVALID_OPERATION;} virtual status_t setOutputFileAuxiliary(int /*fd*/) {return INVALID_OPERATION;} virtual status_t setParameters(const String8& params) = 0; virtual status_t setListener(const sp<IMediaRecorderClient>& listener) = 0; diff --git a/media/libmedia/include/media/OMXBuffer.h b/media/libmedia/include/media/OMXBuffer.h index 6f79182afd..3e84858d14 100644 --- a/media/libmedia/include/media/OMXBuffer.h +++ b/media/libmedia/include/media/OMXBuffer.h @@ -19,7 +19,6 @@ #include <cutils/native_handle.h> #include <media/IOMX.h> -#include <system/window.h> #include <utils/StrongPointer.h> #include <hidl/HidlSupport.h> diff --git a/media/libmedia/include/media/TypeConverter.h b/media/libmedia/include/media/TypeConverter.h index cb8a307e10..84e22b1478 100644 --- a/media/libmedia/include/media/TypeConverter.h +++ b/media/libmedia/include/media/TypeConverter.h @@ -203,7 +203,8 @@ inline void TypeConverter<Traits>::maskToString(uint32_t mask, std::string &str, if (mask != 0) { bool first_flag = true; for (size_t i = 0; mTable[i].literal; i++) { - if (mTable[i].value != 0 && (mask & mTable[i].value) == mTable[i].value) { + uint32_t value = static_cast<uint32_t>(mTable[i].value); + if (mTable[i].value != 0 && ((mask & value) == value)) { if (!first_flag) str += del; first_flag = false; str += mTable[i].literal; @@ -228,6 +229,20 @@ typedef TypeConverter<AudioModeTraits> AudioModeConverter; typedef TypeConverter<UsageTraits> UsageTypeConverter; typedef TypeConverter<SourceTraits> SourceTypeConverter; +template<> const OutputDeviceConverter::Table OutputDeviceConverter::mTable[]; +template<> const InputDeviceConverter::Table InputDeviceConverter::mTable[]; +template<> const OutputFlagConverter::Table OutputFlagConverter::mTable[]; +template<> const InputFlagConverter::Table InputFlagConverter::mTable[]; +template<> const FormatConverter::Table FormatConverter::mTable[]; +template<> const OutputChannelConverter::Table OutputChannelConverter::mTable[]; +template<> const InputChannelConverter::Table InputChannelConverter::mTable[]; +template<> const ChannelIndexConverter::Table ChannelIndexConverter::mTable[]; +template<> const GainModeConverter::Table GainModeConverter::mTable[]; +template<> const StreamTypeConverter::Table StreamTypeConverter::mTable[]; +template<> const AudioModeConverter::Table AudioModeConverter::mTable[]; +template<> const UsageTypeConverter::Table UsageTypeConverter::mTable[]; +template<> const SourceTypeConverter::Table SourceTypeConverter::mTable[]; + bool deviceFromString(const std::string& literalDevice, audio_devices_t& device); bool deviceToString(audio_devices_t device, std::string& literalDevice); diff --git a/media/libmedia/include/media/convert.h b/media/libmedia/include/media/convert.h index 980b5d50df..036c6113bf 100644 --- a/media/libmedia/include/media/convert.h +++ b/media/libmedia/include/media/convert.h @@ -119,7 +119,7 @@ static inline bool fromString(const std::string &str, T &result) /* Check for a '-' in string. If type is unsigned and a - is found, the * parsing fails. This is made necessary because "-1" is read as 65535 for * uint16_t, for example */ - if (str.find("-") != std::string::npos + if (str.find('-') != std::string::npos && !std::numeric_limits<T>::is_signed) { return false; } diff --git a/media/libmedia/omx/1.0/WGraphicBufferSource.cpp b/media/libmedia/omx/1.0/WGraphicBufferSource.cpp index 4c543fad86..31d1df905c 100644 --- a/media/libmedia/omx/1.0/WGraphicBufferSource.cpp +++ b/media/libmedia/omx/1.0/WGraphicBufferSource.cpp @@ -67,6 +67,14 @@ BnStatus LWGraphicBufferSource::setStopTimeUs( return toBinderStatus(mBase->setStopTimeUs(stopTimeUs)); } +BnStatus LWGraphicBufferSource::getStopTimeOffsetUs( + int64_t *stopTimeOffsetUs) { + return toBinderStatus(mBase->getStopTimeOffsetUs( + [stopTimeOffsetUs](auto, auto offsetUs) { + *stopTimeOffsetUs = offsetUs; + })); +} + BnStatus LWGraphicBufferSource::setColorAspects( int32_t aspects) { return toBinderStatus(mBase->setColorAspects( diff --git a/media/libmedia/omx/1.0/WOmxNode.cpp b/media/libmedia/omx/1.0/WOmxNode.cpp index 0933d1f837..2cd8b760d1 100644 --- a/media/libmedia/omx/1.0/WOmxNode.cpp +++ b/media/libmedia/omx/1.0/WOmxNode.cpp @@ -47,7 +47,7 @@ status_t LWOmxNode::getParameter( status_t transStatus = toStatusT(mBase->getParameter( toRawIndexType(index), tParams, - [&fnStatus, params, size]( + [&fnStatus, params]( Status status, hidl_vec<uint8_t> const& outParams) { fnStatus = toStatusT(status); std::copy( @@ -145,7 +145,7 @@ status_t LWOmxNode::allocateSecureBuffer( status_t transStatus = toStatusT(mBase->allocateSecureBuffer( portIndex, static_cast<uint64_t>(size), - [&fnStatus, buffer, buffer_data, native_handle]( + [&fnStatus, buffer, native_handle]( Status status, uint32_t outBuffer, hidl_handle const& outNativeHandle) { diff --git a/media/libmediametrics/Android.bp b/media/libmediametrics/Android.bp new file mode 100644 index 0000000000..15dac59f82 --- /dev/null +++ b/media/libmediametrics/Android.bp @@ -0,0 +1,36 @@ +cc_library_shared { + name: "libmediametrics", + + srcs: [ + "IMediaAnalyticsService.cpp", + "MediaAnalyticsItem.cpp", + ], + + shared_libs: [ + "liblog", + "libcutils", + "libutils", + "libbinder", + "libstagefright_foundation", + "libbase", + ], + + export_include_dirs: ["include"], + + cflags: [ + "-Werror", + "-Wno-error=deprecated-declarations", + "-Wall", + ], + + sanitize: { + misc_undefined: [ + "unsigned-integer-overflow", + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, +} diff --git a/media/libmediametrics/Android.mk b/media/libmediametrics/Android.mk deleted file mode 100644 index f8c4bb3414..0000000000 --- a/media/libmediametrics/Android.mk +++ /dev/null @@ -1,34 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES += \ - IMediaAnalyticsService.cpp \ - MediaAnalyticsItem.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - liblog libcutils libutils libbinder \ - libstagefright_foundation \ - libbase \ - -LOCAL_MODULE:= libmediametrics - -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -LOCAL_C_INCLUDES := \ - $(TOP)/system/libhidl/base/include \ - $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/frameworks/av/include/media/ \ - $(TOP)/frameworks/av/media/libmedia/aidl \ - $(TOP)/frameworks/av/include \ - $(TOP)/frameworks/native/include \ - $(call include-path-for, audio-utils) - -LOCAL_EXPORT_C_INCLUDE_DIRS := \ - frameworks/av/include/media \ - -LOCAL_CFLAGS += -Werror -Wno-error=deprecated-declarations -Wall -LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index 7af7031a8f..1fc74a9c25 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -49,15 +49,15 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libmedia LOCAL_C_INCLUDES := \ - $(TOP)/frameworks/av/media/libstagefright/include \ - $(TOP)/frameworks/av/media/libstagefright/rtsp \ - $(TOP)/frameworks/av/media/libstagefright/wifi-display \ - $(TOP)/frameworks/av/media/libstagefright/webm \ + frameworks/av/media/libstagefright/include \ + frameworks/av/media/libstagefright/rtsp \ + frameworks/av/media/libstagefright/wifi-display \ + frameworks/av/media/libstagefright/webm \ $(LOCAL_PATH)/include/media \ - $(TOP)/frameworks/av/include/camera \ - $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/frameworks/native/include/media/hardware \ - $(TOP)/external/tremolo/Tremolo \ + frameworks/av/include/camera \ + frameworks/native/include/media/openmax \ + frameworks/native/include/media/hardware \ + external/tremolo/Tremolo \ LOCAL_CFLAGS += -Werror -Wno-error=deprecated-declarations -Wall @@ -65,6 +65,9 @@ LOCAL_MODULE:= libmediaplayerservice LOCAL_32_BIT_ONLY := true +LOCAL_SANITIZE := cfi +LOCAL_SANITIZE_DIAG := cfi + include $(BUILD_SHARED_LIBRARY) include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index cb6404c5c0..91887a1aa5 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -2330,6 +2330,33 @@ VolumeShaper::Status MediaPlayerService::AudioOutput::applyVolumeShaper( } } } else { + // VolumeShapers are not affected when a track moves between players for + // gapless playback (setNextMediaPlayer). + // We forward VolumeShaper operations that do not change configuration + // to the new player so that unducking may occur as expected. + // Unducking is an idempotent operation, same if applied back-to-back. + if (configuration->getType() == VolumeShaper::Configuration::TYPE_ID + && mNextOutput != nullptr) { + ALOGV("applyVolumeShaper: Attempting to forward missed operation: %s %s", + configuration->toString().c_str(), operation->toString().c_str()); + Mutex::Autolock nextLock(mNextOutput->mLock); + + // recycled track should be forwarded from this AudioSink by switchToNextOutput + sp<AudioTrack> track = mNextOutput->mRecycledTrack; + if (track != nullptr) { + ALOGD("Forward VolumeShaper operation to recycled track %p", track.get()); + (void)track->applyVolumeShaper(configuration, operation); + } else { + // There is a small chance that the unduck occurs after the next + // player has already started, but before it is registered to receive + // the unduck command. + track = mNextOutput->mTrack; + if (track != nullptr) { + ALOGD("Forward VolumeShaper operation to track %p", track.get()); + (void)track->applyVolumeShaper(configuration, operation); + } + } + } status = mVolumeHandler->applyVolumeShaper(configuration, operation); } return status; diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index e1d762ffb3..89354d6d09 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -1864,7 +1864,7 @@ status_t StagefrightRecorder::setupMPEG4orWEBMRecording() { mStartTimeOffsetMs = mEncoderProfiles->getStartTimeOffsetMs(mCameraId); } else if (mVideoSource == VIDEO_SOURCE_SURFACE) { // surface source doesn't need large initial delay - mStartTimeOffsetMs = 200; + mStartTimeOffsetMs = 100; } if (mStartTimeOffsetMs > 0) { writer->setStartTimeOffsetMs(mStartTimeOffsetMs); @@ -1982,10 +1982,12 @@ status_t StagefrightRecorder::stop() { mCameraSourceTimeLapse = NULL; } - if (mVideoEncoderSource != NULL) { - int64_t stopTimeUs = systemTime() / 1000; - sp<MetaData> meta = new MetaData; - err = mVideoEncoderSource->setStopStimeUs(stopTimeUs); + int64_t stopTimeUs = systemTime() / 1000; + for (const auto &source : { mAudioEncoderSource, mVideoEncoderSource }) { + if (source != nullptr && OK != source->setStopTimeUs(stopTimeUs)) { + ALOGW("Failed to set stopTime %lld us for %s", + (long long)stopTimeUs, source->isVideo() ? "Video" : "Audio"); + } } if (mWriter != NULL) { diff --git a/media/libmediaplayerservice/include/MediaPlayerInterface.h b/media/libmediaplayerservice/include/MediaPlayerInterface.h index 0ef38090f3..6d02cce6f3 100644 --- a/media/libmediaplayerservice/include/MediaPlayerInterface.h +++ b/media/libmediaplayerservice/include/MediaPlayerInterface.h @@ -289,7 +289,7 @@ public: } // Modular DRM - virtual status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId) { + virtual status_t prepareDrm(const uint8_t /* uuid */[16], const Vector<uint8_t>& /* drmSessionId */) { return INVALID_OPERATION; } virtual status_t releaseDrm() { diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk index 08c3cf8ef5..c582631f01 100644 --- a/media/libmediaplayerservice/nuplayer/Android.mk +++ b/media/libmediaplayerservice/nuplayer/Android.mk @@ -17,14 +17,14 @@ LOCAL_SRC_FILES:= \ StreamingSource.cpp \ LOCAL_C_INCLUDES := \ - $(TOP)/frameworks/av/media/libstagefright \ - $(TOP)/frameworks/av/media/libstagefright/httplive \ - $(TOP)/frameworks/av/media/libstagefright/include \ - $(TOP)/frameworks/av/media/libstagefright/mpeg2ts \ - $(TOP)/frameworks/av/media/libstagefright/rtsp \ - $(TOP)/frameworks/av/media/libstagefright/timedtext \ - $(TOP)/frameworks/av/media/libmediaplayerservice \ - $(TOP)/frameworks/native/include/media/openmax + frameworks/av/media/libstagefright \ + frameworks/av/media/libstagefright/httplive \ + frameworks/av/media/libstagefright/include \ + frameworks/av/media/libstagefright/mpeg2ts \ + frameworks/av/media/libstagefright/rtsp \ + frameworks/av/media/libstagefright/timedtext \ + frameworks/av/media/libmediaplayerservice \ + frameworks/native/include/media/openmax LOCAL_CFLAGS += -Werror -Wall @@ -44,5 +44,7 @@ LOCAL_MODULE:= libstagefright_nuplayer LOCAL_MODULE_TAGS := eng -include $(BUILD_STATIC_LIBRARY) +LOCAL_SANITIZE := cfi +LOCAL_SANITIZE_DIAG := cfi +include $(BUILD_STATIC_LIBRARY) diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index d83c40619e..aa21fff23d 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -1242,6 +1242,16 @@ status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs, MediaPlayerSeekMode mAudioLastDequeueTimeUs = seekTimeUs; } + if (mSubtitleTrack.mSource != NULL) { + mSubtitleTrack.mPackets->clear(); + mFetchSubtitleDataGeneration++; + } + + if (mTimedTextTrack.mSource != NULL) { + mTimedTextTrack.mPackets->clear(); + mFetchTimedTextDataGeneration++; + } + // If currently buffering, post kWhatBufferingEnd first, so that // NuPlayer resumes. Otherwise, if cache hits high watermark // before new polling happens, no one will resume the playback. diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 6ded3925b6..6a092278eb 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -762,12 +762,13 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { } mDeferredActions.push_back( - new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */, + new FlushDecoderAction( + (obj != NULL ? FLUSH_CMD_FLUSH : FLUSH_CMD_NONE) /* audio */, FLUSH_CMD_SHUTDOWN /* video */)); mDeferredActions.push_back(new SetSurfaceAction(surface)); - if (obj != NULL || mAudioDecoder != NULL) { + if (obj != NULL) { if (mStarted) { // Issue a seek to refresh the video screen only if started otherwise // the extractor may not yet be started and will assert. @@ -785,13 +786,13 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { // again if possible. mDeferredActions.push_back( new SimpleAction(&NuPlayer::performScanSources)); - } - // After a flush without shutdown, decoder is paused. - // Don't resume it until source seek is done, otherwise it could - // start pulling stale data too soon. - mDeferredActions.push_back( - new ResumeDecoderAction(false /* needNotify */)); + // After a flush without shutdown, decoder is paused. + // Don't resume it until source seek is done, otherwise it could + // start pulling stale data too soon. + mDeferredActions.push_back( + new ResumeDecoderAction(false /* needNotify */)); + } processDeferredActions(); break; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 5775b434e7..758db1fa0f 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -1110,7 +1110,7 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { // (Case 1) // Must be a multiple of the frame size. If it is not a multiple of a frame size, it // needs to fail, as we should not carry over fractional frames between calls. - CHECK_EQ(copy % mAudioSink->frameSize(), 0); + CHECK_EQ(copy % mAudioSink->frameSize(), 0u); // (Case 2, 3, 4) // Return early to the caller. diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp index 9264e4930f..8b3d0dc5d6 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp @@ -544,7 +544,7 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) { return; } - CHECK_EQ(msg->what(), (int)kWhatNotify); + CHECK_EQ(msg->what(), kWhatNotify); int32_t what; CHECK(msg->findInt32("what", &what)); diff --git a/media/libmediaplayerservice/tests/Android.mk b/media/libmediaplayerservice/tests/Android.mk index dc761ec5d4..0b9b85ff18 100644 --- a/media/libmediaplayerservice/tests/Android.mk +++ b/media/libmediaplayerservice/tests/Android.mk @@ -14,7 +14,6 @@ LOCAL_SHARED_LIBRARIES := \ libmediaplayerservice \ libmediadrm \ libutils \ - android.hidl.base@1.0 \ android.hardware.drm@1.0 \ LOCAL_C_INCLUDES := \ diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp index de38e7ff95..ebb90c8fa3 100644 --- a/media/libnbaio/NBLog.cpp +++ b/media/libnbaio/NBLog.cpp @@ -14,10 +14,85 @@ * limitations under the License. */ +/* +* Documentation: Workflow summary for histogram data processing: +* For more details on FIFO, please see system/media/audio_utils; doxygen +* TODO: add this documentation to doxygen once it is further developed +* 1) writing the data to a buffer +* onWork +* Called every period length (e.g., 4ms) +* Calls LOG_HIST_TS +* LOG_HIST_TS +* Hashes file name and line number +* calls NBLOG::Writer::logHistTS once +* NBLOG::Writer::logHistTS +* calls NBLOG::Writer::log on hash and current timestamp +* time is in CLOCK_MONOTONIC converted to ns +* NBLOG::Writer::log(Event, const void*, size_t) +* Initializes Entry, a struct containing one log entry +* Entry contains the event type (mEvent), data length (mLength), +* and data pointer (mData) +* TODO: why mLength (max length of buffer data) must be <= kMaxLength = 255? +* calls NBLOG::Writer::log(Entry *, bool) +* NBLog::Writer::log(Entry *, bool) +* Calls copyEntryDataAt to format data as follows in temp array: +* [type][length][data ... ][length] +* calls audio_utils_fifo_writer.write on temp +* audio_utils_fifo_writer.write +* calls obtain(), memcpy (reference in doxygen) +* returns number of frames written +* ssize_t audio_utils_fifo_reader::obtain +* Determines readable buffer section via pointer arithmetic on reader +* and writer pointers +* +* 2) reading the data from shared memory +* Thread::threadloop() +* TODO: add description? +* NBLog::MergeThread::threadLoop() +* calls NBLog::Merger::merge +* NBLog::Merger::merge +* for each reader in vector of class NamedReader, +* callsNamedReader::reader()->getSnapshot +* TODO: check whether the rest of this function is relevant +* NBLog::Reader::getSnapshot +* copies snapshot of reader's fifo buffer into its own buffer +* calls mFifoReader->obtain to find readable data +* sets snapshot.begin() and .end() iterators to boundaries of valid entries +* moves the fifo reader index to after the last entry read +* in this case, the buffer is in shared memory. in (3), the buffer is private +* +* 3) reading the data from private buffer +* MediaLogService::dump +* calls NBLog::Reader::dump(int) on instance of subclass mergeReader +* NBLog::Reader::dump(int) +* calls getSnapshot on the current reader +* calls dump(int, size_t, Snapshot) +* NBLog::Reader::dump(int, size, snapshot) +* iterates through snapshot's events and switches based on their type +* (string, timestamp, etc...) +* In the case of EVENT_HISTOGRAM_ENTRY_TS, adds a list of timestamp sequences +* (histogram entry) to NBLog::mHists +* In the case of EVENT_HISTOGRAM_FLUSH, calls drawHistogram on each element in +* the list and erases it +* TODO: when do these events occur? +* NBLog::drawHistogram +* input: timestamp array +* buckets this to a histogram and prints +* +*/ + #define LOG_TAG "NBLog" //#define LOG_NDEBUG 0 +#include <algorithm> #include <climits> +#include <deque> +#include <fstream> +// #include <inttypes.h> +#include <iostream> +#include <math.h> +#include <numeric> +#include <vector> #include <stdarg.h> #include <stdint.h> #include <stdio.h> @@ -27,16 +102,18 @@ #include <new> #include <audio_utils/roundup.h> #include <media/nbaio/NBLog.h> +// #include <utils/CallStack.h> // used to print callstack #include <utils/Log.h> #include <utils/String8.h> #include <queue> +#include <utility> namespace android { -int NBLog::Entry::readAt(size_t offset) const +int NBLog::Entry::copyEntryDataAt(size_t offset) const { - // FIXME This is too slow, despite the name it is used during writing + // FIXME This is too slow if (offset == 0) return mEvent; else if (offset == 1) @@ -51,12 +128,29 @@ int NBLog::Entry::readAt(size_t offset) const // --------------------------------------------------------------------------- -NBLog::FormatEntry::FormatEntry(const uint8_t *entry) : mEntry(entry) { - ALOGW_IF(entry[offsetof(struct entry, type)] != EVENT_START_FMT, - "Created format entry with invalid event type %d", entry[offsetof(struct entry, type)]); +/*static*/ +std::unique_ptr<NBLog::AbstractEntry> NBLog::AbstractEntry::buildEntry(const uint8_t *ptr) { + const uint8_t type = EntryIterator(ptr)->type; + switch (type) { + case EVENT_START_FMT: + return std::make_unique<FormatEntry>(FormatEntry(ptr)); + case EVENT_HISTOGRAM_FLUSH: + case EVENT_HISTOGRAM_ENTRY_TS: + return std::make_unique<HistogramEntry>(HistogramEntry(ptr)); + default: + ALOGW("Tried to create AbstractEntry of type %d", type); + return nullptr; + } +} + +NBLog::AbstractEntry::AbstractEntry(const uint8_t *entry) : mEntry(entry) { } -NBLog::FormatEntry::FormatEntry(const NBLog::FormatEntry::iterator &it) : FormatEntry(it.ptr) {} +// --------------------------------------------------------------------------- + +NBLog::EntryIterator NBLog::FormatEntry::begin() const { + return EntryIterator(mEntry); +} const char *NBLog::FormatEntry::formatString() const { return (const char*) mEntry + offsetof(entry, data); @@ -66,12 +160,14 @@ size_t NBLog::FormatEntry::formatStringLength() const { return mEntry[offsetof(entry, length)]; } -NBLog::FormatEntry::iterator NBLog::FormatEntry::args() const { +NBLog::EntryIterator NBLog::FormatEntry::args() const { auto it = begin(); // skip start fmt ++it; // skip timestamp ++it; + // skip hash + ++it; // Skip author if present if (it->type == EVENT_AUTHOR) { ++it; @@ -79,19 +175,33 @@ NBLog::FormatEntry::iterator NBLog::FormatEntry::args() const { return it; } -timespec NBLog::FormatEntry::timestamp() const { +int64_t NBLog::FormatEntry::timestamp() const { + auto it = begin(); + // skip start fmt + ++it; + return it.payload<int64_t>(); +} + +NBLog::log_hash_t NBLog::FormatEntry::hash() const { auto it = begin(); // skip start fmt ++it; - return it.payload<timespec>(); + // skip timestamp + ++it; + // unaligned 64-bit read not supported + log_hash_t hash; + memcpy(&hash, it->data, sizeof(hash)); + return hash; } -pid_t NBLog::FormatEntry::author() const { +int NBLog::FormatEntry::author() const { auto it = begin(); // skip start fmt ++it; // skip timestamp ++it; + // skip hash + ++it; // if there is an author entry, return it, return -1 otherwise if (it->type == EVENT_AUTHOR) { return it.payload<int>(); @@ -99,12 +209,13 @@ pid_t NBLog::FormatEntry::author() const { return -1; } -NBLog::FormatEntry::iterator NBLog::FormatEntry::copyWithAuthor( +NBLog::EntryIterator NBLog::FormatEntry::copyWithAuthor( std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const { auto it = begin(); // copy fmt start entry it.copyTo(dst); // copy timestamp + (++it).copyTo(dst); // copy hash (++it).copyTo(dst); // insert author entry size_t authorEntrySize = NBLog::Entry::kOverhead + sizeof(author); @@ -124,71 +235,103 @@ NBLog::FormatEntry::iterator NBLog::FormatEntry::copyWithAuthor( return it; } -void NBLog::FormatEntry::iterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const { +void NBLog::EntryIterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const { size_t length = ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead; dst->write(ptr, length); } -void NBLog::FormatEntry::iterator::copyData(uint8_t *dst) const { +void NBLog::EntryIterator::copyData(uint8_t *dst) const { memcpy((void*) dst, ptr + offsetof(entry, data), ptr[offsetof(entry, length)]); } -NBLog::FormatEntry::iterator NBLog::FormatEntry::begin() const { - return iterator(mEntry); -} - -NBLog::FormatEntry::iterator::iterator() +NBLog::EntryIterator::EntryIterator() : ptr(nullptr) {} -NBLog::FormatEntry::iterator::iterator(const uint8_t *entry) +NBLog::EntryIterator::EntryIterator(const uint8_t *entry) : ptr(entry) {} -NBLog::FormatEntry::iterator::iterator(const NBLog::FormatEntry::iterator &other) +NBLog::EntryIterator::EntryIterator(const NBLog::EntryIterator &other) : ptr(other.ptr) {} -const NBLog::FormatEntry::entry& NBLog::FormatEntry::iterator::operator*() const { +const NBLog::entry& NBLog::EntryIterator::operator*() const { return *(entry*) ptr; } -const NBLog::FormatEntry::entry* NBLog::FormatEntry::iterator::operator->() const { +const NBLog::entry* NBLog::EntryIterator::operator->() const { return (entry*) ptr; } -NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator++() { +NBLog::EntryIterator& NBLog::EntryIterator::operator++() { ptr += ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead; return *this; } -NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator--() { +NBLog::EntryIterator& NBLog::EntryIterator::operator--() { ptr -= ptr[NBLog::Entry::kPreviousLengthOffset] + NBLog::Entry::kOverhead; return *this; } -NBLog::FormatEntry::iterator NBLog::FormatEntry::iterator::next() const { - iterator aux(*this); +NBLog::EntryIterator NBLog::EntryIterator::next() const { + EntryIterator aux(*this); return ++aux; } -NBLog::FormatEntry::iterator NBLog::FormatEntry::iterator::prev() const { - iterator aux(*this); +NBLog::EntryIterator NBLog::EntryIterator::prev() const { + EntryIterator aux(*this); return --aux; } -int NBLog::FormatEntry::iterator::operator-(const NBLog::FormatEntry::iterator &other) const { +int NBLog::EntryIterator::operator-(const NBLog::EntryIterator &other) const { return ptr - other.ptr; } -bool NBLog::FormatEntry::iterator::operator!=(const iterator &other) const { +bool NBLog::EntryIterator::operator!=(const EntryIterator &other) const { return ptr != other.ptr; } -bool NBLog::FormatEntry::iterator::hasConsistentLength() const { +bool NBLog::EntryIterator::hasConsistentLength() const { return ptr[offsetof(entry, length)] == ptr[ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead + NBLog::Entry::kPreviousLengthOffset]; } // --------------------------------------------------------------------------- +int64_t NBLog::HistogramEntry::timestamp() const { + return EntryIterator(mEntry).payload<HistTsEntry>().ts; +} + +NBLog::log_hash_t NBLog::HistogramEntry::hash() const { + return EntryIterator(mEntry).payload<HistTsEntry>().hash; +} + +int NBLog::HistogramEntry::author() const { + EntryIterator it(mEntry); + if (it->length == sizeof(HistTsEntryWithAuthor)) { + return it.payload<HistTsEntryWithAuthor>().author; + } else { + return -1; + } +} + +NBLog::EntryIterator NBLog::HistogramEntry::copyWithAuthor( + std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const { + // Current histogram entry has {type, length, struct HistTsEntry, length}. + // We now want {type, length, struct HistTsEntryWithAuthor, length} + uint8_t buffer[Entry::kOverhead + sizeof(HistTsEntryWithAuthor)]; + // Copy content until the point we want to add the author + memcpy(buffer, mEntry, sizeof(entry) + sizeof(HistTsEntry)); + // Copy the author + *(int*) (buffer + sizeof(entry) + sizeof(HistTsEntry)) = author; + // Update lengths + buffer[offsetof(entry, length)] = sizeof(HistTsEntryWithAuthor); + buffer[sizeof(buffer) + Entry::kPreviousLengthOffset] = sizeof(HistTsEntryWithAuthor); + // Write new buffer into FIFO + dst->write(buffer, sizeof(buffer)); + return EntryIterator(mEntry).next(); +} + +// --------------------------------------------------------------------------- + #if 0 // FIXME see note in NBLog.h NBLog::Timeline::Timeline(size_t size, void *shared) : mSize(roundup(size)), mOwn(shared == NULL), @@ -301,13 +444,15 @@ void NBLog::Writer::logTimestamp() if (!mEnabled) { return; } - struct timespec ts; - if (!clock_gettime(CLOCK_MONOTONIC, &ts)) { + int64_t ts = get_monotonic_ns(); + if (ts > 0) { log(EVENT_TIMESTAMP, &ts, sizeof(ts)); + } else { + ALOGE("Failed to get timestamp"); } } -void NBLog::Writer::logTimestamp(const struct timespec &ts) +void NBLog::Writer::logTimestamp(const int64_t ts) { if (!mEnabled) { return; @@ -360,19 +505,57 @@ void NBLog::Writer::logEnd() log(&entry, true); } -void NBLog::Writer::logFormat(const char *fmt, ...) +void NBLog::Writer::logHash(log_hash_t hash) +{ + if (!mEnabled) { + return; + } + log(EVENT_HASH, &hash, sizeof(hash)); +} + +void NBLog::Writer::logHistTS(log_hash_t hash) +{ + if (!mEnabled) { + return; + } + HistTsEntry data; + data.hash = hash; + data.ts = get_monotonic_ns(); + if (data.ts > 0) { + log(EVENT_HISTOGRAM_ENTRY_TS, &data, sizeof(data)); + } else { + ALOGE("Failed to get timestamp"); + } +} + +void NBLog::Writer::logHistFlush(log_hash_t hash) +{ + if (!mEnabled) { + return; + } + HistTsEntry data; + data.hash = hash; + data.ts = get_monotonic_ns(); + if (data.ts > 0) { + log(EVENT_HISTOGRAM_FLUSH, &data, sizeof(data)); + } else { + ALOGE("Failed to get timestamp"); + } +} + +void NBLog::Writer::logFormat(const char *fmt, log_hash_t hash, ...) { if (!mEnabled) { return; } va_list ap; - va_start(ap, fmt); - Writer::logVFormat(fmt, ap); + va_start(ap, hash); + Writer::logVFormat(fmt, hash, ap); va_end(ap); } -void NBLog::Writer::logVFormat(const char *fmt, va_list argp) +void NBLog::Writer::logVFormat(const char *fmt, log_hash_t hash, va_list argp) { if (!mEnabled) { return; @@ -381,8 +564,9 @@ void NBLog::Writer::logVFormat(const char *fmt, va_list argp) int i; double f; char* s; - struct timespec t; + int64_t t; Writer::logTimestamp(); + Writer::logHash(hash); for (const char *p = fmt; *p != '\0'; p++) { // TODO: implement more complex formatting such as %.3f if (*p != '%') { @@ -395,7 +579,7 @@ void NBLog::Writer::logVFormat(const char *fmt, va_list argp) break; case 't': // timestamp - t = va_arg(argp, struct timespec); + t = va_arg(argp, int64_t); Writer::logTimestamp(t); break; @@ -440,40 +624,35 @@ void NBLog::Writer::log(Event event, const void *data, size_t length) // a confusion for a programmer debugging their code. return; } - switch (event) { - case EVENT_STRING: - case EVENT_TIMESTAMP: - case EVENT_INTEGER: - case EVENT_FLOAT: - case EVENT_PID: - case EVENT_START_FMT: - break; - case EVENT_RESERVED: - default: + // Ignore if invalid event + if (event == EVENT_RESERVED || event >= EVENT_UPPER_BOUND) { return; } - Entry entry(event, data, length); - log(&entry, true /*trusted*/); + Entry etr(event, data, length); + log(&etr, true /*trusted*/); } -void NBLog::Writer::log(const NBLog::Entry *entry, bool trusted) +void NBLog::Writer::log(const NBLog::Entry *etr, bool trusted) { if (!mEnabled) { return; } if (!trusted) { - log(entry->mEvent, entry->mData, entry->mLength); + log(etr->mEvent, etr->mData, etr->mLength); return; } - size_t need = entry->mLength + Entry::kOverhead; // mEvent, mLength, data[length], mLength - // need = number of bytes remaining to write + size_t need = etr->mLength + Entry::kOverhead; // mEvent, mLength, data[mLength], mLength + // need = number of bytes written to FIFO // FIXME optimize this using memcpy for the data part of the Entry. // The Entry could have a method copyTo(ptr, offset, size) to optimize the copy. + // checks size of a single log Entry: type, length, data pointer and ending uint8_t temp[Entry::kMaxLength + Entry::kOverhead]; + // write this data to temp array for (size_t i = 0; i < need; i++) { - temp[i] = entry->readAt(i); + temp[i] = etr->copyEntryDataAt(i); } + // write to circular buffer mFifoWriter->write(temp, need); } @@ -531,7 +710,7 @@ void NBLog::LockedWriter::logTimestamp() Writer::logTimestamp(); } -void NBLog::LockedWriter::logTimestamp(const struct timespec &ts) +void NBLog::LockedWriter::logTimestamp(const int64_t ts) { Mutex::Autolock _l(mLock); Writer::logTimestamp(ts); @@ -568,6 +747,12 @@ void NBLog::LockedWriter::logEnd() Writer::logEnd(); } +void NBLog::LockedWriter::logHash(log_hash_t hash) +{ + Mutex::Autolock _l(mLock); + Writer::logHash(hash); +} + bool NBLog::LockedWriter::isEnabled() const { Mutex::Autolock _l(mLock); @@ -582,13 +767,19 @@ bool NBLog::LockedWriter::setEnabled(bool enabled) // --------------------------------------------------------------------------- +const std::set<NBLog::Event> NBLog::Reader::startingTypes {NBLog::Event::EVENT_START_FMT, + NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS}; +const std::set<NBLog::Event> NBLog::Reader::endingTypes {NBLog::Event::EVENT_END_FMT, + NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS, + NBLog::Event::EVENT_HISTOGRAM_FLUSH}; NBLog::Reader::Reader(const void *shared, size_t size) : mShared((/*const*/ Shared *) shared), /*mIMemory*/ mFd(-1), mIndent(0), mFifo(mShared != NULL ? new audio_utils_fifo(size, sizeof(uint8_t), mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL), - mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL) + mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL), + findGlitch(false) { } @@ -604,16 +795,50 @@ NBLog::Reader::~Reader() delete mFifo; } -uint8_t *NBLog::Reader::findLastEntryOfType(uint8_t *front, uint8_t *back, uint8_t type) { +inline static int deltaMs(int64_t ns1, int64_t ns2) { + return (ns2 - ns1) / (1000 * 1000); +} + +// Produces a log warning if the timing of recent buffer periods caused a glitch +// Computes sum of running window of three buffer periods +// Checks whether the buffer periods leave enough CPU time for the next one +// e.g. if a buffer period is expected to be 4 ms and a buffer requires 3 ms of CPU time, +// here are some glitch cases: +// 4 + 4 + 6 ; 5 + 4 + 5; 2 + 2 + 10 +// TODO: develop this code to track changes in histogram distribution in addition +// to / instead of glitches +void NBLog::Reader::alertIfGlitch(const std::vector<int64_t> &samples) { + //TODO: measure kPeriodLen and kRatio from the data as they may change. + static const int kPeriodLen = 4; // current period length is ideally 4 ms + static const double kRatio = 0.75; // estimate of CPU time as ratio of period length + // DAC processing time for 4 ms buffer + static const int kPeriodTime = static_cast<int>(round(kPeriodLen * kRatio)); + static const int kNumBuff = 3; // number of buffers considered in local history + std::deque<int> periods(kNumBuff, kPeriodLen); + for (size_t i = 2; i < samples.size(); ++i) { // skip first time entry + periods.push_front(deltaMs(samples[i - 1], samples[i])); + periods.pop_back(); + // TODO: check that all glitch cases are covered + if (std::accumulate(periods.begin(), periods.end(), 0) > kNumBuff * kPeriodLen + + kPeriodLen - kPeriodTime) { + ALOGW("A glitch occurred"); + periods.assign(kNumBuff, kPeriodLen); + } + } + return; +} + +const uint8_t *NBLog::Reader::findLastEntryOfTypes(const uint8_t *front, const uint8_t *back, + const std::set<Event> &types) { while (back + Entry::kPreviousLengthOffset >= front) { - uint8_t *prev = back - back[Entry::kPreviousLengthOffset] - Entry::kOverhead; - if (prev < front || prev + prev[offsetof(FormatEntry::entry, length)] + + const uint8_t *prev = back - back[Entry::kPreviousLengthOffset] - Entry::kOverhead; + if (prev < front || prev + prev[offsetof(entry, length)] + Entry::kOverhead != back) { // prev points to an out of limits or inconsistent entry return nullptr; } - if (prev[offsetof(FormatEntry::entry, type)] == type) { + if (types.find((const Event) prev[offsetof(entry, type)]) != types.end()) { return prev; } back = prev; @@ -652,21 +877,21 @@ std::unique_ptr<NBLog::Reader::Snapshot> NBLog::Reader::getSnapshot() // it ends in a complete entry (which is not an END_FMT). So is safe to traverse backwards. // TODO: handle client corruption (in the middle of a buffer) - uint8_t *back = snapshot->mData + availToRead; - uint8_t *front = snapshot->mData; + const uint8_t *back = snapshot->mData + availToRead; + const uint8_t *front = snapshot->mData; // Find last END_FMT. <back> is sitting on an entry which might be the middle of a FormatEntry. // We go backwards until we find an EVENT_END_FMT. - uint8_t *lastEnd = findLastEntryOfType(front, back, EVENT_END_FMT); + const uint8_t *lastEnd = findLastEntryOfTypes(front, back, endingTypes); if (lastEnd == nullptr) { - snapshot->mEnd = snapshot->mBegin = FormatEntry::iterator(front); + snapshot->mEnd = snapshot->mBegin = EntryIterator(front); } else { // end of snapshot points to after last END_FMT entry - snapshot->mEnd = FormatEntry::iterator(lastEnd + Entry::kOverhead); + snapshot->mEnd = EntryIterator(lastEnd).next(); // find first START_FMT - uint8_t *firstStart = nullptr; - uint8_t *firstStartTmp = lastEnd; - while ((firstStartTmp = findLastEntryOfType(front, firstStartTmp, EVENT_START_FMT)) + const uint8_t *firstStart = nullptr; + const uint8_t *firstStartTmp = snapshot->mEnd; + while ((firstStartTmp = findLastEntryOfTypes(front, firstStartTmp, startingTypes)) != nullptr) { firstStart = firstStartTmp; } @@ -674,7 +899,7 @@ std::unique_ptr<NBLog::Reader::Snapshot> NBLog::Reader::getSnapshot() if (firstStart == nullptr) { snapshot->mBegin = snapshot->mEnd; } else { - snapshot->mBegin = FormatEntry::iterator(firstStart); + snapshot->mBegin = EntryIterator(firstStart); } } @@ -686,8 +911,37 @@ std::unique_ptr<NBLog::Reader::Snapshot> NBLog::Reader::getSnapshot() } +// writes sample deltas to file, either truncating or appending +inline void writeHistToFile(const std::vector<int64_t> &samples, bool append) { + // name of file on audioserver + static const char* const kName = (char *)"/data/misc/audioserver/sample_results.txt"; + // stores deltas between the samples + std::vector<int64_t> intervals; + for (size_t i = 1; i < samples.size(); ++i) { + intervals.push_back(deltaMs(samples[i - 1], samples[i])); + } + if (intervals.empty()) return; + // Deletes maximum value in a histogram. Temp quick fix. + // FIXME: need to find root cause of approx. 35th element from the end + // consistently being an outlier in the first histogram of a flush + // ALOGW("%" PRId64 "before", (int64_t) *(std::max_element(intervals.begin(), intervals.end()))); + intervals.erase(std::max_element(intervals.begin(), intervals.end())); + // ALOGW("%" PRId64 "after", (int64_t) *(std::max_element(intervals.begin(), intervals.end()))); + std::ofstream ofs; + ofs.open(kName, append ? std::ios::app : std::ios::trunc); + if (!ofs) { + ALOGW("couldn't open file %s", kName); + return; + } + for (size_t i = 0; i < intervals.size(); ++i) { + ofs << intervals[i] << "\n"; + } + ofs.close(); +} + void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapshot) { + // CallStack cs(LOG_TAG); #if 0 struct timespec ts; time_t maxSec = -1; @@ -712,11 +966,11 @@ void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapsho mFd = fd; mIndent = indent; String8 timestamp, body; - size_t lost = snapshot.lost() + (snapshot.begin() - FormatEntry::iterator(snapshot.data())); + size_t lost = snapshot.lost() + (snapshot.begin() - EntryIterator(snapshot.data())); if (lost > 0) { body.appendFormat("warning: lost %zu bytes worth of events", lost); // TODO timestamp empty here, only other choice to wait for the first timestamp event in the - // log to push it out. Consider keeping the timestamp/body between calls to readAt(). + // log to push it out. Consider keeping the timestamp/body between calls to copyEntryDataAt(). dumpLine(timestamp, body); } #if 0 @@ -730,6 +984,7 @@ void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapsho } bool deferredTimestamp = false; #endif + for (auto entry = snapshot.begin(); entry != snapshot.end();) { switch (entry->type) { #if 0 @@ -798,9 +1053,53 @@ void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapsho break; #endif case EVENT_START_FMT: - // right now, this is the only supported case entry = handleFormat(FormatEntry(entry), ×tamp, &body); break; + case EVENT_HISTOGRAM_ENTRY_TS: { + HistTsEntryWithAuthor *data = (HistTsEntryWithAuthor *) (entry->data); + // TODO This memcpies are here to avoid unaligned memory access crash. + // There's probably a more efficient way to do it + log_hash_t hash; + memcpy(&hash, &(data->hash), sizeof(hash)); + int64_t ts; + memcpy(&ts, &data->ts, sizeof(ts)); + const std::pair<log_hash_t, int> key(hash, data->author); + // TODO might want to filter excessively high outliers, which are usually caused + // by the thread being inactive. + mHists[key].push_back(ts); + ++entry; + break; + } + // draws histograms stored in global Reader::mHists and erases them + case EVENT_HISTOGRAM_FLUSH: { + HistogramEntry histEntry(entry); + // Log timestamp + // Timestamp of call to drawHistogram, not when audio was generated + const int64_t ts = histEntry.timestamp(); + timestamp.clear(); + timestamp.appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)), + (int) ((ts / (1000 * 1000)) % 1000)); + // Log histograms + setFindGlitch(true); + body.appendFormat("Histogram flush - "); + handleAuthor(histEntry, &body); + for (auto hist = mHists.begin(); hist != mHists.end();) { + if (hist->first.second == histEntry.author()) { + body.appendFormat("%X", (int)hist->first.first); + if (findGlitch) { + alertIfGlitch(hist->second); + } + // set file to empty and write data for all histograms in this set + writeHistToFile(hist->second, hist != mHists.begin()); + drawHistogram(&body, hist->second, true, indent); + hist = mHists.erase(hist); + } else { + ++hist; + } + } + ++entry; + break; + } case EVENT_END_FMT: body.appendFormat("warning: got to end format event"); ++entry; @@ -814,12 +1113,8 @@ void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapsho if (!body.isEmpty()) { dumpLine(timestamp, body); - // deferredTimestamp = false; } } - // if (deferredTimestamp) { - // dumpLine(timestamp, body); - // } } void NBLog::Reader::dump(int fd, size_t indent) @@ -844,11 +1139,23 @@ bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer(); } +void NBLog::Reader::setFindGlitch(bool s) +{ + findGlitch = s; +} + +bool NBLog::Reader::isFindGlitch() const +{ + return findGlitch; +} + +// --------------------------------------------------------------------------- + void NBLog::appendTimestamp(String8 *body, const void *data) { - struct timespec ts; - memcpy(&ts, data, sizeof(struct timespec)); - body->appendFormat("[%d.%03d]", (int) ts.tv_sec, - (int) (ts.tv_nsec / 1000000)); + int64_t ts; + memcpy(&ts, data, sizeof(ts)); + body->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)), + (int) ((ts / (1000 * 1000)) % 1000)); } void NBLog::appendInt(String8 *body, const void *data) { @@ -868,20 +1175,42 @@ void NBLog::appendPID(String8 *body, const void* data, size_t length) { body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name); } -NBLog::FormatEntry::iterator NBLog::Reader::handleFormat(const FormatEntry &fmtEntry, +String8 NBLog::bufferDump(const uint8_t *buffer, size_t size) +{ + String8 str; + str.append("[ "); + for(size_t i = 0; i < size; i++) + { + str.appendFormat("%d ", buffer[i]); + } + str.append("]"); + return str; +} + +String8 NBLog::bufferDump(const EntryIterator &it) +{ + return bufferDump(it, it->length + Entry::kOverhead); +} + +NBLog::EntryIterator NBLog::Reader::handleFormat(const FormatEntry &fmtEntry, String8 *timestamp, String8 *body) { // log timestamp - struct timespec ts = fmtEntry.timestamp(); + int64_t ts = fmtEntry.timestamp(); timestamp->clear(); - timestamp->appendFormat("[%d.%03d]", (int) ts.tv_sec, - (int) (ts.tv_nsec / 1000000)); + timestamp->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)), + (int) ((ts / (1000 * 1000)) % 1000)); + + // log unique hash + log_hash_t hash = fmtEntry.hash(); + // print only lower 16bit of hash as hex and line as int to reduce spam in the log + body->appendFormat("%.4X-%d ", (int)(hash >> 16) & 0xFFFF, (int) hash & 0xFFFF); // log author (if present) handleAuthor(fmtEntry, body); // log string - NBLog::FormatEntry::iterator arg = fmtEntry.args(); + NBLog::EntryIterator arg = fmtEntry.args(); const char* fmt = fmtEntry.formatString(); size_t fmt_length = fmtEntry.formatStringLength(); @@ -954,10 +1283,127 @@ NBLog::FormatEntry::iterator NBLog::Reader::handleFormat(const FormatEntry &fmtE return arg; } -// --------------------------------------------------------------------------- +static int widthOf(int x) { + int width = 0; + while (x > 0) { + ++width; + x /= 10; + } + return width; +} + +static std::map<int, int> buildBuckets(const std::vector<int64_t> &samples) { + // TODO allow buckets of variable resolution + std::map<int, int> buckets; + for (size_t i = 1; i < samples.size(); ++i) { + ++buckets[deltaMs(samples[i - 1], samples[i])]; + } + return buckets; +} + +static inline uint32_t log2(uint32_t x) { + // This works for x > 0 + return 31 - __builtin_clz(x); +} + +// TODO put this function in separate file. Make it return a std::string instead of modifying body +/* +Example output: +[54.234] Histogram flush - AudioOut_D: +Histogram 33640BF1 + [ 1][ 1][ 1][ 3][54][69][ 1][ 2][ 1] + 64| [] + 32| [] [] + 16| [] [] + 8| [] [] + 4| [] [] + 2|______________[]__[]__[]______[]____ + 4 5 6 8 9 10 11 13 15 +Notice that all values that fall in the same row have the same height (65 and 127 are displayed +identically). That's why exact counts are added at the top. +*/ +void NBLog::Reader::drawHistogram(String8 *body, + const std::vector<int64_t> &samples, + bool logScale, + int indent, + int maxHeight) { + // this avoids some corner cases + if (samples.size() <= 1) { + return; + } + // temp code for debugging the outlier timestamp + const int kMaxMs = 100; + for (size_t i = 1; i < samples.size()-1; ++i) { + const int currDelta = deltaMs(samples[i - 1], samples[i]); + if (currDelta > kMaxMs) { + body->appendFormat("\nlocation: %zu, size: %zu, pos from end: %zu, %d\t", i, + samples.size(), samples.size() - i, currDelta); + } + } + // FIXME: as can be seen when printing the values, the outlier timestamps typically occur + // in the first histogram 35 to 38 indices from the end (most often 35). + // TODO: build histogram buckets earlier and discard timestamps to save memory + std::map<int, int> buckets = buildBuckets(samples); + // TODO consider changing all ints to uint32_t or uint64_t + + // underscores and spaces length corresponds to maximum width of histogram + static const int kLen = 40; + std::string underscores(kLen, '-'); + std::string spaces(kLen, ' '); + + auto it = buckets.begin(); + int maxDelta = it->first; + int maxCount = it->second; + // Compute maximum values + while (++it != buckets.end()) { + if (it->first > maxDelta) { + maxDelta = it->first; + } + if (it->second > maxCount) { + maxCount = it->second; + } + } + int height = logScale ? log2(maxCount) + 1 : maxCount; // maxCount > 0, safe to call log2 + const int leftPadding = widthOf(logScale ? pow(2, height) : maxCount); + const int colWidth = std::max(std::max(widthOf(maxDelta) + 1, 3), leftPadding + 2); + int scalingFactor = 1; + // scale data if it exceeds maximum height + if (height > maxHeight) { + scalingFactor = (height + maxHeight) / maxHeight; + height /= scalingFactor; + } + body->appendFormat("\n%*s", leftPadding + 11, "Occurrences"); + // write histogram label line with bucket values + body->appendFormat("\n%*s", indent, " "); + body->appendFormat("%*s", leftPadding, " "); + for (auto const &x : buckets) { + body->appendFormat("%*d", colWidth, x.second); + } + // write histogram ascii art + body->appendFormat("\n%*s", indent, " "); + for (int row = height * scalingFactor; row >= 0; row -= scalingFactor) { + const int value = logScale ? (1 << row) : row; + body->appendFormat("%.*s", leftPadding, spaces.c_str()); + for (auto const &x : buckets) { + body->appendFormat("%.*s%s", colWidth - 1, spaces.c_str(), x.second < value ? " " : "|"); + } + body->appendFormat("\n%*s", indent, " "); + } + // print x-axis + const int columns = static_cast<int>(buckets.size()); + body->appendFormat("%*c", leftPadding, ' '); + body->appendFormat("%.*s", (columns + 1) * colWidth, underscores.c_str()); + body->appendFormat("\n%*s", indent, " "); + + // write footer with bucket labels + body->appendFormat("%*s", leftPadding, " "); + for (auto const &x : buckets) { + body->appendFormat("%*d", colWidth, x.first); + } + body->appendFormat("%.*s%s", colWidth, spaces.c_str(), "ms\n"); +} NBLog::Merger::Merger(const void *shared, size_t size): - mBuffer(NULL), mShared((Shared *) shared), mFifo(mShared != NULL ? new audio_utils_fifo(size, sizeof(uint8_t), @@ -966,6 +1412,8 @@ NBLog::Merger::Merger(const void *shared, size_t size): {} void NBLog::Merger::addReader(const NBLog::NamedReader &reader) { + // FIXME This is called by binder thread in MediaLogService::registerWriter + // but the access to shared variable mNamedReaders is not yet protected by a lock. mNamedReaders.push_back(reader); } @@ -973,26 +1421,27 @@ void NBLog::Merger::addReader(const NBLog::NamedReader &reader) { // composed by a timestamp and the index of the snapshot where the timestamp came from struct MergeItem { - struct timespec ts; + int64_t ts; int index; - MergeItem(struct timespec ts, int index): ts(ts), index(index) {} + MergeItem(int64_t ts, int index): ts(ts), index(index) {} }; // operators needed for priority queue in merge -bool operator>(const struct timespec &t1, const struct timespec &t2) { - return t1.tv_sec > t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec); -} +// bool operator>(const int64_t &t1, const int64_t &t2) { +// return t1.tv_sec > t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec); +// } bool operator>(const struct MergeItem &i1, const struct MergeItem &i2) { - return i1.ts > i2.ts || - (i1.ts.tv_sec == i2.ts.tv_sec && i1.ts.tv_nsec == i2.ts.tv_nsec && i1.index > i2.index); + return i1.ts > i2.ts || (i1.ts == i2.ts && i1.index > i2.index); } // Merge registered readers, sorted by timestamp void NBLog::Merger::merge() { + // FIXME This is called by merge thread + // but the access to shared variable mNamedReaders is not yet protected by a lock. int nLogs = mNamedReaders.size(); std::vector<std::unique_ptr<NBLog::Reader::Snapshot>> snapshots(nLogs); - std::vector<NBLog::FormatEntry::iterator> offsets(nLogs); + std::vector<NBLog::EntryIterator> offsets(nLogs); for (int i = 0; i < nLogs; ++i) { snapshots[i] = mNamedReaders[i].reader()->getSnapshot(); offsets[i] = snapshots[i]->begin(); @@ -1004,7 +1453,7 @@ void NBLog::Merger::merge() { for (int i = 0; i < nLogs; ++i) { if (offsets[i] != snapshots[i]->end()) { - timespec ts = FormatEntry(offsets[i]).timestamp(); + int64_t ts = AbstractEntry::buildEntry(offsets[i])->timestamp(); timestamps.emplace(ts, i); } } @@ -1013,30 +1462,36 @@ void NBLog::Merger::merge() { // find minimum timestamp int index = timestamps.top().index; // copy it to the log, increasing offset - offsets[index] = FormatEntry(offsets[index]).copyWithAuthor(mFifoWriter, index); + offsets[index] = AbstractEntry::buildEntry(offsets[index])->copyWithAuthor(mFifoWriter, + index); // update data structures timestamps.pop(); if (offsets[index] != snapshots[index]->end()) { - timespec ts = FormatEntry(offsets[index]).timestamp(); + int64_t ts = AbstractEntry::buildEntry(offsets[index])->timestamp(); timestamps.emplace(ts, index); } } } -const std::vector<NBLog::NamedReader> *NBLog::Merger::getNamedReaders() const { - return &mNamedReaders; +const std::vector<NBLog::NamedReader>& NBLog::Merger::getNamedReaders() const { + // FIXME This is returning a reference to a shared variable that needs a lock + return mNamedReaders; } +// --------------------------------------------------------------------------- + NBLog::MergeReader::MergeReader(const void *shared, size_t size, Merger &merger) : Reader(shared, size), mNamedReaders(merger.getNamedReaders()) {} -size_t NBLog::MergeReader::handleAuthor(const NBLog::FormatEntry &fmtEntry, String8 *body) { - int author = fmtEntry.author(); - const char* name = (*mNamedReaders)[author].name(); +void NBLog::MergeReader::handleAuthor(const NBLog::AbstractEntry &entry, String8 *body) { + int author = entry.author(); + // FIXME Needs a lock + const char* name = mNamedReaders[author].name(); body->appendFormat("%s: ", name); - return NBLog::Entry::kOverhead + sizeof(author); } +// --------------------------------------------------------------------------- + NBLog::MergeThread::MergeThread(NBLog::Merger &merger) : mMerger(merger), mTimeoutUs(0) {} diff --git a/media/libnbaio/include/NBLog.h b/media/libnbaio/include/NBLog.h index 59b77bd55a..785b9c2732 100644 --- a/media/libnbaio/include/NBLog.h +++ b/media/libnbaio/include/NBLog.h @@ -24,6 +24,8 @@ #include <utils/Mutex.h> #include <utils/threads.h> +#include <map> +#include <set> #include <vector> namespace android { @@ -34,12 +36,16 @@ class NBLog { public: +typedef uint64_t log_hash_t; + +// FIXME Everything needed for client (writer API and registration) should be isolated +// from the rest of the implementation. class Writer; class Reader; private: -enum Event { +enum Event : uint8_t { EVENT_RESERVED, EVENT_STRING, // ASCII string, not NUL-terminated // TODO: make timestamp optional @@ -50,7 +56,13 @@ enum Event { EVENT_AUTHOR, // author index (present in merged logs) tracks entry's original log EVENT_START_FMT, // logFormat start event: entry includes format string, following // entries contain format arguments + EVENT_HASH, // unique HASH of log origin, originates from hash of file name + // and line number + EVENT_HISTOGRAM_ENTRY_TS, // single datum for timestamp histogram + EVENT_HISTOGRAM_FLUSH, // show histogram on log EVENT_END_FMT, // end of logFormat argument list + + EVENT_UPPER_BOUND, // to check for invalid events }; @@ -60,91 +72,144 @@ enum Event { // a formatted entry has the following structure: // * START_FMT entry, containing the format string // * TIMESTAMP entry +// * HASH entry // * author entry of the thread that generated it (optional, present in merged log) // * format arg1 // * format arg2 // * ... // * END_FMT entry -class FormatEntry { +// entry representation in memory +struct entry { + const uint8_t type; + const uint8_t length; + const uint8_t data[0]; +}; + +// entry tail representation (after data) +struct ending { + uint8_t length; + uint8_t next[0]; +}; + +// entry iterator +class EntryIterator { public: - // build a Format Entry starting in the given pointer - class iterator; - explicit FormatEntry(const uint8_t *entry); - explicit FormatEntry(const iterator &it); - - // entry representation in memory - struct entry { - const uint8_t type; - const uint8_t length; - const uint8_t data[0]; - }; + EntryIterator(); + explicit EntryIterator(const uint8_t *entry); + EntryIterator(const EntryIterator &other); + + // dereference underlying entry + const entry& operator*() const; + const entry* operator->() const; + // advance to next entry + EntryIterator& operator++(); // ++i + // back to previous entry + EntryIterator& operator--(); // --i + EntryIterator next() const; + EntryIterator prev() const; + bool operator!=(const EntryIterator &other) const; + int operator-(const EntryIterator &other) const; + + bool hasConsistentLength() const; + void copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const; + void copyData(uint8_t *dst) const; + + template<typename T> + inline const T& payload() { + return *reinterpret_cast<const T *>(ptr + offsetof(entry, data)); + } + + inline operator const uint8_t*() const { + return ptr; + } - // entry tail representation (after data) - struct ending { - uint8_t length; - uint8_t next[0]; - }; +private: + const uint8_t *ptr; +}; - // entry iterator - class iterator { - public: - iterator(); - iterator(const uint8_t *entry); - iterator(const iterator &other); - - // dereference underlying entry - const entry& operator*() const; - const entry* operator->() const; - // advance to next entry - iterator& operator++(); // ++i - // back to previous entry - iterator& operator--(); // --i - iterator next() const; - iterator prev() const; - bool operator!=(const iterator &other) const; - int operator-(const iterator &other) const; - - bool hasConsistentLength() const; - void copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const; - void copyData(uint8_t *dst) const; - - template<typename T> - inline const T& payload() { - return *reinterpret_cast<const T *>(ptr + offsetof(entry, data)); - } +class AbstractEntry { +public: - private: - friend class FormatEntry; - const uint8_t *ptr; - }; + // Entry starting in the given pointer + explicit AbstractEntry(const uint8_t *entry); + virtual ~AbstractEntry() {} + + // build concrete entry of appropriate class from pointer + static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr); + + // get format entry timestamp + // TODO consider changing to uint64_t + virtual int64_t timestamp() const = 0; + + // get format entry's unique id + virtual log_hash_t hash() const = 0; + + // entry's author index (-1 if none present) + // a Merger has a vector of Readers, author simply points to the index of the + // Reader that originated the entry + // TODO consider changing to uint32_t + virtual int author() const = 0; + + // copy entry, adding author before timestamp, returns iterator to end of entry + virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst, + int author) const = 0; + +protected: + // copies ordinary entry from src to dst, and returns length of entry + // size_t copyEntry(audio_utils_fifo_writer *dst, const iterator &it); + const uint8_t *mEntry; +}; + +class FormatEntry : public AbstractEntry { +public: + // explicit FormatEntry(const EntryIterator &it); + explicit FormatEntry(const uint8_t *ptr) : AbstractEntry(ptr) {} + virtual ~FormatEntry() {} + + EntryIterator begin() const; // Entry's format string - const char* formatString() const; + const char* formatString() const; // Enrty's format string length - size_t formatStringLength() const; + size_t formatStringLength() const; // Format arguments (excluding format string, timestamp and author) - iterator args() const; + EntryIterator args() const; // get format entry timestamp - timespec timestamp() const; + virtual int64_t timestamp() const override; + + // get format entry's unique id + virtual log_hash_t hash() const override; // entry's author index (-1 if none present) // a Merger has a vector of Readers, author simply points to the index of the // Reader that originated the entry - int author() const; + virtual int author() const override; // copy entry, adding author before timestamp, returns size of original entry - iterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const; + virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst, + int author) const override; - iterator begin() const; +}; + +class HistogramEntry : public AbstractEntry { +public: + explicit HistogramEntry(const uint8_t *ptr) : AbstractEntry(ptr) { + } + virtual ~HistogramEntry() {} + + virtual int64_t timestamp() const override; + + virtual log_hash_t hash() const override; + + virtual int author() const override; + + virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst, + int author) const override; -private: - // copies ordinary entry from src to dst, and returns length of entry - // size_t copyEntry(audio_utils_fifo_writer *dst, const iterator &it); - const uint8_t *mEntry; }; // --------------------------------------------------------------------------- @@ -155,7 +220,8 @@ struct Entry { : mEvent(event), mLength(length), mData(data) { } /*virtual*/ ~Entry() { } - int readAt(size_t offset) const; + // used during writing to format Entry information as follows: [type][length][data ... ][length] + int copyEntryDataAt(size_t offset) const; private: friend class Writer; @@ -165,12 +231,28 @@ private: static const size_t kMaxLength = 255; public: // mEvent, mLength, mData[...], duplicate mLength - static const size_t kOverhead = sizeof(FormatEntry::entry) + sizeof(FormatEntry::ending); + static const size_t kOverhead = sizeof(entry) + sizeof(ending); // endind length of previous entry - static const size_t kPreviousLengthOffset = - sizeof(FormatEntry::ending) + - offsetof(FormatEntry::ending, length); + static const size_t kPreviousLengthOffset = - sizeof(ending) + + offsetof(ending, length); }; +struct HistTsEntry { + log_hash_t hash; + int64_t ts; +}; //TODO __attribute__((packed)); + +struct HistTsEntryWithAuthor { + log_hash_t hash; + int64_t ts; + int author; +}; //TODO __attribute__((packed)); + +struct HistIntEntry { + log_hash_t hash; + int value; +}; //TODO __attribute__((packed)); + // representation of a single log entry in shared memory // byte[0] mEvent // byte[1] mLength @@ -187,7 +269,8 @@ public: static void appendPID(String8 *body, const void *data, size_t length); static void appendTimestamp(String8 *body, const void *data); static size_t fmtEntryLength(const uint8_t *data); - + static String8 bufferDump(const uint8_t *buffer, size_t size); + static String8 bufferDump(const EntryIterator &it); public: // Located in shared memory, must be POD. @@ -244,19 +327,22 @@ public: virtual ~Writer(); + // FIXME needs comments, and some should be private virtual void log(const char *string); virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); virtual void logvf(const char *fmt, va_list ap); virtual void logTimestamp(); - virtual void logTimestamp(const struct timespec &ts); + virtual void logTimestamp(const int64_t ts); virtual void logInteger(const int x); virtual void logFloat(const float x); virtual void logPID(); - virtual void logFormat(const char *fmt, ...); - virtual void logVFormat(const char *fmt, va_list ap); + virtual void logFormat(const char *fmt, log_hash_t hash, ...); + virtual void logVFormat(const char *fmt, log_hash_t hash, va_list ap); virtual void logStart(const char *fmt); virtual void logEnd(); - + virtual void logHash(log_hash_t hash); + virtual void logHistTS(log_hash_t hash); + virtual void logHistFlush(log_hash_t hash); virtual bool isEnabled() const; @@ -269,7 +355,9 @@ public: private: // 0 <= length <= kMaxLength + // writes a single Entry to the FIFO void log(Event event, const void *data, size_t length); + // checks validity of an event before calling log above this one void log(const Entry *entry, bool trusted = false); Shared* const mShared; // raw pointer to shared memory @@ -298,12 +386,13 @@ public: virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); virtual void logvf(const char *fmt, va_list ap); virtual void logTimestamp(); - virtual void logTimestamp(const struct timespec &ts); + virtual void logTimestamp(const int64_t ts); virtual void logInteger(const int x); virtual void logFloat(const float x); virtual void logPID(); virtual void logStart(const char *fmt); virtual void logEnd(); + virtual void logHash(log_hash_t hash); virtual bool isEnabled() const; virtual bool setEnabled(bool enabled); @@ -334,18 +423,17 @@ public: // iterator to beginning of readable segment of snapshot // data between begin and end has valid entries - FormatEntry::iterator begin() { return mBegin; } + EntryIterator begin() { return mBegin; } // iterator to end of readable segment of snapshot - FormatEntry::iterator end() { return mEnd; } - + EntryIterator end() { return mEnd; } private: friend class Reader; uint8_t *mData; size_t mLost; - FormatEntry::iterator mBegin; - FormatEntry::iterator mEnd; + EntryIterator mBegin; + EntryIterator mEnd; }; // Input parameter 'size' is the desired size of the timeline in byte units. @@ -355,15 +443,22 @@ public: virtual ~Reader(); + void alertIfGlitch(const std::vector<int64_t> &samples); + // get snapshot of readers fifo buffer, effectively consuming the buffer std::unique_ptr<Snapshot> getSnapshot(); // dump a particular snapshot of the reader void dump(int fd, size_t indent, Snapshot & snap); - // dump the current content of the reader's buffer + // dump the current content of the reader's buffer (call getSnapshot() and previous dump()) void dump(int fd, size_t indent = 0); bool isIMemory(const sp<IMemory>& iMemory) const; + // if findGlitch is true, log warning when buffer periods caused glitch + void setFindGlitch(bool s); + bool isFindGlitch() const; private: + static const std::set<Event> startingTypes; + static const std::set<Event> endingTypes; /*const*/ Shared* const mShared; // raw pointer to shared memory, actually const but not // declared as const because audio_utils_fifo() constructor sp<IMemory> mIMemory; // ref-counted version, assigned only in constructor @@ -374,19 +469,33 @@ private: audio_utils_fifo_reader * const mFifoReader; // used to read from FIFO, // non-NULL unless constructor fails + // each pair contains a sequence of timestamps (one histogram's worth) + // pair's log_hash_t is the hash of the source code location where the timestamp was taken + // pair's int points to the Reader that originated the entry + std::map<std::pair<log_hash_t, int>, std::vector<int64_t>> mHists; + // TODO: it might be clearer, instead of a direct map from source location to vector of + // timestamps, if we instead first mapped from source location to an object that + // represented that location. And one_of its fields would be a vector of timestamps. + // That would allow us to record other information about the source location beyond timestamps. void dumpLine(const String8& timestamp, String8& body); - FormatEntry::iterator handleFormat(const FormatEntry &fmtEntry, + EntryIterator handleFormat(const FormatEntry &fmtEntry, String8 *timestamp, String8 *body); // dummy method for handling absent author entry - virtual size_t handleAuthor(const FormatEntry &fmtEntry, String8 *body) { return 0; } + virtual void handleAuthor(const AbstractEntry& /*fmtEntry*/, String8* /*body*/) {} + + static void drawHistogram(String8 *body, const std::vector<int64_t> &samples, + bool logScale, int indent = 0, int maxHeight = 10); // Searches for the last entry of type <type> in the range [front, back) // back has to be entry-aligned. Returns nullptr if none enconuntered. - static uint8_t *findLastEntryOfType(uint8_t *front, uint8_t *back, uint8_t type); + static const uint8_t *findLastEntryOfTypes(const uint8_t *front, const uint8_t *back, + const std::set<Event> &types); static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps + + bool findGlitch; // alert if a local buffer period sequence caused an audio glitch }; // Wrapper for a reader with a name. Contains a pointer to the reader and a pointer to the name @@ -417,27 +526,30 @@ public: void addReader(const NamedReader &reader); // TODO add removeReader void merge(); - const std::vector<NamedReader> *getNamedReaders() const; + // FIXME This is returning a reference to a shared variable that needs a lock + const std::vector<NamedReader>& getNamedReaders() const; private: // vector of the readers the merger is supposed to merge from. // every reader reads from a writer's buffer + // FIXME Needs to be protected by a lock std::vector<NamedReader> mNamedReaders; - uint8_t *mBuffer; + + // TODO Need comments on all of these Shared * const mShared; std::unique_ptr<audio_utils_fifo> mFifo; std::unique_ptr<audio_utils_fifo_writer> mFifoWriter; - - static struct timespec getTimestamp(const uint8_t *data); }; class MergeReader : public Reader { public: MergeReader(const void *shared, size_t size, Merger &merger); private: - const std::vector<NamedReader> *mNamedReaders; + // FIXME Needs to be protected by a lock, + // because even though our use of it is read-only there may be asynchronous updates + const std::vector<NamedReader>& mNamedReaders; // handle author entry by looking up the author's name and appending it to the body // returns number of bytes read from fmtEntry - size_t handleAuthor(const FormatEntry &fmtEntry, String8 *body); + void handleAuthor(const AbstractEntry &fmtEntry, String8 *body); }; // MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot: @@ -479,6 +591,15 @@ private: }; // class NBLog +// TODO put somewhere else +static inline int64_t get_monotonic_ns() { + timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { + return (uint64_t) ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; + } + return 0; // should not happen. +} + } // namespace android #endif // ANDROID_MEDIA_NBLOG_H diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index d187ecbc54..01f09be492 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -960,7 +960,9 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) { return NO_MEMORY; } hidlMem = mapMemory(hidlMemToken); - + if (hidlMem == nullptr) { + return NO_MEMORY; + } err = mOMXNode->useBuffer( portIndex, hidlMemToken, &info.mBufferID); } else { @@ -1008,6 +1010,9 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) { return NO_MEMORY; } hidlMem = mapMemory(hidlMemToken); + if (hidlMem == nullptr) { + return NO_MEMORY; + } info.mData = new SharedMemoryBuffer(format, hidlMem); info.mMemRef = hidlMem; } else { @@ -7244,6 +7249,16 @@ status_t ACodec::setParameters(const sp<AMessage> ¶ms) { ALOGE("Failed to set parameter 'stop-time-us' (err %d)", err); return err; } + + int64_t stopTimeOffsetUs; + err = statusFromBinderStatus( + mGraphicBufferSource->getStopTimeOffsetUs(&stopTimeOffsetUs)); + + if (err != OK) { + ALOGE("Failed to get stop time offset (err %d)", err); + return err; + } + mInputFormat->setInt64("android._stop-time-offset-us", stopTimeOffsetUs); } int32_t dummy; diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp index 3d9341b08e..6cc1ace86b 100644 --- a/media/libstagefright/Android.bp +++ b/media/libstagefright/Android.bp @@ -1 +1,176 @@ -subdirs = ["foundation"] +cc_library_headers { + name: "libstagefright_headers", + export_include_dirs: ["include"], + vendor_available: true, +} + +cc_library_shared { + name: "libstagefright", + + srcs: [ + "ACodec.cpp", + "ACodecBufferChannel.cpp", + "AACExtractor.cpp", + "AACWriter.cpp", + "AMRExtractor.cpp", + "AMRWriter.cpp", + "AudioPlayer.cpp", + "AudioSource.cpp", + "BufferImpl.cpp", + "CallbackDataSource.cpp", + "CameraSource.cpp", + "CameraSourceTimeLapse.cpp", + "DataConverter.cpp", + "DataSource.cpp", + "DataURISource.cpp", + "ESDS.cpp", + "FileSource.cpp", + "FLACExtractor.cpp", + "FrameRenderTracker.cpp", + "HTTPBase.cpp", + "HevcUtils.cpp", + "JPEGSource.cpp", + "MP3Extractor.cpp", + "MPEG2TSWriter.cpp", + "MPEG4Extractor.cpp", + "MPEG4Writer.cpp", + "MediaAdapter.cpp", + "MediaClock.cpp", + "MediaCodec.cpp", + "MediaCodecList.cpp", + "MediaCodecListOverrides.cpp", + "MediaCodecSource.cpp", + "MediaExtractor.cpp", + "MediaSync.cpp", + "MidiExtractor.cpp", + "http/MediaHTTP.cpp", + "MediaMuxer.cpp", + "MediaSource.cpp", + "NuCachedSource2.cpp", + "NuMediaExtractor.cpp", + "OMXClient.cpp", + "OggExtractor.cpp", + "SampleIterator.cpp", + "SampleTable.cpp", + "SimpleDecodingSource.cpp", + "SkipCutBuffer.cpp", + "StagefrightMediaScanner.cpp", + "StagefrightMetadataRetriever.cpp", + "SurfaceMediaSource.cpp", + "SurfaceUtils.cpp", + "ThrottledSource.cpp", + "Utils.cpp", + "VBRISeeker.cpp", + "VideoFrameScheduler.cpp", + "WAVExtractor.cpp", + "XINGSeeker.cpp", + "avc_utils.cpp", + ], + + include_dirs: [ + "frameworks/native/include/media/openmax", + "frameworks/native/include/media/hardware", + ], + + shared_libs: [ + "libaudioutils", + "libbinder", + "libcamera_client", + "libcrypto", + "libcutils", + "libdl", + "libdrmframework", + "libexpat", + "libgui", + "liblog", + "libmedia", + "libaudioclient", + "libmediametrics", + "libmediautils", + "libnetd_client", + "libsonivox", + "libui", + "libutils", + "libvorbisidec", + "libmediadrm", + "libnativewindow", + + "libmedia_helper", + "libstagefright_flacdec", + "libstagefright_foundation", + "libdl", + "libRScpp", + "libhidlbase", + "libhidlmemory", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "android.hardware.media.omx@1.0", + "libstagefright_xmlparser@1.0", + ], + + static_libs: [ + "libstagefright_color_conversion", + "libyuv_static", + "libstagefright_aacenc", + "libstagefright_matroska", + "libstagefright_mediafilter", + "libstagefright_omx_utils", + "libstagefright_webm", + "libstagefright_timedtext", + "libvpx", + "libwebm", + "libstagefright_mpeg2ts", + "libstagefright_id3", + "libFLAC", + ], + + export_shared_lib_headers: ["libmedia"], + export_include_dirs: [ + ".", + "include", + ], + + cflags: [ + "-Wno-multichar", + "-Werror", + "-Wno-error=deprecated-declarations", + "-Wall", + ], + + product_variables: { + debuggable: { + // enable experiments only in userdebug and eng builds + cflags: ["-DENABLE_STAGEFRIGHT_EXPERIMENTS"], + }, + }, + + sanitize: { + cfi: true, + misc_undefined: [ + "unsigned-integer-overflow", + "signed-integer-overflow", + ], + diag: { + cfi: true, + }, + }, +} + +subdirs = [ + "codecs/*", + "colorconversion", + "filters", + "flac/dec", + "foundation", + "http", + "httplive", + "id3", + "matroska", + "mpeg2ts", + "omx", + "rtsp", + "tests", + "timedtext", + "webm", + "wifi-display", +] diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk deleted file mode 100644 index 372b11a94f..0000000000 --- a/media/libstagefright/Android.mk +++ /dev/null @@ -1,145 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - - -LOCAL_SRC_FILES:= \ - ACodec.cpp \ - ACodecBufferChannel.cpp \ - AACExtractor.cpp \ - AACWriter.cpp \ - AMRExtractor.cpp \ - AMRWriter.cpp \ - AudioPlayer.cpp \ - AudioSource.cpp \ - BufferImpl.cpp \ - CallbackDataSource.cpp \ - CameraSource.cpp \ - CameraSourceTimeLapse.cpp \ - DataConverter.cpp \ - DataSource.cpp \ - DataURISource.cpp \ - ESDS.cpp \ - FileSource.cpp \ - FLACExtractor.cpp \ - FrameRenderTracker.cpp \ - HTTPBase.cpp \ - HevcUtils.cpp \ - JPEGSource.cpp \ - MP3Extractor.cpp \ - MPEG2TSWriter.cpp \ - MPEG4Extractor.cpp \ - MPEG4Writer.cpp \ - MediaAdapter.cpp \ - MediaClock.cpp \ - MediaCodec.cpp \ - MediaCodecList.cpp \ - MediaCodecListOverrides.cpp \ - MediaCodecSource.cpp \ - MediaExtractor.cpp \ - MediaSync.cpp \ - MidiExtractor.cpp \ - http/MediaHTTP.cpp \ - MediaMuxer.cpp \ - MediaSource.cpp \ - NuCachedSource2.cpp \ - NuMediaExtractor.cpp \ - OMXClient.cpp \ - OggExtractor.cpp \ - SampleIterator.cpp \ - SampleTable.cpp \ - SimpleDecodingSource.cpp \ - SkipCutBuffer.cpp \ - StagefrightMediaScanner.cpp \ - StagefrightMetadataRetriever.cpp \ - SurfaceMediaSource.cpp \ - SurfaceUtils.cpp \ - ThrottledSource.cpp \ - Utils.cpp \ - VBRISeeker.cpp \ - VideoFrameScheduler.cpp \ - WAVExtractor.cpp \ - XINGSeeker.cpp \ - avc_utils.cpp \ - -LOCAL_C_INCLUDES:= \ - $(TOP)/frameworks/av/include/media/ \ - $(TOP)/frameworks/av/include/media/stagefright/timedtext \ - $(TOP)/frameworks/native/include/media/hardware \ - $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/external/flac/include \ - $(TOP)/external/tremolo \ - $(TOP)/external/libvpx/libwebm \ - $(TOP)/external/icu/icu4c/source/common \ - $(TOP)/external/icu/icu4c/source/i18n \ - $(TOP)/system/netd/include \ - $(call include-path-for, audio-utils) - -LOCAL_SHARED_LIBRARIES := \ - libaudioutils \ - libbinder \ - libcamera_client \ - libcrypto \ - libcutils \ - libdl \ - libdrmframework \ - libexpat \ - libgui \ - liblog \ - libmedia \ - libaudioclient \ - libmediametrics \ - libmediautils \ - libnetd_client \ - libsonivox \ - libstagefright_omx \ - libui \ - libutils \ - libvorbisidec \ - libmediadrm \ - libnativewindow \ - -LOCAL_STATIC_LIBRARIES := \ - libstagefright_color_conversion \ - libyuv_static \ - libstagefright_aacenc \ - libstagefright_matroska \ - libstagefright_mediafilter \ - libstagefright_webm \ - libstagefright_timedtext \ - libvpx \ - libwebm \ - libstagefright_mpeg2ts \ - libstagefright_id3 \ - libFLAC \ - -LOCAL_SHARED_LIBRARIES += \ - libmedia_helper \ - libstagefright_foundation \ - libdl \ - libRScpp \ - libhidlbase \ - libhidlmemory \ - android.hidl.allocator@1.0 \ - android.hidl.memory@1.0 \ - android.hardware.media.omx@1.0 \ - libstagefright_xmlparser@1.0 \ - -LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libmedia - -LOCAL_CFLAGS += -Wno-multichar -Werror -Wno-error=deprecated-declarations -Wall - -# enable experiments only in userdebug and eng builds -ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) -LOCAL_CFLAGS += -DENABLE_STAGEFRIGHT_EXPERIMENTS -endif - -LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_MODULE:= libstagefright - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index 4ccd2d0b78..f2b1f10f22 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -58,13 +58,16 @@ AudioSource::AudioSource( mOutSampleRate(outSampleRate > 0 ? outSampleRate : sampleRate), mTrackMaxAmplitude(false), mStartTimeUs(0), + mStopSystemTimeUs(-1), + mLastFrameTimestampUs(0), mMaxAmplitude(0), mPrevSampleTimeUs(0), mInitialReadTimeUs(0), mNumFramesReceived(0), mNumFramesSkipped(0), mNumFramesLost(0), - mNumClientOwnedBuffers(0) { + mNumClientOwnedBuffers(0), + mNoMoreFramesToRead(false) { ALOGV("sampleRate: %u, outSampleRate: %u, channelCount: %u", sampleRate, outSampleRate, channelCount); CHECK(channelCount == 1 || channelCount == 2); @@ -175,6 +178,8 @@ status_t AudioSource::reset() { } mStarted = false; + mStopSystemTimeUs = -1; + mNoMoreFramesToRead = false; mFrameAvailableCondition.signal(); mRecord->stop(); @@ -243,6 +248,9 @@ status_t AudioSource::read( while (mStarted && mBuffersReceived.empty()) { mFrameAvailableCondition.wait(mLock); + if (mNoMoreFramesToRead) { + return OK; + } } if (!mStarted) { return OK; @@ -286,6 +294,21 @@ status_t AudioSource::read( return OK; } +status_t AudioSource::setStopTimeUs(int64_t stopTimeUs) { + Mutex::Autolock autoLock(mLock); + ALOGV("Set stoptime: %lld us", (long long)stopTimeUs); + + if (stopTimeUs < -1) { + ALOGE("Invalid stop time %lld us", (long long)stopTimeUs); + return BAD_VALUE; + } else if (stopTimeUs == -1) { + ALOGI("reset stopTime to be -1"); + } + + mStopSystemTimeUs = stopTimeUs; + return OK; +} + void AudioSource::signalBufferReturned(MediaBuffer *buffer) { ALOGV("signalBufferReturned: %p", buffer->data()); Mutex::Autolock autoLock(mLock); @@ -338,6 +361,14 @@ status_t AudioSource::dataCallback(const AudioRecord::Buffer& audioBuffer) { return OK; } + if (mStopSystemTimeUs != -1 && timeUs >= mStopSystemTimeUs) { + ALOGV("Drop Audio frame at %lld stop time: %lld us", + (long long)timeUs, (long long)mStopSystemTimeUs); + mNoMoreFramesToRead = true; + mFrameAvailableCondition.signal(); + return OK; + } + if (mNumFramesReceived == 0 && mPrevSampleTimeUs == 0) { mInitialReadTimeUs = timeUs; // Initial delay @@ -346,6 +377,7 @@ status_t AudioSource::dataCallback(const AudioRecord::Buffer& audioBuffer) { } mPrevSampleTimeUs = mStartTimeUs; } + mLastFrameTimestampUs = timeUs; size_t numLostBytes = 0; if (mNumFramesReceived > 0) { // Ignore earlier frame lost diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index 1cd7693383..6ed0d0eb43 100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -220,6 +220,7 @@ CameraSource::CameraSource( mNumFramesEncoded(0), mTimeBetweenFrameCaptureUs(0), mFirstFrameTimeUs(0), + mStopSystemTimeUs(-1), mNumFramesDropped(0), mNumGlitches(0), mGlitchDurationThresholdUs(200000), @@ -879,6 +880,7 @@ status_t CameraSource::reset() { { Mutex::Autolock autoLock(mLock); mStarted = false; + mStopSystemTimeUs = -1; mFrameAvailableCondition.signal(); int64_t token; @@ -1103,12 +1105,33 @@ status_t CameraSource::read( return OK; } +status_t CameraSource::setStopTimeUs(int64_t stopTimeUs) { + Mutex::Autolock autoLock(mLock); + ALOGV("Set stoptime: %lld us", (long long)stopTimeUs); + + if (stopTimeUs < -1) { + ALOGE("Invalid stop time %lld us", (long long)stopTimeUs); + return BAD_VALUE; + } else if (stopTimeUs == -1) { + ALOGI("reset stopTime to be -1"); + } + + mStopSystemTimeUs = stopTimeUs; + return OK; +} + bool CameraSource::shouldSkipFrameLocked(int64_t timestampUs) { if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) { ALOGV("Drop frame at %lld/%lld us", (long long)timestampUs, (long long)mStartTimeUs); return true; } + if (mStopSystemTimeUs != -1 && timestampUs >= mStopSystemTimeUs) { + ALOGV("Drop Camera frame at %lld stop time: %lld us", + (long long)timestampUs, (long long)mStopSystemTimeUs); + return true; + } + // May need to skip frame or modify timestamp. Currently implemented // by the subclass CameraSourceTimeLapse. if (skipCurrentFrame(timestampUs)) { diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp index b83b0a06c1..03ea959868 100644 --- a/media/libstagefright/MPEG2TSWriter.cpp +++ b/media/libstagefright/MPEG2TSWriter.cpp @@ -710,7 +710,7 @@ void MPEG2TSWriter::writeProgramAssociationTable() { uint32_t crc = htonl(crc32(&buffer->data()[5], 12)); memcpy(&buffer->data()[17], &crc, sizeof(crc)); - CHECK_EQ(internalWrite(buffer->data(), buffer->size()), buffer->size()); + CHECK_EQ(internalWrite(buffer->data(), buffer->size()), (ssize_t)buffer->size()); } void MPEG2TSWriter::writeProgramMap() { @@ -786,7 +786,7 @@ void MPEG2TSWriter::writeProgramMap() { uint32_t crc = htonl(crc32(&buffer->data()[5], 12+mSources.size()*5)); memcpy(&buffer->data()[17+mSources.size()*5], &crc, sizeof(crc)); - CHECK_EQ(internalWrite(buffer->data(), buffer->size()), buffer->size()); + CHECK_EQ(internalWrite(buffer->data(), buffer->size()), (ssize_t)buffer->size()); } void MPEG2TSWriter::writeAccessUnit( @@ -891,7 +891,7 @@ void MPEG2TSWriter::writeAccessUnit( memcpy(ptr, accessUnit->data(), copy); - CHECK_EQ(internalWrite(buffer->data(), buffer->size()), buffer->size()); + CHECK_EQ(internalWrite(buffer->data(), buffer->size()), (ssize_t)buffer->size()); size_t offset = copy; while (offset < accessUnit->size()) { @@ -937,7 +937,7 @@ void MPEG2TSWriter::writeAccessUnit( memcpy(ptr, accessUnit->data() + offset, copy); CHECK_EQ(internalWrite(buffer->data(), buffer->size()), - buffer->size()); + (ssize_t)buffer->size()); offset += copy; } diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index e4306a51f6..87abb6ae4d 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -5207,6 +5207,7 @@ static bool isCompatibleBrand(uint32_t fourcc) { FOURCC('3', 'g', 'p', '4'), FOURCC('m', 'p', '4', '1'), FOURCC('m', 'p', '4', '2'), + FOURCC('d', 'a', 's', 'h'), // Won't promise that the following file types can be played. // Just give these file types a chance. diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 223b16668a..93d4f57c41 100755..100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -112,6 +112,7 @@ public: int64_t getDurationUs() const; int64_t getEstimatedTrackSizeBytes() const; void writeTrackHeader(bool use32BitOffset = true); + int64_t getMinCttsOffsetTimeUs(); void bufferChunk(int64_t timestampUs); bool isAvc() const { return mIsAvc; } bool isHevc() const { return mIsHevc; } @@ -140,7 +141,7 @@ private: mTotalNumTableEntries(0), mNumValuesInCurrEntry(0), mCurrTableEntriesElement(NULL) { - CHECK_GT(mElementCapacity, 0); + CHECK_GT(mElementCapacity, 0u); // Ensure no integer overflow on allocation in add(). CHECK_LT(ENTRY_SIZE, UINT32_MAX / mElementCapacity); } @@ -168,7 +169,7 @@ private: --iterations; } CHECK(it != mTableEntryList.end()); - CHECK_EQ(iterations, 0); + CHECK_EQ(iterations, 0u); (*it)[(pos % (mElementCapacity * ENTRY_SIZE))] = value; } @@ -189,7 +190,7 @@ private: --iterations; } CHECK(it != mTableEntryList.end()); - CHECK_EQ(iterations, 0); + CHECK_EQ(iterations, 0u); value = (*it)[(pos % (mElementCapacity * ENTRY_SIZE))]; return true; @@ -237,12 +238,12 @@ private: // 2. followed by the values in the table enties in order // @arg writer the writer to actual write to the storage void write(MPEG4Writer *writer) const { - CHECK_EQ(mNumValuesInCurrEntry % ENTRY_SIZE, 0); + CHECK_EQ(mNumValuesInCurrEntry % ENTRY_SIZE, 0u); uint32_t nEntries = mTotalNumTableEntries; writer->writeInt32(nEntries); for (typename List<TYPE *>::iterator it = mTableEntryList.begin(); it != mTableEntryList.end(); ++it) { - CHECK_GT(nEntries, 0); + CHECK_GT(nEntries, 0u); if (nEntries >= mElementCapacity) { writer->write(*it, sizeof(TYPE) * ENTRY_SIZE, mElementCapacity); nEntries -= mElementCapacity; @@ -307,10 +308,17 @@ private: ListTableEntries<uint32_t, 2> *mCttsTableEntries; int64_t mMinCttsOffsetTimeUs; - int64_t mMaxCttsOffsetTimeUs; + int64_t mMinCttsOffsetTicks; + int64_t mMaxCttsOffsetTicks; + + // Save the last 10 frames' timestamp and frame type for debug. + struct TimestampDebugHelperEntry { + int64_t pts; + int64_t dts; + std::string frameType; + }; - // Save the last 10 frames' timestamp for debug. - std::list<std::pair<int64_t, int64_t>> mTimestampDebugHelper; + std::list<TimestampDebugHelperEntry> mTimestampDebugHelper; // Sequence parameter set or picture parameter set struct AVCParamSet { @@ -343,6 +351,7 @@ private: void dumpTimeStamps(); + int64_t getStartTimeOffsetTimeUs() const; int32_t getStartTimeOffsetScaledTime() const; static void *ThreadWrapper(void *me); @@ -1133,9 +1142,22 @@ void MPEG4Writer::writeMoovBox(int64_t durationUs) { writeUdtaBox(); } writeMetaBox(); - int32_t id = 1; + // Loop through all the tracks to get the global time offset if there is + // any ctts table appears in a video track. + int64_t minCttsOffsetTimeUs = kMaxCttsOffsetTimeUs; for (List<Track *>::iterator it = mTracks.begin(); - it != mTracks.end(); ++it, ++id) { + it != mTracks.end(); ++it) { + minCttsOffsetTimeUs = + std::min(minCttsOffsetTimeUs, (*it)->getMinCttsOffsetTimeUs()); + } + ALOGI("Ajust the moov start time from %lld us -> %lld us", + (long long)mStartTimestampUs, + (long long)(mStartTimestampUs + minCttsOffsetTimeUs - kMaxCttsOffsetTimeUs)); + // Adjust the global start time. + mStartTimestampUs += minCttsOffsetTimeUs - kMaxCttsOffsetTimeUs; + + for (List<Track *>::iterator it = mTracks.begin(); + it != mTracks.end(); ++it) { (*it)->writeTrackHeader(mUse32BitOffset); } endBox(); // moov @@ -1280,7 +1302,7 @@ off64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { mOffset += length + 4; } else { - CHECK_LT(length, 65536); + CHECK_LT(length, 65536u); uint8_t x = length >> 8; ::write(mFd, &x, 1); @@ -1340,7 +1362,7 @@ void MPEG4Writer::beginBox(uint32_t id) { } void MPEG4Writer::beginBox(const char *fourcc) { - CHECK_EQ(strlen(fourcc), 4); + CHECK_EQ(strlen(fourcc), 4u); mBoxes.push_back(mWriteMoovBoxToMemory? mMoovBoxBufferOffset: mOffset); @@ -1391,7 +1413,7 @@ void MPEG4Writer::writeCString(const char *s) { } void MPEG4Writer::writeFourcc(const char *s) { - CHECK_EQ(strlen(s), 4); + CHECK_EQ(strlen(s), 4u); write(s, 1, 4); } @@ -1625,10 +1647,14 @@ MPEG4Writer::Track::Track( mStssTableEntries(new ListTableEntries<uint32_t, 1>(1000)), mSttsTableEntries(new ListTableEntries<uint32_t, 2>(1000)), mCttsTableEntries(new ListTableEntries<uint32_t, 2>(1000)), + mMinCttsOffsetTimeUs(0), + mMinCttsOffsetTicks(0), + mMaxCttsOffsetTicks(0), mCodecSpecificData(NULL), mCodecSpecificDataSize(0), mGotAllCodecSpecificData(false), mReachedEOS(false), + mStartTimestampUs(-1), mRotation(0) { getCodecSpecificDataFromInputFormatIfPossible(); @@ -2135,13 +2161,17 @@ status_t MPEG4Writer::Track::stop(bool stopSource) { if (mDone) { return OK; } - mDone = true; + if (stopSource) { ALOGD("%s track source stopping", getTrackType()); mSource->stop(); ALOGD("%s track source stopped", getTrackType()); } + // Set mDone to be true after sucessfully stop mSource as mSource may be still outputting + // buffers to the writer. + mDone = true; + void *dummy; pthread_join(mThread, &dummy); status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy)); @@ -2521,12 +2551,12 @@ void MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) { } void MPEG4Writer::Track::dumpTimeStamps() { - ALOGE("Dumping %s track's last 10 frames timestamp ", getTrackType()); + ALOGE("Dumping %s track's last 10 frames timestamp and frame type ", getTrackType()); std::string timeStampString; - for (std::list<std::pair<int64_t, int64_t>>::iterator num = mTimestampDebugHelper.begin(); - num != mTimestampDebugHelper.end(); ++num) { - timeStampString += "(" + std::to_string(num->first)+ - "us, " + std::to_string(num->second) + "us) "; + for (std::list<TimestampDebugHelperEntry>::iterator entry = mTimestampDebugHelper.begin(); + entry != mTimestampDebugHelper.end(); ++entry) { + timeStampString += "(" + std::to_string(entry->pts)+ + "us, " + std::to_string(entry->dts) + "us " + entry->frameType + ") "; } ALOGE("%s", timeStampString.c_str()); } @@ -2736,9 +2766,9 @@ status_t MPEG4Writer::Track::threadEntry() { previousPausedDurationUs += pausedDurationUs - lastDurationUs; mResumed = false; } - std::pair<int64_t, int64_t> timestampPair; + TimestampDebugHelperEntry timestampDebugEntry; timestampUs -= previousPausedDurationUs; - timestampPair.first = timestampUs; + timestampDebugEntry.pts = timestampUs; if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) { copy->release(); mSource->stop(); @@ -2768,6 +2798,14 @@ status_t MPEG4Writer::Track::threadEntry() { } mLastDecodingTimeUs = decodingTimeUs; + timestampDebugEntry.dts = decodingTimeUs; + timestampDebugEntry.frameType = isSync ? "Key frame" : "Non-Key frame"; + // Insert the timestamp into the mTimestampDebugHelper + if (mTimestampDebugHelper.size() >= kTimestampDebugCount) { + mTimestampDebugHelper.pop_front(); + } + mTimestampDebugHelper.push_back(timestampDebugEntry); + cttsOffsetTimeUs = timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs; if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) { @@ -2810,16 +2848,16 @@ status_t MPEG4Writer::Track::threadEntry() { // Update ctts time offset range if (mStszTableEntries->count() == 0) { - mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks; - mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks; + mMinCttsOffsetTicks = currCttsOffsetTimeTicks; + mMaxCttsOffsetTicks = currCttsOffsetTimeTicks; } else { - if (currCttsOffsetTimeTicks > mMaxCttsOffsetTimeUs) { - mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks; - } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTimeUs) { - mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks; + if (currCttsOffsetTimeTicks > mMaxCttsOffsetTicks) { + mMaxCttsOffsetTicks = currCttsOffsetTimeTicks; + } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTicks) { + mMinCttsOffsetTicks = currCttsOffsetTimeTicks; + mMinCttsOffsetTimeUs = cttsOffsetTimeUs; } } - } if (mOwner->isRealTimeRecording()) { @@ -2897,12 +2935,6 @@ status_t MPEG4Writer::Track::threadEntry() { lastDurationUs = timestampUs - lastTimestampUs; lastDurationTicks = currDurationTicks; lastTimestampUs = timestampUs; - timestampPair.second = timestampUs; - // Insert the timestamp into the mTimestampDebugHelper - if (mTimestampDebugHelper.size() >= kTimestampDebugCount) { - mTimestampDebugHelper.pop_front(); - } - mTimestampDebugHelper.push_back(timestampPair); if (isSync != 0) { addOneStssTableEntry(mStszTableEntries->count()); @@ -3160,7 +3192,7 @@ void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) { } int64_t MPEG4Writer::Track::getDurationUs() const { - return mTrackDurationUs; + return mTrackDurationUs + getStartTimeOffsetTimeUs(); } int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { @@ -3215,6 +3247,16 @@ void MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) { mOwner->endBox(); // trak } +int64_t MPEG4Writer::Track::getMinCttsOffsetTimeUs() { + // For video tracks with ctts table, this should return the minimum ctts + // offset in the table. For non-video tracks or video tracks without ctts + // table, this will return kMaxCttsOffsetTimeUs. + if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) { + return kMaxCttsOffsetTimeUs; + } + return mMinCttsOffsetTimeUs; +} + void MPEG4Writer::Track::writeStblBox(bool use32BitOffset) { mOwner->beginBox("stbl"); mOwner->beginBox("stsd"); @@ -3365,10 +3407,10 @@ void MPEG4Writer::Track::writeAudioFourCCBox() { void MPEG4Writer::Track::writeMp4aEsdsBox() { mOwner->beginBox("esds"); CHECK(mCodecSpecificData); - CHECK_GT(mCodecSpecificDataSize, 0); + CHECK_GT(mCodecSpecificDataSize, 0u); // Make sure all sizes encode to a single byte. - CHECK_LT(mCodecSpecificDataSize + 23, 128); + CHECK_LT(mCodecSpecificDataSize + 23, 128u); mOwner->writeInt32(0); // version=0, flags=0 mOwner->writeInt8(0x03); // ES_DescrTag @@ -3407,10 +3449,10 @@ void MPEG4Writer::Track::writeMp4aEsdsBox() { void MPEG4Writer::Track::writeMp4vEsdsBox() { CHECK(mCodecSpecificData); - CHECK_GT(mCodecSpecificDataSize, 0); + CHECK_GT(mCodecSpecificDataSize, 0u); // Make sure all sizes encode to a single byte. - CHECK_LT(23 + mCodecSpecificDataSize, 128); + CHECK_LT(23 + mCodecSpecificDataSize, 128u); mOwner->beginBox("esds"); @@ -3602,7 +3644,7 @@ void MPEG4Writer::Track::writeDinfBox() { void MPEG4Writer::Track::writeAvccBox() { CHECK(mCodecSpecificData); - CHECK_GE(mCodecSpecificDataSize, 5); + CHECK_GE(mCodecSpecificDataSize, 5u); // Patch avcc's lengthSize field to match the number // of bytes we use to indicate the size of a nal unit. @@ -3616,7 +3658,7 @@ void MPEG4Writer::Track::writeAvccBox() { void MPEG4Writer::Track::writeHvccBox() { CHECK(mCodecSpecificData); - CHECK_GE(mCodecSpecificDataSize, 5); + CHECK_GE(mCodecSpecificDataSize, 5u); // Patch avcc's lengthSize field to match the number // of bytes we use to indicate the size of a nal unit. @@ -3644,30 +3686,41 @@ void MPEG4Writer::Track::writePaspBox() { mOwner->endBox(); // pasp } -int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const { +int64_t MPEG4Writer::Track::getStartTimeOffsetTimeUs() const { int64_t trackStartTimeOffsetUs = 0; int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); - if (mStartTimestampUs != moovStartTimeUs) { + if (mStartTimestampUs != -1 && mStartTimestampUs != moovStartTimeUs) { CHECK_GT(mStartTimestampUs, moovStartTimeUs); trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; } - return (trackStartTimeOffsetUs * mTimeScale + 500000LL) / 1000000LL; + return trackStartTimeOffsetUs; +} + +int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const { + return (getStartTimeOffsetTimeUs() * mTimeScale + 500000LL) / 1000000LL; } void MPEG4Writer::Track::writeSttsBox() { mOwner->beginBox("stts"); mOwner->writeInt32(0); // version=0, flags=0 - uint32_t duration; - CHECK(mSttsTableEntries->get(duration, 1)); - duration = htonl(duration); // Back to host byte order - mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1); + if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) { + // For non-vdeio tracks or video tracks without ctts table, + // adjust duration of first sample for tracks to account for + // first sample not starting at the media start time. + // TODO: consider signaling this using some offset + // as this is not quite correct. + uint32_t duration; + CHECK(mSttsTableEntries->get(duration, 1)); + duration = htonl(duration); // Back to host byte order + mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1); + } mSttsTableEntries->write(mOwner); mOwner->endBox(); // stts } void MPEG4Writer::Track::writeCttsBox() { // There is no B frame at all - if (mMinCttsOffsetTimeUs == mMaxCttsOffsetTimeUs) { + if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) { return; } @@ -3677,11 +3730,12 @@ void MPEG4Writer::Track::writeCttsBox() { } ALOGV("ctts box has %d entries with range [%" PRId64 ", %" PRId64 "]", - mCttsTableEntries->count(), mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs); + mCttsTableEntries->count(), mMinCttsOffsetTicks, mMaxCttsOffsetTicks); mOwner->beginBox("ctts"); mOwner->writeInt32(0); // version=0, flags=0 - int64_t delta = mMinCttsOffsetTimeUs - getStartTimeOffsetScaledTime(); + int64_t deltaTimeUs = kMaxCttsOffsetTimeUs - getStartTimeOffsetTimeUs(); + int64_t delta = (deltaTimeUs * mTimeScale + 500000LL) / 1000000LL; mCttsTableEntries->adjustEntries([delta](size_t /* ix */, uint32_t (&value)[2]) { // entries are <count, ctts> pairs; adjust only ctts uint32_t duration = htonl(value[1]); // back to host byte order diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp index bb20850824..d808e5bb46 100644 --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -44,6 +44,9 @@ const int32_t kDefaultHwVideoEncoderFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEF const int32_t kDefaultVideoEncoderDataSpace = HAL_DATASPACE_V0_BT709; const int kStopTimeoutUs = 300000; // allow 1 sec for shutting down encoder +// allow maximum 1 sec for stop time offset. This limits the the delay in the +// input source. +const int kMaxStopTimeOffsetUs = 1000000; struct MediaCodecSource::Puller : public AHandler { explicit Puller(const sp<MediaSource> &source); @@ -54,7 +57,7 @@ struct MediaCodecSource::Puller : public AHandler { void stopSource(); void pause(); void resume(); - + status_t setStopTimeUs(int64_t stopTimeUs); bool readBuffer(MediaBuffer **buffer); protected: @@ -66,6 +69,7 @@ private: kWhatStart = 'msta', kWhatStop, kWhatPull, + kWhatSetStopTimeUs, }; sp<MediaSource> mSource; @@ -161,6 +165,12 @@ status_t MediaCodecSource::Puller::postSynchronouslyAndReturnError( return err; } +status_t MediaCodecSource::Puller::setStopTimeUs(int64_t stopTimeUs) { + sp<AMessage> msg = new AMessage(kWhatSetStopTimeUs, this); + msg->setInt64("stop-time-us", stopTimeUs); + return postSynchronouslyAndReturnError(msg); +} + status_t MediaCodecSource::Puller::start(const sp<MetaData> &meta, const sp<AMessage> ¬ify) { ALOGV("puller (%s) start", mIsAudio ? "audio" : "video"); mLooper->start( @@ -250,6 +260,20 @@ void MediaCodecSource::Puller::onMessageReceived(const sp<AMessage> &msg) { break; } + case kWhatSetStopTimeUs: + { + sp<AReplyToken> replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + int64_t stopTimeUs; + CHECK(msg->findInt64("stop-time-us", &stopTimeUs)); + status_t err = mSource->setStopTimeUs(stopTimeUs); + + sp<AMessage> response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + case kWhatStop: { mSource->stop(); @@ -364,11 +388,8 @@ status_t MediaCodecSource::stop() { } -status_t MediaCodecSource::setStopStimeUs(int64_t stopTimeUs) { - if (!(mFlags & FLAG_USE_SURFACE_INPUT)) { - return OK; - } - sp<AMessage> msg = new AMessage(kWhatSetStopTimeOffset, mReflector); +status_t MediaCodecSource::setStopTimeUs(int64_t stopTimeUs) { + sp<AMessage> msg = new AMessage(kWhatSetStopTimeUs, mReflector); msg->setInt64("stop-time-us", stopTimeUs); return postSynchronouslyAndReturnError(msg); } @@ -986,12 +1007,29 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) { mStopping = true; + int64_t timeoutUs = kStopTimeoutUs; // if using surface, signal source EOS and wait for EOS to come back. // otherwise, stop puller (which also clears the input buffer queue) // and wait for the EOS message. We cannot call source->stop() because // the encoder may still be processing input buffers. if (mFlags & FLAG_USE_SURFACE_INPUT) { mEncoder->signalEndOfInputStream(); + // Increase the timeout if there is delay in the GraphicBufferSource + sp<AMessage> inputFormat; + int64_t stopTimeOffsetUs; + if (mEncoder->getInputFormat(&inputFormat) == OK && + inputFormat->findInt64("android._stop-time-offset-us", &stopTimeOffsetUs) && + stopTimeOffsetUs > 0) { + if (stopTimeOffsetUs > kMaxStopTimeOffsetUs) { + ALOGW("Source stopTimeOffsetUs %lld too large, limit at %lld us", + (long long)stopTimeOffsetUs, (long long)kMaxStopTimeOffsetUs); + stopTimeOffsetUs = kMaxStopTimeOffsetUs; + } + timeoutUs += stopTimeOffsetUs; + } else { + // Use kMaxStopTimeOffsetUs if stop time offset is not provided by input source + timeoutUs = kMaxStopTimeOffsetUs; + } } else { mPuller->stop(); } @@ -999,7 +1037,7 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) { // complete stop even if encoder/puller stalled sp<AMessage> timeoutMsg = new AMessage(kWhatStopStalled, mReflector); timeoutMsg->setInt32("generation", mGeneration); - timeoutMsg->post(kStopTimeoutUs); + timeoutMsg->post(timeoutUs); break; } @@ -1055,7 +1093,7 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) { response->postReply(replyID); break; } - case kWhatSetStopTimeOffset: + case kWhatSetStopTimeUs: { sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); @@ -1063,11 +1101,13 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) { int64_t stopTimeUs; CHECK(msg->findInt64("stop-time-us", &stopTimeUs)); - // Propagate the timestamp offset to GraphicBufferSource. + // Propagate the stop time to GraphicBufferSource. if (mFlags & FLAG_USE_SURFACE_INPUT) { sp<AMessage> params = new AMessage; params->setInt64("stop-time-us", stopTimeUs); err = mEncoder->setParameters(params); + } else { + err = mPuller->setStopTimeUs(stopTimeUs); } sp<AMessage> response = new AMessage; diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp index 0cf6fbf134..927838122e 100644 --- a/media/libstagefright/MediaSync.cpp +++ b/media/libstagefright/MediaSync.cpp @@ -32,6 +32,8 @@ #include <ui/GraphicBuffer.h> +#include <system/window.h> + // Maximum late time allowed for a video frame to be rendered. When a video // frame arrives later than this number, it will be discarded without rendering. static const int64_t kMaxAllowedVideoLateTimeUs = 40000ll; diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp index 4134698128..4f31c5fa05 100644 --- a/media/libstagefright/SampleIterator.cpp +++ b/media/libstagefright/SampleIterator.cpp @@ -282,7 +282,7 @@ status_t SampleIterator::getSampleSizeDirect( default: { - CHECK_EQ(mTable->mSampleSizeFieldSize, 4); + CHECK_EQ(mTable->mSampleSizeFieldSize, 4u); uint8_t x; if (mTable->mDataSource->readAt( diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp index ea7d5af909..90b8603864 100644 --- a/media/libstagefright/SimpleDecodingSource.cpp +++ b/media/libstagefright/SimpleDecodingSource.cpp @@ -36,6 +36,12 @@ const int64_t kTimeoutWaitForInputUs = 5000; // 5 milliseconds //static sp<SimpleDecodingSource> SimpleDecodingSource::Create( + const sp<IMediaSource> &source, uint32_t flags) { + return SimpleDecodingSource::Create(source, flags, nullptr, nullptr); +} + +//static +sp<SimpleDecodingSource> SimpleDecodingSource::Create( const sp<IMediaSource> &source, uint32_t flags, const sp<ANativeWindow> &nativeWindow, const char *desiredCodec) { sp<Surface> surface = static_cast<Surface*>(nativeWindow.get()); diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp index 883a4dd0a2..03dc9df221 100644 --- a/media/libstagefright/StagefrightMetadataRetriever.cpp +++ b/media/libstagefright/StagefrightMetadataRetriever.cpp @@ -44,7 +44,7 @@ #include <media/stagefright/MetaData.h> #include <media/stagefright/Utils.h> -#include <CharacterEncodingDetector.h> +#include <media/CharacterEncodingDetector.h> namespace android { diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp index d0d82b3fdb..d14e86b1f2 100644 --- a/media/libstagefright/SurfaceMediaSource.cpp +++ b/media/libstagefright/SurfaceMediaSource.cpp @@ -96,13 +96,13 @@ void SurfaceMediaSource::setFrameAvailableListener( mFrameAvailableListener = listener; } -void SurfaceMediaSource::dump(String8& result) const +void SurfaceMediaSource::dumpState(String8& result) const { char buffer[1024]; - dump(result, "", buffer, 1024); + dumpState(result, "", buffer, 1024); } -void SurfaceMediaSource::dump( +void SurfaceMediaSource::dumpState( String8& result, const char* /* prefix */, char* buffer, @@ -166,7 +166,7 @@ status_t SurfaceMediaSource::start(MetaData *params) mMaxAcquiredBufferCount = bufferCount; } - CHECK_GT(mMaxAcquiredBufferCount, 1); + CHECK_GT(mMaxAcquiredBufferCount, 1u); status_t err = mConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBufferCount); @@ -185,7 +185,7 @@ status_t SurfaceMediaSource::setMaxAcquiredBufferCount(size_t count) { ALOGV("setMaxAcquiredBufferCount(%zu)", count); Mutex::Autolock lock(mMutex); - CHECK_GT(count, 1); + CHECK_GT(count, 1u); mMaxAcquiredBufferCount = count; return OK; diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 621c2cef3c..0aea8e18c8 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -1069,6 +1069,16 @@ status_t convertMetaDataToMessage( buffer->meta()->setInt32("csd", true); buffer->meta()->setInt64("timeUs", 0); msg->setBuffer("csd-2", buffer); + } else if (meta->findData(kKeyFlacMetadata, &type, &data, &size)) { + sp<ABuffer> buffer = new (std::nothrow) ABuffer(size); + if (buffer.get() == NULL || buffer->base() == NULL) { + return NO_MEMORY; + } + memcpy(buffer->data(), data, size); + + buffer->meta()->setInt32("csd", true); + buffer->meta()->setInt64("timeUs", 0); + msg->setBuffer("csd-0", buffer); } else if (meta->findData(kKeyVp9CodecPrivate, &type, &data, &size)) { sp<ABuffer> buffer = new (std::nothrow) ABuffer(size); if (buffer.get() == NULL || buffer->base() == NULL) { @@ -1552,6 +1562,7 @@ static const struct mime_conv_t mimeLookup[] = { { MEDIA_MIMETYPE_AUDIO_VORBIS, AUDIO_FORMAT_VORBIS }, { MEDIA_MIMETYPE_AUDIO_OPUS, AUDIO_FORMAT_OPUS}, { MEDIA_MIMETYPE_AUDIO_AC3, AUDIO_FORMAT_AC3}, + { MEDIA_MIMETYPE_AUDIO_FLAC, AUDIO_FORMAT_FLAC}, { 0, AUDIO_FORMAT_INVALID } }; diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp index 9b042d3809..ea2433afc4 100644 --- a/media/libstagefright/avc_utils.cpp +++ b/media/libstagefright/avc_utils.cpp @@ -80,7 +80,16 @@ static void skipScalingList(ABitReader *br, size_t sizeOfScalingList) { for (size_t j = 0; j < sizeOfScalingList; ++j) { if (nextScale != 0) { signed delta_scale = parseSE(br); - nextScale = (lastScale + delta_scale + 256) % 256; + // ISO_IEC_14496-10_201402-ITU, 7.4.2.1.1.1, The value of delta_scale + // shall be in the range of −128 to +127, inclusive. + if (delta_scale < -128) { + ALOGW("delta_scale (%d) is below range, capped to -128", delta_scale); + delta_scale = -128; + } else if (delta_scale > 127) { + ALOGW("delta_scale (%d) is above range, capped to 127", delta_scale); + delta_scale = 127; + } + nextScale = (lastScale + (delta_scale + 256)) % 256; } lastScale = (nextScale == 0) ? lastScale : nextScale; diff --git a/media/libstagefright/codecs/Android.mk b/media/libstagefright/codecs/Android.mk deleted file mode 100644 index 2e431205aa..0000000000 --- a/media/libstagefright/codecs/Android.mk +++ /dev/null @@ -1,4 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media/libstagefright/codecs/aacdec/Android.bp b/media/libstagefright/codecs/aacdec/Android.bp new file mode 100644 index 0000000000..6e04c1e8f4 --- /dev/null +++ b/media/libstagefright/codecs/aacdec/Android.bp @@ -0,0 +1,36 @@ +cc_library_shared { + name: "libstagefright_soft_aacdec", + + srcs: [ + "SoftAAC2.cpp", + "DrcPresModeWrap.cpp", + ], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + cflags: ["-Werror"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + static_libs: ["libFraunhoferAAC"], + + shared_libs: [ + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "libcutils", + "liblog", + ], +} diff --git a/media/libstagefright/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk deleted file mode 100644 index 29c0f33bd9..0000000000 --- a/media/libstagefright/codecs/aacdec/Android.mk +++ /dev/null @@ -1,33 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - SoftAAC2.cpp \ - DrcPresModeWrap.cpp - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - frameworks/native/include/media/openmax \ - external/aac/libAACdec/include \ - external/aac/libPCMutils/include \ - external/aac/libFDK/include \ - external/aac/libMpegTPDec/include \ - external/aac/libSBRdec/include \ - external/aac/libSYS/include - -LOCAL_CFLAGS := - -LOCAL_CFLAGS += -Werror -LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_STATIC_LIBRARIES := libFraunhoferAAC - -LOCAL_SHARED_LIBRARIES := \ - libstagefright_omx libstagefright_foundation libutils libcutils liblog - -LOCAL_MODULE := libstagefright_soft_aacdec -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp index 9e596ff7f0..5656139cfd 100644 --- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp +++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp @@ -296,7 +296,7 @@ status_t AACEncoder::read( memset(&inputData, 0, sizeof(inputData)); inputData.Buffer = (unsigned char*) mInputFrame; inputData.Length = nSamples * sizeof(int16_t); - CHECK(VO_ERR_NONE == mApiHandle->SetInputData(mEncoderHandle,&inputData)); + CHECK((VO_U32)VO_ERR_NONE == mApiHandle->SetInputData(mEncoderHandle,&inputData)); VO_CODECBUFFER outputData; memset(&outputData, 0, sizeof(outputData)); diff --git a/media/libstagefright/codecs/aacenc/Android.bp b/media/libstagefright/codecs/aacenc/Android.bp new file mode 100644 index 0000000000..1a7ffca5c1 --- /dev/null +++ b/media/libstagefright/codecs/aacenc/Android.bp @@ -0,0 +1,176 @@ +cc_library_static { + name: "libstagefright_aacenc", + + srcs: [ + "basic_op/basicop2.c", + "basic_op/oper_32b.c", + + "AACEncoder.cpp", + "src/aac_rom.c", + "src/aacenc.c", + "src/aacenc_core.c", + "src/adj_thr.c", + "src/band_nrg.c", + "src/bit_cnt.c", + "src/bitbuffer.c", + "src/bitenc.c", + "src/block_switch.c", + "src/channel_map.c", + "src/dyn_bits.c", + "src/grp_data.c", + "src/interface.c", + "src/line_pe.c", + "src/ms_stereo.c", + "src/pre_echo_control.c", + "src/psy_configuration.c", + "src/psy_main.c", + "src/qc_main.c", + "src/quantize.c", + "src/sf_estim.c", + "src/spreading.c", + "src/stat_bits.c", + "src/tns.c", + "src/transform.c", + "src/memalign.c", + ], + + arch: { + arm: { + srcs: [ + "src/asm/ARMV5E/AutoCorrelation_v5.s", + "src/asm/ARMV5E/band_nrg_v5.s", + "src/asm/ARMV5E/CalcWindowEnergy_v5.s", + "src/asm/ARMV5E/PrePostMDCT_v5.s", + "src/asm/ARMV5E/R4R8First_v5.s", + "src/asm/ARMV5E/Radix4FFT_v5.s", + ], + + cflags: [ + "-DARMV5E", + "-DARM_INASM", + "-DARMV5_INASM", + ], + + local_include_dirs: ["src/asm/ARMV5E"], + + instruction_set: "arm", + + armv7_a_neon: { + exclude_srcs: [ + "src/asm/ARMV5E/PrePostMDCT_v5.s", + "src/asm/ARMV5E/R4R8First_v5.s", + "src/asm/ARMV5E/Radix4FFT_v5.s", + ], + srcs: [ + "src/asm/ARMV7/PrePostMDCT_v7.s", + "src/asm/ARMV7/R4R8First_v7.s", + "src/asm/ARMV7/Radix4FFT_v7.s", + ], + + cflags: [ + "-DARMV7Neon", + "-DARMV6_INASM", + ], + + local_include_dirs: ["src/asm/ARMV7"], + }, + }, + }, + + // libstagefright links this static library, so it probably isn't appropriate to + // link libstagefright. However, this library includes libstagefright headers, + // and needs libbinder to be able to do so correctly. + shared_libs: [ + "libbinder", + "libstagefright_enc_common", + ], + + include_dirs: [ + "frameworks/av/include", + "frameworks/av/media/libstagefright/include", + ], + + local_include_dirs: [ + "src", + "inc", + "basic_op", + ], + + cflags: ["-Werror"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + }, + +} + +//############################################################################### + +cc_library_shared { + name: "libstagefright_soft_aacenc", + + srcs: ["SoftAACEncoder2.cpp"], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + cflags: ["-Werror"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + static_libs: ["libFraunhoferAAC"], + + shared_libs: [ + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "liblog", + ], +} + +cc_library_shared { + name: "libstagefright_soft_aacenc_visualon", + + srcs: ["SoftAACEncoder.cpp"], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + cflags: [ + "-DOSCL_IMPORT_REF=", + "-Werror", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + }, + + static_libs: ["libstagefright_aacenc"], + + shared_libs: [ + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "liblog", + "libstagefright_enc_common", + ], +} diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk deleted file mode 100644 index 527687b200..0000000000 --- a/media/libstagefright/codecs/aacenc/Android.mk +++ /dev/null @@ -1,149 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -AAC_LIBRARY = fraunhofer - -LOCAL_SRC_FILES := basic_op/basicop2.c basic_op/oper_32b.c - -LOCAL_SRC_FILES += \ - AACEncoder.cpp \ - src/aac_rom.c \ - src/aacenc.c \ - src/aacenc_core.c \ - src/adj_thr.c \ - src/band_nrg.c \ - src/bit_cnt.c \ - src/bitbuffer.c \ - src/bitenc.c \ - src/block_switch.c \ - src/channel_map.c \ - src/dyn_bits.c \ - src/grp_data.c \ - src/interface.c \ - src/line_pe.c \ - src/ms_stereo.c \ - src/pre_echo_control.c \ - src/psy_configuration.c \ - src/psy_main.c \ - src/qc_main.c \ - src/quantize.c \ - src/sf_estim.c \ - src/spreading.c \ - src/stat_bits.c \ - src/tns.c \ - src/transform.c \ - src/memalign.c - -ifneq ($(ARCH_ARM_HAVE_NEON),true) - LOCAL_SRC_FILES_arm := \ - src/asm/ARMV5E/AutoCorrelation_v5.s \ - src/asm/ARMV5E/band_nrg_v5.s \ - src/asm/ARMV5E/CalcWindowEnergy_v5.s \ - src/asm/ARMV5E/PrePostMDCT_v5.s \ - src/asm/ARMV5E/R4R8First_v5.s \ - src/asm/ARMV5E/Radix4FFT_v5.s - - LOCAL_CFLAGS_arm := -DARMV5E -DARM_INASM -DARMV5_INASM - LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/src/asm/ARMV5E -else - LOCAL_SRC_FILES_arm := \ - src/asm/ARMV5E/AutoCorrelation_v5.s \ - src/asm/ARMV5E/band_nrg_v5.s \ - src/asm/ARMV5E/CalcWindowEnergy_v5.s \ - src/asm/ARMV7/PrePostMDCT_v7.s \ - src/asm/ARMV7/R4R8First_v7.s \ - src/asm/ARMV7/Radix4FFT_v7.s - LOCAL_CFLAGS_arm := -DARMV5E -DARMV7Neon -DARM_INASM -DARMV5_INASM -DARMV6_INASM - LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/src/asm/ARMV5E - LOCAL_C_INCLUDES_arm += $(LOCAL_PATH)/src/asm/ARMV7 -endif - -LOCAL_MODULE := libstagefright_aacenc - -LOCAL_ARM_MODE := arm - -LOCAL_STATIC_LIBRARIES := - -# libstagefright links this static library, so it probably isn't appropriate to -# link libstagefright. However, this library includes libstagefright headers, -# and needs libbinder to be able to do so correctly. -LOCAL_SHARED_LIBRARIES := libbinder - -LOCAL_C_INCLUDES := \ - frameworks/av/include \ - frameworks/av/media/libstagefright/include \ - frameworks/av/media/libstagefright/codecs/common/include \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/inc \ - $(LOCAL_PATH)/basic_op - -LOCAL_CFLAGS += -Werror -LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow - -include $(BUILD_STATIC_LIBRARY) - -################################################################################ - -include $(CLEAR_VARS) - -ifeq ($(AAC_LIBRARY), fraunhofer) - - include $(CLEAR_VARS) - - LOCAL_SRC_FILES := \ - SoftAACEncoder2.cpp - - LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - frameworks/native/include/media/openmax \ - external/aac/libAACenc/include \ - external/aac/libFDK/include \ - external/aac/libMpegTPEnc/include \ - external/aac/libSBRenc/include \ - external/aac/libSYS/include - - LOCAL_CFLAGS := - - LOCAL_CFLAGS += -Werror - LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi - LOCAL_SANITIZE_DIAG := cfi - - LOCAL_STATIC_LIBRARIES := libFraunhoferAAC - - LOCAL_SHARED_LIBRARIES := \ - libstagefright_omx libstagefright_foundation libutils liblog - - LOCAL_MODULE := libstagefright_soft_aacenc - LOCAL_MODULE_TAGS := optional - - include $(BUILD_SHARED_LIBRARY) - -else # visualon - - LOCAL_SRC_FILES := \ - SoftAACEncoder.cpp - - LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - frameworks/av/media/libstagefright/codecs/common/include \ - frameworks/native/include/media/openmax - - LOCAL_CFLAGS := -DOSCL_IMPORT_REF= - - LOCAL_CFLAGS += -Werror - LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi - LOCAL_SANITIZE_DIAG := cfi - - LOCAL_STATIC_LIBRARIES := \ - libstagefright_aacenc - - LOCAL_SHARED_LIBRARIES := \ - libstagefright_omx libstagefright_foundation libutils liblog \ - libstagefright_enc_common - - LOCAL_MODULE := libstagefright_soft_aacenc - LOCAL_MODULE_TAGS := optional - - include $(BUILD_SHARED_LIBRARY) - -endif # $(AAC_LIBRARY) diff --git a/media/libstagefright/codecs/aacenc/SampleCode/Android.bp b/media/libstagefright/codecs/aacenc/SampleCode/Android.bp new file mode 100644 index 0000000000..c6ba4f3c9a --- /dev/null +++ b/media/libstagefright/codecs/aacenc/SampleCode/Android.bp @@ -0,0 +1,18 @@ +cc_binary { + name: "AACEncTest", + + srcs: ["AAC_E_SAMPLES.c"], + + arch: { + arm: { + instruction_set: "arm", + }, + }, + + shared_libs: [ + "libstagefright", + "libdl", + ], + + static_libs: ["libstagefright_enc_common"], +} diff --git a/media/libstagefright/codecs/aacenc/SampleCode/Android.mk b/media/libstagefright/codecs/aacenc/SampleCode/Android.mk deleted file mode 100644 index d06dcf6784..0000000000 --- a/media/libstagefright/codecs/aacenc/SampleCode/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - AAC_E_SAMPLES.c \ - ../../common/cmnMemory.c - -LOCAL_MODULE_TAGS := optional - -LOCAL_MODULE := AACEncTest - -LOCAL_ARM_MODE := arm - -LOCAL_SHARED_LIBRARIES := \ - libstagefright \ - libdl - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/ \ - $(LOCAL_PATH)/../../common \ - $(LOCAL_PATH)/../../common/include \ - -include $(BUILD_EXECUTABLE) diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp index 67c31af595..0704294dd8 100644 --- a/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp +++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp @@ -65,7 +65,7 @@ SoftAACEncoder::~SoftAACEncoder() { onReset(); if (mEncoderHandle) { - CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle)); + CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle)); mEncoderHandle = NULL; } @@ -333,7 +333,7 @@ status_t SoftAACEncoder::setAudioParams() { // We call this whenever sample rate, number of channels or bitrate change // in reponse to setParameter calls. - ALOGV("setAudioParams: %lu Hz, %lu channels, %lu bps", + ALOGV("setAudioParams: %u Hz, %u channels, %u bps", mSampleRate, mNumChannels, mBitRate); status_t err = setAudioSpecificConfigData(); @@ -383,12 +383,12 @@ status_t SoftAACEncoder::setAudioSpecificConfigData() { int32_t index; status_t err = getSampleRateTableIndex(mSampleRate, index); if (err != OK) { - ALOGE("Unsupported sample rate (%lu Hz)", mSampleRate); + ALOGE("Unsupported sample rate (%u Hz)", mSampleRate); return err; } if (mNumChannels > 2 || mNumChannels <= 0) { - ALOGE("Unsupported number of channels(%lu)", mNumChannels); + ALOGE("Unsupported number of channels(%u)", mNumChannels); return UNKNOWN_ERROR; } @@ -399,7 +399,7 @@ status_t SoftAACEncoder::setAudioSpecificConfigData() { return OK; } -void SoftAACEncoder::onQueueFilled(OMX_U32 portIndex) { +void SoftAACEncoder::onQueueFilled(OMX_U32 /*portIndex*/) { if (mSignalledError) { return; } @@ -520,7 +520,7 @@ void SoftAACEncoder::onQueueFilled(OMX_U32 portIndex) { memset(&inputData, 0, sizeof(inputData)); inputData.Buffer = (unsigned char *)mInputFrame; inputData.Length = numBytesPerInputFrame; - CHECK(VO_ERR_NONE == + CHECK((VO_U32)VO_ERR_NONE == mApiHandle->SetInputData(mEncoderHandle, &inputData)); VO_CODECBUFFER outputData; diff --git a/media/libstagefright/codecs/aacenc/src/grp_data.c b/media/libstagefright/codecs/aacenc/src/grp_data.c index 7861e1cdcc..edfb95bbbf 100644 --- a/media/libstagefright/codecs/aacenc/src/grp_data.c +++ b/media/libstagefright/codecs/aacenc/src/grp_data.c @@ -88,7 +88,6 @@ groupShortData(Word32 *mdctSpectrum, offset += groupLen[grp] * FRAME_LEN_SHORT; } groupedSfbOffset[i] = FRAME_LEN_LONG; - i += 1; /* calculate minSnr */ i = 0; diff --git a/media/libstagefright/codecs/aacenc/src/ms_stereo.c b/media/libstagefright/codecs/aacenc/src/ms_stereo.c index 1e4b227c79..ca028dcb49 100644 --- a/media/libstagefright/codecs/aacenc/src/ms_stereo.c +++ b/media/libstagefright/codecs/aacenc/src/ms_stereo.c @@ -94,8 +94,6 @@ void MsStereoProcessing(Word32 *sfbEnergyLeft, pnms = fixmul(nrgL, nrgR); - temp = (pnlr + 1) / ((pnms >> 8) + 1); - temp = pnms - pnlr; if( temp > 0 ){ diff --git a/media/libstagefright/codecs/amrnb/Android.bp b/media/libstagefright/codecs/amrnb/Android.bp new file mode 100644 index 0000000000..b44c296012 --- /dev/null +++ b/media/libstagefright/codecs/amrnb/Android.bp @@ -0,0 +1 @@ +subdirs = ["*"] diff --git a/media/libstagefright/codecs/amrnb/Android.mk b/media/libstagefright/codecs/amrnb/Android.mk deleted file mode 100644 index 2e431205aa..0000000000 --- a/media/libstagefright/codecs/amrnb/Android.mk +++ /dev/null @@ -1,4 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media/libstagefright/codecs/amrnb/common/Android.bp b/media/libstagefright/codecs/amrnb/common/Android.bp new file mode 100644 index 0000000000..c5ac55829d --- /dev/null +++ b/media/libstagefright/codecs/amrnb/common/Android.bp @@ -0,0 +1,82 @@ +cc_library_shared { + name: "libstagefright_amrnb_common", + + srcs: [ + "src/add.cpp", + "src/az_lsp.cpp", + "src/bitno_tab.cpp", + "src/bitreorder_tab.cpp", + "src/bits2prm.cpp", + "src/c2_9pf_tab.cpp", + "src/copy.cpp", + "src/div_32.cpp", + "src/div_s.cpp", + "src/extract_h.cpp", + "src/extract_l.cpp", + "src/gains_tbl.cpp", + "src/gc_pred.cpp", + "src/gmed_n.cpp", + "src/grid_tbl.cpp", + "src/gray_tbl.cpp", + "src/int_lpc.cpp", + "src/inv_sqrt.cpp", + "src/inv_sqrt_tbl.cpp", + "src/l_abs.cpp", + "src/l_deposit_h.cpp", + "src/l_deposit_l.cpp", + "src/l_shr_r.cpp", + "src/log2.cpp", + "src/log2_norm.cpp", + "src/log2_tbl.cpp", + "src/lsfwt.cpp", + "src/lsp.cpp", + "src/lsp_az.cpp", + "src/lsp_lsf.cpp", + "src/lsp_lsf_tbl.cpp", + "src/lsp_tab.cpp", + "src/mult_r.cpp", + "src/norm_l.cpp", + "src/norm_s.cpp", + "src/ph_disp_tab.cpp", + "src/pow2.cpp", + "src/pow2_tbl.cpp", + "src/pred_lt.cpp", + "src/q_plsf.cpp", + "src/q_plsf_3.cpp", + "src/q_plsf_3_tbl.cpp", + "src/q_plsf_5.cpp", + "src/q_plsf_5_tbl.cpp", + "src/qua_gain_tbl.cpp", + "src/reorder.cpp", + "src/residu.cpp", + "src/round.cpp", + "src/set_zero.cpp", + "src/shr.cpp", + "src/shr_r.cpp", + "src/sqrt_l.cpp", + "src/sqrt_l_tbl.cpp", + "src/sub.cpp", + "src/syn_filt.cpp", + "src/vad1.cpp", + "src/weight_a.cpp", + "src/window_tab.cpp", + ], + + export_include_dirs: ["include"], + + cflags: [ + "-DOSCL_UNUSED_ARG(x)=(void)(x)", + "-DOSCL_IMPORT_REF=", + "-DOSCL_EXPORT_REF=", + + "-Werror", + ], + + //addressing b/25409744 + //sanitize: { + // misc_undefined: [ + // "signed-integer-overflow", + // "unsigned-integer-overflow", + // ], + //}, +} diff --git a/media/libstagefright/codecs/amrnb/common/Android.mk b/media/libstagefright/codecs/amrnb/common/Android.mk deleted file mode 100644 index 0bb57241f4..0000000000 --- a/media/libstagefright/codecs/amrnb/common/Android.mk +++ /dev/null @@ -1,76 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - src/add.cpp \ - src/az_lsp.cpp \ - src/bitno_tab.cpp \ - src/bitreorder_tab.cpp \ - src/bits2prm.cpp \ - src/c2_9pf_tab.cpp \ - src/copy.cpp \ - src/div_32.cpp \ - src/div_s.cpp \ - src/extract_h.cpp \ - src/extract_l.cpp \ - src/gains_tbl.cpp \ - src/gc_pred.cpp \ - src/gmed_n.cpp \ - src/grid_tbl.cpp \ - src/gray_tbl.cpp \ - src/int_lpc.cpp \ - src/inv_sqrt.cpp \ - src/inv_sqrt_tbl.cpp \ - src/l_abs.cpp \ - src/l_deposit_h.cpp \ - src/l_deposit_l.cpp \ - src/l_shr_r.cpp \ - src/log2.cpp \ - src/log2_norm.cpp \ - src/log2_tbl.cpp \ - src/lsfwt.cpp \ - src/lsp.cpp \ - src/lsp_az.cpp \ - src/lsp_lsf.cpp \ - src/lsp_lsf_tbl.cpp \ - src/lsp_tab.cpp \ - src/mult_r.cpp \ - src/norm_l.cpp \ - src/norm_s.cpp \ - src/ph_disp_tab.cpp \ - src/pow2.cpp \ - src/pow2_tbl.cpp \ - src/pred_lt.cpp \ - src/q_plsf.cpp \ - src/q_plsf_3.cpp \ - src/q_plsf_3_tbl.cpp \ - src/q_plsf_5.cpp \ - src/q_plsf_5_tbl.cpp \ - src/qua_gain_tbl.cpp \ - src/reorder.cpp \ - src/residu.cpp \ - src/round.cpp \ - src/set_zero.cpp \ - src/shr.cpp \ - src/shr_r.cpp \ - src/sqrt_l.cpp \ - src/sqrt_l_tbl.cpp \ - src/sub.cpp \ - src/syn_filt.cpp \ - src/vad1.cpp \ - src/weight_a.cpp \ - src/window_tab.cpp - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/include - -LOCAL_CFLAGS := \ - -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_IMPORT_REF= -DOSCL_EXPORT_REF= - -LOCAL_CFLAGS += -Werror -#addressing b/25409744 -#LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow - -LOCAL_MODULE := libstagefright_amrnb_common - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/amrnb/dec/Android.bp b/media/libstagefright/codecs/amrnb/dec/Android.bp new file mode 100644 index 0000000000..996183bb93 --- /dev/null +++ b/media/libstagefright/codecs/amrnb/dec/Android.bp @@ -0,0 +1,126 @@ +cc_library_static { + name: "libstagefright_amrnbdec", + + srcs: [ + "src/a_refl.cpp", + "src/agc.cpp", + "src/amrdecode.cpp", + "src/b_cn_cod.cpp", + "src/bgnscd.cpp", + "src/c_g_aver.cpp", + "src/d1035pf.cpp", + "src/d2_11pf.cpp", + "src/d2_9pf.cpp", + "src/d3_14pf.cpp", + "src/d4_17pf.cpp", + "src/d8_31pf.cpp", + "src/d_gain_c.cpp", + "src/d_gain_p.cpp", + "src/d_plsf.cpp", + "src/d_plsf_3.cpp", + "src/d_plsf_5.cpp", + "src/dec_amr.cpp", + "src/dec_gain.cpp", + "src/dec_input_format_tab.cpp", + "src/dec_lag3.cpp", + "src/dec_lag6.cpp", + "src/dtx_dec.cpp", + "src/ec_gains.cpp", + "src/ex_ctrl.cpp", + "src/if2_to_ets.cpp", + "src/int_lsf.cpp", + "src/lsp_avg.cpp", + "src/ph_disp.cpp", + "src/post_pro.cpp", + "src/preemph.cpp", + "src/pstfilt.cpp", + "src/qgain475_tab.cpp", + "src/sp_dec.cpp", + "src/wmf_to_ets.cpp", + ], + + include_dirs: ["frameworks/av/media/libstagefright/include"], + local_include_dirs: ["src"], + + cflags: [ + "-DOSCL_UNUSED_ARG(x)=(void)(x)", + "-DOSCL_IMPORT_REF=", + + "-Werror", + ], + + //sanitize: { + // misc_undefined: [ + // "signed-integer-overflow", + // ], + //}, + + shared_libs: ["libstagefright_amrnb_common"], +} + +//############################################################################### + +cc_library_shared { + name: "libstagefright_soft_amrdec", + + srcs: ["SoftAMR.cpp"], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/av/media/libstagefright/codecs/amrwb/src", + "frameworks/native/include/media/openmax", + ], + local_include_dirs: ["src"], + + cflags: [ + "-DOSCL_IMPORT_REF=", + "-Werror", + ], + + //sanitize: { + // misc_undefined: [ + // "signed-integer-overflow", + // ], + //}, + //LOCAL_SANITIZE := signed-integer-overflow + + static_libs: [ + "libstagefright_amrnbdec", + "libstagefright_amrwbdec", + ], + + shared_libs: [ + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "liblog", + "libstagefright_amrnb_common", + ], +} + +//############################################################################### +cc_test { + name: "libstagefright_amrnbdec_test", + gtest: false, + + srcs: ["test/amrnbdec_test.cpp"], + + local_include_dirs: ["src"], + + static_libs: [ + "libstagefright_amrnbdec", + "libsndfile", + ], + + shared_libs: [ + "libstagefright_amrnb_common", + "libaudioutils", + "liblog", + ], + + //sanitize: { + // misc_undefined: [ + // "signed-integer-overflow", + // ], + //}, +} diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk deleted file mode 100644 index 3959b8081d..0000000000 --- a/media/libstagefright/codecs/amrnb/dec/Android.mk +++ /dev/null @@ -1,110 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - src/a_refl.cpp \ - src/agc.cpp \ - src/amrdecode.cpp \ - src/b_cn_cod.cpp \ - src/bgnscd.cpp \ - src/c_g_aver.cpp \ - src/d1035pf.cpp \ - src/d2_11pf.cpp \ - src/d2_9pf.cpp \ - src/d3_14pf.cpp \ - src/d4_17pf.cpp \ - src/d8_31pf.cpp \ - src/d_gain_c.cpp \ - src/d_gain_p.cpp \ - src/d_plsf.cpp \ - src/d_plsf_3.cpp \ - src/d_plsf_5.cpp \ - src/dec_amr.cpp \ - src/dec_gain.cpp \ - src/dec_input_format_tab.cpp \ - src/dec_lag3.cpp \ - src/dec_lag6.cpp \ - src/dtx_dec.cpp \ - src/ec_gains.cpp \ - src/ex_ctrl.cpp \ - src/if2_to_ets.cpp \ - src/int_lsf.cpp \ - src/lsp_avg.cpp \ - src/ph_disp.cpp \ - src/post_pro.cpp \ - src/preemph.cpp \ - src/pstfilt.cpp \ - src/qgain475_tab.cpp \ - src/sp_dec.cpp \ - src/wmf_to_ets.cpp - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/include \ - $(LOCAL_PATH)/../common/include - -LOCAL_CFLAGS := \ - -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_IMPORT_REF= - -LOCAL_CFLAGS += -Werror -#LOCAL_SANITIZE := signed-integer-overflow - -LOCAL_MODULE := libstagefright_amrnbdec - -include $(BUILD_STATIC_LIBRARY) - -################################################################################ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - SoftAMR.cpp - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - frameworks/av/media/libstagefright/codecs/amrwb/src \ - frameworks/native/include/media/openmax \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/include \ - $(LOCAL_PATH)/../common/include \ - -LOCAL_CFLAGS := -DOSCL_IMPORT_REF= - -LOCAL_CFLAGS += -Werror -#LOCAL_SANITIZE := signed-integer-overflow - -LOCAL_STATIC_LIBRARIES := \ - libstagefright_amrnbdec libstagefright_amrwbdec - -LOCAL_SHARED_LIBRARIES := \ - libstagefright_omx libstagefright_foundation libutils liblog \ - libstagefright_amrnb_common - -LOCAL_MODULE := libstagefright_soft_amrdec -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) - -################################################################################ -include $(CLEAR_VARS) -LOCAL_SRC_FILES := \ - test/amrnbdec_test.cpp - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/../common/include \ - $(call include-path-for, audio-utils) - -LOCAL_STATIC_LIBRARIES := \ - libstagefright_amrnbdec libsndfile - -LOCAL_SHARED_LIBRARIES := \ - libstagefright_amrnb_common libaudioutils liblog - -#LOCAL_SANITIZE := signed-integer-overflow - -LOCAL_MODULE := libstagefright_amrnbdec_test -LOCAL_MODULE_TAGS := optional - -include $(BUILD_EXECUTABLE) diff --git a/media/libstagefright/codecs/amrnb/enc/Android.bp b/media/libstagefright/codecs/amrnb/enc/Android.bp new file mode 100644 index 0000000000..af0f8c250d --- /dev/null +++ b/media/libstagefright/codecs/amrnb/enc/Android.bp @@ -0,0 +1,135 @@ +cc_library_static { + name: "libstagefright_amrnbenc", + + srcs: [ + "src/amrencode.cpp", + "src/autocorr.cpp", + "src/c1035pf.cpp", + "src/c2_11pf.cpp", + "src/c2_9pf.cpp", + "src/c3_14pf.cpp", + "src/c4_17pf.cpp", + "src/c8_31pf.cpp", + "src/calc_cor.cpp", + "src/calc_en.cpp", + "src/cbsearch.cpp", + "src/cl_ltp.cpp", + "src/cod_amr.cpp", + "src/convolve.cpp", + "src/cor_h.cpp", + "src/cor_h_x.cpp", + "src/cor_h_x2.cpp", + "src/corrwght_tab.cpp", + "src/dtx_enc.cpp", + "src/enc_lag3.cpp", + "src/enc_lag6.cpp", + "src/enc_output_format_tab.cpp", + "src/ets_to_if2.cpp", + "src/ets_to_wmf.cpp", + "src/g_adapt.cpp", + "src/g_code.cpp", + "src/g_pitch.cpp", + "src/gain_q.cpp", + "src/hp_max.cpp", + "src/inter_36.cpp", + "src/inter_36_tab.cpp", + "src/l_comp.cpp", + "src/l_extract.cpp", + "src/l_negate.cpp", + "src/lag_wind.cpp", + "src/lag_wind_tab.cpp", + "src/levinson.cpp", + "src/lpc.cpp", + "src/ol_ltp.cpp", + "src/p_ol_wgh.cpp", + "src/pitch_fr.cpp", + "src/pitch_ol.cpp", + "src/pre_big.cpp", + "src/pre_proc.cpp", + "src/prm2bits.cpp", + "src/q_gain_c.cpp", + "src/q_gain_p.cpp", + "src/qgain475.cpp", + "src/qgain795.cpp", + "src/qua_gain.cpp", + "src/s10_8pf.cpp", + "src/set_sign.cpp", + "src/sid_sync.cpp", + "src/sp_enc.cpp", + "src/spreproc.cpp", + "src/spstproc.cpp", + "src/ton_stab.cpp", + ], + + include_dirs: ["frameworks/av/media/libstagefright/include"], + local_include_dirs: ["src"], + + cflags: [ + "-DOSCL_UNUSED_ARG(x)=(void)(x)", + "-Werror", + ], + + //addressing b/25409744 + //sanitize: { + // misc_undefined: [ + // "signed-integer-overflow", + // ], + //}, + + shared_libs: ["libstagefright_amrnb_common"], +} + +//############################################################################### + +cc_library_shared { + name: "libstagefright_soft_amrnbenc", + + srcs: ["SoftAMRNBEncoder.cpp"], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + local_include_dirs: ["src"], + + cflags: ["-Werror"], + + //addressing b/25409744 + //sanitize: { + // misc_undefined: [ + // "signed-integer-overflow", + // ], + //}, + + static_libs: ["libstagefright_amrnbenc"], + + shared_libs: [ + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "liblog", + "libstagefright_amrnb_common", + ], +} + +//############################################################################### + +cc_test { + name: "libstagefright_amrnbenc_test", + gtest: false, + + srcs: ["test/amrnb_enc_test.cpp"], + + local_include_dirs: ["src"], + + static_libs: ["libstagefright_amrnbenc"], + + shared_libs: ["libstagefright_amrnb_common"], + + //addressing b/25409744 + //sanitize: { + // misc_undefined: [ + // "signed-integer-overflow", + // ], + //}, +} diff --git a/media/libstagefright/codecs/amrnb/enc/Android.mk b/media/libstagefright/codecs/amrnb/enc/Android.mk deleted file mode 100644 index af1efb97d3..0000000000 --- a/media/libstagefright/codecs/amrnb/enc/Android.mk +++ /dev/null @@ -1,134 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - src/amrencode.cpp \ - src/autocorr.cpp \ - src/c1035pf.cpp \ - src/c2_11pf.cpp \ - src/c2_9pf.cpp \ - src/c3_14pf.cpp \ - src/c4_17pf.cpp \ - src/c8_31pf.cpp \ - src/calc_cor.cpp \ - src/calc_en.cpp \ - src/cbsearch.cpp \ - src/cl_ltp.cpp \ - src/cod_amr.cpp \ - src/convolve.cpp \ - src/cor_h.cpp \ - src/cor_h_x.cpp \ - src/cor_h_x2.cpp \ - src/corrwght_tab.cpp \ - src/dtx_enc.cpp \ - src/enc_lag3.cpp \ - src/enc_lag6.cpp \ - src/enc_output_format_tab.cpp \ - src/ets_to_if2.cpp \ - src/ets_to_wmf.cpp \ - src/g_adapt.cpp \ - src/g_code.cpp \ - src/g_pitch.cpp \ - src/gain_q.cpp \ - src/hp_max.cpp \ - src/inter_36.cpp \ - src/inter_36_tab.cpp \ - src/l_comp.cpp \ - src/l_extract.cpp \ - src/l_negate.cpp \ - src/lag_wind.cpp \ - src/lag_wind_tab.cpp \ - src/levinson.cpp \ - src/lpc.cpp \ - src/ol_ltp.cpp \ - src/p_ol_wgh.cpp \ - src/pitch_fr.cpp \ - src/pitch_ol.cpp \ - src/pre_big.cpp \ - src/pre_proc.cpp \ - src/prm2bits.cpp \ - src/q_gain_c.cpp \ - src/q_gain_p.cpp \ - src/qgain475.cpp \ - src/qgain795.cpp \ - src/qua_gain.cpp \ - src/s10_8pf.cpp \ - src/set_sign.cpp \ - src/sid_sync.cpp \ - src/sp_enc.cpp \ - src/spreproc.cpp \ - src/spstproc.cpp \ - src/ton_stab.cpp - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/include \ - $(LOCAL_PATH)/../common/include - -LOCAL_CFLAGS := \ - -D"OSCL_UNUSED_ARG(x)=(void)(x)" - -LOCAL_CFLAGS += -Werror -#addressing b/25409744 -#LOCAL_SANITIZE := signed-integer-overflow - -LOCAL_MODULE := libstagefright_amrnbenc - -include $(BUILD_STATIC_LIBRARY) - -################################################################################ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - SoftAMRNBEncoder.cpp - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - frameworks/native/include/media/openmax \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/include \ - $(LOCAL_PATH)/../common/include \ - $(LOCAL_PATH)/../common - -LOCAL_CFLAGS += -Werror -#addressing b/25409744 -#LOCAL_SANITIZE := signed-integer-overflow - -LOCAL_STATIC_LIBRARIES := \ - libstagefright_amrnbenc - -LOCAL_SHARED_LIBRARIES := \ - libstagefright_omx libstagefright_foundation libutils liblog \ - libstagefright_amrnb_common - -LOCAL_MODULE := libstagefright_soft_amrnbenc -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) - -################################################################################ - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := \ - test/amrnb_enc_test.cpp - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/../common/include - - -LOCAL_STATIC_LIBRARIES := \ - libstagefright_amrnbenc - -LOCAL_SHARED_LIBRARIES := \ - libstagefright_amrnb_common - -#addressing b/25409744 -#LOCAL_SANITIZE := signed-integer-overflow - -LOCAL_MODULE := libstagefright_amrnbenc_test -LOCAL_MODULE_TAGS := tests - -include $(BUILD_EXECUTABLE) diff --git a/media/libstagefright/codecs/amrwb/Android.bp b/media/libstagefright/codecs/amrwb/Android.bp new file mode 100644 index 0000000000..e261c04613 --- /dev/null +++ b/media/libstagefright/codecs/amrwb/Android.bp @@ -0,0 +1,85 @@ +cc_library_static { + name: "libstagefright_amrwbdec", + + srcs: [ + "src/agc2_amr_wb.cpp", + "src/band_pass_6k_7k.cpp", + "src/dec_acelp_2p_in_64.cpp", + "src/dec_acelp_4p_in_64.cpp", + "src/dec_alg_codebook.cpp", + "src/dec_gain2_amr_wb.cpp", + "src/deemphasis_32.cpp", + "src/dtx_decoder_amr_wb.cpp", + "src/get_amr_wb_bits.cpp", + "src/highpass_400hz_at_12k8.cpp", + "src/highpass_50hz_at_12k8.cpp", + "src/homing_amr_wb_dec.cpp", + "src/interpolate_isp.cpp", + "src/isf_extrapolation.cpp", + "src/isp_az.cpp", + "src/isp_isf.cpp", + "src/lagconceal.cpp", + "src/low_pass_filt_7k.cpp", + "src/median5.cpp", + "src/mime_io.cpp", + "src/noise_gen_amrwb.cpp", + "src/normalize_amr_wb.cpp", + "src/oversamp_12k8_to_16k.cpp", + "src/phase_dispersion.cpp", + "src/pit_shrp.cpp", + "src/pred_lt4.cpp", + "src/preemph_amrwb_dec.cpp", + "src/pvamrwb_math_op.cpp", + "src/pvamrwbdecoder.cpp", + "src/q_gain2_tab.cpp", + "src/qisf_ns.cpp", + "src/qisf_ns_tab.cpp", + "src/qpisf_2s.cpp", + "src/qpisf_2s_tab.cpp", + "src/scale_signal.cpp", + "src/synthesis_amr_wb.cpp", + "src/voice_factor.cpp", + "src/wb_syn_filt.cpp", + "src/weight_amrwb_lpc.cpp", + ], + + include_dirs: ["frameworks/av/media/libstagefright/include"], + local_include_dirs: ["src"], + export_include_dirs: ["include"], + + cflags: [ + "-DOSCL_UNUSED_ARG(x)=(void)(x)", + "-DOSCL_IMPORT_REF=", + + "-Werror", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + }, +} + +//############################################################################### +cc_test { + name: "libstagefright_amrwbdec_test", + gtest: false, + + srcs: ["test/amrwbdec_test.cpp"], + + static_libs: [ + "libstagefright_amrwbdec", + "libsndfile", + ], + + local_include_dirs: ["src"], + + shared_libs: ["libaudioutils"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + }, +} diff --git a/media/libstagefright/codecs/amrwb/Android.mk b/media/libstagefright/codecs/amrwb/Android.mk deleted file mode 100644 index 73a17517ee..0000000000 --- a/media/libstagefright/codecs/amrwb/Android.mk +++ /dev/null @@ -1,81 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - src/agc2_amr_wb.cpp \ - src/band_pass_6k_7k.cpp \ - src/dec_acelp_2p_in_64.cpp \ - src/dec_acelp_4p_in_64.cpp \ - src/dec_alg_codebook.cpp \ - src/dec_gain2_amr_wb.cpp \ - src/deemphasis_32.cpp \ - src/dtx_decoder_amr_wb.cpp \ - src/get_amr_wb_bits.cpp \ - src/highpass_400hz_at_12k8.cpp \ - src/highpass_50hz_at_12k8.cpp \ - src/homing_amr_wb_dec.cpp \ - src/interpolate_isp.cpp \ - src/isf_extrapolation.cpp \ - src/isp_az.cpp \ - src/isp_isf.cpp \ - src/lagconceal.cpp \ - src/low_pass_filt_7k.cpp \ - src/median5.cpp \ - src/mime_io.cpp \ - src/noise_gen_amrwb.cpp \ - src/normalize_amr_wb.cpp \ - src/oversamp_12k8_to_16k.cpp \ - src/phase_dispersion.cpp \ - src/pit_shrp.cpp \ - src/pred_lt4.cpp \ - src/preemph_amrwb_dec.cpp \ - src/pvamrwb_math_op.cpp \ - src/pvamrwbdecoder.cpp \ - src/q_gain2_tab.cpp \ - src/qisf_ns.cpp \ - src/qisf_ns_tab.cpp \ - src/qpisf_2s.cpp \ - src/qpisf_2s_tab.cpp \ - src/scale_signal.cpp \ - src/synthesis_amr_wb.cpp \ - src/voice_factor.cpp \ - src/wb_syn_filt.cpp \ - src/weight_amrwb_lpc.cpp - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/include - -LOCAL_CFLAGS := \ - -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_IMPORT_REF= - -LOCAL_CFLAGS += -Werror -LOCAL_SANITIZE := signed-integer-overflow - -LOCAL_MODULE := libstagefright_amrwbdec - -include $(BUILD_STATIC_LIBRARY) - -################################################################################ -include $(CLEAR_VARS) -LOCAL_SRC_FILES := \ - test/amrwbdec_test.cpp - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/include \ - $(call include-path-for, audio-utils) - -LOCAL_STATIC_LIBRARIES := \ - libstagefright_amrwbdec libsndfile - -LOCAL_SHARED_LIBRARIES := \ - libaudioutils - -LOCAL_SANITIZE := signed-integer-overflow - -LOCAL_MODULE := libstagefright_amrwbdec_test -LOCAL_MODULE_TAGS := tests - -include $(BUILD_EXECUTABLE) diff --git a/media/libstagefright/codecs/amrwbenc/Android.bp b/media/libstagefright/codecs/amrwbenc/Android.bp new file mode 100644 index 0000000000..5c5a122728 --- /dev/null +++ b/media/libstagefright/codecs/amrwbenc/Android.bp @@ -0,0 +1,180 @@ +cc_library_static { + name: "libstagefright_amrwbenc", + + srcs: [ + "src/autocorr.c", + "src/az_isp.c", + "src/bits.c", + "src/c2t64fx.c", + "src/c4t64fx.c", + "src/convolve.c", + "src/cor_h_x.c", + "src/decim54.c", + "src/deemph.c", + "src/dtx.c", + "src/g_pitch.c", + "src/gpclip.c", + "src/homing.c", + "src/hp400.c", + "src/hp50.c", + "src/hp6k.c", + "src/hp_wsp.c", + "src/int_lpc.c", + "src/isp_az.c", + "src/isp_isf.c", + "src/lag_wind.c", + "src/levinson.c", + "src/log2.c", + "src/lp_dec2.c", + "src/math_op.c", + "src/oper_32b.c", + "src/p_med_ol.c", + "src/pit_shrp.c", + "src/pitch_f4.c", + "src/pred_lt4.c", + "src/preemph.c", + "src/q_gain2.c", + "src/q_pulse.c", + "src/qisf_ns.c", + "src/qpisf_2s.c", + "src/random.c", + "src/residu.c", + "src/scale.c", + "src/stream.c", + "src/syn_filt.c", + "src/updt_tar.c", + "src/util.c", + "src/voAMRWBEnc.c", + "src/voicefac.c", + "src/wb_vad.c", + "src/weight_a.c", + "src/mem_align.c", + ], + + arch: { + arm: { + srcs: [ + "src/asm/ARMV5E/convolve_opt.s", + "src/asm/ARMV5E/cor_h_vec_opt.s", + "src/asm/ARMV5E/Deemph_32_opt.s", + "src/asm/ARMV5E/Dot_p_opt.s", + "src/asm/ARMV5E/Filt_6k_7k_opt.s", + "src/asm/ARMV5E/Norm_Corr_opt.s", + "src/asm/ARMV5E/pred_lt4_1_opt.s", + "src/asm/ARMV5E/residu_asm_opt.s", + "src/asm/ARMV5E/scale_sig_opt.s", + "src/asm/ARMV5E/Syn_filt_32_opt.s", + "src/asm/ARMV5E/syn_filt_opt.s", + ], + + cflags: [ + "-DARM", + "-DASM_OPT", + ], + local_include_dirs: ["src/asm/ARMV5E"], + + instruction_set: "arm", + + armv7_a_neon: { + exclude_srcs: [ + "src/asm/ARMV5E/convolve_opt.s", + "src/asm/ARMV5E/cor_h_vec_opt.s", + "src/asm/ARMV5E/Deemph_32_opt.s", + "src/asm/ARMV5E/Dot_p_opt.s", + "src/asm/ARMV5E/Filt_6k_7k_opt.s", + "src/asm/ARMV5E/Norm_Corr_opt.s", + "src/asm/ARMV5E/pred_lt4_1_opt.s", + "src/asm/ARMV5E/residu_asm_opt.s", + "src/asm/ARMV5E/scale_sig_opt.s", + "src/asm/ARMV5E/Syn_filt_32_opt.s", + "src/asm/ARMV5E/syn_filt_opt.s", + ], + + srcs: [ + "src/asm/ARMV7/convolve_neon.s", + "src/asm/ARMV7/cor_h_vec_neon.s", + "src/asm/ARMV7/Deemph_32_neon.s", + "src/asm/ARMV7/Dot_p_neon.s", + "src/asm/ARMV7/Filt_6k_7k_neon.s", + "src/asm/ARMV7/Norm_Corr_neon.s", + "src/asm/ARMV7/pred_lt4_1_neon.s", + "src/asm/ARMV7/residu_asm_neon.s", + "src/asm/ARMV7/scale_sig_neon.s", + "src/asm/ARMV7/Syn_filt_32_neon.s", + "src/asm/ARMV7/syn_filt_neon.s", + ], + + // don't actually generate neon instructions, see bug 26932980 + cflags: [ + "-DARMV7", + "-mfpu=vfpv3", + ], + local_include_dirs: [ + "src/asm/ARMV5E", + "src/asm/ARMV7", + ], + }, + + }, + }, + + include_dirs: [ + "frameworks/av/include", + "frameworks/av/media/libstagefright/include", + ], + + local_include_dirs: ["src"], + export_include_dirs: ["inc"], + + shared_libs: [ + "libstagefright_enc_common", + ], + + cflags: ["-Werror"], + sanitize: { + cfi: true, + diag: { + cfi: true, + }, + }, + +} + +//############################################################################### + +cc_library_shared { + name: "libstagefright_soft_amrwbenc", + + srcs: ["SoftAMRWBEncoder.cpp"], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + cflags: ["-Werror"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + static_libs: ["libstagefright_amrwbenc"], + + shared_libs: [ + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "liblog", + "libstagefright_enc_common", + ], +} + +//############################################################################### + +subdirs = ["SampleCode"] diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk deleted file mode 100644 index 573363217d..0000000000 --- a/media/libstagefright/codecs/amrwbenc/Android.mk +++ /dev/null @@ -1,139 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - src/autocorr.c \ - src/az_isp.c \ - src/bits.c \ - src/c2t64fx.c \ - src/c4t64fx.c \ - src/convolve.c \ - src/cor_h_x.c \ - src/decim54.c \ - src/deemph.c \ - src/dtx.c \ - src/g_pitch.c \ - src/gpclip.c \ - src/homing.c \ - src/hp400.c \ - src/hp50.c \ - src/hp6k.c \ - src/hp_wsp.c \ - src/int_lpc.c \ - src/isp_az.c \ - src/isp_isf.c \ - src/lag_wind.c \ - src/levinson.c \ - src/log2.c \ - src/lp_dec2.c \ - src/math_op.c \ - src/oper_32b.c \ - src/p_med_ol.c \ - src/pit_shrp.c \ - src/pitch_f4.c \ - src/pred_lt4.c \ - src/preemph.c \ - src/q_gain2.c \ - src/q_pulse.c \ - src/qisf_ns.c \ - src/qpisf_2s.c \ - src/random.c \ - src/residu.c \ - src/scale.c \ - src/stream.c \ - src/syn_filt.c \ - src/updt_tar.c \ - src/util.c \ - src/voAMRWBEnc.c \ - src/voicefac.c \ - src/wb_vad.c \ - src/weight_a.c \ - src/mem_align.c - -ifneq ($(ARCH_ARM_HAVE_NEON),true) - LOCAL_SRC_FILES_arm := \ - src/asm/ARMV5E/convolve_opt.s \ - src/asm/ARMV5E/cor_h_vec_opt.s \ - src/asm/ARMV5E/Deemph_32_opt.s \ - src/asm/ARMV5E/Dot_p_opt.s \ - src/asm/ARMV5E/Filt_6k_7k_opt.s \ - src/asm/ARMV5E/Norm_Corr_opt.s \ - src/asm/ARMV5E/pred_lt4_1_opt.s \ - src/asm/ARMV5E/residu_asm_opt.s \ - src/asm/ARMV5E/scale_sig_opt.s \ - src/asm/ARMV5E/Syn_filt_32_opt.s \ - src/asm/ARMV5E/syn_filt_opt.s - - LOCAL_CFLAGS_arm := -DARM -DASM_OPT - LOCAL_C_INCLUDES_arm = $(LOCAL_PATH)/src/asm/ARMV5E -else - LOCAL_SRC_FILES_arm := \ - src/asm/ARMV7/convolve_neon.s \ - src/asm/ARMV7/cor_h_vec_neon.s \ - src/asm/ARMV7/Deemph_32_neon.s \ - src/asm/ARMV7/Dot_p_neon.s \ - src/asm/ARMV7/Filt_6k_7k_neon.s \ - src/asm/ARMV7/Norm_Corr_neon.s \ - src/asm/ARMV7/pred_lt4_1_neon.s \ - src/asm/ARMV7/residu_asm_neon.s \ - src/asm/ARMV7/scale_sig_neon.s \ - src/asm/ARMV7/Syn_filt_32_neon.s \ - src/asm/ARMV7/syn_filt_neon.s - - # don't actually generate neon instructions, see bug 26932980 - LOCAL_CFLAGS_arm := -DARM -DARMV7 -DASM_OPT -mfpu=vfpv3 - LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/src/asm/ARMV5E - LOCAL_C_INCLUDES_arm += $(LOCAL_PATH)/src/asm/ARMV7 -endif - -LOCAL_MODULE := libstagefright_amrwbenc - -LOCAL_ARM_MODE := arm - -LOCAL_STATIC_LIBRARIES := - -LOCAL_SHARED_LIBRARIES := \ - liblog - -LOCAL_C_INCLUDES := \ - frameworks/av/include \ - frameworks/av/media/libstagefright/include \ - frameworks/av/media/libstagefright/codecs/common/include \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/inc - -LOCAL_CFLAGS += -Werror -#LOCAL_SANITIZE := signed-integer-overflow - -include $(BUILD_STATIC_LIBRARY) - -################################################################################ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - SoftAMRWBEncoder.cpp - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - frameworks/av/media/libstagefright/codecs/common/include \ - frameworks/native/include/media/openmax - -LOCAL_CFLAGS += -Werror -LOCAL_SANITIZE := signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_STATIC_LIBRARIES := \ - libstagefright_amrwbenc - -LOCAL_SHARED_LIBRARIES := \ - libstagefright_omx libstagefright_foundation libutils liblog \ - libstagefright_enc_common - -LOCAL_MODULE := libstagefright_soft_amrwbenc -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) - -################################################################################ -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp new file mode 100644 index 0000000000..d52fed389d --- /dev/null +++ b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp @@ -0,0 +1,28 @@ +cc_test { + name: "AMRWBEncTest", + gtest: false, + + srcs: ["AMRWB_E_SAMPLE.c"], + + arch: { + arm: { + instruction_set: "arm", + }, + }, + + shared_libs: [ + "libdl", + ], + + static_libs: [ + "libstagefright_amrwbenc", + "libstagefright_enc_common", + ], + + sanitize: { + cfi: true, + diag: { + cfi: true, + }, + }, +} diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk deleted file mode 100644 index 0d6549eea7..0000000000 --- a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk +++ /dev/null @@ -1,31 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - AMRWB_E_SAMPLE.c \ - ../../common/cmnMemory.c - -LOCAL_MODULE_TAGS := tests -LOCAL_MODULE := AMRWBEncTest - -LOCAL_ARM_MODE := arm - -LOCAL_CFLAGS := - -LOCAL_SHARED_LIBRARIES := \ - libstagefright \ - libdl \ - liblog - -LOCAL_STATIC_LIBRARIES := \ - libstagefright_amrwbenc - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/ \ - $(LOCAL_PATH)/../../common \ - $(LOCAL_PATH)/../../common/include - -include $(BUILD_EXECUTABLE) - - - diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp index f05f552254..a644b66c33 100644 --- a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp +++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp @@ -59,7 +59,7 @@ SoftAMRWBEncoder::SoftAMRWBEncoder( SoftAMRWBEncoder::~SoftAMRWBEncoder() { if (mEncoderHandle != NULL) { - CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle)); + CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle)); mEncoderHandle = NULL; } @@ -431,7 +431,7 @@ void SoftAMRWBEncoder::onQueueFilled(OMX_U32 /* portIndex */) { inputData.Buffer = (unsigned char *) mInputFrame; inputData.Length = mInputSize; - CHECK_EQ(VO_ERR_NONE, + CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->SetInputData(mEncoderHandle, &inputData)); VO_CODECBUFFER outputData; diff --git a/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c b/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c index b26eedb508..8cebb097bd 100644 --- a/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c +++ b/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c @@ -47,10 +47,6 @@ #include "q_pulse.h" -#undef LOG_TAG -#define LOG_TAG "amrwbenc" -#include <log/log.h> - static Word16 tipos[36] = { 0, 1, 2, 3, /* starting point &ipos[0], 1st iter */ 1, 2, 3, 0, /* starting point &ipos[4], 2nd iter */ @@ -749,16 +745,11 @@ void ACELP_4t64_fx( i = (Word16)((vo_L_mult(track, NPMAXPT) >> 1)); - while (i < NPMAXPT * NB_TRACK && ind[i] >= 0) + while (ind[i] >= 0) { i += 1; } - if (i < NPMAXPT * NB_TRACK) { - ind[i] = index; - } else { - ALOGE("b/132647222, OOB access in ind array track=%d i=%d", track, i); - android_errorWriteLog(0x534e4554, "132647222"); - } + ind[i] = index; } k = 0; diff --git a/media/libstagefright/codecs/avcdec/Android.bp b/media/libstagefright/codecs/avcdec/Android.bp new file mode 100644 index 0000000000..6b996a7b34 --- /dev/null +++ b/media/libstagefright/codecs/avcdec/Android.bp @@ -0,0 +1,33 @@ +cc_library_shared { + name: "libstagefright_soft_avcdec", + + static_libs: ["libavcdec"], + srcs: ["SoftAVCDec.cpp"], + + include_dirs: [ + "external/libavc/decoder", + "external/libavc/common", + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + shared_libs: [ + "libmedia", + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "liblog", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + ldflags: ["-Wl,-Bsymbolic"], +} diff --git a/media/libstagefright/codecs/avcdec/Android.mk b/media/libstagefright/codecs/avcdec/Android.mk deleted file mode 100644 index 8c894fd3ed..0000000000 --- a/media/libstagefright/codecs/avcdec/Android.mk +++ /dev/null @@ -1,31 +0,0 @@ -#ifeq ($(if $(wildcard external/libh264),1,0),1) - -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE := libstagefright_soft_avcdec -LOCAL_MODULE_TAGS := optional - -LOCAL_STATIC_LIBRARIES := libavcdec -LOCAL_SRC_FILES := SoftAVCDec.cpp - -LOCAL_C_INCLUDES := $(TOP)/external/libavc/decoder -LOCAL_C_INCLUDES += $(TOP)/external/libavc/common -LOCAL_C_INCLUDES += $(TOP)/frameworks/av/media/libstagefright/include -LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax - -LOCAL_SHARED_LIBRARIES := libmedia -LOCAL_SHARED_LIBRARIES += libstagefright_omx -LOCAL_SHARED_LIBRARIES += libstagefright_foundation -LOCAL_SHARED_LIBRARIES += libutils -LOCAL_SHARED_LIBRARIES += liblog - -LOCAL_SANITIZE := signed-integer-overflow cfi - -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_LDFLAGS := -Wl,-Bsymbolic - -include $(BUILD_SHARED_LIBRARY) - -#endif diff --git a/media/libstagefright/codecs/avcenc/Android.bp b/media/libstagefright/codecs/avcenc/Android.bp new file mode 100644 index 0000000000..49021a94c2 --- /dev/null +++ b/media/libstagefright/codecs/avcenc/Android.bp @@ -0,0 +1,33 @@ +cc_library_shared { + name: "libstagefright_soft_avcenc", + + static_libs: ["libavcenc"], + srcs: ["SoftAVCEnc.cpp"], + + include_dirs: [ + "external/libavc/encoder", + "external/libavc/common", + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/hardware", + "frameworks/native/include/media/openmax", + ], + + shared_libs: [ + "libmedia", + "libstagefright_omx", + "libutils", + "liblog", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + ldflags: ["-Wl,-Bsymbolic"], +} diff --git a/media/libstagefright/codecs/avcenc/Android.mk b/media/libstagefright/codecs/avcenc/Android.mk deleted file mode 100644 index 23ba2082be..0000000000 --- a/media/libstagefright/codecs/avcenc/Android.mk +++ /dev/null @@ -1,31 +0,0 @@ -#ifeq ($(if $(wildcard external/libh264),1,0),1) - -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE := libstagefright_soft_avcenc -LOCAL_MODULE_TAGS := optional - -LOCAL_STATIC_LIBRARIES := libavcenc -LOCAL_SRC_FILES := SoftAVCEnc.cpp - -LOCAL_C_INCLUDES := $(TOP)/external/libavc/encoder -LOCAL_C_INCLUDES += $(TOP)/external/libavc/common -LOCAL_C_INCLUDES += $(TOP)/frameworks/av/media/libstagefright/include -LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/hardware -LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax - -LOCAL_SHARED_LIBRARIES := libmedia -LOCAL_SHARED_LIBRARIES += libstagefright_omx -LOCAL_SHARED_LIBRARIES += libutils -LOCAL_SHARED_LIBRARIES += liblog - -LOCAL_SANITIZE := signed-integer-overflow cfi - -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_LDFLAGS := -Wl,-Bsymbolic - -include $(BUILD_SHARED_LIBRARY) - -#endif diff --git a/media/libstagefright/codecs/common/Android.bp b/media/libstagefright/codecs/common/Android.bp new file mode 100644 index 0000000000..021e6af5f2 --- /dev/null +++ b/media/libstagefright/codecs/common/Android.bp @@ -0,0 +1,15 @@ +cc_library { + name: "libstagefright_enc_common", + + srcs: ["cmnMemory.c"], + + arch: { + arm: { + instruction_set: "arm", + }, + }, + + export_include_dirs: ["include"], + + cflags: ["-Werror"], +} diff --git a/media/libstagefright/codecs/common/Android.mk b/media/libstagefright/codecs/common/Android.mk deleted file mode 100644 index b0010ff1bb..0000000000 --- a/media/libstagefright/codecs/common/Android.mk +++ /dev/null @@ -1,22 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - - - -LOCAL_SRC_FILES := cmnMemory.c - -LOCAL_MODULE := libstagefright_enc_common - -LOCAL_ARM_MODE := arm - -LOCAL_STATIC_LIBRARIES := - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/include - -LOCAL_CFLAGS += -Werror - -include $(BUILD_SHARED_LIBRARY) - - - diff --git a/media/libstagefright/codecs/flac/Android.bp b/media/libstagefright/codecs/flac/Android.bp new file mode 100644 index 0000000000..b44c296012 --- /dev/null +++ b/media/libstagefright/codecs/flac/Android.bp @@ -0,0 +1 @@ +subdirs = ["*"] diff --git a/media/libstagefright/codecs/flac/Android.mk b/media/libstagefright/codecs/flac/Android.mk deleted file mode 100644 index 2e431205aa..0000000000 --- a/media/libstagefright/codecs/flac/Android.mk +++ /dev/null @@ -1,4 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media/libstagefright/codecs/flac/dec/Android.bp b/media/libstagefright/codecs/flac/dec/Android.bp new file mode 100644 index 0000000000..6ac264d438 --- /dev/null +++ b/media/libstagefright/codecs/flac/dec/Android.bp @@ -0,0 +1,36 @@ +cc_library_shared { + name: "libstagefright_soft_flacdec", + + srcs: [ + "SoftFlacDecoder.cpp", + ], + + include_dirs: [ + "external/flac/include", + "frameworks/av/media/libstagefright/flac/dec", + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + cflags: ["-Werror"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + shared_libs: [ + "libcutils", + "liblog", + "libstagefright_flacdec", + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + ], +} diff --git a/media/libstagefright/codecs/flac/dec/MODULE_LICENSE_APACHE2 b/media/libstagefright/codecs/flac/dec/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/media/libstagefright/codecs/flac/dec/MODULE_LICENSE_APACHE2 diff --git a/media/libstagefright/codecs/flac/dec/NOTICE b/media/libstagefright/codecs/flac/dec/NOTICE new file mode 100644 index 0000000000..c5b1efa7aa --- /dev/null +++ b/media/libstagefright/codecs/flac/dec/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, 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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp new file mode 100644 index 0000000000..cff4a33d0b --- /dev/null +++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SoftFlacDecoder" +#include <utils/Log.h> + +#include "SoftFlacDecoder.h" +#include <OMX_AudioExt.h> +#include <OMX_IndexExt.h> + +#include <cutils/properties.h> +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/MediaErrors.h> +#include <utils/misc.h> + +namespace android { + +template<class T> +static void InitOMXParams(T *params) { + params->nSize = sizeof(T); + params->nVersion.s.nVersionMajor = 1; + params->nVersion.s.nVersionMinor = 0; + params->nVersion.s.nRevision = 0; + params->nVersion.s.nStep = 0; +} + +SoftFlacDecoder::SoftFlacDecoder( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component) + : SimpleSoftOMXComponent(name, callbacks, appData, component), + mFLACDecoder(NULL), + mHasStreamInfo(false), + mInputBufferCount(0), + mSignalledError(false), + mOutputPortSettingsChange(NONE) { + ALOGV("ctor:"); + memset(&mStreamInfo, 0, sizeof(mStreamInfo)); + initPorts(); + initDecoder(); +} + +SoftFlacDecoder::~SoftFlacDecoder() { + ALOGV("dtor:"); +} + +void SoftFlacDecoder::initPorts() { + ALOGV("initPorts:"); + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + + def.nPortIndex = 0; + def.eDir = OMX_DirInput; + def.nBufferCountMin = kNumInputBuffers; + def.nBufferCountActual = def.nBufferCountMin; + def.nBufferSize = 32768; + def.bEnabled = OMX_TRUE; + def.bPopulated = OMX_FALSE; + def.eDomain = OMX_PortDomainAudio; + def.bBuffersContiguous = OMX_FALSE; + def.nBufferAlignment = 1; + + def.format.audio.cMIMEType = const_cast<char *>("audio/flac"); + def.format.audio.pNativeRender = NULL; + def.format.audio.bFlagErrorConcealment = OMX_FALSE; + def.format.audio.eEncoding = OMX_AUDIO_CodingFLAC; + + addPort(def); + + def.nPortIndex = 1; + def.eDir = OMX_DirOutput; + def.nBufferCountMin = kNumOutputBuffers; + def.nBufferCountActual = def.nBufferCountMin; + def.nBufferSize = 4096 * FLACDecoder::kMaxChannels; + def.bEnabled = OMX_TRUE; + def.bPopulated = OMX_FALSE; + def.eDomain = OMX_PortDomainAudio; + def.bBuffersContiguous = OMX_FALSE; + def.nBufferAlignment = 2; + + def.format.audio.cMIMEType = const_cast<char *>("audio/raw"); + def.format.audio.pNativeRender = NULL; + def.format.audio.bFlagErrorConcealment = OMX_FALSE; + def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; + + addPort(def); +} + +void SoftFlacDecoder::initDecoder() { + ALOGV("initDecoder:"); + mFLACDecoder = FLACDecoder::Create(); + if (mFLACDecoder == NULL) { + ALOGE("initDecoder: failed to create FLACDecoder"); + mSignalledError = true; + } +} + +OMX_ERRORTYPE SoftFlacDecoder::initCheck() const { + if (mSignalledError) { + if (mFLACDecoder == NULL) { + ALOGE("initCheck: failed due to NULL encoder"); + return OMX_ErrorDynamicResourcesUnavailable; + } + return OMX_ErrorUndefined; + } + + return SimpleSoftOMXComponent::initCheck(); +} + +OMX_ERRORTYPE SoftFlacDecoder::internalGetParameter( + OMX_INDEXTYPE index, OMX_PTR params) { + ALOGV("internalGetParameter: index(%x)", index); + switch ((OMX_U32)index) { + case OMX_IndexParamAudioFlac: + { + OMX_AUDIO_PARAM_FLACTYPE *flacParams = + (OMX_AUDIO_PARAM_FLACTYPE *)params; + + if (!isValidOMXParam(flacParams)) { + ALOGE("internalGetParameter(OMX_IndexParamAudioFlac): invalid omx params"); + return OMX_ErrorBadParameter; + } + + if (flacParams->nPortIndex != 0) { + ALOGE("internalGetParameter(OMX_IndexParamAudioFlac): bad port index"); + return OMX_ErrorBadPortIndex; + } + + flacParams->nCompressionLevel = 0; + + if (isConfigured()) { + flacParams->nChannels = mStreamInfo.channels; + flacParams->nSampleRate = mStreamInfo.sample_rate; + } else { + flacParams->nChannels = 1; + flacParams->nSampleRate = 44100; + } + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioPcm: + { + OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = + (OMX_AUDIO_PARAM_PCMMODETYPE *)params; + + if (!isValidOMXParam(pcmParams)) { + ALOGE("internalGetParameter(OMX_IndexParamAudioPcm): invalid omx params"); + return OMX_ErrorBadParameter; + } + + if (pcmParams->nPortIndex != 1) { + ALOGE("internalGetParameter(OMX_IndexParamAudioPcm): bad port index"); + return OMX_ErrorBadPortIndex; + } + + pcmParams->eNumData = OMX_NumericalDataSigned; + pcmParams->eEndian = OMX_EndianBig; + pcmParams->bInterleaved = OMX_TRUE; + pcmParams->nBitPerSample = 16; + pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; + pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; + pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; + pcmParams->eChannelMapping[2] = OMX_AUDIO_ChannelCF; + pcmParams->eChannelMapping[3] = OMX_AUDIO_ChannelLFE; + pcmParams->eChannelMapping[4] = OMX_AUDIO_ChannelLS; + pcmParams->eChannelMapping[5] = OMX_AUDIO_ChannelRS; + + if (isConfigured()) { + pcmParams->nChannels = mStreamInfo.channels; + pcmParams->nSamplingRate = mStreamInfo.sample_rate; + } else { + pcmParams->nChannels = 1; + pcmParams->nSamplingRate = 44100; + } + + return OMX_ErrorNone; + } + + default: + return SimpleSoftOMXComponent::internalGetParameter(index, params); + } +} + +OMX_ERRORTYPE SoftFlacDecoder::internalSetParameter( + OMX_INDEXTYPE index, const OMX_PTR params) { + ALOGV("internalSetParameter: index(%x)", (int)index); + switch ((int)index) { + case OMX_IndexParamStandardComponentRole: + { + const OMX_PARAM_COMPONENTROLETYPE *roleParams = + (const OMX_PARAM_COMPONENTROLETYPE *)params; + + if (!isValidOMXParam(roleParams)) { + return OMX_ErrorBadParameter; + } + + if (strncmp((const char *)roleParams->cRole, + "audio_decoder.flac", + OMX_MAX_STRINGNAME_SIZE - 1) != 0) { + return OMX_ErrorInvalidComponentName; + } + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioPcm: + { + const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = + (OMX_AUDIO_PARAM_PCMMODETYPE *)params; + + if (!isValidOMXParam(pcmParams)) { + return OMX_ErrorBadParameter; + } + + if (pcmParams->nPortIndex != 1) { + return OMX_ErrorBadPortIndex; + } + + return OMX_ErrorNone; + } + + default: + return SimpleSoftOMXComponent::internalSetParameter(index, params); + } +} + +bool SoftFlacDecoder::isConfigured() const { + return mHasStreamInfo; +} + +void SoftFlacDecoder::onQueueFilled(OMX_U32 /* portIndex */) { + ALOGV("onQueueFilled:"); + if (mSignalledError || mOutputPortSettingsChange != NONE) { + return; + } + + List<BufferInfo *> &inQueue = getPortQueue(0); + List<BufferInfo *> &outQueue = getPortQueue(1); + + while (!inQueue.empty() && !outQueue.empty()) { + BufferInfo *inInfo = *inQueue.begin(); + OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; + uint8_t* inBuffer = inHeader->pBuffer + inHeader->nOffset; + uint32_t inBufferLength = inHeader->nFilledLen; + bool endOfInput = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0; + + if (mInputBufferCount == 0 && !(inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) { + ALOGE("onQueueFilled: first buffer should have OMX_BUFFERFLAG_CODECCONFIG set"); + inHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG; + } + if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) != 0) { + status_t decoderErr = mFLACDecoder->parseMetadata(inBuffer, inBufferLength); + mInputBufferCount++; + + if (decoderErr != OK && decoderErr != WOULD_BLOCK) { + ALOGE("onQueueFilled: FLACDecoder parseMetaData returns error %d", decoderErr); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorStreamCorrupt, decoderErr, NULL); + return; + } + + inInfo->mOwnedByUs = false; + inQueue.erase(inQueue.begin()); + notifyEmptyBufferDone(inHeader); + + if (decoderErr == WOULD_BLOCK) { + continue; + } + mStreamInfo = mFLACDecoder->getStreamInfo(); + mHasStreamInfo = true; + + // Only send out port settings changed event if both sample rate + // and numChannels are valid. + if (mStreamInfo.sample_rate && mStreamInfo.channels) { + ALOGD("onQueueFilled: initially configuring decoder: %d Hz, %d channels", + mStreamInfo.sample_rate, mStreamInfo.channels); + + notify(OMX_EventPortSettingsChanged, 1, 0, NULL); + mOutputPortSettingsChange = AWAITING_DISABLED; + } + return; + } + + BufferInfo *outInfo = *outQueue.begin(); + OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; + short *outBuffer = + reinterpret_cast<short *>(outHeader->pBuffer + outHeader->nOffset); + size_t outBufferSize = outHeader->nAllocLen - outHeader->nOffset; + + status_t decoderErr = mFLACDecoder->decodeOneFrame( + inBuffer, inBufferLength, outBuffer, &outBufferSize); + if (decoderErr != OK) { + ALOGE("onQueueFilled: FLACDecoder decodeOneFrame returns error %d", decoderErr); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorStreamCorrupt, decoderErr, NULL); + return; + } + + mInputBufferCount++; + int64_t ts = inHeader->nTimeStamp; + inInfo->mOwnedByUs = false; + inQueue.erase(inQueue.begin()); + notifyEmptyBufferDone(inHeader); + + if (endOfInput) { + outHeader->nFlags = OMX_BUFFERFLAG_EOS; + } else if (outBufferSize == 0) { + continue; + } else { + outHeader->nFlags = 0; + } + + outHeader->nFilledLen = outBufferSize; + outHeader->nTimeStamp = ts; + + outInfo->mOwnedByUs = false; + outQueue.erase(outQueue.begin()); + notifyFillBufferDone(outHeader); + } +} + +void SoftFlacDecoder::onPortFlushCompleted(OMX_U32 portIndex) { + ALOGV("onPortFlushCompleted: portIndex(%u)", portIndex); + if (portIndex == 0) { + drainDecoder(); + } +} + +void SoftFlacDecoder::drainDecoder() { + mFLACDecoder->flush(); +} + +void SoftFlacDecoder::onReset() { + drainDecoder(); + + memset(&mStreamInfo, 0, sizeof(mStreamInfo)); + mHasStreamInfo = false; + mInputBufferCount = 0; + mSignalledError = false; + mOutputPortSettingsChange = NONE; +} + +void SoftFlacDecoder::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { + ALOGV("onPortEnableCompleted: portIndex(%u), enabled(%d)", portIndex, enabled); + if (portIndex != 1) { + return; + } + + switch (mOutputPortSettingsChange) { + case NONE: + break; + + case AWAITING_DISABLED: + { + CHECK(!enabled); + mOutputPortSettingsChange = AWAITING_ENABLED; + PortInfo *info = editPortInfo(1 /* portIndex */); + if (!info->mDef.bEnabled) { + info->mDef.nBufferSize = mStreamInfo.max_blocksize * mStreamInfo.channels * 2; + } + break; + } + + default: + { + CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); + CHECK(enabled); + mOutputPortSettingsChange = NONE; + break; + } + } +} + +} // namespace android + +android::SoftOMXComponent *createSoftOMXComponent( + const char *name, const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, OMX_COMPONENTTYPE **component) { + ALOGV("createSoftOMXComponent: flac decoder"); + return new android::SoftFlacDecoder(name, callbacks, appData, component); +} diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h new file mode 100644 index 0000000000..c09081d595 --- /dev/null +++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SOFT_FLAC_DECODER_H +#define SOFT_FLAC_DECODER_H + +#include "FLACDecoder.h" +#include "SimpleSoftOMXComponent.h" + +namespace android { + +struct SoftFlacDecoder : public SimpleSoftOMXComponent { + SoftFlacDecoder(const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component); + + virtual OMX_ERRORTYPE initCheck() const override; + +protected: + virtual ~SoftFlacDecoder(); + + virtual OMX_ERRORTYPE internalGetParameter( + OMX_INDEXTYPE index, OMX_PTR params) override; + + virtual OMX_ERRORTYPE internalSetParameter( + OMX_INDEXTYPE index, const OMX_PTR params) override; + + virtual void onQueueFilled(OMX_U32 portIndex); + virtual void onPortFlushCompleted(OMX_U32 portIndex) override; + virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled) override; + virtual void onReset() override; + +private: + enum { + kNumInputBuffers = 4, + kNumOutputBuffers = 4, + }; + + sp<FLACDecoder> mFLACDecoder; + FLAC__StreamMetadata_StreamInfo mStreamInfo; + bool mHasStreamInfo; + size_t mInputBufferCount; + bool mSignalledError; + + enum { + NONE, + AWAITING_DISABLED, + AWAITING_ENABLED + } mOutputPortSettingsChange; + + void initPorts(); + void initDecoder(); + bool isConfigured() const; + void drainDecoder(); + + DISALLOW_EVIL_CONSTRUCTORS(SoftFlacDecoder); +}; + +} // namespace android + +#endif // SOFT_FLAC_DECODER_H diff --git a/media/libstagefright/codecs/flac/enc/Android.bp b/media/libstagefright/codecs/flac/enc/Android.bp new file mode 100644 index 0000000000..d1413f64be --- /dev/null +++ b/media/libstagefright/codecs/flac/enc/Android.bp @@ -0,0 +1,36 @@ +cc_library_shared { + + srcs: ["SoftFlacEncoder.cpp"], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + "external/flac/include", + ], + + cflags: ["-Werror"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + shared_libs: [ + "libmedia", + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "liblog", + ], + + static_libs: ["libFLAC"], + + name: "libstagefright_soft_flacenc", + +} diff --git a/media/libstagefright/codecs/flac/enc/Android.mk b/media/libstagefright/codecs/flac/enc/Android.mk deleted file mode 100644 index 8031bf6543..0000000000 --- a/media/libstagefright/codecs/flac/enc/Android.mk +++ /dev/null @@ -1,25 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - SoftFlacEncoder.cpp - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - frameworks/native/include/media/openmax \ - external/flac/include - -LOCAL_CFLAGS += -Werror -LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_SHARED_LIBRARIES := \ - libmedia libstagefright_omx libstagefright_foundation libutils liblog - -LOCAL_STATIC_LIBRARIES := \ - libFLAC \ - -LOCAL_MODULE := libstagefright_soft_flacenc -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h index 97361fa1c6..6027f76688 100644 --- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h +++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h @@ -48,13 +48,10 @@ protected: virtual void onQueueFilled(OMX_U32 portIndex); private: - - enum { - kNumBuffers = 2, - kMaxNumSamplesPerFrame = 1152, - kMaxInputBufferSize = kMaxNumSamplesPerFrame * sizeof(int16_t) * 2, - kMaxOutputBufferSize = 65536, //TODO check if this can be reduced - }; + const unsigned int kNumBuffers = 2; + const unsigned int kMaxNumSamplesPerFrame = 1152; + const unsigned int kMaxInputBufferSize = kMaxNumSamplesPerFrame * sizeof(int16_t) * 2; + const unsigned int kMaxOutputBufferSize = 65536; //TODO check if this can be reduced bool mSignalledError; diff --git a/media/libstagefright/codecs/g711/Android.bp b/media/libstagefright/codecs/g711/Android.bp new file mode 100644 index 0000000000..b44c296012 --- /dev/null +++ b/media/libstagefright/codecs/g711/Android.bp @@ -0,0 +1 @@ +subdirs = ["*"] diff --git a/media/libstagefright/codecs/g711/Android.mk b/media/libstagefright/codecs/g711/Android.mk deleted file mode 100644 index 2e431205aa..0000000000 --- a/media/libstagefright/codecs/g711/Android.mk +++ /dev/null @@ -1,4 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media/libstagefright/codecs/g711/dec/Android.bp b/media/libstagefright/codecs/g711/dec/Android.bp new file mode 100644 index 0000000000..b78b689b1d --- /dev/null +++ b/media/libstagefright/codecs/g711/dec/Android.bp @@ -0,0 +1,30 @@ +cc_library_shared { + name: "libstagefright_soft_g711dec", + + srcs: ["SoftG711.cpp"], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + shared_libs: [ + "libmedia", + "libstagefright_omx", + "libutils", + "liblog", + ], + + cflags: ["-Werror"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, +} diff --git a/media/libstagefright/codecs/g711/dec/Android.mk b/media/libstagefright/codecs/g711/dec/Android.mk deleted file mode 100644 index b9a1f8caaf..0000000000 --- a/media/libstagefright/codecs/g711/dec/Android.mk +++ /dev/null @@ -1,21 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - SoftG711.cpp - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - frameworks/native/include/media/openmax - -LOCAL_SHARED_LIBRARIES := \ - libmedia libstagefright_omx libutils liblog - -LOCAL_MODULE := libstagefright_soft_g711dec -LOCAL_MODULE_TAGS := optional - -LOCAL_CFLAGS += -Werror -LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/gsm/Android.bp b/media/libstagefright/codecs/gsm/Android.bp new file mode 100644 index 0000000000..b44c296012 --- /dev/null +++ b/media/libstagefright/codecs/gsm/Android.bp @@ -0,0 +1 @@ +subdirs = ["*"] diff --git a/media/libstagefright/codecs/gsm/Android.mk b/media/libstagefright/codecs/gsm/Android.mk deleted file mode 100644 index 2e431205aa..0000000000 --- a/media/libstagefright/codecs/gsm/Android.mk +++ /dev/null @@ -1,4 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media/libstagefright/codecs/gsm/dec/Android.bp b/media/libstagefright/codecs/gsm/dec/Android.bp new file mode 100644 index 0000000000..8e86ad603a --- /dev/null +++ b/media/libstagefright/codecs/gsm/dec/Android.bp @@ -0,0 +1,33 @@ +cc_library_shared { + name: "libstagefright_soft_gsmdec", + + srcs: ["SoftGSM.cpp"], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + "external/libgsm/inc", + ], + + cflags: ["-Werror"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + shared_libs: [ + "libmedia", + "libstagefright_omx", + "libutils", + "liblog", + ], + + static_libs: ["libgsm"], +} diff --git a/media/libstagefright/codecs/gsm/dec/Android.mk b/media/libstagefright/codecs/gsm/dec/Android.mk deleted file mode 100644 index 401b56c2cc..0000000000 --- a/media/libstagefright/codecs/gsm/dec/Android.mk +++ /dev/null @@ -1,25 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - SoftGSM.cpp - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - frameworks/native/include/media/openmax \ - external/libgsm/inc - -LOCAL_CFLAGS += -Werror -LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_SHARED_LIBRARIES := \ - libmedia libstagefright_omx libutils liblog - -LOCAL_STATIC_LIBRARIES := \ - libgsm - -LOCAL_MODULE := libstagefright_soft_gsmdec -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/hevcdec/Android.bp b/media/libstagefright/codecs/hevcdec/Android.bp new file mode 100644 index 0000000000..cd75c97c79 --- /dev/null +++ b/media/libstagefright/codecs/hevcdec/Android.bp @@ -0,0 +1,36 @@ +cc_library_shared { + name: "libstagefright_soft_hevcdec", + + static_libs: ["libhevcdec"], + srcs: ["SoftHEVC.cpp"], + + include_dirs: [ + "external/libhevc/decoder", + "external/libhevc/common", + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + shared_libs: [ + "libmedia", + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "liblog", + ], + + // We need this because the current asm generates the following link error: + // requires unsupported dynamic reloc R_ARM_REL32; recompile with -fPIC + // Bug: 16853291 + ldflags: ["-Wl,-Bsymbolic"], +} diff --git a/media/libstagefright/codecs/hevcdec/Android.mk b/media/libstagefright/codecs/hevcdec/Android.mk deleted file mode 100644 index 11c1b89119..0000000000 --- a/media/libstagefright/codecs/hevcdec/Android.mk +++ /dev/null @@ -1,32 +0,0 @@ -ifeq ($(if $(wildcard external/libhevc),1,0),1) - -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE := libstagefright_soft_hevcdec -LOCAL_MODULE_TAGS := optional - -LOCAL_STATIC_LIBRARIES := libhevcdec -LOCAL_SRC_FILES := SoftHEVC.cpp - -LOCAL_C_INCLUDES := $(TOP)/external/libhevc/decoder -LOCAL_C_INCLUDES += $(TOP)/external/libhevc/common -LOCAL_C_INCLUDES += $(TOP)/frameworks/av/media/libstagefright/include -LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax -LOCAL_SANITIZE := signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_SHARED_LIBRARIES := libmedia -LOCAL_SHARED_LIBRARIES += libstagefright_omx -LOCAL_SHARED_LIBRARIES += libstagefright_foundation -LOCAL_SHARED_LIBRARIES += libutils -LOCAL_SHARED_LIBRARIES += liblog - -# We need this because the current asm generates the following link error: -# requires unsupported dynamic reloc R_ARM_REL32; recompile with -fPIC -# Bug: 16853291 -LOCAL_LDFLAGS := -Wl,-Bsymbolic - -include $(BUILD_SHARED_LIBRARY) - -endif diff --git a/media/libstagefright/codecs/m4v_h263/Android.bp b/media/libstagefright/codecs/m4v_h263/Android.bp new file mode 100644 index 0000000000..b44c296012 --- /dev/null +++ b/media/libstagefright/codecs/m4v_h263/Android.bp @@ -0,0 +1 @@ +subdirs = ["*"] diff --git a/media/libstagefright/codecs/m4v_h263/Android.mk b/media/libstagefright/codecs/m4v_h263/Android.mk deleted file mode 100644 index 2e431205aa..0000000000 --- a/media/libstagefright/codecs/m4v_h263/Android.mk +++ /dev/null @@ -1,4 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.bp b/media/libstagefright/codecs/m4v_h263/dec/Android.bp new file mode 100644 index 0000000000..04ea075bce --- /dev/null +++ b/media/libstagefright/codecs/m4v_h263/dec/Android.bp @@ -0,0 +1,106 @@ +cc_library_static { + name: "libstagefright_m4vh263dec", + + srcs: [ + "src/adaptive_smooth_no_mmx.cpp", + "src/bitstream.cpp", + "src/block_idct.cpp", + "src/cal_dc_scaler.cpp", + "src/chvr_filter.cpp", + "src/chv_filter.cpp", + "src/combined_decode.cpp", + "src/conceal.cpp", + "src/datapart_decode.cpp", + "src/dcac_prediction.cpp", + "src/dec_pred_intra_dc.cpp", + "src/deringing_chroma.cpp", + "src/deringing_luma.cpp", + "src/find_min_max.cpp", + "src/get_pred_adv_b_add.cpp", + "src/get_pred_outside.cpp", + "src/idct.cpp", + "src/idct_vca.cpp", + "src/mb_motion_comp.cpp", + "src/mb_utils.cpp", + "src/packet_util.cpp", + "src/post_filter.cpp", + "src/post_proc_semaphore.cpp", + "src/pp_semaphore_chroma_inter.cpp", + "src/pp_semaphore_luma.cpp", + "src/pvdec_api.cpp", + "src/scaling_tab.cpp", + "src/vlc_decode.cpp", + "src/vlc_dequant.cpp", + "src/vlc_tab.cpp", + "src/vop.cpp", + "src/zigzag_tab.cpp", + ], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + local_include_dirs: ["src"], + export_include_dirs: ["include"], + + cflags: [ + "-DOSCL_EXPORT_REF=", + "-DOSCL_IMPORT_REF=", + + "-Werror", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, +} + +//############################################################################### + +cc_library_shared { + name: "libstagefright_soft_mpeg4dec", + + srcs: ["SoftMPEG4.cpp"], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + local_include_dirs: ["src"], + export_include_dirs: ["include"], + + cflags: [ + "-DOSCL_EXPORT_REF=", + "-DOSCL_IMPORT_REF=", + + "-Werror", + ], + + static_libs: ["libstagefright_m4vh263dec"], + + shared_libs: [ + "libmedia", + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "liblog", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, +} diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.mk b/media/libstagefright/codecs/m4v_h263/dec/Android.mk deleted file mode 100644 index c20dc4d6a6..0000000000 --- a/media/libstagefright/codecs/m4v_h263/dec/Android.mk +++ /dev/null @@ -1,82 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - src/adaptive_smooth_no_mmx.cpp \ - src/bitstream.cpp \ - src/block_idct.cpp \ - src/cal_dc_scaler.cpp \ - src/chvr_filter.cpp \ - src/chv_filter.cpp \ - src/combined_decode.cpp \ - src/conceal.cpp \ - src/datapart_decode.cpp \ - src/dcac_prediction.cpp \ - src/dec_pred_intra_dc.cpp \ - src/deringing_chroma.cpp \ - src/deringing_luma.cpp \ - src/find_min_max.cpp \ - src/get_pred_adv_b_add.cpp \ - src/get_pred_outside.cpp \ - src/idct.cpp \ - src/idct_vca.cpp \ - src/mb_motion_comp.cpp \ - src/mb_utils.cpp \ - src/packet_util.cpp \ - src/post_filter.cpp \ - src/post_proc_semaphore.cpp \ - src/pp_semaphore_chroma_inter.cpp \ - src/pp_semaphore_luma.cpp \ - src/pvdec_api.cpp \ - src/scaling_tab.cpp \ - src/vlc_decode.cpp \ - src/vlc_dequant.cpp \ - src/vlc_tab.cpp \ - src/vop.cpp \ - src/zigzag_tab.cpp - - -LOCAL_MODULE := libstagefright_m4vh263dec - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/include \ - $(TOP)/frameworks/av/media/libstagefright/include \ - $(TOP)/frameworks/native/include/media/openmax - -LOCAL_CFLAGS := -DOSCL_EXPORT_REF= -DOSCL_IMPORT_REF= - -LOCAL_CFLAGS += -Werror -LOCAL_SANITIZE := signed-integer-overflow - -include $(BUILD_STATIC_LIBRARY) - -################################################################################ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - SoftMPEG4.cpp - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/include \ - frameworks/av/media/libstagefright/include \ - frameworks/native/include/media/openmax - -LOCAL_CFLAGS := -DOSCL_EXPORT_REF= -DOSCL_IMPORT_REF= - -LOCAL_STATIC_LIBRARIES := \ - libstagefright_m4vh263dec - -LOCAL_SHARED_LIBRARIES := \ - libmedia libstagefright_omx libstagefright_foundation libutils liblog - -LOCAL_MODULE := libstagefright_soft_mpeg4dec -LOCAL_MODULE_TAGS := optional - -LOCAL_CFLAGS += -Werror -LOCAL_SANITIZE := signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.bp b/media/libstagefright/codecs/m4v_h263/enc/Android.bp new file mode 100644 index 0000000000..da5b1623e5 --- /dev/null +++ b/media/libstagefright/codecs/m4v_h263/enc/Android.bp @@ -0,0 +1,122 @@ +cc_library_static { + name: "libstagefright_m4vh263enc", + + srcs: [ + "src/bitstream_io.cpp", + "src/combined_encode.cpp", + "src/datapart_encode.cpp", + "src/dct.cpp", + "src/findhalfpel.cpp", + "src/fastcodemb.cpp", + "src/fastidct.cpp", + "src/fastquant.cpp", + "src/me_utils.cpp", + "src/mp4enc_api.cpp", + "src/rate_control.cpp", + "src/motion_est.cpp", + "src/motion_comp.cpp", + "src/sad.cpp", + "src/sad_halfpel.cpp", + "src/vlc_encode.cpp", + "src/vop.cpp", + ], + + cflags: [ + "-DBX_RC", + "-DOSCL_IMPORT_REF=", + "-DOSCL_UNUSED_ARG(x)=(void)(x)", + "-DOSCL_EXPORT_REF=", + + "-Werror", + ], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + local_include_dirs: ["src"], + export_include_dirs: ["include"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, +} + +//############################################################################### + +cc_library_shared { + name: "libstagefright_soft_mpeg4enc", + + srcs: ["SoftMPEG4Encoder.cpp"], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + "frameworks/native/include/media/hardware", + ], + local_include_dirs: ["src"], + export_include_dirs: ["include"], + + cflags: [ + "-DBX_RC", + "-DOSCL_IMPORT_REF=", + "-DOSCL_UNUSED_ARG(x)=(void)(x)", + "-DOSCL_EXPORT_REF=", + + "-Werror", + ], + + static_libs: ["libstagefright_m4vh263enc"], + + shared_libs: [ + "libmedia", + "libstagefright_omx", + "libutils", + "liblog", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, +} + +//############################################################################### + +cc_test { + name: "libstagefright_m4vh263enc_test", + gtest: false, + + srcs: ["test/m4v_h263_enc_test.cpp"], + + local_include_dirs: ["src"], + + cflags: [ + "-DOSCL_EXPORT_REF=", + "-DOSCL_IMPORT_REF=", + "-DBX_RC", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + static_libs: ["libstagefright_m4vh263enc"], +} diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.mk b/media/libstagefright/codecs/m4v_h263/enc/Android.mk deleted file mode 100644 index f950052699..0000000000 --- a/media/libstagefright/codecs/m4v_h263/enc/Android.mk +++ /dev/null @@ -1,99 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - src/bitstream_io.cpp \ - src/combined_encode.cpp \ - src/datapart_encode.cpp \ - src/dct.cpp \ - src/findhalfpel.cpp \ - src/fastcodemb.cpp \ - src/fastidct.cpp \ - src/fastquant.cpp \ - src/me_utils.cpp \ - src/mp4enc_api.cpp \ - src/rate_control.cpp \ - src/motion_est.cpp \ - src/motion_comp.cpp \ - src/sad.cpp \ - src/sad_halfpel.cpp \ - src/vlc_encode.cpp \ - src/vop.cpp - - -LOCAL_MODULE := libstagefright_m4vh263enc - -LOCAL_CFLAGS := \ - -DBX_RC \ - -DOSCL_IMPORT_REF= -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_EXPORT_REF= - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/include \ - $(TOP)/frameworks/av/media/libstagefright/include \ - $(TOP)/frameworks/native/include/media/openmax - -LOCAL_CFLAGS += -Werror -LOCAL_SANITIZE := signed-integer-overflow - -include $(BUILD_STATIC_LIBRARY) - -################################################################################ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - SoftMPEG4Encoder.cpp - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - frameworks/native/include/media/openmax \ - frameworks/native/include/media/hardware \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/include \ - $(LOCAL_PATH)/../common/include \ - $(LOCAL_PATH)/../common - -LOCAL_CFLAGS := \ - -DBX_RC \ - -DOSCL_IMPORT_REF= -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_EXPORT_REF= - - -LOCAL_STATIC_LIBRARIES := \ - libstagefright_m4vh263enc - -LOCAL_SHARED_LIBRARIES := \ - libmedia \ - libstagefright_omx \ - libutils \ - liblog \ - -LOCAL_MODULE := libstagefright_soft_mpeg4enc -LOCAL_MODULE_TAGS := optional - -LOCAL_CFLAGS += -Werror -LOCAL_SANITIZE := signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -include $(BUILD_SHARED_LIBRARY) - -################################################################################ - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := \ - test/m4v_h263_enc_test.cpp - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/include - -LOCAL_CFLAGS := -DOSCL_EXPORT_REF= -DOSCL_IMPORT_REF= -DBX_RC -LOCAL_SANITIZE := signed-integer-overflow - -LOCAL_STATIC_LIBRARIES := \ - libstagefright_m4vh263enc - -LOCAL_MODULE := libstagefright_m4vh263enc_test -LOCAL_MODULE_TAGS := tests - -include $(BUILD_EXECUTABLE) diff --git a/media/libstagefright/codecs/mp3dec/Android.bp b/media/libstagefright/codecs/mp3dec/Android.bp new file mode 100644 index 0000000000..0d0a2c6569 --- /dev/null +++ b/media/libstagefright/codecs/mp3dec/Android.bp @@ -0,0 +1,146 @@ +cc_library_static { + name: "libstagefright_mp3dec", + + srcs: [ + "src/pvmp3_normalize.cpp", + "src/pvmp3_alias_reduction.cpp", + "src/pvmp3_crc.cpp", + "src/pvmp3_decode_header.cpp", + "src/pvmp3_decode_huff_cw.cpp", + "src/pvmp3_getbits.cpp", + "src/pvmp3_dequantize_sample.cpp", + "src/pvmp3_framedecoder.cpp", + "src/pvmp3_get_main_data_size.cpp", + "src/pvmp3_get_side_info.cpp", + "src/pvmp3_get_scale_factors.cpp", + "src/pvmp3_mpeg2_get_scale_data.cpp", + "src/pvmp3_mpeg2_get_scale_factors.cpp", + "src/pvmp3_mpeg2_stereo_proc.cpp", + "src/pvmp3_huffman_decoding.cpp", + "src/pvmp3_huffman_parsing.cpp", + "src/pvmp3_tables.cpp", + "src/pvmp3_imdct_synth.cpp", + "src/pvmp3_mdct_6.cpp", + "src/pvmp3_dct_6.cpp", + "src/pvmp3_poly_phase_synthesis.cpp", + "src/pvmp3_equalizer.cpp", + "src/pvmp3_seek_synch.cpp", + "src/pvmp3_stereo_proc.cpp", + "src/pvmp3_reorder.cpp", + + "src/pvmp3_polyphase_filter_window.cpp", + "src/pvmp3_mdct_18.cpp", + "src/pvmp3_dct_9.cpp", + "src/pvmp3_dct_16.cpp", + ], + + arch: { + arm: { + exclude_srcs: [ + "src/pvmp3_polyphase_filter_window.cpp", + "src/pvmp3_mdct_18.cpp", + "src/pvmp3_dct_9.cpp", + "src/pvmp3_dct_16.cpp", + ], + srcs: [ + "src/asm/pvmp3_polyphase_filter_window_gcc.s", + "src/asm/pvmp3_mdct_18_gcc.s", + "src/asm/pvmp3_dct_9_gcc.s", + "src/asm/pvmp3_dct_16_gcc.s", + ], + + instruction_set: "arm", + }, + }, + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + include_dirs: ["frameworks/av/media/libstagefright/include"], + local_include_dirs: ["src"], + export_include_dirs: ["include"], + + cflags: [ + "-DOSCL_UNUSED_ARG(x)=(void)(x)", + "-Werror", + ], +} + +//############################################################################### + +cc_library_shared { + name: "libstagefright_soft_mp3dec", + + srcs: ["SoftMP3.cpp"], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + local_include_dirs: [ + "src", + "include", + ], + + cflags: ["-Werror"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + shared_libs: [ + "libmedia", + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "liblog", + ], + + static_libs: ["libstagefright_mp3dec"], +} + +//############################################################################### +cc_test { + name: "libstagefright_mp3dec_test", + gtest: false, + + srcs: [ + "test/mp3dec_test.cpp", + "test/mp3reader.cpp", + ], + + local_include_dirs: [ + "src", + "include", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + static_libs: [ + "libstagefright_mp3dec", + "libsndfile", + ], + + shared_libs: ["libaudioutils"], +} diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk deleted file mode 100644 index 5d153d15a8..0000000000 --- a/media/libstagefright/codecs/mp3dec/Android.mk +++ /dev/null @@ -1,114 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - src/pvmp3_normalize.cpp \ - src/pvmp3_alias_reduction.cpp \ - src/pvmp3_crc.cpp \ - src/pvmp3_decode_header.cpp \ - src/pvmp3_decode_huff_cw.cpp \ - src/pvmp3_getbits.cpp \ - src/pvmp3_dequantize_sample.cpp \ - src/pvmp3_framedecoder.cpp \ - src/pvmp3_get_main_data_size.cpp \ - src/pvmp3_get_side_info.cpp \ - src/pvmp3_get_scale_factors.cpp \ - src/pvmp3_mpeg2_get_scale_data.cpp \ - src/pvmp3_mpeg2_get_scale_factors.cpp \ - src/pvmp3_mpeg2_stereo_proc.cpp \ - src/pvmp3_huffman_decoding.cpp \ - src/pvmp3_huffman_parsing.cpp \ - src/pvmp3_tables.cpp \ - src/pvmp3_imdct_synth.cpp \ - src/pvmp3_mdct_6.cpp \ - src/pvmp3_dct_6.cpp \ - src/pvmp3_poly_phase_synthesis.cpp \ - src/pvmp3_equalizer.cpp \ - src/pvmp3_seek_synch.cpp \ - src/pvmp3_stereo_proc.cpp \ - src/pvmp3_reorder.cpp \ - -LOCAL_SRC_FILES_arm += \ - src/asm/pvmp3_polyphase_filter_window_gcc.s \ - src/asm/pvmp3_mdct_18_gcc.s \ - src/asm/pvmp3_dct_9_gcc.s \ - src/asm/pvmp3_dct_16_gcc.s -LOCAL_SRC_FILES_other_archs := \ - src/pvmp3_polyphase_filter_window.cpp \ - src/pvmp3_mdct_18.cpp \ - src/pvmp3_dct_9.cpp \ - src/pvmp3_dct_16.cpp - -LOCAL_SRC_FILES_arm64 := $(LOCAL_SRC_FILES_other_archs) -LOCAL_SRC_FILES_mips := $(LOCAL_SRC_FILES_other_archs) -LOCAL_SRC_FILES_mips64 := $(LOCAL_SRC_FILES_other_archs) -LOCAL_SRC_FILES_x86 := $(LOCAL_SRC_FILES_other_archs) -LOCAL_SRC_FILES_x86_64 := $(LOCAL_SRC_FILES_other_archs) - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/include - -LOCAL_CFLAGS := \ - -D"OSCL_UNUSED_ARG(x)=(void)(x)" - -LOCAL_CFLAGS += -Werror -LOCAL_SANITIZE := signed-integer-overflow - -LOCAL_MODULE := libstagefright_mp3dec - -LOCAL_ARM_MODE := arm - -include $(BUILD_STATIC_LIBRARY) - -################################################################################ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - SoftMP3.cpp - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - frameworks/native/include/media/openmax \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/include - -LOCAL_CFLAGS += -Werror -LOCAL_SANITIZE := signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_SHARED_LIBRARIES := \ - libmedia libstagefright_omx libstagefright_foundation libutils liblog - -LOCAL_STATIC_LIBRARIES := \ - libstagefright_mp3dec - -LOCAL_MODULE := libstagefright_soft_mp3dec -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) - -################################################################################ -include $(CLEAR_VARS) -LOCAL_SRC_FILES := \ - test/mp3dec_test.cpp \ - test/mp3reader.cpp - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/include \ - $(LOCAL_PATH)/test/include \ - $(call include-path-for, audio-utils) - -LOCAL_SANITIZE := signed-integer-overflow -LOCAL_STATIC_LIBRARIES := \ - libstagefright_mp3dec libsndfile - -LOCAL_SHARED_LIBRARIES := libaudioutils - -LOCAL_MODULE := libstagefright_mp3dec_test -LOCAL_MODULE_TAGS := tests - -include $(BUILD_EXECUTABLE) diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp index 0822c34d6e..3def1f0d80 100644 --- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp +++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp @@ -274,7 +274,7 @@ void SoftMP3::onQueueFilled(OMX_U32 /* portIndex */) { mConfig->inputBufferUsedLength = 0; mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t); - if ((int32)outHeader->nAllocLen < mConfig->outputFrameSize) { + if ((int32_t)outHeader->nAllocLen < mConfig->outputFrameSize) { ALOGE("input buffer too small: got %u, expected %u", outHeader->nAllocLen, mConfig->outputFrameSize); android_errorWriteLog(0x534e4554, "27793371"); @@ -363,7 +363,7 @@ void SoftMP3::onQueueFilled(OMX_U32 /* portIndex */) { mAnchorTimeUs + (mNumFramesOutput * 1000000ll) / mSamplingRate; if (inHeader) { - CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength); + CHECK_GE((int32_t)inHeader->nFilledLen, mConfig->inputBufferUsedLength); inHeader->nOffset += mConfig->inputBufferUsedLength; inHeader->nFilledLen -= mConfig->inputBufferUsedLength; diff --git a/media/libstagefright/codecs/mpeg2dec/Android.bp b/media/libstagefright/codecs/mpeg2dec/Android.bp new file mode 100644 index 0000000000..0144581805 --- /dev/null +++ b/media/libstagefright/codecs/mpeg2dec/Android.bp @@ -0,0 +1,33 @@ +cc_library_shared { + name: "libstagefright_soft_mpeg2dec", + + static_libs: ["libmpeg2dec"], + srcs: ["SoftMPEG2.cpp"], + + include_dirs: [ + "external/libmpeg2/decoder", + "external/libmpeg2/common", + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + shared_libs: [ + "libmedia", + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "liblog", + ], + + ldflags: ["-Wl,-Bsymbolic"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, +} diff --git a/media/libstagefright/codecs/mpeg2dec/Android.mk b/media/libstagefright/codecs/mpeg2dec/Android.mk deleted file mode 100644 index 0afc180cb6..0000000000 --- a/media/libstagefright/codecs/mpeg2dec/Android.mk +++ /dev/null @@ -1,29 +0,0 @@ -ifeq ($(if $(wildcard external/libmpeg2),1,0),1) - -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE := libstagefright_soft_mpeg2dec -LOCAL_MODULE_TAGS := optional - -LOCAL_STATIC_LIBRARIES := libmpeg2dec -LOCAL_SRC_FILES := SoftMPEG2.cpp - -LOCAL_C_INCLUDES := $(TOP)/external/libmpeg2/decoder -LOCAL_C_INCLUDES += $(TOP)/external/libmpeg2/common -LOCAL_C_INCLUDES += $(TOP)/frameworks/av/media/libstagefright/include -LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax - -LOCAL_SHARED_LIBRARIES := libmedia -LOCAL_SHARED_LIBRARIES += libstagefright_omx -LOCAL_SHARED_LIBRARIES += libstagefright_foundation -LOCAL_SHARED_LIBRARIES += libutils -LOCAL_SHARED_LIBRARIES += liblog - -LOCAL_LDFLAGS := -Wl,-Bsymbolic -LOCAL_SANITIZE := signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -include $(BUILD_SHARED_LIBRARY) - -endif diff --git a/media/libstagefright/codecs/on2/Android.bp b/media/libstagefright/codecs/on2/Android.bp new file mode 100644 index 0000000000..b44c296012 --- /dev/null +++ b/media/libstagefright/codecs/on2/Android.bp @@ -0,0 +1 @@ +subdirs = ["*"] diff --git a/media/libstagefright/codecs/on2/Android.mk b/media/libstagefright/codecs/on2/Android.mk deleted file mode 100644 index 2e431205aa..0000000000 --- a/media/libstagefright/codecs/on2/Android.mk +++ /dev/null @@ -1,4 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media/libstagefright/codecs/on2/dec/Android.bp b/media/libstagefright/codecs/on2/dec/Android.bp new file mode 100644 index 0000000000..c4242c2b1a --- /dev/null +++ b/media/libstagefright/codecs/on2/dec/Android.bp @@ -0,0 +1,33 @@ +cc_library_shared { + name: "libstagefright_soft_vpxdec", + + srcs: ["SoftVPX.cpp"], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + static_libs: ["libvpx"], + + shared_libs: [ + "libmedia", + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "liblog", + ], + + cflags: ["-Werror"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, +} diff --git a/media/libstagefright/codecs/on2/dec/Android.mk b/media/libstagefright/codecs/on2/dec/Android.mk deleted file mode 100644 index 8bc7dbc948..0000000000 --- a/media/libstagefright/codecs/on2/dec/Android.mk +++ /dev/null @@ -1,27 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - SoftVPX.cpp - -LOCAL_C_INCLUDES := \ - $(TOP)/external/libvpx/libvpx \ - $(TOP)/external/libvpx/libvpx/vpx_codec \ - $(TOP)/external/libvpx/libvpx/vpx_ports \ - frameworks/av/media/libstagefright/include \ - frameworks/native/include/media/openmax \ - -LOCAL_STATIC_LIBRARIES := \ - libvpx - -LOCAL_SHARED_LIBRARIES := \ - libmedia libstagefright_omx libstagefright_foundation libutils liblog - -LOCAL_MODULE := libstagefright_soft_vpxdec -LOCAL_MODULE_TAGS := optional - -LOCAL_CFLAGS += -Werror -LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/on2/enc/Android.bp b/media/libstagefright/codecs/on2/enc/Android.bp new file mode 100644 index 0000000000..114c1be8b0 --- /dev/null +++ b/media/libstagefright/codecs/on2/enc/Android.bp @@ -0,0 +1,35 @@ +cc_library_shared { + name: "libstagefright_soft_vpxenc", + + srcs: [ + "SoftVPXEncoder.cpp", + "SoftVP8Encoder.cpp", + "SoftVP9Encoder.cpp", + ], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + static_libs: ["libvpx"], + + shared_libs: [ + "libmedia", + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "liblog", + ], +} diff --git a/media/libstagefright/codecs/on2/enc/Android.mk b/media/libstagefright/codecs/on2/enc/Android.mk deleted file mode 100644 index 747aae08a5..0000000000 --- a/media/libstagefright/codecs/on2/enc/Android.mk +++ /dev/null @@ -1,29 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - SoftVPXEncoder.cpp \ - SoftVP8Encoder.cpp \ - SoftVP9Encoder.cpp - -LOCAL_C_INCLUDES := \ - $(TOP)/external/libvpx/libvpx \ - $(TOP)/external/libvpx/libvpx/vpx_codec \ - $(TOP)/external/libvpx/libvpx/vpx_ports \ - frameworks/av/media/libstagefright/include \ - frameworks/native/include/media/openmax \ - -LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi - -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_STATIC_LIBRARIES := \ - libvpx - -LOCAL_SHARED_LIBRARIES := \ - libmedia libstagefright_omx libstagefright_foundation libutils liblog \ - -LOCAL_MODULE := libstagefright_soft_vpxenc -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/on2/h264dec/Android.bp b/media/libstagefright/codecs/on2/h264dec/Android.bp new file mode 100644 index 0000000000..95c20757da --- /dev/null +++ b/media/libstagefright/codecs/on2/h264dec/Android.bp @@ -0,0 +1,137 @@ +cc_library_shared { + name: "libstagefright_soft_h264dec", + + srcs: [ + "source/h264bsd_transform.c", + "source/h264bsd_util.c", + "source/h264bsd_byte_stream.c", + "source/h264bsd_seq_param_set.c", + "source/h264bsd_pic_param_set.c", + "source/h264bsd_slice_header.c", + "source/h264bsd_slice_data.c", + "source/h264bsd_macroblock_layer.c", + "source/h264bsd_stream.c", + "source/h264bsd_vlc.c", + "source/h264bsd_cavlc.c", + "source/h264bsd_nal_unit.c", + "source/h264bsd_neighbour.c", + "source/h264bsd_storage.c", + "source/h264bsd_slice_group_map.c", + "source/h264bsd_intra_prediction.c", + "source/h264bsd_inter_prediction.c", + "source/h264bsd_reconstruct.c", + "source/h264bsd_dpb.c", + "source/h264bsd_image.c", + "source/h264bsd_deblocking.c", + "source/h264bsd_conceal.c", + "source/h264bsd_vui.c", + "source/h264bsd_pic_order_cnt.c", + "source/h264bsd_decoder.c", + "source/H264SwDecApi.c", + "SoftAVC.cpp", + ], + + arch: { + arm: { + instruction_set: "arm", + + armv7_a_neon: { + cflags: [ + "-DH264DEC_NEON", + "-DH264DEC_OMXDL", + ], + srcs: [ + "source/arm_neon_asm_gcc/h264bsdWriteMacroblock.S", + "source/arm_neon_asm_gcc/h264bsdClearMbLayer.S", + "source/arm_neon_asm_gcc/h264bsdFillRow7.S", + "source/arm_neon_asm_gcc/h264bsdCountLeadingZeros.S", + "source/arm_neon_asm_gcc/h264bsdFlushBits.S", + + "omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DeblockChroma_I.c", + "omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DeblockLuma_I.c", + "omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_InterpolateChroma.c", + "omxdl/arm_neon/vc/m4p10/src/armVCM4P10_CAVLCTables.c", + "omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DecodeChromaDcCoeffsToPairCAVLC.c", + "omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DecodeCoeffsToPairCAVLC.c", + "omxdl/arm_neon/src/armCOMM_Bitstream.c", + "omxdl/arm_neon/src/armCOMM.c", + + "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingChroma_unsafe_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingLuma_unsafe_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Interpolate_Chroma_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Align_unsafe_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Copy_unsafe_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_DiagCopy_unsafe_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_HorEdge_I_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_VerEdge_I_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_HorEdge_I_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_VerEdge_I_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_InterpolateLuma_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Average_4x_Align_unsafe_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DequantTables_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_QuantTables_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_TransformResidual4x4_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_UnpackBlock4x4_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantLumaDCFromPair_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_16x16_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_4x4_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntraChroma_8x8_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S", + "omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S", + ], + + local_include_dirs: [ + "source/arm_neon_asm_gcc", + + "omxdl/arm_neon/api", + "omxdl/arm_neon/vc/api", + "omxdl/arm_neon/vc/m4p10/api", + ], + }, + }, + }, + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + export_include_dirs: ["inc"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + shared_libs: [ + "libmedia", + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "liblog", + ], +} + +//#################################################################### +// test utility: decoder +//#################################################################### +//# +//# Test application +//# +cc_binary { + name: "decoder", + + srcs: ["source/DecTestBench.c"], + + shared_libs: ["libstagefright_soft_h264dec"], +} diff --git a/media/libstagefright/codecs/on2/h264dec/Android.mk b/media/libstagefright/codecs/on2/h264dec/Android.mk deleted file mode 100644 index 10147ecf5e..0000000000 --- a/media/libstagefright/codecs/on2/h264dec/Android.mk +++ /dev/null @@ -1,129 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_ARM_MODE := arm - -LOCAL_SRC_FILES := \ - ./source/h264bsd_transform.c \ - ./source/h264bsd_util.c \ - ./source/h264bsd_byte_stream.c \ - ./source/h264bsd_seq_param_set.c \ - ./source/h264bsd_pic_param_set.c \ - ./source/h264bsd_slice_header.c \ - ./source/h264bsd_slice_data.c \ - ./source/h264bsd_macroblock_layer.c \ - ./source/h264bsd_stream.c \ - ./source/h264bsd_vlc.c \ - ./source/h264bsd_cavlc.c \ - ./source/h264bsd_nal_unit.c \ - ./source/h264bsd_neighbour.c \ - ./source/h264bsd_storage.c \ - ./source/h264bsd_slice_group_map.c \ - ./source/h264bsd_intra_prediction.c \ - ./source/h264bsd_inter_prediction.c \ - ./source/h264bsd_reconstruct.c \ - ./source/h264bsd_dpb.c \ - ./source/h264bsd_image.c \ - ./source/h264bsd_deblocking.c \ - ./source/h264bsd_conceal.c \ - ./source/h264bsd_vui.c \ - ./source/h264bsd_pic_order_cnt.c \ - ./source/h264bsd_decoder.c \ - ./source/H264SwDecApi.c \ - SoftAVC.cpp \ - -LOCAL_C_INCLUDES := $(LOCAL_PATH)/./inc \ - frameworks/av/media/libstagefright/include \ - frameworks/native/include/media/openmax \ - -MY_ASM := \ - ./source/arm_neon_asm_gcc/h264bsdWriteMacroblock.S \ - ./source/arm_neon_asm_gcc/h264bsdClearMbLayer.S \ - ./source/arm_neon_asm_gcc/h264bsdFillRow7.S \ - ./source/arm_neon_asm_gcc/h264bsdCountLeadingZeros.S \ - ./source/arm_neon_asm_gcc/h264bsdFlushBits.S - - -MY_OMXDL_C_SRC := \ - ./omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DeblockChroma_I.c \ - ./omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DeblockLuma_I.c \ - ./omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_InterpolateChroma.c \ - ./omxdl/arm_neon/vc/m4p10/src/armVCM4P10_CAVLCTables.c \ - ./omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DecodeChromaDcCoeffsToPairCAVLC.c \ - ./omxdl/arm_neon/vc/m4p10/src/omxVCM4P10_DecodeCoeffsToPairCAVLC.c \ - ./omxdl/arm_neon/src/armCOMM_Bitstream.c \ - ./omxdl/arm_neon/src/armCOMM.c - -MY_OMXDL_ASM_SRC := \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingChroma_unsafe_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingLuma_unsafe_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Interpolate_Chroma_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Align_unsafe_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Copy_unsafe_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_DiagCopy_unsafe_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_HorEdge_I_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_VerEdge_I_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_HorEdge_I_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_VerEdge_I_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_InterpolateLuma_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Average_4x_Align_unsafe_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DequantTables_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_QuantTables_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_TransformResidual4x4_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_UnpackBlock4x4_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantLumaDCFromPair_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_16x16_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_4x4_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntraChroma_8x8_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S \ - ./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S \ - - -ifeq ($(ARCH_ARM_HAVE_NEON),true) - LOCAL_ARM_NEON := true - LOCAL_CFLAGS_arm := -DH264DEC_NEON -DH264DEC_OMXDL - LOCAL_SRC_FILES_arm := $(MY_ASM) $(MY_OMXDL_C_SRC) $(MY_OMXDL_ASM_SRC) - LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/./source/arm_neon_asm_gcc - LOCAL_C_INCLUDES_arm += $(LOCAL_PATH)/./omxdl/arm_neon/api \ - $(LOCAL_PATH)/./omxdl/arm_neon/vc/api \ - $(LOCAL_PATH)/./omxdl/arm_neon/vc/m4p10/api -endif - -LOCAL_SANITIZE := signed-integer-overflow cfi - -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_SHARED_LIBRARIES := \ - libmedia libstagefright_omx libstagefright_foundation libutils liblog \ - -LOCAL_MODULE := libstagefright_soft_h264dec - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) - -##################################################################### -# test utility: decoder -##################################################################### -## -## Test application -## -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := ./source/DecTestBench.c - -LOCAL_C_INCLUDES := $(LOCAL_PATH)/inc - -LOCAL_SHARED_LIBRARIES := libstagefright_soft_h264dec - -LOCAL_MODULE_TAGS := optional - -LOCAL_MODULE := decoder - -include $(BUILD_EXECUTABLE) diff --git a/media/libstagefright/codecs/opus/Android.bp b/media/libstagefright/codecs/opus/Android.bp new file mode 100644 index 0000000000..b44c296012 --- /dev/null +++ b/media/libstagefright/codecs/opus/Android.bp @@ -0,0 +1 @@ +subdirs = ["*"] diff --git a/media/libstagefright/codecs/opus/Android.mk b/media/libstagefright/codecs/opus/Android.mk deleted file mode 100644 index 365b1796b9..0000000000 --- a/media/libstagefright/codecs/opus/Android.mk +++ /dev/null @@ -1,4 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file diff --git a/media/libstagefright/codecs/opus/dec/Android.bp b/media/libstagefright/codecs/opus/dec/Android.bp new file mode 100644 index 0000000000..5d9c4c829d --- /dev/null +++ b/media/libstagefright/codecs/opus/dec/Android.bp @@ -0,0 +1,30 @@ +cc_library_shared { + name: "libstagefright_soft_opusdec", + + srcs: ["SoftOpus.cpp"], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + shared_libs: [ + "libopus", + "libmedia", + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "liblog", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, +} diff --git a/media/libstagefright/codecs/opus/dec/Android.mk b/media/libstagefright/codecs/opus/dec/Android.mk deleted file mode 100644 index 5b887b3186..0000000000 --- a/media/libstagefright/codecs/opus/dec/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - SoftOpus.cpp - -LOCAL_C_INCLUDES := \ - external/libopus/include \ - frameworks/av/media/libstagefright/include \ - frameworks/native/include/media/openmax \ - -LOCAL_SHARED_LIBRARIES := \ - libopus libmedia libstagefright_omx \ - libstagefright_foundation libutils liblog - -LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi - -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_MODULE := libstagefright_soft_opusdec -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/raw/Android.bp b/media/libstagefright/codecs/raw/Android.bp new file mode 100644 index 0000000000..c64027b77d --- /dev/null +++ b/media/libstagefright/codecs/raw/Android.bp @@ -0,0 +1,30 @@ +cc_library_shared { + name: "libstagefright_soft_rawdec", + + srcs: ["SoftRaw.cpp"], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + cflags: ["-Werror"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + shared_libs: [ + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "liblog", + ], +} diff --git a/media/libstagefright/codecs/raw/Android.mk b/media/libstagefright/codecs/raw/Android.mk deleted file mode 100644 index 5fe260bf95..0000000000 --- a/media/libstagefright/codecs/raw/Android.mk +++ /dev/null @@ -1,21 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - SoftRaw.cpp - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/include \ - frameworks/native/include/media/openmax - -LOCAL_CFLAGS += -Werror -LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_SHARED_LIBRARIES := \ - libstagefright_omx libstagefright_foundation libutils liblog - -LOCAL_MODULE := libstagefright_soft_rawdec -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/vorbis/Android.bp b/media/libstagefright/codecs/vorbis/Android.bp new file mode 100644 index 0000000000..b44c296012 --- /dev/null +++ b/media/libstagefright/codecs/vorbis/Android.bp @@ -0,0 +1 @@ +subdirs = ["*"] diff --git a/media/libstagefright/codecs/vorbis/Android.mk b/media/libstagefright/codecs/vorbis/Android.mk deleted file mode 100644 index 2e431205aa..0000000000 --- a/media/libstagefright/codecs/vorbis/Android.mk +++ /dev/null @@ -1,4 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media/libstagefright/codecs/vorbis/dec/Android.bp b/media/libstagefright/codecs/vorbis/dec/Android.bp new file mode 100644 index 0000000000..1a4de60ed1 --- /dev/null +++ b/media/libstagefright/codecs/vorbis/dec/Android.bp @@ -0,0 +1,28 @@ +cc_library_shared { + name: "libstagefright_soft_vorbisdec", + + srcs: ["SoftVorbis.cpp"], + + include_dirs: [ + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + shared_libs: [ + "libvorbisidec", + "libmedia", + "libstagefright_omx", + "libstagefright_foundation", + "libutils", + "liblog", + ], + + cflags: ["-Werror"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + }, +} diff --git a/media/libstagefright/codecs/vorbis/dec/Android.mk b/media/libstagefright/codecs/vorbis/dec/Android.mk deleted file mode 100644 index 3d72d3adda..0000000000 --- a/media/libstagefright/codecs/vorbis/dec/Android.mk +++ /dev/null @@ -1,22 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - SoftVorbis.cpp - -LOCAL_C_INCLUDES := \ - external/tremolo \ - frameworks/av/media/libstagefright/include \ - frameworks/native/include/media/openmax \ - -LOCAL_SHARED_LIBRARIES := \ - libvorbisidec libmedia libstagefright_omx \ - libstagefright_foundation libutils liblog - -LOCAL_MODULE := libstagefright_soft_vorbisdec -LOCAL_MODULE_TAGS := optional - -LOCAL_CFLAGS += -Werror -LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp index be04e08b0d..14dd250cc0 100644 --- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp +++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp @@ -23,6 +23,9 @@ #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/MediaDefs.h> +static int kDefaultChannelCount = 1; +static int kDefaultSamplingRate = 48000; + extern "C" { #include <Tremolo/codec_internal.h> @@ -148,8 +151,8 @@ OMX_ERRORTYPE SoftVorbis::internalGetParameter( vorbisParams->bDownmix = OMX_FALSE; if (!isConfigured()) { - vorbisParams->nChannels = 1; - vorbisParams->nSampleRate = 44100; + vorbisParams->nChannels = kDefaultChannelCount; + vorbisParams->nSampleRate = kDefaultSamplingRate; } else { vorbisParams->nChannels = mVi->channels; vorbisParams->nSampleRate = mVi->rate; @@ -157,7 +160,6 @@ OMX_ERRORTYPE SoftVorbis::internalGetParameter( vorbisParams->nMinBitRate = mVi->bitrate_lower; vorbisParams->nMaxBitRate = mVi->bitrate_upper; } - return OMX_ErrorNone; } @@ -183,8 +185,8 @@ OMX_ERRORTYPE SoftVorbis::internalGetParameter( pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; if (!isConfigured()) { - pcmParams->nChannels = 1; - pcmParams->nSamplingRate = 44100; + pcmParams->nChannels = kDefaultChannelCount; + pcmParams->nSamplingRate = kDefaultSamplingRate; } else { pcmParams->nChannels = mVi->channels; pcmParams->nSamplingRate = mVi->rate; @@ -313,8 +315,12 @@ void SoftVorbis::onQueueFilled(OMX_U32 portIndex) { mState = new vorbis_dsp_state; CHECK_EQ(0, vorbis_dsp_init(mState, mVi)); - notify(OMX_EventPortSettingsChanged, 1, 0, NULL); - mOutputPortSettingsChange = AWAITING_DISABLED; + if (mVi->rate != kDefaultSamplingRate || + mVi->channels != kDefaultChannelCount) { + ALOGV("vorbis: rate/channels changed: %ld/%d", mVi->rate, mVi->channels); + notify(OMX_EventPortSettingsChanged, 1, 0, NULL); + mOutputPortSettingsChange = AWAITING_DISABLED; + } } inQueue.erase(inQueue.begin()); diff --git a/media/libstagefright/colorconversion/Android.bp b/media/libstagefright/colorconversion/Android.bp new file mode 100644 index 0000000000..16e9ded0ea --- /dev/null +++ b/media/libstagefright/colorconversion/Android.bp @@ -0,0 +1,31 @@ +cc_library_static { + name: "libstagefright_color_conversion", + + srcs: [ + "ColorConverter.cpp", + "SoftwareRenderer.cpp", + ], + + include_dirs: [ + "frameworks/native/include/media/openmax", + ], + + shared_libs: [ + "libui", + "libnativewindow", + ], + + static_libs: ["libyuv_static"], + + cflags: ["-Werror"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, +} diff --git a/media/libstagefright/colorconversion/Android.mk b/media/libstagefright/colorconversion/Android.mk deleted file mode 100644 index 1e7a4ccd91..0000000000 --- a/media/libstagefright/colorconversion/Android.mk +++ /dev/null @@ -1,25 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - ColorConverter.cpp \ - SoftwareRenderer.cpp - -LOCAL_C_INCLUDES := \ - $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/hardware/msm7k \ - $(TOP)/external/libyuv/files/include - -LOCAL_SHARED_LIBRARIES := \ - libui \ - -LOCAL_STATIC_LIBRARIES := \ - libyuv_static \ - -LOCAL_CFLAGS += -Werror -LOCAL_SANITIZE := signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_MODULE:= libstagefright_color_conversion - -include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp index 536d40d5d2..a07787ac5a 100644 --- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp +++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp @@ -30,10 +30,6 @@ namespace android { -static bool runningInEmulator() { - char prop[PROPERTY_VALUE_MAX]; - return (property_get("ro.kernel.qemu", prop, NULL) > 0); -} static int ALIGN(int x, int y) { // y must be a power of 2. @@ -108,7 +104,7 @@ void SoftwareRenderer::resetFormatIfChanged(const sp<AMessage> &format) { size_t bufHeight = mCropHeight; // hardware has YUV12 and RGBA8888 support, so convert known formats - if (!runningInEmulator()) { + { switch (mColorFormat) { case OMX_COLOR_FormatYUV420Planar: case OMX_COLOR_FormatYUV420SemiPlanar: @@ -205,7 +201,7 @@ void SoftwareRenderer::clearTracker() { } std::list<FrameRenderTracker::Info> SoftwareRenderer::render( - const void *data, size_t size, int64_t mediaTimeUs, nsecs_t renderTimeNs, + const void *data, size_t , int64_t mediaTimeUs, nsecs_t renderTimeNs, void* /*platformPrivate*/, const sp<AMessage>& format) { resetFormatIfChanged(format); FrameRenderTracker::Info *info = NULL; @@ -244,14 +240,15 @@ std::list<FrameRenderTracker::Info> SoftwareRenderer::render( buf->stride, buf->height, 0, 0, mCropWidth - 1, mCropHeight - 1); } else if (mColorFormat == OMX_COLOR_FormatYUV420Planar) { - if ((size_t)mWidth * mHeight * 3 / 2 > size) { - goto skip_copying; - } const uint8_t *src_y = (const uint8_t *)data; const uint8_t *src_u = (const uint8_t *)data + mWidth * mHeight; const uint8_t *src_v = src_u + (mWidth / 2 * mHeight / 2); + src_y +=mCropLeft + mCropTop * mWidth; + src_u +=(mCropLeft + mCropTop * mWidth / 2)/2; + src_v +=(mCropLeft + mCropTop * mWidth / 2)/2; + uint8_t *dst_y = (uint8_t *)dst; size_t dst_y_size = buf->stride * buf->height; size_t dst_c_stride = ALIGN(buf->stride / 2, 16); @@ -259,6 +256,10 @@ std::list<FrameRenderTracker::Info> SoftwareRenderer::render( uint8_t *dst_v = dst_y + dst_y_size; uint8_t *dst_u = dst_v + dst_c_size; + dst_y += mCropTop * buf->stride + mCropLeft; + dst_v += (mCropTop/2) * dst_c_stride + mCropLeft/2; + dst_u += (mCropTop/2) * dst_c_stride + mCropLeft/2; + for (int y = 0; y < mCropHeight; ++y) { memcpy(dst_y, src_y, mCropWidth); @@ -277,12 +278,12 @@ std::list<FrameRenderTracker::Info> SoftwareRenderer::render( } } else if (mColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar || mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { - if ((size_t)mWidth * mHeight * 3 / 2 > size) { - goto skip_copying; - } const uint8_t *src_y = (const uint8_t *)data; const uint8_t *src_uv = (const uint8_t *)data - + mWidth * (mHeight - mCropTop / 2); + + mWidth * mHeight; + + src_y += mCropLeft + mCropTop * mWidth; + src_uv += (mCropLeft + mCropTop * mWidth) / 2; uint8_t *dst_y = (uint8_t *)dst; @@ -292,6 +293,10 @@ std::list<FrameRenderTracker::Info> SoftwareRenderer::render( uint8_t *dst_v = dst_y + dst_y_size; uint8_t *dst_u = dst_v + dst_c_size; + dst_y += mCropTop * buf->stride + mCropLeft; + dst_v += (mCropTop/2) * dst_c_stride + mCropLeft/2; + dst_u += (mCropTop/2) * dst_c_stride + mCropLeft/2; + for (int y = 0; y < mCropHeight; ++y) { memcpy(dst_y, src_y, mCropWidth); @@ -311,11 +316,8 @@ std::list<FrameRenderTracker::Info> SoftwareRenderer::render( dst_v += dst_c_stride; } } else if (mColorFormat == OMX_COLOR_Format24bitRGB888) { - if ((size_t)mWidth * mHeight * 3 > size) { - goto skip_copying; - } - uint8_t* srcPtr = (uint8_t*)data; - uint8_t* dstPtr = (uint8_t*)dst; + uint8_t* srcPtr = (uint8_t*)data + mWidth * mCropTop * 3 + mCropLeft * 3; + uint8_t* dstPtr = (uint8_t*)dst + buf->stride * mCropTop * 3 + mCropLeft * 3; for (size_t y = 0; y < (size_t)mCropHeight; ++y) { memcpy(dstPtr, srcPtr, mCropWidth * 3); @@ -323,14 +325,11 @@ std::list<FrameRenderTracker::Info> SoftwareRenderer::render( dstPtr += buf->stride * 3; } } else if (mColorFormat == OMX_COLOR_Format32bitARGB8888) { - if ((size_t)mWidth * mHeight * 4 > size) { - goto skip_copying; - } uint8_t *srcPtr, *dstPtr; for (size_t y = 0; y < (size_t)mCropHeight; ++y) { - srcPtr = (uint8_t*)data + mWidth * 4 * y; - dstPtr = (uint8_t*)dst + buf->stride * 4 * y; + srcPtr = (uint8_t*)data + mWidth * 4 * (y + mCropTop) + mCropLeft * 4; + dstPtr = (uint8_t*)dst + buf->stride * 4 * (y + mCropTop) + mCropLeft * 4; for (size_t x = 0; x < (size_t)mCropWidth; ++x) { uint8_t a = *srcPtr++; for (size_t i = 0; i < 3; ++i) { // copy RGB @@ -340,11 +339,8 @@ std::list<FrameRenderTracker::Info> SoftwareRenderer::render( } } } else if (mColorFormat == OMX_COLOR_Format32BitRGBA8888) { - if ((size_t)mWidth * mHeight * 4 > size) { - goto skip_copying; - } - uint8_t* srcPtr = (uint8_t*)data; - uint8_t* dstPtr = (uint8_t*)dst; + uint8_t* srcPtr = (uint8_t*)data + mWidth * mCropTop * 4 + mCropLeft * 4; + uint8_t* dstPtr = (uint8_t*)dst + buf->stride * mCropTop * 4 + mCropLeft * 4; for (size_t y = 0; y < (size_t)mCropHeight; ++y) { memcpy(dstPtr, srcPtr, mCropWidth * 4); diff --git a/media/libstagefright/data/media_codecs_google_audio.xml b/media/libstagefright/data/media_codecs_google_audio.xml index b957b0c240..632088ae7e 100644 --- a/media/libstagefright/data/media_codecs_google_audio.xml +++ b/media/libstagefright/data/media_codecs_google_audio.xml @@ -61,6 +61,11 @@ <Limit name="sample-rate" ranges="8000-96000" /> <Limit name="bitrate" range="1-10000000" /> </MediaCodec> + <MediaCodec name="OMX.google.flac.decoder" type="audio/flac"> + <Limit name="channel-count" max="8" /> + <Limit name="sample-rate" ranges="1-655350" /> + <Limit name="bitrate" range="1-21000000" /> + </MediaCodec> </Decoders> <Encoders> <MediaCodec name="OMX.google.aac.encoder" type="audio/mp4a-latm"> diff --git a/media/libstagefright/filters/Android.bp b/media/libstagefright/filters/Android.bp new file mode 100644 index 0000000000..e94422447b --- /dev/null +++ b/media/libstagefright/filters/Android.bp @@ -0,0 +1,38 @@ +cc_library_static { + name: "libstagefright_mediafilter", + + srcs: [ + "ColorConvert.cpp", + "GraphicBufferListener.cpp", + "IntrinsicBlurFilter.cpp", + "MediaFilter.cpp", + "RSFilter.cpp", + "SaturationFilter.cpp", + "saturationARGB.rs", + "SimpleFilter.cpp", + "ZeroFilter.cpp", + ], + + include_dirs: [ + "frameworks/native/include/media/openmax", + ], + + cflags: [ + "-Wno-multichar", + "-Werror", + "-Wall", + ], + + shared_libs: [ + "libgui", + "libmedia", + "libhidlmemory", + ], + + sanitize: { + cfi: true, + diag: { + cfi: true, + }, + }, +} diff --git a/media/libstagefright/filters/Android.mk b/media/libstagefright/filters/Android.mk deleted file mode 100644 index d4ecfccadd..0000000000 --- a/media/libstagefright/filters/Android.mk +++ /dev/null @@ -1,35 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - ColorConvert.cpp \ - GraphicBufferListener.cpp \ - IntrinsicBlurFilter.cpp \ - MediaFilter.cpp \ - RSFilter.cpp \ - SaturationFilter.cpp \ - saturationARGB.rs \ - SimpleFilter.cpp \ - ZeroFilter.cpp - -LOCAL_C_INCLUDES := \ - $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/frameworks/rs/cpp \ - $(TOP)/frameworks/rs \ - -intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,) -LOCAL_C_INCLUDES += $(intermediates) - -LOCAL_CFLAGS += -Wno-multichar -Werror -Wall - -LOCAL_SHARED_LIBRARIES := \ - libgui \ - libmedia \ - libhidlmemory \ - -LOCAL_MODULE:= libstagefright_mediafilter - -LOCAL_SANITIZE := cfi -LOCAL_SANITIZE_DIAG := cfi - -include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/flac/dec/Android.bp b/media/libstagefright/flac/dec/Android.bp new file mode 100644 index 0000000000..284c25f2f7 --- /dev/null +++ b/media/libstagefright/flac/dec/Android.bp @@ -0,0 +1,34 @@ +cc_library_shared { + name: "libstagefright_flacdec", + + srcs: [ + "FLACDecoder.cpp", + ], + + include_dirs: [ + "external/flac/include", + "frameworks/av/media/libstagefright/include", + ], + + cflags: ["-Werror"], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + static_libs: ["libFLAC"], + + shared_libs: [ + "libcutils", + "liblog", + "libstagefright_foundation", + "libutils", + ], +} diff --git a/media/libstagefright/flac/dec/FLACDecoder.cpp b/media/libstagefright/flac/dec/FLACDecoder.cpp new file mode 100644 index 0000000000..8c7137c3be --- /dev/null +++ b/media/libstagefright/flac/dec/FLACDecoder.cpp @@ -0,0 +1,526 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "FLACDecoder" +#include <utils/Log.h> + +#include "FLACDecoder.h" + +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/hexdump.h> +#include <media/stagefright/MediaDefs.h> +#include <media/stagefright/MediaErrors.h> +#include <media/stagefright/MetaData.h> + +namespace android { + +// These are the corresponding callbacks with C++ calling conventions +FLAC__StreamDecoderReadStatus FLACDecoder::readCallback( + FLAC__byte buffer[], size_t *bytes) { + if (mBuffer == nullptr || mBufferLen == 0) { + *bytes = 0; + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } + + size_t actual = *bytes; + if (actual > mBufferDataSize - mBufferPos) { + actual = mBufferDataSize - mBufferPos; + } + memcpy(buffer, mBuffer + mBufferPos, actual); + mBufferPos += actual; + *bytes = actual; + return (actual == 0 ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM + : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE); +} + +FLAC__StreamDecoderWriteStatus FLACDecoder::writeCallback( + const FLAC__Frame *frame, const FLAC__int32 * const buffer[]) +{ + if (!mWriteRequested) { + ALOGE("writeCallback: unexpected"); + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + + mWriteRequested = false; + // FLAC decoder doesn't free or realloc buffer until next frame or finish + mWriteHeader = frame->header; + memmove(mWriteBuffer, buffer, sizeof(const FLAC__int32 * const) * getChannels()); + mWriteCompleted = true; + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +void FLACDecoder::metadataCallback(const FLAC__StreamMetadata *metadata) +{ + switch (metadata->type) { + case FLAC__METADATA_TYPE_STREAMINFO: + { + if (mStreamInfoValid) { + ALOGE("metadataCallback: unexpected STREAMINFO"); + } else { + mStreamInfo = metadata->data.stream_info; + mStreamInfoValid = true; + } + break; + } + + /* TODO: enable metadata parsing below. + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + { + const FLAC__StreamMetadata_VorbisComment *vc; + vc = &metadata->data.vorbis_comment; + for (FLAC__uint32 i = 0; i < vc->num_comments; ++i) { + FLAC__StreamMetadata_VorbisComment_Entry *vce; + vce = &vc->comments[i]; + if (mFileMetadata != 0 && vce->entry != NULL) { + parseVorbisComment(mFileMetadata, (const char *) vce->entry, + vce->length); + } + } + break; + } + + case FLAC__METADATA_TYPE_PICTURE: + { + if (mFileMetadata != 0) { + const FLAC__StreamMetadata_Picture *p = &metadata->data.picture; + mFileMetadata->setData(kKeyAlbumArt, + MetaData::TYPE_NONE, p->data, p->data_length); + mFileMetadata->setCString(kKeyAlbumArtMIME, p->mime_type); + } + break; + } + */ + + default: + ALOGW("metadataCallback: unexpected type %u", metadata->type); + break; + } +} + +void FLACDecoder::errorCallback(FLAC__StreamDecoderErrorStatus status) +{ + ALOGE("errorCallback: status=%d", status); + mErrorStatus = status; +} + +// Copy samples from FLAC native 32-bit non-interleaved to 16-bit interleaved. +// These are candidates for optimization if needed. +static void copyMono8( + short *dst, + const int * src[FLACDecoder::kMaxChannels], + unsigned nSamples, + unsigned /* nChannels */) { + for (unsigned i = 0; i < nSamples; ++i) { + *dst++ = src[0][i] << 8; + } +} + +static void copyStereo8( + short *dst, + const int * src[FLACDecoder::kMaxChannels], + unsigned nSamples, + unsigned /* nChannels */) { + for (unsigned i = 0; i < nSamples; ++i) { + *dst++ = src[0][i] << 8; + *dst++ = src[1][i] << 8; + } +} + +static void copyMultiCh8( + short *dst, + const int * src[FLACDecoder::kMaxChannels], + unsigned nSamples, + unsigned nChannels) { + for (unsigned i = 0; i < nSamples; ++i) { + for (unsigned c = 0; c < nChannels; ++c) { + *dst++ = src[c][i] << 8; + } + } +} + +static void copyMono16( + short *dst, + const int * src[FLACDecoder::kMaxChannels], + unsigned nSamples, + unsigned /* nChannels */) { + for (unsigned i = 0; i < nSamples; ++i) { + *dst++ = src[0][i]; + } +} + +static void copyStereo16( + short *dst, + const int * src[FLACDecoder::kMaxChannels], + unsigned nSamples, + unsigned /* nChannels */) { + for (unsigned i = 0; i < nSamples; ++i) { + *dst++ = src[0][i]; + *dst++ = src[1][i]; + } +} + +static void copyMultiCh16( + short *dst, + const int * src[FLACDecoder::kMaxChannels], + unsigned nSamples, + unsigned nChannels) { + for (unsigned i = 0; i < nSamples; ++i) { + for (unsigned c = 0; c < nChannels; ++c) { + *dst++ = src[c][i]; + } + } +} + +// TODO: 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger +static void copyMono24( + short *dst, + const int * src[FLACDecoder::kMaxChannels], + unsigned nSamples, + unsigned /* nChannels */) { + for (unsigned i = 0; i < nSamples; ++i) { + *dst++ = src[0][i] >> 8; + } +} + +static void copyStereo24( + short *dst, + const int * src[FLACDecoder::kMaxChannels], + unsigned nSamples, + unsigned /* nChannels */) { + for (unsigned i = 0; i < nSamples; ++i) { + *dst++ = src[0][i] >> 8; + *dst++ = src[1][i] >> 8; + } +} + +static void copyMultiCh24( + short *dst, + const int * src[FLACDecoder::kMaxChannels], + unsigned nSamples, + unsigned nChannels) { + for (unsigned i = 0; i < nSamples; ++i) { + for (unsigned c = 0; c < nChannels; ++c) { + *dst++ = src[c][i] >> 8; + } + } +} + +// static +sp<FLACDecoder> FLACDecoder::Create() { + sp<FLACDecoder> decoder = new FLACDecoder(); + if (decoder->init() != OK) { + return NULL; + } + return decoder; +} + +FLACDecoder::FLACDecoder() + : mDecoder(NULL), + mBuffer(NULL), + mBufferLen(0), + mBufferPos(0), + mBufferDataSize(0), + mStreamInfoValid(false), + mWriteRequested(false), + mWriteCompleted(false), + mErrorStatus((FLAC__StreamDecoderErrorStatus) -1), + mCopy(nullptr) { + ALOGV("ctor:"); + memset(&mStreamInfo, 0, sizeof(mStreamInfo)); + memset(&mWriteHeader, 0, sizeof(mWriteHeader)); + memset(&mWriteBuffer, 0, sizeof(mWriteBuffer)); +} + +FLACDecoder::~FLACDecoder() { + ALOGV("dtor:"); + if (mDecoder != NULL) { + FLAC__stream_decoder_delete(mDecoder); + mDecoder = NULL; + } + if (mBuffer != NULL) { + free(mBuffer); + } +} + +status_t FLACDecoder::init() { + ALOGV("init:"); + // setup libFLAC stream decoder + mDecoder = FLAC__stream_decoder_new(); + if (mDecoder == NULL) { + ALOGE("init: failed to create libFLAC stream decoder"); + return NO_INIT; + } + FLAC__stream_decoder_set_md5_checking(mDecoder, false); + FLAC__stream_decoder_set_metadata_ignore_all(mDecoder); + FLAC__stream_decoder_set_metadata_respond( + mDecoder, FLAC__METADATA_TYPE_STREAMINFO); + /* + FLAC__stream_decoder_set_metadata_respond( + mDecoder, FLAC__METADATA_TYPE_PICTURE); + FLAC__stream_decoder_set_metadata_respond( + mDecoder, FLAC__METADATA_TYPE_VORBIS_COMMENT); + */ + static auto read_callback = + [] (const FLAC__StreamDecoder * /* decoder */, + FLAC__byte buffer[], + size_t *bytes, + void *client_data) -> FLAC__StreamDecoderReadStatus { + return ((FLACDecoder *) client_data)->readCallback(buffer, bytes); }; + + static auto write_callback = + [] (const FLAC__StreamDecoder * /* decoder */, + const FLAC__Frame *frame, + const FLAC__int32 * const buffer[], + void *client_data) -> FLAC__StreamDecoderWriteStatus { + return ((FLACDecoder *) client_data)->writeCallback(frame, buffer); }; + + static auto metadata_callback = + [] (const FLAC__StreamDecoder * /* decoder */, + const FLAC__StreamMetadata *metadata, + void *client_data) { + ((FLACDecoder *) client_data)->metadataCallback(metadata); }; + + static auto error_callback = + [] (const FLAC__StreamDecoder * /* decoder */, + FLAC__StreamDecoderErrorStatus status, + void *client_data) { + ((FLACDecoder *) client_data)->errorCallback(status); }; + + FLAC__StreamDecoderInitStatus initStatus = + FLAC__stream_decoder_init_stream( + mDecoder, + read_callback, + NULL /* seek_callback */, + NULL /* tell_callback */, + NULL /* length_callback */, + NULL /* eof_callback */, + write_callback, + metadata_callback, + error_callback, + (void *)this); + if (initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK) { + ALOGE("init: init_stream failed, returned %d", initStatus); + return NO_INIT; + } + return OK; +} + +void FLACDecoder::flush() { + ALOGV("flush:"); + mBufferPos = 0; + mBufferDataSize = 0; + mStreamInfoValid = false; + if (!FLAC__stream_decoder_reset(mDecoder)) { + ALOGE("flush: failed to reset FLAC stream decoder"); + } +} + +status_t FLACDecoder::parseMetadata(const uint8_t *inBuffer, size_t inBufferLen) { + ALOGV("parseMetadata: input size(%zu)", inBufferLen); + //hexdump(inBuffer, inBufferLen); + + if (mStreamInfoValid) { + ALOGE("parseMetadata: already have full metadata blocks"); + return ERROR_MALFORMED; + } + + status_t err = addDataToBuffer(inBuffer, inBufferLen); + if (err != OK) { + ALOGE("parseMetadata: addDataToBuffer returns error %d", err); + return err; + } + + if (!FLAC__stream_decoder_process_until_end_of_metadata(mDecoder)) { + if (!FLAC__stream_decoder_reset(mDecoder)) { + ALOGE("parseMetadata: failed to reset FLAC stream decoder"); + return FAILED_TRANSACTION; + } + mBufferPos = 0; + ALOGV("parseMetadata: do not have full metadata blocks yet"); + return WOULD_BLOCK; + } + + if (!mStreamInfoValid) { + ALOGE("parseMetadata: missing STREAMINFO"); + return ERROR_MALFORMED; + } + + // check block size + if (getMaxBlockSize() == 0) { + ALOGE("wrong max blocksize %u", getMaxBlockSize()); + mStreamInfoValid = false; + return ERROR_MALFORMED; + } + + // check channel count + if (getChannels() == 0 || getChannels() > kMaxChannels) { + ALOGE("unsupported channel count %u", getChannels()); + mStreamInfoValid = false; + return ERROR_MALFORMED; + } + + // check bit depth + switch (getBitsPerSample()) { + case 8: + case 16: + case 24: + break; + + default: + ALOGE("parseMetadata: unsupported bits per sample %u", getBitsPerSample()); + mStreamInfoValid = false; + return ERROR_MALFORMED; + } + + // configure the appropriate copy function, defaulting to trespass + static const struct { + unsigned mChannels; + unsigned mBitsPerSample; + void (*mCopy)(short *dst, const int * src[kMaxChannels], + unsigned nSamples, unsigned nChannels); + } table[] = { + { 1, 8, copyMono8 }, + { 2, 8, copyStereo8 }, + { 8, 8, copyMultiCh8 }, + { 1, 16, copyMono16 }, + { 2, 16, copyStereo16 }, + { 8, 16, copyMultiCh16 }, + { 1, 24, copyMono24 }, + { 2, 24, copyStereo24 }, + { 8, 24, copyMultiCh24 }, + }; + for (const auto &entry : table) { + if (entry.mChannels >= getChannels() && + entry.mBitsPerSample == getBitsPerSample()) { + mCopy = entry.mCopy; + break; + } + } + + // Now we have all metadata blocks. + mBufferPos = 0; + mBufferDataSize = 0; + + return OK; +} + +status_t FLACDecoder::decodeOneFrame(const uint8_t *inBuffer, size_t inBufferLen, + short *outBuffer, size_t *outBufferLen) { + ALOGV("decodeOneFrame: input size(%zu)", inBufferLen); + + if (inBufferLen == 0) { + ALOGV("decodeOneFrame: no input data"); + if (outBufferLen) { + *outBufferLen = 0; + } + return OK; + } + + if (!mStreamInfoValid) { + ALOGW("decodeOneFrame: no streaminfo metadata block"); + } + + status_t err = addDataToBuffer(inBuffer, inBufferLen); + if (err != OK) { + ALOGW("decodeOneFrame: addDataToBuffer returns error %d", err); + return err; + } + + mWriteRequested = true; + mWriteCompleted = false; + if (!FLAC__stream_decoder_process_single(mDecoder)) { + ALOGE("decodeOneFrame: process_single failed"); + return ERROR_MALFORMED; + } + if (!mWriteCompleted) { + ALOGV("decodeOneFrame: write did not complete"); + if (outBufferLen) { + *outBufferLen = 0; + } + return OK; + } + + // frame header should be consistent with STREAMINFO + unsigned blocksize = mWriteHeader.blocksize; + if (blocksize == 0 || blocksize > getMaxBlockSize()) { + ALOGE("decodeOneFrame: write invalid blocksize %u", blocksize); + return ERROR_MALFORMED; + } + if (mWriteHeader.sample_rate != getSampleRate() || + mWriteHeader.channels != getChannels() || + mWriteHeader.bits_per_sample != getBitsPerSample()) { + ALOGE("decodeOneFrame: parameters are changed mid-stream: %d/%d/%d -> %d/%d/%d", + getSampleRate(), getChannels(), getBitsPerSample(), + mWriteHeader.sample_rate, mWriteHeader.channels, mWriteHeader.bits_per_sample); + return ERROR_MALFORMED; + } + if (mWriteHeader.number_type != FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER) { + ALOGE("decodeOneFrame: number type is %d, expected %d", + mWriteHeader.number_type, FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); + return ERROR_MALFORMED; + } + + size_t bufferSize = blocksize * getChannels() * sizeof(short); + if (bufferSize > *outBufferLen) { + ALOGW("decodeOneFrame: output buffer holds only partial frame %zu:%zu", + *outBufferLen, bufferSize); + blocksize = *outBufferLen / (getChannels() * sizeof(short)); + bufferSize = blocksize * getChannels() * sizeof(short); + } + + if (mCopy == nullptr) { + ALOGE("decodeOneFrame: format is not supported: channels(%d), BitsPerSample(%d)", + getChannels(), getBitsPerSample()); + return ERROR_UNSUPPORTED; + } + // copy PCM from FLAC write buffer to output buffer, with interleaving + (*mCopy)(outBuffer, mWriteBuffer, blocksize, getChannels()); + *outBufferLen = bufferSize; + return OK; +} + +status_t FLACDecoder::addDataToBuffer(const uint8_t *inBuffer, size_t inBufferLen) { + // mBufferPos should be no larger than mBufferDataSize + if (inBufferLen > SIZE_MAX - (mBufferDataSize - mBufferPos)) { + ALOGE("addDataToBuffer: input buffer is too large"); + return ERROR_MALFORMED; + } + + if (inBufferLen > mBufferLen - mBufferDataSize) { + if (mBufferPos > 0) { + memmove(mBuffer, mBuffer + mBufferPos, mBufferDataSize - mBufferPos); + mBufferDataSize -= mBufferPos; + mBufferPos = 0; + } + if (inBufferLen > mBufferLen - mBufferDataSize) { + mBuffer = (uint8_t*)realloc(mBuffer, mBufferDataSize + inBufferLen); + if (mBuffer == nullptr) { + mBufferDataSize = 0; + mBufferLen = 0; + ALOGE("decodeOneFrame: failed to allocate memory for input buffer"); + return NO_MEMORY; + } + mBufferLen = mBufferDataSize + inBufferLen; + } + } + + memcpy(mBuffer + mBufferDataSize, inBuffer, inBufferLen); + mBufferDataSize += inBufferLen; + return OK; +} + +} // namespace android diff --git a/media/libstagefright/flac/dec/FLACDecoder.h b/media/libstagefright/flac/dec/FLACDecoder.h new file mode 100644 index 0000000000..36282a8c66 --- /dev/null +++ b/media/libstagefright/flac/dec/FLACDecoder.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLAC_DECODER_H_ +#define FLAC_DECODER_H_ + +#include <media/stagefright/foundation/ABase.h> +#include <utils/RefBase.h> +#include <utils/String8.h> + +#include "FLAC/stream_decoder.h" + +namespace android { + +// packet based FLAC decoder, wrapps libFLAC stream decoder. +class FLACDecoder : public RefBase { + +public: + enum { + kMaxChannels = 8, + }; + + static sp<FLACDecoder> Create(); + + FLAC__StreamMetadata_StreamInfo getStreamInfo() const { + return mStreamInfo; + } + + status_t parseMetadata(const uint8_t *inBuffer, size_t inBufferLen); + status_t decodeOneFrame(const uint8_t *inBuffer, size_t inBufferLen, + short *outBuffer, size_t *outBufferLen); + void flush(); + +protected: + FLACDecoder(); + virtual ~FLACDecoder() override; + +private: + // stream properties + unsigned getMaxBlockSize() const { + return mStreamInfo.max_blocksize; + } + unsigned getSampleRate() const { + return mStreamInfo.sample_rate; + } + unsigned getChannels() const { + return mStreamInfo.channels; + } + unsigned getBitsPerSample() const { + return mStreamInfo.bits_per_sample; + } + FLAC__uint64 getTotalSamples() const { + return mStreamInfo.total_samples; + } + + status_t addDataToBuffer(const uint8_t *inBuffer, size_t inBufferLen); + + FLAC__StreamDecoder *mDecoder; + + uint8_t *mBuffer; // cache input bit stream data + size_t mBufferLen; // the memory size of |mBuffer| + size_t mBufferPos; // next byte to read in |mBuffer| + // size of input data stored in |mBuffer|, always started at offset 0 + size_t mBufferDataSize; + + // cached when the STREAMINFO metadata is parsed by libFLAC + FLAC__StreamMetadata_StreamInfo mStreamInfo; + bool mStreamInfoValid; + + // cached when a decoded PCM block is "written" by libFLAC decoder + bool mWriteRequested; + bool mWriteCompleted; + FLAC__FrameHeader mWriteHeader; + FLAC__int32 const * mWriteBuffer[kMaxChannels]; + + // most recent error reported by libFLAC decoder + FLAC__StreamDecoderErrorStatus mErrorStatus; + + void (*mCopy)(short *dst, const int *src[kMaxChannels], unsigned nSamples, unsigned nChannels); + + status_t init(); + + // FLAC stream decoder callbacks as C++ instance methods + FLAC__StreamDecoderReadStatus readCallback(FLAC__byte buffer[], size_t *bytes); + FLAC__StreamDecoderWriteStatus writeCallback( + const FLAC__Frame *frame, const FLAC__int32 * const buffer[]); + void metadataCallback(const FLAC__StreamMetadata *metadata); + void errorCallback(FLAC__StreamDecoderErrorStatus status); + + DISALLOW_EVIL_CONSTRUCTORS(FLACDecoder); +}; + +} // namespace android + +#endif // FLAC_DECODER_H_ diff --git a/media/libstagefright/flac/dec/MODULE_LICENSE_APACHE2 b/media/libstagefright/flac/dec/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/media/libstagefright/flac/dec/MODULE_LICENSE_APACHE2 diff --git a/media/libstagefright/flac/dec/NOTICE b/media/libstagefright/flac/dec/NOTICE new file mode 100644 index 0000000000..c5b1efa7aa --- /dev/null +++ b/media/libstagefright/flac/dec/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, 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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp index 9b2e7fa4bc..91462c8046 100644 --- a/media/libstagefright/foundation/Android.bp +++ b/media/libstagefright/foundation/Android.bp @@ -1,5 +1,43 @@ cc_library_shared { name: "libstagefright_foundation", + vendor_available: true, + + include_dirs: [ + "frameworks/av/include", + "frameworks/native/include", + ], + + local_include_dirs: [ + "include/media/stagefright/foundation", + ], + + export_include_dirs: [ + "include", + ], + + header_libs: [ + "libhardware_headers", + ], + + export_shared_lib_headers: [ + "libbinder", + "libui", + ], + + cflags: [ + "-Wno-multichar", + "-Werror", + "-Wall", + ], + + shared_libs: [ + "libbinder", + "libutils", + "libui", + "libcutils", + "liblog", + "libpowermanager", + ], srcs: [ "AAtomizer.cpp", @@ -24,27 +62,15 @@ cc_library_shared { "hexdump.cpp", ], - include_dirs: ["frameworks/av/include/media/stagefright/foundation"], - - export_include_dirs: ["include"], - - shared_libs: [ - "libbinder", - "libutils", - "libui", - "libcutils", - "liblog", - "libpowermanager", - ], - - export_shared_lib_headers: ["libbinder", "libui"], + target: { + vendor: { + exclude_shared_libs: ["libpowermanager"], + exclude_srcs: ["AWakeLock.cpp"], + }, + }, - cflags: [ - "-Wno-multichar", - "-Werror", - "-Wall", - ], clang: true, + sanitize: { misc_undefined: [ "unsigned-integer-overflow", @@ -52,7 +78,7 @@ cc_library_shared { ], cfi: true, diag: { - cfi: true, + cfi: true, }, }, } diff --git a/media/libstagefright/foundation/include b/media/libstagefright/foundation/include deleted file mode 120000 index 3a1af68fd1..0000000000 --- a/media/libstagefright/foundation/include +++ /dev/null @@ -1 +0,0 @@ -../include/
\ No newline at end of file diff --git a/media/libstagefright/include/foundation/AAtomizer.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AAtomizer.h index 5f3a678a72..5f3a678a72 100644 --- a/media/libstagefright/include/foundation/AAtomizer.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AAtomizer.h diff --git a/media/libstagefright/include/foundation/ABase.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ABase.h index 76a787ee5e..76a787ee5e 100644 --- a/media/libstagefright/include/foundation/ABase.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ABase.h diff --git a/media/libstagefright/include/foundation/ABitReader.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ABitReader.h index a30dd2ef7a..a30dd2ef7a 100644 --- a/media/libstagefright/include/foundation/ABitReader.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ABitReader.h diff --git a/media/libstagefright/include/foundation/ABuffer.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ABuffer.h index ef11434dac..ef11434dac 100644 --- a/media/libstagefright/include/foundation/ABuffer.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ABuffer.h diff --git a/media/libstagefright/include/foundation/AData.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h index 49aa0dc446..49aa0dc446 100644 --- a/media/libstagefright/include/foundation/AData.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h diff --git a/media/libstagefright/include/foundation/ADebug.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ADebug.h index 9ad45f359c..b498c91a7d 100644 --- a/media/libstagefright/include/foundation/ADebug.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ADebug.h @@ -53,6 +53,9 @@ inline static const char *asString(status_t i, const char *def = "??") { #define LITERAL_TO_STRING_INTERNAL(x) #x #define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x) +#ifdef CHECK +#undef CHECK +#endif #define CHECK(condition) \ LOG_ALWAYS_FATAL_IF( \ !(condition), \ @@ -92,6 +95,15 @@ MAKE_COMPARATOR(GT,>) } \ } while (false) +#ifdef CHECK_EQ +#undef CHECK_EQ +#undef CHECK_NE +#undef CHECK_LE +#undef CHECK_LT +#undef CHECK_GE +#undef CHECK_GT +#endif + #define CHECK_EQ(x,y) CHECK_OP(x,y,EQ,==) #define CHECK_NE(x,y) CHECK_OP(x,y,NE,!=) #define CHECK_LE(x,y) CHECK_OP(x,y,LE,<=) diff --git a/media/libstagefright/include/foundation/AHandler.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AHandler.h index 53d8a9bbaa..53d8a9bbaa 100644 --- a/media/libstagefright/include/foundation/AHandler.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AHandler.h diff --git a/media/libstagefright/include/foundation/AHandlerReflector.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AHandlerReflector.h index 9d201b56a2..9d201b56a2 100644 --- a/media/libstagefright/include/foundation/AHandlerReflector.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AHandlerReflector.h diff --git a/media/libstagefright/include/foundation/AHierarchicalStateMachine.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AHierarchicalStateMachine.h index 3bb7d751b4..3bb7d751b4 100644 --- a/media/libstagefright/include/foundation/AHierarchicalStateMachine.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AHierarchicalStateMachine.h diff --git a/media/libstagefright/include/foundation/ALookup.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ALookup.h index 5a68806dac..5a68806dac 100644 --- a/media/libstagefright/include/foundation/ALookup.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ALookup.h diff --git a/media/libstagefright/include/foundation/ALooper.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ALooper.h index 09c469b2b8..09c469b2b8 100644 --- a/media/libstagefright/include/foundation/ALooper.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ALooper.h diff --git a/media/libstagefright/include/foundation/ALooperRoster.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ALooperRoster.h index 5873e6822d..5873e6822d 100644 --- a/media/libstagefright/include/foundation/ALooperRoster.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ALooperRoster.h diff --git a/media/libstagefright/include/foundation/AMessage.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h index 8580eb5a3e..8580eb5a3e 100644 --- a/media/libstagefright/include/foundation/AMessage.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h diff --git a/media/libstagefright/include/foundation/ANetworkSession.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ANetworkSession.h index fd3ebaaa28..fd3ebaaa28 100644 --- a/media/libstagefright/include/foundation/ANetworkSession.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ANetworkSession.h diff --git a/media/libstagefright/include/foundation/AString.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AString.h index ff086b3128..ff086b3128 100644 --- a/media/libstagefright/include/foundation/AString.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AString.h diff --git a/media/libstagefright/include/foundation/AStringUtils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AStringUtils.h index 76a77914c9..76a77914c9 100644 --- a/media/libstagefright/include/foundation/AStringUtils.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AStringUtils.h diff --git a/media/libstagefright/include/foundation/AUtils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AUtils.h index 255a0f4dcc..255a0f4dcc 100644 --- a/media/libstagefright/include/foundation/AUtils.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AUtils.h diff --git a/media/libstagefright/include/foundation/AWakeLock.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AWakeLock.h index 323e7d7279..323e7d7279 100644 --- a/media/libstagefright/include/foundation/AWakeLock.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AWakeLock.h diff --git a/media/libstagefright/include/foundation/ColorUtils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h index b889a02f9d..b889a02f9d 100644 --- a/media/libstagefright/include/foundation/ColorUtils.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h diff --git a/media/libstagefright/include/foundation/FileDescriptor.h b/media/libstagefright/foundation/include/media/stagefright/foundation/FileDescriptor.h index 7acf4b87cb..7acf4b87cb 100644 --- a/media/libstagefright/include/foundation/FileDescriptor.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/FileDescriptor.h diff --git a/media/libstagefright/include/foundation/Flagged.h b/media/libstagefright/foundation/include/media/stagefright/foundation/Flagged.h index bf0afbfaaf..bf0afbfaaf 100644 --- a/media/libstagefright/include/foundation/Flagged.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/Flagged.h diff --git a/media/libstagefright/include/foundation/MediaBufferBase.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaBufferBase.h index 99418fb766..99418fb766 100644 --- a/media/libstagefright/include/foundation/MediaBufferBase.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaBufferBase.h diff --git a/media/libstagefright/include/foundation/Mutexed.h b/media/libstagefright/foundation/include/media/stagefright/foundation/Mutexed.h index 143b140423..143b140423 100644 --- a/media/libstagefright/include/foundation/Mutexed.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/Mutexed.h diff --git a/media/libstagefright/include/foundation/ParsedMessage.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ParsedMessage.h index 9d43a93319..9d43a93319 100644 --- a/media/libstagefright/include/foundation/ParsedMessage.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ParsedMessage.h diff --git a/media/libstagefright/include/foundation/TypeTraits.h b/media/libstagefright/foundation/include/media/stagefright/foundation/TypeTraits.h index 1250e9b973..1250e9b973 100644 --- a/media/libstagefright/include/foundation/TypeTraits.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/TypeTraits.h diff --git a/media/libstagefright/include/foundation/base64.h b/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h index e340b89401..e340b89401 100644 --- a/media/libstagefright/include/foundation/base64.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h diff --git a/media/libstagefright/include/foundation/hexdump.h b/media/libstagefright/foundation/include/media/stagefright/foundation/hexdump.h index 8360c5a380..8360c5a380 100644 --- a/media/libstagefright/include/foundation/hexdump.h +++ b/media/libstagefright/foundation/include/media/stagefright/foundation/hexdump.h diff --git a/media/libstagefright/http/Android.bp b/media/libstagefright/http/Android.bp new file mode 100644 index 0000000000..5d90b0abb8 --- /dev/null +++ b/media/libstagefright/http/Android.bp @@ -0,0 +1,43 @@ +cc_library_shared { + name: "libstagefright_http_support", + + srcs: ["HTTPHelper.cpp"], + + include_dirs: [ + "frameworks/av/media/libstagefright", + "frameworks/native/include/media/openmax", + "frameworks/base/core/jni", + ], + + shared_libs: [ + "liblog", + "libutils", + "libbinder", + "libandroid_runtime", + "libmedia", + ], + + export_include_dirs: ["."], + + cflags: [ + "-Wno-multichar", + "-Werror", + "-Wall", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + product_variables: { + pdk: { + enabled: false, + }, + }, +} diff --git a/media/libstagefright/http/Android.mk b/media/libstagefright/http/Android.mk deleted file mode 100644 index 9c16f4012d..0000000000 --- a/media/libstagefright/http/Android.mk +++ /dev/null @@ -1,30 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -ifneq ($(TARGET_BUILD_PDK), true) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - HTTPHelper.cpp \ - -LOCAL_C_INCLUDES:= \ - $(TOP)/frameworks/av/media/libstagefright \ - $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/frameworks/base/core/jni \ - -LOCAL_SHARED_LIBRARIES := \ - liblog libutils libbinder \ - libandroid_runtime \ - libmedia - -LOCAL_MODULE:= libstagefright_http_support - -LOCAL_CFLAGS += -Wno-multichar - -LOCAL_CFLAGS += -Werror -Wall -LOCAL_SANITIZE := signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -include $(BUILD_SHARED_LIBRARY) - -endif diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp new file mode 100644 index 0000000000..e415334403 --- /dev/null +++ b/media/libstagefright/httplive/Android.bp @@ -0,0 +1,43 @@ +cc_library_shared { + name: "libstagefright_httplive", + + srcs: [ + "HTTPDownloader.cpp", + "LiveDataSource.cpp", + "LiveSession.cpp", + "M3UParser.cpp", + "PlaylistFetcher.cpp", + ], + + include_dirs: [ + "frameworks/av/media/libstagefright", + "frameworks/native/include/media/openmax", + ], + + cflags: [ + "-Werror", + "-Wall", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + shared_libs: [ + "liblog", + "libbinder", + "libcrypto", + "libcutils", + "libmedia", + "libstagefright", + "libstagefright_foundation", + "libutils", + ], +} diff --git a/media/libstagefright/httplive/Android.mk b/media/libstagefright/httplive/Android.mk deleted file mode 100644 index 1903d10415..0000000000 --- a/media/libstagefright/httplive/Android.mk +++ /dev/null @@ -1,36 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - HTTPDownloader.cpp \ - LiveDataSource.cpp \ - LiveSession.cpp \ - M3UParser.cpp \ - PlaylistFetcher.cpp \ - -LOCAL_C_INCLUDES:= \ - $(TOP)/frameworks/av/media/libstagefright \ - $(TOP)/frameworks/native/include/media/openmax - -LOCAL_CFLAGS += -Werror -Wall -LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_SHARED_LIBRARIES := \ - liblog \ - libbinder \ - libcrypto \ - libcutils \ - libmedia \ - libstagefright \ - libstagefright_foundation \ - libutils \ - -LOCAL_MODULE:= libstagefright_httplive - -ifeq ($(TARGET_ARCH),arm) - LOCAL_CFLAGS += -Wno-psabi -endif - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index e144942e8c..143fd59bd9 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -699,7 +699,7 @@ void LiveSession::onMessageReceived(const sp<AMessage> &msg) { } if (mContinuation != NULL) { - CHECK_GT(mContinuationCounter, 0); + CHECK_GT(mContinuationCounter, 0u); if (--mContinuationCounter == 0) { mContinuation->post(); } @@ -1550,7 +1550,7 @@ void LiveSession::changeConfiguration( mOrigBandwidthIndex, mCurBandwidthIndex); } } - CHECK_LT(mCurBandwidthIndex, mBandwidthItems.size()); + CHECK_LT((size_t)mCurBandwidthIndex, mBandwidthItems.size()); const BandwidthItem &item = mBandwidthItems.itemAt(mCurBandwidthIndex); uint32_t streamMask = 0; // streams that should be fetched by the new fetcher diff --git a/media/libstagefright/id3/Android.bp b/media/libstagefright/id3/Android.bp new file mode 100644 index 0000000000..30008d97cb --- /dev/null +++ b/media/libstagefright/id3/Android.bp @@ -0,0 +1,53 @@ +cc_library_static { + name: "libstagefright_id3", + + srcs: ["ID3.cpp"], + + cflags: [ + "-Werror", + "-Wall", + ], + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + shared_libs: ["libmedia"], +} + +//############################################################################### + +cc_test { + name: "testid3", + gtest: false, + + srcs: ["testid3.cpp"], + + cflags: [ + "-Werror", + "-Wall", + ], + + shared_libs: [ + "libstagefright", + "libutils", + "liblog", + "libbinder", + "libstagefright_foundation", + ], + + static_libs: ["libstagefright_id3"], + + sanitize: { + cfi: true, + diag: { + cfi: true, + }, + }, + +} diff --git a/media/libstagefright/id3/Android.mk b/media/libstagefright/id3/Android.mk deleted file mode 100644 index 827703ec54..0000000000 --- a/media/libstagefright/id3/Android.mk +++ /dev/null @@ -1,36 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - ID3.cpp - -LOCAL_CFLAGS += -Werror -Wall -LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_SHARED_LIBRARIES := libmedia - -LOCAL_MODULE := libstagefright_id3 - -include $(BUILD_STATIC_LIBRARY) - -################################################################################ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - testid3.cpp - -LOCAL_CFLAGS += -Werror -Wall - -LOCAL_SHARED_LIBRARIES := \ - libstagefright libutils liblog libbinder libstagefright_foundation - -LOCAL_STATIC_LIBRARIES := \ - libstagefright_id3 - -LOCAL_MODULE_TAGS := optional - -LOCAL_MODULE := testid3 - -include $(BUILD_EXECUTABLE) diff --git a/media/libstagefright/include/SoftVideoEncoderOMXComponent.h b/media/libstagefright/include/SoftVideoEncoderOMXComponent.h index 02555a2f34..2d6f31b84f 100644 --- a/media/libstagefright/include/SoftVideoEncoderOMXComponent.h +++ b/media/libstagefright/include/SoftVideoEncoderOMXComponent.h @@ -21,7 +21,6 @@ #include <media/IOMX.h> #include "SimpleSoftOMXComponent.h" -#include <system/window.h> struct hw_module_t; diff --git a/media/libstagefright/include/AACWriter.h b/media/libstagefright/include/media/stagefright/AACWriter.h index a1f63d7ec1..a1f63d7ec1 100644 --- a/media/libstagefright/include/AACWriter.h +++ b/media/libstagefright/include/media/stagefright/AACWriter.h diff --git a/media/libstagefright/include/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h index 22b8657de7..d049df55d0 100644 --- a/media/libstagefright/include/ACodec.h +++ b/media/libstagefright/include/media/stagefright/ACodec.h @@ -15,7 +15,6 @@ */ #ifndef A_CODEC_H_ - #define A_CODEC_H_ #include <stdint.h> @@ -30,6 +29,7 @@ #include <utils/NativeHandle.h> #include <OMX_Audio.h> #include <hardware/gralloc.h> +#include <nativebase/nativebase.h> #define TRACK_BUFFER_TIMING 0 diff --git a/media/libstagefright/include/AMRWriter.h b/media/libstagefright/include/media/stagefright/AMRWriter.h index fbbdf2e436..fbbdf2e436 100644 --- a/media/libstagefright/include/AMRWriter.h +++ b/media/libstagefright/include/media/stagefright/AMRWriter.h diff --git a/media/libstagefright/include/AudioPlayer.h b/media/libstagefright/include/media/stagefright/AudioPlayer.h index f7499b6afc..f7499b6afc 100644 --- a/media/libstagefright/include/AudioPlayer.h +++ b/media/libstagefright/include/media/stagefright/AudioPlayer.h diff --git a/media/libstagefright/include/AudioSource.h b/media/libstagefright/include/media/stagefright/AudioSource.h index f20c2cd81a..1595be4ee1 100644 --- a/media/libstagefright/include/AudioSource.h +++ b/media/libstagefright/include/media/stagefright/AudioSource.h @@ -53,6 +53,7 @@ struct AudioSource : public MediaSource, public MediaBufferObserver { virtual status_t read( MediaBuffer **buffer, const ReadOptions *options = NULL); + virtual status_t setStopTimeUs(int64_t stopTimeUs); status_t dataCallback(const AudioRecord::Buffer& buffer); virtual void signalBufferReturned(MediaBuffer *buffer); @@ -85,6 +86,8 @@ private: bool mTrackMaxAmplitude; int64_t mStartTimeUs; + int64_t mStopSystemTimeUs; + int64_t mLastFrameTimestampUs; int16_t mMaxAmplitude; int64_t mPrevSampleTimeUs; int64_t mInitialReadTimeUs; @@ -92,6 +95,7 @@ private: int64_t mNumFramesSkipped; int64_t mNumFramesLost; int64_t mNumClientOwnedBuffers; + bool mNoMoreFramesToRead; List<MediaBuffer * > mBuffersReceived; diff --git a/media/libstagefright/include/BufferProducerWrapper.h b/media/libstagefright/include/media/stagefright/BufferProducerWrapper.h index 4caa2c6192..4caa2c6192 100644 --- a/media/libstagefright/include/BufferProducerWrapper.h +++ b/media/libstagefright/include/media/stagefright/BufferProducerWrapper.h diff --git a/media/libstagefright/include/CameraSource.h b/media/libstagefright/include/media/stagefright/CameraSource.h index aa56d2780c..2aaa884309 100644 --- a/media/libstagefright/include/CameraSource.h +++ b/media/libstagefright/include/media/stagefright/CameraSource.h @@ -98,6 +98,7 @@ public: virtual status_t stop() { return reset(); } virtual status_t read( MediaBuffer **buffer, const ReadOptions *options = NULL); + virtual status_t setStopTimeUs(int64_t stopTimeUs); /** * Check whether a CameraSource object is properly initialized. @@ -253,6 +254,7 @@ private: List<int64_t> mFrameTimes; int64_t mFirstFrameTimeUs; + int64_t mStopSystemTimeUs; int32_t mNumFramesDropped; int32_t mNumGlitches; int64_t mGlitchDurationThresholdUs; diff --git a/media/libstagefright/include/CameraSourceTimeLapse.h b/media/libstagefright/include/media/stagefright/CameraSourceTimeLapse.h index b066f9a463..b066f9a463 100644 --- a/media/libstagefright/include/CameraSourceTimeLapse.h +++ b/media/libstagefright/include/media/stagefright/CameraSourceTimeLapse.h diff --git a/media/libstagefright/include/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h index 845146d70f..0dd77ba4d0 100644 --- a/media/libstagefright/include/CodecBase.h +++ b/media/libstagefright/include/media/stagefright/CodecBase.h @@ -40,7 +40,7 @@ namespace android { using namespace media; class BufferChannelBase; -class BufferProducerWrapper; +struct BufferProducerWrapper; class MediaCodecBuffer; struct PersistentSurface; struct RenderedFrameInfo; diff --git a/media/libstagefright/include/ColorConverter.h b/media/libstagefright/include/media/stagefright/ColorConverter.h index 270c80966f..270c80966f 100644 --- a/media/libstagefright/include/ColorConverter.h +++ b/media/libstagefright/include/media/stagefright/ColorConverter.h diff --git a/media/libstagefright/include/DataSource.h b/media/libstagefright/include/media/stagefright/DataSource.h index 8f2c7ebe2a..63eccea065 100644 --- a/media/libstagefright/include/DataSource.h +++ b/media/libstagefright/include/media/stagefright/DataSource.h @@ -156,7 +156,7 @@ bool DataSource::getVector(off64_t offset, Vector<T>* x, size_t count, if (numBytesRead == -1) { // If readAt() returns -1, there is an error. return false; } - if (numBytesRead < numBytesPerChunk) { + if (static_cast<size_t>(numBytesRead) < numBytesPerChunk) { // This case is triggered when the stream ends before the whole // chunk is read. x->appendArray(tmp, (size_t)numBytesRead / sizeof(T)); diff --git a/media/libstagefright/include/DataURISource.h b/media/libstagefright/include/media/stagefright/DataURISource.h index 693562edc3..693562edc3 100644 --- a/media/libstagefright/include/DataURISource.h +++ b/media/libstagefright/include/media/stagefright/DataURISource.h diff --git a/media/libstagefright/include/DataUriSource.h b/media/libstagefright/include/media/stagefright/DataUriSource.h index d223c0640d..d223c0640d 100644 --- a/media/libstagefright/include/DataUriSource.h +++ b/media/libstagefright/include/media/stagefright/DataUriSource.h diff --git a/media/libstagefright/include/FileSource.h b/media/libstagefright/include/media/stagefright/FileSource.h index 7267e9a7a6..7267e9a7a6 100644 --- a/media/libstagefright/include/FileSource.h +++ b/media/libstagefright/include/media/stagefright/FileSource.h diff --git a/media/libstagefright/include/FrameRenderTracker.h b/media/libstagefright/include/media/stagefright/FrameRenderTracker.h index 6cbf85dc69..044699c6da 100644 --- a/media/libstagefright/include/FrameRenderTracker.h +++ b/media/libstagefright/include/media/stagefright/FrameRenderTracker.h @@ -20,13 +20,14 @@ #include <utils/RefBase.h> #include <utils/Timers.h> -#include <system/window.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AString.h> #include <list> +struct ANativeWindowBuffer; + namespace android { class Fence; diff --git a/media/libstagefright/include/JPEGSource.h b/media/libstagefright/include/media/stagefright/JPEGSource.h index 1b7e91b866..1b7e91b866 100644 --- a/media/libstagefright/include/JPEGSource.h +++ b/media/libstagefright/include/media/stagefright/JPEGSource.h diff --git a/media/libstagefright/include/MPEG2TSWriter.h b/media/libstagefright/include/media/stagefright/MPEG2TSWriter.h index 4516fb6ddc..4516fb6ddc 100644 --- a/media/libstagefright/include/MPEG2TSWriter.h +++ b/media/libstagefright/include/media/stagefright/MPEG2TSWriter.h diff --git a/media/libstagefright/include/MPEG4Writer.h b/media/libstagefright/include/media/stagefright/MPEG4Writer.h index 39e7d01d48..dd357ccfc6 100644 --- a/media/libstagefright/include/MPEG4Writer.h +++ b/media/libstagefright/include/media/stagefright/MPEG4Writer.h @@ -29,7 +29,7 @@ namespace android { -class AMessage; +struct AMessage; class MediaBuffer; class MetaData; @@ -83,6 +83,10 @@ private: kWhatSwitch = 'swch', }; + enum { + kMaxCttsOffsetTimeUs = 1000000LL, // 1 second + }; + int mFd; int mNextFd; sp<MetaData> mStartMeta; diff --git a/media/libstagefright/include/MediaAdapter.h b/media/libstagefright/include/media/stagefright/MediaAdapter.h index 369fce62d0..369fce62d0 100644 --- a/media/libstagefright/include/MediaAdapter.h +++ b/media/libstagefright/include/media/stagefright/MediaAdapter.h diff --git a/media/libstagefright/include/MediaBuffer.h b/media/libstagefright/include/media/stagefright/MediaBuffer.h index 2c0ebe798c..e74410d1b0 100644 --- a/media/libstagefright/include/MediaBuffer.h +++ b/media/libstagefright/include/media/stagefright/MediaBuffer.h @@ -223,7 +223,7 @@ private: // Caution: atomic_int_fast32_t is 64 bits on LP64. std::atomic_int_least32_t mFlags; std::atomic_int_least32_t mRemoteRefcount; - int32_t unused[6]; // additional buffer space + int32_t unused[6] __attribute__((__unused__)); // additional buffer space }; inline SharedControl *getSharedControl() const { diff --git a/media/libstagefright/include/MediaBufferGroup.h b/media/libstagefright/include/media/stagefright/MediaBufferGroup.h index 30514062da..30514062da 100644 --- a/media/libstagefright/include/MediaBufferGroup.h +++ b/media/libstagefright/include/media/stagefright/MediaBufferGroup.h diff --git a/media/libstagefright/include/MediaClock.h b/media/libstagefright/include/media/stagefright/MediaClock.h index dd1a8091c7..dd1a8091c7 100644 --- a/media/libstagefright/include/MediaClock.h +++ b/media/libstagefright/include/media/stagefright/MediaClock.h diff --git a/media/libstagefright/include/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h index 4140266765..4140266765 100644 --- a/media/libstagefright/include/MediaCodec.h +++ b/media/libstagefright/include/media/stagefright/MediaCodec.h diff --git a/media/libstagefright/include/MediaCodecList.h b/media/libstagefright/include/media/stagefright/MediaCodecList.h index 430bc16d86..430bc16d86 100644 --- a/media/libstagefright/include/MediaCodecList.h +++ b/media/libstagefright/include/media/stagefright/MediaCodecList.h diff --git a/media/libstagefright/include/MediaCodecSource.h b/media/libstagefright/include/media/stagefright/MediaCodecSource.h index 5e99b786a3..3ac539e13d 100644 --- a/media/libstagefright/include/MediaCodecSource.h +++ b/media/libstagefright/include/media/stagefright/MediaCodecSource.h @@ -54,11 +54,14 @@ struct MediaCodecSource : public MediaSource, // MediaSource virtual status_t start(MetaData *params = NULL); virtual status_t stop(); - virtual status_t pause(MetaData *params = NULL); + virtual status_t pause() { return pause(NULL); } + virtual status_t pause(MetaData *params); virtual sp<MetaData> getFormat(); virtual status_t read( MediaBuffer **buffer, const ReadOptions *options = NULL); + virtual status_t setStopTimeUs(int64_t stopTimeUs); + // MediaBufferObserver virtual void signalBufferReturned(MediaBuffer *buffer); @@ -66,11 +69,7 @@ struct MediaCodecSource : public MediaSource, // for AHandlerReflector void onMessageReceived(const sp<AMessage> &msg); - // Set GraphicBufferSource stop time. GraphicBufferSource will stop - // after receiving a buffer with timestamp larger or equal than stopTimeUs. - // All the buffers with timestamp larger or equal to stopTimeUs will be - // discarded. stopTimeUs uses SYSTEM_TIME_MONOTONIC time base. - status_t setStopStimeUs(int64_t stopTimeUs); + protected: virtual ~MediaCodecSource(); @@ -85,7 +84,7 @@ private: kWhatStop, kWhatPause, kWhatSetInputBufferTimeOffset, - kWhatSetStopTimeOffset, + kWhatSetStopTimeUs, kWhatGetFirstSampleSystemTimeUs, kWhatStopStalled, }; diff --git a/media/libstagefright/include/MediaDefs.h b/media/libstagefright/include/media/stagefright/MediaDefs.h index 359fb692c6..359fb692c6 100644 --- a/media/libstagefright/include/MediaDefs.h +++ b/media/libstagefright/include/media/stagefright/MediaDefs.h diff --git a/media/libstagefright/include/MediaErrors.h b/media/libstagefright/include/media/stagefright/MediaErrors.h index 2e663eca0c..2e663eca0c 100644 --- a/media/libstagefright/include/MediaErrors.h +++ b/media/libstagefright/include/media/stagefright/MediaErrors.h diff --git a/media/libstagefright/include/MediaExtractor.h b/media/libstagefright/include/media/stagefright/MediaExtractor.h index 073391fb8e..a856b2bb05 100644 --- a/media/libstagefright/include/MediaExtractor.h +++ b/media/libstagefright/include/media/stagefright/MediaExtractor.h @@ -70,7 +70,7 @@ public: } virtual void setUID(uid_t /*uid*/) { } - virtual status_t setMediaCas(const sp<ICas> &cas) override { + virtual status_t setMediaCas(const sp<ICas>& /*cas*/) override { return INVALID_OPERATION; } diff --git a/media/libstagefright/include/MediaFilter.h b/media/libstagefright/include/media/stagefright/MediaFilter.h index 0c10d11b52..0c10d11b52 100644 --- a/media/libstagefright/include/MediaFilter.h +++ b/media/libstagefright/include/media/stagefright/MediaFilter.h diff --git a/media/libstagefright/include/MediaHTTP.h b/media/libstagefright/include/media/stagefright/MediaHTTP.h index 006d8d896b..006d8d896b 100644 --- a/media/libstagefright/include/MediaHTTP.h +++ b/media/libstagefright/include/media/stagefright/MediaHTTP.h diff --git a/media/libstagefright/include/MediaMuxer.h b/media/libstagefright/include/media/stagefright/MediaMuxer.h index 63c3ca55f0..63c3ca55f0 100644 --- a/media/libstagefright/include/MediaMuxer.h +++ b/media/libstagefright/include/media/stagefright/MediaMuxer.h diff --git a/media/libstagefright/include/MediaSource.h b/media/libstagefright/include/media/stagefright/MediaSource.h index 1bd3ed036f..14adb0524a 100644 --- a/media/libstagefright/include/MediaSource.h +++ b/media/libstagefright/include/media/stagefright/MediaSource.h @@ -75,6 +75,23 @@ struct MediaSource : public BnMediaSource { return ERROR_UNSUPPORTED; } + // The consumer of this media source requests the source stops sending + // buffers with timestamp larger than or equal to stopTimeUs. stopTimeUs + // must be in the same time base as the startTime passed in start(). If + // source does not support this request, ERROR_UNSUPPORTED will be returned. + // If stopTimeUs is invalid, BAD_VALUE will be returned. This could be + // called at any time even before source starts and it could be called + // multiple times. Setting stopTimeUs to be -1 will effectively cancel the stopTimeUs + // set previously. If stopTimeUs is larger than or equal to last buffer's timestamp, + // source will start to drop buffer when it gets a buffer with timestamp larger + // than or equal to stopTimeUs. If stopTimeUs is smaller than or equal to last + // buffer's timestamp, source will drop all the incoming buffers immediately. + // After setting stopTimeUs, source may still stop sending buffers with timestamp + // less than stopTimeUs if it is stopped by the consumer. + virtual status_t setStopTimeUs(int64_t /* stopTimeUs */) { + return ERROR_UNSUPPORTED; + } + protected: virtual ~MediaSource(); diff --git a/media/libstagefright/include/MediaSync.h b/media/libstagefright/include/media/stagefright/MediaSync.h index ef8cb23d7f..ef8cb23d7f 100644 --- a/media/libstagefright/include/MediaSync.h +++ b/media/libstagefright/include/media/stagefright/MediaSync.h diff --git a/media/libstagefright/include/MediaWriter.h b/media/libstagefright/include/media/stagefright/MediaWriter.h index 9c30ffa519..cd4af4d22a 100644 --- a/media/libstagefright/include/MediaWriter.h +++ b/media/libstagefright/include/media/stagefright/MediaWriter.h @@ -50,7 +50,7 @@ struct MediaWriter : public RefBase { virtual void setStartTimeOffsetMs(int /*ms*/) {} virtual int32_t getStartTimeOffsetMs() const { return 0; } - virtual status_t setNextFd(int fd) { return INVALID_OPERATION; } + virtual status_t setNextFd(int /*fd*/) { return INVALID_OPERATION; } protected: virtual ~MediaWriter() {} diff --git a/media/libstagefright/include/MetaData.h b/media/libstagefright/include/media/stagefright/MetaData.h index 7afd22d872..9676b9700d 100644 --- a/media/libstagefright/include/MetaData.h +++ b/media/libstagefright/include/media/stagefright/MetaData.h @@ -64,6 +64,7 @@ enum { kKeyOpusHeader = 'ohdr', // raw data kKeyOpusCodecDelay = 'ocod', // uint64_t (codec delay in ns) kKeyOpusSeekPreRoll = 'ospr', // uint64_t (seek preroll in ns) + kKeyFlacMetadata = 'flMd', // raw data kKeyVp9CodecPrivate = 'vp9p', // raw data (vp9 csd information) kKeyWantsNALFragments = 'NALf', kKeyIsSyncFrame = 'sync', // int32_t (bool) diff --git a/media/libstagefright/include/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h index 3e3cc17d8c..3e3cc17d8c 100644 --- a/media/libstagefright/include/NuMediaExtractor.h +++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h diff --git a/media/libstagefright/include/OMXClient.h b/media/libstagefright/include/media/stagefright/OMXClient.h index 203a181555..203a181555 100644 --- a/media/libstagefright/include/OMXClient.h +++ b/media/libstagefright/include/media/stagefright/OMXClient.h diff --git a/media/libstagefright/include/PersistentSurface.h b/media/libstagefright/include/media/stagefright/PersistentSurface.h index d8b75a2402..d8b75a2402 100644 --- a/media/libstagefright/include/PersistentSurface.h +++ b/media/libstagefright/include/media/stagefright/PersistentSurface.h diff --git a/media/libstagefright/include/ProcessInfo.h b/media/libstagefright/include/media/stagefright/ProcessInfo.h index 0be1a52e58..0be1a52e58 100644 --- a/media/libstagefright/include/ProcessInfo.h +++ b/media/libstagefright/include/media/stagefright/ProcessInfo.h diff --git a/media/libstagefright/include/ProcessInfoInterface.h b/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h index b39112afce..b39112afce 100644 --- a/media/libstagefright/include/ProcessInfoInterface.h +++ b/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h diff --git a/media/libstagefright/include/RemoteDataSource.h b/media/libstagefright/include/media/stagefright/RemoteDataSource.h index c91ddfcee3..c91ddfcee3 100644 --- a/media/libstagefright/include/RemoteDataSource.h +++ b/media/libstagefright/include/media/stagefright/RemoteDataSource.h diff --git a/media/libstagefright/include/RenderScriptWrapper.h b/media/libstagefright/include/media/stagefright/RenderScriptWrapper.h index b42649e0de..b42649e0de 100644 --- a/media/libstagefright/include/RenderScriptWrapper.h +++ b/media/libstagefright/include/media/stagefright/RenderScriptWrapper.h diff --git a/media/libstagefright/include/SimpleDecodingSource.h b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h index e6aee6a14a..a000fdea82 100644 --- a/media/libstagefright/include/SimpleDecodingSource.h +++ b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h @@ -17,8 +17,6 @@ #ifndef SIMPLE_DECODING_SOURCE_H_ #define SIMPLE_DECODING_SOURCE_H_ -#include <system/window.h> - #include <media/stagefright/MediaSource.h> #include <media/stagefright/foundation/AString.h> #include <media/stagefright/foundation/Mutexed.h> @@ -26,6 +24,8 @@ #include <utils/Condition.h> #include <utils/StrongPointer.h> +struct ANativeWindow; + namespace android { struct ALooper; @@ -45,10 +45,13 @@ public: // does not support secure input or pausing. // if |desiredCodec| is given, use this specific codec. static sp<SimpleDecodingSource> Create( - const sp<IMediaSource> &source, uint32_t flags = 0, - const sp<ANativeWindow> &nativeWindow = NULL, + const sp<IMediaSource> &source, uint32_t flags, + const sp<ANativeWindow> &nativeWindow, const char *desiredCodec = NULL); + static sp<SimpleDecodingSource> Create( + const sp<IMediaSource> &source, uint32_t flags = 0); + virtual ~SimpleDecodingSource(); // starts this source (and it's underlying source). |params| is ignored. diff --git a/media/libstagefright/include/SkipCutBuffer.h b/media/libstagefright/include/media/stagefright/SkipCutBuffer.h index 0fb5690ffa..0fb5690ffa 100644 --- a/media/libstagefright/include/SkipCutBuffer.h +++ b/media/libstagefright/include/media/stagefright/SkipCutBuffer.h diff --git a/media/libstagefright/include/StagefrightMediaScanner.h b/media/libstagefright/include/media/stagefright/StagefrightMediaScanner.h index eb3accc973..eb3accc973 100644 --- a/media/libstagefright/include/StagefrightMediaScanner.h +++ b/media/libstagefright/include/media/stagefright/StagefrightMediaScanner.h diff --git a/media/libstagefright/include/SurfaceMediaSource.h b/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h index ae19a75da5..d38c337e24 100644 --- a/media/libstagefright/include/SurfaceMediaSource.h +++ b/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h @@ -106,8 +106,8 @@ public: void setFrameAvailableListener(const sp<FrameAvailableListener>& listener); // dump our state in a String - void dump(String8& result) const; - void dump(String8& result, const char* prefix, char* buffer, + void dumpState(String8& result) const; + void dumpState(String8& result, const char* prefix, char* buffer, size_t SIZE) const; // metaDataStoredInVideoBuffers tells the encoder what kind of metadata diff --git a/media/libstagefright/include/SurfaceUtils.h b/media/libstagefright/include/media/stagefright/SurfaceUtils.h index a7747c79bc..a7747c79bc 100644 --- a/media/libstagefright/include/SurfaceUtils.h +++ b/media/libstagefright/include/media/stagefright/SurfaceUtils.h diff --git a/media/libstagefright/include/Utils.h b/media/libstagefright/include/media/stagefright/Utils.h index 88a416a37d..88a416a37d 100644 --- a/media/libstagefright/include/Utils.h +++ b/media/libstagefright/include/media/stagefright/Utils.h diff --git a/media/libstagefright/include/VideoFrameScheduler.h b/media/libstagefright/include/media/stagefright/VideoFrameScheduler.h index 9d97dfde6e..9d97dfde6e 100644 --- a/media/libstagefright/include/VideoFrameScheduler.h +++ b/media/libstagefright/include/media/stagefright/VideoFrameScheduler.h diff --git a/media/libstagefright/include/YUVCanvas.h b/media/libstagefright/include/media/stagefright/YUVCanvas.h index ff70923f04..ff70923f04 100644 --- a/media/libstagefright/include/YUVCanvas.h +++ b/media/libstagefright/include/media/stagefright/YUVCanvas.h diff --git a/media/libstagefright/include/YUVImage.h b/media/libstagefright/include/media/stagefright/YUVImage.h index 4e98618948..4e98618948 100644 --- a/media/libstagefright/include/YUVImage.h +++ b/media/libstagefright/include/media/stagefright/YUVImage.h diff --git a/media/libstagefright/include/media/stagefright/foundation b/media/libstagefright/include/media/stagefright/foundation new file mode 120000 index 0000000000..b9fd3b3611 --- /dev/null +++ b/media/libstagefright/include/media/stagefright/foundation @@ -0,0 +1 @@ +../../../foundation/include/media/stagefright/foundation/
\ No newline at end of file diff --git a/media/libstagefright/matroska/Android.bp b/media/libstagefright/matroska/Android.bp new file mode 100644 index 0000000000..ec2fb4b776 --- /dev/null +++ b/media/libstagefright/matroska/Android.bp @@ -0,0 +1,35 @@ +cc_library_static { + name: "libstagefright_matroska", + + srcs: ["MatroskaExtractor.cpp"], + + include_dirs: [ + "external/flac/include", + "external/libvpx/libwebm", + "frameworks/native/include/media/openmax", + "frameworks/av/media/libstagefright/flac/dec", + "frameworks/av/media/libstagefright/include", + ], + + cflags: [ + "-Wno-multichar", + "-Werror", + "-Wall", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + shared_libs: [ + "libmedia", + "libstagefright_flacdec" + ], +} diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk deleted file mode 100644 index 7de5dbeb7f..0000000000 --- a/media/libstagefright/matroska/Android.mk +++ /dev/null @@ -1,20 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - MatroskaExtractor.cpp - -LOCAL_C_INCLUDES:= \ - $(TOP)/external/libvpx/libwebm \ - $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/frameworks/av/media/libstagefright/include \ - -LOCAL_CFLAGS += -Wno-multichar -Werror -Wall -LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_SHARED_LIBRARIES := libmedia - -LOCAL_MODULE:= libstagefright_matroska - -include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index 81179d1709..813a257e9f 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -18,6 +18,7 @@ #define LOG_TAG "MatroskaExtractor" #include <utils/Log.h> +#include "FLACDecoder.h" #include "MatroskaExtractor.h" #include "avc_utils.h" @@ -1051,6 +1052,37 @@ status_t addVorbisCodecInfo( return OK; } +static status_t addFlacMetadata( + const sp<MetaData> &meta, + const void *codecPrivate, size_t codecPrivateSize) { + // hexdump(codecPrivate, codecPrivateSize); + + meta->setData(kKeyFlacMetadata, 0, codecPrivate, codecPrivateSize); + + int32_t maxInputSize = 64 << 10; + sp<FLACDecoder> flacDecoder = FLACDecoder::Create(); + if (flacDecoder != NULL + && flacDecoder->parseMetadata((const uint8_t*)codecPrivate, codecPrivateSize) == OK) { + FLAC__StreamMetadata_StreamInfo streamInfo = flacDecoder->getStreamInfo(); + maxInputSize = streamInfo.max_framesize; + if (maxInputSize == 0) { + // In case max framesize is not available, use raw data size as max framesize, + // assuming there is no expansion. + if (streamInfo.max_blocksize != 0 + && streamInfo.channels != 0 + && ((streamInfo.bits_per_sample + 7) / 8) > + INT32_MAX / streamInfo.max_blocksize / streamInfo.channels) { + return ERROR_MALFORMED; + } + maxInputSize = ((streamInfo.bits_per_sample + 7) / 8) + * streamInfo.max_blocksize * streamInfo.channels; + } + } + meta->setInt32(kKeyMaxInputSize, maxInputSize); + + return OK; +} + status_t MatroskaExtractor::synthesizeAVCC(TrackInfo *trackInfo, size_t index) { BlockIterator iter(this, trackInfo->mTrackNum, index); if (iter.eos()) { @@ -1363,6 +1395,9 @@ void MatroskaExtractor::addTracks() { mSeekPreRollNs = track->GetSeekPreRoll(); } else if (!strcmp("A_MPEG/L3", codecID)) { meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG); + } else if (!strcmp("A_FLAC", codecID)) { + meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_FLAC); + err = addFlacMetadata(meta, codecPrivate, codecPrivateSize); } else { ALOGW("%s is not supported.", codecID); continue; diff --git a/media/libstagefright/mpeg2ts/Android.bp b/media/libstagefright/mpeg2ts/Android.bp new file mode 100644 index 0000000000..96eb5bf8cc --- /dev/null +++ b/media/libstagefright/mpeg2ts/Android.bp @@ -0,0 +1,39 @@ +cc_library_static { + name: "libstagefright_mpeg2ts", + + srcs: [ + "AnotherPacketSource.cpp", + "ATSParser.cpp", + "CasManager.cpp", + "ESQueue.cpp", + "HlsSampleDecryptor.cpp", + "MPEG2PSExtractor.cpp", + "MPEG2TSExtractor.cpp", + ], + + include_dirs: [ + "frameworks/av/media/libstagefright", + "frameworks/native/include/media/openmax", + ], + + cflags: [ + "-Werror", + "-Wall", + ], + + sanitize: { + misc_undefined: [ + "unsigned-integer-overflow", + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + shared_libs: [ + "libcrypto", + "libmedia", + ], +} diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk deleted file mode 100644 index 20acfe7b41..0000000000 --- a/media/libstagefright/mpeg2ts/Android.mk +++ /dev/null @@ -1,32 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - AnotherPacketSource.cpp \ - ATSParser.cpp \ - CasManager.cpp \ - ESQueue.cpp \ - HlsSampleDecryptor.cpp \ - MPEG2PSExtractor.cpp \ - MPEG2TSExtractor.cpp \ - -LOCAL_C_INCLUDES:= \ - $(TOP)/frameworks/av/media/libstagefright \ - $(TOP)/frameworks/native/include/media/openmax - -LOCAL_CFLAGS += -Werror -Wall -LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_SHARED_LIBRARIES := \ - libcrypto \ - libmedia \ - -LOCAL_MODULE:= libstagefright_mpeg2ts - -ifeq ($(TARGET_ARCH),arm) - LOCAL_CFLAGS += -Wno-psabi -endif - -include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/omx/1.0/Omx.cpp b/media/libstagefright/omx/1.0/Omx.cpp index 64b2c08185..789379a64f 100644 --- a/media/libstagefright/omx/1.0/Omx.cpp +++ b/media/libstagefright/omx/1.0/Omx.cpp @@ -90,46 +90,49 @@ Return<void> Omx::allocateNode( using ::android::IOMXNode; using ::android::IOMXObserver; - Mutex::Autolock autoLock(mLock); - if (mLiveNodes.size() == kMaxNodeInstances) { - _hidl_cb(toStatus(NO_MEMORY), nullptr); - return Void(); - } - - sp<OMXNodeInstance> instance = new OMXNodeInstance( - this, new LWOmxObserver(observer), name.c_str()); - - OMX_COMPONENTTYPE *handle; - OMX_ERRORTYPE err = mMaster->makeComponentInstance( - name.c_str(), &OMXNodeInstance::kCallbacks, - instance.get(), &handle); + sp<OMXNodeInstance> instance; + { + Mutex::Autolock autoLock(mLock); + if (mLiveNodes.size() == kMaxNodeInstances) { + _hidl_cb(toStatus(NO_MEMORY), nullptr); + return Void(); + } - if (err != OMX_ErrorNone) { - LOG(ERROR) << "Failed to allocate omx component " - "'" << name.c_str() << "' " - " err=" << asString(err) << - "(0x" << std::hex << unsigned(err) << ")"; - _hidl_cb(toStatus(StatusFromOMXError(err)), nullptr); - return Void(); - } - instance->setHandle(handle); - std::vector<AString> quirkVector; - if (mParser.getQuirks(name.c_str(), &quirkVector) == OK) { - uint32_t quirks = 0; - for (const AString quirk : quirkVector) { - if (quirk == "requires-allocate-on-input-ports") { - quirks |= kRequiresAllocateBufferOnInputPorts; - } - if (quirk == "requires-allocate-on-output-ports") { - quirks |= kRequiresAllocateBufferOnOutputPorts; + instance = new OMXNodeInstance( + this, new LWOmxObserver(observer), name.c_str()); + + OMX_COMPONENTTYPE *handle; + OMX_ERRORTYPE err = mMaster->makeComponentInstance( + name.c_str(), &OMXNodeInstance::kCallbacks, + instance.get(), &handle); + + if (err != OMX_ErrorNone) { + LOG(ERROR) << "Failed to allocate omx component " + "'" << name.c_str() << "' " + " err=" << asString(err) << + "(0x" << std::hex << unsigned(err) << ")"; + _hidl_cb(toStatus(StatusFromOMXError(err)), nullptr); + return Void(); + } + instance->setHandle(handle); + std::vector<AString> quirkVector; + if (mParser.getQuirks(name.c_str(), &quirkVector) == OK) { + uint32_t quirks = 0; + for (const AString quirk : quirkVector) { + if (quirk == "requires-allocate-on-input-ports") { + quirks |= kRequiresAllocateBufferOnInputPorts; + } + if (quirk == "requires-allocate-on-output-ports") { + quirks |= kRequiresAllocateBufferOnOutputPorts; + } } + instance->setQuirks(quirks); } - instance->setQuirks(quirks); - } - mLiveNodes.add(observer.get(), instance); + mLiveNodes.add(observer.get(), instance); + mNode2Observer.add(instance.get(), observer.get()); + } observer->linkToDeath(this, 0); - mNode2Observer.add(instance.get(), observer.get()); _hidl_cb(toStatus(OK), new TWOmxNode(instance)); return Void(); diff --git a/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp b/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp index 631f52e597..9327f03503 100644 --- a/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp +++ b/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp @@ -21,6 +21,7 @@ #include "WGraphicBufferProducer.h" #include "WProducerListener.h" #include "Conversion.h" +#include <system/window.h> namespace android { namespace hardware { diff --git a/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp b/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp index e8763065c1..d8540f8a4a 100644 --- a/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp +++ b/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp @@ -206,8 +206,10 @@ Return<Status> TWGraphicBufferSource::setStopTimeUs(int64_t stopTimeUs) { Return<void> TWGraphicBufferSource::getStopTimeOffsetUs( getStopTimeOffsetUs_cb _hidl_cb) { - // TODO: Implement this when needed. - _hidl_cb(Status::OK, 0); + status_t status; + int64_t stopTimeOffsetUs; + status = mBase->getStopTimeOffsetUs(&stopTimeOffsetUs); + _hidl_cb(toStatus(status), stopTimeOffsetUs); return Void(); } diff --git a/media/libstagefright/omx/1.0/WOmxNode.cpp b/media/libstagefright/omx/1.0/WOmxNode.cpp index d0680fbc0a..6c0abc90ee 100644 --- a/media/libstagefright/omx/1.0/WOmxNode.cpp +++ b/media/libstagefright/omx/1.0/WOmxNode.cpp @@ -50,7 +50,7 @@ status_t LWOmxNode::getParameter( status_t transStatus = toStatusT(mBase->getParameter( toRawIndexType(index), tParams, - [&fnStatus, params, size]( + [&fnStatus, params]( Status status, hidl_vec<uint8_t> const& outParams) { fnStatus = toStatusT(status); std::copy( @@ -148,7 +148,7 @@ status_t LWOmxNode::allocateSecureBuffer( status_t transStatus = toStatusT(mBase->allocateSecureBuffer( portIndex, static_cast<uint64_t>(size), - [&fnStatus, buffer, buffer_data, native_handle]( + [&fnStatus, buffer, native_handle]( Status status, uint32_t outBuffer, hidl_handle const& outNativeHandle) { diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp new file mode 100644 index 0000000000..2d921f9a13 --- /dev/null +++ b/media/libstagefright/omx/Android.bp @@ -0,0 +1,106 @@ +cc_library_shared { + name: "libstagefright_omx", + vendor_available: true, + + srcs: [ + "FrameDropper.cpp", + "GraphicBufferSource.cpp", + "BWGraphicBufferSource.cpp", + "OMX.cpp", + "OMXMaster.cpp", + "OMXNodeInstance.cpp", + "OMXUtils.cpp", + "SimpleSoftOMXComponent.cpp", + "SoftOMXComponent.cpp", + "SoftOMXPlugin.cpp", + "SoftVideoDecoderOMXComponent.cpp", + "SoftVideoEncoderOMXComponent.cpp", + "1.0/Omx.cpp", + "1.0/OmxStore.cpp", + "1.0/WGraphicBufferProducer.cpp", + "1.0/WProducerListener.cpp", + "1.0/WGraphicBufferSource.cpp", + "1.0/WOmxNode.cpp", + "1.0/WOmxObserver.cpp", + "1.0/WOmxBufferSource.cpp", + ], + + include_dirs: [ + "frameworks/av/include", // for media/vndk/xmlparser/1.0/MediaCodecsXmlParser.h + "frameworks/av/include/media/", + "frameworks/av/media/libstagefright", + "frameworks/av/media/libstagefright/include", + "frameworks/native/include", // for media/hardware/MetadataBufferType.h + "frameworks/native/include/media/hardware", + "frameworks/native/include/media/openmax", + ], + + shared_libs: [ + "libbase", + "libbinder", + "libmedia_omx", + "libutils", + "liblog", + "libui", + "libgui", + "libcutils", + "libstagefright_foundation", + "libdl", + "libhidlbase", + "libhidlmemory", + "libhidltransport", + "libnativewindow", // TODO(b/62923479): use header library + "libstagefright_xmlparser@1.0", + "android.hidl.memory@1.0", + "android.hidl.token@1.0-utils", + "android.hardware.media@1.0", + "android.hardware.media.omx@1.0", + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.bufferqueue@1.0", + ], + + export_shared_lib_headers: ["android.hidl.memory@1.0"], + + cflags: [ + "-Werror", + "-Wall", + "-Wno-unused-parameter", + "-Wno-documentation", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, +} + +cc_library_static { + name: "libstagefright_omx_utils", + srcs: ["OMXUtils.cpp"], + include_dirs: [ + "frameworks/av/media/libstagefright", + "frameworks/native/include/media/hardware", + "frameworks/native/include/media/openmax", + ], + shared_libs: ["libmedia"], + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, +} + +//############################################################################### + +subdirs = ["tests"] diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk deleted file mode 100644 index 29e2ccc83b..0000000000 --- a/media/libstagefright/omx/Android.mk +++ /dev/null @@ -1,69 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - FrameDropper.cpp \ - GraphicBufferSource.cpp \ - BWGraphicBufferSource.cpp \ - OMX.cpp \ - OMXMaster.cpp \ - OMXNodeInstance.cpp \ - OMXUtils.cpp \ - SimpleSoftOMXComponent.cpp \ - SoftOMXComponent.cpp \ - SoftOMXPlugin.cpp \ - SoftVideoDecoderOMXComponent.cpp \ - SoftVideoEncoderOMXComponent.cpp \ - 1.0/Omx.cpp \ - 1.0/OmxStore.cpp \ - 1.0/WGraphicBufferProducer.cpp \ - 1.0/WProducerListener.cpp \ - 1.0/WGraphicBufferSource.cpp \ - 1.0/WOmxNode.cpp \ - 1.0/WOmxObserver.cpp \ - 1.0/WOmxBufferSource.cpp \ - -LOCAL_C_INCLUDES += \ - $(TOP)/frameworks/av/media/libstagefright \ - $(TOP)/frameworks/native/include/media/hardware \ - $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/system/libhidl/base/include \ - -LOCAL_SHARED_LIBRARIES := \ - libbase \ - libbinder \ - libmedia \ - libutils \ - liblog \ - libui \ - libgui \ - libcutils \ - libstagefright_foundation \ - libdl \ - libhidlbase \ - libhidlmemory \ - libstagefright_xmlparser@1.0 \ - android.hidl.base@1.0 \ - android.hidl.memory@1.0 \ - android.hardware.media@1.0 \ - android.hardware.media.omx@1.0 \ - android.hardware.graphics.common@1.0 \ - android.hardware.graphics.bufferqueue@1.0 \ - -LOCAL_EXPORT_C_INCLUDES := \ - $(TOP)/frameworks/av/include - -LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \ - android.hidl.memory@1.0 - -LOCAL_MODULE:= libstagefright_omx -LOCAL_CFLAGS += -Werror -Wall -Wno-unused-parameter -Wno-documentation -LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -include $(BUILD_SHARED_LIBRARY) - -################################################################################ - -include $(call all-makefiles-under,$(LOCAL_PATH)/hal) -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media/libstagefright/omx/BWGraphicBufferSource.cpp b/media/libstagefright/omx/BWGraphicBufferSource.cpp index f2a454f578..79f6d93b3d 100644 --- a/media/libstagefright/omx/BWGraphicBufferSource.cpp +++ b/media/libstagefright/omx/BWGraphicBufferSource.cpp @@ -21,7 +21,7 @@ #include <OMX_IndexExt.h> #include <media/OMXBuffer.h> -#include <IOMX.h> +#include <media/IOMX.h> #include "OMXUtils.h" #include "BWGraphicBufferSource.h" @@ -160,6 +160,11 @@ BWGraphicBufferSource::BWGraphicBufferSource( return Status::fromStatusT(mBase->setStopTimeUs(stopTimeUs)); } +::android::binder::Status BWGraphicBufferSource::getStopTimeOffsetUs( + int64_t *stopTimeOffsetUs) { + return Status::fromStatusT(mBase->getStopTimeOffsetUs(stopTimeOffsetUs)); +} + ::android::binder::Status BWGraphicBufferSource::setColorAspects( int32_t aspects) { return Status::fromStatusT(mBase->setColorAspects(aspects)); diff --git a/media/libstagefright/omx/BWGraphicBufferSource.h b/media/libstagefright/omx/BWGraphicBufferSource.h index 43763c2485..0f78eb605d 100644 --- a/media/libstagefright/omx/BWGraphicBufferSource.h +++ b/media/libstagefright/omx/BWGraphicBufferSource.h @@ -21,7 +21,7 @@ #include <binder/Status.h> #include <android/BnGraphicBufferSource.h> #include <android/BnOMXBufferSource.h> -#include <IOMX.h> +#include <media/IOMX.h> #include "GraphicBufferSource.h" #include "IOmxNodeWrapper.h" @@ -53,6 +53,7 @@ struct BWGraphicBufferSource : public BnGraphicBufferSource { double fps, double captureFps) override; Status setStartTimeUs(int64_t startTimeUs) override; Status setStopTimeUs(int64_t stopTimeUs) override; + Status getStopTimeOffsetUs(int64_t* stopTimeOffsetUs) override; Status setColorAspects(int32_t aspects) override; Status setTimeOffsetUs(int64_t timeOffsetsUs) override; Status signalEndOfInputStream() override; diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index 47d80bb756..ef4d745371 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -35,7 +35,7 @@ #include "omx/OMXUtils.h" #include <OMX_Component.h> #include <OMX_IndexExt.h> -#include "OMXBuffer.h" +#include "media/OMXBuffer.h" #include <inttypes.h> #include "FrameDropper.h" @@ -264,6 +264,7 @@ GraphicBufferSource::GraphicBufferSource() : mLastDataspace(HAL_DATASPACE_UNKNOWN), mExecuting(false), mSuspended(false), + mLastFrameTimestampUs(-1), mStopTimeUs(-1), mLastActionTimeUs(-1ll), mSkipFramesBeforeNs(-1ll), @@ -649,6 +650,7 @@ bool GraphicBufferSource::fillCodecBuffer_l() { } ALOGV("buffer submitted [slot=%d, useCount=%ld] acquired=%d", item.mBuffer->getSlot(), item.mBuffer.use_count(), mNumOutstandingAcquires); + mLastFrameTimestampUs = itemTimeUs; } return true; @@ -1220,10 +1222,21 @@ status_t GraphicBufferSource::setStopTimeUs(int64_t stopTimeUs) { return OK; } +status_t GraphicBufferSource::getStopTimeOffsetUs(int64_t *stopTimeOffsetUs) { + ALOGV("getStopTimeOffsetUs"); + Mutex::Autolock autoLock(mMutex); + if (mStopTimeUs == -1) { + ALOGW("Fail to return stopTimeOffsetUs as stop time is not set"); + return INVALID_OPERATION; + } + *stopTimeOffsetUs = + mLastFrameTimestampUs == -1 ? 0 : mStopTimeUs - mLastFrameTimestampUs; + return OK; +} + status_t GraphicBufferSource::setTimeLapseConfig(double fps, double captureFps) { ALOGV("setTimeLapseConfig: fps=%lg, captureFps=%lg", fps, captureFps); - Mutex::Autolock autoLock(mMutex); if (mExecuting || !(fps > 0) || !(captureFps > 0)) { diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h index 3df1aa1906..29b51a8c05 100644 --- a/media/libstagefright/omx/GraphicBufferSource.h +++ b/media/libstagefright/omx/GraphicBufferSource.h @@ -172,6 +172,13 @@ public: // and not submitted to encoder. timeUs uses SYSTEM_TIME_MONOTONIC time base. status_t setStopTimeUs(int64_t stopTimeUs); + // Gets the stop time offset in us. This is the time offset between latest buffer + // time and the stopTimeUs. If stop time is not set, INVALID_OPERATION will be returned. + // If return is OK, *stopTimeOffsetUs will contain the valid offset. Otherwise, + // *stopTimeOffsetUs will not be modified. Positive stopTimeOffsetUs means buffer time + // larger than stopTimeUs. + status_t getStopTimeOffsetUs(int64_t *stopTimeOffsetUs); + // Sets the desired color aspects, e.g. to be used when producer does not specify a dataspace. status_t setColorAspects(int32_t aspectsPacked); @@ -340,6 +347,8 @@ private: // regardless of the metadata of those buffers bool areWeDiscardingAvailableBuffers_l(); + int64_t mLastFrameTimestampUs; + // Our BufferQueue interfaces. mProducer is passed to the producer through // getIGraphicBufferProducer, and mConsumer is used internally to retrieve // the buffers queued by the producer. diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index 35fb31291a..035947ea8b 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -1085,6 +1085,10 @@ status_t OMXNodeInstance::useBuffer( break; } sp<IHidlMemory> hidlMemory = mapMemory(omxBuffer.mHidlMemory); + if (hidlMemory == nullptr) { + ALOGE("OMXNodeInstance useBuffer() failed to map memory"); + return NO_MEMORY; + } return useBuffer_l(portIndex, NULL, hidlMemory, buffer); } default: diff --git a/media/libstagefright/omx/OMXUtils.cpp b/media/libstagefright/omx/OMXUtils.cpp index ee6d1d586b..a66d565c93 100644 --- a/media/libstagefright/omx/OMXUtils.cpp +++ b/media/libstagefright/omx/OMXUtils.cpp @@ -24,6 +24,7 @@ #include <media/stagefright/foundation/AUtils.h> #include <media/stagefright/MediaErrors.h> #include <media/MediaDefs.h> +#include <system/graphics-base.h> #include "OMXUtils.h" namespace android { diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp index a773ca2b8a..fccb12ba7e 100644 --- a/media/libstagefright/omx/SoftOMXPlugin.cpp +++ b/media/libstagefright/omx/SoftOMXPlugin.cpp @@ -58,6 +58,7 @@ static const struct { { "OMX.google.vp8.encoder", "vpxenc", "video_encoder.vp8" }, { "OMX.google.vp9.encoder", "vpxenc", "video_encoder.vp9" }, { "OMX.google.raw.decoder", "rawdec", "audio_decoder.raw" }, + { "OMX.google.flac.decoder", "flacdec", "audio_decoder.flac" }, { "OMX.google.flac.encoder", "flacenc", "audio_encoder.flac" }, { "OMX.google.gsm.decoder", "gsmdec", "audio_decoder.gsm" }, }; diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp index 361cfb453d..41d634a72b 100644 --- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp +++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp @@ -36,6 +36,8 @@ #include <hardware/gralloc.h> +#include <nativebase/nativebase.h> + #include <OMX_IndexExt.h> namespace android { diff --git a/media/libstagefright/omx/tests/Android.bp b/media/libstagefright/omx/tests/Android.bp new file mode 100644 index 0000000000..8bcb99e20b --- /dev/null +++ b/media/libstagefright/omx/tests/Android.bp @@ -0,0 +1,52 @@ +cc_test { + name: "omx_tests", + gtest: false, + + srcs: ["OMXHarness.cpp"], + + shared_libs: [ + "libstagefright", + "libbinder", + "libmedia", + "libutils", + "liblog", + "libstagefright_foundation", + "libcutils", + "libhidlbase", + "libhidlmemory", + "libnativewindow", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "android.hardware.media.omx@1.0", + ], + + include_dirs: [ + "frameworks/av/media/libstagefright", + "frameworks/native/include/media/openmax", + ], + + cflags: [ + "-Werror", + "-Wall", + ], + + compile_multilib: "32", +} + +cc_test { + name: "FrameDropper_test", + + srcs: ["FrameDropper_test.cpp"], + + shared_libs: [ + "libstagefright_omx", + "libutils", + ], + + include_dirs: ["frameworks/av/media/libstagefright/omx"], + + cflags: [ + "-Werror", + "-Wall", + ], +} diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk deleted file mode 100644 index 5941b94ec8..0000000000 --- a/media/libstagefright/omx/tests/Android.mk +++ /dev/null @@ -1,54 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES = \ - OMXHarness.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - libstagefright \ - libbinder \ - libmedia \ - libutils \ - liblog \ - libstagefright_foundation \ - libcutils \ - libhidlbase \ - libhidlmemory \ - android.hidl.allocator@1.0 \ - android.hidl.memory@1.0 \ - android.hardware.media.omx@1.0 \ - -LOCAL_C_INCLUDES := \ - $(TOP)/frameworks/av/media/libstagefright \ - $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/system/libhidl/base/include \ - -LOCAL_CFLAGS += -Werror -Wall - -LOCAL_MODULE := omx_tests - -LOCAL_MODULE_TAGS := tests - -LOCAL_32_BIT_ONLY := true - -include $(BUILD_EXECUTABLE) - -include $(CLEAR_VARS) - -LOCAL_MODULE := FrameDropper_test - -LOCAL_MODULE_TAGS := tests - -LOCAL_SRC_FILES := \ - FrameDropper_test.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - libstagefright_omx \ - libutils \ - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright/omx \ - -LOCAL_CFLAGS += -Werror -Wall - -include $(BUILD_NATIVE_TEST) diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp index fcc44d804a..326643907a 100644 --- a/media/libstagefright/omx/tests/OMXHarness.cpp +++ b/media/libstagefright/omx/tests/OMXHarness.cpp @@ -41,6 +41,7 @@ #include <media/OMXBuffer.h> #include <android/hardware/media/omx/1.0/IOmx.h> #include <media/omx/1.0/WOmx.h> +#include <system/window.h> #define DEFAULT_TIMEOUT 500000 diff --git a/media/libstagefright/rtsp/Android.bp b/media/libstagefright/rtsp/Android.bp new file mode 100644 index 0000000000..debd07e2a3 --- /dev/null +++ b/media/libstagefright/rtsp/Android.bp @@ -0,0 +1,96 @@ +cc_library_static { + name: "libstagefright_rtsp", + + srcs: [ + "AAMRAssembler.cpp", + "AAVCAssembler.cpp", + "AH263Assembler.cpp", + "AMPEG2TSAssembler.cpp", + "AMPEG4AudioAssembler.cpp", + "AMPEG4ElementaryAssembler.cpp", + "APacketSource.cpp", + "ARawAudioAssembler.cpp", + "ARTPAssembler.cpp", + "ARTPConnection.cpp", + "ARTPSource.cpp", + "ARTPWriter.cpp", + "ARTSPConnection.cpp", + "ASessionDescription.cpp", + "SDPLoader.cpp", + ], + + shared_libs: [ + "libcrypto", + "libmedia", + ], + + include_dirs: [ + "frameworks/av/media/libstagefright", + "frameworks/native/include/media/openmax", + ], + + arch: { + arm: { + cflags: ["-Wno-psabi"], + }, + }, + + cflags: [ + "-Werror", + "-Wall", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, +} + +//############################################################################### + +cc_test { + name: "rtp_test", + gtest: false, + enabled: false, + + srcs: ["rtp_test.cpp"], + + shared_libs: [ + "libstagefright", + "liblog", + "libutils", + "libbinder", + "libstagefright_foundation", + "libmedia", + ], + + static_libs: ["libstagefright_rtsp"], + + include_dirs: [ + "frameworks/av/media/libstagefright", + "frameworks/av/cmds/stagefright", + "frameworks/native/include/media/openmax", + ], + + cflags: [ + "-Wno-multichar", + "-Werror", + "-Wall", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, +} diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk deleted file mode 100644 index 3472e49ced..0000000000 --- a/media/libstagefright/rtsp/Android.mk +++ /dev/null @@ -1,68 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - AAMRAssembler.cpp \ - AAVCAssembler.cpp \ - AH263Assembler.cpp \ - AMPEG2TSAssembler.cpp \ - AMPEG4AudioAssembler.cpp \ - AMPEG4ElementaryAssembler.cpp \ - APacketSource.cpp \ - ARawAudioAssembler.cpp \ - ARTPAssembler.cpp \ - ARTPConnection.cpp \ - ARTPSource.cpp \ - ARTPWriter.cpp \ - ARTSPConnection.cpp \ - ASessionDescription.cpp \ - SDPLoader.cpp \ - -LOCAL_SHARED_LIBRARIES += libcrypto libmedia - -LOCAL_C_INCLUDES:= \ - $(TOP)/frameworks/av/media/libstagefright \ - $(TOP)/frameworks/native/include/media/openmax - -LOCAL_MODULE:= libstagefright_rtsp - -ifeq ($(TARGET_ARCH),arm) - LOCAL_CFLAGS += -Wno-psabi -endif - -LOCAL_CFLAGS += -Werror -Wall -LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow - -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -include $(BUILD_STATIC_LIBRARY) - -################################################################################ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - rtp_test.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - libstagefright liblog libutils libbinder libstagefright_foundation libmedia - -LOCAL_STATIC_LIBRARIES := \ - libstagefright_rtsp - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright \ - frameworks/av/cmds/stagefright \ - $(TOP)/frameworks/native/include/media/openmax - -LOCAL_CFLAGS += -Wno-multichar -Werror -Wall -LOCAL_SANITIZE := signed-integer-overflow - -LOCAL_MODULE_TAGS := optional - -LOCAL_MODULE:= rtp_test - -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -# include $(BUILD_EXECUTABLE) diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h index 5505aa4344..c6c0245a46 100644 --- a/media/libstagefright/rtsp/MyHandler.h +++ b/media/libstagefright/rtsp/MyHandler.h @@ -33,6 +33,7 @@ #include "ASessionDescription.h" #include <ctype.h> +#include <cutils/properties.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> @@ -135,7 +136,7 @@ struct MyHandler : public AHandler { mCheckPending(false), mCheckGeneration(0), mCheckTimeoutGeneration(0), - mTryTCPInterleaving(false), + mTryTCPInterleaving(property_get_bool("rtp.transport.TCP", false)), mTryFakeRTCP(false), mReceivedFirstRTCPPacket(false), mReceivedFirstRTPPacket(false), diff --git a/media/libstagefright/tests/Android.bp b/media/libstagefright/tests/Android.bp new file mode 100644 index 0000000000..35119c2b2f --- /dev/null +++ b/media/libstagefright/tests/Android.bp @@ -0,0 +1,68 @@ +// Build the unit tests. + +cc_test { + name: "SurfaceMediaSource_test", + + srcs: [ + "SurfaceMediaSource_test.cpp", + "DummyRecorder.cpp", + ], + + shared_libs: [ + "libEGL", + "libGLESv2", + "libbinder", + "libcutils", + "libgui", + "libmedia", + "libstagefright", + "libstagefright_foundation", + "libstagefright_omx", + "libsync", + "libui", + "libutils", + "liblog", + ], + + include_dirs: [ + "frameworks/av/media/libstagefright", + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + "frameworks/native/include/media/hardware", + ], + + cflags: [ + "-Werror", + "-Wall", + ], + + compile_multilib: "32", +} + +cc_test { + name: "MediaCodecListOverrides_test", + + srcs: ["MediaCodecListOverrides_test.cpp"], + + shared_libs: [ + "libmedia", + "libstagefright", + "libstagefright_foundation", + "libstagefright_omx", + "libutils", + "liblog", + ], + + include_dirs: [ + "frameworks/av/media/libstagefright", + "frameworks/av/media/libstagefright/include", + "frameworks/native/include/media/openmax", + ], + + compile_multilib: "32", + + cflags: [ + "-Werror", + "-Wall", + ], +} diff --git a/media/libstagefright/tests/Android.mk b/media/libstagefright/tests/Android.mk deleted file mode 100644 index c6963b13bc..0000000000 --- a/media/libstagefright/tests/Android.mk +++ /dev/null @@ -1,77 +0,0 @@ -# Build the unit tests. -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -LOCAL_MODULE := SurfaceMediaSource_test - -LOCAL_MODULE_TAGS := tests - -LOCAL_SRC_FILES := \ - SurfaceMediaSource_test.cpp \ - DummyRecorder.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - libEGL \ - libGLESv2 \ - libbinder \ - libcutils \ - libgui \ - libmedia \ - libstagefright \ - libstagefright_foundation \ - libstagefright_omx \ - libsync \ - libui \ - libutils \ - liblog - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright \ - frameworks/av/media/libstagefright/include \ - $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/frameworks/native/include/media/hardware \ - -LOCAL_CFLAGS += -Werror -Wall - -LOCAL_32_BIT_ONLY := true - -include $(BUILD_NATIVE_TEST) - -include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -LOCAL_MODULE := MediaCodecListOverrides_test - -LOCAL_MODULE_TAGS := tests - -LOCAL_SRC_FILES := \ - MediaCodecListOverrides_test.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - libmedia \ - libstagefright \ - libstagefright_foundation \ - libstagefright_omx \ - libutils \ - liblog - -LOCAL_C_INCLUDES := \ - frameworks/av/media/libstagefright \ - frameworks/av/media/libstagefright/include \ - frameworks/native/include/media/openmax \ - -LOCAL_32_BIT_ONLY := true - -LOCAL_CFLAGS += -Werror -Wall - -include $(BUILD_NATIVE_TEST) - -# Include subdirectory makefiles -# ============================================================ - -# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework -# team really wants is to build the stuff defined by this makefile. -ifeq (,$(ONE_SHOT_MAKEFILE)) -include $(call first-makefiles-under,$(LOCAL_PATH)) -endif diff --git a/media/libstagefright/timedtext/Android.bp b/media/libstagefright/timedtext/Android.bp new file mode 100644 index 0000000000..a5ad6c60b9 --- /dev/null +++ b/media/libstagefright/timedtext/Android.bp @@ -0,0 +1,27 @@ +cc_library_static { + name: "libstagefright_timedtext", + + srcs: ["TextDescriptions.cpp"], + + cflags: [ + "-Wno-multichar", + "-Werror", + "-Wall", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + include_dirs: [ + "frameworks/av/media/libstagefright", + ], + + shared_libs: ["libmedia"], +} diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk deleted file mode 100644 index 70ae46b042..0000000000 --- a/media/libstagefright/timedtext/Android.mk +++ /dev/null @@ -1,19 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - TextDescriptions.cpp \ - -LOCAL_CFLAGS += -Wno-multichar -Werror -Wall -LOCAL_SANITIZE := signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_C_INCLUDES:= \ - $(TOP)/frameworks/av/include/media/stagefright/timedtext \ - $(TOP)/frameworks/av/media/libstagefright - -LOCAL_SHARED_LIBRARIES := libmedia - -LOCAL_MODULE:= libstagefright_timedtext - -include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/webm/Android.bp b/media/libstagefright/webm/Android.bp new file mode 100644 index 0000000000..f96878895e --- /dev/null +++ b/media/libstagefright/webm/Android.bp @@ -0,0 +1,37 @@ +cc_library_static { + name: "libstagefright_webm", + + cppflags: ["-D__STDINT_LIMITS"], + + cflags: [ + "-Werror", + "-Wall", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, + + srcs: [ + "EbmlUtil.cpp", + "WebmElement.cpp", + "WebmFrame.cpp", + "WebmFrameThread.cpp", + "WebmWriter.cpp", + ], + + include_dirs: ["frameworks/av/include"], + + shared_libs: [ + "libstagefright_foundation", + "libutils", + "liblog", + ], +} diff --git a/media/libstagefright/webm/Android.mk b/media/libstagefright/webm/Android.mk deleted file mode 100644 index 0d55de96b1..0000000000 --- a/media/libstagefright/webm/Android.mk +++ /dev/null @@ -1,26 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_CPPFLAGS += -D__STDINT_LIMITS - -LOCAL_CFLAGS += -Werror -Wall -LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_SRC_FILES:= EbmlUtil.cpp \ - WebmElement.cpp \ - WebmFrame.cpp \ - WebmFrameThread.cpp \ - WebmWriter.cpp - - -LOCAL_C_INCLUDES += $(TOP)/frameworks/av/include - -LOCAL_SHARED_LIBRARIES += libstagefright_foundation \ - libstagefright \ - libutils \ - liblog - -LOCAL_MODULE:= libstagefright_webm - -include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp index 77de3c8e96..71bfbc90c8 100644 --- a/media/libstagefright/webm/WebmFrameThread.cpp +++ b/media/libstagefright/webm/WebmFrameThread.cpp @@ -124,7 +124,7 @@ void WebmFrameSinkThread::initCluster( void WebmFrameSinkThread::writeCluster(List<sp<WebmElement> >& children) { // children must contain at least one simpleblock and its timecode - CHECK_GE(children.size(), 2); + CHECK_GE(children.size(), 2u); uint64_t size; sp<WebmElement> cluster = new WebmMaster(kMkvCluster, children); @@ -155,7 +155,7 @@ void WebmFrameSinkThread::flushFrames(List<const sp<WebmFrame> >& frames, bool l // flushing the second to last frame before we check its type. A audio frame // should precede the aforementioned video key frame in the next sequence, a video // frame should be the last frame in the current (to-be-flushed) sequence. - CHECK_GE(n, 2); + CHECK_GE(n, 2u); n -= 2; } diff --git a/media/libstagefright/webm/WebmWriter.cpp b/media/libstagefright/webm/WebmWriter.cpp index 25d6821400..d6c6930cae 100644 --- a/media/libstagefright/webm/WebmWriter.cpp +++ b/media/libstagefright/webm/WebmWriter.cpp @@ -488,7 +488,7 @@ status_t WebmWriter::start(MetaData *params) { params->findInt32(kKeyBitRate, &bitRate); } mEstimatedCuesSize = estimateCuesSize(bitRate); - CHECK_GE(mEstimatedCuesSize, 8); + CHECK_GE(mEstimatedCuesSize, 8u); cues = new EbmlVoid(mEstimatedCuesSize); } diff --git a/media/libstagefright/wifi-display/Android.bp b/media/libstagefright/wifi-display/Android.bp new file mode 100644 index 0000000000..fb08c5b072 --- /dev/null +++ b/media/libstagefright/wifi-display/Android.bp @@ -0,0 +1,51 @@ +cc_library_shared { + name: "libstagefright_wfd", + + srcs: [ + "MediaSender.cpp", + "Parameters.cpp", + "rtp/RTPSender.cpp", + "source/Converter.cpp", + "source/MediaPuller.cpp", + "source/PlaybackSession.cpp", + "source/RepeaterSource.cpp", + "source/TSPacketizer.cpp", + "source/WifiDisplaySource.cpp", + "VideoFormats.cpp", + ], + + include_dirs: [ + "frameworks/av/media/libstagefright", + "frameworks/native/include/media/openmax", + "frameworks/native/include/media/hardware", + "frameworks/av/media/libstagefright/mpeg2ts", + ], + + shared_libs: [ + "libbinder", + "libcutils", + "liblog", + "libmedia", + "libstagefright", + "libstagefright_foundation", + "libui", + "libgui", + "libutils", + ], + + cflags: [ + "-Wno-multichar", + "-Werror", + "-Wall", + ], + + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + ], + cfi: true, + diag: { + cfi: true, + }, + }, +} diff --git a/media/libstagefright/wifi-display/Android.mk b/media/libstagefright/wifi-display/Android.mk deleted file mode 100644 index a1b4aec130..0000000000 --- a/media/libstagefright/wifi-display/Android.mk +++ /dev/null @@ -1,41 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - MediaSender.cpp \ - Parameters.cpp \ - rtp/RTPSender.cpp \ - source/Converter.cpp \ - source/MediaPuller.cpp \ - source/PlaybackSession.cpp \ - source/RepeaterSource.cpp \ - source/TSPacketizer.cpp \ - source/WifiDisplaySource.cpp \ - VideoFormats.cpp \ - -LOCAL_C_INCLUDES:= \ - $(TOP)/frameworks/av/media/libstagefright \ - $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/frameworks/native/include/media/hardware \ - $(TOP)/frameworks/av/media/libstagefright/mpeg2ts \ - -LOCAL_SHARED_LIBRARIES:= \ - libbinder \ - libcutils \ - liblog \ - libmedia \ - libstagefright \ - libstagefright_foundation \ - libui \ - libutils \ - -LOCAL_CFLAGS += -Wno-multichar -Werror -Wall -LOCAL_SANITIZE := signed-integer-overflow cfi -LOCAL_SANITIZE_DIAG := cfi - -LOCAL_MODULE:= libstagefright_wfd - -LOCAL_MODULE_TAGS:= optional - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/wifi-display/MediaSender.cpp b/media/libstagefright/wifi-display/MediaSender.cpp index ae507fc5a7..cc412f5f46 100644 --- a/media/libstagefright/wifi-display/MediaSender.cpp +++ b/media/libstagefright/wifi-display/MediaSender.cpp @@ -420,7 +420,7 @@ status_t MediaSender::packetizeAccessUnit( CHECK(accessUnit->meta()->findInt32("rangeLength", &rangeLength)); CHECK(accessUnit->meta()->findMessage("notify", ¬ify) && notify != NULL); - CHECK_GE(accessUnit->size(), rangeLength); + CHECK_GE((int32_t)accessUnit->size(), rangeLength); sp<GraphicBuffer> grbuf(new GraphicBuffer( rangeOffset + rangeLength /* width */, 1 /* height */, diff --git a/media/libstagefright/wifi-display/rtp/RTPBase.h b/media/libstagefright/wifi-display/rtp/RTPBase.h index 6178f00d93..194f1ee13b 100644 --- a/media/libstagefright/wifi-display/rtp/RTPBase.h +++ b/media/libstagefright/wifi-display/rtp/RTPBase.h @@ -36,10 +36,8 @@ struct RTPBase { TRANSPORT_TCP_INTERLEAVED, }; - enum { - // Really UDP _payload_ size - kMaxUDPPacketSize = 1472, // 1472 good, 1473 bad on Android@Home - }; + // Really UDP _payload_ size + const unsigned int kMaxUDPPacketSize = 1472; // 1472 good, 1473 bad on Android@Home static int32_t PickRandomRTPPort(); }; diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.cpp b/media/libstagefright/wifi-display/rtp/RTPSender.cpp index 83af3930cf..ca9fdd2bd7 100644 --- a/media/libstagefright/wifi-display/rtp/RTPSender.cpp +++ b/media/libstagefright/wifi-display/rtp/RTPSender.cpp @@ -247,7 +247,7 @@ status_t RTPSender::queueRawPacket( status_t RTPSender::queueTSPackets( const sp<ABuffer> &tsPackets, uint8_t packetType) { - CHECK_EQ(0, tsPackets->size() % 188); + CHECK_EQ(0u, tsPackets->size() % 188); int64_t timeUs; CHECK(tsPackets->meta()->findInt64("timeUs", &timeUs)); diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.h b/media/libstagefright/wifi-display/rtp/RTPSender.h index fefcab766f..bedfd01a8a 100644 --- a/media/libstagefright/wifi-display/rtp/RTPSender.h +++ b/media/libstagefright/wifi-display/rtp/RTPSender.h @@ -66,11 +66,9 @@ private: kWhatRTCPNotify, }; - enum { - kMaxNumTSPacketsPerRTPPacket = (kMaxUDPPacketSize - 12) / 188, - kMaxHistorySize = 1024, - kSourceID = 0xdeadbeef, - }; + const unsigned int kMaxNumTSPacketsPerRTPPacket = (kMaxUDPPacketSize - 12) / 188; + const unsigned int kMaxHistorySize = 1024; + const unsigned int kSourceID = 0xdeadbeef; sp<ANetworkSession> mNetSession; sp<AMessage> mNotify; diff --git a/media/libstagefright/wifi-display/source/TSPacketizer.cpp b/media/libstagefright/wifi-display/source/TSPacketizer.cpp index 4c5ad17215..865ba94e14 100644 --- a/media/libstagefright/wifi-display/source/TSPacketizer.cpp +++ b/media/libstagefright/wifi-display/source/TSPacketizer.cpp @@ -273,8 +273,8 @@ void TSPacketizer::Track::finalize() { CHECK(mFormat->findInt32("profile-idc", &profileIdc)); CHECK(mFormat->findInt32("level-idc", &levelIdc)); CHECK(mFormat->findInt32("constraint-set", &constraintSet)); - CHECK_GE(profileIdc, 0u); - CHECK_GE(levelIdc, 0u); + CHECK_GE(profileIdc, 0); + CHECK_GE(levelIdc, 0); data[2] = profileIdc; // profile_idc data[3] = constraintSet; // constraint_set* data[4] = levelIdc; // level_idc @@ -771,7 +771,7 @@ status_t TSPacketizer::packetize( program_info_length += mProgramInfoDescriptors.itemAt(i)->size(); } - CHECK_LT(program_info_length, 0x400); + CHECK_LT(program_info_length, 0x400u); *ptr++ = 0xf0 | (program_info_length >> 8); *ptr++ = (program_info_length & 0xff); @@ -795,7 +795,7 @@ status_t TSPacketizer::packetize( for (size_t i = 0; i < track->countDescriptors(); ++i) { ES_info_length += track->descriptorAt(i)->size(); } - CHECK_LE(ES_info_length, 0xfff); + CHECK_LE(ES_info_length, 0xfffu); *ptr++ = 0xf0 | (ES_info_length >> 8); *ptr++ = (ES_info_length & 0xff); diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp index 9cda8dcd36..4695e5d289 100644 --- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp +++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp @@ -454,7 +454,7 @@ void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) { sp<ABuffer> data; CHECK(msg->findBuffer("data", &data)); - CHECK_LE(channel, 0xffu); + CHECK_LE(channel, 0xff); CHECK_LE(data->size(), 0xffffu); int32_t sessionID; diff --git a/media/mtp/Android.bp b/media/mtp/Android.bp new file mode 100644 index 0000000000..5d5ae496ea --- /dev/null +++ b/media/mtp/Android.bp @@ -0,0 +1,57 @@ +// +// Copyright (C) 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_library_shared { + name: "libmtp", + srcs: [ + "AsyncIO.cpp", + "MtpDataPacket.cpp", + "MtpDebug.cpp", + "MtpDevHandle.cpp", + "MtpDevice.cpp", + "MtpDeviceInfo.cpp", + "MtpEventPacket.cpp", + "MtpFfsHandle.cpp", + "MtpObjectInfo.cpp", + "MtpPacket.cpp", + "MtpProperty.cpp", + "MtpRequestPacket.cpp", + "MtpResponsePacket.cpp", + "MtpServer.cpp", + "MtpStorage.cpp", + "MtpStorageInfo.cpp", + "MtpStringBuffer.cpp", + "MtpUtils.cpp", + ], + export_include_dirs: ["."], + cflags: [ + "-DMTP_DEVICE", + "-DMTP_HOST", + "-Wall", + "-Wextra", + "-Werror", + ], + shared_libs: [ + "libbase", + "libutils", + "liblog", + "libusbhost", + ], +} + +subdirs = [ + "tests", +] diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk deleted file mode 100644 index 58753ffb7a..0000000000 --- a/media/mtp/Android.mk +++ /dev/null @@ -1,49 +0,0 @@ -# -# Copyright (C) 2010 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. -# - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - AsyncIO.cpp \ - MtpDataPacket.cpp \ - MtpDebug.cpp \ - MtpDevHandle.cpp \ - MtpDevice.cpp \ - MtpDeviceInfo.cpp \ - MtpEventPacket.cpp \ - MtpFfsHandle.cpp \ - MtpObjectInfo.cpp \ - MtpPacket.cpp \ - MtpProperty.cpp \ - MtpRequestPacket.cpp \ - MtpResponsePacket.cpp \ - MtpServer.cpp \ - MtpStorage.cpp \ - MtpStorageInfo.cpp \ - MtpStringBuffer.cpp \ - MtpUtils.cpp \ - -LOCAL_MODULE:= libmtp - -LOCAL_CFLAGS := -DMTP_DEVICE -DMTP_HOST -Wall -Wextra -Werror - -LOCAL_SHARED_LIBRARIES := libbase libutils libcutils liblog libusbhost libbinder - -include $(BUILD_SHARED_LIBRARY) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp index 5c33265666..2180462e87 100644 --- a/media/mtp/MtpServer.cpp +++ b/media/mtp/MtpServer.cpp @@ -25,6 +25,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <sys/stat.h> +#include <sys/time.h> #define LOG_TAG "MtpServer" @@ -113,7 +114,8 @@ MtpServer::MtpServer(MtpDatabase* database, bool ptp, mSessionOpen(false), mSendObjectHandle(kInvalidObjectHandle), mSendObjectFormat(0), - mSendObjectFileSize(0) + mSendObjectFileSize(0), + mSendObjectModifiedTime(0) { } @@ -999,6 +1001,7 @@ MtpResponseCode MtpServer::doSendObjectInfo() { // save the handle for the SendObject call, which should follow mSendObjectHandle = handle; mSendObjectFormat = format; + mSendObjectModifiedTime = modifiedTime; } mResponse.setParameter(1, storageID); @@ -1015,6 +1018,7 @@ MtpResponseCode MtpServer::doSendObject() { mode_t mask; int ret, initialData; bool isCanceled = false; + struct stat sstat = {}; auto start = std::chrono::steady_clock::now(); @@ -1070,7 +1074,17 @@ MtpResponseCode MtpServer::doSendObject() { isCanceled = true; } } - struct stat sstat; + + if (mSendObjectModifiedTime) { + struct timespec newTime[2]; + newTime[0].tv_nsec = UTIME_NOW; + newTime[1].tv_sec = mSendObjectModifiedTime; + newTime[1].tv_nsec = 0; + if (futimens(mfr.fd, newTime) < 0) { + ALOGW("changing modified time failed, %s", strerror(errno)); + } + } + fstat(mfr.fd, &sstat); close(mfr.fd); @@ -1091,6 +1105,7 @@ done: result == MTP_RESPONSE_OK); mSendObjectHandle = kInvalidObjectHandle; mSendObjectFormat = 0; + mSendObjectModifiedTime = 0; auto end = std::chrono::steady_clock::now(); std::chrono::duration<double> diff = end - start; diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h index 64d1b72df2..08a9e4a4b4 100644 --- a/media/mtp/MtpServer.h +++ b/media/mtp/MtpServer.h @@ -78,6 +78,7 @@ private: MtpObjectFormat mSendObjectFormat; MtpString mSendObjectFilePath; size_t mSendObjectFileSize; + time_t mSendObjectModifiedTime; Mutex mMutex; diff --git a/media/mtp/tests/Android.bp b/media/mtp/tests/Android.bp new file mode 100644 index 0000000000..fe7018b511 --- /dev/null +++ b/media/mtp/tests/Android.bp @@ -0,0 +1,46 @@ +// +// Copyright (C) 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_test { + name: "mtp_ffs_handle_test", + test_suites: ["device-tests"], + srcs: ["MtpFfsHandle_test.cpp"], + shared_libs: [ + "libbase", + "libmtp", + "liblog", + ], + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], +} + +cc_test { + name: "async_io_test", + srcs: ["AsyncIO_test.cpp"], + shared_libs: [ + "libbase", + "libmtp", + "liblog", + ], + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], +} diff --git a/media/mtp/tests/Android.mk b/media/mtp/tests/Android.mk deleted file mode 100644 index ace0d4050b..0000000000 --- a/media/mtp/tests/Android.mk +++ /dev/null @@ -1,51 +0,0 @@ -# Build the unit tests. -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -LOCAL_MODULE := mtp_ffs_handle_test - -LOCAL_MODULE_TAGS := tests - -LOCAL_SRC_FILES := \ - MtpFfsHandle_test.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - libbase \ - libcutils \ - libmedia \ - libmtp \ - libutils \ - liblog - -LOCAL_C_INCLUDES := \ - frameworks/av/media/mtp \ - -LOCAL_CFLAGS += -Werror -Wall - -include $(BUILD_NATIVE_TEST) - -include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -LOCAL_MODULE := async_io_test - -LOCAL_MODULE_TAGS := tests - -LOCAL_SRC_FILES := \ - AsyncIO_test.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - libbase \ - libcutils \ - libmedia \ - libmtp \ - libutils \ - liblog - -LOCAL_C_INCLUDES := \ - frameworks/av/media/mtp \ - -LOCAL_CFLAGS += -Werror -Wall - -include $(BUILD_NATIVE_TEST) diff --git a/media/mtp/tests/AndroidTest.xml b/media/mtp/tests/AndroidTest.xml new file mode 100644 index 0000000000..c1f4753f37 --- /dev/null +++ b/media/mtp/tests/AndroidTest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2017 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. +--> +<configuration description="Config for mtp_ffs_handle_test"> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="cleanup" value="true" /> + <option name="push" value="mtp_ffs_handle_test->/data/local/tmp/mtp_ffs_handle_test" /> + </target_preparer> + <option name="test-suite-tag" value="apct" /> + <test class="com.android.tradefed.testtype.GTest" > + <option name="native-test-device-path" value="/data/local/tmp" /> + <option name="module-name" value="mtp_ffs_handle_test" /> + </test> +</configuration>
\ No newline at end of file diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp index 824872fd1b..40974f383b 100644 --- a/media/ndk/Android.bp +++ b/media/ndk/Android.bp @@ -22,3 +22,71 @@ ndk_library { first_version: "21", unversioned_until: "current", } + +ndk_headers { + name: "libmediandk_headers", + from: "include/media", + to: "media", + srcs: ["include/media/**/*.h"], + license: "NOTICE", +} + +cc_library_shared { + name: "libmediandk", + + srcs: [ + "NdkMediaCodec.cpp", + "NdkMediaCrypto.cpp", + "NdkMediaExtractor.cpp", + "NdkMediaFormat.cpp", + "NdkMediaMuxer.cpp", + "NdkMediaDrm.cpp", + "NdkImage.cpp", + "NdkImageReader.cpp", + ], + + include_dirs: [ + "bionic/libc/private", + "frameworks/base/core/jni", + "frameworks/native/include/media/openmax", + "system/media/camera/include", + ], + + cflags: [ + "-fvisibility=hidden", + "-DEXPORT=__attribute__((visibility(\"default\")))", + + "-Werror", + "-Wall", + ], + + static_libs: [ + "libgrallocusage", + ], + + shared_libs: [ + "libbinder", + "libmedia", + "libmedia_jni", + "libmediadrm", + "libskia", + "libstagefright", + "libstagefright_foundation", + "liblog", + "libutils", + "libcutils", + "libandroid", + "libandroid_runtime", + "libbinder", + "libgui", + "libui", + ], + + export_include_dirs: ["include"], + + product_variables: { + pdk: { + enabled: false, + }, + }, +} diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk deleted file mode 100644 index 2c070af4fe..0000000000 --- a/media/ndk/Android.mk +++ /dev/null @@ -1,73 +0,0 @@ -# -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -LOCAL_PATH:= $(call my-dir) - -ifneq ($(TARGET_BUILD_PDK), true) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - NdkMediaCodec.cpp \ - NdkMediaCrypto.cpp \ - NdkMediaExtractor.cpp \ - NdkMediaFormat.cpp \ - NdkMediaMuxer.cpp \ - NdkMediaDrm.cpp \ - NdkImage.cpp \ - NdkImageReader.cpp \ - -LOCAL_MODULE:= libmediandk - -LOCAL_C_INCLUDES := \ - bionic/libc/private \ - external/piex \ - frameworks/base/core/jni \ - frameworks/base/media/jni \ - frameworks/av/include/ndk \ - frameworks/native/include \ - frameworks/native/include/media/openmax \ - system/media/camera/include \ - $(call include-path-for, libhardware)/hardware \ - -LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))' - -LOCAL_CFLAGS += -Werror -Wall - -LOCAL_STATIC_LIBRARIES := \ - libgrallocusage \ - -LOCAL_SHARED_LIBRARIES := \ - libbinder \ - libmedia \ - libmedia_jni \ - libmediadrm \ - libskia \ - libstagefright \ - libstagefright_foundation \ - liblog \ - libutils \ - libcutils \ - libandroid \ - libandroid_runtime \ - libbinder \ - libgui \ - libui \ - libandroid \ - -include $(BUILD_SHARED_LIBRARY) - -endif diff --git a/media/ndk/NOTICE b/media/ndk/NOTICE new file mode 100644 index 0000000000..152be20595 --- /dev/null +++ b/media/ndk/NOTICE @@ -0,0 +1,324 @@ + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the Android-specific code. == + ========================================================================= + +Android Code +Copyright 2005-2008 The Android Open Source Project + +This product includes software developed as part of +The Android Open Source Project (http://source.android.com). + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for Apache Commons code. == + ========================================================================= + +Apache Commons +Copyright 1999-2006 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for Jakarta Commons Logging. == + ========================================================================= + +Jakarta Commons Logging (JCL) +Copyright 2005,2006 The Apache Software Foundation. + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the Nuance code. == + ========================================================================= + +These files are Copyright 2007 Nuance Communications, but released under +the Apache2 License. + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the Media Codecs code. == + ========================================================================= + +Media Codecs +These files are Copyright 1998 - 2009 PacketVideo, but released under +the Apache2 License. + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the TagSoup code. == + ========================================================================= + +This file is part of TagSoup and is Copyright 2002-2008 by John Cowan. + +TagSoup is licensed under the Apache License, +Version 2.0. You may obtain a copy of this license at +http://www.apache.org/licenses/LICENSE-2.0 . You may also have +additional legal rights not granted by this license. + +TagSoup is distributed in the hope that it will be useful, but +unless required by applicable law or agreed to in writing, TagSoup +is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +OF ANY KIND, either express or implied; not even the implied warranty +of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for Additional Codecs code. == + ========================================================================= + +Additional Codecs +These files are Copyright 2003-2010 VisualOn, but released under +the Apache2 License. + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the Audio Effects code. == + ========================================================================= + +Audio Effects +These files are Copyright (C) 2004-2010 NXP Software and +Copyright (C) 2010 The Android Open Source Project, but released under +the Apache2 License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + + +UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE + +Unicode Data Files include all data files under the directories +http://www.unicode.org/Public/, http://www.unicode.org/reports/, +and http://www.unicode.org/cldr/data/ . Unicode Software includes any +source code published in the Unicode Standard or under the directories +http://www.unicode.org/Public/, http://www.unicode.org/reports/, and +http://www.unicode.org/cldr/data/. + +NOTICE TO USER: Carefully read the following legal agreement. BY +DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA +FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY +ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF +THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, +DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2008 Unicode, Inc. All rights reserved. Distributed +under the Terms of Use in http://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation (the +"Data Files") or Unicode software and any associated documentation (the +"Software") to deal in the Data Files or Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, and/or sell copies of the Data Files or Software, +and to permit persons to whom the Data Files or Software are furnished to +do so, provided that (a) the above copyright notice(s) and this permission +notice appear with all copies of the Data Files or Software, (b) both the +above copyright notice(s) and this permission notice appear in associated +documentation, and (c) there is clear notice in each modified Data File +or in the Software as well as in the documentation associated with the +Data File(s) or Software that the data or software has been modified. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS +INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT +OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE +OR PERFORMANCE OF THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in these Data Files or Software without prior written +authorization of the copyright holder. diff --git a/media/ndk/NdkImagePriv.h b/media/ndk/NdkImagePriv.h index e9073d57c1..e0f16dadf9 100644 --- a/media/ndk/NdkImagePriv.h +++ b/media/ndk/NdkImagePriv.h @@ -25,7 +25,7 @@ #include <gui/CpuConsumer.h> #include "NdkImageReaderPriv.h" -#include "NdkImage.h" +#include <media/NdkImage.h> using namespace android; diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h index 35af16932d..989c1fdbec 100644 --- a/media/ndk/NdkImageReaderPriv.h +++ b/media/ndk/NdkImageReaderPriv.h @@ -19,7 +19,7 @@ #include <inttypes.h> -#include "NdkImageReader.h" +#include <media/NdkImageReader.h> #include <utils/List.h> #include <utils/Mutex.h> diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index 6faa19f1b5..f313e901cd 100644 --- a/media/ndk/NdkMediaCodec.cpp +++ b/media/ndk/NdkMediaCodec.cpp @@ -19,8 +19,8 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "NdkMediaCodec" -#include "NdkMediaCodec.h" -#include "NdkMediaError.h" +#include <media/NdkMediaCodec.h> +#include <media/NdkMediaError.h> #include "NdkMediaCryptoPriv.h" #include "NdkMediaFormatPriv.h" diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp index 32aabddd08..d7193caf0a 100644 --- a/media/ndk/NdkMediaCrypto.cpp +++ b/media/ndk/NdkMediaCrypto.cpp @@ -18,8 +18,8 @@ #define LOG_TAG "NdkMediaCrypto" -#include "NdkMediaCrypto.h" -#include "NdkMediaCodec.h" +#include <media/NdkMediaCrypto.h> +#include <media/NdkMediaCodec.h> #include "NdkMediaFormatPriv.h" diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp index 7a9240b721..51143ac531 100644 --- a/media/ndk/NdkMediaDrm.cpp +++ b/media/ndk/NdkMediaDrm.cpp @@ -17,7 +17,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "NdkMediaDrm" -#include "NdkMediaDrm.h" +#include <media/NdkMediaDrm.h> #include <cutils/properties.h> #include <utils/Log.h> @@ -29,7 +29,7 @@ #include <media/stagefright/MediaErrors.h> #include <binder/IServiceManager.h> #include <media/IMediaDrmService.h> -#include <ndk/NdkMediaCrypto.h> +#include <media/NdkMediaCrypto.h> using namespace android; diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp index 805eafb894..e677d004ad 100644 --- a/media/ndk/NdkMediaExtractor.cpp +++ b/media/ndk/NdkMediaExtractor.cpp @@ -18,8 +18,8 @@ #define LOG_TAG "NdkMediaExtractor" -#include "NdkMediaError.h" -#include "NdkMediaExtractor.h" +#include <media/NdkMediaError.h> +#include <media/NdkMediaExtractor.h> #include "NdkMediaFormatPriv.h" diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp index 5598d5d059..ee27520f9a 100644 --- a/media/ndk/NdkMediaFormat.cpp +++ b/media/ndk/NdkMediaFormat.cpp @@ -19,7 +19,7 @@ #include <inttypes.h> -#include "NdkMediaFormat.h" +#include <media/NdkMediaFormat.h> #include <utils/Log.h> #include <utils/StrongPointer.h> diff --git a/media/ndk/NdkMediaFormatPriv.h b/media/ndk/NdkMediaFormatPriv.h index 02342d9e0e..c6a6563aa5 100644 --- a/media/ndk/NdkMediaFormatPriv.h +++ b/media/ndk/NdkMediaFormatPriv.h @@ -27,7 +27,7 @@ #ifndef _NDK_MEDIA_FORMAT_PRIV_H #define _NDK_MEDIA_FORMAT_PRIV_H -#include <NdkMediaFormat.h> +#include <media/NdkMediaFormat.h> #ifdef __cplusplus extern "C" { diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp index bbf33cd42c..80a4391945 100644 --- a/media/ndk/NdkMediaMuxer.cpp +++ b/media/ndk/NdkMediaMuxer.cpp @@ -18,8 +18,8 @@ #define LOG_TAG "NdkMediaMuxer" -#include "NdkMediaMuxer.h" -#include "NdkMediaCodec.h" +#include <media/NdkMediaMuxer.h> +#include <media/NdkMediaCodec.h> #include "NdkMediaFormatPriv.h" diff --git a/include/ndk/NdkImage.h b/media/ndk/include/media/NdkImage.h index d7443be8ec..d7443be8ec 100644 --- a/include/ndk/NdkImage.h +++ b/media/ndk/include/media/NdkImage.h diff --git a/include/ndk/NdkImageReader.h b/media/ndk/include/media/NdkImageReader.h index 59ae507496..59ae507496 100644 --- a/include/ndk/NdkImageReader.h +++ b/media/ndk/include/media/NdkImageReader.h diff --git a/include/ndk/NdkMediaCodec.h b/media/ndk/include/media/NdkMediaCodec.h index 637bf9b33d..637bf9b33d 100644 --- a/include/ndk/NdkMediaCodec.h +++ b/media/ndk/include/media/NdkMediaCodec.h diff --git a/include/ndk/NdkMediaCrypto.h b/media/ndk/include/media/NdkMediaCrypto.h index 9236765d95..9236765d95 100644 --- a/include/ndk/NdkMediaCrypto.h +++ b/media/ndk/include/media/NdkMediaCrypto.h diff --git a/include/ndk/NdkMediaDrm.h b/media/ndk/include/media/NdkMediaDrm.h index cba43801f4..cba43801f4 100644 --- a/include/ndk/NdkMediaDrm.h +++ b/media/ndk/include/media/NdkMediaDrm.h diff --git a/include/ndk/NdkMediaError.h b/media/ndk/include/media/NdkMediaError.h index 1b51364e8e..1b51364e8e 100644 --- a/include/ndk/NdkMediaError.h +++ b/media/ndk/include/media/NdkMediaError.h diff --git a/include/ndk/NdkMediaExtractor.h b/media/ndk/include/media/NdkMediaExtractor.h index c3180dcf9d..c3180dcf9d 100644 --- a/include/ndk/NdkMediaExtractor.h +++ b/media/ndk/include/media/NdkMediaExtractor.h diff --git a/include/ndk/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h index a2a21d2cdb..a2a21d2cdb 100644 --- a/include/ndk/NdkMediaFormat.h +++ b/media/ndk/include/media/NdkMediaFormat.h diff --git a/include/ndk/NdkMediaMuxer.h b/media/ndk/include/media/NdkMediaMuxer.h index 25987a28a0..25987a28a0 100644 --- a/include/ndk/NdkMediaMuxer.h +++ b/media/ndk/include/media/NdkMediaMuxer.h diff --git a/media/vndk/Android.bp b/media/vndk/Android.bp index a233d6c41b..e93fd16da3 100644 --- a/media/vndk/Android.bp +++ b/media/vndk/Android.bp @@ -1,4 +1,4 @@ subdirs = [ - "*", + "xmlparser/1.0", ] diff --git a/media/vndk/xmlparser/1.0/Android.bp b/media/vndk/xmlparser/1.0/Android.bp index c48703ce6d..2f10cb10b3 100644 --- a/media/vndk/xmlparser/1.0/Android.bp +++ b/media/vndk/xmlparser/1.0/Android.bp @@ -1,6 +1,6 @@ cc_library_shared { - name: "libstagefright_xmlparser@1.0", + vendor_available: true, srcs: [ "MediaCodecsXmlParser.cpp", diff --git a/media/vndk/xmlparser/Android.bp b/media/vndk/xmlparser/Android.bp deleted file mode 100644 index a233d6c41b..0000000000 --- a/media/vndk/xmlparser/Android.bp +++ /dev/null @@ -1,4 +0,0 @@ -subdirs = [ - "*", -] - diff --git a/radio/Android.bp b/radio/Android.bp new file mode 100644 index 0000000000..8e614f2ae6 --- /dev/null +++ b/radio/Android.bp @@ -0,0 +1,37 @@ +// Copyright 2014 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_library_shared { + name: "libradio", + + srcs: [ + "Radio.cpp", + "IRadio.cpp", + "IRadioClient.cpp", + "IRadioService.cpp", + ], + + shared_libs: [ + "libcutils", + "libutils", + "liblog", + "libbinder", + "libradio_metadata", + ], + + cflags: [ + "-Werror", + "-Wall", + ], +} diff --git a/radio/Android.mk b/radio/Android.mk deleted file mode 100644 index be5d283ad7..0000000000 --- a/radio/Android.mk +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - Radio.cpp \ - IRadio.cpp \ - IRadioClient.cpp \ - IRadioService.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - liblog \ - libbinder \ - libradio_metadata - -#LOCAL_C_INCLUDES += \ - system/media/camera/include \ - system/media/private/camera/include - -LOCAL_MODULE:= libradio - -LOCAL_CFLAGS := -Werror -Wall - -include $(BUILD_SHARED_LIBRARY) diff --git a/radio/Radio.cpp b/radio/Radio.cpp index fa395899ce..9ddd221d60 100644 --- a/radio/Radio.cpp +++ b/radio/Radio.cpp @@ -117,8 +117,8 @@ sp<Radio> Radio::attach(radio_handle_t handle, // Radio -Radio::Radio(radio_handle_t handle, const sp<RadioCallback>& callback) - : mHandle(handle), mCallback(callback) +Radio::Radio(radio_handle_t /*handle*/, const sp<RadioCallback>& callback) + : mCallback(callback) { } diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk index 0c620f4fe0..d0454d4afa 100644 --- a/services/audioflinger/Android.mk +++ b/services/audioflinger/Android.mk @@ -34,8 +34,8 @@ LOCAL_SRC_FILES:= \ TypedLogger.cpp LOCAL_C_INCLUDES := \ - $(TOPDIR)frameworks/av/services/audiopolicy \ - $(TOPDIR)frameworks/av/services/medialog \ + frameworks/av/services/audiopolicy \ + frameworks/av/services/medialog \ $(call include-path-for, audio-utils) LOCAL_SHARED_LIBRARIES := \ diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 0f43ed6e50..111193c38e 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -41,7 +41,6 @@ #include <utils/threads.h> #include <utils/Atomic.h> -#include <cutils/bitops.h> #include <cutils/properties.h> #include <system/audio.h> @@ -261,10 +260,11 @@ __attribute__ ((visibility ("default"))) status_t MmapStreamInterface::openMmapStream(MmapStreamInterface::stream_direction_t direction, const audio_attributes_t *attr, audio_config_base_t *config, - const MmapStreamInterface::Client& client, + const AudioClient& client, audio_port_handle_t *deviceId, const sp<MmapStreamCallback>& callback, - sp<MmapStreamInterface>& interface) + sp<MmapStreamInterface>& interface, + audio_port_handle_t *handle) { sp<AudioFlinger> af; { @@ -274,7 +274,7 @@ status_t MmapStreamInterface::openMmapStream(MmapStreamInterface::stream_directi status_t ret = NO_INIT; if (af != 0) { ret = af->openMmapStream( - direction, attr, config, client, deviceId, callback, interface); + direction, attr, config, client, deviceId, callback, interface, handle); } return ret; } @@ -282,10 +282,11 @@ status_t MmapStreamInterface::openMmapStream(MmapStreamInterface::stream_directi status_t AudioFlinger::openMmapStream(MmapStreamInterface::stream_direction_t direction, const audio_attributes_t *attr, audio_config_base_t *config, - const MmapStreamInterface::Client& client, + const AudioClient& client, audio_port_handle_t *deviceId, const sp<MmapStreamCallback>& callback, - sp<MmapStreamInterface>& interface) + sp<MmapStreamInterface>& interface, + audio_port_handle_t *handle) { status_t ret = initCheck(); if (ret != NO_ERROR) { @@ -294,7 +295,7 @@ status_t AudioFlinger::openMmapStream(MmapStreamInterface::stream_direction_t di audio_session_t sessionId = (audio_session_t) newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION); audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT; - audio_io_handle_t io; + audio_io_handle_t io = AUDIO_IO_HANDLE_NONE; audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE; if (direction == MmapStreamInterface::DIRECTION_OUTPUT) { audio_config_t fullConfig = AUDIO_CONFIG_INITIALIZER; @@ -307,14 +308,14 @@ status_t AudioFlinger::openMmapStream(MmapStreamInterface::stream_direction_t di &fullConfig, (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT), - *deviceId, &portId); + deviceId, &portId); } else { ret = AudioSystem::getInputForAttr(attr, &io, sessionId, client.clientPid, client.clientUid, config, - AUDIO_INPUT_FLAG_MMAP_NOIRQ, *deviceId, &portId); + AUDIO_INPUT_FLAG_MMAP_NOIRQ, deviceId, &portId); } if (ret != NO_ERROR) { return ret; @@ -326,6 +327,7 @@ status_t AudioFlinger::openMmapStream(MmapStreamInterface::stream_direction_t di if (thread != 0) { interface = new MmapThreadHandle(thread); thread->configure(attr, streamType, sessionId, callback, portId); + *handle = portId; } else { ret = NO_INIT; } @@ -340,7 +342,6 @@ static const char * const audio_interfaces[] = { AUDIO_HARDWARE_MODULE_ID_A2DP, AUDIO_HARDWARE_MODULE_ID_USB, }; -#define ARRAY_SIZE(x) (sizeof((x))/sizeof(((x)[0]))) AudioHwDevice* AudioFlinger::findSuitableHwDev_l( audio_module_handle_t module, @@ -350,7 +351,7 @@ AudioHwDevice* AudioFlinger::findSuitableHwDev_l( // well known modules if (module == 0) { ALOGW("findSuitableHwDev_l() loading well know audio hw modules"); - for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) { + for (size_t i = 0; i < arraysize(audio_interfaces); i++) { loadHwModule_l(audio_interfaces[i]); } // then try to find a module supporting the requested device. @@ -520,7 +521,7 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args) #ifdef TEE_SINK // dump the serially shared record tee sink if (mRecordTeeSource != 0) { - dumpTee(fd, mRecordTeeSource); + dumpTee(fd, mRecordTeeSource, AUDIO_IO_HANDLE_NONE, 'C'); } #endif @@ -1192,25 +1193,10 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& String8 value; if (param.get(String8(AudioParameter::keyBtNrec), value) == NO_ERROR) { bool btNrecIsOff = (value == AudioParameter::valueOff); - if (mBtNrecIsOff != btNrecIsOff) { + if (mBtNrecIsOff.exchange(btNrecIsOff) != btNrecIsOff) { for (size_t i = 0; i < mRecordThreads.size(); i++) { - sp<RecordThread> thread = mRecordThreads.valueAt(i); - audio_devices_t device = thread->inDevice(); - bool suspend = audio_is_bluetooth_sco_device(device) && btNrecIsOff; - // collect all of the thread's session IDs - KeyedVector<audio_session_t, bool> ids = thread->sessionIds(); - // suspend effects associated with those session IDs - for (size_t j = 0; j < ids.size(); ++j) { - audio_session_t sessionId = ids.keyAt(j); - thread->setEffectSuspended(FX_IID_AEC, - suspend, - sessionId); - thread->setEffectSuspended(FX_IID_NS, - suspend, - sessionId); - } + mRecordThreads.valueAt(i)->checkBtNrec(); } - mBtNrecIsOff = btNrecIsOff; } } String8 screenState; @@ -1281,7 +1267,7 @@ String8 AudioFlinger::getParameters(audio_io_handle_t ioHandle, const String8& k if (thread == NULL) { thread = (ThreadBase *)checkMmapThread_l(ioHandle); if (thread == NULL) { - String8(""); + return String8(""); } } } @@ -3236,6 +3222,11 @@ void AudioFlinger::onNonOffloadableGlobalEffectEnable() status_t AudioFlinger::putOrphanEffectChain_l(const sp<AudioFlinger::EffectChain>& chain) { + // clear possible suspended state before parking the chain so that it starts in default state + // when attached to a new record thread + chain->setEffectSuspended_l(FX_IID_AEC, false); + chain->setEffectSuspended_l(FX_IID_NS, false); + audio_session_t session = chain->sessionId(); ssize_t index = mOrphanEffectChains.indexOfKey(session); ALOGV("putOrphanEffectChain_l session %d index %zd", session, index); @@ -3288,7 +3279,7 @@ int comparEntry(const void *p1, const void *p2) } #ifdef TEE_SINK -void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id) +void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id, char suffix) { NBAIO_Source *teeSource = source.get(); if (teeSource != NULL) { @@ -3350,7 +3341,8 @@ void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_hand struct tm tm; localtime_r(&tv.tv_sec, &tm); strftime(teeTime, sizeof(teeTime), "%Y%m%d%H%M%S", &tm); - snprintf(&teePath[teePathLen], sizeof(teePath) - teePathLen, "%s_%d.wav", teeTime, id); + snprintf(&teePath[teePathLen], sizeof(teePath) - teePathLen, "%s_%d_%c.wav", teeTime, id, + suffix); // if 2 dumpsys are done within 1 second, and rotation didn't work, then discard 2nd int teeFd = open(teePath, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, S_IRUSR | S_IWUSR); if (teeFd >= 0) { diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 75b4e4c919..9023b2d52f 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -25,6 +25,8 @@ #include <sys/types.h> #include <limits.h> +#include <android-base/macros.h> + #include <cutils/compiler.h> #include <cutils/properties.h> @@ -71,12 +73,11 @@ #include <powermanager/IPowerManager.h> #include <media/nbaio/NBLog.h> +#include <private/media/AudioEffectShared.h> #include <private/media/AudioTrackShared.h> namespace android { -struct audio_track_cblk_t; -struct effect_param_cblk_t; class AudioMixer; class AudioBuffer; class AudioResampler; @@ -293,12 +294,14 @@ public: status_t openMmapStream(MmapStreamInterface::stream_direction_t direction, const audio_attributes_t *attr, audio_config_base_t *config, - const MmapStreamInterface::Client& client, + const AudioClient& client, audio_port_handle_t *deviceId, const sp<MmapStreamCallback>& callback, - sp<MmapStreamInterface>& interface); + sp<MmapStreamInterface>& interface, + audio_port_handle_t *handle); private: - static const size_t kLogMemorySize = 40 * 1024; + // FIXME The 400 is temporarily too high until a leak of writers in media.log is fixed. + static const size_t kLogMemorySize = 400 * 1024; sp<MemoryDealer> mLogMemoryDealer; // == 0 when NBLog is disabled // When a log writer is unregistered, it is done lazily so that media.log can continue to see it // for as long as possible. The memory is only freed when it is needed for another log writer. @@ -347,12 +350,13 @@ public: sync_event_callback_t callBack, const wp<RefBase>& cookie); + bool btNrecIsOff() const { return mBtNrecIsOff.load(); } + + private: audio_mode_t getMode() const { return mMode; } - bool btNrecIsOff() const { return mBtNrecIsOff; } - AudioFlinger() ANDROID_API; virtual ~AudioFlinger(); @@ -445,8 +449,8 @@ private: sp<AudioFlinger> audioFlinger() const { return mAudioFlinger; } private: - Client(const Client&); - Client& operator = (const Client&); + DISALLOW_COPY_AND_ASSIGN(Client); + const sp<AudioFlinger> mAudioFlinger; sp<MemoryDealer> mMemoryDealer; const pid_t mPid; @@ -466,8 +470,7 @@ private: virtual void binderDied(const wp<IBinder>& who); private: - NotificationClient(const NotificationClient&); - NotificationClient& operator = (const NotificationClient&); + DISALLOW_COPY_AND_ASSIGN(NotificationClient); const sp<AudioFlinger> mAudioFlinger; const pid_t mPid; @@ -595,7 +598,7 @@ private: virtual status_t createMmapBuffer(int32_t minSizeFrames, struct audio_mmap_buffer_info *info); virtual status_t getMmapPosition(struct audio_mmap_position *position); - virtual status_t start(const MmapStreamInterface::Client& client, + virtual status_t start(const AudioClient& client, audio_port_handle_t *handle); virtual status_t stop(audio_port_handle_t handle); virtual status_t standby(); @@ -779,7 +782,7 @@ private: volatile atomic_uint_fast32_t mNextUniqueIds[AUDIO_UNIQUE_ID_USE_MAX]; audio_mode_t mMode; - bool mBtNrecIsOff; + std::atomic_bool mBtNrecIsOff; // protected by mLock Vector<AudioSessionRef*> mAudioSessionRefs; @@ -824,7 +827,7 @@ public: #ifdef TEE_SINK // tee sink, if enabled by property, allows dumpsys to write most recent audio to .wav file - static void dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id = 0); + static void dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id, char suffix); // whether tee sink is enabled by property static bool mTeeSinkInputEnabled; diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index 60eca7e5c3..f2c1c4fbce 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -21,11 +21,12 @@ #include "Configuration.h" #include <utils/Log.h> +#include <system/audio_effects/effect_aec.h> +#include <system/audio_effects/effect_ns.h> +#include <system/audio_effects/effect_visualizer.h> #include <audio_utils/primitives.h> -#include <private/media/AudioEffectShared.h> #include <media/audiohal/EffectHalInterface.h> #include <media/audiohal/EffectsFactoryHalInterface.h> -#include <system/audio_effects/effect_visualizer.h> #include "AudioFlinger.h" #include "ServiceUtilities.h" @@ -1810,6 +1811,7 @@ status_t AudioFlinger::EffectChain::addEffect_ll(const sp<EffectModule>& effect) idx_insert); } effect->configure(); + return NO_ERROR; } @@ -2031,6 +2033,7 @@ void AudioFlinger::EffectChain::setEffectSuspended_l( mSuspendedEffects.add(type->timeLow, desc); ALOGV("setEffectSuspended_l() add entry for %08x", type->timeLow); } + if (desc->mRefCount++ == 0) { sp<EffectModule> effect = getEffectIfEnabled(type); if (effect != 0) { @@ -2046,7 +2049,8 @@ void AudioFlinger::EffectChain::setEffectSuspended_l( desc = mSuspendedEffects.valueAt(index); if (desc->mRefCount <= 0) { ALOGW("setEffectSuspended_l() restore refcount should not be 0 %d", desc->mRefCount); - desc->mRefCount = 1; + desc->mRefCount = 0; + return; } if (--desc->mRefCount == 0) { ALOGV("setEffectSuspended_l() remove entry for %08x", mSuspendedEffects.keyAt(index)); @@ -2124,6 +2128,17 @@ static const effect_uuid_t SL_IID_VOLUME_ = { 0x09e8ede0, 0xddde, 0x11db, 0xb4f6 const effect_uuid_t * const SL_IID_VOLUME = &SL_IID_VOLUME_; #endif //OPENSL_ES_H_ +/* static */ +bool AudioFlinger::EffectChain::isEffectEligibleForBtNrecSuspend(const effect_uuid_t *type) +{ + // Only NS and AEC are suspended when BtNRec is off + if ((memcmp(type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) || + (memcmp(type, FX_IID_NS, sizeof(effect_uuid_t)) == 0)) { + return true; + } + return false; +} + bool AudioFlinger::EffectChain::isEffectEligibleForSuspend(const effect_descriptor_t& desc) { // auxiliary effects and visualizer are never suspended on output mix @@ -2178,7 +2193,7 @@ void AudioFlinger::EffectChain::checkSuspendOnEffectEnabled(const sp<EffectModul ALOGV("checkSuspendOnEffectEnabled() enable suspending fx %08x", effect->desc().type.timeLow); sp<SuspendedEffectDesc> desc = mSuspendedEffects.valueAt(index); - // if effect is requested to suspended but was not yet enabled, supend it now. + // if effect is requested to suspended but was not yet enabled, suspend it now. if (desc->mEffect == 0) { desc->mEffect = effect; effect->setEnabled(false); diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h index 0755c523b9..e29798b36b 100644 --- a/services/audioflinger/Effects.h +++ b/services/audioflinger/Effects.h @@ -135,15 +135,14 @@ public: void dump(int fd, const Vector<String16>& args); -protected: +private: friend class AudioFlinger; // for mHandles bool mPinned; // Maximum time allocated to effect engines to complete the turn off sequence static const uint32_t MAX_DISABLE_TIME_MS = 10000; - EffectModule(const EffectModule&); - EffectModule& operator = (const EffectModule&); + DISALLOW_COPY_AND_ASSIGN(EffectModule); status_t start_l(); status_t stop_l(); @@ -232,10 +231,9 @@ public: void dumpToBuffer(char* buffer, size_t size); -protected: +private: friend class AudioFlinger; // for mEffect, mHasControl, mEnabled - EffectHandle(const EffectHandle&); - EffectHandle& operator =(const EffectHandle&); + DISALLOW_COPY_AND_ASSIGN(EffectHandle); Mutex mLock; // protects IEffect method calls wp<EffectModule> mEffect; // pointer to controlled EffectModule @@ -333,7 +331,8 @@ public: void setStrategy(uint32_t strategy) { mStrategy = strategy; } - // suspend effect of the given type + // suspend or restore effects of the specified type. The number of suspend requests is counted + // and restore occurs once all suspend requests are cancelled. void setEffectSuspended_l(const effect_uuid_t *type, bool suspend); // suspend all eligible effects @@ -366,16 +365,15 @@ public: void dump(int fd, const Vector<String16>& args); -protected: +private: friend class AudioFlinger; // for mThread, mEffects - EffectChain(const EffectChain&); - EffectChain& operator =(const EffectChain&); + DISALLOW_COPY_AND_ASSIGN(EffectChain); class SuspendedEffectDesc : public RefBase { public: SuspendedEffectDesc() : mRefCount(0) {} - int mRefCount; + int mRefCount; // > 0 when suspended effect_uuid_t mType; wp<EffectModule> mEffect; }; @@ -391,6 +389,8 @@ protected: // types or implementations from the suspend/restore mechanism. bool isEffectEligibleForSuspend(const effect_descriptor_t& desc); + static bool isEffectEligibleForBtNrecSuspend(const effect_uuid_t *type); + void clearInputBuffer_l(const sp<ThreadBase>& thread); void setThread(const sp<ThreadBase>& thread); @@ -417,6 +417,6 @@ protected: // mSuspendedEffects lists all effects currently suspended in the chain. // Use effect type UUID timelow field as key. There is no real risk of identical // timeLow fields among effect type UUIDs. - // Updated by updateSuspendedSessions_l() only. + // Updated by setEffectSuspended_l() and setEffectSuspendedAll_l() only. KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects; }; diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp index 873a9adf26..d063772bab 100644 --- a/services/audioflinger/FastCapture.cpp +++ b/services/audioflinger/FastCapture.cpp @@ -57,7 +57,7 @@ const FastThreadState *FastCapture::poll() return mSQ.poll(); } -void FastCapture::setLog(NBLog::Writer *logWriter __unused) +void FastCapture::setNBLogWriter(NBLog::Writer *logWriter __unused) { } diff --git a/services/audioflinger/FastCapture.h b/services/audioflinger/FastCapture.h index e258a4daaa..c3817c0f32 100644 --- a/services/audioflinger/FastCapture.h +++ b/services/audioflinger/FastCapture.h @@ -39,7 +39,7 @@ private: // callouts virtual const FastThreadState *poll(); - virtual void setLog(NBLog::Writer *logWriter); + virtual void setNBLogWriter(NBLog::Writer *logWriter); virtual void onIdle(); virtual void onExit(); virtual bool isSubClassCommand(FastThreadState::Command command); diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp index 103e7f8158..c4f1af354e 100644 --- a/services/audioflinger/FastMixer.cpp +++ b/services/audioflinger/FastMixer.cpp @@ -41,6 +41,7 @@ #include <audio_utils/format.h> #include <media/AudioMixer.h> #include "FastMixer.h" +#include "TypedLogger.h" namespace android { @@ -101,10 +102,12 @@ const FastThreadState *FastMixer::poll() return mSQ.poll(); } -void FastMixer::setLog(NBLog::Writer *logWriter) +void FastMixer::setNBLogWriter(NBLog::Writer *logWriter) { + // FIXME If mMixer is set or changed prior to this, we don't inform correctly. + // Should cache logWriter and re-apply it at the assignment to mMixer. if (mMixer != NULL) { - mMixer->setLog(logWriter); + mMixer->setNBLogWriter(logWriter); } } @@ -135,6 +138,7 @@ bool FastMixer::isSubClassCommand(FastThreadState::Command command) void FastMixer::onStateChange() { + LOG_HIST_FLUSH(); const FastMixerState * const current = (const FastMixerState *) mCurrent; const FastMixerState * const previous = (const FastMixerState *) mPrevious; FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState; @@ -188,6 +192,7 @@ void FastMixer::onStateChange() // implementation; it would be better to have normal mixer allocate for us // to avoid blocking here and to prevent possible priority inversion mMixer = new AudioMixer(frameCount, mSampleRate, FastMixerState::sMaxFastTracks); + // FIXME See the other FIXME at FastMixer::setNBLogWriter() const size_t mixerFrameSize = mSinkChannelCount * audio_bytes_per_sample(mMixerBufferFormat); mMixerBufferSize = mixerFrameSize * frameCount; @@ -330,6 +335,7 @@ void FastMixer::onStateChange() void FastMixer::onWork() { + LOG_HIST_TS(); const FastMixerState * const current = (const FastMixerState *) mCurrent; FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState; const FastMixerState::Command command = mCommand; diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h index bdfd8a01dd..930fa8d8cc 100644 --- a/services/audioflinger/FastMixer.h +++ b/services/audioflinger/FastMixer.h @@ -46,7 +46,7 @@ private: // callouts virtual const FastThreadState *poll(); - virtual void setLog(NBLog::Writer *logWriter); + virtual void setNBLogWriter(NBLog::Writer *logWriter); virtual void onIdle(); virtual void onExit(); virtual bool isSubClassCommand(FastThreadState::Command command); diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp index cf9fce3ff6..85865b7661 100644 --- a/services/audioflinger/FastThread.cpp +++ b/services/audioflinger/FastThread.cpp @@ -27,6 +27,7 @@ #include <utils/Trace.h> #include "FastThread.h" #include "FastThreadDumpState.h" +#include "TypedLogger.h" #define FAST_DEFAULT_NS 999999999L // ~1 sec: default time to sleep #define FAST_HOT_IDLE_NS 1000000L // 1 ms: time to sleep while hot idling @@ -64,8 +65,8 @@ FastThread::FastThread(const char *cycleMs, const char *loadUs) : Thread(false / /* mMeasuredWarmupTs({0, 0}), */ mWarmupCycles(0), mWarmupConsecutiveInRangeCycles(0), - // mDummyLogWriter - mLogWriter(&mDummyLogWriter), + // mDummyNBLogWriter + mNBLogWriter(&mDummyNBLogWriter), mTimestampStatus(INVALID_OPERATION), mCommand(FastThreadState::INITIAL), @@ -90,6 +91,9 @@ FastThread::~FastThread() bool FastThread::threadLoop() { + // LOGT now works even if tlNBLogWriter is nullptr, but we're considering changing that, + // so this initialization permits a future change to remove the check for nullptr. + tlNBLogWriter = &mDummyNBLogWriter; for (;;) { // either nanosleep, sched_yield, or busy wait @@ -119,8 +123,9 @@ bool FastThread::threadLoop() // As soon as possible of learning of a new dump area, start using it mDumpState = next->mDumpState != NULL ? next->mDumpState : mDummyDumpState; - mLogWriter = next->mNBLogWriter != NULL ? next->mNBLogWriter : &mDummyLogWriter; - setLog(mLogWriter); + mNBLogWriter = next->mNBLogWriter != NULL ? next->mNBLogWriter : &mDummyNBLogWriter; + setNBLogWriter(mNBLogWriter); // FastMixer informs its AudioMixer, FastCapture ignores + tlNBLogWriter = mNBLogWriter; // We want to always have a valid reference to the previous (non-idle) state. // However, the state queue only guarantees access to current and previous states. @@ -218,7 +223,6 @@ bool FastThread::threadLoop() struct timespec newTs; int rc = clock_gettime(CLOCK_MONOTONIC, &newTs); if (rc == 0) { - //mLogWriter->logTimestamp(newTs); if (mOldTsValid) { time_t sec = newTs.tv_sec - mOldTs.tv_sec; long nsec = newTs.tv_nsec - mOldTs.tv_nsec; diff --git a/services/audioflinger/FastThread.h b/services/audioflinger/FastThread.h index 816b66686e..2a71414dae 100644 --- a/services/audioflinger/FastThread.h +++ b/services/audioflinger/FastThread.h @@ -41,7 +41,7 @@ protected: // callouts to subclass in same lexical order as they were in original FastMixer.cpp // FIXME need comments virtual const FastThreadState *poll() = 0; - virtual void setLog(NBLog::Writer *logWriter __unused) { } + virtual void setNBLogWriter(NBLog::Writer *logWriter __unused) { } virtual void onIdle() = 0; virtual void onExit() = 0; virtual bool isSubClassCommand(FastThreadState::Command command) = 0; @@ -81,8 +81,8 @@ protected: struct timespec mMeasuredWarmupTs; // how long did it take for warmup to complete uint32_t mWarmupCycles; // counter of number of loop cycles during warmup phase uint32_t mWarmupConsecutiveInRangeCycles; // number of consecutive cycles in range - NBLog::Writer mDummyLogWriter; - NBLog::Writer* mLogWriter; + NBLog::Writer mDummyNBLogWriter; + NBLog::Writer* mNBLogWriter; // always non-nullptr: real NBLog::Writer* or &mDummyNBLogWriter status_t mTimestampStatus; FastThreadState::Command mCommand; diff --git a/services/audioflinger/MmapTracks.h b/services/audioflinger/MmapTracks.h index e4fe8ac04c..2a27dfdb3b 100644 --- a/services/audioflinger/MmapTracks.h +++ b/services/audioflinger/MmapTracks.h @@ -41,11 +41,10 @@ public: static void appendDumpHeader(String8& result); void dump(char* buffer, size_t size); -protected: +private: friend class MmapThread; - MmapTrack(const MmapTrack&); - MmapTrack& operator = (const MmapTrack&); + DISALLOW_COPY_AND_ASSIGN(MmapTrack); // AudioBufferProvider interface virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer); diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h index f84ba08663..3f1a0c0aa4 100644 --- a/services/audioflinger/PlaybackTracks.h +++ b/services/audioflinger/PlaybackTracks.h @@ -94,8 +94,7 @@ protected: friend class DirectOutputThread; friend class OffloadThread; - Track(const Track&); - Track& operator = (const Track&); + DISALLOW_COPY_AND_ASSIGN(Track); // AudioBufferProvider interface virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer); diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h index 72ebc93cf7..3f83ca80ff 100644 --- a/services/audioflinger/RecordTracks.h +++ b/services/audioflinger/RecordTracks.h @@ -65,8 +65,7 @@ public: private: friend class AudioFlinger; // for mState - RecordTrack(const RecordTrack&); - RecordTrack& operator = (const RecordTrack&); + DISALLOW_COPY_AND_ASSIGN(RecordTrack); // AudioBufferProvider interface virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer); diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index a6857fe54c..65eccb6db4 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -100,10 +100,6 @@ static inline T min(const T& a, const T& b) return a < b ? a : b; } -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#endif - namespace android { // retry counts for buffer fill timeout @@ -995,13 +991,6 @@ void AudioFlinger::ThreadBase::PMDeathRecipient::binderDied(const wp<IBinder>& w ALOGW("power manager service died !!!"); } -void AudioFlinger::ThreadBase::setEffectSuspended( - const effect_uuid_t *type, bool suspend, audio_session_t sessionId) -{ - Mutex::Autolock _l(mLock); - setEffectSuspended_l(type, suspend, sessionId); -} - void AudioFlinger::ThreadBase::setEffectSuspended_l( const effect_uuid_t *type, bool suspend, audio_session_t sessionId) { @@ -1180,6 +1169,11 @@ status_t AudioFlinger::PlaybackThread::checkEffectCompatibility_l( return BAD_VALUE; } + // always allow effects without processing load or latency + if ((desc->flags & EFFECT_FLAG_NO_PROCESS_MASK) == EFFECT_FLAG_NO_PROCESS) { + return NO_ERROR; + } + switch (mType) { case MIXER: { // Reject any effect on mixer multichannel sinks. @@ -1210,10 +1204,6 @@ status_t AudioFlinger::PlaybackThread::checkEffectCompatibility_l( } } - // always allow effects without processing load or latency - if ((desc->flags & EFFECT_FLAG_NO_PROCESS_MASK) == EFFECT_FLAG_NO_PROCESS) { - break; - } if (flags & AUDIO_OUTPUT_FLAG_RAW) { ALOGW("checkEffectCompatibility_l(): effect %s on playback thread in raw mode", desc->name); @@ -1455,6 +1445,7 @@ status_t AudioFlinger::ThreadBase::addEffect_l(const sp<EffectModule>& effect) effect->setDevice(mInDevice); effect->setMode(mAudioFlinger->getMode()); effect->setAudioSource(mAudioSource); + return NO_ERROR; } @@ -2045,7 +2036,7 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac pid_t callingPid = IPCThreadState::self()->getCallingPid(); // we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful, // so ask activity manager to do this on our behalf - sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true /*isForApp*/); + sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true /*forApp*/); } } @@ -2182,7 +2173,7 @@ status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track) } char buffer[256]; - track->dump(buffer, ARRAY_SIZE(buffer), false /* active */); + track->dump(buffer, arraysize(buffer), false /* active */); mLocalLog.log("addTrack_l (%p) %s", track.get(), buffer + 4); // log for analysis status = NO_ERROR; @@ -2212,7 +2203,7 @@ void AudioFlinger::PlaybackThread::removeTrack_l(const sp<Track>& track) track->triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE); char buffer[256]; - track->dump(buffer, ARRAY_SIZE(buffer), false /* active */); + track->dump(buffer, arraysize(buffer), false /* active */); mLocalLog.log("removeTrack_l (%p) %s", track.get(), buffer + 4); // log for analysis mTracks.remove(track); @@ -2930,7 +2921,7 @@ void AudioFlinger::PlaybackThread::detachAuxEffect_l(int effectId) bool AudioFlinger::PlaybackThread::threadLoop() { - logWriterTLS = mNBLogWriter.get(); + tlNBLogWriter = mNBLogWriter.get(); Vector< sp<Track> > tracksToRemove; @@ -2957,9 +2948,13 @@ bool AudioFlinger::PlaybackThread::threadLoop() acquireWakeLock(); - // mNBLogWriter->log can only be called while thread mutex mLock is held. + // mNBLogWriter logging APIs can only be called by a single thread, typically the + // thread associated with this PlaybackThread. + // If you want to share the mNBLogWriter with other threads (for example, binder threads) + // then all such threads must agree to hold a common mutex before logging. // So if you need to log when mutex is unlocked, set logString to a non-NULL string, // and then that string will be logged at the next convenient opportunity. + // See reference to logString below. const char *logString = NULL; // Estimated time for next buffer to be written to hal. This is used only on @@ -2967,9 +2962,7 @@ bool AudioFlinger::PlaybackThread::threadLoop() nsecs_t timeLoopNextNs = 0; checkSilentMode_l(); -#if 0 - int z = 0; // used in logFormat example -#endif + while (!exitPending()) { // Log merge requests are performed during AudioFlinger binder transactions, but @@ -2986,6 +2979,7 @@ bool AudioFlinger::PlaybackThread::threadLoop() processConfigEvents_l(); + // See comment at declaration of logString for why this is done under mLock if (logString != NULL) { mNBLogWriter->logTimestamp(); mNBLogWriter->log(logString); @@ -3412,7 +3406,7 @@ void AudioFlinger::PlaybackThread::removeTracks_l(const Vector< sp<Track> >& tra removeTrack_l(track); } else { // inactive but not terminated char buffer[256]; - track->dump(buffer, ARRAY_SIZE(buffer), false /* active */); + track->dump(buffer, arraysize(buffer), false /* active */); mLocalLog.log("removeTracks_l(%p) %s", track.get(), buffer + 4); } } @@ -3738,7 +3732,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud // start the fast mixer mFastMixer->run("FastMixer", PRIORITY_URGENT_AUDIO); pid_t tid = mFastMixer->getTid(); - sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer, false); + sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer, false /*forApp*/); stream()->setHalThreadPriority(kPriorityFastMixer); #ifdef AUDIO_WATCHDOG @@ -3747,7 +3741,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud mAudioWatchdog->setDump(&mAudioWatchdogDump); mAudioWatchdog->run("AudioWatchdog", PRIORITY_URGENT_AUDIO); tid = mAudioWatchdog->getTid(); - sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer); + sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer, false /*forApp*/); #endif } @@ -4775,7 +4769,7 @@ void AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& ar #ifdef TEE_SINK // Write the tee output to a .wav file - dumpTee(fd, mTeeSource, mId); + dumpTee(fd, mTeeSource, mId, 'M'); #endif } @@ -5948,6 +5942,7 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, // mPipeMemory // mFastCaptureNBLogWriter , mFastTrackAvail(false) + , mBtNrecSuspended(false) { snprintf(mThreadName, kThreadNameLength, "AudioIn_%X", id); mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName); @@ -5971,12 +5966,17 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, switch (kUseFastCapture) { case FastCapture_Never: initFastCapture = false; + ALOGV("%p kUseFastCapture = Never, initFastCapture = false", this); break; case FastCapture_Always: initFastCapture = true; + ALOGV("%p kUseFastCapture = Always, initFastCapture = true", this); break; case FastCapture_Static: initFastCapture = (mFrameCount * 1000) / mSampleRate < kMinNormalCaptureBufferSizeMs; + ALOGV("%p kUseFastCapture = Static, (%lld * 1000) / %u vs %u, initFastCapture = %d", + this, (long long)mFrameCount, mSampleRate, kMinNormalCaptureBufferSizeMs, + initFastCapture); break; // case FastCapture_Dynamic: } @@ -5987,13 +5987,16 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, // quadruple-buffering of 20 ms each; this ensures we can sleep for 20ms in RecordThread size_t pipeFramesP2 = roundup(4 * FMS_20 * mSampleRate / 1000); size_t pipeSize = pipeFramesP2 * Format_frameSize(format); - void *pipeBuffer; + void *pipeBuffer = nullptr; const sp<MemoryDealer> roHeap(readOnlyHeap()); sp<IMemory> pipeMemory; if ((roHeap == 0) || (pipeMemory = roHeap->allocate(pipeSize)) == 0 || - (pipeBuffer = pipeMemory->pointer()) == NULL) { - ALOGE("not enough memory for pipe buffer size=%zu", pipeSize); + (pipeBuffer = pipeMemory->pointer()) == nullptr) { + ALOGE("not enough memory for pipe buffer size=%zu; " + "roHeap=%p, pipeMemory=%p, pipeBuffer=%p; roHeapSize: %lld", + pipeSize, roHeap.get(), pipeMemory.get(), pipeBuffer, + (long long)kRecordThreadReadOnlyHeapSize); goto failed; } // pipe will be shared directly with fast clients, so clear to avoid leaking old information @@ -6042,7 +6045,7 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, // start the fast capture mFastCapture->run("FastCapture", ANDROID_PRIORITY_URGENT_AUDIO); pid_t tid = mFastCapture->getTid(); - sendPrioConfigEvent(getpid_cached, tid, kPriorityFastCapture, false); + sendPrioConfigEvent(getpid_cached, tid, kPriorityFastCapture, false /*forApp*/); stream()->setHalThreadPriority(kPriorityFastCapture); #ifdef AUDIO_WATCHDOG // FIXME @@ -6635,19 +6638,19 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRe audio_input_flags_t old = *flags; chain->checkInputFlagCompatibility(flags); if (old != *flags) { - ALOGV("AUDIO_INPUT_FLAGS denied by effect old=%#x new=%#x", - (int)old, (int)*flags); + ALOGV("%p AUDIO_INPUT_FLAGS denied by effect old=%#x new=%#x", + this, (int)old, (int)*flags); } } ALOGV_IF((*flags & AUDIO_INPUT_FLAG_FAST) != 0, - "AUDIO_INPUT_FLAG_FAST accepted: frameCount=%zu mFrameCount=%zu", - frameCount, mFrameCount); + "%p AUDIO_INPUT_FLAG_FAST accepted: frameCount=%zu mFrameCount=%zu", + this, frameCount, mFrameCount); } else { - ALOGV("AUDIO_INPUT_FLAG_FAST denied: frameCount=%zu mFrameCount=%zu mPipeFramesP2=%zu " - "format=%#x isLinear=%d channelMask=%#x sampleRate=%u mSampleRate=%u " + ALOGV("%p AUDIO_INPUT_FLAG_FAST denied: frameCount=%zu mFrameCount=%zu mPipeFramesP2=%zu " + "format=%#x isLinear=%d mFormat=%#x channelMask=%#x sampleRate=%u mSampleRate=%u " "hasFastCapture=%d tid=%d mFastTrackAvail=%d", - frameCount, mFrameCount, mPipeFramesP2, - format, audio_is_linear_pcm(format), channelMask, sampleRate, mSampleRate, + this, frameCount, mFrameCount, mPipeFramesP2, + format, audio_is_linear_pcm(format), mFormat, channelMask, sampleRate, mSampleRate, hasFastCapture(), tid, mFastTrackAvail); *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_FAST); } @@ -6704,17 +6707,11 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRe } mTracks.add(track); - // disable AEC and NS if the device is a BT SCO headset supporting those pre processings - bool suspend = audio_is_bluetooth_sco_device(mInDevice) && - mAudioFlinger->btNrecIsOff(); - setEffectSuspended_l(FX_IID_AEC, suspend, sessionId); - setEffectSuspended_l(FX_IID_NS, suspend, sessionId); - if ((*flags & AUDIO_INPUT_FLAG_FAST) && (tid != -1)) { pid_t callingPid = IPCThreadState::self()->getCallingPid(); // we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful, // so ask activity manager to do this on our behalf - sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true); + sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true /*forApp*/); } } @@ -7072,6 +7069,26 @@ void AudioFlinger::RecordThread::ResamplerBufferProvider::releaseBuffer( buffer->frameCount = 0; } +void AudioFlinger::RecordThread::checkBtNrec() +{ + Mutex::Autolock _l(mLock); + checkBtNrec_l(); +} + +void AudioFlinger::RecordThread::checkBtNrec_l() +{ + // disable AEC and NS if the device is a BT SCO headset supporting those + // pre processings + bool suspend = audio_is_bluetooth_sco_device(mInDevice) && + mAudioFlinger->btNrecIsOff(); + if (mBtNrecSuspended.exchange(suspend) != suspend) { + for (size_t i = 0; i < mEffectChains.size(); i++) { + setEffectSuspended_l(FX_IID_AEC, suspend, mEffectChains[i]->sessionId()); + setEffectSuspended_l(FX_IID_NS, suspend, mEffectChains[i]->sessionId()); + } + } +} + bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValuePair, status_t& status) @@ -7144,17 +7161,7 @@ bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValueP if (value != AUDIO_DEVICE_NONE) { mPrevInDevice = value; } - // disable AEC and NS if the device is a BT SCO headset supporting those - // pre processings - if (mTracks.size() > 0) { - bool suspend = audio_is_bluetooth_sco_device(mInDevice) && - mAudioFlinger->btNrecIsOff(); - for (size_t i = 0; i < mTracks.size(); i++) { - sp<RecordTrack> track = mTracks[i]; - setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId()); - setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId()); - } - } + checkBtNrec_l(); } } if (param.getInt(String8(AudioParameter::keyInputSource), value) == NO_ERROR && @@ -7244,6 +7251,10 @@ void AudioFlinger::RecordThread::readInputParameters_l() result = mInput->stream->getBufferSize(&mBufferSize); LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving buffer size from HAL: %d", result); mFrameCount = mBufferSize / mFrameSize; + ALOGV("%p RecordThread params: mChannelCount=%u, mFormat=%#x, mFrameSize=%lld, " + "mBufferSize=%lld, mFrameCount=%lld", + this, mChannelCount, mFormat, (long long)mFrameSize, (long long)mBufferSize, + (long long)mFrameCount); // This is the formula for calculating the temporary buffer size. // With 7 HAL buffers, we can guarantee ability to down-sample the input by ratio of 6:1 to // 1 full output buffer, regardless of the alignment of the available input. @@ -7383,17 +7394,7 @@ status_t AudioFlinger::RecordThread::createAudioPatch_l(const struct audio_patch mEffectChains[i]->setDevice_l(mInDevice); } - // disable AEC and NS if the device is a BT SCO headset supporting those - // pre processings - if (mTracks.size() > 0) { - bool suspend = audio_is_bluetooth_sco_device(mInDevice) && - mAudioFlinger->btNrecIsOff(); - for (size_t i = 0; i < mTracks.size(); i++) { - sp<RecordTrack> track = mTracks[i]; - setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId()); - setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId()); - } - } + checkBtNrec_l(); // store new source and send to effects if (mAudioSource != patch->sinks[0].ext.mix.usecase.source) { @@ -7512,7 +7513,7 @@ status_t AudioFlinger::MmapThreadHandle::getMmapPosition(struct audio_mmap_posit return mThread->getMmapPosition(position); } -status_t AudioFlinger::MmapThreadHandle::start(const MmapStreamInterface::Client& client, +status_t AudioFlinger::MmapThreadHandle::start(const AudioClient& client, audio_port_handle_t *handle) { @@ -7605,75 +7606,75 @@ status_t AudioFlinger::MmapThread::getMmapPosition(struct audio_mmap_position *p return mHalStream->getMmapPosition(position); } -status_t AudioFlinger::MmapThread::start(const MmapStreamInterface::Client& client, +status_t AudioFlinger::MmapThread::start(const AudioClient& client, audio_port_handle_t *handle) { - ALOGV("%s clientUid %d mStandby %d", __FUNCTION__, client.clientUid, mStandby); + ALOGV("%s clientUid %d mStandby %d mPortId %d *handle %d", __FUNCTION__, + client.clientUid, mStandby, mPortId, *handle); if (mHalStream == 0) { return NO_INIT; } status_t ret; - audio_session_t sessionId; - audio_port_handle_t portId; - if (mActiveTracks.size() == 0) { + if (*handle == mPortId) { // for the first track, reuse portId and session allocated when the stream was opened ret = mHalStream->start(); if (ret != NO_ERROR) { ALOGE("%s: error mHalStream->start() = %d for first track", __FUNCTION__, ret); return ret; } - portId = mPortId; - sessionId = mSessionId; mStandby = false; + return NO_ERROR; + } + + audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE; + + audio_io_handle_t io = mId; + if (isOutput()) { + audio_config_t config = AUDIO_CONFIG_INITIALIZER; + config.sample_rate = mSampleRate; + config.channel_mask = mChannelMask; + config.format = mFormat; + audio_stream_type_t stream = streamType(); + audio_output_flags_t flags = + (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT); + audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE; + ret = AudioSystem::getOutputForAttr(&mAttr, &io, + mSessionId, + &stream, + client.clientUid, + &config, + flags, + &deviceId, + &portId); } else { - // for other tracks than first one, get a new port ID from APM. - sessionId = (audio_session_t)mAudioFlinger->newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION); - audio_io_handle_t io; - if (isOutput()) { - audio_config_t config = AUDIO_CONFIG_INITIALIZER; - config.sample_rate = mSampleRate; - config.channel_mask = mChannelMask; - config.format = mFormat; - audio_stream_type_t stream = streamType(); - audio_output_flags_t flags = - (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT); - ret = AudioSystem::getOutputForAttr(&mAttr, &io, - sessionId, - &stream, - client.clientUid, - &config, - flags, - AUDIO_PORT_HANDLE_NONE, - &portId); - } else { - audio_config_base_t config; - config.sample_rate = mSampleRate; - config.channel_mask = mChannelMask; - config.format = mFormat; - ret = AudioSystem::getInputForAttr(&mAttr, &io, - sessionId, - client.clientPid, - client.clientUid, - &config, - AUDIO_INPUT_FLAG_MMAP_NOIRQ, - AUDIO_PORT_HANDLE_NONE, - &portId); - } - // APM should not chose a different input or output stream for the same set of attributes - // and audo configuration - if (ret != NO_ERROR || io != mId) { - ALOGE("%s: error getting output or input from APM (error %d, io %d expected io %d)", - __FUNCTION__, ret, io, mId); - return BAD_VALUE; - } + audio_config_base_t config; + config.sample_rate = mSampleRate; + config.channel_mask = mChannelMask; + config.format = mFormat; + audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE; + ret = AudioSystem::getInputForAttr(&mAttr, &io, + mSessionId, + client.clientPid, + client.clientUid, + &config, + AUDIO_INPUT_FLAG_MMAP_NOIRQ, + &deviceId, + &portId); + } + // APM should not chose a different input or output stream for the same set of attributes + // and audo configuration + if (ret != NO_ERROR || io != mId) { + ALOGE("%s: error getting output or input from APM (error %d, io %d expected io %d)", + __FUNCTION__, ret, io, mId); + return BAD_VALUE; } if (isOutput()) { - ret = AudioSystem::startOutput(mId, streamType(), sessionId); + ret = AudioSystem::startOutput(mId, streamType(), mSessionId); } else { - ret = AudioSystem::startInput(mId, sessionId); + ret = AudioSystem::startInput(mId, mSessionId); } // abort if start is rejected by audio policy manager @@ -7681,9 +7682,9 @@ status_t AudioFlinger::MmapThread::start(const MmapStreamInterface::Client& clie ALOGE("%s: error start rejected by AudioPolicyManager = %d", __FUNCTION__, ret); if (mActiveTracks.size() != 0) { if (isOutput()) { - AudioSystem::releaseOutput(mId, streamType(), sessionId); + AudioSystem::releaseOutput(mId, streamType(), mSessionId); } else { - AudioSystem::releaseInput(mId, sessionId); + AudioSystem::releaseInput(mId, mSessionId); } } else { mHalStream->stop(); @@ -7691,11 +7692,11 @@ status_t AudioFlinger::MmapThread::start(const MmapStreamInterface::Client& clie return PERMISSION_DENIED; } - sp<MmapTrack> track = new MmapTrack(this, mSampleRate, mFormat, mChannelMask, sessionId, + sp<MmapTrack> track = new MmapTrack(this, mSampleRate, mFormat, mChannelMask, mSessionId, client.clientUid, portId); mActiveTracks.add(track); - sp<EffectChain> chain = getEffectChain_l(sessionId); + sp<EffectChain> chain = getEffectChain_l(mSessionId); if (chain != 0) { chain->setStrategy(AudioSystem::getStrategyForStream(streamType())); chain->incTrackCnt(); @@ -7703,10 +7704,9 @@ status_t AudioFlinger::MmapThread::start(const MmapStreamInterface::Client& clie } *handle = portId; - broadcast_l(); - ALOGV("%s DONE handle %d stream %p", __FUNCTION__, portId, mHalStream.get()); + ALOGV("%s DONE handle %d stream %p", __FUNCTION__, *handle, mHalStream.get()); return NO_ERROR; } @@ -7719,6 +7719,11 @@ status_t AudioFlinger::MmapThread::stop(audio_port_handle_t handle) return NO_INIT; } + if (handle == mPortId) { + mHalStream->stop(); + return NO_ERROR; + } + sp<MmapTrack> track; for (const sp<MmapTrack> &t : mActiveTracks) { if (handle == t->portId()) { @@ -7734,14 +7739,10 @@ status_t AudioFlinger::MmapThread::stop(audio_port_handle_t handle) if (isOutput()) { AudioSystem::stopOutput(mId, streamType(), track->sessionId()); - if (mActiveTracks.size() != 0) { - AudioSystem::releaseOutput(mId, streamType(), track->sessionId()); - } + AudioSystem::releaseOutput(mId, streamType(), track->sessionId()); } else { AudioSystem::stopInput(mId, track->sessionId()); - if (mActiveTracks.size() != 0) { - AudioSystem::releaseInput(mId, track->sessionId()); - } + AudioSystem::releaseInput(mId, track->sessionId()); } sp<EffectChain> chain = getEffectChain_l(track->sessionId()); @@ -7752,9 +7753,6 @@ status_t AudioFlinger::MmapThread::stop(audio_port_handle_t handle) broadcast_l(); - if (mActiveTracks.size() == 0) { - mHalStream->stop(); - } return NO_ERROR; } @@ -7857,17 +7855,34 @@ bool AudioFlinger::MmapThread::checkForNewParameter_l(const String8& keyValuePai { AudioParameter param = AudioParameter(keyValuePair); int value; + bool sendToHal = true; if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) { + audio_devices_t device = (audio_devices_t)value; // forward device change to effects that have requested to be // aware of attached audio device. - if (value != AUDIO_DEVICE_NONE) { - mOutDevice = value; + if (device != AUDIO_DEVICE_NONE) { for (size_t i = 0; i < mEffectChains.size(); i++) { - mEffectChains[i]->setDevice_l(mOutDevice); + mEffectChains[i]->setDevice_l(device); } } + if (audio_is_output_devices(device)) { + mOutDevice = device; + if (!isOutput()) { + sendToHal = false; + } + } else { + mInDevice = device; + if (device != AUDIO_DEVICE_NONE) { + mPrevInDevice = value; + } + // TODO: implement and call checkBtNrec_l(); + } + } + if (sendToHal) { + status = mHalStream->setParameters(keyValuePair); + } else { + status = NO_ERROR; } - status = mHalStream->setParameters(keyValuePair); return false; } diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 80b368e1ca..062bad6217 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -229,8 +229,7 @@ public: virtual void binderDied(const wp<IBinder>& who); private: - PMDeathRecipient(const PMDeathRecipient&); - PMDeathRecipient& operator = (const PMDeathRecipient&); + DISALLOW_COPY_AND_ASSIGN(PMDeathRecipient); wp<ThreadBase> mThread; }; @@ -362,11 +361,6 @@ public: virtual uint32_t getStrategyForSession_l(audio_session_t sessionId __unused) { return 0; } - // suspend or restore effect according to the type of effect passed. a NULL - // type pointer means suspend all effects in the session - void setEffectSuspended(const effect_uuid_t *type, - bool suspend, - audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX); // check if some effects must be suspended/restored when an effect is enabled // or disabled void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect, @@ -418,10 +412,13 @@ protected: void releaseWakeLock_l(); void updateWakeLockUids_l(const SortedVector<uid_t> &uids); void getPowerManager_l(); + // suspend or restore effects of the specified type (or all if type is NULL) + // on a given session. The number of suspend requests is counted and restore + // occurs when all suspend requests are cancelled. void setEffectSuspended_l(const effect_uuid_t *type, bool suspend, audio_session_t sessionId); - // updated mSuspendedSessions when an effect suspended or restored + // updated mSuspendedSessions when an effect is suspended or restored void updateSuspendedSessions_l(const effect_uuid_t *type, bool suspend, audio_session_t sessionId); @@ -485,6 +482,7 @@ protected: const sp<PMDeathRecipient> mDeathRecipient; // list of suspended effects per session and per type. The first (outer) vector is // keyed by session ID, the second (inner) by type UUID timeLow field + // Updated by updateSuspendedSessions_l() only. KeyedVector< audio_session_t, KeyedVector< int, sp<SuspendedSessionDesc> > > mSuspendedSessions; static const size_t kLogSize = 4 * 1024; @@ -901,7 +899,7 @@ private: friend class AudioFlinger; // for numerous - PlaybackThread& operator = (const PlaybackThread&); + DISALLOW_COPY_AND_ASSIGN(PlaybackThread); status_t addTrack_l(const sp<Track>& track); bool destroyTrack_l(const sp<Track>& track); @@ -982,7 +980,7 @@ private: sp<NBAIO_Source> mTeeSource; #endif uint32_t mScreenState; // cached copy of gScreenState - static const size_t kFastMixerLogSize = 4 * 1024; + static const size_t kFastMixerLogSize = 8 * 1024; sp<NBLog::Writer> mFastMixerNBLogWriter; @@ -1388,6 +1386,8 @@ public: } virtual bool isOutput() const override { return false; } + void checkBtNrec(); + private: // Enter standby if not already in standby, and set mStandby flag void standbyIfNotAlreadyInStandby(); @@ -1395,6 +1395,8 @@ private: // Call the HAL standby method unconditionally, and don't change mStandby flag void inputStandBy(); + void checkBtNrec_l(); + AudioStreamIn *mInput; SortedVector < sp<RecordTrack> > mTracks; // mActiveTracks has dual roles: it indicates the current active track(s), and @@ -1454,6 +1456,8 @@ private: sp<NBLog::Writer> mFastCaptureNBLogWriter; bool mFastTrackAvail; // true if fast track available + // common state to all record threads + std::atomic_bool mBtNrecSuspended; }; class MmapThread : public ThreadBase @@ -1479,7 +1483,7 @@ class MmapThread : public ThreadBase status_t createMmapBuffer(int32_t minSizeFrames, struct audio_mmap_buffer_info *info); status_t getMmapPosition(struct audio_mmap_position *position); - status_t start(const MmapStreamInterface::Client& client, audio_port_handle_t *handle); + status_t start(const AudioClient& client, audio_port_handle_t *handle); status_t stop(audio_port_handle_t handle); status_t standby(); diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h index e0c09f7423..cb540ca0a0 100644 --- a/services/audioflinger/TrackBase.h +++ b/services/audioflinger/TrackBase.h @@ -92,8 +92,7 @@ public: protected: - TrackBase(const TrackBase&); - TrackBase& operator = (const TrackBase&); + DISALLOW_COPY_AND_ASSIGN(TrackBase); // AudioBufferProvider interface virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0; diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 301510cf80..9763bf2cb9 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -234,7 +234,7 @@ status_t AudioFlinger::ThreadBase::TrackBase::initCheck() const AudioFlinger::ThreadBase::TrackBase::~TrackBase() { #ifdef TEE_SINK - dumpTee(-1, mTeeSource, mId); + dumpTee(-1, mTeeSource, mId, 'T'); #endif // delete the proxy before deleting the shared memory it refers to, to avoid dangling reference mServerProxy.clear(); diff --git a/services/audioflinger/TypedLogger.cpp b/services/audioflinger/TypedLogger.cpp index e08f6f67f3..57c206bcbe 100644 --- a/services/audioflinger/TypedLogger.cpp +++ b/services/audioflinger/TypedLogger.cpp @@ -23,5 +23,5 @@ #include "TypedLogger.h" namespace android { -thread_local NBLog::Writer *logWriterTLS; +thread_local NBLog::Writer *tlNBLogWriter; } diff --git a/services/audioflinger/TypedLogger.h b/services/audioflinger/TypedLogger.h index 0b23c7c9dc..2d8402815c 100644 --- a/services/audioflinger/TypedLogger.h +++ b/services/audioflinger/TypedLogger.h @@ -19,11 +19,84 @@ #define ANDROID_TYPED_LOGGER_H #include <media/nbaio/NBLog.h> -#define LOGT(fmt, ...) logWriterTLS->logFormat(fmt, ##__VA_ARGS__) // TODO: check null pointer +#include <algorithm> + +/* +Fowler-Noll-Vo (FNV-1a) hash function for the file name. +Hashes at compile time. FNV-1a iterative function: + +hash = offset_basis +for each byte to be hashed + hash = hash xor byte + hash = hash * FNV_prime +return hash + +offset_basis and FNV_prime values depend on the size of the hash output +Following values are defined by FNV and should not be changed arbitrarily +*/ + +template<typename T> +constexpr T offset_basis(); + +template<typename T> +constexpr T FNV_prime(); + +template<> +constexpr uint32_t offset_basis<uint32_t>() { + return 2166136261u; +} + +template<> +constexpr uint32_t FNV_prime<uint32_t>() { + return 16777619u; +} + +template<> +constexpr uint64_t offset_basis<uint64_t>() { + return 14695981039346656037ull; +} + +template<> +constexpr uint64_t FNV_prime<uint64_t>() { + return 1099511628211ull; +} + +template <typename T, size_t n> +constexpr T fnv1a(const char (&file)[n], int i = n - 1) { + return i == -1 ? offset_basis<T>() : (fnv1a<T>(file, i - 1) ^ file[i]) * FNV_prime<T>(); +} + +template <size_t n> +constexpr uint64_t hash(const char (&file)[n], uint32_t line) { + // Line numbers over or equal to 2^16 are clamped to 2^16 - 1. This way increases collisions + // compared to wrapping around, but is easy to identify because it doesn't produce aliasing. + // It's a very unlikely case anyways. + return ((fnv1a<uint64_t>(file) << 16) ^ ((fnv1a<uint64_t>(file) >> 32) & 0xFFFF0000)) | + std::min(line, 0xFFFFu); +} + +// TODO Permit disabling of logging at compile-time. + +// TODO A non-nullptr dummy implementation that is a nop would be faster than checking for nullptr +// in the case when logging is enabled at compile-time and enabled at runtime, but it might be +// slower than nullptr check when logging is enabled at compile-time and disabled at runtime. + +// Write formatted entry to log +#define LOGT(fmt, ...) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \ + x->logFormat((fmt), hash(__FILE__, __LINE__), ##__VA_ARGS__); } \ + while (0) + +// Write histogram timestamp entry +#define LOG_HIST_TS() do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \ + x->logHistTS(hash(__FILE__, __LINE__)); } while(0) + +// flush all histogram +#define LOG_HIST_FLUSH() do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \ + x->logHistFlush(hash(__FILE__, __LINE__)); } while(0) namespace android { extern "C" { -extern thread_local NBLog::Writer *logWriterTLS; +extern thread_local NBLog::Writer *tlNBLogWriter; } } // namespace android diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk index 7cd2b81467..ad340e5bee 100644 --- a/services/audiopolicy/Android.mk +++ b/services/audiopolicy/Android.mk @@ -9,11 +9,11 @@ LOCAL_SRC_FILES:= \ service/AudioPolicyClientImpl.cpp LOCAL_C_INCLUDES := \ - $(TOPDIR)frameworks/av/services/audioflinger \ + frameworks/av/services/audioflinger \ $(call include-path-for, audio-utils) \ - $(TOPDIR)frameworks/av/services/audiopolicy/common/include \ - $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface \ - $(TOPDIR)frameworks/av/services/audiopolicy/utilities + frameworks/av/services/audiopolicy/common/include \ + frameworks/av/services/audiopolicy/engine/interface \ + frameworks/av/services/audiopolicy/utilities LOCAL_SHARED_LIBRARIES := \ libcutils \ @@ -58,7 +58,7 @@ LOCAL_REQUIRED_MODULES := \ parameter-framework.policy \ audio_policy_criteria.conf \ -LOCAL_C_INCLUDES += $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/include +LOCAL_C_INCLUDES += frameworks/av/services/audiopolicy/engineconfigurable/include LOCAL_SHARED_LIBRARIES += libaudiopolicyengineconfigurable @@ -69,9 +69,9 @@ LOCAL_SHARED_LIBRARIES += libaudiopolicyenginedefault endif # ifeq ($(USE_CONFIGURABLE_AUDIO_POLICY), 1) LOCAL_C_INCLUDES += \ - $(TOPDIR)frameworks/av/services/audiopolicy/common/include \ - $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface \ - $(TOPDIR)frameworks/av/services/audiopolicy/utilities + frameworks/av/services/audiopolicy/common/include \ + frameworks/av/services/audiopolicy/engine/interface \ + frameworks/av/services/audiopolicy/utilities LOCAL_STATIC_LIBRARIES := \ libaudiopolicycomponents @@ -106,8 +106,8 @@ LOCAL_STATIC_LIBRARIES := \ libaudiopolicycomponents LOCAL_C_INCLUDES += \ - $(TOPDIR)frameworks/av/services/audiopolicy/common/include \ - $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface + frameworks/av/services/audiopolicy/common/include \ + frameworks/av/services/audiopolicy/engine/interface LOCAL_CFLAGS := -Wall -Werror diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h index 60ed1d6941..c8682060c2 100644 --- a/services/audiopolicy/AudioPolicyInterface.h +++ b/services/audiopolicy/AudioPolicyInterface.h @@ -122,7 +122,7 @@ public: uid_t uid, const audio_config_t *config, audio_output_flags_t flags, - int selectedDeviceId, + audio_port_handle_t *selectedDeviceId, audio_port_handle_t *portId) = 0; // indicates to the audio policy manager that the output starts being used by corresponding stream. virtual status_t startOutput(audio_io_handle_t output, @@ -144,7 +144,7 @@ public: uid_t uid, const audio_config_base_t *config, audio_input_flags_t flags, - audio_port_handle_t selectedDeviceId, + audio_port_handle_t *selectedDeviceId, input_type_t *inputType, audio_port_handle_t *portId) = 0; // indicates to the audio policy manager that the input starts being used. @@ -241,6 +241,9 @@ public: virtual status_t setMasterMono(bool mono) = 0; virtual status_t getMasterMono(bool *mono) = 0; + + virtual float getStreamVolumeDB( + audio_stream_type_t stream, int index, audio_devices_t device) = 0; }; diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk index 7968103afa..e263c0c752 100644 --- a/services/audiopolicy/common/managerdefinitions/Android.mk +++ b/services/audiopolicy/common/managerdefinitions/Android.mk @@ -33,9 +33,9 @@ LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libmedia LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/include \ - $(TOPDIR)frameworks/av/services/audiopolicy/common/include \ - $(TOPDIR)frameworks/av/services/audiopolicy \ - $(TOPDIR)frameworks/av/services/audiopolicy/utilities \ + frameworks/av/services/audiopolicy/common/include \ + frameworks/av/services/audiopolicy \ + frameworks/av/services/audiopolicy/utilities \ ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1) @@ -44,8 +44,8 @@ LOCAL_SRC_FILES += src/Serializer.cpp LOCAL_SHARED_LIBRARIES += libicuuc libxml2 LOCAL_C_INCLUDES += \ - $(TOPDIR)external/libxml2/include \ - $(TOPDIR)external/icu/icu4c/source/common + external/libxml2/include \ + external/icu/icu4c/source/common else diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h index ded22859b7..4f79ed292a 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h @@ -71,7 +71,7 @@ public: virtual void toAudioPort(struct audio_port *port) const; - virtual void importAudioPort(const sp<AudioPort>& port); + virtual void importAudioPort(const sp<AudioPort>& port, bool force = false); void addAudioProfile(const sp<AudioProfile> &profile) { mProfiles.add(profile); } diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h index 56e282f364..202b417f26 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h @@ -52,6 +52,7 @@ public: audio_channel_mask_t channelMask() const { return mConfig.channel_mask; } audio_input_flags_t flags() const { return mFlags; } uid_t uid() const { return mUid; } + void setUid(uid_t uid) { mUid = uid; } bool matches(const sp<AudioSession> &other) const; bool isSoundTrigger() const { return mIsSoundTrigger; } uint32_t openCount() const { return mOpenCount; } ; @@ -69,7 +70,7 @@ private: const audio_source_t mInputSource; const struct audio_config_base mConfig; const audio_input_flags_t mFlags; - const uid_t mUid; + uid_t mUid; bool mIsSoundTrigger; uint32_t mOpenCount; uint32_t mActiveCount; diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h index 9a52d225f7..1a644d782c 100644 --- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h +++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h @@ -48,7 +48,7 @@ public: // AudioPort virtual void attach(const sp<HwModule>& module); virtual void toAudioPort(struct audio_port *port) const; - virtual void importAudioPort(const sp<AudioPort>& port); + virtual void importAudioPort(const sp<AudioPort>& port, bool force = false); audio_port_handle_t getId() const; status_t dump(int fd, int spaces, int index, bool verbose = true) const; diff --git a/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h index 9e705aa1da..fc95eb90e2 100644 --- a/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h +++ b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h @@ -49,4 +49,13 @@ typedef TypeConverter<MixTypeTraits> MixTypeConverter; typedef TypeConverter<RouteFlagTraits> RouteFlagTypeConverter; typedef TypeConverter<RuleTraits> RuleTypeConverter; +template <> +const DeviceCategoryConverter::Table DeviceCategoryConverter::mTable[]; +template <> +const MixTypeConverter::Table MixTypeConverter::mTable[]; +template <> +const RouteFlagTypeConverter::Table RouteFlagTypeConverter::mTable[]; +template <> +const RuleTypeConverter::Table RuleTypeConverter::mTable[]; + }; // namespace android diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp index 4be4ac7fab..cdaffe79fc 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp @@ -128,7 +128,7 @@ void AudioPort::toAudioPort(struct audio_port *port) const port->num_gains = i; } -void AudioPort::importAudioPort(const sp<AudioPort>& port) +void AudioPort::importAudioPort(const sp<AudioPort>& port, bool force __unused) { size_t indexToImport; for (indexToImport = 0; indexToImport < port->mProfiles.size(); indexToImport++) { diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp index f0e48b6255..a2c1165c5e 100644 --- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp @@ -263,7 +263,10 @@ void DeviceDescriptor::toAudioPort(struct audio_port *port) const strncpy(port->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN); } -void DeviceDescriptor::importAudioPort(const sp<AudioPort>& port) { +void DeviceDescriptor::importAudioPort(const sp<AudioPort>& port, bool force) { + if (!force && !port->hasDynamicAudioProfile()) { + return; + } AudioPort::importAudioPort(port); port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat); } diff --git a/services/audiopolicy/config/audio_policy_configuration_stub.xml b/services/audiopolicy/config/audio_policy_configuration_stub.xml index a7747f80d2..26c381f561 100644 --- a/services/audiopolicy/config/audio_policy_configuration_stub.xml +++ b/services/audiopolicy/config/audio_policy_configuration_stub.xml @@ -15,38 +15,9 @@ --> <audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude"> - <modules> - <module name="stub" halVersion="2.0"> - <attachedDevices> - <item>Default Out</item> - <item>Default In</item> - </attachedDevices> - <defaultOutputDevice>Default Out</defaultOutputDevice> - <mixPorts> - <mixPort name="stub output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY"> - <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" - samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> - </mixPort> - - <mixPort name="stub input" role="sink"> - <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" - samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/> - </mixPort> - </mixPorts> - <devicePorts> - <devicePort tagName="Default Out" type="AUDIO_DEVICE_OUT_STUB" role="sink"> - </devicePort> - - <devicePort tagName="Default In" type="AUDIO_DEVICE_IN_STUB" role="source"> - </devicePort> - </devicePorts> - <routes> - <route type="mix" sink="Default Out" sources="stub output"/> - - <route type="mix" sink="stub input" sources="Default In"/> - </routes> - - </module> + <modules> + <!-- Stub Audio HAL --> + <xi:include href="stub_audio_policy_configuration.xml"/> <!-- Remote Submix Audio HAL --> <xi:include href="r_submix_audio_policy_configuration.xml"/> diff --git a/services/audiopolicy/config/stub_audio_policy_configuration.xml b/services/audiopolicy/config/stub_audio_policy_configuration.xml new file mode 100644 index 0000000000..17005d22ca --- /dev/null +++ b/services/audiopolicy/config/stub_audio_policy_configuration.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2017 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. +--> + +<module name="stub" halVersion="2.0"> + <attachedDevices> + <item>Default Out</item> + <item>Default In</item> + </attachedDevices> + <defaultOutputDevice>Default Out</defaultOutputDevice> + <mixPorts> + <mixPort name="stub output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + + <mixPort name="stub input" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/> + </mixPort> + </mixPorts> + <devicePorts> + <devicePort tagName="Default Out" type="AUDIO_DEVICE_OUT_STUB" role="sink"> + </devicePort> + + <devicePort tagName="Default In" type="AUDIO_DEVICE_IN_STUB" role="source"> + </devicePort> + </devicePorts> + <routes> + <route type="mix" sink="Default Out" sources="stub output"/> + + <route type="mix" sink="stub input" sources="Default In"/> + </routes> +</module> diff --git a/services/audiopolicy/config/usb_audio_policy_configuration.xml b/services/audiopolicy/config/usb_audio_policy_configuration.xml index 1630a94238..a487ecb3a7 100644 --- a/services/audiopolicy/config/usb_audio_policy_configuration.xml +++ b/services/audiopolicy/config/usb_audio_policy_configuration.xml @@ -30,14 +30,18 @@ samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> </devicePort> <devicePort tagName="USB Device Out" type="AUDIO_DEVICE_OUT_USB_DEVICE" role="sink"/> + <devicePort tagName="USB Headset Out" type="AUDIO_DEVICE_OUT_USB_HEADSET" role="sink"/> <devicePort tagName="USB Device In" type="AUDIO_DEVICE_IN_USB_DEVICE" role="source"/> + <devicePort tagName="USB Headset In" type="AUDIO_DEVICE_IN_USB_HEADSET" role="source"/> </devicePorts> <routes> <route type="mix" sink="USB Host Out" sources="usb_accessory output"/> <route type="mix" sink="USB Device Out" sources="usb_device output"/> + <route type="mix" sink="USB Headset Out" + sources="usb_device output"/> <route type="mix" sink="usb_device input" - sources="USB Device In"/> + sources="USB Device In,USB Headset In"/> </routes> </module> diff --git a/services/audiopolicy/engineconfigurable/Android.mk b/services/audiopolicy/engineconfigurable/Android.mk index 5b43347511..c2105e936b 100644 --- a/services/audiopolicy/engineconfigurable/Android.mk +++ b/services/audiopolicy/engineconfigurable/Android.mk @@ -16,9 +16,9 @@ LOCAL_SRC_FILES := \ src/InputSource.cpp \ audio_policy_engine_includes_common := \ - $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/include \ - $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/interface \ - $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface + frameworks/av/services/audiopolicy/engineconfigurable/include \ + frameworks/av/services/audiopolicy/engineconfigurable/interface \ + frameworks/av/services/audiopolicy/engine/interface LOCAL_CFLAGS += \ -Wall \ @@ -33,7 +33,7 @@ LOCAL_C_INCLUDES := \ $(TARGET_OUT_HEADERS)/hw \ $(call include-path-for, frameworks-av) \ $(call include-path-for, audio-utils) \ - $(TOPDIR)frameworks/av/services/audiopolicy/common/include + frameworks/av/services/audiopolicy/common/include LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB) diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk index 0e44f2c03e..3559cf1eee 100644 --- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk +++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk @@ -21,9 +21,9 @@ LOCAL_CFLAGS += \ -fvisibility=hidden LOCAL_C_INCLUDES := \ - $(TOPDIR)frameworks/av/services/audiopolicy/common/include \ - $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/include \ - $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/interface \ + frameworks/av/services/audiopolicy/common/include \ + frameworks/av/services/audiopolicy/engineconfigurable/include \ + frameworks/av/services/audiopolicy/engineconfigurable/interface \ LOCAL_SHARED_LIBRARIES := \ libaudiopolicyengineconfigurable \ diff --git a/services/audiopolicy/engineconfigurable/wrapper/Android.mk b/services/audiopolicy/engineconfigurable/wrapper/Android.mk index 066ee0d1fd..36e0f429b7 100644 --- a/services/audiopolicy/engineconfigurable/wrapper/Android.mk +++ b/services/audiopolicy/engineconfigurable/wrapper/Android.mk @@ -8,9 +8,9 @@ include $(CLEAR_VARS) LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/include \ - $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/include \ - $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/interface \ - $(TOPDIR)frameworks/av/services/audiopolicy/utilities/convert \ + frameworks/av/services/audiopolicy/engineconfigurable/include \ + frameworks/av/services/audiopolicy/engineconfigurable/interface \ + frameworks/av/services/audiopolicy/utilities/convert \ LOCAL_SRC_FILES:= ParameterManagerWrapper.cpp diff --git a/services/audiopolicy/enginedefault/Android.mk b/services/audiopolicy/enginedefault/Android.mk index b37b379fc5..cbbe30633b 100644 --- a/services/audiopolicy/enginedefault/Android.mk +++ b/services/audiopolicy/enginedefault/Android.mk @@ -11,7 +11,7 @@ LOCAL_SRC_FILES := \ audio_policy_engine_includes_common := \ $(LOCAL_PATH)/include \ - $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface + frameworks/av/services/audiopolicy/engine/interface LOCAL_CFLAGS += \ -Wall \ @@ -27,7 +27,7 @@ LOCAL_C_INCLUDES := \ $(call include-path-for, frameworks-av) \ $(call include-path-for, audio-utils) \ $(call include-path-for, bionic) \ - $(TOPDIR)frameworks/av/services/audiopolicy/common/include + frameworks/av/services/audiopolicy/common/include LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB) diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp index 096ffd186e..9bdb98cfe3 100644 --- a/services/audiopolicy/enginedefault/src/Engine.cpp +++ b/services/audiopolicy/enginedefault/src/Engine.cpp @@ -277,8 +277,11 @@ audio_devices_t Engine::getDeviceForStrategyInt(routing_strategy strategy, device &= ~AUDIO_DEVICE_OUT_SPEAKER; } } else if (outputs.isStreamActive( - AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) { - // while media is playing (or has recently played), use the same device + AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) + || outputs.isStreamActive( + AUDIO_STREAM_ACCESSIBILITY, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) + { + // while media/a11y is playing (or has recently played), use the same device device = getDeviceForStrategyInt( STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs); } else { @@ -552,6 +555,15 @@ audio_devices_t Engine::getDeviceForStrategyInt(routing_strategy strategy, AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED)) { device &= ~AUDIO_DEVICE_OUT_SPEAKER; } + + // for STRATEGY_SONIFICATION: + // if SPEAKER was selected, and SPEAKER_SAFE is available, use SPEAKER_SAFE instead + if ((strategy == STRATEGY_SONIFICATION) && + (device & AUDIO_DEVICE_OUT_SPEAKER) && + (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) { + device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE; + device &= ~AUDIO_DEVICE_OUT_SPEAKER; + } } break; default: diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index 853a6bb8a7..b600940c5a 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -54,6 +54,11 @@ namespace android { //FIXME: workaround for truncated touch sounds // to be removed when the problem is handled by system UI #define TOUCH_SOUND_FIXED_DELAY_MS 100 + +// Largest difference in dB on earpiece in call between the voice volume and another +// media / notification / system volume. +constexpr float IN_CALL_EARPIECE_HEADROOM_DB = 3.f; + // ---------------------------------------------------------------------------- // AudioPolicyInterface implementation // ---------------------------------------------------------------------------- @@ -709,7 +714,8 @@ sp<IOProfile> AudioPolicyManager::getProfileForDirectOutput( // only retain flags that will drive the direct output profile selection // if explicitly requested static const uint32_t kRelevantFlags = - (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD); + (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | + AUDIO_OUTPUT_FLAG_VOIP_RX); flags = (audio_output_flags_t)((flags & kRelevantFlags) | AUDIO_OUTPUT_FLAG_DIRECT); @@ -768,7 +774,7 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr, uid_t uid, const audio_config_t *config, audio_output_flags_t flags, - audio_port_handle_t selectedDeviceId, + audio_port_handle_t *selectedDeviceId, audio_port_handle_t *portId) { audio_attributes_t attributes; @@ -812,16 +818,18 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr, ALOGV("getOutputForAttr() usage=%d, content=%d, tag=%s flags=%08x" " session %d selectedDeviceId %d", attributes.usage, attributes.content_type, attributes.tags, attributes.flags, - session, selectedDeviceId); + session, *selectedDeviceId); *stream = streamTypefromAttributesInt(&attributes); // Explicit routing? sp<DeviceDescriptor> deviceDesc; - for (size_t i = 0; i < mAvailableOutputDevices.size(); i++) { - if (mAvailableOutputDevices[i]->getId() == selectedDeviceId) { - deviceDesc = mAvailableOutputDevices[i]; - break; + if (*selectedDeviceId != AUDIO_PORT_HANDLE_NONE) { + for (size_t i = 0; i < mAvailableOutputDevices.size(); i++) { + if (mAvailableOutputDevices[i]->getId() == *selectedDeviceId) { + deviceDesc = mAvailableOutputDevices[i]; + break; + } } } mOutputRoutes.addRoute(session, *stream, SessionRoute::SOURCE_TYPE_NA, deviceDesc, uid); @@ -844,6 +852,12 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr, return INVALID_OPERATION; } + DeviceVector outputDevices = mAvailableOutputDevices.getDevicesFromType(device); + *selectedDeviceId = outputDevices.size() > 0 ? outputDevices.itemAt(0)->getId() + : AUDIO_PORT_HANDLE_NONE; + + ALOGV(" getOutputForAttr() returns output %d selectedDeviceId %d", *output, *selectedDeviceId); + return NO_ERROR; } @@ -923,6 +937,11 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice( } if (stream == AUDIO_STREAM_TTS) { flags = AUDIO_OUTPUT_FLAG_TTS; + } else if (stream == AUDIO_STREAM_VOICE_CALL && + audio_is_linear_pcm(format)) { + flags = (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_VOIP_RX | + AUDIO_OUTPUT_FLAG_DIRECT); + ALOGV("Set VoIP and Direct output flags for PCM format"); } sp<IOProfile> profile; @@ -1078,8 +1097,6 @@ non_direct_output: ALOGW_IF((output == 0), "getOutput() could not find output for stream %d, samplingRate %d," "format %d, channels %x, flags %x", stream, samplingRate, format, channelMask, flags); - ALOGV(" getOutputForDevice() returns output %d", output); - return output; } @@ -1474,7 +1491,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, uid_t uid, const audio_config_base_t *config, audio_input_flags_t flags, - audio_port_handle_t selectedDeviceId, + audio_port_handle_t *selectedDeviceId, input_type_t *inputType, audio_port_handle_t *portId) { @@ -1482,6 +1499,43 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, "session %d, flags %#x", attr->source, config->sample_rate, config->format, config->channel_mask, session, flags); + // special case for mmap capture: if an input IO handle is specified, we reuse this input if + // possible + if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) == AUDIO_INPUT_FLAG_MMAP_NOIRQ && + *input != AUDIO_IO_HANDLE_NONE) { + ssize_t index = mInputs.indexOfKey(*input); + if (index < 0) { + ALOGW("getInputForAttr() unknown MMAP input %d", *input); + return BAD_VALUE; + } + sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index); + sp<AudioSession> audioSession = inputDesc->getAudioSession(session); + if (audioSession == 0) { + ALOGW("getInputForAttr() unknown session %d on input %d", session, *input); + return BAD_VALUE; + } + // For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger. + // The second call is for the first active client and sets the UID. Any further call + // corresponds to a new client and is only permitted from the same UId. + if (audioSession->openCount() == 1) { + audioSession->setUid(uid); + } else if (audioSession->uid() != uid) { + ALOGW("getInputForAttr() bad uid %d for session %d uid %d", + uid, session, audioSession->uid()); + return INVALID_OPERATION; + } + audioSession->changeOpenCount(1); + *inputType = API_INPUT_LEGACY; + if (*portId == AUDIO_PORT_HANDLE_NONE) { + *portId = AudioPort::getNextUniqueId(); + } + DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(inputDesc->mDevice); + *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId() + : AUDIO_PORT_HANDLE_NONE; + ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session); + return NO_ERROR; + } + *input = AUDIO_IO_HANDLE_NONE; *inputType = API_INPUT_INVALID; @@ -1504,10 +1558,12 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, // Explicit routing? sp<DeviceDescriptor> deviceDesc; - for (size_t i = 0; i < mAvailableInputDevices.size(); i++) { - if (mAvailableInputDevices[i]->getId() == selectedDeviceId) { - deviceDesc = mAvailableInputDevices[i]; - break; + if (*selectedDeviceId != AUDIO_PORT_HANDLE_NONE) { + for (size_t i = 0; i < mAvailableInputDevices.size(); i++) { + if (mAvailableInputDevices[i]->getId() == *selectedDeviceId) { + deviceDesc = mAvailableInputDevices[i]; + break; + } } } mInputRoutes.addRoute(session, SessionRoute::STREAM_TYPE_NA, inputSource, deviceDesc, uid); @@ -1558,7 +1614,13 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, return INVALID_OPERATION; } - ALOGV("getInputForAttr() returns input type = %d", *inputType); + DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(device); + *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId() + : AUDIO_PORT_HANDLE_NONE; + + ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d", + *input, *inputType, *selectedDeviceId); + return NO_ERROR; } @@ -1588,6 +1650,9 @@ audio_io_handle_t AudioPolicyManager::getInputForDevice(audio_devices_t device, } else { halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION; } + } else if (inputSource == AUDIO_SOURCE_VOICE_COMMUNICATION && + audio_is_linear_pcm(format)) { + flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_VOIP_TX); } // find a compatible input profile (not necessarily identical in parameters) @@ -1790,6 +1855,40 @@ bool AudioPolicyManager::isConcurentCaptureAllowed(const sp<AudioInputDescriptor return true; } +// FIXME: remove when concurrent capture is ready. This is a hack to work around bug b/63083537. +bool AudioPolicyManager::soundTriggerSupportsConcurrentCapture() { + if (!mHasComputedSoundTriggerSupportsConcurrentCapture) { + bool soundTriggerSupportsConcurrentCapture = false; + unsigned int numModules = 0; + struct sound_trigger_module_descriptor* nModules = NULL; + + status_t status = SoundTrigger::listModules(nModules, &numModules); + if (status == NO_ERROR && numModules != 0) { + nModules = (struct sound_trigger_module_descriptor*) calloc( + numModules, sizeof(struct sound_trigger_module_descriptor)); + if (nModules == NULL) { + // We failed to malloc the buffer, so just say no for now, and hope that we have more + // ram the next time this function is called. + ALOGE("Failed to allocate buffer for module descriptors"); + return false; + } + + status = SoundTrigger::listModules(nModules, &numModules); + if (status == NO_ERROR) { + soundTriggerSupportsConcurrentCapture = true; + for (size_t i = 0; i < numModules; ++i) { + soundTriggerSupportsConcurrentCapture &= + nModules[i].properties.concurrent_capture; + } + } + free(nModules); + } + mSoundTriggerSupportsConcurrentCapture = soundTriggerSupportsConcurrentCapture; + mHasComputedSoundTriggerSupportsConcurrentCapture = true; + } + return mSoundTriggerSupportsConcurrentCapture; +} + status_t AudioPolicyManager::startInput(audio_io_handle_t input, audio_session_t session, @@ -1839,6 +1938,11 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input, continue; } + if ((audioSession->flags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0 && + activeDesc->getId() == inputDesc->getId()) { + continue; + } + audio_source_t activeSource = activeDesc->inputSource(true); if (audioSession->inputSource() == AUDIO_SOURCE_HOTWORD) { if (activeSource == AUDIO_SOURCE_HOTWORD) { @@ -1862,6 +1966,12 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input, } } + // We only need to check if the sound trigger session supports concurrent capture if the + // input is also a sound trigger input. Otherwise, we should preempt any hotword stream + // that's running. + const bool allowConcurrentWithSoundTrigger = + inputDesc->isSoundTrigger() ? soundTriggerSupportsConcurrentCapture() : false; + // if capture is allowed, preempt currently active HOTWORD captures for (size_t i = 0; i < activeInputs.size(); i++) { sp<AudioInputDescriptor> activeDesc = activeInputs[i]; @@ -1870,6 +1980,10 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input, continue; } + if (allowConcurrentWithSoundTrigger && activeDesc->isSoundTrigger()) { + continue; + } + audio_source_t activeSource = activeDesc->inputSource(true); if (activeSource == AUDIO_SOURCE_HOTWORD) { AudioSessionCollection activeSessions = @@ -2142,7 +2256,8 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, continue; } routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream); - audio_devices_t curStreamDevice = getDeviceForStrategy(curStrategy, false /*fromCache*/); + audio_devices_t curStreamDevice = Volume::getDeviceForVolume(getDeviceForStrategy( + curStrategy, false /*fromCache*/)); if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) && ((curStreamDevice & device) == 0)) { continue; @@ -2153,7 +2268,7 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, applyVolume = (curDevice & curStreamDevice) != 0; } else { applyVolume = !mVolumeCurves->hasVolumeIndexForDevice( - stream, Volume::getDeviceForVolume(curStreamDevice)); + stream, curStreamDevice); } if (applyVolume) { @@ -3367,6 +3482,12 @@ status_t AudioPolicyManager::getMasterMono(bool *mono) return NO_ERROR; } +float AudioPolicyManager::getStreamVolumeDB( + audio_stream_type_t stream, int index, audio_devices_t device) +{ + return computeVolume(stream, index, device); +} + status_t AudioPolicyManager::disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc) { ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle()); @@ -3461,7 +3582,8 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa mBeaconMuted(false), mTtsOutputAvailable(false), mMasterMono(false), - mMusicEffectOutput(AUDIO_IO_HANDLE_NONE) + mMusicEffectOutput(AUDIO_IO_HANDLE_NONE), + mHasComputedSoundTriggerSupportsConcurrentCapture(false) { mUidCached = getuid(); mpClientInterface = clientInterface; @@ -3649,7 +3771,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa sp<DeviceDescriptor> devDesc = mAvailableInputDevices[index]; if (!devDesc->isAttached()) { devDesc->attach(mHwModules[i]); - devDesc->importAudioPort(inProfile); + devDesc->importAudioPort(inProfile, true); } } } @@ -4012,8 +4134,8 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor>& d continue; } - ALOGV("opening output for device %08x with params %s profile %p", - device, address.string(), profile.get()); + ALOGV("opening output for device %08x with params %s profile %p name %s", + device, address.string(), profile.get(), profile->getName().string()); desc = new SwAudioOutputDescriptor(profile, mpClientInterface); desc->mDevice = device; audio_config_t config = AUDIO_CONFIG_INITIALIZER; @@ -4262,6 +4384,10 @@ status_t AudioPolicyManager::checkInputsForDevice(const sp<DeviceDescriptor>& de config.channel_mask = desc->mChannelMask; config.format = desc->mFormat; audio_io_handle_t input = AUDIO_IO_HANDLE_NONE; + + ALOGV("opening inputput for device %08x with params %s profile %p name %s", + desc->mDevice, address.string(), profile.get(), profile->getName().string()); + status_t status = mpClientInterface->openInput(profile->getModuleHandle(), &input, &config, @@ -5229,6 +5355,30 @@ float AudioPolicyManager::computeVolume(audio_stream_type_t stream, return ringVolumeDB - 4 > volumeDB ? ringVolumeDB - 4 : volumeDB; } + // in-call: always cap earpiece volume by voice volume + some low headroom + if ((stream != AUDIO_STREAM_VOICE_CALL) && (device & AUDIO_DEVICE_OUT_EARPIECE) && isInCall()) { + switch (stream) { + case AUDIO_STREAM_SYSTEM: + case AUDIO_STREAM_RING: + case AUDIO_STREAM_MUSIC: + case AUDIO_STREAM_ALARM: + case AUDIO_STREAM_NOTIFICATION: + case AUDIO_STREAM_ENFORCED_AUDIBLE: + case AUDIO_STREAM_DTMF: + case AUDIO_STREAM_ACCESSIBILITY: { + const float maxVoiceVolDb = computeVolume(AUDIO_STREAM_VOICE_CALL, index, device) + + IN_CALL_EARPIECE_HEADROOM_DB; + if (volumeDB > maxVoiceVolDb) { + ALOGV("computeVolume() stream %d at vol=%f overriden by stream %d at vol=%f", + stream, volumeDB, AUDIO_STREAM_VOICE_CALL, maxVoiceVolDb); + volumeDB = maxVoiceVolDb; + } + } break; + default: + break; + } + } + // if a headset is connected, apply the following rules to ring tones and notifications // to avoid sound level bursts in user's ears: // - always attenuate notifications volume by 6dB diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h index 0f31279ad9..ea8d5c884a 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.h +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h @@ -116,7 +116,7 @@ public: uid_t uid, const audio_config_t *config, audio_output_flags_t flags, - audio_port_handle_t selectedDeviceId, + audio_port_handle_t *selectedDeviceId, audio_port_handle_t *portId); virtual status_t startOutput(audio_io_handle_t output, audio_stream_type_t stream, @@ -133,7 +133,7 @@ public: uid_t uid, const audio_config_base_t *config, audio_input_flags_t flags, - audio_port_handle_t selectedDeviceId, + audio_port_handle_t *selectedDeviceId, input_type_t *inputType, audio_port_handle_t *portId); @@ -234,6 +234,8 @@ public: virtual status_t setMasterMono(bool mono); virtual status_t getMasterMono(bool *mono); + virtual float getStreamVolumeDB( + audio_stream_type_t stream, int index, audio_devices_t device); // return the strategy corresponding to a given stream type routing_strategy getStrategy(audio_stream_type_t stream) const; @@ -669,6 +671,10 @@ private: param.addInt(String8(AudioParameter::keyMonoOutput), (int)mMasterMono); mpClientInterface->setParameters(output, param.toString()); } + + bool soundTriggerSupportsConcurrentCapture(); + bool mSoundTriggerSupportsConcurrentCapture; + bool mHasComputedSoundTriggerSupportsConcurrentCapture; }; }; diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index 2f7b1fbbeb..f60030d755 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -167,7 +167,7 @@ status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr, uid_t uid, const audio_config_t *config, audio_output_flags_t flags, - audio_port_handle_t selectedDeviceId, + audio_port_handle_t *selectedDeviceId, audio_port_handle_t *portId) { if (mAudioPolicyManager == NULL) { @@ -277,7 +277,7 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr, uid_t uid, const audio_config_base_t *config, audio_input_flags_t flags, - audio_port_handle_t selectedDeviceId, + audio_port_handle_t *selectedDeviceId, audio_port_handle_t *portId) { if (mAudioPolicyManager == NULL) { @@ -771,4 +771,16 @@ status_t AudioPolicyService::getMasterMono(bool *mono) return mAudioPolicyManager->getMasterMono(mono); } + +float AudioPolicyService::getStreamVolumeDB( + audio_stream_type_t stream, int index, audio_devices_t device) +{ + if (mAudioPolicyManager == NULL) { + return NAN; + } + Mutex::Autolock _l(mLock); + return mAudioPolicyManager->getStreamVolumeDB(stream, index, device); +} + + }; // namespace android diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h index 9a083f42b4..35542f17d8 100644 --- a/services/audiopolicy/service/AudioPolicyService.h +++ b/services/audiopolicy/service/AudioPolicyService.h @@ -82,7 +82,7 @@ public: uid_t uid, const audio_config_t *config, audio_output_flags_t flags, - audio_port_handle_t selectedDeviceId, + audio_port_handle_t *selectedDeviceId, audio_port_handle_t *portId); virtual status_t startOutput(audio_io_handle_t output, audio_stream_type_t stream, @@ -100,7 +100,7 @@ public: uid_t uid, const audio_config_base_t *config, audio_input_flags_t flags, - audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE, + audio_port_handle_t *selectedDeviceId = NULL, audio_port_handle_t *portId = NULL); virtual status_t startInput(audio_io_handle_t input, audio_session_t session); @@ -202,6 +202,9 @@ public: virtual status_t setMasterMono(bool mono); virtual status_t getMasterMono(bool *mono); + virtual float getStreamVolumeDB( + audio_stream_type_t stream, int index, audio_devices_t device); + status_t doStopOutput(audio_io_handle_t output, audio_stream_type_t stream, audio_session_t session); diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index 502ac5d86e..f1cdea3ea2 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -77,8 +77,7 @@ LOCAL_SHARED_LIBRARIES:= \ android.hardware.camera.common@1.0 \ android.hardware.camera.provider@2.4 \ android.hardware.camera.device@1.0 \ - android.hardware.camera.device@3.2 \ - android.hidl.manager@1.0 + android.hardware.camera.device@3.2 LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libcamera_client libfmq @@ -91,6 +90,9 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := \ LOCAL_CFLAGS += -Wall -Wextra -Werror +# Workaround for invalid unused-lambda-capture warning http://b/38349491 +LOCAL_CLANG_CFLAGS += -Wno-error=unused-lambda-capture + LOCAL_MODULE:= libcameraservice include $(BUILD_SHARED_LIBRARY) diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index c2b71a2372..20bd5e4479 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -73,6 +73,7 @@ namespace android { using binder::Status; using hardware::ICamera; using hardware::ICameraClient; +using hardware::ICameraServiceProxy; using hardware::ICameraServiceListener; using hardware::camera::common::V1_0::CameraDeviceStatus; using hardware::camera::common::V1_0::TorchModeStatus; @@ -231,29 +232,33 @@ status_t CameraService::enumerateProviders() { for (auto& cameraId : mCameraProviderManager->getCameraDeviceIds()) { String8 id8 = String8(cameraId.c_str()); + bool cameraFound = false; { + Mutex::Autolock lock(mCameraStatesLock); auto iter = mCameraStates.find(id8); if (iter != mCameraStates.end()) { - continue; + cameraFound = true; } } - hardware::camera::common::V1_0::CameraResourceCost cost; - res = mCameraProviderManager->getResourceCost(cameraId, &cost); - if (res != OK) { - ALOGE("Failed to query device resource cost: %s (%d)", strerror(-res), res); - continue; - } - std::set<String8> conflicting; - for (size_t i = 0; i < cost.conflictingDevices.size(); i++) { - conflicting.emplace(String8(cost.conflictingDevices[i].c_str())); - } + if (!cameraFound) { + hardware::camera::common::V1_0::CameraResourceCost cost; + res = mCameraProviderManager->getResourceCost(cameraId, &cost); + if (res != OK) { + ALOGE("Failed to query device resource cost: %s (%d)", strerror(-res), res); + continue; + } + std::set<String8> conflicting; + for (size_t i = 0; i < cost.conflictingDevices.size(); i++) { + conflicting.emplace(String8(cost.conflictingDevices[i].c_str())); + } - { - Mutex::Autolock lock(mCameraStatesLock); - mCameraStates.emplace(id8, - std::make_shared<CameraState>(id8, cost.resourceCost, conflicting)); + { + Mutex::Autolock lock(mCameraStatesLock); + mCameraStates.emplace(id8, + std::make_shared<CameraState>(id8, cost.resourceCost, conflicting)); + } } onDeviceStatusChanged(id8, CameraDeviceStatus::PRESENT); @@ -2209,7 +2214,7 @@ status_t CameraService::BasicClient::startCameraOps() { // Transition device state to OPEN sCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_OPEN, - mCameraIdStr); + mCameraIdStr, mCameraFacing, mClientPackageName); return OK; } @@ -2233,7 +2238,7 @@ status_t CameraService::BasicClient::finishCameraOps() { // Transition device state to CLOSED sCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_CLOSED, - mCameraIdStr); + mCameraIdStr, mCameraFacing, mClientPackageName); } // Always stop watching, even if no camera op is active if (mOpsCallback != NULL) { @@ -2737,12 +2742,12 @@ void CameraService::CameraState::updateStatus(StatusInternal status, onStatusUpdatedLocked(cameraId, status); } -void CameraService::updateProxyDeviceState(ICameraServiceProxy::CameraState newState, - const String8& cameraId) { +void CameraService::updateProxyDeviceState(int newState, + const String8& cameraId, int facing, const String16& clientName) { sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy(); if (proxyBinder == nullptr) return; String16 id(cameraId); - proxyBinder->notifyCameraState(id, newState); + proxyBinder->notifyCameraState(id, newState, facing, clientName); } status_t CameraService::getTorchStatusLocked( diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 87603a304f..6d5dde89de 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -19,6 +19,7 @@ #include <android/hardware/BnCameraService.h> #include <android/hardware/ICameraServiceListener.h> +#include <android/hardware/ICameraServiceProxy.h> #include <cutils/multiuser.h> #include <utils/Vector.h> @@ -26,7 +27,6 @@ #include <binder/AppOpsManager.h> #include <binder/BinderService.h> #include <binder/IAppOpsCallback.h> -#include <camera/ICameraServiceProxy.h> #include <hardware/camera.h> #include <android/hardware/camera/common/1.0/types.h> @@ -182,8 +182,10 @@ public: * the camera proxy service in the system service */ static void updateProxyDeviceState( - ICameraServiceProxy::CameraState newState, - const String8& cameraId); + int newState, + const String8& cameraId, + int facing, + const String16& clientName); ///////////////////////////////////////////////////////////////////// // CameraDeviceFactory functionality @@ -772,7 +774,7 @@ private: static StatusInternal mapToInternal(hardware::camera::common::V1_0::CameraDeviceStatus status); static int32_t mapToInterface(StatusInternal status); - static sp<ICameraServiceProxy> getCameraServiceProxy(); + static sp<hardware::ICameraServiceProxy> getCameraServiceProxy(); static void pingCameraServiceProxy(); }; diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp index 075c2e3166..a407d0bb59 100644 --- a/services/camera/libcameraservice/api1/CameraClient.cpp +++ b/services/camera/libcameraservice/api1/CameraClient.cpp @@ -256,8 +256,8 @@ binder::Status CameraClient::disconnect() { disableMsgType(CAMERA_MSG_ALL_MSGS); mHardware->stopPreview(); sCameraService->updateProxyDeviceState( - ICameraServiceProxy::CAMERA_STATE_IDLE, - String8::format("%d", mCameraId)); + hardware::ICameraServiceProxy::CAMERA_STATE_IDLE, + mCameraIdStr, mCameraFacing, mClientPackageName); mHardware->cancelPicture(); // Release the hardware resources. mHardware->release(); @@ -418,8 +418,8 @@ status_t CameraClient::startPreviewMode() { result = mHardware->startPreview(); if (result == NO_ERROR) { sCameraService->updateProxyDeviceState( - ICameraServiceProxy::CAMERA_STATE_ACTIVE, - String8::format("%d", mCameraId)); + hardware::ICameraServiceProxy::CAMERA_STATE_ACTIVE, + mCameraIdStr, mCameraFacing, mClientPackageName); } return result; } @@ -461,8 +461,8 @@ void CameraClient::stopPreview() { disableMsgType(CAMERA_MSG_PREVIEW_FRAME); mHardware->stopPreview(); sCameraService->updateProxyDeviceState( - ICameraServiceProxy::CAMERA_STATE_IDLE, - String8::format("%d", mCameraId)); + hardware::ICameraServiceProxy::CAMERA_STATE_IDLE, + mCameraIdStr, mCameraFacing, mClientPackageName); mPreviewBuffer.clear(); } @@ -960,8 +960,8 @@ void CameraClient::handleShutter(void) { // Shutters only happen in response to takePicture, so mark device as // idle now, until preview is restarted sCameraService->updateProxyDeviceState( - ICameraServiceProxy::CAMERA_STATE_IDLE, - String8::format("%d", mCameraId)); + hardware::ICameraServiceProxy::CAMERA_STATE_IDLE, + mCameraIdStr, mCameraFacing, mClientPackageName); mLock.unlock(); } diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h index 2bf73a0123..e8fc080c40 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.h +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h @@ -85,7 +85,7 @@ public: virtual binder::Status endConfigure(int operatingMode) override; - // Returns -EBUSY if device is not idle + // Returns -EBUSY if device is not idle or in error state virtual binder::Status deleteStream(int streamId) override; virtual binder::Status createStream( diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp index 32ee2734d4..51ef1609a7 100644 --- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp +++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp @@ -248,7 +248,8 @@ template <typename TClientBase> void Camera2ClientBase<TClientBase>::notifyIdle() { if (mDeviceActive) { getCameraService()->updateProxyDeviceState( - ICameraServiceProxy::CAMERA_STATE_IDLE, TClientBase::mCameraIdStr); + hardware::ICameraServiceProxy::CAMERA_STATE_IDLE, TClientBase::mCameraIdStr, + TClientBase::mCameraFacing, TClientBase::mClientPackageName); } mDeviceActive = false; @@ -263,7 +264,8 @@ void Camera2ClientBase<TClientBase>::notifyShutter(const CaptureResultExtras& re if (!mDeviceActive) { getCameraService()->updateProxyDeviceState( - ICameraServiceProxy::CAMERA_STATE_ACTIVE, TClientBase::mCameraIdStr); + hardware::ICameraServiceProxy::CAMERA_STATE_ACTIVE, TClientBase::mCameraIdStr, + TClientBase::mCameraFacing, TClientBase::mClientPackageName); } mDeviceActive = true; diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index e8b9b205b4..69b1d7d571 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -138,13 +138,15 @@ status_t Camera3Device::initialize(sp<CameraProviderManager> manager) { requestQueueRet.description().c_str()); return DEAD_OBJECT; } + + std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue; auto resultQueueRet = session->getCaptureResultMetadataQueue( - [&queue = mResultMetadataQueue](const auto& descriptor) { - queue = std::make_unique<ResultMetadataQueue>(descriptor); - if (!queue->isValid() || queue->availableToWrite() <= 0) { + [&resQueue](const auto& descriptor) { + resQueue = std::make_unique<ResultMetadataQueue>(descriptor); + if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) { ALOGE("HAL returns empty result metadata fmq, not use it"); - queue = nullptr; - // Don't use the queue onwards. + resQueue = nullptr; + // Don't use the resQueue onwards. } }); if (!resultQueueRet.isOk()) { @@ -153,7 +155,7 @@ status_t Camera3Device::initialize(sp<CameraProviderManager> manager) { return DEAD_OBJECT; } - mInterface = std::make_unique<HalInterface>(session, queue); + mInterface = new HalInterface(session, queue); std::string providerType; mVendorTagId = manager->getProviderTagIdLocked(mId.string()); @@ -182,7 +184,7 @@ status_t Camera3Device::initializeCommonLocked() { mTagMonitor.initialize(mVendorTagId); /** Start up request queue thread */ - mRequestThread = new RequestThread(this, mStatusTracker, mInterface.get()); + mRequestThread = new RequestThread(this, mStatusTracker, mInterface); res = mRequestThread->run(String8::format("C3Dev-%s-ReqQueue", mId.string()).string()); if (res != OK) { SET_ERR_L("Unable to start request queue thread: %s (%d)", @@ -237,7 +239,8 @@ status_t Camera3Device::disconnect() { ALOGI("%s: E", __FUNCTION__); status_t res = OK; - + std::vector<wp<Camera3StreamInterface>> streams; + nsecs_t maxExpectedDuration = getExpectedInFlightDuration(); { Mutex::Autolock l(mLock); if (mStatus == STATUS_UNINITIALIZED) return res; @@ -249,9 +252,10 @@ status_t Camera3Device::disconnect() { SET_ERR_L("Can't stop streaming"); // Continue to close device even in case of error } else { - res = waitUntilStateThenRelock(/*active*/ false, kShutdownTimeout); + res = waitUntilStateThenRelock(/*active*/ false, maxExpectedDuration); if (res != OK) { - SET_ERR_L("Timeout waiting for HAL to drain"); + SET_ERR_L("Timeout waiting for HAL to drain (% " PRIi64 " ns)", + maxExpectedDuration); // Continue to close device even in case of error } } @@ -269,8 +273,13 @@ status_t Camera3Device::disconnect() { mRequestThread->requestExit(); } - mOutputStreams.clear(); - mInputStream.clear(); + streams.reserve(mOutputStreams.size() + (mInputStream != nullptr ? 1 : 0)); + for (size_t i = 0; i < mOutputStreams.size(); i++) { + streams.push_back(mOutputStreams[i]); + } + if (mInputStream != nullptr) { + streams.push_back(mInputStream); + } } // Joining done without holding mLock, otherwise deadlocks may ensue @@ -289,11 +298,8 @@ status_t Camera3Device::disconnect() { HalInterface* interface; { Mutex::Autolock l(mLock); - mRequestThread.clear(); mStatusTracker.clear(); - mBufferManager.clear(); - interface = mInterface.get(); } @@ -301,12 +307,26 @@ status_t Camera3Device::disconnect() { // wait on assorted callbacks,etc, to complete before it can return. interface->close(); + flushInflightRequests(); + { Mutex::Autolock l(mLock); mInterface->clear(); + mOutputStreams.clear(); + mInputStream.clear(); + mDeletedStreams.clear(); + mBufferManager.clear(); internalUpdateStatusLocked(STATUS_UNINITIALIZED); } + for (auto& weakStream : streams) { + sp<Camera3StreamInterface> stream = weakStream.promote(); + if (stream != nullptr) { + ALOGE("%s: Stream %d leaked! strong reference (%d)!", + __FUNCTION__, stream->getId(), stream->getStrongCount() - 1); + } + } + ALOGI("%s: X", __FUNCTION__); return res; } @@ -834,6 +854,15 @@ status_t Camera3Device::submitRequestsHelper( hardware::Return<void> Camera3Device::processCaptureResult( const hardware::hidl_vec< hardware::camera::device::V3_2::CaptureResult>& results) { + // Ideally we should grab mLock, but that can lead to deadlock, and + // it's not super important to get up to date value of mStatus for this + // warning print, hence skipping the lock here + if (mStatus == STATUS_ERROR) { + // Per API contract, HAL should act as closed after device error + // But mStatus can be set to error by framework as well, so just log + // a warning here. + ALOGW("%s: received capture result in error state.", __FUNCTION__); + } if (mProcessCaptureResultLock.tryLock() != OK) { // This should never happen; it indicates a wrong client implementation @@ -965,6 +994,16 @@ void Camera3Device::processOneCaptureResultLocked( hardware::Return<void> Camera3Device::notify( const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) { + // Ideally we should grab mLock, but that can lead to deadlock, and + // it's not super important to get up to date value of mStatus for this + // warning print, hence skipping the lock here + if (mStatus == STATUS_ERROR) { + // Per API contract, HAL should act as closed after device error + // But mStatus can be set to error by framework as well, so just log + // a warning here. + ALOGW("%s: received notify message in error state.", __FUNCTION__); + } + for (const auto& msg : msgs) { notify(msg); } @@ -1102,6 +1141,7 @@ status_t Camera3Device::createInputStream( uint32_t width, uint32_t height, int format, int *id) { ATRACE_CALL(); Mutex::Autolock il(mInterfaceLock); + nsecs_t maxExpectedDuration = getExpectedInFlightDuration(); Mutex::Autolock l(mLock); ALOGV("Camera %s: Creating new input stream %d: %d x %d, format %d", mId.string(), mNextStreamId, width, height, format); @@ -1122,7 +1162,7 @@ status_t Camera3Device::createInputStream( break; case STATUS_ACTIVE: ALOGV("%s: Stopping activity to reconfigure streams", __FUNCTION__); - res = internalPauseAndWaitLocked(); + res = internalPauseAndWaitLocked(maxExpectedDuration); if (res != OK) { SET_ERR_L("Can't pause captures to reconfigure streams!"); return res; @@ -1189,6 +1229,7 @@ status_t Camera3Device::createStream(const std::vector<sp<Surface>>& consumers, int streamSetId, bool isShared, uint32_t consumerUsage) { ATRACE_CALL(); Mutex::Autolock il(mInterfaceLock); + nsecs_t maxExpectedDuration = getExpectedInFlightDuration(); Mutex::Autolock l(mLock); ALOGV("Camera %s: Creating new stream %d: %d x %d, format %d, dataspace %d rotation %d" " consumer usage 0x%x, isShared %d", mId.string(), mNextStreamId, width, height, format, @@ -1210,7 +1251,7 @@ status_t Camera3Device::createStream(const std::vector<sp<Surface>>& consumers, break; case STATUS_ACTIVE: ALOGV("%s: Stopping activity to reconfigure streams", __FUNCTION__); - res = internalPauseAndWaitLocked(); + res = internalPauseAndWaitLocked(maxExpectedDuration); if (res != OK) { SET_ERR_L("Can't pause captures to reconfigure streams!"); return res; @@ -1389,6 +1430,12 @@ status_t Camera3Device::deleteStream(int id) { return -EBUSY; } + if (mStatus == STATUS_ERROR) { + ALOGW("%s: Camera %s: deleteStream not allowed in ERROR state", + __FUNCTION__, mId.string()); + return -EBUSY; + } + sp<Camera3StreamInterface> deletedStream; ssize_t outputStreamIdx = mOutputStreams.indexOfKey(id); if (mInputStream != NULL && id == mInputStream->getId()) { @@ -1455,59 +1502,66 @@ status_t Camera3Device::createDefaultRequest(int templateId, } Mutex::Autolock il(mInterfaceLock); - Mutex::Autolock l(mLock); - switch (mStatus) { - case STATUS_ERROR: - CLOGE("Device has encountered a serious error"); - return INVALID_OPERATION; - case STATUS_UNINITIALIZED: - CLOGE("Device is not initialized!"); - return INVALID_OPERATION; - case STATUS_UNCONFIGURED: - case STATUS_CONFIGURED: - case STATUS_ACTIVE: - // OK - break; - default: - SET_ERR_L("Unexpected status: %d", mStatus); - return INVALID_OPERATION; - } + { + Mutex::Autolock l(mLock); + switch (mStatus) { + case STATUS_ERROR: + CLOGE("Device has encountered a serious error"); + return INVALID_OPERATION; + case STATUS_UNINITIALIZED: + CLOGE("Device is not initialized!"); + return INVALID_OPERATION; + case STATUS_UNCONFIGURED: + case STATUS_CONFIGURED: + case STATUS_ACTIVE: + // OK + break; + default: + SET_ERR_L("Unexpected status: %d", mStatus); + return INVALID_OPERATION; + } - if (!mRequestTemplateCache[templateId].isEmpty()) { - *request = mRequestTemplateCache[templateId]; - return OK; + if (!mRequestTemplateCache[templateId].isEmpty()) { + *request = mRequestTemplateCache[templateId]; + return OK; + } } camera_metadata_t *rawRequest; status_t res = mInterface->constructDefaultRequestSettings( (camera3_request_template_t) templateId, &rawRequest); - if (res == BAD_VALUE) { - ALOGI("%s: template %d is not supported on this camera device", - __FUNCTION__, templateId); - return res; - } else if (res != OK) { - CLOGE("Unable to construct request template %d: %s (%d)", - templateId, strerror(-res), res); - return res; - } - set_camera_metadata_vendor_id(rawRequest, mVendorTagId); - mRequestTemplateCache[templateId].acquire(rawRequest); + { + Mutex::Autolock l(mLock); + if (res == BAD_VALUE) { + ALOGI("%s: template %d is not supported on this camera device", + __FUNCTION__, templateId); + return res; + } else if (res != OK) { + CLOGE("Unable to construct request template %d: %s (%d)", + templateId, strerror(-res), res); + return res; + } + + set_camera_metadata_vendor_id(rawRequest, mVendorTagId); + mRequestTemplateCache[templateId].acquire(rawRequest); - *request = mRequestTemplateCache[templateId]; + *request = mRequestTemplateCache[templateId]; + } return OK; } status_t Camera3Device::waitUntilDrained() { ATRACE_CALL(); Mutex::Autolock il(mInterfaceLock); + nsecs_t maxExpectedDuration = getExpectedInFlightDuration(); Mutex::Autolock l(mLock); - return waitUntilDrainedLocked(); + return waitUntilDrainedLocked(maxExpectedDuration); } -status_t Camera3Device::waitUntilDrainedLocked() { +status_t Camera3Device::waitUntilDrainedLocked(nsecs_t maxExpectedDuration) { switch (mStatus) { case STATUS_UNINITIALIZED: case STATUS_UNCONFIGURED: @@ -1523,9 +1577,9 @@ status_t Camera3Device::waitUntilDrainedLocked() { SET_ERR_L("Unexpected status: %d",mStatus); return INVALID_OPERATION; } - - ALOGV("%s: Camera %s: Waiting until idle", __FUNCTION__, mId.string()); - status_t res = waitUntilStateThenRelock(/*active*/ false, kShutdownTimeout); + ALOGV("%s: Camera %s: Waiting until idle (%" PRIi64 "ns)", __FUNCTION__, mId.string(), + maxExpectedDuration); + status_t res = waitUntilStateThenRelock(/*active*/ false, maxExpectedDuration); if (res != OK) { SET_ERR_L("Error waiting for HAL to drain: %s (%d)", strerror(-res), res); @@ -1541,15 +1595,16 @@ void Camera3Device::internalUpdateStatusLocked(Status status) { } // Pause to reconfigure -status_t Camera3Device::internalPauseAndWaitLocked() { +status_t Camera3Device::internalPauseAndWaitLocked(nsecs_t maxExpectedDuration) { mRequestThread->setPaused(true); mPauseStateNotify = true; - ALOGV("%s: Camera %s: Internal wait until idle", __FUNCTION__, mId.string()); - status_t res = waitUntilStateThenRelock(/*active*/ false, kShutdownTimeout); + ALOGV("%s: Camera %s: Internal wait until idle (% " PRIi64 " ns)", __FUNCTION__, mId.string(), + maxExpectedDuration); + status_t res = waitUntilStateThenRelock(/*active*/ false, maxExpectedDuration); if (res != OK) { SET_ERR_L("Can't idle device in %f seconds!", - kShutdownTimeout/1e9); + maxExpectedDuration/1e9); } return res; @@ -2295,7 +2350,9 @@ void Camera3Device::setErrorStateLockedV(const char *fmt, va_list args) { mErrorCause = errorCause; - mRequestThread->setPaused(true); + if (mRequestThread != nullptr) { + mRequestThread->setPaused(true); + } internalUpdateStatusLocked(STATUS_ERROR); // Notify upstream about a device error @@ -2316,19 +2373,24 @@ void Camera3Device::setErrorStateLockedV(const char *fmt, va_list args) { status_t Camera3Device::registerInFlight(uint32_t frameNumber, int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput, - bool hasAppCallback) { + bool hasAppCallback, nsecs_t maxExpectedDuration) { ATRACE_CALL(); Mutex::Autolock l(mInFlightLock); ssize_t res; res = mInFlightMap.add(frameNumber, InFlightRequest(numBuffers, resultExtras, hasInput, - hasAppCallback)); + hasAppCallback, maxExpectedDuration)); if (res < 0) return res; if (mInFlightMap.size() == 1) { - mStatusTracker->markComponentActive(mInFlightStatusId); + // hold mLock to prevent race with disconnect + Mutex::Autolock l(mLock); + if (mStatusTracker != nullptr) { + mStatusTracker->markComponentActive(mInFlightStatusId); + } } + mExpectedInflightDuration += maxExpectedDuration; return OK; } @@ -2349,12 +2411,18 @@ void Camera3Device::returnOutputBuffers( } void Camera3Device::removeInFlightMapEntryLocked(int idx) { + nsecs_t duration = mInFlightMap.valueAt(idx).maxExpectedDuration; mInFlightMap.removeItemsAt(idx, 1); // Indicate idle inFlightMap to the status tracker if (mInFlightMap.size() == 0) { - mStatusTracker->markComponentIdle(mInFlightStatusId, Fence::NO_FENCE); + // hold mLock to prevent race with disconnect + Mutex::Autolock l(mLock); + if (mStatusTracker != nullptr) { + mStatusTracker->markComponentIdle(mInFlightStatusId, Fence::NO_FENCE); + } } + mExpectedInflightDuration -= duration; } void Camera3Device::removeInFlightRequestIfReadyLocked(int idx) { @@ -2365,6 +2433,25 @@ void Camera3Device::removeInFlightRequestIfReadyLocked(int idx) { nsecs_t sensorTimestamp = request.sensorTimestamp; nsecs_t shutterTimestamp = request.shutterTimestamp; + bool skipResultMetadata = false; + if (request.requestStatus != OK) { + switch (request.requestStatus) { + case CAMERA3_MSG_ERROR_DEVICE: + case CAMERA3_MSG_ERROR_REQUEST: + case CAMERA3_MSG_ERROR_RESULT: + skipResultMetadata = true; + break; + case CAMERA3_MSG_ERROR_BUFFER: + //Result metadata should return in this case. + skipResultMetadata = false; + break; + default: + SET_ERR("Unknown error message: %d", request.requestStatus); + skipResultMetadata = false; + break; + } + } + // Check if it's okay to remove the request from InFlightMap: // In the case of a successful request: // all input and output buffers, all result metadata, shutter callback @@ -2372,7 +2459,7 @@ void Camera3Device::removeInFlightRequestIfReadyLocked(int idx) { // In the case of a unsuccessful request: // all input and output buffers arrived. if (request.numBuffersLeft == 0 && - (request.requestStatus != OK || + (skipResultMetadata || (request.haveResultMetadata && shutterTimestamp != 0))) { ATRACE_ASYNC_END("frame capture", frameNumber); @@ -2407,6 +2494,98 @@ void Camera3Device::removeInFlightRequestIfReadyLocked(int idx) { } } +void Camera3Device::flushInflightRequests() { + { // First return buffers cached in mInFlightMap + Mutex::Autolock l(mInFlightLock); + for (size_t idx = 0; idx < mInFlightMap.size(); idx++) { + const InFlightRequest &request = mInFlightMap.valueAt(idx); + returnOutputBuffers(request.pendingOutputBuffers.array(), + request.pendingOutputBuffers.size(), 0); + } + mInFlightMap.clear(); + mExpectedInflightDuration = 0; + } + + // Then return all inflight buffers not returned by HAL + std::vector<std::pair<int32_t, int32_t>> inflightKeys; + mInterface->getInflightBufferKeys(&inflightKeys); + + int32_t inputStreamId = (mInputStream != nullptr) ? mInputStream->getId() : -1; + for (auto& pair : inflightKeys) { + int32_t frameNumber = pair.first; + int32_t streamId = pair.second; + buffer_handle_t* buffer; + status_t res = mInterface->popInflightBuffer(frameNumber, streamId, &buffer); + if (res != OK) { + ALOGE("%s: Frame %d: No in-flight buffer for stream %d", + __FUNCTION__, frameNumber, streamId); + continue; + } + + camera3_stream_buffer_t streamBuffer; + streamBuffer.buffer = buffer; + streamBuffer.status = CAMERA3_BUFFER_STATUS_ERROR; + streamBuffer.acquire_fence = -1; + streamBuffer.release_fence = -1; + + // First check if the buffer belongs to deleted stream + bool streamDeleted = false; + for (auto& stream : mDeletedStreams) { + if (streamId == stream->getId()) { + streamDeleted = true; + // Return buffer to deleted stream + camera3_stream* halStream = stream->asHalStream(); + streamBuffer.stream = halStream; + switch (halStream->stream_type) { + case CAMERA3_STREAM_OUTPUT: + res = stream->returnBuffer(streamBuffer, /*timestamp*/ 0); + if (res != OK) { + ALOGE("%s: Can't return output buffer for frame %d to" + " stream %d: %s (%d)", __FUNCTION__, + frameNumber, streamId, strerror(-res), res); + } + break; + case CAMERA3_STREAM_INPUT: + res = stream->returnInputBuffer(streamBuffer); + if (res != OK) { + ALOGE("%s: Can't return input buffer for frame %d to" + " stream %d: %s (%d)", __FUNCTION__, + frameNumber, streamId, strerror(-res), res); + } + break; + default: // Bi-direcitonal stream is deprecated + ALOGE("%s: stream %d has unknown stream type %d", + __FUNCTION__, streamId, halStream->stream_type); + break; + } + break; + } + } + if (streamDeleted) { + continue; + } + + // Then check against configured streams + if (streamId == inputStreamId) { + streamBuffer.stream = mInputStream->asHalStream(); + res = mInputStream->returnInputBuffer(streamBuffer); + if (res != OK) { + ALOGE("%s: Can't return input buffer for frame %d to" + " stream %d: %s (%d)", __FUNCTION__, + frameNumber, streamId, strerror(-res), res); + } + } else { + ssize_t idx = mOutputStreams.indexOfKey(streamId); + if (idx == NAME_NOT_FOUND) { + ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId); + continue; + } + streamBuffer.stream = mOutputStreams.valueAt(idx)->asHalStream(); + returnOutputBuffers(&streamBuffer, /*size*/1, /*timestamp*/ 0); + } + } +} + void Camera3Device::insertResultLocked(CaptureResult *result, uint32_t frameNumber) { if (result == nullptr) return; @@ -3322,6 +3501,20 @@ status_t Camera3Device::HalInterface::close() { return res; } +void Camera3Device::HalInterface::getInflightBufferKeys( + std::vector<std::pair<int32_t, int32_t>>* out) { + std::lock_guard<std::mutex> lock(mInflightLock); + out->clear(); + out->reserve(mInflightBufferMap.size()); + for (auto& pair : mInflightBufferMap) { + uint64_t key = pair.first; + int32_t streamId = key & 0xFFFFFFFF; + int32_t frameNumber = (key >> 32) & 0xFFFFFFFF; + out->push_back(std::make_pair(frameNumber, streamId)); + } + return; +} + status_t Camera3Device::HalInterface::pushInflightBufferLocked( int32_t frameNumber, int32_t streamId, buffer_handle_t *buffer, int acquireFence) { uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId); @@ -3396,7 +3589,7 @@ void Camera3Device::HalInterface::onBufferFreed( Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent, sp<StatusTracker> statusTracker, - HalInterface* interface) : + sp<HalInterface> interface) : Thread(/*canCallJava*/false), mParent(parent), mStatusTracker(statusTracker), @@ -3571,7 +3764,8 @@ status_t Camera3Device::RequestThread::clear( // Abort the input buffers for reprocess requests. if ((*it)->mInputStream != NULL) { camera3_stream_buffer_t inputBuffer; - status_t res = (*it)->mInputStream->getInputBuffer(&inputBuffer); + status_t res = (*it)->mInputStream->getInputBuffer(&inputBuffer, + /*respectHalLimit*/ false); if (res != OK) { ALOGW("%s: %d: couldn't get input buffer while clearing the request " "list: %s (%d)", __FUNCTION__, __LINE__, strerror(-res), res); @@ -3793,6 +3987,42 @@ bool Camera3Device::RequestThread::sendRequestsOneByOne() { return true; } +nsecs_t Camera3Device::RequestThread::calculateMaxExpectedDuration(const camera_metadata_t *request) { + nsecs_t maxExpectedDuration = kDefaultExpectedDuration; + camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t(); + find_camera_metadata_ro_entry(request, + ANDROID_CONTROL_AE_MODE, + &e); + if (e.count == 0) return maxExpectedDuration; + + switch (e.data.u8[0]) { + case ANDROID_CONTROL_AE_MODE_OFF: + find_camera_metadata_ro_entry(request, + ANDROID_SENSOR_EXPOSURE_TIME, + &e); + if (e.count > 0) { + maxExpectedDuration = e.data.i64[0]; + } + find_camera_metadata_ro_entry(request, + ANDROID_SENSOR_FRAME_DURATION, + &e); + if (e.count > 0) { + maxExpectedDuration = std::max(e.data.i64[0], maxExpectedDuration); + } + break; + default: + find_camera_metadata_ro_entry(request, + ANDROID_CONTROL_AE_TARGET_FPS_RANGE, + &e); + if (e.count > 1) { + maxExpectedDuration = 1e9 / e.data.u8[0]; + } + break; + } + + return maxExpectedDuration; +} + bool Camera3Device::RequestThread::threadLoop() { ATRACE_CALL(); status_t res; @@ -4013,7 +4243,8 @@ status_t Camera3Device::RequestThread::prepareHalRequests() { res = parent->registerInFlight(halRequest->frame_number, totalNumBuffers, captureRequest->mResultExtras, /*hasInput*/halRequest->input_buffer != NULL, - hasCallback); + hasCallback, + calculateMaxExpectedDuration(halRequest->settings)); ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64 ", burstId = %" PRId32 ".", __FUNCTION__, @@ -4067,6 +4298,12 @@ bool Camera3Device::RequestThread::isStreamPending( return false; } +nsecs_t Camera3Device::getExpectedInFlightDuration() { + Mutex::Autolock al(mInFlightLock); + return mExpectedInflightDuration > kMinInflightDuration ? + mExpectedInflightDuration : kMinInflightDuration; +} + void Camera3Device::RequestThread::cleanUpFailedRequests(bool sendRequestError) { if (mNextRequests.empty()) { return; diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index bfb58c66f7..d700e0398f 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -187,10 +187,11 @@ class Camera3Device : static const size_t kDumpLockAttempts = 10; static const size_t kDumpSleepDuration = 100000; // 0.10 sec - static const nsecs_t kShutdownTimeout = 5000000000; // 5 sec static const nsecs_t kActiveTimeout = 500000000; // 500 ms - static const size_t kInFlightWarnLimit = 20; + static const size_t kInFlightWarnLimit = 30; static const size_t kInFlightWarnLimitHighSpeed = 256; // batch size 32 * pipe depth 8 + static const nsecs_t kDefaultExpectedDuration = 100000000; // 100 ms + static const nsecs_t kMinInflightDuration = 5000000000; // 5 s // SCHED_FIFO priority for request submission thread in HFR mode static const int kRequestThreadPriority = 1; @@ -265,6 +266,10 @@ class Camera3Device : status_t popInflightBuffer(int32_t frameNumber, int32_t streamId, /*out*/ buffer_handle_t **buffer); + // Get a vector of (frameNumber, streamId) pair of currently inflight + // buffers + void getInflightBufferKeys(std::vector<std::pair<int32_t, int32_t>>* out); + private: camera3_device_t *mHal3Device; sp<hardware::camera::device::V3_2::ICameraDeviceSession> mHidlSession; @@ -333,7 +338,7 @@ class Camera3Device : std::vector<std::pair<int, uint64_t>> mFreedBuffers; }; - std::unique_ptr<HalInterface> mInterface; + sp<HalInterface> mInterface; CameraMetadata mDeviceInfo; @@ -481,7 +486,7 @@ class Camera3Device : * CameraDeviceBase interface we shouldn't need to. * Must be called with mLock and mInterfaceLock both held. */ - status_t internalPauseAndWaitLocked(); + status_t internalPauseAndWaitLocked(nsecs_t maxExpectedDuration); /** * Resume work after internalPauseAndWaitLocked() @@ -507,7 +512,7 @@ class Camera3Device : * * Need to be called with mLock and mInterfaceLock held. */ - status_t waitUntilDrainedLocked(); + status_t waitUntilDrainedLocked(nsecs_t maxExpectedDuration); /** * Do common work for setting up a streaming or single capture request. @@ -624,7 +629,7 @@ class Camera3Device : RequestThread(wp<Camera3Device> parent, sp<camera3::StatusTracker> statusTracker, - HalInterface* interface); + sp<HalInterface> interface); ~RequestThread(); void setNotificationListener(wp<NotificationListener> listener); @@ -772,9 +777,12 @@ class Camera3Device : // send request in mNextRequests to HAL in a batch. Return true = sucssess bool sendRequestsBatch(); + // Calculate the expected maximum duration for a request + nsecs_t calculateMaxExpectedDuration(const camera_metadata_t *request); + wp<Camera3Device> mParent; wp<camera3::StatusTracker> mStatusTracker; - HalInterface* mInterface; + sp<HalInterface> mInterface; wp<NotificationListener> mListener; @@ -873,6 +881,11 @@ class Camera3Device : // is not for constrained high speed recording, this flag will also be true. bool hasCallback; + // Maximum expected frame duration for this request. + // For manual captures, equal to the max of requested exposure time and frame duration + // For auto-exposure modes, equal to 1/(lower end of target FPS range) + nsecs_t maxExpectedDuration; + // Default constructor needed by KeyedVector InFlightRequest() : shutterTimestamp(0), @@ -881,11 +894,12 @@ class Camera3Device : haveResultMetadata(false), numBuffersLeft(0), hasInputBuffer(false), - hasCallback(true) { + hasCallback(true), + maxExpectedDuration(kDefaultExpectedDuration) { } InFlightRequest(int numBuffers, CaptureResultExtras extras, bool hasInput, - bool hasAppCallback) : + bool hasAppCallback, nsecs_t maxDuration) : shutterTimestamp(0), sensorTimestamp(0), requestStatus(OK), @@ -893,20 +907,31 @@ class Camera3Device : numBuffersLeft(numBuffers), resultExtras(extras), hasInputBuffer(hasInput), - hasCallback(hasAppCallback) { + hasCallback(hasAppCallback), + maxExpectedDuration(maxDuration) { } }; // Map from frame number to the in-flight request state typedef KeyedVector<uint32_t, InFlightRequest> InFlightMap; - Mutex mInFlightLock; // Protects mInFlightMap + + Mutex mInFlightLock; // Protects mInFlightMap and + // mExpectedInflightDuration InFlightMap mInFlightMap; + nsecs_t mExpectedInflightDuration = 0; int mInFlightStatusId; + status_t registerInFlight(uint32_t frameNumber, int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput, - bool callback); + bool callback, nsecs_t maxExpectedDuration); + + /** + * Returns the maximum expected time it'll take for all currently in-flight + * requests to complete, based on their settings + */ + nsecs_t getExpectedInFlightDuration(); /** * Tracking for idle detection @@ -1023,6 +1048,10 @@ class Camera3Device : // Remove the in-flight request of the given index from mInFlightMap // if it's no longer needed. It must only be called with mInFlightLock held. void removeInFlightRequestIfReadyLocked(int idx); + // Remove all in-flight requests and return all buffers. + // This is used after HAL interface is closed to cleanup any request/buffers + // not returned by HAL. + void flushInflightRequests(); /**** End scope for mInFlightLock ****/ diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp index 4eb15ad659..ff2dcef71f 100644 --- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp @@ -293,8 +293,18 @@ status_t Camera3InputStream::getEndpointUsage(uint32_t *usage) const { void Camera3InputStream::onBufferFreed(const wp<GraphicBuffer>& gb) { const sp<GraphicBuffer> buffer = gb.promote(); if (buffer != nullptr) { - if (mBufferFreedListener != nullptr) { - mBufferFreedListener->onBufferFreed(mId, buffer->handle); + camera3_stream_buffer streamBuffer = + {nullptr, &buffer->handle, 0, -1, -1}; + // Check if this buffer is outstanding. + if (isOutstandingBuffer(streamBuffer)) { + ALOGV("%s: Stream %d: Trying to free a buffer that is still being " + "processed.", __FUNCTION__, mId); + return; + } + + sp<Camera3StreamBufferFreedListener> callback = mBufferFreedListener.promote(); + if (callback != nullptr) { + callback->onBufferFreed(mId, buffer->handle); } } else { ALOGE("%s: GraphicBuffer is freed before onBufferFreed callback finishes!", __FUNCTION__); diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp index e15aa436f3..b02cd6a980 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp @@ -727,7 +727,7 @@ void Camera3OutputStream::BufferReleasedListener::onBufferReleased() { void Camera3OutputStream::onBuffersRemovedLocked( const std::vector<sp<GraphicBuffer>>& removedBuffers) { - Camera3StreamBufferFreedListener* callback = mBufferFreedListener; + sp<Camera3StreamBufferFreedListener> callback = mBufferFreedListener.promote(); if (callback != nullptr) { for (auto gb : removedBuffers) { callback->onBufferFreed(mId, gb->handle); diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index ba352c4200..9e6ac798b3 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -479,6 +479,7 @@ status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer, if (res == OK) { fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/true); if (buffer->buffer) { + Mutex::Autolock l(mOutstandingBuffersLock); mOutstandingBuffers.push_back(*buffer->buffer); } } @@ -486,11 +487,13 @@ status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer, return res; } -bool Camera3Stream::isOutstandingBuffer(const camera3_stream_buffer &buffer) { +bool Camera3Stream::isOutstandingBuffer(const camera3_stream_buffer &buffer) const{ if (buffer.buffer == nullptr) { return false; } + Mutex::Autolock l(mOutstandingBuffersLock); + for (auto b : mOutstandingBuffers) { if (b == *buffer.buffer) { return true; @@ -504,6 +507,8 @@ void Camera3Stream::removeOutstandingBuffer(const camera3_stream_buffer &buffer) return; } + Mutex::Autolock l(mOutstandingBuffersLock); + for (auto b = mOutstandingBuffers.begin(); b != mOutstandingBuffers.end(); b++) { if (*b == *buffer.buffer) { mOutstandingBuffers.erase(b); @@ -523,6 +528,8 @@ status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer, return BAD_VALUE; } + removeOutstandingBuffer(buffer); + /** * TODO: Check that the state is valid first. * @@ -540,11 +547,10 @@ status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer, // buffer to be returned. mOutputBufferReturnedSignal.signal(); - removeOutstandingBuffer(buffer); return res; } -status_t Camera3Stream::getInputBuffer(camera3_stream_buffer *buffer) { +status_t Camera3Stream::getInputBuffer(camera3_stream_buffer *buffer, bool respectHalLimit) { ATRACE_CALL(); Mutex::Autolock l(mLock); status_t res = OK; @@ -557,7 +563,7 @@ status_t Camera3Stream::getInputBuffer(camera3_stream_buffer *buffer) { } // Wait for new buffer returned back if we are running into the limit. - if (getHandoutInputBufferCountLocked() == camera3_stream::max_buffers) { + if (getHandoutInputBufferCountLocked() == camera3_stream::max_buffers && respectHalLimit) { ALOGV("%s: Already dequeued max input buffers (%d), wait for next returned one.", __FUNCTION__, camera3_stream::max_buffers); res = mInputBufferReturnedSignal.waitRelative(mLock, kWaitForBufferDuration); @@ -574,6 +580,7 @@ status_t Camera3Stream::getInputBuffer(camera3_stream_buffer *buffer) { if (res == OK) { fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/false); if (buffer->buffer) { + Mutex::Autolock l(mOutstandingBuffersLock); mOutstandingBuffers.push_back(*buffer->buffer); } } @@ -591,13 +598,14 @@ status_t Camera3Stream::returnInputBuffer(const camera3_stream_buffer &buffer) { return BAD_VALUE; } + removeOutstandingBuffer(buffer); + status_t res = returnInputBufferLocked(buffer); if (res == OK) { fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/false); mInputBufferReturnedSignal.signal(); } - removeOutstandingBuffer(buffer); return res; } @@ -744,7 +752,7 @@ void Camera3Stream::removeBufferListener( } void Camera3Stream::setBufferFreedListener( - Camera3StreamBufferFreedListener* listener) { + wp<Camera3StreamBufferFreedListener> listener) { Mutex::Autolock l(mLock); // Only allow set listener during stream configuration because stream is guaranteed to be IDLE // at this state, so setBufferFreedListener won't collide with onBufferFreed callbacks diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h index b5a9c5d85b..44fe6b6920 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.h +++ b/services/camera/libcameraservice/device3/Camera3Stream.h @@ -308,8 +308,10 @@ class Camera3Stream : * For bidirectional streams, this method applies to the input-side * buffers. * + * Normally this call will block until the handed out buffer count is less than the stream + * max buffer count; if respectHalLimit is set to false, this is ignored. */ - status_t getInputBuffer(camera3_stream_buffer *buffer); + status_t getInputBuffer(camera3_stream_buffer *buffer, bool respectHalLimit = true); /** * Return a buffer to the stream after use by the HAL. @@ -369,7 +371,7 @@ class Camera3Stream : // Setting listener will remove previous listener (if exists) virtual void setBufferFreedListener( - Camera3StreamBufferFreedListener* listener) override; + wp<Camera3StreamBufferFreedListener> listener) override; /** * Return if the buffer queue of the stream is abandoned. @@ -414,7 +416,7 @@ class Camera3Stream : android_dataspace dataSpace, camera3_stream_rotation_t rotation, int setId); - Camera3StreamBufferFreedListener* mBufferFreedListener; + wp<Camera3StreamBufferFreedListener> mBufferFreedListener; /** * Interface to be implemented by derived classes @@ -459,6 +461,9 @@ class Camera3Stream : // INVALID_OPERATION if they cannot be obtained. virtual status_t getEndpointUsage(uint32_t *usage) const = 0; + // Return whether the buffer is in the list of outstanding buffers. + bool isOutstandingBuffer(const camera3_stream_buffer& buffer) const; + // Tracking for idle state wp<StatusTracker> mStatusTracker; // Status tracker component ID @@ -481,9 +486,6 @@ class Camera3Stream : status_t cancelPrepareLocked(); - // Return whether the buffer is in the list of outstanding buffers. - bool isOutstandingBuffer(const camera3_stream_buffer& buffer); - // Remove the buffer from the list of outstanding buffers. void removeOutstandingBuffer(const camera3_stream_buffer& buffer); @@ -500,6 +502,7 @@ class Camera3Stream : // Number of buffers allocated on last prepare call. size_t mLastMaxCount; + mutable Mutex mOutstandingBuffersLock; // Outstanding buffers dequeued from the stream's buffer queue. List<buffer_handle_t> mOutstandingBuffers; diff --git a/services/camera/libcameraservice/device3/Camera3StreamBufferFreedListener.h b/services/camera/libcameraservice/device3/Camera3StreamBufferFreedListener.h index 478a752ad9..104cd22c8e 100644 --- a/services/camera/libcameraservice/device3/Camera3StreamBufferFreedListener.h +++ b/services/camera/libcameraservice/device3/Camera3StreamBufferFreedListener.h @@ -24,7 +24,7 @@ namespace android { namespace camera3 { -class Camera3StreamBufferFreedListener { +class Camera3StreamBufferFreedListener : public virtual RefBase { public: // onBufferFreed is called when a buffer is no longer being managed // by this stream. This will not be called in events when all diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h index 37b7c36707..0544a1bc34 100644 --- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h +++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h @@ -232,8 +232,10 @@ class Camera3StreamInterface : public virtual RefBase { * For bidirectional streams, this method applies to the input-side * buffers. * + * Normally this call will block until the handed out buffer count is less than the stream + * max buffer count; if respectHalLimit is set to false, this is ignored. */ - virtual status_t getInputBuffer(camera3_stream_buffer *buffer) = 0; + virtual status_t getInputBuffer(camera3_stream_buffer *buffer, bool respectHalLimit = true) = 0; /** * Return a buffer to the stream after use by the HAL. @@ -296,7 +298,7 @@ class Camera3StreamInterface : public virtual RefBase { * Client is responsible to keep the listener object alive throughout the lifecycle of this * Camera3Stream. */ - virtual void setBufferFreedListener(Camera3StreamBufferFreedListener* listener) = 0; + virtual void setBufferFreedListener(wp<Camera3StreamBufferFreedListener> listener) = 0; }; } // namespace camera3 diff --git a/services/mediaanalytics/MetricsSummarizer.cpp b/services/mediaanalytics/MetricsSummarizer.cpp index 6d5787e35c..3477f1f344 100644 --- a/services/mediaanalytics/MetricsSummarizer.cpp +++ b/services/mediaanalytics/MetricsSummarizer.cpp @@ -153,11 +153,11 @@ void MetricsSummarizer::handleRecord(MediaAnalyticsItem *item) { ALOGE("unable to save MediaMetrics record"); } sortProps(item); - item->setInt32("aggregated",1); + item->setInt32("count",1); mSummaries->push_back(item); } else { ALOGV("increment existing record"); - (*it)->addInt32("aggregated",1); + (*it)->addInt32("count",1); mergeRecord(*(*it), *item); } } diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk index 8eb4aa0e27..6997b5a2f1 100644 --- a/services/mediacodec/Android.mk +++ b/services/mediacodec/Android.mk @@ -4,46 +4,52 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := MediaCodecService.cpp LOCAL_SHARED_LIBRARIES := \ - libmedia \ + libmedia_omx \ libbinder \ libgui \ libutils \ liblog \ libstagefright_omx LOCAL_C_INCLUDES := \ - $(TOP)/frameworks/av/media/libstagefright \ - $(TOP)/frameworks/native/include/media/openmax + frameworks/av/include \ + frameworks/av/media/libstagefright \ + frameworks/av/media/libstagefright/include \ + frameworks/native/include \ + frameworks/native/include/media/openmax LOCAL_MODULE:= libmediacodecservice +LOCAL_VENDOR_MODULE := true LOCAL_32_BIT_ONLY := true include $(BUILD_SHARED_LIBRARY) - # service executable include $(CLEAR_VARS) LOCAL_REQUIRED_MODULES_arm := mediacodec.policy LOCAL_SRC_FILES := main_codecservice.cpp LOCAL_SHARED_LIBRARIES := \ - libmedia \ + libmedia_omx \ libmediacodecservice \ libbinder \ libutils \ libgui \ liblog \ libbase \ - libavservices_minijail \ + libavservices_minijail_vendor \ libcutils \ libhwbinder \ libhidltransport \ libstagefright_omx \ android.hardware.media.omx@1.0 \ android.hidl.memory@1.0 + LOCAL_C_INCLUDES := \ - $(TOP)/frameworks/av/media/libstagefright \ - $(TOP)/frameworks/av/media/libstagefright/include \ - $(TOP)/frameworks/native/include/media/openmax + frameworks/av/include \ + frameworks/av/media/libstagefright \ + frameworks/av/media/libstagefright/include \ + frameworks/native/include \ + frameworks/native/include/media/openmax LOCAL_MODULE := android.hardware.media.omx@1.0-service LOCAL_MODULE_RELATIVE_PATH := hw -LOCAL_PROPRIETARY_MODULE := true +LOCAL_VENDOR_MODULE := true LOCAL_32_BIT_ONLY := true LOCAL_INIT_RC := android.hardware.media.omx@1.0-service.rc include $(BUILD_EXECUTABLE) diff --git a/services/mediacodec/seccomp_policy/mediacodec-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy index 52658d10cc..cbd7fb9c49 100644 --- a/services/mediacodec/seccomp_policy/mediacodec-arm.policy +++ b/services/mediacodec/seccomp_policy/mediacodec-arm.policy @@ -12,6 +12,7 @@ writev: 1 dup: 1 ppoll: 1 mmap2: 1 +getrandom: 1 # mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail # parser support for '<' is in this needs to be modified to also prevent diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk index fa3a02b99a..6b30db633f 100644 --- a/services/mediadrm/Android.mk +++ b/services/mediadrm/Android.mk @@ -25,19 +25,13 @@ LOCAL_SHARED_LIBRARIES:= \ libbinder \ liblog \ libmediadrm \ - libutils -ifneq ($(DISABLE_TREBLE_DRM), true) -LOCAL_SHARED_LIBRARIES += \ + libutils \ libhidlbase \ libhidlmemory \ - android.hidl.base@1.0 \ + libhidltransport \ android.hardware.drm@1.0 -endif LOCAL_CFLAGS += -Wall -Wextra -Werror -ifeq ($(DISABLE_TREBLE_DRM), true) -LOCAL_CFLAGS += -DDISABLE_TREBLE_DRM=1 -endif LOCAL_MODULE:= mediadrmserver diff --git a/services/mediadrm/MediaDrmService.cpp b/services/mediadrm/MediaDrmService.cpp index b9ec347cc3..a368c11cdc 100644 --- a/services/mediadrm/MediaDrmService.cpp +++ b/services/mediadrm/MediaDrmService.cpp @@ -24,13 +24,8 @@ #include <binder/IServiceManager.h> #include <utils/Log.h> -#ifdef DISABLE_TREBLE_DRM -#include <media/Crypto.h> -#include <media/Drm.h> -#else #include <media/CryptoHal.h> #include <media/DrmHal.h> -#endif namespace android { @@ -40,19 +35,11 @@ void MediaDrmService::instantiate() { } sp<ICrypto> MediaDrmService::makeCrypto() { -#ifdef DISABLE_TREBLE_DRM - return new Crypto; -#else return new CryptoHal; -#endif } sp<IDrm> MediaDrmService::makeDrm() { -#ifdef DISABLE_TREBLE_DRM - return new Drm; -#else return new DrmHal; -#endif } } // namespace android diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp index aaf1018e34..a5512e1207 100644 --- a/services/medialog/MediaLogService.cpp +++ b/services/medialog/MediaLogService.cpp @@ -26,7 +26,7 @@ namespace android { -// static const char kDeadlockedString[] = "MediaLogService may be deadlocked\n"; + static const char kDeadlockedString[] = "MediaLogService may be deadlocked\n"; MediaLogService::MediaLogService() : BnMediaLogService(), mMergerShared((NBLog::Shared*) malloc(NBLog::Timeline::sharedSize(kMergeBufferSize))), @@ -99,35 +99,38 @@ status_t MediaLogService::dump(int fd, const Vector<String16>& args __unused) return NO_ERROR; } -#if 0 - Vector<NBLog::NamedReader> namedReaders; - { - bool locked = dumpTryLock(mLock); - - // failed to lock - MediaLogService is probably deadlocked - if (!locked) { - String8 result(kDeadlockedString); - if (fd >= 0) { - write(fd, result.string(), result.size()); - } else { - ALOGW("%s:", result.string()); + if (args.size() > 0) { + const String8 arg0(args[0]); + if (!strcmp(arg0.string(), "-r")) { + // needed because mNamedReaders is protected by mLock + bool locked = dumpTryLock(mLock); + + // failed to lock - MediaLogService is probably deadlocked + if (!locked) { + String8 result(kDeadlockedString); + if (fd >= 0) { + write(fd, result.string(), result.size()); + } else { + ALOGW("%s:", result.string()); + } + // TODO should we instead proceed to mMergeReader.dump? does it need lock? + return NO_ERROR; + } + + for (const auto& namedReader : mNamedReaders) { + if (fd >= 0) { + dprintf(fd, "\n%s:\n", namedReader.name()); + } else { + ALOGI("%s:", namedReader.name()); + } + // TODO This code is for testing, remove it when done + // namedReader.reader()->dump(fd, 0 /*indent*/); } - return NO_ERROR; + + mLock.unlock(); } - // namedReaders = mNamedReaders; - // for (size_t i = 0; i < namedReaders.size(); i++) { - // const NBLog::NamedReader& namedReader = namedReaders[i]; - // if (fd >= 0) { - // dprintf(fd, "\n%s:\n", namedReader.name()); - // } else { - // ALOGI("%s:", namedReader.name()); - // } - // namedReader.reader()->dump(fd, 0 /*indent*/); - // } - - mLock.unlock(); } -#endif + // FIXME request merge to make sure log is up to date mMergeReader.dump(fd); return NO_ERROR; diff --git a/services/medialog/MediaLogService.h b/services/medialog/MediaLogService.h index c6b99f1995..39d9cc0981 100644 --- a/services/medialog/MediaLogService.h +++ b/services/medialog/MediaLogService.h @@ -49,12 +49,15 @@ private: // Internal dump static const int kDumpLockRetries = 50; static const int kDumpLockSleepUs = 20000; - static const size_t kMergeBufferSize = 16 * 1024; // TODO determine good value for this + // Size of merge buffer, in bytes + static const size_t kMergeBufferSize = 64 * 1024; // TODO determine good value for this static bool dumpTryLock(Mutex& mutex); Mutex mLock; - Vector<NBLog::NamedReader> mNamedReaders; + Vector<NBLog::NamedReader> mNamedReaders; // protected by mLock + + // FIXME Need comments on all of these, especially about locking NBLog::Shared *mMergerShared; NBLog::Merger mMerger; NBLog::MergeReader mMergeReader; diff --git a/services/mediaresourcemanager/Android.mk b/services/mediaresourcemanager/Android.mk index c9cd8cc53d..5823036aec 100644 --- a/services/mediaresourcemanager/Android.mk +++ b/services/mediaresourcemanager/Android.mk @@ -11,7 +11,7 @@ LOCAL_MODULE:= libresourcemanagerservice LOCAL_32_BIT_ONLY := true LOCAL_C_INCLUDES += \ - $(TOPDIR)frameworks/av/include + frameworks/av/include LOCAL_CFLAGS += -Werror -Wall diff --git a/services/minijail/Android.mk b/services/minijail/Android.mk index 3e63f97c94..b6fcacc341 100644 --- a/services/minijail/Android.mk +++ b/services/minijail/Android.mk @@ -8,6 +8,14 @@ LOCAL_SHARED_LIBRARIES := libbase libminijail LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) include $(BUILD_SHARED_LIBRARY) +# Small library for media.extractor and media.codec sandboxing. +include $(CLEAR_VARS) +LOCAL_MODULE := libavservices_minijail_vendor +LOCAL_VENDOR_MODULE := true +LOCAL_SRC_FILES := minijail.cpp +LOCAL_SHARED_LIBRARIES := libbase libminijail_vendor +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) +include $(BUILD_SHARED_LIBRARY) # Unit tests. include $(CLEAR_VARS) diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp new file mode 100644 index 0000000000..75392bd791 --- /dev/null +++ b/services/oboeservice/AAudioClientTracker.cpp @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#define LOG_TAG "AAudioService" +//#define LOG_NDEBUG 0 +#include <utils/Log.h> + +#include <assert.h> +#include <binder/IPCThreadState.h> +#include <map> +#include <mutex> +#include <utils/Singleton.h> + +#include "utility/AAudioUtilities.h" +#include "AAudioEndpointManager.h" +#include "AAudioServiceEndpoint.h" +#include "AAudioClientTracker.h" + +using namespace android; +using namespace aaudio; + +ANDROID_SINGLETON_STATIC_INSTANCE(AAudioClientTracker); + +AAudioClientTracker::AAudioClientTracker() + : Singleton<AAudioClientTracker>() { +} + + +std::string AAudioClientTracker::dump() const { + std::stringstream result; + const bool isLocked = AAudio_tryUntilTrue( + [this]()->bool { return mLock.try_lock(); } /* f */, + 50 /* times */, + 20 /* sleepMs */); + if (!isLocked) { + result << "AAudioClientTracker may be deadlocked\n"; + } + + result << "AAudioClientTracker:\n"; + for (const auto& it : mNotificationClients) { + result << it.second->dump(); + } + + if (isLocked) { + mLock.unlock(); + } + return result.str(); +} + +// Create a tracker for the client. +aaudio_result_t AAudioClientTracker::registerClient(pid_t pid, + const sp<IAAudioClient>& client) { + ALOGV("AAudioClientTracker::registerClient(), calling pid = %d, getpid() = %d\n", + pid, getpid()); + + std::lock_guard<std::mutex> lock(mLock); + if (mNotificationClients.count(pid) == 0) { + sp<NotificationClient> notificationClient = new NotificationClient(pid); + mNotificationClients[pid] = notificationClient; + + sp<IBinder> binder = IInterface::asBinder(client); + status_t status = binder->linkToDeath(notificationClient); + ALOGW_IF(status != NO_ERROR, + "AAudioClientTracker::registerClient() linkToDeath = %d\n", status); + return AAudioConvert_androidToAAudioResult(status); + } else { + ALOGW("AAudioClientTracker::registerClient(%d) already registered!", pid); + return AAUDIO_OK; // TODO should this be considered an error + } +} + +void AAudioClientTracker::unregisterClient(pid_t pid) { + ALOGV("AAudioClientTracker::unregisterClient(), calling pid = %d, getpid() = %d\n", + pid, getpid()); + std::lock_guard<std::mutex> lock(mLock); + mNotificationClients.erase(pid); +} + +int32_t AAudioClientTracker::getStreamCount(pid_t pid) { + std::lock_guard<std::mutex> lock(mLock); + auto it = mNotificationClients.find(pid); + if (it != mNotificationClients.end()) { + return it->second->getStreamCount(); + } else { + return 0; // no existing client + } +} + +aaudio_result_t +AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) { + aaudio_result_t result = AAUDIO_OK; + ALOGV("AAudioClientTracker::registerClientStream(%d, %p)\n", pid, serviceStream.get()); + std::lock_guard<std::mutex> lock(mLock); + sp<NotificationClient> notificationClient = mNotificationClients[pid]; + if (notificationClient == 0) { + // This will get called the first time the audio server registers an internal stream. + ALOGV("AAudioClientTracker::registerClientStream(%d,) unrecognized pid\n", pid); + notificationClient = new NotificationClient(pid); + mNotificationClients[pid] = notificationClient; + } + notificationClient->registerClientStream(serviceStream); + return result; +} + +// Find the tracker for this process and remove it. +aaudio_result_t +AAudioClientTracker::unregisterClientStream(pid_t pid, + sp<AAudioServiceStreamBase> serviceStream) { + ALOGV("AAudioClientTracker::unregisterClientStream(%d, %p)\n", pid, serviceStream.get()); + std::lock_guard<std::mutex> lock(mLock); + auto it = mNotificationClients.find(pid); + if (it != mNotificationClients.end()) { + ALOGV("AAudioClientTracker::unregisterClientStream(%d, %p) found NotificationClient\n", + pid, serviceStream.get()); + it->second->unregisterClientStream(serviceStream); + } else { + ALOGE("AAudioClientTracker::unregisterClientStream(%d, %p) missing NotificationClient\n", + pid, serviceStream.get()); + } + return AAUDIO_OK; +} + +AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid) + : mProcessId(pid) { + //ALOGD("AAudioClientTracker::NotificationClient(%d) created %p\n", pid, this); +} + +AAudioClientTracker::NotificationClient::~NotificationClient() { + //ALOGD("AAudioClientTracker::~NotificationClient() destroyed %p\n", this); +} + +int32_t AAudioClientTracker::NotificationClient::getStreamCount() { + std::lock_guard<std::mutex> lock(mLock); + return mStreams.size(); +} + +aaudio_result_t AAudioClientTracker::NotificationClient::registerClientStream( + sp<AAudioServiceStreamBase> serviceStream) { + std::lock_guard<std::mutex> lock(mLock); + mStreams.insert(serviceStream); + return AAUDIO_OK; +} + +aaudio_result_t AAudioClientTracker::NotificationClient::unregisterClientStream( + sp<AAudioServiceStreamBase> serviceStream) { + std::lock_guard<std::mutex> lock(mLock); + mStreams.erase(serviceStream); + return AAUDIO_OK; +} + +// Close any open streams for the client. +void AAudioClientTracker::NotificationClient::binderDied(const wp<IBinder>& who __unused) { + AAudioService *aaudioService = AAudioClientTracker::getInstance().getAAudioService(); + if (aaudioService != nullptr) { + // Copy the current list of streams to another vector because closing them below + // will cause unregisterClientStream() calls back to this object. + std::set<sp<AAudioServiceStreamBase>> streamsToClose; + + { + std::lock_guard<std::mutex> lock(mLock); + for (auto serviceStream : mStreams) { + streamsToClose.insert(serviceStream); + } + } + + for (auto serviceStream : streamsToClose) { + aaudio_handle_t handle = serviceStream->getHandle(); + ALOGW("AAudioClientTracker::binderDied() close abandoned stream 0x%08X\n", handle); + aaudioService->closeStream(handle); + } + // mStreams should be empty now + } + sp<NotificationClient> keep(this); + AAudioClientTracker::getInstance().unregisterClient(mProcessId); +} + + +std::string AAudioClientTracker::NotificationClient::dump() const { + std::stringstream result; + const bool isLocked = AAudio_tryUntilTrue( + [this]()->bool { return mLock.try_lock(); } /* f */, + 50 /* times */, + 20 /* sleepMs */); + if (!isLocked) { + result << "AAudioClientTracker::NotificationClient may be deadlocked\n"; + } + + result << " client: pid = " << mProcessId << " has " << mStreams.size() << " streams\n"; + for (auto serviceStream : mStreams) { + result << " stream: 0x" << std::hex << serviceStream->getHandle() << std::dec << "\n"; + } + + if (isLocked) { + mLock.unlock(); + } + return result.str(); +} diff --git a/services/oboeservice/AAudioClientTracker.h b/services/oboeservice/AAudioClientTracker.h new file mode 100644 index 0000000000..accf1a7b31 --- /dev/null +++ b/services/oboeservice/AAudioClientTracker.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_AAUDIO_AAUDIO_CLIENT_TRACKER_H +#define ANDROID_AAUDIO_AAUDIO_CLIENT_TRACKER_H + +#include <map> +#include <mutex> +#include <set> + +#include <utils/Singleton.h> + +#include <aaudio/AAudio.h> +#include "binding/IAAudioClient.h" +#include "AAudioService.h" + +namespace aaudio { + +class AAudioClientTracker : public android::Singleton<AAudioClientTracker>{ +public: + AAudioClientTracker(); + ~AAudioClientTracker() = default; + + /** + * Returns information about the state of the this class. + * + * Will attempt to get the object lock, but will proceed + * even if it cannot. + * + * Each line of information ends with a newline. + * + * @return a string with useful information + */ + std::string dump() const; + + aaudio_result_t registerClient(pid_t pid, const android::sp<android::IAAudioClient>& client); + + void unregisterClient(pid_t pid); + + int32_t getStreamCount(pid_t pid); + + aaudio_result_t registerClientStream(pid_t pid, + android::sp<AAudioServiceStreamBase> serviceStream); + + aaudio_result_t unregisterClientStream(pid_t pid, + android::sp<AAudioServiceStreamBase> serviceStream); + + android::AAudioService *getAAudioService() const { + return mAAudioService; + } + + void setAAudioService(android::AAudioService *aaudioService) { + mAAudioService = aaudioService; + } + +private: + + /** + * One per process. + */ + class NotificationClient : public IBinder::DeathRecipient { + public: + NotificationClient(pid_t pid); + virtual ~NotificationClient(); + + int32_t getStreamCount(); + + std::string dump() const; + + aaudio_result_t registerClientStream(android::sp<AAudioServiceStreamBase> serviceStream); + + aaudio_result_t unregisterClientStream(android::sp<AAudioServiceStreamBase> serviceStream); + + // IBinder::DeathRecipient + virtual void binderDied(const android::wp<IBinder>& who); + + protected: + mutable std::mutex mLock; + const pid_t mProcessId; + std::set<android::sp<AAudioServiceStreamBase>> mStreams; + }; + + mutable std::mutex mLock; + std::map<pid_t, android::sp<NotificationClient>> mNotificationClients; + android::AAudioService *mAAudioService = nullptr; +}; + +} /* namespace aaudio */ + +#endif //ANDROID_AAUDIO_AAUDIO_CLIENT_TRACKER_H diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp index 3dc1feba01..ec2f5b9684 100644 --- a/services/oboeservice/AAudioEndpointManager.cpp +++ b/services/oboeservice/AAudioEndpointManager.cpp @@ -14,13 +14,16 @@ * limitations under the License. */ -#define LOG_TAG "AAudioService" +#define LOG_TAG "AAudioEndpointManager" //#define LOG_NDEBUG 0 #include <utils/Log.h> #include <assert.h> +#include <functional> #include <map> #include <mutex> +#include <sstream> +#include <utility/AAudioUtilities.h> #include "AAudioEndpointManager.h" @@ -35,51 +38,114 @@ AAudioEndpointManager::AAudioEndpointManager() , mOutputs() { } -AAudioServiceEndpoint *AAudioEndpointManager::openEndpoint(AAudioService &audioService, int32_t deviceId, - aaudio_direction_t direction) { +std::string AAudioEndpointManager::dump() const { + std::stringstream result; + const bool isLocked = AAudio_tryUntilTrue( + [this]()->bool { return mLock.try_lock(); } /* f */, + 50 /* times */, + 20 /* sleepMs */); + if (!isLocked) { + result << "EndpointManager may be deadlocked\n"; + } + + result << "AAudioEndpointManager:" << "\n"; + size_t inputs = mInputs.size(); + result << "Input Endpoints: " << inputs << "\n"; + for (const auto &input : mInputs) { + result << " Input: " << input->dump() << "\n"; + } + + size_t outputs = mOutputs.size(); + result << "Output Endpoints: " << outputs << "\n"; + for (const auto &output : mOutputs) { + result << " Output: " << output->dump() << "\n"; + } + + if (isLocked) { + mLock.unlock(); + } + return result.str(); +} + +AAudioServiceEndpoint *AAudioEndpointManager::openEndpoint(AAudioService &audioService, + const AAudioStreamConfiguration& configuration, aaudio_direction_t direction) { AAudioServiceEndpoint *endpoint = nullptr; + AAudioServiceEndpointCapture *capture = nullptr; + AAudioServiceEndpointPlay *player = nullptr; std::lock_guard<std::mutex> lock(mLock); // Try to find an existing endpoint. + + + switch (direction) { case AAUDIO_DIRECTION_INPUT: - endpoint = mInputs[deviceId]; + for (AAudioServiceEndpoint *ep : mInputs) { + if (ep->matches(configuration)) { + endpoint = ep; + break; + } + } break; case AAUDIO_DIRECTION_OUTPUT: - endpoint = mOutputs[deviceId]; + for (AAudioServiceEndpoint *ep : mOutputs) { + if (ep->matches(configuration)) { + endpoint = ep; + break; + } + } break; default: assert(false); // There are only two possible directions. break; } ALOGD("AAudioEndpointManager::openEndpoint(), found %p for device = %d, dir = %d", - endpoint, deviceId, (int)direction); + endpoint, configuration.getDeviceId(), (int)direction); // If we can't find an existing one then open a new one. if (endpoint == nullptr) { - if (direction == AAUDIO_DIRECTION_INPUT) { - AAudioServiceEndpointCapture *capture = new AAudioServiceEndpointCapture(audioService); - if (capture->open(deviceId) != AAUDIO_OK) { - ALOGE("AAudioEndpointManager::openEndpoint(), open failed"); - delete capture; - } else { - mInputs[deviceId] = capture; + // we must call openStream with audioserver identity + int64_t token = IPCThreadState::self()->clearCallingIdentity(); + switch(direction) { + case AAUDIO_DIRECTION_INPUT: + capture = new AAudioServiceEndpointCapture(audioService); endpoint = capture; - } - } else if (direction == AAUDIO_DIRECTION_OUTPUT) { - AAudioServiceEndpointPlay *player = new AAudioServiceEndpointPlay(audioService); - if (player->open(deviceId) != AAUDIO_OK) { - ALOGE("AAudioEndpointManager::openEndpoint(), open failed"); - delete player; - } else { - mOutputs[deviceId] = player; + break; + case AAUDIO_DIRECTION_OUTPUT: + player = new AAudioServiceEndpointPlay(audioService); endpoint = player; - } + break; + default: + break; } + if (endpoint != nullptr) { + aaudio_result_t result = endpoint->open(configuration); + if (result != AAUDIO_OK) { + ALOGE("AAudioEndpointManager::findEndpoint(), open failed"); + delete endpoint; + endpoint = nullptr; + } else { + switch(direction) { + case AAUDIO_DIRECTION_INPUT: + mInputs.push_back(capture); + break; + case AAUDIO_DIRECTION_OUTPUT: + mOutputs.push_back(player); + break; + default: + break; + } + } + } + ALOGD("AAudioEndpointManager::openEndpoint(), created %p for device = %d, dir = %d", + endpoint, configuration.getDeviceId(), (int)direction); + IPCThreadState::self()->restoreCallingIdentity(token); } if (endpoint != nullptr) { + ALOGD("AAudioEndpointManager::openEndpoint(), sampleRate = %d, framesPerBurst = %d", + endpoint->getSampleRate(), endpoint->getFramesPerBurst()); // Increment the reference count under this lock. endpoint->setReferenceCount(endpoint->getReferenceCount() + 1); } @@ -95,20 +161,32 @@ void AAudioEndpointManager::closeEndpoint(AAudioServiceEndpoint *serviceEndpoint // Decrement the reference count under this lock. int32_t newRefCount = serviceEndpoint->getReferenceCount() - 1; serviceEndpoint->setReferenceCount(newRefCount); + ALOGD("AAudioEndpointManager::closeEndpoint(%p) newRefCount = %d", + serviceEndpoint, newRefCount); + + // If no longer in use then close and delete it. if (newRefCount <= 0) { aaudio_direction_t direction = serviceEndpoint->getDirection(); - int32_t deviceId = serviceEndpoint->getDeviceId(); + // Track endpoints based on requested deviceId because UNSPECIFIED + // can change to a specific device after opening. + int32_t deviceId = serviceEndpoint->getRequestedDeviceId(); switch (direction) { case AAUDIO_DIRECTION_INPUT: - mInputs.erase(deviceId); + mInputs.erase( + std::remove(mInputs.begin(), mInputs.end(), serviceEndpoint), mInputs.end()); break; case AAUDIO_DIRECTION_OUTPUT: - mOutputs.erase(deviceId); + mOutputs.erase( + std::remove(mOutputs.begin(), mOutputs.end(), serviceEndpoint), mOutputs.end()); + break; + default: break; } serviceEndpoint->close(); + ALOGD("AAudioEndpointManager::closeEndpoint() delete %p for device %d, dir = %d", + serviceEndpoint, deviceId, (int)direction); delete serviceEndpoint; } } diff --git a/services/oboeservice/AAudioEndpointManager.h b/services/oboeservice/AAudioEndpointManager.h index db1103dc9c..2511b2fdeb 100644 --- a/services/oboeservice/AAudioEndpointManager.h +++ b/services/oboeservice/AAudioEndpointManager.h @@ -34,25 +34,37 @@ public: ~AAudioEndpointManager() = default; /** + * Returns information about the state of the this class. + * + * Will attempt to get the object lock, but will proceed + * even if it cannot. + * + * Each line of information ends with a newline. + * + * @return a string with useful information + */ + std::string dump() const; + + /** * Find a service endpoint for the given deviceId and direction. - * If an endpoint does not already exist then it will try to create one. + * If an endpoint does not already exist then try to create one. * * @param deviceId * @param direction * @return endpoint or nullptr */ AAudioServiceEndpoint *openEndpoint(android::AAudioService &audioService, - int32_t deviceId, + const AAudioStreamConfiguration& configuration, aaudio_direction_t direction); void closeEndpoint(AAudioServiceEndpoint *serviceEndpoint); private: - std::mutex mLock; + mutable std::mutex mLock; - std::map<int32_t, AAudioServiceEndpointCapture *> mInputs; - std::map<int32_t, AAudioServiceEndpointPlay *> mOutputs; + std::vector<AAudioServiceEndpointCapture *> mInputs; + std::vector<AAudioServiceEndpointPlay *> mOutputs; }; diff --git a/services/oboeservice/AAudioMixer.cpp b/services/oboeservice/AAudioMixer.cpp index 43203d4b67..952aa82587 100644 --- a/services/oboeservice/AAudioMixer.cpp +++ b/services/oboeservice/AAudioMixer.cpp @@ -18,9 +18,17 @@ //#define LOG_NDEBUG 0 #include <utils/Log.h> +#define ATRACE_TAG ATRACE_TAG_AUDIO + #include <cstring> +#include <utils/Trace.h> + #include "AAudioMixer.h" +#ifndef AAUDIO_MIXER_ATRACE_ENABLED +#define AAUDIO_MIXER_ATRACE_ENABLED 1 +#endif + using android::WrappingBuffer; using android::FifoBuffer; using android::fifo_frames_t; @@ -41,13 +49,28 @@ void AAudioMixer::clear() { memset(mOutputBuffer, 0, mBufferSizeInBytes); } -bool AAudioMixer::mix(FifoBuffer *fifo, float volume) { +bool AAudioMixer::mix(int trackIndex, FifoBuffer *fifo, float volume) { WrappingBuffer wrappingBuffer; float *destination = mOutputBuffer; fifo_frames_t framesLeft = mFramesPerBurst; +#if AAUDIO_MIXER_ATRACE_ENABLED + ATRACE_BEGIN("aaMix"); +#endif /* AAUDIO_MIXER_ATRACE_ENABLED */ + // Gather the data from the client. May be in two parts. - fifo->getFullDataAvailable(&wrappingBuffer); + fifo_frames_t fullFrames = fifo->getFullDataAvailable(&wrappingBuffer); +#if AAUDIO_MIXER_ATRACE_ENABLED + if (ATRACE_ENABLED()) { + char rdyText[] = "aaMixRdy#"; + char letter = 'A' + (trackIndex % 26); + rdyText[sizeof(rdyText) - 2] = letter; + ATRACE_INT(rdyText, fullFrames); + } +#else /* MIXER_ATRACE_ENABLED */ + (void) trackIndex; + (void) fullFrames; +#endif /* AAUDIO_MIXER_ATRACE_ENABLED */ // Mix data in one or two parts. int partIndex = 0; @@ -65,11 +88,15 @@ bool AAudioMixer::mix(FifoBuffer *fifo, float volume) { } partIndex++; } - fifo->getFifoControllerBase()->advanceReadIndex(mFramesPerBurst - framesLeft); - if (framesLeft > 0) { - //ALOGW("AAudioMixer::mix() UNDERFLOW by %d / %d frames ----- UNDERFLOW !!!!!!!!!!", - // framesLeft, mFramesPerBurst); - } + // Always advance by one burst even if we do not have the data. + // Otherwise the stream timing will drift whenever there is an underflow. + // This actual underflow can then be detected by the client for XRun counting. + fifo->getFifoControllerBase()->advanceReadIndex(mFramesPerBurst); + +#if AAUDIO_MIXER_ATRACE_ENABLED + ATRACE_END(); +#endif /* AAUDIO_MIXER_ATRACE_ENABLED */ + return (framesLeft > 0); // did not get all the frames we needed, ie. "underflow" } diff --git a/services/oboeservice/AAudioMixer.h b/services/oboeservice/AAudioMixer.h index 9155fec771..a8090bcaf5 100644 --- a/services/oboeservice/AAudioMixer.h +++ b/services/oboeservice/AAudioMixer.h @@ -37,7 +37,7 @@ public: * @param volume * @return true if underflowed */ - bool mix(android::FifoBuffer *fifo, float volume); + bool mix(int trackIndex, android::FifoBuffer *fifo, float volume); void mixPart(float *destination, float *source, int32_t numFrames, float volume); diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp index c9b9065082..3992719280 100644 --- a/services/oboeservice/AAudioService.cpp +++ b/services/oboeservice/AAudioService.cpp @@ -18,6 +18,7 @@ //#define LOG_NDEBUG 0 #include <utils/Log.h> +#include <sstream> //#include <time.h> //#include <pthread.h> @@ -26,16 +27,21 @@ #include <utils/String16.h> #include "binding/AAudioServiceMessage.h" +#include "AAudioClientTracker.h" +#include "AAudioEndpointManager.h" #include "AAudioService.h" #include "AAudioServiceStreamMMAP.h" #include "AAudioServiceStreamShared.h" #include "AAudioServiceStreamMMAP.h" #include "binding/IAAudioService.h" +#include "ServiceUtilities.h" #include "utility/HandleTracker.h" using namespace android; using namespace aaudio; +#define MAX_STREAMS_PER_PROCESS 8 + typedef enum { AAUDIO_HANDLE_TYPE_STREAM @@ -44,32 +50,76 @@ static_assert(AAUDIO_HANDLE_TYPE_STREAM < HANDLE_TRACKER_MAX_TYPES, "Too many ha android::AAudioService::AAudioService() : BnAAudioService() { + mAudioClient.clientUid = getuid(); // TODO consider using geteuid() + mAudioClient.clientPid = getpid(); + mAudioClient.packageName = String16(""); + AAudioClientTracker::getInstance().setAAudioService(this); } AAudioService::~AAudioService() { } +status_t AAudioService::dump(int fd, const Vector<String16>& args) { + std::string result; + + if (!dumpAllowed()) { + std::stringstream ss; + ss << "Permission denial: can't dump AAudioService from pid=" + << IPCThreadState::self()->getCallingPid() << ", uid=" + << IPCThreadState::self()->getCallingUid() << "\n"; + result = ss.str(); + ALOGW("%s", result.c_str()); + } else { + result = mHandleTracker.dump() + + AAudioClientTracker::getInstance().dump() + + AAudioEndpointManager::getInstance().dump(); + } + (void)write(fd, result.c_str(), result.size()); + return NO_ERROR; +} + +void AAudioService::registerClient(const sp<IAAudioClient>& client) { + pid_t pid = IPCThreadState::self()->getCallingPid(); + AAudioClientTracker::getInstance().registerClient(pid, client); +} + aaudio_handle_t AAudioService::openStream(const aaudio::AAudioStreamRequest &request, aaudio::AAudioStreamConfiguration &configurationOutput) { aaudio_result_t result = AAUDIO_OK; - AAudioServiceStreamBase *serviceStream = nullptr; + sp<AAudioServiceStreamBase> serviceStream; const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration(); bool sharingModeMatchRequired = request.isSharingModeMatchRequired(); aaudio_sharing_mode_t sharingMode = configurationInput.getSharingMode(); + // Enforce limit on client processes. + pid_t pid = request.getProcessId(); + if (pid != mAudioClient.clientPid) { + int32_t count = AAudioClientTracker::getInstance().getStreamCount(pid); + if (count >= MAX_STREAMS_PER_PROCESS) { + ALOGE("AAudioService::openStream(): exceeded max streams per process %d >= %d", + count, MAX_STREAMS_PER_PROCESS); + return AAUDIO_ERROR_UNAVAILABLE; + } + } + if (sharingMode != AAUDIO_SHARING_MODE_EXCLUSIVE && sharingMode != AAUDIO_SHARING_MODE_SHARED) { ALOGE("AAudioService::openStream(): unrecognized sharing mode = %d", sharingMode); return AAUDIO_ERROR_ILLEGAL_ARGUMENT; } if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) { - serviceStream = new AAudioServiceStreamMMAP(); + // only trust audioserver for in service indication + bool inService = false; + if (mAudioClient.clientPid == IPCThreadState::self()->getCallingPid() && + mAudioClient.clientUid == IPCThreadState::self()->getCallingUid()) { + inService = request.isInService(); + } + serviceStream = new AAudioServiceStreamMMAP(mAudioClient, inService); result = serviceStream->open(request, configurationOutput); if (result != AAUDIO_OK) { // fall back to using a shared stream - ALOGD("AAudioService::openStream(), EXCLUSIVE mode failed"); - delete serviceStream; - serviceStream = nullptr; + ALOGW("AAudioService::openStream(), could not open in EXCLUSIVE mode"); + serviceStream.clear(); } else { configurationOutput.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE); } @@ -84,28 +134,43 @@ aaudio_handle_t AAudioService::openStream(const aaudio::AAudioStreamRequest &req } if (result != AAUDIO_OK) { - delete serviceStream; - ALOGE("AAudioService::openStream(): failed, return %d", result); + serviceStream.clear(); + ALOGE("AAudioService::openStream(): failed, return %d = %s", + result, AAudio_convertResultToText(result)); return result; } else { - aaudio_handle_t handle = mHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, serviceStream); - ALOGV("AAudioService::openStream(): handle = 0x%08X", handle); + aaudio_handle_t handle = mHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, serviceStream.get()); if (handle < 0) { ALOGE("AAudioService::openStream(): handle table full"); - delete serviceStream; + serviceStream->close(); + serviceStream.clear(); + } else { + ALOGD("AAudioService::openStream(): handle = 0x%08X", handle); + serviceStream->setHandle(handle); + pid_t pid = request.getProcessId(); + AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream); } return handle; } } aaudio_result_t AAudioService::closeStream(aaudio_handle_t streamHandle) { - AAudioServiceStreamBase *serviceStream = (AAudioServiceStreamBase *) + // Check permission and ownership first. + sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle); + if (serviceStream == nullptr) { + ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle); + return AAUDIO_ERROR_INVALID_HANDLE; + } + + ALOGD("AAudioService.closeStream(0x%08X)", streamHandle); + // Remove handle from tracker so that we cannot look up the raw address any more. + serviceStream = (AAudioServiceStreamBase *) mHandleTracker.remove(AAUDIO_HANDLE_TYPE_STREAM, streamHandle); - ALOGV("AAudioService.closeStream(0x%08X)", streamHandle); if (serviceStream != nullptr) { serviceStream->close(); - delete serviceStream; + pid_t pid = serviceStream->getOwnerProcessId(); + AAudioClientTracker::getInstance().unregisterClientStream(pid, serviceStream); return AAUDIO_OK; } return AAUDIO_ERROR_INVALID_HANDLE; @@ -113,8 +178,23 @@ aaudio_result_t AAudioService::closeStream(aaudio_handle_t streamHandle) { AAudioServiceStreamBase *AAudioService::convertHandleToServiceStream( aaudio_handle_t streamHandle) const { - return (AAudioServiceStreamBase *) mHandleTracker.get(AAUDIO_HANDLE_TYPE_STREAM, - (aaudio_handle_t)streamHandle); + AAudioServiceStreamBase *serviceStream = (AAudioServiceStreamBase *) + mHandleTracker.get(AAUDIO_HANDLE_TYPE_STREAM, (aaudio_handle_t)streamHandle); + if (serviceStream != nullptr) { + // Only allow owner or the aaudio service to access the stream. + const uid_t callingUserId = IPCThreadState::self()->getCallingUid(); + const uid_t ownerUserId = serviceStream->getOwnerUserId(); + bool callerOwnsIt = callingUserId == ownerUserId; + bool serverCalling = callingUserId == mAudioClient.clientUid; + bool serverOwnsIt = ownerUserId == mAudioClient.clientUid; + bool allowed = callerOwnsIt || serverCalling || serverOwnsIt; + if (!allowed) { + ALOGE("AAudioService: calling uid %d cannot access stream 0x%08X owned by %d", + callingUserId, streamHandle, ownerUserId); + serviceStream = nullptr; + } + } + return serviceStream; } aaudio_result_t AAudioService::getStreamDescription( @@ -136,6 +216,7 @@ aaudio_result_t AAudioService::startStream(aaudio_handle_t streamHandle) { ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle); return AAUDIO_ERROR_INVALID_HANDLE; } + aaudio_result_t result = serviceStream->start(); return result; } @@ -170,9 +251,8 @@ aaudio_result_t AAudioService::flushStream(aaudio_handle_t streamHandle) { } aaudio_result_t AAudioService::registerAudioThread(aaudio_handle_t streamHandle, - pid_t clientProcessId, - pid_t clientThreadId, - int64_t periodNanoseconds) { + pid_t clientThreadId, + int64_t periodNanoseconds) { AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle); if (serviceStream == nullptr) { ALOGE("AAudioService::registerAudioThread(), illegal stream handle = 0x%0x", streamHandle); @@ -182,12 +262,14 @@ aaudio_result_t AAudioService::registerAudioThread(aaudio_handle_t streamHandle, ALOGE("AAudioService::registerAudioThread(), thread already registered"); return AAUDIO_ERROR_INVALID_STATE; } + + const pid_t ownerPid = IPCThreadState::self()->getCallingPid(); // TODO review serviceStream->setRegisteredThread(clientThreadId); - int err = android::requestPriority(clientProcessId, clientThreadId, + int err = android::requestPriority(ownerPid, clientThreadId, DEFAULT_AUDIO_PRIORITY, true /* isForApp */); if (err != 0){ - ALOGE("AAudioService::registerAudioThread() failed, errno = %d, priority = %d", - errno, DEFAULT_AUDIO_PRIORITY); + ALOGE("AAudioService::registerAudioThread(%d) failed, errno = %d, priority = %d", + clientThreadId, errno, DEFAULT_AUDIO_PRIORITY); return AAUDIO_ERROR_INTERNAL; } else { return AAUDIO_OK; @@ -195,7 +277,6 @@ aaudio_result_t AAudioService::registerAudioThread(aaudio_handle_t streamHandle, } aaudio_result_t AAudioService::unregisterAudioThread(aaudio_handle_t streamHandle, - pid_t clientProcessId, pid_t clientThreadId) { AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle); if (serviceStream == nullptr) { @@ -210,3 +291,26 @@ aaudio_result_t AAudioService::unregisterAudioThread(aaudio_handle_t streamHandl serviceStream->setRegisteredThread(0); return AAUDIO_OK; } + +aaudio_result_t AAudioService::startClient(aaudio_handle_t streamHandle, + const android::AudioClient& client, + audio_port_handle_t *clientHandle) { + AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle); + if (serviceStream == nullptr) { + ALOGE("AAudioService::startClient(), illegal stream handle = 0x%0x", + streamHandle); + return AAUDIO_ERROR_INVALID_HANDLE; + } + return serviceStream->startClient(client, clientHandle); +} + +aaudio_result_t AAudioService::stopClient(aaudio_handle_t streamHandle, + audio_port_handle_t clientHandle) { + AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle); + if (serviceStream == nullptr) { + ALOGE("AAudioService::stopClient(), illegal stream handle = 0x%0x", + streamHandle); + return AAUDIO_ERROR_INVALID_HANDLE; + } + return serviceStream->stopClient(clientHandle); +} diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h index f5a7d2f991..8421efc858 100644 --- a/services/oboeservice/AAudioService.h +++ b/services/oboeservice/AAudioService.h @@ -21,6 +21,7 @@ #include <pthread.h> #include <binder/BinderService.h> +#include <media/AudioClient.h> #include <aaudio/AAudio.h> #include "utility/HandleTracker.h" @@ -44,8 +45,12 @@ public: static const char* getServiceName() { return AAUDIO_SERVICE_NAME; } + virtual status_t dump(int fd, const Vector<String16>& args) override; + + virtual void registerClient(const sp<IAAudioClient>& client); + virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request, - aaudio::AAudioStreamConfiguration &configuration); + aaudio::AAudioStreamConfiguration &configurationOutput); virtual aaudio_result_t closeStream(aaudio_handle_t streamHandle); @@ -62,11 +67,18 @@ public: virtual aaudio_result_t flushStream(aaudio_handle_t streamHandle); virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle, - pid_t pid, pid_t tid, - int64_t periodNanoseconds) ; + pid_t tid, + int64_t periodNanoseconds) ; virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle, - pid_t pid, pid_t tid); + pid_t tid); + + virtual aaudio_result_t startClient(aaudio_handle_t streamHandle, + const android::AudioClient& client, + audio_port_handle_t *clientHandle); + + virtual aaudio_result_t stopClient(aaudio_handle_t streamHandle, + audio_port_handle_t clientHandle); private: @@ -74,6 +86,8 @@ private: HandleTracker mHandleTracker; + android::AudioClient mAudioClient; + enum constants { DEFAULT_AUDIO_PRIORITY = 2 }; diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp index d8ae284ac2..0f863fe160 100644 --- a/services/oboeservice/AAudioServiceEndpoint.cpp +++ b/services/oboeservice/AAudioServiceEndpoint.cpp @@ -14,20 +14,21 @@ * limitations under the License. */ -#define LOG_TAG "AAudioService" +#define LOG_TAG "AAudioServiceEndpoint" //#define LOG_NDEBUG 0 #include <utils/Log.h> +#include <algorithm> #include <assert.h> #include <map> #include <mutex> +#include <sstream> +#include <vector> + #include <utils/Singleton.h> #include "AAudioEndpointManager.h" #include "AAudioServiceEndpoint.h" -#include <algorithm> -#include <mutex> -#include <vector> #include "core/AudioStreamBuilder.h" #include "AAudioServiceEndpoint.h" @@ -44,15 +45,48 @@ using namespace aaudio; // TODO just import names needed // This is the maximum size in frames. The effective size can be tuned smaller at runtime. #define DEFAULT_BUFFER_CAPACITY (48 * 8) +std::string AAudioServiceEndpoint::dump() const { + std::stringstream result; + + const bool isLocked = AAudio_tryUntilTrue( + [this]()->bool { return mLockStreams.try_lock(); } /* f */, + 50 /* times */, + 20 /* sleepMs */); + if (!isLocked) { + result << "EndpointManager may be deadlocked\n"; + } + + AudioStreamInternal *stream = mStreamInternal; + if (stream == nullptr) { + result << "null stream!" << "\n"; + } else { + result << "mmap stream: rate = " << stream->getSampleRate() << "\n"; + } + + result << " Registered Streams:" << "\n"; + for (sp<AAudioServiceStreamShared> sharedStream : mRegisteredStreams) { + result << sharedStream->dump(); + } + + if (isLocked) { + mLockStreams.unlock(); + } + return result.str(); +} + // Set up an EXCLUSIVE MMAP stream that will be shared. -aaudio_result_t AAudioServiceEndpoint::open(int32_t deviceId) { +aaudio_result_t AAudioServiceEndpoint::open(const AAudioStreamConfiguration& configuration) { + mRequestedDeviceId = configuration.getDeviceId(); mStreamInternal = getStreamInternal(); AudioStreamBuilder builder; builder.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE); // Don't fall back to SHARED because that would cause recursion. builder.setSharingModeMatchRequired(true); - builder.setDeviceId(deviceId); + builder.setDeviceId(mRequestedDeviceId); + builder.setFormat(configuration.getFormat()); + builder.setSampleRate(configuration.getSampleRate()); + builder.setSamplesPerFrame(configuration.getSamplesPerFrame()); builder.setDirection(getDirection()); builder.setBufferCapacity(DEFAULT_BUFFER_CAPACITY); @@ -60,45 +94,39 @@ aaudio_result_t AAudioServiceEndpoint::open(int32_t deviceId) { } aaudio_result_t AAudioServiceEndpoint::close() { - return getStreamInternal()->close(); + return getStreamInternal()->close(); } // TODO, maybe use an interface to reduce exposure -aaudio_result_t AAudioServiceEndpoint::registerStream(AAudioServiceStreamShared *sharedStream) { +aaudio_result_t AAudioServiceEndpoint::registerStream(sp<AAudioServiceStreamShared>sharedStream) { std::lock_guard<std::mutex> lock(mLockStreams); mRegisteredStreams.push_back(sharedStream); return AAUDIO_OK; } -aaudio_result_t AAudioServiceEndpoint::unregisterStream(AAudioServiceStreamShared *sharedStream) { +aaudio_result_t AAudioServiceEndpoint::unregisterStream(sp<AAudioServiceStreamShared>sharedStream) { std::lock_guard<std::mutex> lock(mLockStreams); mRegisteredStreams.erase(std::remove(mRegisteredStreams.begin(), mRegisteredStreams.end(), sharedStream), mRegisteredStreams.end()); return AAUDIO_OK; } -aaudio_result_t AAudioServiceEndpoint::startStream(AAudioServiceStreamShared *sharedStream) { - // TODO use real-time technique to avoid mutex, eg. atomic command FIFO - std::lock_guard<std::mutex> lock(mLockStreams); - mRunningStreams.push_back(sharedStream); - if (mRunningStreams.size() == 1) { +aaudio_result_t AAudioServiceEndpoint::startStream(sp<AAudioServiceStreamShared> sharedStream) { + aaudio_result_t result = AAUDIO_OK; + if (++mRunningStreams == 1) { + // TODO use real-time technique to avoid mutex, eg. atomic command FIFO + std::lock_guard<std::mutex> lock(mLockStreams); + result = getStreamInternal()->requestStart(); startSharingThread_l(); } - return AAUDIO_OK; + return result; } -aaudio_result_t AAudioServiceEndpoint::stopStream(AAudioServiceStreamShared *sharedStream) { - int numRunningStreams = 0; - { - std::lock_guard<std::mutex> lock(mLockStreams); - mRunningStreams.erase( - std::remove(mRunningStreams.begin(), mRunningStreams.end(), sharedStream), - mRunningStreams.end()); - numRunningStreams = mRunningStreams.size(); - } - if (numRunningStreams == 0) { - // Don't call this under a lock because the callbackLoop also uses the lock. +aaudio_result_t AAudioServiceEndpoint::stopStream(sp<AAudioServiceStreamShared> sharedStream) { + // Don't lock here because the disconnectRegisteredStreams also uses the lock. + if (--mRunningStreams == 0) { // atomic stopSharingThread(); + getStreamInternal()->requestStop(); } return AAUDIO_OK; } @@ -129,12 +157,27 @@ aaudio_result_t AAudioServiceEndpoint::stopSharingThread() { void AAudioServiceEndpoint::disconnectRegisteredStreams() { std::lock_guard<std::mutex> lock(mLockStreams); - for(AAudioServiceStreamShared *sharedStream : mRunningStreams) { - sharedStream->onStop(); - } - mRunningStreams.clear(); - for(AAudioServiceStreamShared *sharedStream : mRegisteredStreams) { - sharedStream->onDisconnect(); + for(auto sharedStream : mRegisteredStreams) { + sharedStream->stop(); + sharedStream->disconnect(); } mRegisteredStreams.clear(); } + +bool AAudioServiceEndpoint::matches(const AAudioStreamConfiguration& configuration) { + if (configuration.getDeviceId() != AAUDIO_UNSPECIFIED && + configuration.getDeviceId() != mStreamInternal->getDeviceId()) { + return false; + } + if (configuration.getSampleRate() != AAUDIO_UNSPECIFIED && + configuration.getSampleRate() != mStreamInternal->getSampleRate()) { + return false; + } + if (configuration.getSamplesPerFrame() != AAUDIO_UNSPECIFIED && + configuration.getSamplesPerFrame() != mStreamInternal->getSamplesPerFrame()) { + return false; + } + + return true; +} + diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h index 50bf0490e7..e40a6708ab 100644 --- a/services/oboeservice/AAudioServiceEndpoint.h +++ b/services/oboeservice/AAudioServiceEndpoint.h @@ -36,18 +36,21 @@ class AAudioServiceEndpoint { public: virtual ~AAudioServiceEndpoint() = default; - virtual aaudio_result_t open(int32_t deviceId); + std::string dump() const; + + virtual aaudio_result_t open(const AAudioStreamConfiguration& configuration); int32_t getSampleRate() const { return mStreamInternal->getSampleRate(); } int32_t getSamplesPerFrame() const { return mStreamInternal->getSamplesPerFrame(); } int32_t getFramesPerBurst() const { return mStreamInternal->getFramesPerBurst(); } - aaudio_result_t registerStream(AAudioServiceStreamShared *sharedStream); - aaudio_result_t unregisterStream(AAudioServiceStreamShared *sharedStream); - aaudio_result_t startStream(AAudioServiceStreamShared *sharedStream); - aaudio_result_t stopStream(AAudioServiceStreamShared *sharedStream); + aaudio_result_t registerStream(android::sp<AAudioServiceStreamShared> sharedStream); + aaudio_result_t unregisterStream(android::sp<AAudioServiceStreamShared> sharedStream); + aaudio_result_t startStream(android::sp<AAudioServiceStreamShared> sharedStream); + aaudio_result_t stopStream(android::sp<AAudioServiceStreamShared> sharedStream); aaudio_result_t close(); + int32_t getRequestedDeviceId() const { return mRequestedDeviceId; } int32_t getDeviceId() const { return mStreamInternal->getDeviceId(); } aaudio_direction_t getDirection() const { return mStreamInternal->getDirection(); } @@ -66,14 +69,17 @@ public: mReferenceCount = count; } + bool matches(const AAudioStreamConfiguration& configuration); + virtual AudioStreamInternal *getStreamInternal() = 0; - std::atomic<bool> mCallbackEnabled; + std::atomic<bool> mCallbackEnabled{false}; + + mutable std::mutex mLockStreams; - std::mutex mLockStreams; + std::vector<android::sp<AAudioServiceStreamShared>> mRegisteredStreams; - std::vector<AAudioServiceStreamShared *> mRegisteredStreams; - std::vector<AAudioServiceStreamShared *> mRunningStreams; + std::atomic<int> mRunningStreams{0}; private: aaudio_result_t startSharingThread_l(); @@ -81,6 +87,7 @@ private: AudioStreamInternal *mStreamInternal = nullptr; int32_t mReferenceCount = 0; + int32_t mRequestedDeviceId = 0; }; } /* namespace aaudio */ diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp index 29d6cb9818..6a373308a4 100644 --- a/services/oboeservice/AAudioServiceEndpointCapture.cpp +++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp @@ -42,8 +42,8 @@ AAudioServiceEndpointCapture::~AAudioServiceEndpointCapture() { delete mDistributionBuffer; } -aaudio_result_t AAudioServiceEndpointCapture::open(int32_t deviceId) { - aaudio_result_t result = AAudioServiceEndpoint::open(deviceId); +aaudio_result_t AAudioServiceEndpointCapture::open(const AAudioStreamConfiguration& configuration) { + aaudio_result_t result = AAudioServiceEndpoint::open(configuration); if (result == AAUDIO_OK) { delete mDistributionBuffer; int distributionBufferSizeBytes = getStreamInternal()->getFramesPerBurst() @@ -57,9 +57,7 @@ aaudio_result_t AAudioServiceEndpointCapture::open(int32_t deviceId) { void *AAudioServiceEndpointCapture::callbackLoop() { ALOGD("AAudioServiceEndpointCapture(): callbackLoop() entering"); int32_t underflowCount = 0; - - aaudio_result_t result = getStreamInternal()->requestStart(); - + aaudio_result_t result = AAUDIO_OK; int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout(); // result might be a frame count @@ -78,21 +76,21 @@ void *AAudioServiceEndpointCapture::callbackLoop() { // Distribute data to each active stream. { // use lock guard std::lock_guard <std::mutex> lock(mLockStreams); - for (AAudioServiceStreamShared *sharedStream : mRunningStreams) { - FifoBuffer *fifo = sharedStream->getDataFifoBuffer(); - if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() < - getFramesPerBurst()) { - underflowCount++; - } else { - fifo->write(mDistributionBuffer, getFramesPerBurst()); + for (sp<AAudioServiceStreamShared> sharedStream : mRegisteredStreams) { + if (sharedStream->isRunning()) { + FifoBuffer *fifo = sharedStream->getDataFifoBuffer(); + if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() < + getFramesPerBurst()) { + underflowCount++; + } else { + fifo->write(mDistributionBuffer, getFramesPerBurst()); + } + sharedStream->markTransferTime(AudioClock::getNanoseconds()); } - sharedStream->markTransferTime(AudioClock::getNanoseconds()); } } } - result = getStreamInternal()->requestStop(); - ALOGD("AAudioServiceEndpointCapture(): callbackLoop() exiting, %d underflows", underflowCount); return NULL; // TODO review } diff --git a/services/oboeservice/AAudioServiceEndpointCapture.h b/services/oboeservice/AAudioServiceEndpointCapture.h index 35857d19ea..8a3d72ff7e 100644 --- a/services/oboeservice/AAudioServiceEndpointCapture.h +++ b/services/oboeservice/AAudioServiceEndpointCapture.h @@ -27,7 +27,7 @@ public: explicit AAudioServiceEndpointCapture(android::AAudioService &audioService); virtual ~AAudioServiceEndpointCapture(); - aaudio_result_t open(int32_t deviceId) override; + aaudio_result_t open(const AAudioStreamConfiguration& configuration) override; AudioStreamInternal *getStreamInternal() override { return &mStreamInternalCapture; diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp index cc09cc3d8b..b83b918798 100644 --- a/services/oboeservice/AAudioServiceEndpointPlay.cpp +++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp @@ -46,8 +46,8 @@ AAudioServiceEndpointPlay::AAudioServiceEndpointPlay(AAudioService &audioService AAudioServiceEndpointPlay::~AAudioServiceEndpointPlay() { } -aaudio_result_t AAudioServiceEndpointPlay::open(int32_t deviceId) { - aaudio_result_t result = AAudioServiceEndpoint::open(deviceId); +aaudio_result_t AAudioServiceEndpointPlay::open(const AAudioStreamConfiguration& configuration) { + aaudio_result_t result = AAudioServiceEndpoint::open(configuration); if (result == AAUDIO_OK) { mMixer.allocate(getStreamInternal()->getSamplesPerFrame(), getStreamInternal()->getFramesPerBurst()); @@ -57,7 +57,6 @@ aaudio_result_t AAudioServiceEndpointPlay::open(int32_t deviceId) { mLatencyTuningEnabled = true; burstsPerBuffer = BURSTS_PER_BUFFER_DEFAULT; } - ALOGD("AAudioServiceEndpoint(): burstsPerBuffer = %d", burstsPerBuffer); int32_t desiredBufferSize = burstsPerBuffer * getStreamInternal()->getFramesPerBurst(); getStreamInternal()->setBufferSize(desiredBufferSize); } @@ -66,11 +65,8 @@ aaudio_result_t AAudioServiceEndpointPlay::open(int32_t deviceId) { // Mix data from each application stream and write result to the shared MMAP stream. void *AAudioServiceEndpointPlay::callbackLoop() { - ALOGD("AAudioServiceEndpointPlay(): callbackLoop() entering"); int32_t underflowCount = 0; - - aaudio_result_t result = getStreamInternal()->requestStart(); - + aaudio_result_t result = AAUDIO_OK; int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout(); // result might be a frame count @@ -78,14 +74,18 @@ void *AAudioServiceEndpointPlay::callbackLoop() { // Mix data from each active stream. mMixer.clear(); { // use lock guard + int index = 0; std::lock_guard <std::mutex> lock(mLockStreams); - for (AAudioServiceStreamShared *sharedStream : mRunningStreams) { - FifoBuffer *fifo = sharedStream->getDataFifoBuffer(); - float volume = 0.5; // TODO get from system - bool underflowed = mMixer.mix(fifo, volume); - underflowCount += underflowed ? 1 : 0; - // TODO log underflows in each stream - sharedStream->markTransferTime(AudioClock::getNanoseconds()); + for (sp<AAudioServiceStreamShared> sharedStream : mRegisteredStreams) { + if (sharedStream->isRunning()) { + FifoBuffer *fifo = sharedStream->getDataFifoBuffer(); + float volume = 1.0; // to match legacy volume + bool underflowed = mMixer.mix(index, fifo, volume); + underflowCount += underflowed ? 1 : 0; + // TODO log underflows in each stream + sharedStream->markTransferTime(AudioClock::getNanoseconds()); + } + index++; } } @@ -102,8 +102,8 @@ void *AAudioServiceEndpointPlay::callbackLoop() { } } - result = getStreamInternal()->requestStop(); + ALOGW_IF((underflowCount > 0), + "AAudioServiceEndpointPlay(): callbackLoop() had %d underflows", underflowCount); - ALOGD("AAudioServiceEndpointPlay(): callbackLoop() exiting, %d underflows", underflowCount); return NULL; // TODO review } diff --git a/services/oboeservice/AAudioServiceEndpointPlay.h b/services/oboeservice/AAudioServiceEndpointPlay.h index b9779608c8..c22f510679 100644 --- a/services/oboeservice/AAudioServiceEndpointPlay.h +++ b/services/oboeservice/AAudioServiceEndpointPlay.h @@ -32,12 +32,15 @@ namespace aaudio { +/** + * Contains a mixer and a stream for writing the result of the mix. + */ class AAudioServiceEndpointPlay : public AAudioServiceEndpoint { public: explicit AAudioServiceEndpointPlay(android::AAudioService &audioService); virtual ~AAudioServiceEndpointPlay(); - aaudio_result_t open(int32_t deviceId) override; + aaudio_result_t open(const AAudioStreamConfiguration& configuration) override; AudioStreamInternal *getStreamInternal() override { return &mStreamInternalPlay; diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp index 8f0abc2e43..5f7d1792cd 100644 --- a/services/oboeservice/AAudioServiceStreamBase.cpp +++ b/services/oboeservice/AAudioServiceStreamBase.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "AAudioService" +#define LOG_TAG "AAudioServiceStreamBase" //#define LOG_NDEBUG 0 #include <utils/Log.h> @@ -38,14 +38,42 @@ using namespace aaudio; // TODO just import names needed AAudioServiceStreamBase::AAudioServiceStreamBase() : mUpMessageQueue(nullptr) , mAAudioThread() { + mMmapClient.clientUid = -1; + mMmapClient.clientPid = -1; + mMmapClient.packageName = String16(""); } AAudioServiceStreamBase::~AAudioServiceStreamBase() { - close(); + ALOGD("AAudioServiceStreamBase::~AAudioServiceStreamBase() destroying %p", this); + // If the stream is deleted when OPEN or in use then audio resources will leak. + // This would indicate an internal error. So we want to find this ASAP. + LOG_ALWAYS_FATAL_IF(!(mState == AAUDIO_STREAM_STATE_CLOSED + || mState == AAUDIO_STREAM_STATE_UNINITIALIZED + || mState == AAUDIO_STREAM_STATE_DISCONNECTED), + "service stream still open, state = %d", mState); +} + +std::string AAudioServiceStreamBase::dump() const { + std::stringstream result; + + result << " -------- handle = 0x" << std::hex << mHandle << std::dec << "\n"; + result << " state = " << AAudio_convertStreamStateToText(mState) << "\n"; + result << " format = " << mAudioFormat << "\n"; + result << " framesPerBurst = " << mFramesPerBurst << "\n"; + result << " channelCount = " << mSamplesPerFrame << "\n"; + result << " capacityFrames = " << mCapacityInFrames << "\n"; + result << " owner uid = " << mMmapClient.clientUid << "\n"; + + return result.str(); } aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request, aaudio::AAudioStreamConfiguration &configurationOutput) { + + mMmapClient.clientUid = request.getUserId(); + mMmapClient.clientPid = request.getProcessId(); + mMmapClient.packageName.setTo(String16("")); // FIXME what should we do here? + std::lock_guard<std::mutex> lock(mLockUpMessageQueue); if (mUpMessageQueue != nullptr) { return AAUDIO_ERROR_INVALID_STATE; @@ -56,14 +84,20 @@ aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest } aaudio_result_t AAudioServiceStreamBase::close() { - std::lock_guard<std::mutex> lock(mLockUpMessageQueue); - delete mUpMessageQueue; - mUpMessageQueue = nullptr; - + if (mState != AAUDIO_STREAM_STATE_CLOSED) { + stopTimestampThread(); + std::lock_guard<std::mutex> lock(mLockUpMessageQueue); + delete mUpMessageQueue; + mUpMessageQueue = nullptr; + mState = AAUDIO_STREAM_STATE_CLOSED; + } return AAUDIO_OK; } aaudio_result_t AAudioServiceStreamBase::start() { + if (isRunning()) { + return AAUDIO_OK; + } sendServiceEvent(AAUDIO_SERVICE_EVENT_STARTED); mState = AAUDIO_STREAM_STATE_STARTED; mThreadEnabled.store(true); @@ -71,12 +105,15 @@ aaudio_result_t AAudioServiceStreamBase::start() { } aaudio_result_t AAudioServiceStreamBase::pause() { - + aaudio_result_t result = AAUDIO_OK; + if (!isRunning()) { + return result; + } sendCurrentTimestamp(); mThreadEnabled.store(false); - aaudio_result_t result = mAAudioThread.stop(); + result = mAAudioThread.stop(); if (result != AAUDIO_OK) { - processError(); + disconnect(); return result; } sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED); @@ -85,12 +122,15 @@ aaudio_result_t AAudioServiceStreamBase::pause() { } aaudio_result_t AAudioServiceStreamBase::stop() { + aaudio_result_t result = AAUDIO_OK; + if (!isRunning()) { + return result; + } // TODO wait for data to be played out - sendCurrentTimestamp(); - mThreadEnabled.store(false); - aaudio_result_t result = mAAudioThread.stop(); + sendCurrentTimestamp(); // warning - this calls a virtual function + result = stopTimestampThread(); if (result != AAUDIO_OK) { - processError(); + disconnect(); return result; } sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED); @@ -98,6 +138,15 @@ aaudio_result_t AAudioServiceStreamBase::stop() { return result; } +aaudio_result_t AAudioServiceStreamBase::stopTimestampThread() { + aaudio_result_t result = AAUDIO_OK; + // clear flag that tells thread to loop + if (mThreadEnabled.exchange(false)) { + result = mAAudioThread.stop(); + } + return result; +} + aaudio_result_t AAudioServiceStreamBase::flush() { sendServiceEvent(AAUDIO_SERVICE_EVENT_FLUSHED); mState = AAUDIO_STREAM_STATE_FLUSHED; @@ -120,14 +169,18 @@ void AAudioServiceStreamBase::run() { nextTime = timestampScheduler.nextAbsoluteTime(); } else { // Sleep until it is time to send the next timestamp. + // TODO Wait for a signal with a timeout so that we can stop more quickly. AudioClock::sleepUntilNanoTime(nextTime); } } ALOGD("AAudioServiceStreamBase::run() exiting ----------------"); } -void AAudioServiceStreamBase::processError() { - sendServiceEvent(AAUDIO_SERVICE_EVENT_DISCONNECTED); +void AAudioServiceStreamBase::disconnect() { + if (mState != AAUDIO_STREAM_STATE_DISCONNECTED) { + sendServiceEvent(AAUDIO_SERVICE_EVENT_DISCONNECTED); + mState = AAUDIO_STREAM_STATE_DISCONNECTED; + } } aaudio_result_t AAudioServiceStreamBase::sendServiceEvent(aaudio_service_event_t event, @@ -166,6 +219,8 @@ aaudio_result_t AAudioServiceStreamBase::sendCurrentTimestamp() { // (long long) command.timestamp.timestamp); command.what = AAudioServiceMessage::code::TIMESTAMP; result = writeUpMessageQueue(&command); + } else if (result == AAUDIO_ERROR_UNAVAILABLE) { + result = AAUDIO_OK; // just not available yet, try again later } return result; } @@ -179,4 +234,4 @@ aaudio_result_t AAudioServiceStreamBase::getDescription(AudioEndpointParcelable mUpMessageQueue->fillParcelable(parcelable, parcelable.mUpMessageQueueParcelable); return getDownDataDescription(parcelable); -}
\ No newline at end of file +} diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h index ee52c39afd..cebefec08e 100644 --- a/services/oboeservice/AAudioServiceStreamBase.h +++ b/services/oboeservice/AAudioServiceStreamBase.h @@ -20,11 +20,14 @@ #include <assert.h> #include <mutex> +#include <utils/RefBase.h> + #include "fifo/FifoBuffer.h" #include "binding/IAAudioService.h" #include "binding/AudioEndpointParcelable.h" #include "binding/AAudioServiceMessage.h" #include "utility/AAudioUtilities.h" +#include <media/AudioClient.h> #include "SharedRingBuffer.h" #include "AAudioThread.h" @@ -39,7 +42,8 @@ namespace aaudio { * Base class for a stream in the AAudio service. */ class AAudioServiceStreamBase - : public Runnable { + : public virtual android::RefBase + , public Runnable { public: AAudioServiceStreamBase(); @@ -49,6 +53,8 @@ public: ILLEGAL_THREAD_ID = 0 }; + std::string dump() const; + // ------------------------------------------------------------------- /** * Open the device. @@ -73,11 +79,26 @@ public: */ virtual aaudio_result_t stop(); + aaudio_result_t stopTimestampThread(); + /** * Discard any data held by the underlying HAL or Service. */ virtual aaudio_result_t flush(); + virtual aaudio_result_t startClient(const android::AudioClient& client __unused, + audio_port_handle_t *clientHandle __unused) { + return AAUDIO_ERROR_UNAVAILABLE; + } + + virtual aaudio_result_t stopClient(audio_port_handle_t clientHandle __unused) { + return AAUDIO_ERROR_UNAVAILABLE; + } + + bool isRunning() const { + return mState == AAUDIO_STREAM_STATE_STARTED; + } + // ------------------------------------------------------------------- /** @@ -111,33 +132,67 @@ public: void run() override; // to implement Runnable - void processError(); + void disconnect(); + + uid_t getOwnerUserId() const { + return mMmapClient.clientUid; + } + + pid_t getOwnerProcessId() const { + return mMmapClient.clientPid; + } + + aaudio_handle_t getHandle() const { + return mHandle; + } + void setHandle(aaudio_handle_t handle) { + mHandle = handle; + } + + aaudio_stream_state_t getState() const { + return mState; + } protected: + + void setState(aaudio_stream_state_t state) { + mState = state; + } + aaudio_result_t writeUpMessageQueue(AAudioServiceMessage *command); aaudio_result_t sendCurrentTimestamp(); + /** + * @param positionFrames + * @param timeNanos + * @return AAUDIO_OK or AAUDIO_ERROR_UNAVAILABLE or other negative error + */ virtual aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) = 0; virtual aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) = 0; - aaudio_stream_state_t mState = AAUDIO_STREAM_STATE_UNINITIALIZED; + aaudio_stream_state_t mState = AAUDIO_STREAM_STATE_UNINITIALIZED; - pid_t mRegisteredClientThread = ILLEGAL_THREAD_ID; + pid_t mRegisteredClientThread = ILLEGAL_THREAD_ID; - SharedRingBuffer* mUpMessageQueue; - std::mutex mLockUpMessageQueue; + SharedRingBuffer* mUpMessageQueue; + std::mutex mLockUpMessageQueue; - AAudioThread mAAudioThread; + AAudioThread mAAudioThread; // This is used by one thread to tell another thread to exit. So it must be atomic. - std::atomic<bool> mThreadEnabled; - - aaudio_format_t mAudioFormat = AAUDIO_FORMAT_UNSPECIFIED; - int32_t mFramesPerBurst = 0; - int32_t mSamplesPerFrame = AAUDIO_UNSPECIFIED; - int32_t mSampleRate = AAUDIO_UNSPECIFIED; - int32_t mCapacityInFrames = AAUDIO_UNSPECIFIED; + std::atomic<bool> mThreadEnabled; + + aaudio_format_t mAudioFormat = AAUDIO_FORMAT_UNSPECIFIED; + int32_t mFramesPerBurst = 0; + int32_t mSamplesPerFrame = AAUDIO_UNSPECIFIED; + int32_t mSampleRate = AAUDIO_UNSPECIFIED; + int32_t mCapacityInFrames = AAUDIO_UNSPECIFIED; + android::AudioClient mMmapClient; + audio_port_handle_t mClientHandle = AUDIO_PORT_HANDLE_NONE; + +private: + aaudio_handle_t mHandle = -1; }; } /* namespace aaudio */ diff --git a/services/oboeservice/AAudioServiceStreamExclusive.h b/services/oboeservice/AAudioServiceStreamExclusive.h deleted file mode 100644 index db382a3b9d..0000000000 --- a/services/oboeservice/AAudioServiceStreamExclusive.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AAUDIO_AAUDIO_SERVICE_STREAM_EXCLUSIVE_H -#define AAUDIO_AAUDIO_SERVICE_STREAM_EXCLUSIVE_H - -#include "AAudioServiceStreamMMAP.h" - -namespace aaudio { - -/** - * Exclusive mode stream in the AAudio service. - * - * This is currently a stub. - * We may move code from AAudioServiceStreamMMAP into this class. - * If not, then it will be removed. - */ -class AAudioServiceStreamExclusive : public AAudioServiceStreamMMAP { - -public: - AAudioServiceStreamExclusive() {}; - virtual ~AAudioServiceStreamExclusive() = default; -}; - -} /* namespace aaudio */ - -#endif //AAUDIO_AAUDIO_SERVICE_STREAM_EXCLUSIVE_H diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp index 97b993770a..08dd680f37 100644 --- a/services/oboeservice/AAudioServiceStreamMMAP.cpp +++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "AAudioService" +#define LOG_TAG "AAudioServiceStreamMMAP" //#define LOG_NDEBUG 0 #include <utils/Log.h> @@ -31,6 +31,7 @@ #include "SharedMemoryProxy.h" #include "utility/AAudioUtilities.h" +using android::base::unique_fd; using namespace android; using namespace aaudio; @@ -38,30 +39,30 @@ using namespace aaudio; #define AAUDIO_SAMPLE_RATE_DEFAULT 48000 /** - * Stream that uses an MMAP buffer. + * Service Stream that uses an MMAP buffer. */ -AAudioServiceStreamMMAP::AAudioServiceStreamMMAP() +AAudioServiceStreamMMAP::AAudioServiceStreamMMAP(const android::AudioClient& serviceClient, + bool inService) : AAudioServiceStreamBase() , mMmapStreamCallback(new MyMmapStreamCallback(*this)) , mPreviousFrameCounter(0) - , mMmapStream(nullptr) { -} - -AAudioServiceStreamMMAP::~AAudioServiceStreamMMAP() { - close(); + , mMmapStream(nullptr) + , mServiceClient(serviceClient) + , mInService(inService) { } aaudio_result_t AAudioServiceStreamMMAP::close() { - mMmapStream.clear(); // TODO review. Is that all we have to do? - // Apparently the above close is asynchronous. An attempt to open a new device - // right after a close can fail. Also some callbacks may still be in flight! - // FIXME Make closing synchronous. - AudioClock::sleepForNanos(100 * AAUDIO_NANOS_PER_MILLISECOND); - - if (mAudioDataFileDescriptor != -1) { - ::close(mAudioDataFileDescriptor); - mAudioDataFileDescriptor = -1; + if (mState == AAUDIO_STREAM_STATE_CLOSED) { + return AAUDIO_OK; + } + stop(); + if (mMmapStream != 0) { + mMmapStream.clear(); // TODO review. Is that all we have to do? + // Apparently the above close is asynchronous. An attempt to open a new device + // right after a close can fail. Also some callbacks may still be in flight! + // FIXME Make closing synchronous. + AudioClock::sleepForNanos(100 * AAUDIO_NANOS_PER_MILLISECOND); } return AAudioServiceStreamBase::close(); @@ -87,13 +88,10 @@ aaudio_result_t AAudioServiceStreamMMAP::open(const aaudio::AAudioStreamRequest const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration(); audio_port_handle_t deviceId = configurationInput.getDeviceId(); - - mMmapClient.clientUid = request.getUserId(); - mMmapClient.clientPid = request.getProcessId(); aaudio_direction_t direction = request.getDirection(); // Fill in config - aaudio_format_t aaudioFormat = configurationInput.getAudioFormat(); + aaudio_format_t aaudioFormat = configurationInput.getFormat(); if (aaudioFormat == AAUDIO_UNSPECIFIED || aaudioFormat == AAUDIO_FORMAT_PCM_FLOAT) { aaudioFormat = AAUDIO_FORMAT_PCM_I16; } @@ -120,8 +118,6 @@ aaudio_result_t AAudioServiceStreamMMAP::open(const aaudio::AAudioStreamRequest return AAUDIO_ERROR_ILLEGAL_ARGUMENT; } - mMmapClient.packageName.setTo(String16("aaudio_service")); // FIXME what should we do here? - MmapStreamInterface::stream_direction_t streamDirection = (direction == AAUDIO_DIRECTION_OUTPUT) ? MmapStreamInterface::DIRECTION_OUTPUT : MmapStreamInterface::DIRECTION_INPUT; @@ -132,27 +128,51 @@ aaudio_result_t AAudioServiceStreamMMAP::open(const aaudio::AAudioStreamRequest mMmapClient, &deviceId, mMmapStreamCallback, - mMmapStream); + mMmapStream, + &mPortHandle); if (status != OK) { ALOGE("openMmapStream returned status %d", status); return AAUDIO_ERROR_UNAVAILABLE; } + if (deviceId == AAUDIO_UNSPECIFIED) { + ALOGW("AAudioServiceStreamMMAP::open() - openMmapStream() failed to set deviceId"); + } + // Create MMAP/NOIRQ buffer. int32_t minSizeFrames = configurationInput.getBufferCapacity(); - if (minSizeFrames == 0) { // zero will get rejected + if (minSizeFrames <= 0) { // zero will get rejected minSizeFrames = AAUDIO_BUFFER_CAPACITY_MIN; } status = mMmapStream->createMmapBuffer(minSizeFrames, &mMmapBufferinfo); if (status != OK) { - ALOGE("%s: createMmapBuffer() returned status %d, return AAUDIO_ERROR_UNAVAILABLE", - __FILE__, status); + ALOGE("AAudioServiceStreamMMAP::open() - createMmapBuffer() returned status %d", + status); return AAUDIO_ERROR_UNAVAILABLE; } else { - ALOGD("createMmapBuffer status %d shared_address = %p buffer_size %d burst_size %d", - status, mMmapBufferinfo.shared_memory_address, - mMmapBufferinfo.buffer_size_frames, - mMmapBufferinfo.burst_size_frames); + ALOGD("createMmapBuffer status = %d, buffer_size = %d, burst_size %d" + ", Sharable FD: %s", + status, + abs(mMmapBufferinfo.buffer_size_frames), + mMmapBufferinfo.burst_size_frames, + mMmapBufferinfo.buffer_size_frames < 0 ? "Yes" : "No"); + } + + mCapacityInFrames = mMmapBufferinfo.buffer_size_frames; + // FIXME: the audio HAL indicates if the shared memory fd can be shared outside of audioserver + // by returning a negative buffer size + if (mCapacityInFrames < 0) { + // Exclusive mode is possible from any client + mCapacityInFrames = -mCapacityInFrames; + } else { + // exclusive mode is only possible if the final fd destination is inside audioserver + if ((mMmapClient.clientUid != mServiceClient.clientUid) && + configurationInput.getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) { + // Fallback is handled by caller but indicate what is possible in case + // this is used in the future + configurationOutput.setSharingMode(AAUDIO_SHARING_MODE_SHARED); + return AAUDIO_ERROR_UNAVAILABLE; + } } // Get information about the stream and pass it back to the caller. @@ -160,9 +180,14 @@ aaudio_result_t AAudioServiceStreamMMAP::open(const aaudio::AAudioStreamRequest ? audio_channel_count_from_out_mask(config.channel_mask) : audio_channel_count_from_in_mask(config.channel_mask); - mAudioDataFileDescriptor = mMmapBufferinfo.shared_memory_fd; + // AAudio creates a copy of this FD and retains ownership of the copy. + // Assume that AudioFlinger will close the original shared_memory_fd. + mAudioDataFileDescriptor.reset(dup(mMmapBufferinfo.shared_memory_fd)); + if (mAudioDataFileDescriptor.get() == -1) { + ALOGE("AAudioServiceStreamMMAP::open() - could not dup shared_memory_fd"); + return AAUDIO_ERROR_INTERNAL; // TODO review + } mFramesPerBurst = mMmapBufferinfo.burst_size_frames; - mCapacityInFrames = mMmapBufferinfo.buffer_size_frames; mAudioFormat = AAudioConvert_androidToAAudioDataFormat(config.format); mSampleRate = config.sample_rate; @@ -181,12 +206,16 @@ aaudio_result_t AAudioServiceStreamMMAP::open(const aaudio::AAudioStreamRequest ALOGD("AAudioServiceStreamMMAP::open() original burst = %d, minMicros = %d, final burst = %d\n", mMmapBufferinfo.burst_size_frames, burstMinMicros, mFramesPerBurst); + ALOGD("AAudioServiceStreamMMAP::open() actual rate = %d, channels = %d, deviceId = %d\n", + mSampleRate, mSamplesPerFrame, deviceId); + // Fill in AAudioStreamConfiguration configurationOutput.setSampleRate(mSampleRate); configurationOutput.setSamplesPerFrame(mSamplesPerFrame); - configurationOutput.setAudioFormat(mAudioFormat); + configurationOutput.setFormat(mAudioFormat); configurationOutput.setDeviceId(deviceId); + setState(AAUDIO_STREAM_STATE_OPEN); return AAUDIO_OK; } @@ -194,15 +223,21 @@ aaudio_result_t AAudioServiceStreamMMAP::open(const aaudio::AAudioStreamRequest * Start the flow of data. */ aaudio_result_t AAudioServiceStreamMMAP::start() { + if (isRunning()) { + return AAUDIO_OK; + } if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL; aaudio_result_t result; - status_t status = mMmapStream->start(mMmapClient, &mPortHandle); + status_t status = mMmapStream->start(mServiceClient, &mPortHandle); if (status != OK) { ALOGE("AAudioServiceStreamMMAP::start() mMmapStream->start() returned %d", status); - processError(); + disconnect(); result = AAudioConvert_androidToAAudioResult(status); } else { result = AAudioServiceStreamBase::start(); + if (!mInService && result == AAUDIO_OK) { + startClient(mMmapClient, &mClientHandle); + } } return result; } @@ -211,18 +246,28 @@ aaudio_result_t AAudioServiceStreamMMAP::start() { * Stop the flow of data such that start() can resume with loss of data. */ aaudio_result_t AAudioServiceStreamMMAP::pause() { + if (!isRunning()) { + return AAUDIO_OK; + } if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL; - aaudio_result_t result1 = AAudioServiceStreamBase::pause(); + if (!mInService) { + stopClient(mClientHandle); + } status_t status = mMmapStream->stop(mPortHandle); mFramesRead.reset32(); return (result1 != AAUDIO_OK) ? result1 : AAudioConvert_androidToAAudioResult(status); } aaudio_result_t AAudioServiceStreamMMAP::stop() { + if (!isRunning()) { + return AAUDIO_OK; + } if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL; - aaudio_result_t result1 = AAudioServiceStreamBase::stop(); + if (!mInService) { + stopClient(mClientHandle); + } aaudio_result_t status = mMmapStream->stop(mPortHandle); mFramesRead.reset32(); return (result1 != AAUDIO_OK) ? result1 : AAudioConvert_androidToAAudioResult(status); @@ -234,34 +279,43 @@ aaudio_result_t AAudioServiceStreamMMAP::stop() { aaudio_result_t AAudioServiceStreamMMAP::flush() { if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL; // TODO how do we flush an MMAP/NOIRQ buffer? sync pointers? - sendServiceEvent(AAUDIO_SERVICE_EVENT_FLUSHED); - mState = AAUDIO_STREAM_STATE_FLUSHED; return AAudioServiceStreamBase::flush();; } +aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client, + audio_port_handle_t *clientHandle) { + return AAudioConvert_androidToAAudioResult(mMmapStream->start(client, clientHandle)); +} + +aaudio_result_t AAudioServiceStreamMMAP::stopClient(audio_port_handle_t clientHandle) { + return AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle)); +} aaudio_result_t AAudioServiceStreamMMAP::getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) { struct audio_mmap_position position; if (mMmapStream == nullptr) { - processError(); + disconnect(); return AAUDIO_ERROR_NULL; } status_t status = mMmapStream->getMmapPosition(&position); - if (status != OK) { - ALOGE("sendCurrentTimestamp(): getMmapPosition() returned %d", status); - processError(); - return AAudioConvert_androidToAAudioResult(status); + aaudio_result_t result = AAudioConvert_androidToAAudioResult(status); + if (result == AAUDIO_ERROR_UNAVAILABLE) { + ALOGW("sendCurrentTimestamp(): getMmapPosition() has no position data yet"); + } else if (result != AAUDIO_OK) { + ALOGE("sendCurrentTimestamp(): getMmapPosition() returned status %d", status); + disconnect(); } else { mFramesRead.update32(position.position_frames); *positionFrames = mFramesRead.get(); *timeNanos = position.time_nanoseconds; } - return AAUDIO_OK; + return result; } void AAudioServiceStreamMMAP::onTearDown() { - ALOGE("AAudioServiceStreamMMAP::onTearDown() called - TODO"); + ALOGD("AAudioServiceStreamMMAP::onTearDown() called"); + disconnect(); }; void AAudioServiceStreamMMAP::onVolumeChanged(audio_channel_mask_t channels, @@ -274,11 +328,11 @@ void AAudioServiceStreamMMAP::onVolumeChanged(audio_channel_mask_t channels, void AAudioServiceStreamMMAP::onRoutingChanged(audio_port_handle_t deviceId) { ALOGD("AAudioServiceStreamMMAP::onRoutingChanged() called with %d, old = %d", - deviceId, mPortHandle); - if (mPortHandle > 0 && mPortHandle != deviceId) { - sendServiceEvent(AAUDIO_SERVICE_EVENT_DISCONNECTED); + deviceId, mDeviceId); + if (mDeviceId != AUDIO_PORT_HANDLE_NONE && mDeviceId != deviceId) { + disconnect(); } - mPortHandle = deviceId; + mDeviceId = deviceId; }; /** @@ -295,4 +349,4 @@ aaudio_result_t AAudioServiceStreamMMAP::getDownDataDescription(AudioEndpointPar parcelable.mDownDataQueueParcelable.setFramesPerBurst(mFramesPerBurst); parcelable.mDownDataQueueParcelable.setCapacityInFrames(mCapacityInFrames); return AAUDIO_OK; -}
\ No newline at end of file +} diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h index fe75a102b4..b69dc462bb 100644 --- a/services/oboeservice/AAudioServiceStreamMMAP.h +++ b/services/oboeservice/AAudioServiceStreamMMAP.h @@ -19,6 +19,7 @@ #include <atomic> +#include <android-base/unique_fd.h> #include <media/audiohal/StreamHalInterface.h> #include <media/MmapStreamCallback.h> #include <media/MmapStreamInterface.h> @@ -33,6 +34,7 @@ #include "TimestampScheduler.h" #include "utility/MonotonicCounter.h" + namespace aaudio { /** @@ -43,9 +45,8 @@ class AAudioServiceStreamMMAP , public android::MmapStreamCallback { public: - AAudioServiceStreamMMAP(); - virtual ~AAudioServiceStreamMMAP(); - + AAudioServiceStreamMMAP(const android::AudioClient& serviceClient, bool inService); + virtual ~AAudioServiceStreamMMAP() = default; aaudio_result_t open(const aaudio::AAudioStreamRequest &request, aaudio::AAudioStreamConfiguration &configurationOutput) override; @@ -78,6 +79,11 @@ public: aaudio_result_t close() override; + virtual aaudio_result_t startClient(const android::AudioClient& client, + audio_port_handle_t *clientHandle); + + virtual aaudio_result_t stopClient(audio_port_handle_t clientHandle); + /** * Send a MMAP/NOIRQ buffer timestamp to the client. */ @@ -127,13 +133,15 @@ private: MonotonicCounter mFramesWritten; MonotonicCounter mFramesRead; int32_t mPreviousFrameCounter = 0; // from HAL - int mAudioDataFileDescriptor = -1; // Interface to the AudioFlinger MMAP support. android::sp<android::MmapStreamInterface> mMmapStream; struct audio_mmap_buffer_info mMmapBufferinfo; - android::MmapStreamInterface::Client mMmapClient; - audio_port_handle_t mPortHandle = -1; // TODO review best default + audio_port_handle_t mPortHandle = AUDIO_PORT_HANDLE_NONE; + audio_port_handle_t mDeviceId = AUDIO_PORT_HANDLE_NONE; + android::AudioClient mServiceClient; + bool mInService = false; + android::base::unique_fd mAudioDataFileDescriptor; }; } // namespace aaudio diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp index 494b18ecb5..5654113208 100644 --- a/services/oboeservice/AAudioServiceStreamShared.cpp +++ b/services/oboeservice/AAudioServiceStreamShared.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "AAudioService" +#define LOG_TAG "AAudioServiceStreamShared" //#define LOG_NDEBUG 0 #include <utils/Log.h> @@ -34,93 +34,155 @@ using namespace android; using namespace aaudio; -#define MIN_BURSTS_PER_BUFFER 2 -#define MAX_BURSTS_PER_BUFFER 32 +#define MIN_BURSTS_PER_BUFFER 2 +#define DEFAULT_BURSTS_PER_BUFFER 16 +// This is an arbitrary range. TODO review. +#define MAX_FRAMES_PER_BUFFER (32 * 1024) AAudioServiceStreamShared::AAudioServiceStreamShared(AAudioService &audioService) : mAudioService(audioService) { } -AAudioServiceStreamShared::~AAudioServiceStreamShared() { - close(); +int32_t AAudioServiceStreamShared::calculateBufferCapacity(int32_t requestedCapacityFrames, + int32_t framesPerBurst) { + + if (requestedCapacityFrames > MAX_FRAMES_PER_BUFFER) { + ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() requested capacity %d > max %d", + requestedCapacityFrames, MAX_FRAMES_PER_BUFFER); + return AAUDIO_ERROR_OUT_OF_RANGE; + } + + // Determine how many bursts will fit in the buffer. + int32_t numBursts; + if (requestedCapacityFrames == AAUDIO_UNSPECIFIED) { + // Use fewer bursts if default is too many. + if ((DEFAULT_BURSTS_PER_BUFFER * framesPerBurst) > MAX_FRAMES_PER_BUFFER) { + numBursts = MAX_FRAMES_PER_BUFFER / framesPerBurst; + } else { + numBursts = DEFAULT_BURSTS_PER_BUFFER; + } + } else { + // round up to nearest burst boundary + numBursts = (requestedCapacityFrames + framesPerBurst - 1) / framesPerBurst; + } + + // Clip to bare minimum. + if (numBursts < MIN_BURSTS_PER_BUFFER) { + numBursts = MIN_BURSTS_PER_BUFFER; + } + // Check for numeric overflow. + if (numBursts > 0x8000 || framesPerBurst > 0x8000) { + ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() overflow, capacity = %d * %d", + numBursts, framesPerBurst); + return AAUDIO_ERROR_OUT_OF_RANGE; + } + int32_t capacityInFrames = numBursts * framesPerBurst; + + // Final sanity check. + if (capacityInFrames > MAX_FRAMES_PER_BUFFER) { + ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() calc capacity %d > max %d", + capacityInFrames, MAX_FRAMES_PER_BUFFER); + return AAUDIO_ERROR_OUT_OF_RANGE; + } + ALOGD("AAudioServiceStreamShared::calculateBufferCapacity() requested %d frames, actual = %d", + requestedCapacityFrames, capacityInFrames); + return capacityInFrames; } aaudio_result_t AAudioServiceStreamShared::open(const aaudio::AAudioStreamRequest &request, aaudio::AAudioStreamConfiguration &configurationOutput) { + sp<AAudioServiceStreamShared> keep(this); + aaudio_result_t result = AAudioServiceStreamBase::open(request, configurationOutput); if (result != AAUDIO_OK) { - ALOGE("AAudioServiceStreamBase open returned %d", result); + ALOGE("AAudioServiceStreamBase open() returned %d", result); return result; } const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration(); - int32_t deviceId = configurationInput.getDeviceId(); aaudio_direction_t direction = request.getDirection(); AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance(); - mServiceEndpoint = mEndpointManager.openEndpoint(mAudioService, deviceId, direction); + mServiceEndpoint = mEndpointManager.openEndpoint(mAudioService, configurationOutput, direction); if (mServiceEndpoint == nullptr) { - ALOGE("AAudioServiceStreamShared::open(), mServiceEndPoint = %p", mServiceEndpoint); + ALOGE("AAudioServiceStreamShared::open() mServiceEndPoint = %p", mServiceEndpoint); return AAUDIO_ERROR_UNAVAILABLE; } // Is the request compatible with the shared endpoint? - mAudioFormat = configurationInput.getAudioFormat(); + mAudioFormat = configurationInput.getFormat(); if (mAudioFormat == AAUDIO_FORMAT_UNSPECIFIED) { mAudioFormat = AAUDIO_FORMAT_PCM_FLOAT; } else if (mAudioFormat != AAUDIO_FORMAT_PCM_FLOAT) { - ALOGE("AAudioServiceStreamShared::open(), mAudioFormat = %d, need FLOAT", mAudioFormat); - return AAUDIO_ERROR_INVALID_FORMAT; + ALOGE("AAudioServiceStreamShared::open() mAudioFormat = %d, need FLOAT", mAudioFormat); + result = AAUDIO_ERROR_INVALID_FORMAT; + goto error; } mSampleRate = configurationInput.getSampleRate(); if (mSampleRate == AAUDIO_UNSPECIFIED) { mSampleRate = mServiceEndpoint->getSampleRate(); } else if (mSampleRate != mServiceEndpoint->getSampleRate()) { - ALOGE("AAudioServiceStreamShared::open(), mAudioFormat = %d, need %d", + ALOGE("AAudioServiceStreamShared::open() mSampleRate = %d, need %d", mSampleRate, mServiceEndpoint->getSampleRate()); - return AAUDIO_ERROR_INVALID_RATE; + result = AAUDIO_ERROR_INVALID_RATE; + goto error; } mSamplesPerFrame = configurationInput.getSamplesPerFrame(); if (mSamplesPerFrame == AAUDIO_UNSPECIFIED) { mSamplesPerFrame = mServiceEndpoint->getSamplesPerFrame(); } else if (mSamplesPerFrame != mServiceEndpoint->getSamplesPerFrame()) { - ALOGE("AAudioServiceStreamShared::open(), mSamplesPerFrame = %d, need %d", + ALOGE("AAudioServiceStreamShared::open() mSamplesPerFrame = %d, need %d", mSamplesPerFrame, mServiceEndpoint->getSamplesPerFrame()); - return AAUDIO_ERROR_OUT_OF_RANGE; + result = AAUDIO_ERROR_OUT_OF_RANGE; + goto error; } - // Determine this stream's shared memory buffer capacity. mFramesPerBurst = mServiceEndpoint->getFramesPerBurst(); - int32_t minCapacityFrames = configurationInput.getBufferCapacity(); - int32_t numBursts = MAX_BURSTS_PER_BUFFER; - if (minCapacityFrames != AAUDIO_UNSPECIFIED) { - numBursts = (minCapacityFrames + mFramesPerBurst - 1) / mFramesPerBurst; - if (numBursts < MIN_BURSTS_PER_BUFFER) { - numBursts = MIN_BURSTS_PER_BUFFER; - } else if (numBursts > MAX_BURSTS_PER_BUFFER) { - numBursts = MAX_BURSTS_PER_BUFFER; - } + ALOGD("AAudioServiceStreamShared::open() mSampleRate = %d, mFramesPerBurst = %d", + mSampleRate, mFramesPerBurst); + + mCapacityInFrames = calculateBufferCapacity(configurationInput.getBufferCapacity(), + mFramesPerBurst); + if (mCapacityInFrames < 0) { + result = mCapacityInFrames; // negative error code + mCapacityInFrames = 0; + goto error; } - mCapacityInFrames = numBursts * mFramesPerBurst; - ALOGD("AAudioServiceStreamShared::open(), mCapacityInFrames = %d", mCapacityInFrames); // Create audio data shared memory buffer for client. mAudioDataQueue = new SharedRingBuffer(); - mAudioDataQueue->allocate(calculateBytesPerFrame(), mCapacityInFrames); + result = mAudioDataQueue->allocate(calculateBytesPerFrame(), mCapacityInFrames); + if (result != AAUDIO_OK) { + ALOGE("AAudioServiceStreamShared::open() could not allocate FIFO with %d frames", + mCapacityInFrames); + result = AAUDIO_ERROR_NO_MEMORY; + goto error; + } + + ALOGD("AAudioServiceStreamShared::open() actual rate = %d, channels = %d, deviceId = %d", + mSampleRate, mSamplesPerFrame, mServiceEndpoint->getDeviceId()); // Fill in configuration for client. configurationOutput.setSampleRate(mSampleRate); configurationOutput.setSamplesPerFrame(mSamplesPerFrame); - configurationOutput.setAudioFormat(mAudioFormat); - configurationOutput.setDeviceId(deviceId); + configurationOutput.setFormat(mAudioFormat); + configurationOutput.setDeviceId(mServiceEndpoint->getDeviceId()); - mServiceEndpoint->registerStream(this); + result = mServiceEndpoint->registerStream(keep); + if (result != AAUDIO_OK) { + goto error; + } + setState(AAUDIO_STREAM_STATE_OPEN); return AAUDIO_OK; + +error: + close(); + return result; } /** @@ -129,6 +191,9 @@ aaudio_result_t AAudioServiceStreamShared::open(const aaudio::AAudioStreamReques * An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete. */ aaudio_result_t AAudioServiceStreamShared::start() { + if (isRunning()) { + return AAUDIO_OK; + } AAudioServiceEndpoint *endpoint = mServiceEndpoint; if (endpoint == nullptr) { return AAUDIO_ERROR_INVALID_STATE; @@ -137,11 +202,14 @@ aaudio_result_t AAudioServiceStreamShared::start() { aaudio_result_t result = endpoint->startStream(this); if (result != AAUDIO_OK) { ALOGE("AAudioServiceStreamShared::start() mServiceEndpoint returned %d", result); - processError(); + disconnect(); } else { - result = AAudioServiceStreamBase::start(); + result = endpoint->getStreamInternal()->startClient(mMmapClient, &mClientHandle); + if (result == AAUDIO_OK) { + result = AAudioServiceStreamBase::start(); + } } - return AAUDIO_OK; + return result; } /** @@ -150,29 +218,35 @@ aaudio_result_t AAudioServiceStreamShared::start() { * An AAUDIO_SERVICE_EVENT_PAUSED will be sent to the client when complete. */ aaudio_result_t AAudioServiceStreamShared::pause() { + if (!isRunning()) { + return AAUDIO_OK; + } AAudioServiceEndpoint *endpoint = mServiceEndpoint; if (endpoint == nullptr) { return AAUDIO_ERROR_INVALID_STATE; } - // Add this stream to the mixer. + endpoint->getStreamInternal()->stopClient(mClientHandle); aaudio_result_t result = endpoint->stopStream(this); if (result != AAUDIO_OK) { ALOGE("AAudioServiceStreamShared::pause() mServiceEndpoint returned %d", result); - processError(); + disconnect(); // TODO should we return or pause Base first? } return AAudioServiceStreamBase::pause(); } aaudio_result_t AAudioServiceStreamShared::stop() { + if (!isRunning()) { + return AAUDIO_OK; + } AAudioServiceEndpoint *endpoint = mServiceEndpoint; if (endpoint == nullptr) { return AAUDIO_ERROR_INVALID_STATE; } - // Add this stream to the mixer. + endpoint->getStreamInternal()->stopClient(mClientHandle); aaudio_result_t result = endpoint->stopStream(this); if (result != AAUDIO_OK) { ALOGE("AAudioServiceStreamShared::stop() mServiceEndpoint returned %d", result); - processError(); + disconnect(); } return AAudioServiceStreamBase::stop(); } @@ -183,22 +257,37 @@ aaudio_result_t AAudioServiceStreamShared::stop() { * An AAUDIO_SERVICE_EVENT_FLUSHED will be sent to the client when complete. */ aaudio_result_t AAudioServiceStreamShared::flush() { - // TODO make sure we are paused - // TODO actually flush the data - return AAudioServiceStreamBase::flush() ; + AAudioServiceEndpoint *endpoint = mServiceEndpoint; + if (endpoint == nullptr) { + return AAUDIO_ERROR_INVALID_STATE; + } + if (mState != AAUDIO_STREAM_STATE_PAUSED) { + ALOGE("AAudioServiceStreamShared::flush() stream not paused, state = %s", + AAudio_convertStreamStateToText(mState)); + return AAUDIO_ERROR_INVALID_STATE; + } + // Data will get flushed when the client receives the FLUSHED event. + return AAudioServiceStreamBase::flush(); } aaudio_result_t AAudioServiceStreamShared::close() { - pause(); - // TODO wait for pause() to synchronize - AAudioServiceEndpoint *endpoint = mServiceEndpoint; - if (endpoint != nullptr) { - endpoint->unregisterStream(this); + if (mState == AAUDIO_STREAM_STATE_CLOSED) { + return AAUDIO_OK; + } + + stop(); - AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance(); - mEndpointManager.closeEndpoint(endpoint); - mServiceEndpoint = nullptr; + AAudioServiceEndpoint *endpoint = mServiceEndpoint; + if (endpoint == nullptr) { + return AAUDIO_ERROR_INVALID_STATE; } + + endpoint->unregisterStream(this); + + AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance(); + mEndpointManager.closeEndpoint(endpoint); + mServiceEndpoint = nullptr; + if (mAudioDataQueue != nullptr) { delete mAudioDataQueue; mAudioDataQueue = nullptr; @@ -218,14 +307,6 @@ aaudio_result_t AAudioServiceStreamShared::getDownDataDescription(AudioEndpointP return AAUDIO_OK; } -void AAudioServiceStreamShared::onStop() { -} - -void AAudioServiceStreamShared::onDisconnect() { - mServiceEndpoint->close(); - mServiceEndpoint = nullptr; -} - void AAudioServiceStreamShared::markTransferTime(int64_t nanoseconds) { mMarkedPosition = mAudioDataQueue->getFifoBuffer()->getReadCounter(); mMarkedTime = nanoseconds; diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h index dfdbbb3909..6b67337404 100644 --- a/services/oboeservice/AAudioServiceStreamShared.h +++ b/services/oboeservice/AAudioServiceStreamShared.h @@ -44,7 +44,7 @@ class AAudioServiceStreamShared : public AAudioServiceStreamBase { public: AAudioServiceStreamShared(android::AAudioService &aAudioService); - virtual ~AAudioServiceStreamShared(); + virtual ~AAudioServiceStreamShared() = default; aaudio_result_t open(const aaudio::AAudioStreamRequest &request, aaudio::AAudioStreamConfiguration &configurationOutput) override; @@ -87,16 +87,20 @@ public: */ void markTransferTime(int64_t nanoseconds); - void onStop(); - - void onDisconnect(); - protected: aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) override; aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) override; + /** + * @param requestedCapacityFrames + * @param framesPerBurst + * @return capacity or negative error + */ + static int32_t calculateBufferCapacity(int32_t requestedCapacityFrames, + int32_t framesPerBurst); + private: android::AAudioService &mAudioService; AAudioServiceEndpoint *mServiceEndpoint = nullptr; diff --git a/services/oboeservice/Android.mk b/services/oboeservice/Android.mk index b447725c2b..a896a7a64e 100644 --- a/services/oboeservice/Android.mk +++ b/services/oboeservice/Android.mk @@ -25,6 +25,7 @@ LOCAL_SRC_FILES += \ $(LIBAAUDIO_SRC_DIR)/utility/HandleTracker.cpp \ SharedMemoryProxy.cpp \ SharedRingBuffer.cpp \ + AAudioClientTracker.cpp \ AAudioEndpointManager.cpp \ AAudioMixer.cpp \ AAudioService.cpp \ @@ -46,9 +47,11 @@ LOCAL_CFLAGS += -Wall -Werror LOCAL_SHARED_LIBRARIES := \ libaaudio \ libaudioflinger \ + libaudioclient \ libbinder \ libcutils \ libmediautils \ + libserviceutility \ libutils \ liblog diff --git a/services/oboeservice/SharedRingBuffer.cpp b/services/oboeservice/SharedRingBuffer.cpp index 6b3fb4c850..83b25b3b83 100644 --- a/services/oboeservice/SharedRingBuffer.cpp +++ b/services/oboeservice/SharedRingBuffer.cpp @@ -35,11 +35,6 @@ SharedRingBuffer::~SharedRingBuffer() munmap(mSharedMemory, mSharedMemorySizeInBytes); mSharedMemory = nullptr; } - if (mFileDescriptor != -1) { - ALOGV("SharedRingBuffer: LEAK? close(mFileDescriptor = %d)\n", mFileDescriptor); - close(mFileDescriptor); - mFileDescriptor = -1; - } } aaudio_result_t SharedRingBuffer::allocate(fifo_frames_t bytesPerFrame, @@ -49,17 +44,17 @@ aaudio_result_t SharedRingBuffer::allocate(fifo_frames_t bytesPerFrame, // Create shared memory large enough to hold the data and the read and write counters. mDataMemorySizeInBytes = bytesPerFrame * capacityInFrames; mSharedMemorySizeInBytes = mDataMemorySizeInBytes + (2 * (sizeof(fifo_counter_t))); - mFileDescriptor = ashmem_create_region("AAudioSharedRingBuffer", mSharedMemorySizeInBytes); - ALOGV("SharedRingBuffer::allocate() LEAK? mFileDescriptor = %d\n", mFileDescriptor); - if (mFileDescriptor < 0) { + mFileDescriptor.reset(ashmem_create_region("AAudioSharedRingBuffer", mSharedMemorySizeInBytes)); + if (mFileDescriptor.get() == -1) { ALOGE("SharedRingBuffer::allocate() ashmem_create_region() failed %d", errno); return AAUDIO_ERROR_INTERNAL; } + ALOGV("SharedRingBuffer::allocate() mFileDescriptor = %d\n", mFileDescriptor.get()); - int err = ashmem_set_prot_region(mFileDescriptor, PROT_READ|PROT_WRITE); // TODO error handling? + int err = ashmem_set_prot_region(mFileDescriptor.get(), PROT_READ|PROT_WRITE); // TODO error handling? if (err < 0) { ALOGE("SharedRingBuffer::allocate() ashmem_set_prot_region() failed %d", errno); - close(mFileDescriptor); + mFileDescriptor.reset(); return AAUDIO_ERROR_INTERNAL; // TODO convert errno to a better AAUDIO_ERROR; } @@ -67,10 +62,10 @@ aaudio_result_t SharedRingBuffer::allocate(fifo_frames_t bytesPerFrame, mSharedMemory = (uint8_t *) mmap(0, mSharedMemorySizeInBytes, PROT_READ|PROT_WRITE, MAP_SHARED, - mFileDescriptor, 0); + mFileDescriptor.get(), 0); if (mSharedMemory == MAP_FAILED) { ALOGE("SharedRingBuffer::allocate() mmap() failed %d", errno); - close(mFileDescriptor); + mFileDescriptor.reset(); return AAUDIO_ERROR_INTERNAL; // TODO convert errno to a better AAUDIO_ERROR; } diff --git a/services/oboeservice/SharedRingBuffer.h b/services/oboeservice/SharedRingBuffer.h index a2c3766f43..79169bc240 100644 --- a/services/oboeservice/SharedRingBuffer.h +++ b/services/oboeservice/SharedRingBuffer.h @@ -17,6 +17,7 @@ #ifndef AAUDIO_SHARED_RINGBUFFER_H #define AAUDIO_SHARED_RINGBUFFER_H +#include <android-base/unique_fd.h> #include <stdint.h> #include <cutils/ashmem.h> #include <sys/mman.h> @@ -51,12 +52,12 @@ public: } private: - int mFileDescriptor = -1; - android::FifoBuffer *mFifoBuffer = nullptr; - uint8_t *mSharedMemory = nullptr; - int32_t mSharedMemorySizeInBytes = 0; - int32_t mDataMemorySizeInBytes = 0; - android::fifo_frames_t mCapacityInFrames = 0; + android::base::unique_fd mFileDescriptor; + android::FifoBuffer *mFifoBuffer = nullptr; + uint8_t *mSharedMemory = nullptr; + int32_t mSharedMemorySizeInBytes = 0; + int32_t mDataMemorySizeInBytes = 0; + android::fifo_frames_t mCapacityInFrames = 0; }; } /* namespace aaudio */ diff --git a/services/soundtrigger/Android.mk b/services/soundtrigger/Android.mk index e21aae3811..10ee141bde 100644 --- a/services/soundtrigger/Android.mk +++ b/services/soundtrigger/Android.mk @@ -58,7 +58,7 @@ endif LOCAL_C_INCLUDES += \ - $(TOPDIR)frameworks/av/services/audioflinger + frameworks/av/services/audioflinger LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB) diff --git a/soundtrigger/Android.bp b/soundtrigger/Android.bp new file mode 100644 index 0000000000..6178153934 --- /dev/null +++ b/soundtrigger/Android.bp @@ -0,0 +1,36 @@ +// Copyright 2014 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_library_shared { + name: "libsoundtrigger", + + srcs: [ + "SoundTrigger.cpp", + "ISoundTrigger.cpp", + "ISoundTriggerClient.cpp", + "ISoundTriggerHwService.cpp", + ], + + shared_libs: [ + "libcutils", + "libutils", + "liblog", + "libbinder", + ], + + cflags: [ + "-Werror", + "-Wall", + ], +} diff --git a/soundtrigger/Android.mk b/soundtrigger/Android.mk deleted file mode 100644 index e29adbf110..0000000000 --- a/soundtrigger/Android.mk +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - SoundTrigger.cpp \ - ISoundTrigger.cpp \ - ISoundTriggerClient.cpp \ - ISoundTriggerHwService.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - liblog \ - libbinder \ - -#LOCAL_C_INCLUDES += \ - system/media/camera/include \ - system/media/private/camera/include - -LOCAL_MODULE:= libsoundtrigger - -LOCAL_CFLAGS := -Werror -Wall - -include $(BUILD_SHARED_LIBRARY) diff --git a/soundtrigger/SoundTrigger.cpp b/soundtrigger/SoundTrigger.cpp index e959b836f2..289b7b1996 100644 --- a/soundtrigger/SoundTrigger.cpp +++ b/soundtrigger/SoundTrigger.cpp @@ -124,9 +124,9 @@ status_t SoundTrigger::setCaptureState(bool active) } // SoundTrigger -SoundTrigger::SoundTrigger(sound_trigger_module_handle_t module, +SoundTrigger::SoundTrigger(sound_trigger_module_handle_t /*module*/, const sp<SoundTriggerCallback>& callback) - : mModule(module), mCallback(callback) + : mCallback(callback) { } |