From 365efe26a8f0aca15f0df6661084e12f402d104b Mon Sep 17 00:00:00 2001 From: John Stultz Date: Wed, 23 Sep 2020 02:09:15 +0000 Subject: db845c: Add missing etc/permissions/android.software.xml Since Android11 merged in, I have been seeing some odd crashes occasionally that was pointing to the fact that the AutoFillManager mService value was null. However, this same issue was not seen on HiKey960, with the same application and AOSP source. I dug around and realized we were not adding the android.software.xml file we add on HiKey960, and copying it over resolves the issue. Signed-off-by: John Stultz Change-Id: I1bc88c67030b0ed69511acdf348c27367bf7213a --- device-common.mk | 4 ++++ etc/permissions/android.software.xml | 43 ++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 etc/permissions/android.software.xml diff --git a/device-common.mk b/device-common.mk index d0f540e..f39d550 100644 --- a/device-common.mk +++ b/device-common.mk @@ -138,6 +138,10 @@ PRODUCT_COPY_FILES += \ PRODUCT_COPY_FILES += \ $(LOCAL_PATH)/seccomp_policy/mediaswcodec.policy:$(TARGET_COPY_OUT_VENDOR)/etc/seccomp_policy/mediaswcodec.policy +# Copy hardware config file(s) +PRODUCT_COPY_FILES += \ + device/linaro/dragonboard/etc/permissions/android.software.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.xml + # Memtrack PRODUCT_PACKAGES += \ memtrack.default \ diff --git a/etc/permissions/android.software.xml b/etc/permissions/android.software.xml new file mode 100644 index 0000000..742a086 --- /dev/null +++ b/etc/permissions/android.software.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From 70f37c65199443d2502da58ecb81a4be28d36d80 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 6 Oct 2020 05:03:00 +0000 Subject: db845c: Add support for cache partition Add logic to support cache partition, as it seems to be required to properly handle overlayfs remounts on the super paritition. Signed-off-by: John Stultz Change-Id: I5c3c0eebb7e8d34cff85197855f4ea5b989b90b3 --- BoardConfigCommon.mk | 3 +++ fstab.common | 1 + installer/db845c/flash-all-aosp.sh | 2 ++ sepolicy/file_contexts | 1 + 4 files changed, 7 insertions(+) diff --git a/BoardConfigCommon.mk b/BoardConfigCommon.mk index b879d96..d527c0e 100644 --- a/BoardConfigCommon.mk +++ b/BoardConfigCommon.mk @@ -41,6 +41,9 @@ BOARD_SYSTEM_EXTIMAGE_FILE_SYSTEM_TYPE := ext4 TARGET_COPY_OUT_PRODUCT := product BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE := ext4 BOARD_USES_METADATA_PARTITION := true +# Cache partition size: 64M +BOARD_CACHEIMAGE_PARTITION_SIZE := 67108864 +BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE := ext4 # Super partition TARGET_USE_DYNAMIC_PARTITIONS := true BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT := true diff --git a/fstab.common b/fstab.common index dbba930..9634d9c 100644 --- a/fstab.common +++ b/fstab.common @@ -5,3 +5,4 @@ /dev/block/platform/soc@0/1d84000.ufshc/by-name/userdata /data ext4 discard,noatime,noauto_da_alloc,data=ordered,user_xattr,barrier=1,inlinecrypt wait,formattable,fileencryption=aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized /dev/block/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard wait,formattable /devices/platform/soc@0/8804000.sdhci/mmc_host/mmc* auto auto defaults voldmanaged=sdcard1:auto +/dev/block/platform/soc@0/1d84000.ufshc/by-name/cache /cache ext4 nodev,noatime,nosuid,errors=panic wait diff --git a/installer/db845c/flash-all-aosp.sh b/installer/db845c/flash-all-aosp.sh index e6b1995..b3c677b 100755 --- a/installer/db845c/flash-all-aosp.sh +++ b/installer/db845c/flash-all-aosp.sh @@ -40,6 +40,8 @@ echo "FLASH-ALL-AOSP: Flash boot img" fastboot flash boot "${ANDROID_PRODUCT_OUT}"/boot.img echo "FLASH-ALL-AOSP: Flash super/dynamic image" fastboot flash super "${ANDROID_PRODUCT_OUT}"/super.img +echo "FLASH-ALL-AOSP: Flash cache image" +fastboot flash cache "${ANDROID_PRODUCT_OUT}"/cache.img echo "FLASH-ALL-AOSP: Flash userdata image" fastboot flash userdata "${ANDROID_PRODUCT_OUT}"/userdata.img diff --git a/sepolicy/file_contexts b/sepolicy/file_contexts index bf856df..bc69fcc 100644 --- a/sepolicy/file_contexts +++ b/sepolicy/file_contexts @@ -4,6 +4,7 @@ /dev/block/platform/soc@0/1d84000\.ufshc/by-name/metadata u:object_r:metadata_block_device:s0 /dev/block/platform/soc@0/1d84000\.ufshc/by-name/super u:object_r:super_block_device:s0 /dev/block/platform/soc@0/1d84000\.ufshc/by-name/userdata u:object_r:userdata_block_device:s0 +/dev/block/platform/soc@0/1d84000\.ufshc/by-name/cache u:object_r:cache_block_device:s0 /dev/dri u:object_r:dri_device:s0 /dev/dri/card0 u:object_r:graphics_device:s0 -- cgit v1.2.3 From e53665ed853fdcc6d5723e4893845cc8536e6189 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 6 Oct 2020 05:33:49 +0000 Subject: db845c: Unify fstab files to fix issues w/ adb remount The overlayfs remount handling of superpartitions expects the fstab to have all the partitions in it. This means we can't use the split between the ramdisk fstab and the vendor fstab that we have been previously. So this patch merges the two fstabs together. With this change "adb root; adb remount" works now. Signed-off-by: John Stultz Change-Id: Iad408d5d3b1e4c9291a947cd44ee65f4aaef5c45 --- db845c/device.mk | 2 +- fstab.common | 12 ++++++------ fstab.ramdisk.common | 4 ---- pixel3_mainline/device.mk | 2 +- 4 files changed, 8 insertions(+), 12 deletions(-) delete mode 100644 fstab.ramdisk.common diff --git a/db845c/device.mk b/db845c/device.mk index b37e06f..c6825a3 100644 --- a/db845c/device.mk +++ b/db845c/device.mk @@ -23,7 +23,7 @@ $(call inherit-product, frameworks/native/build/tablet-10in-xhdpi-2048-dalvik-he PRODUCT_COPY_FILES := \ $(DB845C_KERNEL_DIR)/Image.gz:kernel \ $(DB845C_KERNEL_DIR)/sdm845-db845c.dtb:dtb.img \ - device/linaro/dragonboard/fstab.ramdisk.common:$(TARGET_COPY_OUT_RAMDISK)/fstab.db845c \ + device/linaro/dragonboard/fstab.common:$(TARGET_COPY_OUT_RAMDISK)/fstab.db845c \ device/linaro/dragonboard/fstab.common:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.db845c \ device/linaro/dragonboard/init.common.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/init.db845c.rc \ device/linaro/dragonboard/init.common.usb.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/init.db845c.usb.rc \ diff --git a/fstab.common b/fstab.common index 9634d9c..733ab06 100644 --- a/fstab.common +++ b/fstab.common @@ -1,8 +1,8 @@ -# Android fstab file. -# -# The filesystem that contains the filesystem checker binary (typically /system) cannot -# specify MF_CHECK, and must come before any filesystems that do specify MF_CHECK +system /system ext4 noatime,ro,errors=panic wait,logical,first_stage_mount /dev/block/platform/soc@0/1d84000.ufshc/by-name/userdata /data ext4 discard,noatime,noauto_da_alloc,data=ordered,user_xattr,barrier=1,inlinecrypt wait,formattable,fileencryption=aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized -/dev/block/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard wait,formattable -/devices/platform/soc@0/8804000.sdhci/mmc_host/mmc* auto auto defaults voldmanaged=sdcard1:auto +/dev/block/platform/soc@0/1d84000.ufshc/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard wait,formattable /dev/block/platform/soc@0/1d84000.ufshc/by-name/cache /cache ext4 nodev,noatime,nosuid,errors=panic wait +/devices/platform/soc@0/8804000.sdhci/mmc_host/mmc* auto auto defaults voldmanaged=sdcard1:auto +vendor /vendor ext4 noatime,ro,errors=panic wait,logical,first_stage_mount +system_ext /system_ext ext4 noatime,ro,errors=panic wait,logical,first_stage_mount +product /product ext4 noatime,ro,errors=panic wait,logical,first_stage_mount diff --git a/fstab.ramdisk.common b/fstab.ramdisk.common deleted file mode 100644 index 9554d4e..0000000 --- a/fstab.ramdisk.common +++ /dev/null @@ -1,4 +0,0 @@ -system /system ext4 noatime,ro,errors=panic wait,logical,first_stage_mount -vendor /vendor ext4 noatime,ro,errors=panic wait,logical,first_stage_mount -system_ext /system_ext ext4 noatime,ro,errors=panic wait,logical,first_stage_mount -product /product ext4 noatime,ro,errors=panic wait,logical,first_stage_mount diff --git a/pixel3_mainline/device.mk b/pixel3_mainline/device.mk index 8109ad3..e394c60 100644 --- a/pixel3_mainline/device.mk +++ b/pixel3_mainline/device.mk @@ -19,7 +19,7 @@ $(call inherit-product, frameworks/native/build/phone-xhdpi-2048-dalvik-heap.mk) PRODUCT_COPY_FILES := \ - device/linaro/dragonboard/fstab.ramdisk.common:$(TARGET_COPY_OUT_RAMDISK)/fstab.pixel3_mainline \ + device/linaro/dragonboard/fstab.common:$(TARGET_COPY_OUT_RAMDISK)/fstab.pixel3_mainline \ device/linaro/dragonboard/fstab.common:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.pixel3_mainline \ device/linaro/dragonboard/init.common.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/init.pixel3_mainline.rc \ device/linaro/dragonboard/init.common.usb.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/init.pixel3_mainline.usb.rc \ -- cgit v1.2.3 From 7d3a1ac4e582e2eebb13c356f696b84409ae6620 Mon Sep 17 00:00:00 2001 From: Amit Pundir Date: Wed, 7 Oct 2020 18:26:24 +0530 Subject: db845c: BoardConfig: Correct the super partition size Super partition size is not set correctly. I rounded off to 10G during initial porting days. Reset it to the correct size mentioned in the bootloader ptable. It fixes the following warning we see during adb remount: [liblp]Device size does not match (got 12437225472, expected 10737418240) [liblp]Block device super size mismatch (expected10737418240, got 12437225472) Signed-off-by: Amit Pundir Change-Id: I89d74070893c14796e24cc8286fd794725b48717 --- db845c/BoardConfig.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/db845c/BoardConfig.mk b/db845c/BoardConfig.mk index 816c465..9d31f97 100644 --- a/db845c/BoardConfig.mk +++ b/db845c/BoardConfig.mk @@ -19,7 +19,7 @@ BOARD_BOOTIMAGE_PARTITION_SIZE := 67108864 #64M BOARD_USERDATAIMAGE_PARTITION_SIZE := 21474836480 #20G BOARD_FLASH_BLOCK_SIZE := 512 # Super partition -BOARD_SUPER_PARTITION_SIZE := 10737418240 #10G -BOARD_DB_DYNAMIC_PARTITIONS_SIZE := 10737418240 #10G +BOARD_SUPER_PARTITION_SIZE := 12437225472 +BOARD_DB_DYNAMIC_PARTITIONS_SIZE := 12437225472 BOARD_SUPER_PARTITION_METADATA_DEVICE := super BOARD_SUPER_IMAGE_IN_UPDATE_PACKAGE := true -- cgit v1.2.3 From 80e228b5d8be952e30cd7bfbc57c152be37f6c7a Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 6 Oct 2020 05:03:30 +0000 Subject: db845c: Add tweaks to properly support emulated storage w/o sdcardfs Now that sdcardfs is deprecated, we need a few tweaks to support emulated storage on the board. Thanks so much to Martijn Coenen and Daniel Rosenberg for their help narrowing down the changes needed here. Signed-off-by: John Stultz Change-Id: I66aa4010df196e9fa7ca6a0be612f706e83a2715 --- device-common.mk | 3 +++ fstab.common | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/device-common.mk b/device-common.mk index f39d550..6fffd07 100644 --- a/device-common.mk +++ b/device-common.mk @@ -26,6 +26,9 @@ PRODUCT_RUNTIMES := runtime_libart_default PRODUCT_SHIPPING_API_LEVEL := 29 PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS := false +# Enable Scoped Storage related +$(call inherit-product, $(SRC_TARGET_DIR)/product/emulated_storage.mk) + # vndk PRODUCT_PACKAGES := vndk-sp diff --git a/fstab.common b/fstab.common index 733ab06..1cdac6e 100644 --- a/fstab.common +++ b/fstab.common @@ -1,5 +1,5 @@ system /system ext4 noatime,ro,errors=panic wait,logical,first_stage_mount -/dev/block/platform/soc@0/1d84000.ufshc/by-name/userdata /data ext4 discard,noatime,noauto_da_alloc,data=ordered,user_xattr,barrier=1,inlinecrypt wait,formattable,fileencryption=aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized +/dev/block/platform/soc@0/1d84000.ufshc/by-name/userdata /data ext4 discard,noatime,noauto_da_alloc,data=ordered,user_xattr,barrier=1,inlinecrypt wait,formattable,fileencryption=aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized,quota /dev/block/platform/soc@0/1d84000.ufshc/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard wait,formattable /dev/block/platform/soc@0/1d84000.ufshc/by-name/cache /cache ext4 nodev,noatime,nosuid,errors=panic wait /devices/platform/soc@0/8804000.sdhci/mmc_host/mmc* auto auto defaults voldmanaged=sdcard1:auto -- cgit v1.2.3 From 2247819df0d6423fcefb111fe2448a719cebcc53 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Tue, 20 Oct 2020 11:53:42 -0700 Subject: Bump target level to 3 Test: m check-vintf-all Bug: 171317032 Change-Id: I4b1d077c82872e50afbd366fa5e71da930d39afd --- manifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.xml b/manifest.xml index fee2945..0a3f708 100644 --- a/manifest.xml +++ b/manifest.xml @@ -1,4 +1,4 @@ - + android.hardware.audio hwbinder -- cgit v1.2.3 From ebef015a20ca2b7a7b0ec49f94539886312c2705 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Tue, 20 Oct 2020 00:15:44 -0700 Subject: Fix an out-of-bounds read in assoc_next. Found using HWASan. Also sent upstream: https://github.com/andersson/pd-mapper/pull/5 Bug: 171327997 Change-Id: I69d07d0228719abbffb38aa709de39c1d8190158 --- qcom/pd-mapper/assoc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qcom/pd-mapper/assoc.c b/qcom/pd-mapper/assoc.c index 692c882..460f0d0 100644 --- a/qcom/pd-mapper/assoc.c +++ b/qcom/pd-mapper/assoc.c @@ -128,7 +128,7 @@ const char *assoc_next(struct assoc *assoc, void **value, unsigned long *iter) { unsigned long it = *iter; - while (!assoc->keys[it] && it < assoc->size) + while (it < assoc->size && !assoc->keys[it]) it++; if (it == assoc->size) -- cgit v1.2.3 From af86a2d34fbecda352aeea769b6f7f119545378f Mon Sep 17 00:00:00 2001 From: Yongqin Liu Date: Wed, 21 Oct 2020 10:24:53 +0800 Subject: enable bootctrol for db845c build so that it will be possible to work with GSI image Test: boot to homescreen console:/ # getprop init.svc.vendor.boot-hal-1-1 running console:/ # VtsHalBootV1_0TargetTest and VtsHalBootV1_1TargetTest Signed-off-by: Yongqin Liu Change-Id: I147f04de1c8bc7fd506d351f514498341ef7388c --- db845c/device.mk | 6 ++++++ fstab.common | 1 + sepolicy/file_contexts | 1 + 3 files changed, 8 insertions(+) diff --git a/db845c/device.mk b/db845c/device.mk index c6825a3..2240981 100644 --- a/db845c/device.mk +++ b/db845c/device.mk @@ -32,6 +32,12 @@ PRODUCT_COPY_FILES := \ # Build generic Audio HAL PRODUCT_PACKAGES := audio.primary.db845c +# BootControl HAL +PRODUCT_PACKAGES += \ + android.hardware.boot@1.1-impl \ + android.hardware.boot@1.1-impl.recovery \ + android.hardware.boot@1.1-service + PRODUCT_PACKAGES += \ pd-mapper \ qrtr-ns \ diff --git a/fstab.common b/fstab.common index 1cdac6e..f9023ad 100644 --- a/fstab.common +++ b/fstab.common @@ -2,6 +2,7 @@ system /system ext4 noatime,ro,errors=panic wait,logical,first_stage_mount /dev/block/platform/soc@0/1d84000.ufshc/by-name/userdata /data ext4 discard,noatime,noauto_da_alloc,data=ordered,user_xattr,barrier=1,inlinecrypt wait,formattable,fileencryption=aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized,quota /dev/block/platform/soc@0/1d84000.ufshc/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard wait,formattable /dev/block/platform/soc@0/1d84000.ufshc/by-name/cache /cache ext4 nodev,noatime,nosuid,errors=panic wait +/dev/block/platform/soc@0/1d84000.ufshc/by-name/misc /misc emmc defaults defaults /devices/platform/soc@0/8804000.sdhci/mmc_host/mmc* auto auto defaults voldmanaged=sdcard1:auto vendor /vendor ext4 noatime,ro,errors=panic wait,logical,first_stage_mount system_ext /system_ext ext4 noatime,ro,errors=panic wait,logical,first_stage_mount diff --git a/sepolicy/file_contexts b/sepolicy/file_contexts index bc69fcc..f70cc5f 100644 --- a/sepolicy/file_contexts +++ b/sepolicy/file_contexts @@ -5,6 +5,7 @@ /dev/block/platform/soc@0/1d84000\.ufshc/by-name/super u:object_r:super_block_device:s0 /dev/block/platform/soc@0/1d84000\.ufshc/by-name/userdata u:object_r:userdata_block_device:s0 /dev/block/platform/soc@0/1d84000\.ufshc/by-name/cache u:object_r:cache_block_device:s0 +/dev/block/platform/soc@0/1d84000\.ufshc/by-name/misc u:object_r:misc_block_device:s0 /dev/dri u:object_r:dri_device:s0 /dev/dri/card0 u:object_r:graphics_device:s0 -- cgit v1.2.3 From 6e1a73e3ae7bcc31248b4fee9f7e5b4fa0cee3bb Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 6 Nov 2020 14:25:45 -0800 Subject: Remove wifilogd. Test: treehugger Change-Id: Ia4840909fc17a4e3e2d510be76cc7c80e302dc63 --- device-common.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/device-common.mk b/device-common.mk index 6fffd07..de39035 100644 --- a/device-common.mk +++ b/device-common.mk @@ -74,8 +74,7 @@ PRODUCT_PACKAGES += \ libwpa_client \ wpa_supplicant \ wpa_supplicant.conf \ - wificond \ - wifilogd + wificond PRODUCT_PROPERTY_OVERRIDES += \ wifi.interface=wlan0 \ -- cgit v1.2.3 From e6732bb951290bc8cdf8241dde06b0195fde6ea8 Mon Sep 17 00:00:00 2001 From: Amit Pundir Date: Mon, 28 Sep 2020 12:43:59 +0530 Subject: audio: Kang audio HAL from amlogic yukawa device Copied from device/amlogic/generic/hal/audio/ minus the speaker equalizer filter file. It is a generic and more feature rich HAL, plus it fixes the occasional static noise we hear on db845c and PocoF1. Removed the mixer control settings from qcom/init.qcom.rc and added HDMI out mixer control in etc/mixer_paths.xml to start with. ** Analog audio out is not tested yet. ** ToDo: 1. Fallback to Analog audio port if the monitor doesn't support HDMI audio out. 2. Mic AEC support is integrated deep in this HAL, so I didn't remove it. Might as well test and use that feature on Pixel 3 and Poco F1. Same with speaker EQ, though we may end up never using this equalizer feature at all. Signed-off-by: Amit Pundir Change-Id: I85614abdd684ab67f405f4c0e48380668ade4e06 --- audio/Android.mk | 8 +- audio/audio_aec.c | 700 ++++++++++++ audio/audio_aec.h | 132 +++ audio/audio_hw.c | 2135 +++++++++++++----------------------- audio/audio_hw.h | 129 +++ audio/fifo_wrapper.cpp | 79 ++ audio/fifo_wrapper.h | 35 + audio/fir_filter.c | 154 +++ audio/fir_filter.h | 39 + device-common.mk | 1 + etc/audio_policy_configuration.xml | 59 +- etc/mixer_paths.xml | 5 + qcom/init.qcom.rc | 25 - 13 files changed, 2063 insertions(+), 1438 deletions(-) create mode 100644 audio/audio_aec.c create mode 100644 audio/audio_aec.h create mode 100644 audio/audio_hw.h create mode 100644 audio/fifo_wrapper.cpp create mode 100644 audio/fifo_wrapper.h create mode 100644 audio/fir_filter.c create mode 100644 audio/fir_filter.h create mode 100644 etc/mixer_paths.xml diff --git a/audio/Android.mk b/audio/Android.mk index 228ccf2..90c18fa 100644 --- a/audio/Android.mk +++ b/audio/Android.mk @@ -27,12 +27,16 @@ LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM) LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_VENDOR_MODULE := true -LOCAL_SRC_FILES := audio_hw.c -LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa +LOCAL_SRC_FILES := audio_hw.c \ + audio_aec.c \ + fifo_wrapper.cpp \ + fir_filter.c +LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa libaudioroute libaudioutils LOCAL_CFLAGS := -Wno-unused-parameter LOCAL_C_INCLUDES += \ external/tinyalsa/include \ external/expat/lib \ + $(call include-path-for, audio-route) \ system/media/audio_utils/include \ system/media/audio_effects/include diff --git a/audio/audio_aec.c b/audio/audio_aec.c new file mode 100644 index 0000000..ab99c93 --- /dev/null +++ b/audio/audio_aec.c @@ -0,0 +1,700 @@ +/* + * Copyright (C) 2019 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. + */ + +// clang-format off +/* + * Typical AEC signal flow: + * + * Microphone Audio + * Timestamps + * +--------------------------------------+ + * | | +---------------+ + * | Microphone +---------------+ | | | + * O|====== | Audio | Sample Rate | +-------> | + * (from . +--+ Samples | + | | | + * mic . +==================> Format |==============> | + * codec) . | Conversion | | | Cleaned + * O|====== | (if required) | | Acoustic | Audio + * +---------------+ | Echo | Samples + * | Canceller |===================> + * | (AEC) | + * Reference +---------------+ | | + * Audio | Sample Rate | | | + * Samples | + | | | + * +=============> Format |==============> | + * | | Conversion | | | + * | | (if required) | +-------> | + * | +---------------+ | | | + * | | +---------------+ + * | +-------------------------------+ + * | | Reference Audio + * | | Timestamps + * | | + * +--+----+---------+ AUDIO CAPTURE + * | Speaker | + * +------------+ Audio/Timestamp +---------------------------------------------------------------------------+ + * | Buffer | + * +--^----^---------+ AUDIO PLAYBACK + * | | + * | | + * | | + * | | + * |\ | | + * | +-+ | | + * (to | | +-----C----+ + * speaker | | | | Playback + * codec) | | <=====+================================================================+ Audio + * | +-+ Samples + * |/ + * + */ +// clang-format on + +#define LOG_TAG "audio_hw_aec" +// #define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "audio_aec.h" + +#ifdef AEC_HAL +#include "audio_aec_process.h" +#else +#define aec_spk_mic_init(...) ((int)0) +#define aec_spk_mic_reset(...) ((void)0) +#define aec_spk_mic_process(...) ((int32_t)0) +#define aec_spk_mic_release(...) ((void)0) +#endif + +#define MAX_TIMESTAMP_DIFF_USEC 200000 + +#define MAX_READ_WAIT_TIME_MSEC 80 + +uint64_t timespec_to_usec(struct timespec ts) { + return (ts.tv_sec * 1e6L + ts.tv_nsec/1000); +} + +void get_reference_audio_in_place(struct aec_t *aec, size_t frames) { + if (aec->num_reference_channels == aec->spk_num_channels) { + /* Reference count equals speaker channels, nothing to do here. */ + return; + } else if (aec->num_reference_channels != 1) { + /* We don't have a rule for non-mono references, show error on log */ + ALOGE("Invalid reference count - must be 1 or match number of playback channels!"); + return; + } + int16_t *src_Nch = &aec->spk_buf_playback_format[0]; + int16_t *dst_1ch = &aec->spk_buf_playback_format[0]; + int32_t num_channels = (int32_t)aec->spk_num_channels; + size_t frame, ch; + for (frame = 0; frame < frames; frame++) { + int32_t acc = 0; + for (ch = 0; ch < aec->spk_num_channels; ch++) { + acc += src_Nch[ch]; + } + *dst_1ch++ = clamp16(acc/num_channels); + src_Nch += aec->spk_num_channels; + } +} + +void print_queue_status_to_log(struct aec_t *aec, bool write_side) { + ssize_t q1 = fifo_available_to_read(aec->spk_fifo); + ssize_t q2 = fifo_available_to_read(aec->ts_fifo); + + ALOGV("Queue available %s: Spk %zd (count %zd) TS %zd (count %zd)", + (write_side) ? "(POST-WRITE)" : "(PRE-READ)", + q1, q1/aec->spk_frame_size_bytes/PLAYBACK_PERIOD_SIZE, + q2, q2/sizeof(struct aec_info)); +} + +void flush_aec_fifos(struct aec_t *aec) { + if (aec == NULL) { + return; + } + if (aec->spk_fifo != NULL) { + ALOGV("Flushing AEC Spk FIFO..."); + fifo_flush(aec->spk_fifo); + } + if (aec->ts_fifo != NULL) { + ALOGV("Flushing AEC Timestamp FIFO..."); + fifo_flush(aec->ts_fifo); + } + /* Reset FIFO read-write offset tracker */ + aec->read_write_diff_bytes = 0; +} + +void aec_set_spk_running_no_lock(struct aec_t* aec, bool state) { + aec->spk_running = state; +} + +bool aec_get_spk_running_no_lock(struct aec_t* aec) { + return aec->spk_running; +} + +void destroy_aec_reference_config_no_lock(struct aec_t* aec) { + if (!aec->spk_initialized) { + return; + } + aec_set_spk_running_no_lock(aec, false); + fifo_release(aec->spk_fifo); + fifo_release(aec->ts_fifo); + memset(&aec->last_spk_info, 0, sizeof(struct aec_info)); + aec->spk_initialized = false; +} + +void destroy_aec_mic_config_no_lock(struct aec_t* aec) { + if (!aec->mic_initialized) { + return; + } + release_resampler(aec->spk_resampler); + free(aec->mic_buf); + free(aec->spk_buf); + free(aec->spk_buf_playback_format); + free(aec->spk_buf_resampler_out); + memset(&aec->last_mic_info, 0, sizeof(struct aec_info)); + aec->mic_initialized = false; +} + +struct aec_t *init_aec_interface() { + ALOGV("%s enter", __func__); + struct aec_t *aec = (struct aec_t *)calloc(1, sizeof(struct aec_t)); + if (aec == NULL) { + ALOGE("Failed to allocate memory for AEC interface!"); + } else { + pthread_mutex_init(&aec->lock, NULL); + } + + ALOGV("%s exit", __func__); + return aec; +} + +void release_aec_interface(struct aec_t *aec) { + ALOGV("%s enter", __func__); + pthread_mutex_lock(&aec->lock); + destroy_aec_mic_config_no_lock(aec); + destroy_aec_reference_config_no_lock(aec); + pthread_mutex_unlock(&aec->lock); + free(aec); + ALOGV("%s exit", __func__); +} + +int init_aec(int sampling_rate, int num_reference_channels, + int num_microphone_channels, struct aec_t **aec_ptr) { + ALOGV("%s enter", __func__); + int ret = 0; + int aec_ret = aec_spk_mic_init( + sampling_rate, + num_reference_channels, + num_microphone_channels); + if (aec_ret) { + ALOGE("AEC object failed to initialize!"); + ret = -EINVAL; + } + struct aec_t *aec = init_aec_interface(); + if (!ret) { + aec->num_reference_channels = num_reference_channels; + /* Set defaults, will be overridden by settings in init_aec_(mic|referece_config) */ + /* Capture uses 2-ch, 32-bit frames */ + aec->mic_sampling_rate = CAPTURE_CODEC_SAMPLING_RATE; + aec->mic_frame_size_bytes = CHANNEL_STEREO * sizeof(int32_t); + aec->mic_num_channels = CHANNEL_STEREO; + + /* Playback uses 2-ch, 16-bit frames */ + aec->spk_sampling_rate = PLAYBACK_CODEC_SAMPLING_RATE; + aec->spk_frame_size_bytes = CHANNEL_STEREO * sizeof(int16_t); + aec->spk_num_channels = CHANNEL_STEREO; + } + + (*aec_ptr) = aec; + ALOGV("%s exit", __func__); + return ret; +} + +void release_aec(struct aec_t *aec) { + ALOGV("%s enter", __func__); + if (aec == NULL) { + return; + } + release_aec_interface(aec); + aec_spk_mic_release(); + ALOGV("%s exit", __func__); +} + +int init_aec_reference_config(struct aec_t *aec, struct alsa_stream_out *out) { + ALOGV("%s enter", __func__); + if (!aec) { + ALOGE("AEC: No valid interface found!"); + return -EINVAL; + } + + int ret = 0; + pthread_mutex_lock(&aec->lock); + if (aec->spk_initialized) { + destroy_aec_reference_config_no_lock(aec); + } + + aec->spk_fifo = fifo_init( + out->config.period_count * out->config.period_size * + audio_stream_out_frame_size(&out->stream), + false /* reader_throttles_writer */); + if (aec->spk_fifo == NULL) { + ALOGE("AEC: Speaker loopback FIFO Init failed!"); + ret = -EINVAL; + goto exit; + } + aec->ts_fifo = fifo_init( + out->config.period_count * sizeof(struct aec_info), + false /* reader_throttles_writer */); + if (aec->ts_fifo == NULL) { + ALOGE("AEC: Speaker timestamp FIFO Init failed!"); + ret = -EINVAL; + fifo_release(aec->spk_fifo); + goto exit; + } + + aec->spk_sampling_rate = out->config.rate; + aec->spk_frame_size_bytes = audio_stream_out_frame_size(&out->stream); + aec->spk_num_channels = out->config.channels; + aec->spk_initialized = true; +exit: + pthread_mutex_unlock(&aec->lock); + ALOGV("%s exit", __func__); + return ret; +} + +void destroy_aec_reference_config(struct aec_t* aec) { + ALOGV("%s enter", __func__); + if (aec == NULL) { + ALOGV("%s exit", __func__); + return; + } + pthread_mutex_lock(&aec->lock); + destroy_aec_reference_config_no_lock(aec); + pthread_mutex_unlock(&aec->lock); + ALOGV("%s exit", __func__); +} + +int write_to_reference_fifo(struct aec_t* aec, void* buffer, struct aec_info* info) { + ALOGV("%s enter", __func__); + int ret = 0; + size_t bytes = info->bytes; + + /* Write audio samples to FIFO */ + ssize_t written_bytes = fifo_write(aec->spk_fifo, buffer, bytes); + if (written_bytes != bytes) { + ALOGE("Could only write %zu of %zu bytes", written_bytes, bytes); + ret = -ENOMEM; + } + + /* Write timestamp to FIFO */ + info->bytes = written_bytes; + ALOGV("Speaker timestamp: %ld s, %ld nsec", info->timestamp.tv_sec, info->timestamp.tv_nsec); + ssize_t ts_bytes = fifo_write(aec->ts_fifo, info, sizeof(struct aec_info)); + ALOGV("Wrote TS bytes: %zu", ts_bytes); + print_queue_status_to_log(aec, true); + ALOGV("%s exit", __func__); + return ret; +} + +void get_spk_timestamp(struct aec_t* aec, ssize_t read_bytes, uint64_t* spk_time) { + *spk_time = 0; + uint64_t spk_time_offset = 0; + float usec_per_byte = 1E6 / ((float)(aec->spk_frame_size_bytes * aec->spk_sampling_rate)); + if (aec->read_write_diff_bytes < 0) { + /* We're still reading a previous write packet. (We only need the first sample's timestamp, + * so even if we straddle packets we only care about the first one) + * So we just use the previous timestamp, with an appropriate offset + * based on the number of bytes remaining to be read from that write packet. */ + spk_time_offset = (aec->last_spk_info.bytes + aec->read_write_diff_bytes) * usec_per_byte; + ALOGV("Reusing previous timestamp, calculated offset (usec) %" PRIu64, spk_time_offset); + } else { + /* If read_write_diff_bytes > 0, there are no new writes, so there won't be timestamps in + * the FIFO, and the check below will fail. */ + if (!fifo_available_to_read(aec->ts_fifo)) { + ALOGE("Timestamp error: no new timestamps!"); + return; + } + /* We just read valid data, so if we're here, we should have a valid timestamp to use. */ + ssize_t ts_bytes = fifo_read(aec->ts_fifo, &aec->last_spk_info, sizeof(struct aec_info)); + ALOGV("Read TS bytes: %zd, expected %zu", ts_bytes, sizeof(struct aec_info)); + aec->read_write_diff_bytes -= aec->last_spk_info.bytes; + } + + *spk_time = timespec_to_usec(aec->last_spk_info.timestamp) + spk_time_offset; + + aec->read_write_diff_bytes += read_bytes; + struct aec_info spk_info = aec->last_spk_info; + while (aec->read_write_diff_bytes > 0) { + /* If read_write_diff_bytes > 0, it means that there are more write packet timestamps + * in FIFO (since there we read more valid data the size of the current timestamp's + * packet). Keep reading timestamps from FIFO to get to the most recent one. */ + if (!fifo_available_to_read(aec->ts_fifo)) { + /* There are no more timestamps, we have the most recent one. */ + ALOGV("At the end of timestamp FIFO, breaking..."); + break; + } + fifo_read(aec->ts_fifo, &spk_info, sizeof(struct aec_info)); + ALOGV("Fast-forwarded timestamp by %zd bytes, remaining bytes: %zd," + " new timestamp (usec) %" PRIu64, + spk_info.bytes, aec->read_write_diff_bytes, timespec_to_usec(spk_info.timestamp)); + aec->read_write_diff_bytes -= spk_info.bytes; + } + aec->last_spk_info = spk_info; +} + +int get_reference_samples(struct aec_t* aec, void* buffer, struct aec_info* info) { + ALOGV("%s enter", __func__); + + if (!aec->spk_initialized) { + ALOGE("%s called with no reference initialized", __func__); + return -EINVAL; + } + + size_t bytes = info->bytes; + const size_t frames = bytes / aec->mic_frame_size_bytes; + const size_t sample_rate_ratio = aec->spk_sampling_rate / aec->mic_sampling_rate; + + /* Read audio samples from FIFO */ + const size_t req_bytes = frames * sample_rate_ratio * aec->spk_frame_size_bytes; + ssize_t available_bytes = 0; + unsigned int wait_count = MAX_READ_WAIT_TIME_MSEC; + while (true) { + available_bytes = fifo_available_to_read(aec->spk_fifo); + if (available_bytes >= req_bytes) { + break; + } else if (available_bytes < 0) { + ALOGE("fifo_read returned code %zu ", available_bytes); + return -ENOMEM; + } + + ALOGV("Sleeping, required bytes: %zu, available bytes: %zd", req_bytes, available_bytes); + usleep(1000); + if ((wait_count--) == 0) { + ALOGE("Timed out waiting for read from reference FIFO"); + return -ETIMEDOUT; + } + } + + const size_t read_bytes = fifo_read(aec->spk_fifo, aec->spk_buf_playback_format, req_bytes); + + /* Get timestamp*/ + get_spk_timestamp(aec, read_bytes, &info->timestamp_usec); + + /* Get reference - could be mono, downmixed from multichannel. + * Reference stored at spk_buf_playback_format */ + const size_t resampler_in_frames = frames * sample_rate_ratio; + get_reference_audio_in_place(aec, resampler_in_frames); + + int16_t* resampler_out_buf; + /* Resample to mic sampling rate (16-bit resampler) */ + if (aec->spk_resampler != NULL) { + size_t in_frame_count = resampler_in_frames; + size_t out_frame_count = frames; + aec->spk_resampler->resample_from_input(aec->spk_resampler, aec->spk_buf_playback_format, + &in_frame_count, aec->spk_buf_resampler_out, + &out_frame_count); + resampler_out_buf = aec->spk_buf_resampler_out; + } else { + if (sample_rate_ratio != 1) { + ALOGE("Speaker sample rate %d, mic sample rate %d but no resampler defined!", + aec->spk_sampling_rate, aec->mic_sampling_rate); + } + resampler_out_buf = aec->spk_buf_playback_format; + } + + /* Convert to 32 bit */ + int16_t* src16 = resampler_out_buf; + int32_t* dst32 = buffer; + size_t frame, ch; + for (frame = 0; frame < frames; frame++) { + for (ch = 0; ch < aec->num_reference_channels; ch++) { + *dst32++ = ((int32_t)*src16++) << 16; + } + } + + info->bytes = bytes; + + ALOGV("%s exit", __func__); + return 0; +} + +int init_aec_mic_config(struct aec_t *aec, struct alsa_stream_in *in) { + ALOGV("%s enter", __func__); +#if DEBUG_AEC + remove("/data/local/traces/aec_in.pcm"); + remove("/data/local/traces/aec_out.pcm"); + remove("/data/local/traces/aec_ref.pcm"); + remove("/data/local/traces/aec_timestamps.txt"); +#endif /* #if DEBUG_AEC */ + + if (!aec) { + ALOGE("AEC: No valid interface found!"); + return -EINVAL; + } + + int ret = 0; + pthread_mutex_lock(&aec->lock); + if (aec->mic_initialized) { + destroy_aec_mic_config_no_lock(aec); + } + aec->mic_sampling_rate = in->config.rate; + aec->mic_frame_size_bytes = audio_stream_in_frame_size(&in->stream); + aec->mic_num_channels = in->config.channels; + + aec->mic_buf_size_bytes = in->config.period_size * audio_stream_in_frame_size(&in->stream); + aec->mic_buf = (int32_t *)malloc(aec->mic_buf_size_bytes); + if (aec->mic_buf == NULL) { + ret = -ENOMEM; + goto exit; + } + memset(aec->mic_buf, 0, aec->mic_buf_size_bytes); + /* Reference buffer is the same number of frames as mic, + * only with a different number of channels in the frame. */ + aec->spk_buf_size_bytes = in->config.period_size * aec->spk_frame_size_bytes; + aec->spk_buf = (int32_t *)malloc(aec->spk_buf_size_bytes); + if (aec->spk_buf == NULL) { + ret = -ENOMEM; + goto exit_1; + } + memset(aec->spk_buf, 0, aec->spk_buf_size_bytes); + + /* Pre-resampler buffer */ + size_t spk_frame_out_format_bytes = aec->spk_sampling_rate / aec->mic_sampling_rate * + aec->spk_buf_size_bytes; + aec->spk_buf_playback_format = (int16_t *)malloc(spk_frame_out_format_bytes); + if (aec->spk_buf_playback_format == NULL) { + ret = -ENOMEM; + goto exit_2; + } + /* Resampler is 16-bit */ + aec->spk_buf_resampler_out = (int16_t *)malloc(aec->spk_buf_size_bytes); + if (aec->spk_buf_resampler_out == NULL) { + ret = -ENOMEM; + goto exit_3; + } + + /* Don't use resampler if it's not required */ + if (in->config.rate == aec->spk_sampling_rate) { + aec->spk_resampler = NULL; + } else { + int resampler_ret = create_resampler( + aec->spk_sampling_rate, in->config.rate, aec->num_reference_channels, + RESAMPLER_QUALITY_MAX - 1, /* MAX - 1 is the real max */ + NULL, /* resampler_buffer_provider */ + &aec->spk_resampler); + if (resampler_ret) { + ALOGE("AEC: Resampler initialization failed! Error code %d", resampler_ret); + ret = resampler_ret; + goto exit_4; + } + } + + flush_aec_fifos(aec); + aec_spk_mic_reset(); + aec->mic_initialized = true; + +exit: + pthread_mutex_unlock(&aec->lock); + ALOGV("%s exit", __func__); + return ret; + +exit_4: + free(aec->spk_buf_resampler_out); +exit_3: + free(aec->spk_buf_playback_format); +exit_2: + free(aec->spk_buf); +exit_1: + free(aec->mic_buf); + pthread_mutex_unlock(&aec->lock); + ALOGV("%s exit", __func__); + return ret; +} + +void aec_set_spk_running(struct aec_t *aec, bool state) { + ALOGV("%s enter", __func__); + pthread_mutex_lock(&aec->lock); + aec_set_spk_running_no_lock(aec, state); + pthread_mutex_unlock(&aec->lock); + ALOGV("%s exit", __func__); +} + +bool aec_get_spk_running(struct aec_t *aec) { + ALOGV("%s enter", __func__); + pthread_mutex_lock(&aec->lock); + bool state = aec_get_spk_running_no_lock(aec); + pthread_mutex_unlock(&aec->lock); + ALOGV("%s exit", __func__); + return state; +} + +void destroy_aec_mic_config(struct aec_t* aec) { + ALOGV("%s enter", __func__); + if (aec == NULL) { + ALOGV("%s exit", __func__); + return; + } + + pthread_mutex_lock(&aec->lock); + destroy_aec_mic_config_no_lock(aec); + pthread_mutex_unlock(&aec->lock); + ALOGV("%s exit", __func__); +} + +#ifdef AEC_HAL +int process_aec(struct aec_t *aec, void* buffer, struct aec_info *info) { + ALOGV("%s enter", __func__); + int ret = 0; + + if (aec == NULL) { + ALOGE("AEC: Interface uninitialized! Cannot process."); + return -EINVAL; + } + + if ((!aec->mic_initialized) || (!aec->spk_initialized)) { + ALOGE("%s called with initialization: mic: %d, spk: %d", __func__, aec->mic_initialized, + aec->spk_initialized); + return -EINVAL; + } + + size_t bytes = info->bytes; + + size_t frame_size = aec->mic_frame_size_bytes; + size_t in_frames = bytes / frame_size; + + /* Copy raw mic samples to AEC input buffer */ + memcpy(aec->mic_buf, buffer, bytes); + + uint64_t mic_time = timespec_to_usec(info->timestamp); + uint64_t spk_time = 0; + + /* + * Only run AEC if there is speaker playback. + * The first time speaker state changes to running, flush FIFOs, so we're not stuck + * processing stale reference input. + */ + bool spk_running = aec_get_spk_running(aec); + + if (!spk_running) { + /* No new playback samples, so don't run AEC. + * 'buffer' already contains input samples. */ + ALOGV("Speaker not running, skipping AEC.."); + goto exit; + } + + if (!aec->prev_spk_running) { + flush_aec_fifos(aec); + } + + /* If there's no data in FIFO, exit */ + if (fifo_available_to_read(aec->spk_fifo) <= 0) { + ALOGV("Echo reference buffer empty, zeroing reference...."); + goto exit; + } + + print_queue_status_to_log(aec, false); + + /* Get reference, with format and sample rate required by AEC */ + struct aec_info spk_info; + spk_info.bytes = bytes; + int ref_ret = get_reference_samples(aec, aec->spk_buf, &spk_info); + spk_time = spk_info.timestamp_usec; + + if (ref_ret) { + ALOGE("get_reference_samples returned code %d", ref_ret); + ret = -ENOMEM; + goto exit; + } + + int64_t time_diff = (mic_time > spk_time) ? (mic_time - spk_time) : (spk_time - mic_time); + if ((spk_time == 0) || (mic_time == 0) || (time_diff > MAX_TIMESTAMP_DIFF_USEC)) { + ALOGV("Speaker-mic timestamps diverged, skipping AEC"); + flush_aec_fifos(aec); + aec_spk_mic_reset(); + goto exit; + } + + ALOGV("Mic time: %"PRIu64", spk time: %"PRIu64, mic_time, spk_time); + + /* + * AEC processing call - output stored at 'buffer' + */ + int32_t aec_status = aec_spk_mic_process( + aec->spk_buf, spk_time, + aec->mic_buf, mic_time, + in_frames, + buffer); + + if (!aec_status) { + ALOGE("AEC processing failed!"); + ret = -EINVAL; + } + +exit: + aec->prev_spk_running = spk_running; + ALOGV("Mic time: %"PRIu64", spk time: %"PRIu64, mic_time, spk_time); + if (ret) { + /* Best we can do is copy over the raw mic signal */ + memcpy(buffer, aec->mic_buf, bytes); + flush_aec_fifos(aec); + aec_spk_mic_reset(); + } + +#if DEBUG_AEC + /* ref data is 32-bit at this point */ + size_t ref_bytes = in_frames*aec->num_reference_channels*sizeof(int32_t); + + FILE *fp_in = fopen("/data/local/traces/aec_in.pcm", "a+"); + if (fp_in) { + fwrite((char *)aec->mic_buf, 1, bytes, fp_in); + fclose(fp_in); + } else { + ALOGE("AEC debug: Could not open file aec_in.pcm!"); + } + FILE *fp_out = fopen("/data/local/traces/aec_out.pcm", "a+"); + if (fp_out) { + fwrite((char *)buffer, 1, bytes, fp_out); + fclose(fp_out); + } else { + ALOGE("AEC debug: Could not open file aec_out.pcm!"); + } + FILE *fp_ref = fopen("/data/local/traces/aec_ref.pcm", "a+"); + if (fp_ref) { + fwrite((char *)aec->spk_buf, 1, ref_bytes, fp_ref); + fclose(fp_ref); + } else { + ALOGE("AEC debug: Could not open file aec_ref.pcm!"); + } + FILE *fp_ts = fopen("/data/local/traces/aec_timestamps.txt", "a+"); + if (fp_ts) { + fprintf(fp_ts, "%"PRIu64",%"PRIu64"\n", mic_time, spk_time); + fclose(fp_ts); + } else { + ALOGE("AEC debug: Could not open file aec_timestamps.txt!"); + } +#endif /* #if DEBUG_AEC */ + ALOGV("%s exit", __func__); + return ret; +} + +#endif /*#ifdef AEC_HAL*/ diff --git a/audio/audio_aec.h b/audio/audio_aec.h new file mode 100644 index 0000000..ac7a1dd --- /dev/null +++ b/audio/audio_aec.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2019 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. + */ + +/* + * Definitions and interface related to HAL implementations of Acoustic Echo Canceller (AEC). + * + * AEC cleans the microphone signal by removing from it audio data corresponding to loudspeaker + * playback. Note that this process can be nonlinear. + * + */ + +#ifndef _AUDIO_AEC_H_ +#define _AUDIO_AEC_H_ + +#include +#include +#include +#include +#include +#include "audio_hw.h" +#include "fifo_wrapper.h" + +struct aec_t { + pthread_mutex_t lock; + size_t num_reference_channels; + bool mic_initialized; + int32_t *mic_buf; + size_t mic_num_channels; + size_t mic_buf_size_bytes; + size_t mic_frame_size_bytes; + uint32_t mic_sampling_rate; + struct aec_info last_mic_info; + bool spk_initialized; + int32_t *spk_buf; + size_t spk_num_channels; + size_t spk_buf_size_bytes; + size_t spk_frame_size_bytes; + uint32_t spk_sampling_rate; + struct aec_info last_spk_info; + int16_t *spk_buf_playback_format; + int16_t *spk_buf_resampler_out; + void *spk_fifo; + void *ts_fifo; + ssize_t read_write_diff_bytes; + struct resampler_itfe *spk_resampler; + bool spk_running; + bool prev_spk_running; +}; + +/* Initialize AEC object. + * This must be called when the audio device is opened. + * ALSA device mutex must be held before calling this API. + * Returns -EINVAL if AEC object fails to initialize, else returns 0. */ +int init_aec (int sampling_rate, int num_reference_channels, + int num_microphone_channels, struct aec_t **); + +/* Release AEC object. + * This must be called when the audio device is closed. */ +void release_aec(struct aec_t* aec); + +/* Initialize reference configuration for AEC. + * Must be called when a new output stream is opened. + * Returns -EINVAL if any processing block fails to initialize, + * else returns 0. */ +int init_aec_reference_config (struct aec_t *aec, struct alsa_stream_out *out); + +/* Clear reference configuration for AEC. + * Must be called when the output stream is closed. */ +void destroy_aec_reference_config (struct aec_t *aec); + +/* Initialize microphone configuration for AEC. + * Must be called when a new input stream is opened. + * Returns -EINVAL if any processing block fails to initialize, + * else returns 0. */ +int init_aec_mic_config(struct aec_t* aec, struct alsa_stream_in* in); + +/* Clear microphone configuration for AEC. + * Must be called when the input stream is closed. */ +void destroy_aec_mic_config (struct aec_t *aec); + +/* Used to communicate playback state (running or not) to AEC interface. + * This is used by process_aec() to determine if AEC processing is to be run. */ +void aec_set_spk_running (struct aec_t *aec, bool state); + +/* Used to communicate playback state (running or not) to the caller. */ +bool aec_get_spk_running(struct aec_t* aec); + +/* Write audio samples to AEC reference FIFO for use in AEC. + * Both audio samples and timestamps are added in FIFO fashion. + * Must be called after every write to PCM. + * Returns -ENOMEM if the write fails, else returns 0. */ +int write_to_reference_fifo(struct aec_t* aec, void* buffer, struct aec_info* info); + +/* Get reference audio samples + timestamp, in the format expected by AEC, + * i.e. same sample rate and bit rate as microphone audio. + * Timestamp is updated in field 'timestamp_usec', and not in 'timestamp'. + * Returns: + * -EINVAL if the AEC object is invalid. + * -ENOMEM if the reference FIFO overflows or is corrupted. + * -ETIMEDOUT if we timed out waiting for the requested number of bytes + * 0 otherwise */ +int get_reference_samples(struct aec_t* aec, void* buffer, struct aec_info* info); + +#ifdef AEC_HAL + +/* Processing function call for AEC. + * AEC output is updated at location pointed to by 'buffer'. + * This function does not run AEC when there is no playback - + * as communicated to this AEC interface using aec_set_spk_running(). + * Returns -EINVAL if processing fails, else returns 0. */ +int process_aec(struct aec_t* aec, void* buffer, struct aec_info* info); + +#else /* #ifdef AEC_HAL */ + +#define process_aec(...) ((int)0) + +#endif /* #ifdef AEC_HAL */ + +#endif /* _AUDIO_AEC_H_ */ diff --git a/audio/audio_hw.c b/audio/audio_hw.c index 805e2cd..4a16ac1 100644 --- a/audio/audio_hw.c +++ b/audio/audio_hw.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2016 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. @@ -13,811 +13,494 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copied as it is from device/google/cuttlefish/guest/hals/audio/audio_hw.c - * and fixed couple of typos pointed out by Lint during review. + * Copied as it is from device/amlogic/generic/hal/audio/ */ -#define LOG_TAG "audio_hw_generic" +#define LOG_TAG "audio_hw_yukawa" +//#define LOG_NDEBUG 0 -#include #include #include +#include #include #include #include #include -#include -#include #include #include -#include #include +#include #include #include #include -#include -#define PCM_CARD 0 -#define PCM_DEVICE 0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#define OUT_PERIOD_MS 15 -#define OUT_PERIOD_COUNT 4 +#include "audio_aec.h" +#include "audio_hw.h" -#define IN_PERIOD_MS 15 -#define IN_PERIOD_COUNT 4 +static int adev_get_mic_mute(const struct audio_hw_device* dev, bool* state); +static int adev_get_microphones(const struct audio_hw_device* dev, + struct audio_microphone_characteristic_t* mic_array, + size_t* mic_count); +static size_t out_get_buffer_size(const struct audio_stream* stream); -struct generic_audio_device { - struct audio_hw_device device; // Constant after init - pthread_mutex_t lock; - bool mic_mute; // Protected by this->lock - struct mixer* mixer; // Protected by this->lock - struct listnode out_streams; // Record for output streams, protected by this->lock - struct listnode in_streams; // Record for input streams, protected by this->lock - audio_patch_handle_t next_patch_handle; // Protected by this->lock -}; +static int get_audio_output_port(audio_devices_t devices) { + /* Only HDMI out for now #FIXME */ + return PORT_HDMI; +} -/* If not NULL, this is a pointer to the fallback module. - * This really is the original goldfish audio device /dev/eac which we will use - * if no alsa devices are detected. - */ -static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state); -static int adev_get_microphones(const audio_hw_device_t *dev, - struct audio_microphone_characteristic_t *mic_array, - size_t *mic_count); - - -typedef struct audio_vbuffer { - pthread_mutex_t lock; - uint8_t * data; - size_t frame_size; - size_t frame_count; - size_t head; - size_t tail; - size_t live; -} audio_vbuffer_t; - -static int audio_vbuffer_init (audio_vbuffer_t * audio_vbuffer, size_t frame_count, - size_t frame_size) { - if (!audio_vbuffer) { - return -EINVAL; +static void timestamp_adjust(struct timespec* ts, ssize_t frames, uint32_t sampling_rate) { + /* This function assumes the adjustment (in nsec) is less than the max value of long, + * which for 32-bit long this is 2^31 * 1e-9 seconds, slightly over 2 seconds. + * For 64-bit long it is 9e+9 seconds. */ + long adj_nsec = (frames / (float) sampling_rate) * 1E9L; + ts->tv_nsec += adj_nsec; + while (ts->tv_nsec > 1E9L) { + ts->tv_sec++; + ts->tv_nsec -= 1E9L; } - audio_vbuffer->frame_size = frame_size; - audio_vbuffer->frame_count = frame_count; - size_t bytes = frame_count * frame_size; - audio_vbuffer->data = calloc(bytes, 1); - if (!audio_vbuffer->data) { - return -ENOMEM; + if (ts->tv_nsec < 0) { + ts->tv_sec--; + ts->tv_nsec += 1E9L; } - audio_vbuffer->head = 0; - audio_vbuffer->tail = 0; - audio_vbuffer->live = 0; - pthread_mutex_init (&audio_vbuffer->lock, (const pthread_mutexattr_t *) NULL); - return 0; } -static int audio_vbuffer_destroy (audio_vbuffer_t * audio_vbuffer) { - if (!audio_vbuffer) { +/* Helper function to get PCM hardware timestamp. + * Only the field 'timestamp' of argument 'ts' is updated. */ +static int get_pcm_timestamp(struct pcm* pcm, uint32_t sample_rate, struct aec_info* info, + bool isOutput) { + int ret = 0; + if (pcm_get_htimestamp(pcm, &info->available, &info->timestamp) < 0) { + ALOGE("Error getting PCM timestamp!"); + info->timestamp.tv_sec = 0; + info->timestamp.tv_nsec = 0; return -EINVAL; } - free(audio_vbuffer->data); - pthread_mutex_destroy(&audio_vbuffer->lock); - return 0; + ssize_t frames; + if (isOutput) { + frames = pcm_get_buffer_size(pcm) - info->available; + } else { + frames = -info->available; /* rewind timestamp */ + } + timestamp_adjust(&info->timestamp, frames, sample_rate); + return ret; } -static int audio_vbuffer_live (audio_vbuffer_t * audio_vbuffer) { - if (!audio_vbuffer) { - return -EINVAL; +static int read_filter_from_file(const char* filename, int16_t* filter, int max_length) { + FILE* fp = fopen(filename, "r"); + if (fp == NULL) { + ALOGI("%s: File %s not found.", __func__, filename); + return 0; } - pthread_mutex_lock (&audio_vbuffer->lock); - int live = audio_vbuffer->live; - pthread_mutex_unlock (&audio_vbuffer->lock); - return live; -} - -#define MIN(a,b) (((a)<(b))?(a):(b)) -static size_t audio_vbuffer_write (audio_vbuffer_t * audio_vbuffer, const void * buffer, size_t frame_count) { - size_t frames_written = 0; - pthread_mutex_lock (&audio_vbuffer->lock); - - while (frame_count != 0) { - int frames = 0; - if (audio_vbuffer->live == 0 || audio_vbuffer->head > audio_vbuffer->tail) { - frames = MIN(frame_count, audio_vbuffer->frame_count - audio_vbuffer->head); - } else if (audio_vbuffer->head < audio_vbuffer->tail) { - frames = MIN(frame_count, audio_vbuffer->tail - (audio_vbuffer->head)); - } else { - // Full + int num_taps = 0; + char* line = NULL; + size_t len = 0; + while (!feof(fp)) { + size_t size = getline(&line, &len, fp); + if ((line[0] == '#') || (size < 2)) { + continue; + } + int n = sscanf(line, "%" SCNd16 "\n", &filter[num_taps++]); + if (n < 1) { + ALOGE("Could not find coefficient %d! Exiting...", num_taps - 1); + return 0; + } + ALOGV("Coeff %d : %" PRId16, num_taps, filter[num_taps - 1]); + if (num_taps == max_length) { + ALOGI("%s: max tap length %d reached.", __func__, max_length); break; } - memcpy(&audio_vbuffer->data[audio_vbuffer->head*audio_vbuffer->frame_size], - &((uint8_t*)buffer)[frames_written*audio_vbuffer->frame_size], - frames*audio_vbuffer->frame_size); - audio_vbuffer->live += frames; - frames_written += frames; - frame_count -= frames; - audio_vbuffer->head = (audio_vbuffer->head + frames) % audio_vbuffer->frame_count; } - - pthread_mutex_unlock (&audio_vbuffer->lock); - return frames_written; + free(line); + fclose(fp); + return num_taps; } -static size_t audio_vbuffer_read (audio_vbuffer_t * audio_vbuffer, void * buffer, size_t frame_count) { - size_t frames_read = 0; - pthread_mutex_lock (&audio_vbuffer->lock); +static void out_set_eq(struct alsa_stream_out* out) { + out->speaker_eq = NULL; + int16_t* speaker_eq_coeffs = (int16_t*)calloc(SPEAKER_MAX_EQ_LENGTH, sizeof(int16_t)); + if (speaker_eq_coeffs == NULL) { + ALOGE("%s: Failed to allocate speaker EQ", __func__); + return; + } + int num_taps = read_filter_from_file(SPEAKER_EQ_FILE, speaker_eq_coeffs, SPEAKER_MAX_EQ_LENGTH); + if (num_taps == 0) { + ALOGI("%s: Empty filter file or 0 taps set.", __func__); + free(speaker_eq_coeffs); + return; + } + out->speaker_eq = fir_init( + out->config.channels, FIR_SINGLE_FILTER, num_taps, + out_get_buffer_size(&out->stream.common) / out->config.channels / sizeof(int16_t), + speaker_eq_coeffs); + free(speaker_eq_coeffs); +} - while (frame_count != 0) { - int frames = 0; - if (audio_vbuffer->live == audio_vbuffer->frame_count || - audio_vbuffer->tail > audio_vbuffer->head) { - frames = MIN(frame_count, audio_vbuffer->frame_count - audio_vbuffer->tail); - } else if (audio_vbuffer->tail < audio_vbuffer->head) { - frames = MIN(frame_count, audio_vbuffer->head - audio_vbuffer->tail); - } else { +/* must be called with hw device and output stream mutexes locked */ +static int start_output_stream(struct alsa_stream_out *out) +{ + struct alsa_audio_device *adev = out->dev; + + /* default to low power: will be corrected in out_write if necessary before first write to + * tinyalsa. + */ + out->write_threshold = PLAYBACK_PERIOD_COUNT * PLAYBACK_PERIOD_SIZE; + out->config.start_threshold = PLAYBACK_PERIOD_START_THRESHOLD * PLAYBACK_PERIOD_SIZE; + out->config.avail_min = PLAYBACK_PERIOD_SIZE; + out->unavailable = true; + unsigned int pcm_retry_count = PCM_OPEN_RETRIES; + int out_port = get_audio_output_port(out->devices); + + while (1) { + out->pcm = pcm_open(CARD_OUT, out_port, PCM_OUT | PCM_MONOTONIC, &out->config); + if ((out->pcm != NULL) && pcm_is_ready(out->pcm)) { break; + } else { + ALOGE("cannot open pcm_out driver: %s", pcm_get_error(out->pcm)); + if (out->pcm != NULL) { + pcm_close(out->pcm); + out->pcm = NULL; + } + if (--pcm_retry_count == 0) { + ALOGE("Failed to open pcm_out after %d tries", PCM_OPEN_RETRIES); + return -ENODEV; + } + usleep(PCM_OPEN_WAIT_TIME_MS * 1000); } - memcpy(&((uint8_t*)buffer)[frames_read*audio_vbuffer->frame_size], - &audio_vbuffer->data[audio_vbuffer->tail*audio_vbuffer->frame_size], - frames*audio_vbuffer->frame_size); - audio_vbuffer->live -= frames; - frames_read += frames; - frame_count -= frames; - audio_vbuffer->tail = (audio_vbuffer->tail + frames) % audio_vbuffer->frame_count; } - - pthread_mutex_unlock (&audio_vbuffer->lock); - return frames_read; -} - -struct generic_stream_out { - struct audio_stream_out stream; // Constant after init - pthread_mutex_t lock; - struct generic_audio_device *dev; // Constant after init - uint32_t num_devices; // Protected by this->lock - audio_devices_t devices[AUDIO_PATCH_PORTS_MAX]; // Protected by this->lock - struct audio_config req_config; // Constant after init - struct pcm_config pcm_config; // Constant after init - audio_vbuffer_t buffer; // Constant after init - - // Time & Position Keeping - bool standby; // Protected by this->lock - uint64_t underrun_position; // Protected by this->lock - struct timespec underrun_time; // Protected by this->lock - uint64_t last_write_time_us; // Protected by this->lock - uint64_t frames_total_buffered; // Protected by this->lock - uint64_t frames_written; // Protected by this->lock - uint64_t frames_rendered; // Protected by this->lock - - // Worker - pthread_t worker_thread; // Constant after init - pthread_cond_t worker_wake; // Protected by this->lock - bool worker_standby; // Protected by this->lock - bool worker_exit; // Protected by this->lock - - audio_io_handle_t handle; // Constant after init - audio_patch_handle_t patch_handle; // Protected by this->dev->lock - - struct listnode stream_node; // Protected by this->dev->lock -}; - -struct generic_stream_in { - struct audio_stream_in stream; // Constant after init - pthread_mutex_t lock; - struct generic_audio_device *dev; // Constant after init - audio_devices_t device; // Protected by this->lock - struct audio_config req_config; // Constant after init - struct pcm *pcm; // Protected by this->lock - struct pcm_config pcm_config; // Constant after init - int16_t *stereo_to_mono_buf; // Protected by this->lock - size_t stereo_to_mono_buf_size; // Protected by this->lock - audio_vbuffer_t buffer; // Protected by this->lock - - // Time & Position Keeping - bool standby; // Protected by this->lock - int64_t standby_position; // Protected by this->lock - struct timespec standby_exit_time;// Protected by this->lock - int64_t standby_frames_read; // Protected by this->lock - - // Worker - pthread_t worker_thread; // Constant after init - pthread_cond_t worker_wake; // Protected by this->lock - bool worker_standby; // Protected by this->lock - bool worker_exit; // Protected by this->lock - - audio_io_handle_t handle; // Constant after init - audio_patch_handle_t patch_handle; // Protected by this->dev->lock - - struct listnode stream_node; // Protected by this->dev->lock -}; - -static struct pcm_config pcm_config_out = { - .channels = 2, - .rate = 0, - .period_size = 0, - .period_count = OUT_PERIOD_COUNT, - .format = PCM_FORMAT_S16_LE, - .start_threshold = 0, -}; - -static struct pcm_config pcm_config_in = { - .channels = 2, - .rate = 0, - .period_size = 0, - .period_count = IN_PERIOD_COUNT, - .format = PCM_FORMAT_S16_LE, - .start_threshold = 0, - .stop_threshold = INT_MAX, -}; - -static pthread_mutex_t adev_init_lock = PTHREAD_MUTEX_INITIALIZER; -static unsigned int audio_device_ref_count = 0; + out->unavailable = false; + adev->active_output = out; + return 0; +} static uint32_t out_get_sample_rate(const struct audio_stream *stream) { - struct generic_stream_out *out = (struct generic_stream_out *)stream; - return out->req_config.sample_rate; + struct alsa_stream_out *out = (struct alsa_stream_out *)stream; + return out->config.rate; } static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) { + ALOGV("out_set_sample_rate: %d", 0); return -ENOSYS; } static size_t out_get_buffer_size(const struct audio_stream *stream) { - struct generic_stream_out *out = (struct generic_stream_out *)stream; - int size = out->pcm_config.period_size * - audio_stream_out_frame_size(&out->stream); + ALOGV("out_get_buffer_size: %d", 4096); - return size; + /* return the closest majoring multiple of 16 frames, as + * audioflinger expects audio buffers to be a multiple of 16 frames */ + size_t size = PLAYBACK_PERIOD_SIZE; + size = ((size + 15) / 16) * 16; + return size * audio_stream_out_frame_size((struct audio_stream_out *)stream); } static audio_channel_mask_t out_get_channels(const struct audio_stream *stream) { - struct generic_stream_out *out = (struct generic_stream_out *)stream; - return out->req_config.channel_mask; + ALOGV("out_get_channels"); + struct alsa_stream_out *out = (struct alsa_stream_out *)stream; + return audio_channel_out_mask_from_count(out->config.channels); } static audio_format_t out_get_format(const struct audio_stream *stream) { - struct generic_stream_out *out = (struct generic_stream_out *)stream; - - return out->req_config.format; + ALOGV("out_get_format"); + struct alsa_stream_out *out = (struct alsa_stream_out *)stream; + return audio_format_from_pcm_format(out->config.format); } static int out_set_format(struct audio_stream *stream, audio_format_t format) { + ALOGV("out_set_format: %d",format); return -ENOSYS; } -static int out_dump(const struct audio_stream *stream, int fd) +static int do_output_standby(struct alsa_stream_out *out) { - struct generic_stream_out *out = (struct generic_stream_out *)stream; - pthread_mutex_lock(&out->lock); - dprintf(fd, "\tout_dump:\n" - "\t\tsample rate: %u\n" - "\t\tbuffer size: %zu\n" - "\t\tchannel mask: %08x\n" - "\t\tformat: %d\n" - "\t\tdevice(s): ", - out_get_sample_rate(stream), - out_get_buffer_size(stream), - out_get_channels(stream), - out_get_format(stream)); - if (out->num_devices == 0) { - dprintf(fd, "%08x\n", AUDIO_DEVICE_NONE); - } else { - for (uint32_t i = 0; i < out->num_devices; i++) { - if (i != 0) { - dprintf(fd, ", "); - } - dprintf(fd, "%08x", out->devices[i]); - } - dprintf(fd, "\n"); + struct alsa_audio_device *adev = out->dev; + + fir_reset(out->speaker_eq); + + if (!out->standby) { + pcm_close(out->pcm); + out->pcm = NULL; + adev->active_output = NULL; + out->standby = 1; } - dprintf(fd, "\t\taudio dev: %p\n\n", out->dev); + aec_set_spk_running(adev->aec, false); + return 0; +} + +static int out_standby(struct audio_stream *stream) +{ + ALOGV("out_standby"); + struct alsa_stream_out *out = (struct alsa_stream_out *)stream; + int status; + + pthread_mutex_lock(&out->dev->lock); + pthread_mutex_lock(&out->lock); + status = do_output_standby(out); pthread_mutex_unlock(&out->lock); + pthread_mutex_unlock(&out->dev->lock); + return status; +} + +static int out_dump(const struct audio_stream *stream, int fd) +{ + ALOGV("out_dump"); return 0; } static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) { + ALOGV("out_set_parameters"); + struct alsa_stream_out *out = (struct alsa_stream_out *)stream; + struct alsa_audio_device *adev = out->dev; struct str_parms *parms; char value[32]; - int success; - int ret = -EINVAL; + int ret, val = 0; - if (kvpairs == NULL || kvpairs[0] == 0) { - return 0; - } parms = str_parms_create_str(kvpairs); - success = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, - value, sizeof(value)); - // As the hal version is 3.0, it must not use set parameters API to set audio devices. - // Instead, it should use create_audio_patch API. - assert(("Must not use set parameters API to set audio devices", success < 0)); - - if (str_parms_has_key(parms, AUDIO_PARAMETER_STREAM_FORMAT)) { - // match the return value of out_set_format - ret = -ENOSYS; - } - - str_parms_destroy(parms); - if (ret == -EINVAL) { - ALOGW("%s(), unsupported parameter %s", __func__, kvpairs); - // There is not any key supported for set_parameters API. - // Return error when there is non-null value passed in. - } - return ret; -} - -static char * out_get_parameters(const struct audio_stream *stream, const char *keys) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - struct str_parms *query = str_parms_create_str(keys); - char *str = NULL; - char value[256]; - struct str_parms *reply = str_parms_create(); - int ret; - bool get = false; - - ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); + ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); if (ret >= 0) { + val = atoi(value); + pthread_mutex_lock(&adev->lock); pthread_mutex_lock(&out->lock); - audio_devices_t device = AUDIO_DEVICE_NONE; - for (uint32_t i = 0; i < out->num_devices; i++) { - device |= out->devices[i]; + if (((out->devices & AUDIO_DEVICE_OUT_ALL) != val) && (val != 0)) { + out->devices &= ~AUDIO_DEVICE_OUT_ALL; + out->devices |= val; } - str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_ROUTING, device); pthread_mutex_unlock(&out->lock); - get = true; - } - - if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) { - value[0] = 0; - strcat(value, "AUDIO_FORMAT_PCM_16_BIT"); - str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value); - get = true; - } - - if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_FORMAT)) { - value[0] = 0; - strcat(value, "AUDIO_FORMAT_PCM_16_BIT"); - str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_FORMAT, value); - get = true; + pthread_mutex_unlock(&adev->lock); } - if (get) { - str = str_parms_to_str(reply); - } - else { - ALOGD("%s Unsupported parameter: %s", __FUNCTION__, keys); - } + str_parms_destroy(parms); + return 0; +} - str_parms_destroy(query); - str_parms_destroy(reply); - return str; +static char * out_get_parameters(const struct audio_stream *stream, const char *keys) +{ + ALOGV("out_get_parameters"); + return strdup(""); } static uint32_t out_get_latency(const struct audio_stream_out *stream) { - struct generic_stream_out *out = (struct generic_stream_out *)stream; - return (out->pcm_config.period_size * 1000) / out->pcm_config.rate; + ALOGV("out_get_latency"); + struct alsa_stream_out *out = (struct alsa_stream_out *)stream; + return (PLAYBACK_PERIOD_SIZE * PLAYBACK_PERIOD_COUNT * 1000) / out->config.rate; } static int out_set_volume(struct audio_stream_out *stream, float left, - float right) + float right) { + ALOGV("out_set_volume: Left:%f Right:%f", left, right); return -ENOSYS; } -static void *out_write_worker(void * args) +static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, + size_t bytes) { - struct generic_stream_out *out = (struct generic_stream_out *)args; - struct pcm *pcm = NULL; - uint8_t *buffer = NULL; - int buffer_frames; - int buffer_size; - bool restart = false; - bool shutdown = false; - while (true) { - pthread_mutex_lock(&out->lock); - while (out->worker_standby || restart) { - restart = false; - if (pcm) { - pcm_close(pcm); // Frees pcm - pcm = NULL; - free(buffer); - buffer=NULL; - } - if (out->worker_exit) { - break; - } - pthread_cond_wait(&out->worker_wake, &out->lock); - } - - if (out->worker_exit) { - if (!out->worker_standby) { - ALOGE("Out worker not in standby before exiting"); - } - shutdown = true; - } - - while (!shutdown && audio_vbuffer_live(&out->buffer) == 0) { - pthread_cond_wait(&out->worker_wake, &out->lock); - } - - if (shutdown) { - pthread_mutex_unlock(&out->lock); - break; - } - - if (!pcm) { - pcm = pcm_open(PCM_CARD, PCM_DEVICE, - PCM_OUT | PCM_MONOTONIC, &out->pcm_config); - if (!pcm_is_ready(pcm)) { - ALOGE("pcm_open(out) failed: %s: channels %d format %d rate %d", - pcm_get_error(pcm), - out->pcm_config.channels, - out->pcm_config.format, - out->pcm_config.rate - ); - pthread_mutex_unlock(&out->lock); - break; - } - buffer_frames = out->pcm_config.period_size; - buffer_size = pcm_frames_to_bytes(pcm, buffer_frames); - buffer = malloc(buffer_size); - if (!buffer) { - ALOGE("could not allocate write buffer"); - pthread_mutex_unlock(&out->lock); - break; - } - } - int frames = audio_vbuffer_read(&out->buffer, buffer, buffer_frames); - pthread_mutex_unlock(&out->lock); - int ret = pcm_write(pcm, buffer, pcm_frames_to_bytes(pcm, frames)); - if (ret != 0) { - ALOGE("pcm_write failed %s", pcm_get_error(pcm)); - restart = true; - } - } - if (buffer) { - free(buffer); - } + int ret; + struct alsa_stream_out *out = (struct alsa_stream_out *)stream; + struct alsa_audio_device *adev = out->dev; + size_t frame_size = audio_stream_out_frame_size(stream); + size_t out_frames = bytes / frame_size; - return NULL; -} + ALOGV("%s: devices: %d, bytes %zu", __func__, out->devices, bytes); -// Call with in->lock held -static void get_current_output_position(struct generic_stream_out *out, - uint64_t * position, - struct timespec * timestamp) { - struct timespec curtime = { .tv_sec = 0, .tv_nsec = 0 }; - clock_gettime(CLOCK_MONOTONIC, &curtime); - const int64_t now_us = (curtime.tv_sec * 1000000000LL + curtime.tv_nsec) / 1000; - if (timestamp) { - *timestamp = curtime; - } - int64_t position_since_underrun; + /* acquiring hw device mutex systematically is useful if a low priority thread is waiting + * on the output stream mutex - e.g. executing select_mode() while holding the hw device + * mutex + */ + pthread_mutex_lock(&adev->lock); + pthread_mutex_lock(&out->lock); if (out->standby) { - position_since_underrun = 0; - } else { - const int64_t first_us = (out->underrun_time.tv_sec * 1000000000LL + - out->underrun_time.tv_nsec) / 1000; - position_since_underrun = (now_us - first_us) * - out_get_sample_rate(&out->stream.common) / - 1000000; - if (position_since_underrun < 0) { - position_since_underrun = 0; + ret = start_output_stream(out); + if (ret != 0) { + pthread_mutex_unlock(&adev->lock); + goto exit; } - } - *position = out->underrun_position + position_since_underrun; - - // The device will reuse the same output stream leading to periods of - // underrun. - if (*position > out->frames_written) { - ALOGW("Not supplying enough data to HAL, expected position %" PRIu64 " , only wrote " - "%" PRIu64, - *position, out->frames_written); - - *position = out->frames_written; - out->underrun_position = *position; - out->underrun_time = curtime; - out->frames_total_buffered = 0; - } -} - - -static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, - size_t bytes) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - const size_t frames = bytes / audio_stream_out_frame_size(stream); - - pthread_mutex_lock(&out->lock); - - if (out->worker_standby) { - out->worker_standby = false; + out->standby = 0; + aec_set_spk_running(adev->aec, true); } - uint64_t current_position; - struct timespec current_time; + pthread_mutex_unlock(&adev->lock); - get_current_output_position(out, ¤t_position, ¤t_time); - const uint64_t now_us = (current_time.tv_sec * 1000000000LL + - current_time.tv_nsec) / 1000; - if (out->standby) { - out->standby = false; - out->underrun_time = current_time; - out->frames_rendered = 0; - out->frames_total_buffered = 0; + if (out->speaker_eq != NULL) { + fir_process_interleaved(out->speaker_eq, (int16_t*)buffer, (int16_t*)buffer, out_frames); } - size_t frames_written = audio_vbuffer_write(&out->buffer, buffer, frames); - pthread_cond_signal(&out->worker_wake); - - /* Implementation just consumes bytes if we start getting backed up */ - out->frames_written += frames; - out->frames_rendered += frames; - out->frames_total_buffered += frames; - - // We simulate the audio device blocking when it's write buffers become - // full. - - // At the beginning or after an underrun, try to fill up the vbuffer. - // This will be throttled by the PlaybackThread - int frames_sleep = out->frames_total_buffered < out->buffer.frame_count ? 0 : frames; - - uint64_t sleep_time_us = frames_sleep * 1000000LL / - out_get_sample_rate(&stream->common); - - // If the write calls are delayed, subtract time off of the sleep to - // compensate - uint64_t time_since_last_write_us = now_us - out->last_write_time_us; - if (time_since_last_write_us < sleep_time_us) { - sleep_time_us -= time_since_last_write_us; - } else { - sleep_time_us = 0; + ret = pcm_write(out->pcm, buffer, out_frames * frame_size); + if (ret == 0) { + out->frames_written += out_frames; + + struct aec_info info; + get_pcm_timestamp(out->pcm, out->config.rate, &info, true /*isOutput*/); + out->timestamp = info.timestamp; + info.bytes = out_frames * frame_size; + int aec_ret = write_to_reference_fifo(adev->aec, (void *)buffer, &info); + if (aec_ret) { + ALOGE("AEC: Write to speaker loopback FIFO failed!"); + } } - out->last_write_time_us = now_us + sleep_time_us; +exit: pthread_mutex_unlock(&out->lock); - if (sleep_time_us > 0) { - usleep(sleep_time_us); + if (ret != 0) { + usleep((int64_t)bytes * 1000000 / audio_stream_out_frame_size(stream) / + out_get_sample_rate(&stream->common)); } - if (frames_written < frames) { - ALOGW("Hardware backing HAL too slow, could only write %zu of %zu frames", frames_written, frames); - } - - /* Always consume all bytes */ return bytes; } +static int out_get_render_position(const struct audio_stream_out *stream, + uint32_t *dsp_frames) +{ + ALOGV("out_get_render_position: dsp_frames: %p", dsp_frames); + return -ENOSYS; +} + static int out_get_presentation_position(const struct audio_stream_out *stream, uint64_t *frames, struct timespec *timestamp) - { if (stream == NULL || frames == NULL || timestamp == NULL) { return -EINVAL; } - struct generic_stream_out *out = (struct generic_stream_out *)stream; + struct alsa_stream_out* out = (struct alsa_stream_out*)stream; - pthread_mutex_lock(&out->lock); - get_current_output_position(out, frames, timestamp); - pthread_mutex_unlock(&out->lock); + *frames = out->frames_written; + *timestamp = out->timestamp; + ALOGV("%s: frames: %" PRIu64 ", timestamp (nsec): %" PRIu64, __func__, *frames, + audio_utils_ns_from_timespec(timestamp)); return 0; } -static int out_get_render_position(const struct audio_stream_out *stream, - uint32_t *dsp_frames) -{ - if (stream == NULL || dsp_frames == NULL) { - return -EINVAL; - } - struct generic_stream_out *out = (struct generic_stream_out *)stream; - pthread_mutex_lock(&out->lock); - *dsp_frames = out->frames_rendered; - pthread_mutex_unlock(&out->lock); - return 0; -} - -// Must be called with out->lock held -static void do_out_standby(struct generic_stream_out *out) -{ - int frames_sleep = 0; - uint64_t sleep_time_us = 0; - if (out->standby) { - return; - } - while (true) { - get_current_output_position(out, &out->underrun_position, NULL); - frames_sleep = out->frames_written - out->underrun_position; - - if (frames_sleep == 0) { - break; - } - - sleep_time_us = frames_sleep * 1000000LL / - out_get_sample_rate(&out->stream.common); - - pthread_mutex_unlock(&out->lock); - usleep(sleep_time_us); - pthread_mutex_lock(&out->lock); - } - out->worker_standby = true; - out->standby = true; -} - -static int out_standby(struct audio_stream *stream) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - pthread_mutex_lock(&out->lock); - do_out_standby(out); - pthread_mutex_unlock(&out->lock); - return 0; -} static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) { - // out_add_audio_effect is a no op + ALOGV("out_add_audio_effect: %p", effect); return 0; } static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) { - // out_remove_audio_effect is a no op + ALOGV("out_remove_audio_effect: %p", effect); return 0; } static int out_get_next_write_timestamp(const struct audio_stream_out *stream, - int64_t *timestamp) + int64_t *timestamp) { + *timestamp = 0; + ALOGV("out_get_next_write_timestamp: %ld", (long int)(*timestamp)); return -ENOSYS; } -static uint32_t in_get_sample_rate(const struct audio_stream *stream) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - return in->req_config.sample_rate; -} +/** audio_stream_in implementation **/ -static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) +/* must be called with hw device and input stream mutexes locked */ +static int start_input_stream(struct alsa_stream_in *in) { - return -ENOSYS; -} + struct alsa_audio_device *adev = in->dev; + in->unavailable = true; + unsigned int pcm_retry_count = PCM_OPEN_RETRIES; -static int refine_output_parameters(uint32_t *sample_rate, audio_format_t *format, audio_channel_mask_t *channel_mask) -{ - static const uint32_t sample_rates [] = {8000,11025,16000,22050,24000,32000, - 44100,48000}; - static const int sample_rates_count = sizeof(sample_rates)/sizeof(uint32_t); - bool inval = false; - if (*format != AUDIO_FORMAT_PCM_16_BIT) { - *format = AUDIO_FORMAT_PCM_16_BIT; - inval = true; - } - - int channel_count = popcount(*channel_mask); - if (channel_count != 1 && channel_count != 2) { - *channel_mask = AUDIO_CHANNEL_IN_STEREO; - inval = true; - } - - int i; - for (i = 0; i < sample_rates_count; i++) { - if (*sample_rate < sample_rates[i]) { - *sample_rate = sample_rates[i]; - inval=true; - break; - } - else if (*sample_rate == sample_rates[i]) { + while (1) { + in->pcm = pcm_open(CARD_IN, PORT_BUILTIN_MIC, PCM_IN | PCM_MONOTONIC, &in->config); + if ((in->pcm != NULL) && pcm_is_ready(in->pcm)) { break; + } else { + ALOGE("cannot open pcm_in driver: %s", pcm_get_error(in->pcm)); + if (in->pcm != NULL) { + pcm_close(in->pcm); + in->pcm = NULL; + } + if (--pcm_retry_count == 0) { + ALOGE("Failed to open pcm_in after %d tries", PCM_OPEN_RETRIES); + return -ENODEV; + } + usleep(PCM_OPEN_WAIT_TIME_MS * 1000); } - else if (i == sample_rates_count-1) { - // Cap it to the highest rate we support - *sample_rate = sample_rates[i]; - inval=true; - } - } - - if (inval) { - return -EINVAL; } + in->unavailable = false; + adev->active_input = in; return 0; } -static int refine_input_parameters(uint32_t *sample_rate, audio_format_t *format, audio_channel_mask_t *channel_mask) -{ - static const uint32_t sample_rates [] = {8000, 11025, 16000, 22050, 44100, 48000}; - static const int sample_rates_count = sizeof(sample_rates)/sizeof(uint32_t); - bool inval = false; - // Only PCM_16_bit is supported. If this is changed, stereo to mono drop - // must be fixed in in_read - if (*format != AUDIO_FORMAT_PCM_16_BIT) { - *format = AUDIO_FORMAT_PCM_16_BIT; - inval = true; - } - - int channel_count = popcount(*channel_mask); - if (channel_count != 1 && channel_count != 2) { - *channel_mask = AUDIO_CHANNEL_IN_STEREO; - inval = true; - } - - int i; - for (i = 0; i < sample_rates_count; i++) { - if (*sample_rate < sample_rates[i]) { - *sample_rate = sample_rates[i]; - inval=true; - break; - } - else if (*sample_rate == sample_rates[i]) { - break; - } - else if (i == sample_rates_count-1) { - // Cap it to the highest rate we support - *sample_rate = sample_rates[i]; - inval=true; - } - } - - if (inval) { - return -EINVAL; - } - return 0; +static void get_mic_characteristics(struct audio_microphone_characteristic_t* mic_data, + size_t* mic_count) { + *mic_count = 1; + memset(mic_data, 0, sizeof(struct audio_microphone_characteristic_t)); + strlcpy(mic_data->device_id, "builtin_mic", AUDIO_MICROPHONE_ID_MAX_LEN - 1); + strlcpy(mic_data->address, "top", AUDIO_DEVICE_MAX_ADDRESS_LEN - 1); + memset(mic_data->channel_mapping, AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED, + sizeof(mic_data->channel_mapping)); + mic_data->device = AUDIO_DEVICE_IN_BUILTIN_MIC; + mic_data->sensitivity = -37.0; + mic_data->max_spl = AUDIO_MICROPHONE_SPL_UNKNOWN; + mic_data->min_spl = AUDIO_MICROPHONE_SPL_UNKNOWN; + mic_data->orientation.x = 0.0f; + mic_data->orientation.y = 0.0f; + mic_data->orientation.z = 0.0f; + mic_data->geometric_location.x = AUDIO_MICROPHONE_COORDINATE_UNKNOWN; + mic_data->geometric_location.y = AUDIO_MICROPHONE_COORDINATE_UNKNOWN; + mic_data->geometric_location.z = AUDIO_MICROPHONE_COORDINATE_UNKNOWN; } -static int check_input_parameters(uint32_t sample_rate, audio_format_t format, - audio_channel_mask_t channel_mask) +static uint32_t in_get_sample_rate(const struct audio_stream *stream) { - return refine_input_parameters(&sample_rate, &format, &channel_mask); + struct alsa_stream_in *in = (struct alsa_stream_in *)stream; + return in->config.rate; } -static size_t get_input_buffer_size(uint32_t sample_rate, audio_format_t format, - audio_channel_mask_t channel_mask) +static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) { - size_t size; - int channel_count = popcount(channel_mask); - if (check_input_parameters(sample_rate, format, channel_mask) != 0) - return 0; - - size = sample_rate*IN_PERIOD_MS/1000; - // Audioflinger expects audio buffers to be multiple of 16 frames - size = ((size + 15) / 16) * 16; - size *= sizeof(short) * channel_count; - - return size; + ALOGV("in_set_sample_rate: %d", rate); + return -ENOSYS; } - -static size_t in_get_buffer_size(const struct audio_stream *stream) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - int size = get_input_buffer_size(in->req_config.sample_rate, - in->req_config.format, - in->req_config.channel_mask); - - return size; +static size_t get_input_buffer_size(size_t frames, audio_format_t format, + audio_channel_mask_t channel_mask) { + /* return the closest majoring multiple of 16 frames, as + * audioflinger expects audio buffers to be a multiple of 16 frames */ + frames = ((frames + 15) / 16) * 16; + size_t bytes_per_frame = audio_channel_count_from_in_mask(channel_mask) * + audio_bytes_per_sample(format); + size_t buffer_size = frames * bytes_per_frame; + return buffer_size; } static audio_channel_mask_t in_get_channels(const struct audio_stream *stream) { - struct generic_stream_in *in = (struct generic_stream_in *)stream; - return in->req_config.channel_mask; + struct alsa_stream_in *in = (struct alsa_stream_in *)stream; + ALOGV("in_get_channels: %d", in->config.channels); + return audio_channel_in_mask_from_count(in->config.channels); } static audio_format_t in_get_format(const struct audio_stream *stream) { - struct generic_stream_in *in = (struct generic_stream_in *)stream; - return in->req_config.format; + struct alsa_stream_in *in = (struct alsa_stream_in *)stream; + ALOGV("in_get_format: %d", in->config.format); + return audio_format_from_pcm_format(in->config.format); } static int in_set_format(struct audio_stream *stream, audio_format_t format) @@ -825,386 +508,293 @@ static int in_set_format(struct audio_stream *stream, audio_format_t format) return -ENOSYS; } -static int in_dump(const struct audio_stream *stream, int fd) +static size_t in_get_buffer_size(const struct audio_stream *stream) { - struct generic_stream_in *in = (struct generic_stream_in *)stream; + struct alsa_stream_in* in = (struct alsa_stream_in*)stream; + size_t frames = CAPTURE_PERIOD_SIZE; + if (in->source == AUDIO_SOURCE_ECHO_REFERENCE) { + frames = CAPTURE_PERIOD_SIZE * PLAYBACK_CODEC_SAMPLING_RATE / CAPTURE_CODEC_SAMPLING_RATE; + } - pthread_mutex_lock(&in->lock); - dprintf(fd, "\tin_dump:\n" - "\t\tsample rate: %u\n" - "\t\tbuffer size: %zu\n" - "\t\tchannel mask: %08x\n" - "\t\tformat: %d\n" - "\t\tdevice: %08x\n" - "\t\taudio dev: %p\n\n", - in_get_sample_rate(stream), - in_get_buffer_size(stream), - in_get_channels(stream), - in_get_format(stream), - in->device, - in->dev); - pthread_mutex_unlock(&in->lock); - return 0; + size_t buffer_size = + get_input_buffer_size(frames, stream->get_format(stream), stream->get_channels(stream)); + ALOGV("in_get_buffer_size: %zu", buffer_size); + return buffer_size; } -static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) -{ - struct str_parms *parms; - char value[32]; - int success; - int ret = -EINVAL; - - if (kvpairs == NULL || kvpairs[0] == 0) { - return 0; +static int in_get_active_microphones(const struct audio_stream_in* stream, + struct audio_microphone_characteristic_t* mic_array, + size_t* mic_count) { + ALOGV("in_get_active_microphones"); + if ((mic_array == NULL) || (mic_count == NULL)) { + return -EINVAL; } - parms = str_parms_create_str(kvpairs); - success = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, - value, sizeof(value)); - // As the hal version is 3.0, it must not use set parameters API to set audio device. - // Instead, it should use create_audio_patch API. - assert(("Must not use set parameters API to set audio devices", success < 0)); - - if (str_parms_has_key(parms, AUDIO_PARAMETER_STREAM_FORMAT)) { - // match the return value of in_set_format - ret = -ENOSYS; + struct alsa_stream_in* in = (struct alsa_stream_in*)stream; + struct audio_hw_device* dev = (struct audio_hw_device*)in->dev; + bool mic_muted = false; + adev_get_mic_mute(dev, &mic_muted); + if ((in->source == AUDIO_SOURCE_ECHO_REFERENCE) || mic_muted) { + *mic_count = 0; + return 0; } + adev_get_microphones(dev, mic_array, mic_count); + return 0; +} - str_parms_destroy(parms); +static int do_input_standby(struct alsa_stream_in *in) +{ + struct alsa_audio_device *adev = in->dev; - if (ret == -EINVAL) { - ALOGW("%s(), unsupported parameter %s", __func__, kvpairs); - // There is not any key supported for set_parameters API. - // Return error when there is non-null value passed in. + if (!in->standby) { + pcm_close(in->pcm); + in->pcm = NULL; + adev->active_input = NULL; + in->standby = true; } - return ret; + return 0; } -static char * in_get_parameters(const struct audio_stream *stream, - const char *keys) +static int in_standby(struct audio_stream *stream) { - struct generic_stream_in *in = (struct generic_stream_in *)stream; - struct str_parms *query = str_parms_create_str(keys); - char *str = NULL; - char value[256]; - struct str_parms *reply = str_parms_create(); - int ret; - bool get = false; + struct alsa_stream_in *in = (struct alsa_stream_in *)stream; + int status; - ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); - if (ret >= 0) { - str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_ROUTING, in->device); - get = true; - } + pthread_mutex_lock(&in->lock); + pthread_mutex_lock(&in->dev->lock); + status = do_input_standby(in); + pthread_mutex_unlock(&in->dev->lock); + pthread_mutex_unlock(&in->lock); + return status; +} - if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) { - value[0] = 0; - strcat(value, "AUDIO_FORMAT_PCM_16_BIT"); - str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value); - get = true; +static int in_dump(const struct audio_stream *stream, int fd) +{ + struct alsa_stream_in* in = (struct alsa_stream_in*)stream; + if (in->source == AUDIO_SOURCE_ECHO_REFERENCE) { + return 0; } - if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_FORMAT)) { - value[0] = 0; - strcat(value, "AUDIO_FORMAT_PCM_16_BIT"); - str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_FORMAT, value); - get = true; - } + struct audio_microphone_characteristic_t mic_array[AUDIO_MICROPHONE_MAX_COUNT]; + size_t mic_count; - if (get) { - str = str_parms_to_str(reply); - } - else { - ALOGD("%s Unsupported parameter: %s", __FUNCTION__, keys); - } + get_mic_characteristics(mic_array, &mic_count); - str_parms_destroy(query); - str_parms_destroy(reply); - return str; -} + dprintf(fd, " Microphone count: %zd\n", mic_count); + size_t idx; + for (idx = 0; idx < mic_count; idx++) { + dprintf(fd, " Microphone: %zd\n", idx); + dprintf(fd, " Address: %s\n", mic_array[idx].address); + dprintf(fd, " Device: %d\n", mic_array[idx].device); + dprintf(fd, " Sensitivity (dB): %.2f\n", mic_array[idx].sensitivity); + } -static int in_set_gain(struct audio_stream_in *stream, float gain) -{ - // in_set_gain is a no op return 0; } -// Call with in->lock held -static void get_current_input_position(struct generic_stream_in *in, - int64_t * position, - struct timespec * timestamp) { - struct timespec t = { .tv_sec = 0, .tv_nsec = 0 }; - clock_gettime(CLOCK_MONOTONIC, &t); - const int64_t now_us = (t.tv_sec * 1000000000LL + t.tv_nsec) / 1000; - if (timestamp) { - *timestamp = t; - } - int64_t position_since_standby; - if (in->standby) { - position_since_standby = 0; - } else { - const int64_t first_us = (in->standby_exit_time.tv_sec * 1000000000LL + - in->standby_exit_time.tv_nsec) / 1000; - position_since_standby = (now_us - first_us) * - in_get_sample_rate(&in->stream.common) / - 1000000; - if (position_since_standby < 0) { - position_since_standby = 0; - } - } - *position = in->standby_position + position_since_standby; +static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) +{ + return 0; } -// Must be called with in->lock held -static void do_in_standby(struct generic_stream_in *in) +static char * in_get_parameters(const struct audio_stream *stream, + const char *keys) { - if (in->standby) { - return; - } - in->worker_standby = true; - get_current_input_position(in, &in->standby_position, NULL); - in->standby = true; + return strdup(""); } -static int in_standby(struct audio_stream *stream) +static int in_set_gain(struct audio_stream_in *stream, float gain) { - struct generic_stream_in *in = (struct generic_stream_in *)stream; - pthread_mutex_lock(&in->lock); - do_in_standby(in); - pthread_mutex_unlock(&in->lock); return 0; } -static void *in_read_worker(void * args) +static ssize_t in_read(struct audio_stream_in *stream, void* buffer, + size_t bytes) { - struct generic_stream_in *in = (struct generic_stream_in *)args; - struct pcm *pcm = NULL; - uint8_t *buffer = NULL; - size_t buffer_frames; - int buffer_size; - - bool restart = false; - bool shutdown = false; - while (true) { - pthread_mutex_lock(&in->lock); - while (in->worker_standby || restart) { - restart = false; - if (pcm) { - pcm_close(pcm); // Frees pcm - pcm = NULL; - free(buffer); - buffer=NULL; + int ret; + struct alsa_stream_in *in = (struct alsa_stream_in *)stream; + struct alsa_audio_device *adev = in->dev; + size_t frame_size = audio_stream_in_frame_size(stream); + size_t in_frames = bytes / frame_size; + + ALOGV("in_read: stream: %d, bytes %zu", in->source, bytes); + + /* Special handling for Echo Reference: simply get the reference from FIFO. + * The format and sample rate should be specified by arguments to adev_open_input_stream. */ + if (in->source == AUDIO_SOURCE_ECHO_REFERENCE) { + struct aec_info info; + info.bytes = bytes; + + const uint64_t time_increment_nsec = (uint64_t)bytes * NANOS_PER_SECOND / + audio_stream_in_frame_size(stream) / + in_get_sample_rate(&stream->common); + if (!aec_get_spk_running(adev->aec)) { + if (in->timestamp_nsec == 0) { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + const uint64_t timestamp_nsec = audio_utils_ns_from_timespec(&now); + in->timestamp_nsec = timestamp_nsec; + } else { + in->timestamp_nsec += time_increment_nsec; } - if (in->worker_exit) { - break; + memset(buffer, 0, bytes); + const uint64_t time_increment_usec = time_increment_nsec / 1000; + usleep(time_increment_usec); + } else { + int ref_ret = get_reference_samples(adev->aec, buffer, &info); + if ((ref_ret) || (info.timestamp_usec == 0)) { + memset(buffer, 0, bytes); + in->timestamp_nsec += time_increment_nsec; + } else { + in->timestamp_nsec = 1000 * info.timestamp_usec; } - pthread_cond_wait(&in->worker_wake, &in->lock); } + in->frames_read += in_frames; - if (in->worker_exit) { - if (!in->worker_standby) { - ALOGE("In worker not in standby before exiting"); - } - shutdown = true; - } - if (shutdown) { - pthread_mutex_unlock(&in->lock); - break; - } - if (!pcm) { - pcm = pcm_open(PCM_CARD, PCM_DEVICE, - PCM_IN | PCM_MONOTONIC, &in->pcm_config); - if (!pcm_is_ready(pcm)) { - ALOGE("pcm_open(in) failed: %s: channels %d format %d rate %d", - pcm_get_error(pcm), - in->pcm_config.channels, - in->pcm_config.format, - in->pcm_config.rate - ); - pthread_mutex_unlock(&in->lock); - break; - } - buffer_frames = in->pcm_config.period_size; - buffer_size = pcm_frames_to_bytes(pcm, buffer_frames); - buffer = malloc(buffer_size); - if (!buffer) { - ALOGE("could not allocate worker read buffer"); - pthread_mutex_unlock(&in->lock); - break; - } - } - pthread_mutex_unlock(&in->lock); - int ret = pcm_read(pcm, buffer, pcm_frames_to_bytes(pcm, buffer_frames)); - if (ret != 0) { - ALOGW("pcm_read failed %s", pcm_get_error(pcm)); - restart = true; - continue; +#if DEBUG_AEC + FILE* fp_ref = fopen("/data/local/traces/aec_ref.pcm", "a+"); + if (fp_ref) { + fwrite((char*)buffer, 1, bytes, fp_ref); + fclose(fp_ref); + } else { + ALOGE("AEC debug: Could not open file aec_ref.pcm!"); } - - pthread_mutex_lock(&in->lock); - size_t frames_written = audio_vbuffer_write(&in->buffer, buffer, buffer_frames); - pthread_mutex_unlock(&in->lock); - - if (frames_written != buffer_frames) { - ALOGW("in_read_worker only could write %zu / %zu frames", frames_written, buffer_frames); + FILE* fp_ref_ts = fopen("/data/local/traces/aec_ref_timestamps.txt", "a+"); + if (fp_ref_ts) { + fprintf(fp_ref_ts, "%" PRIu64 "\n", in->timestamp_nsec); + fclose(fp_ref_ts); + } else { + ALOGE("AEC debug: Could not open file aec_ref_timestamps.txt!"); } +#endif + return info.bytes; } - if (buffer) { - free(buffer); - } - return NULL; -} -static ssize_t in_read(struct audio_stream_in *stream, void* buffer, - size_t bytes) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - struct generic_audio_device *adev = in->dev; - const size_t frames = bytes / audio_stream_in_frame_size(stream); - bool mic_mute = false; - size_t read_bytes = 0; + /* Microphone input stream read */ - adev_get_mic_mute(&adev->device, &mic_mute); + /* acquiring hw device mutex systematically is useful if a low priority thread is waiting + * on the input stream mutex - e.g. executing select_mode() while holding the hw device + * mutex + */ pthread_mutex_lock(&in->lock); - - if (in->worker_standby) { - in->worker_standby = false; - } - pthread_cond_signal(&in->worker_wake); - - int64_t current_position; - struct timespec current_time; - - get_current_input_position(in, ¤t_position, ¤t_time); + pthread_mutex_lock(&adev->lock); if (in->standby) { + ret = start_input_stream(in); + if (ret != 0) { + pthread_mutex_unlock(&adev->lock); + ALOGE("start_input_stream failed with code %d", ret); + goto exit; + } in->standby = false; - in->standby_exit_time = current_time; - in->standby_frames_read = 0; } - const int64_t frames_available = current_position - in->standby_position - in->standby_frames_read; - assert(frames_available >= 0); - - const size_t frames_wait = ((uint64_t)frames_available > frames) ? 0 : frames - frames_available; + pthread_mutex_unlock(&adev->lock); - int64_t sleep_time_us = frames_wait * 1000000LL / - in_get_sample_rate(&stream->common); + ret = pcm_read(in->pcm, buffer, in_frames * frame_size); + struct aec_info info; + get_pcm_timestamp(in->pcm, in->config.rate, &info, false /*isOutput*/); + if (ret == 0) { + in->frames_read += in_frames; + in->timestamp_nsec = audio_utils_ns_from_timespec(&info.timestamp); + } + else { + ALOGE("pcm_read failed with code %d", ret); + } +exit: pthread_mutex_unlock(&in->lock); - if (sleep_time_us > 0) { - usleep(sleep_time_us); + bool mic_muted = false; + adev_get_mic_mute((struct audio_hw_device*)adev, &mic_muted); + if (mic_muted) { + memset(buffer, 0, bytes); } - pthread_mutex_lock(&in->lock); - int read_frames = 0; - if (in->standby) { - ALOGW("Input put to sleep while read in progress"); - goto exit; - } - in->standby_frames_read += frames; - - if (popcount(in->req_config.channel_mask) == 1 && - in->pcm_config.channels == 2) { - // Need to resample to mono - if (in->stereo_to_mono_buf_size < bytes*2) { - in->stereo_to_mono_buf = realloc(in->stereo_to_mono_buf, - bytes*2); - if (!in->stereo_to_mono_buf) { - ALOGE("Failed to allocate stereo_to_mono_buff"); - goto exit; + if (ret != 0) { + usleep((int64_t)bytes * 1000000 / audio_stream_in_frame_size(stream) / + in_get_sample_rate(&stream->common)); + } else { + /* Process AEC if available */ + /* TODO move to a separate thread */ + if (!mic_muted) { + info.bytes = bytes; + int aec_ret = process_aec(adev->aec, buffer, &info); + if (aec_ret) { + ALOGE("process_aec returned error code %d", aec_ret); } } - - read_frames = audio_vbuffer_read(&in->buffer, in->stereo_to_mono_buf, frames); - - // Currently only pcm 16 is supported. - uint16_t *src = (uint16_t *)in->stereo_to_mono_buf; - uint16_t *dst = (uint16_t *)buffer; - size_t i; - // Resample stereo 16 to mono 16 by dropping one channel. - // The stereo stream is interleaved L-R-L-R - for (i = 0; i < frames; i++) { - *dst = *src; - src += 2; - dst += 1; - } - } else { - read_frames = audio_vbuffer_read(&in->buffer, buffer, frames); } -exit: - read_bytes = read_frames*audio_stream_in_frame_size(stream); - - if (mic_mute) { - read_bytes = 0; +#if DEBUG_AEC && !defined(AEC_HAL) + FILE* fp_in = fopen("/data/local/traces/aec_in.pcm", "a+"); + if (fp_in) { + fwrite((char*)buffer, 1, bytes, fp_in); + fclose(fp_in); + } else { + ALOGE("AEC debug: Could not open file aec_in.pcm!"); } - - if (read_bytes < bytes) { - memset (&((uint8_t *)buffer)[read_bytes], 0, bytes-read_bytes); + FILE* fp_mic_ts = fopen("/data/local/traces/aec_in_timestamps.txt", "a+"); + if (fp_mic_ts) { + fprintf(fp_mic_ts, "%" PRIu64 "\n", in->timestamp_nsec); + fclose(fp_mic_ts); + } else { + ALOGE("AEC debug: Could not open file aec_in_timestamps.txt!"); } - - pthread_mutex_unlock(&in->lock); +#endif return bytes; } -static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) -{ - return 0; -} +static int in_get_capture_position(const struct audio_stream_in* stream, int64_t* frames, + int64_t* time) { + if (stream == NULL || frames == NULL || time == NULL) { + return -EINVAL; + } + struct alsa_stream_in* in = (struct alsa_stream_in*)stream; + + *frames = in->frames_read; + *time = in->timestamp_nsec; + ALOGV("%s: source: %d, timestamp (nsec): %" PRIu64, __func__, in->source, *time); -static int in_get_capture_position(const struct audio_stream_in *stream, - int64_t *frames, int64_t *time) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - pthread_mutex_lock(&in->lock); - struct timespec current_time; - get_current_input_position(in, frames, ¤t_time); - *time = (current_time.tv_sec * 1000000000LL + current_time.tv_nsec); - pthread_mutex_unlock(&in->lock); return 0; } -static int in_get_active_microphones(const struct audio_stream_in *stream, - struct audio_microphone_characteristic_t *mic_array, - size_t *mic_count) +static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) { - return adev_get_microphones(NULL, mic_array, mic_count); + return 0; } static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) { - // in_add_audio_effect is a no op return 0; } static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) { - // in_add_audio_effect is a no op return 0; } static int adev_open_output_stream(struct audio_hw_device *dev, - audio_io_handle_t handle, - audio_devices_t devices, - audio_output_flags_t flags, - struct audio_config *config, - struct audio_stream_out **stream_out, - const char *address __unused) + audio_io_handle_t handle, + audio_devices_t devices, + audio_output_flags_t flags, + struct audio_config *config, + struct audio_stream_out **stream_out, + const char *address __unused) { - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - struct generic_stream_out *out; + ALOGV("adev_open_output_stream..."); + + struct alsa_audio_device *ladev = (struct alsa_audio_device *)dev; + struct alsa_stream_out *out; + struct pcm_params *params; int ret = 0; - if (refine_output_parameters(&config->sample_rate, &config->format, &config->channel_mask)) { - ALOGE("Error opening output stream format %d, channel_mask %04x, sample_rate %u", - config->format, config->channel_mask, config->sample_rate); - ret = -EINVAL; - goto error; - } + int out_port = get_audio_output_port(devices); - out = (struct generic_stream_out *)calloc(1, sizeof(struct generic_stream_out)); + params = pcm_params_get(CARD_OUT, out_port, PCM_OUT); + if (!params) + return -ENOSYS; + out = (struct alsa_stream_out *)calloc(1, sizeof(struct alsa_stream_out)); if (!out) return -ENOMEM; @@ -1224,141 +814,141 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->stream.set_volume = out_set_volume; out->stream.write = out_write; out->stream.get_render_position = out_get_render_position; - out->stream.get_presentation_position = out_get_presentation_position; out->stream.get_next_write_timestamp = out_get_next_write_timestamp; + out->stream.get_presentation_position = out_get_presentation_position; - out->handle = handle; - - pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL); - out->dev = adev; - // Only 1 device is expected despite the argument being named 'devices' - out->num_devices = 1; - out->devices[0] = devices; - memcpy(&out->req_config, config, sizeof(struct audio_config)); - memcpy(&out->pcm_config, &pcm_config_out, sizeof(struct pcm_config)); - out->pcm_config.rate = config->sample_rate; - out->pcm_config.period_size = out->pcm_config.rate*OUT_PERIOD_MS/1000; - - out->standby = true; - out->underrun_position = 0; - out->underrun_time.tv_sec = 0; - out->underrun_time.tv_nsec = 0; - out->last_write_time_us = 0; - out->frames_total_buffered = 0; - out->frames_written = 0; - out->frames_rendered = 0; - - ret = audio_vbuffer_init(&out->buffer, - out->pcm_config.period_size*out->pcm_config.period_count, - out->pcm_config.channels * - pcm_format_to_bits(out->pcm_config.format) >> 3); - if (ret == 0) { - pthread_cond_init(&out->worker_wake, NULL); - out->worker_standby = true; - out->worker_exit = false; - pthread_create(&out->worker_thread, NULL, out_write_worker, out); - + out->config.channels = CHANNEL_STEREO; + out->config.rate = PLAYBACK_CODEC_SAMPLING_RATE; + out->config.format = PCM_FORMAT_S16_LE; + out->config.period_size = PLAYBACK_PERIOD_SIZE; + out->config.period_count = PLAYBACK_PERIOD_COUNT; + + if (out->config.rate != config->sample_rate || + audio_channel_count_from_out_mask(config->channel_mask) != CHANNEL_STEREO || + out->config.format != pcm_format_from_audio_format(config->format) ) { + config->sample_rate = out->config.rate; + config->format = audio_format_from_pcm_format(out->config.format); + config->channel_mask = audio_channel_out_mask_from_count(CHANNEL_STEREO); + ret = -EINVAL; } - pthread_mutex_lock(&adev->lock); - list_add_tail(&adev->out_streams, &out->stream_node); - pthread_mutex_unlock(&adev->lock); + ALOGI("adev_open_output_stream selects channels=%d rate=%d format=%d, devices=%d", + out->config.channels, out->config.rate, out->config.format, devices); - *stream_out = &out->stream; + out->dev = ladev; + out->standby = 1; + out->unavailable = false; + out->devices = devices; -error: + config->format = out_get_format(&out->stream.common); + config->channel_mask = out_get_channels(&out->stream.common); + config->sample_rate = out_get_sample_rate(&out->stream.common); - return ret; -} + *stream_out = &out->stream; + + out->speaker_eq = NULL; + if (out_port == PORT_INTERNAL_SPEAKER) { + out_set_eq(out); + if (out->speaker_eq == NULL) { + ALOGE("%s: Failed to initialize speaker EQ", __func__); + } + } -// This must be called with adev->lock held. -struct generic_stream_out *get_stream_out_by_io_handle_l( - struct generic_audio_device *adev, audio_io_handle_t handle) { - struct listnode *node; + /* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger. */ + ret = 0; - list_for_each(node, &adev->out_streams) { - struct generic_stream_out *out = node_to_item( - node, struct generic_stream_out, stream_node); - if (out->handle == handle) { - return out; + if (ret == 0) { + int aec_ret = init_aec_reference_config(ladev->aec, out); + if (aec_ret) { + ALOGE("AEC: Speaker config init failed!"); + return -EINVAL; } } - return NULL; + + return ret; } static void adev_close_output_stream(struct audio_hw_device *dev, - struct audio_stream_out *stream) + struct audio_stream_out *stream) { - struct generic_stream_out *out = (struct generic_stream_out *)stream; - pthread_mutex_lock(&out->lock); - do_out_standby(out); - - out->worker_exit = true; - pthread_cond_signal(&out->worker_wake); - pthread_mutex_unlock(&out->lock); - - pthread_join(out->worker_thread, NULL); - pthread_mutex_destroy(&out->lock); - audio_vbuffer_destroy(&out->buffer); - - struct generic_audio_device *adev = (struct generic_audio_device *) dev; - pthread_mutex_lock(&adev->lock); - list_remove(&out->stream_node); - pthread_mutex_unlock(&adev->lock); + ALOGV("adev_close_output_stream..."); + struct alsa_audio_device *adev = (struct alsa_audio_device *)dev; + destroy_aec_reference_config(adev->aec); + struct alsa_stream_out* out = (struct alsa_stream_out*)stream; + fir_release(out->speaker_eq); free(stream); } static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) { - return 0; + ALOGV("adev_set_parameters"); + return -ENOSYS; } static char * adev_get_parameters(const struct audio_hw_device *dev, - const char *keys) + const char *keys) { + ALOGV("adev_get_parameters"); return strdup(""); } +static int adev_get_microphones(const struct audio_hw_device* dev, + struct audio_microphone_characteristic_t* mic_array, + size_t* mic_count) { + ALOGV("adev_get_microphones"); + if ((mic_array == NULL) || (mic_count == NULL)) { + return -EINVAL; + } + get_mic_characteristics(mic_array, mic_count); + return 0; +} + static int adev_init_check(const struct audio_hw_device *dev) { + ALOGV("adev_init_check"); return 0; } static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) { - // adev_set_voice_volume is a no op (simulates phones) - return 0; + ALOGV("adev_set_voice_volume: %f", volume); + return -ENOSYS; } static int adev_set_master_volume(struct audio_hw_device *dev, float volume) { + ALOGV("adev_set_master_volume: %f", volume); return -ENOSYS; } static int adev_get_master_volume(struct audio_hw_device *dev, float *volume) { + ALOGV("adev_get_master_volume: %f", *volume); return -ENOSYS; } static int adev_set_master_mute(struct audio_hw_device *dev, bool muted) { + ALOGV("adev_set_master_mute: %d", muted); return -ENOSYS; } static int adev_get_master_mute(struct audio_hw_device *dev, bool *muted) { + ALOGV("adev_get_master_mute: %d", *muted); return -ENOSYS; } static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) { - // adev_set_mode is a no op (simulates phones) + ALOGV("adev_set_mode: %d", mode); return 0; } static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) { - struct generic_audio_device *adev = (struct generic_audio_device *)dev; + ALOGV("adev_set_mic_mute: %d",state); + struct alsa_audio_device *adev = (struct alsa_audio_device *)dev; pthread_mutex_lock(&adev->lock); adev->mic_mute = state; pthread_mutex_unlock(&adev->lock); @@ -1367,455 +957,206 @@ static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) { - struct generic_audio_device *adev = (struct generic_audio_device *)dev; + ALOGV("adev_get_mic_mute"); + struct alsa_audio_device *adev = (struct alsa_audio_device *)dev; pthread_mutex_lock(&adev->lock); *state = adev->mic_mute; pthread_mutex_unlock(&adev->lock); return 0; } - static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, - const struct audio_config *config) -{ - return get_input_buffer_size(config->sample_rate, config->format, config->channel_mask); -} - -// This must be called with adev->lock held. -struct generic_stream_in *get_stream_in_by_io_handle_l( - struct generic_audio_device *adev, audio_io_handle_t handle) { - struct listnode *node; - - list_for_each(node, &adev->in_streams) { - struct generic_stream_in *in = node_to_item( - node, struct generic_stream_in, stream_node); - if (in->handle == handle) { - return in; - } - } - return NULL; -} - -static void adev_close_input_stream(struct audio_hw_device *dev, - struct audio_stream_in *stream) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - pthread_mutex_lock(&in->lock); - do_in_standby(in); - - in->worker_exit = true; - pthread_cond_signal(&in->worker_wake); - pthread_mutex_unlock(&in->lock); - pthread_join(in->worker_thread, NULL); - - if (in->stereo_to_mono_buf != NULL) { - free(in->stereo_to_mono_buf); - in->stereo_to_mono_buf_size = 0; - } - - pthread_mutex_destroy(&in->lock); - audio_vbuffer_destroy(&in->buffer); - - struct generic_audio_device *adev = (struct generic_audio_device *) dev; - pthread_mutex_lock(&adev->lock); - list_remove(&in->stream_node); - pthread_mutex_unlock(&adev->lock); - free(stream); -} - - -static int adev_open_input_stream(struct audio_hw_device *dev, - audio_io_handle_t handle, - audio_devices_t devices, - struct audio_config *config, - struct audio_stream_in **stream_in, - audio_input_flags_t flags __unused, - const char *address __unused, - audio_source_t source __unused) + const struct audio_config *config) { - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - struct generic_stream_in *in; + size_t buffer_size = + get_input_buffer_size(CAPTURE_PERIOD_SIZE, config->format, config->channel_mask); + ALOGV("adev_get_input_buffer_size: %zu", buffer_size); + return buffer_size; +} + +static int adev_open_input_stream(struct audio_hw_device* dev, audio_io_handle_t handle, + audio_devices_t devices, struct audio_config* config, + struct audio_stream_in** stream_in, + audio_input_flags_t flags __unused, const char* address __unused, + audio_source_t source) { + ALOGV("adev_open_input_stream..."); + + struct alsa_audio_device *ladev = (struct alsa_audio_device *)dev; + struct alsa_stream_in *in; + struct pcm_params *params; int ret = 0; - if (refine_input_parameters(&config->sample_rate, &config->format, &config->channel_mask)) { - ALOGE("Error opening input stream format %d, channel_mask %04x, sample_rate %u", - config->format, config->channel_mask, config->sample_rate); - ret = -EINVAL; - goto error; - } - in = (struct generic_stream_in *)calloc(1, sizeof(struct generic_stream_in)); - if (!in) { - ret = -ENOMEM; - goto error; - } + params = pcm_params_get(CARD_IN, PORT_BUILTIN_MIC, PCM_IN); + if (!params) + return -ENOSYS; + + in = (struct alsa_stream_in *)calloc(1, sizeof(struct alsa_stream_in)); + if (!in) + return -ENOMEM; in->stream.common.get_sample_rate = in_get_sample_rate; - in->stream.common.set_sample_rate = in_set_sample_rate; // no op + in->stream.common.set_sample_rate = in_set_sample_rate; in->stream.common.get_buffer_size = in_get_buffer_size; in->stream.common.get_channels = in_get_channels; in->stream.common.get_format = in_get_format; - in->stream.common.set_format = in_set_format; // no op + in->stream.common.set_format = in_set_format; in->stream.common.standby = in_standby; in->stream.common.dump = in_dump; in->stream.common.set_parameters = in_set_parameters; in->stream.common.get_parameters = in_get_parameters; - in->stream.common.add_audio_effect = in_add_audio_effect; // no op - in->stream.common.remove_audio_effect = in_remove_audio_effect; // no op - in->stream.set_gain = in_set_gain; // no op + in->stream.common.add_audio_effect = in_add_audio_effect; + in->stream.common.remove_audio_effect = in_remove_audio_effect; + in->stream.set_gain = in_set_gain; in->stream.read = in_read; - in->stream.get_input_frames_lost = in_get_input_frames_lost; // no op + in->stream.get_input_frames_lost = in_get_input_frames_lost; in->stream.get_capture_position = in_get_capture_position; in->stream.get_active_microphones = in_get_active_microphones; - pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL); - in->dev = adev; - in->device = devices; - memcpy(&in->req_config, config, sizeof(struct audio_config)); - memcpy(&in->pcm_config, &pcm_config_in, sizeof(struct pcm_config)); - in->pcm_config.rate = config->sample_rate; - in->pcm_config.period_size = in->pcm_config.rate*IN_PERIOD_MS/1000; - - in->stereo_to_mono_buf = NULL; - in->stereo_to_mono_buf_size = 0; - - in->standby = true; - in->standby_position = 0; - in->standby_exit_time.tv_sec = 0; - in->standby_exit_time.tv_nsec = 0; - in->standby_frames_read = 0; - - ret = audio_vbuffer_init(&in->buffer, - in->pcm_config.period_size*in->pcm_config.period_count, - in->pcm_config.channels * - pcm_format_to_bits(in->pcm_config.format) >> 3); - if (ret == 0) { - pthread_cond_init(&in->worker_wake, NULL); - in->worker_standby = true; - in->worker_exit = false; - pthread_create(&in->worker_thread, NULL, in_read_worker, in); - } - in->handle = handle; - - pthread_mutex_lock(&adev->lock); - list_add_tail(&adev->in_streams, &in->stream_node); - pthread_mutex_unlock(&adev->lock); - - *stream_in = &in->stream; - -error: - return ret; -} - - -static int adev_dump(const audio_hw_device_t *dev, int fd) -{ - return 0; -} - -static int adev_get_microphones(const audio_hw_device_t *dev, - struct audio_microphone_characteristic_t *mic_array, - size_t *mic_count) -{ - if (mic_count == NULL) { - return -ENOSYS; - } - - if (*mic_count == 0) { - *mic_count = 1; - return 0; + in->config.channels = CHANNEL_STEREO; + if (source == AUDIO_SOURCE_ECHO_REFERENCE) { + in->config.rate = PLAYBACK_CODEC_SAMPLING_RATE; + } else { + in->config.rate = CAPTURE_CODEC_SAMPLING_RATE; } + in->config.format = PCM_FORMAT_S32_LE; + in->config.period_size = CAPTURE_PERIOD_SIZE; + in->config.period_count = CAPTURE_PERIOD_COUNT; - if (mic_array == NULL) { - return -ENOSYS; + if (in->config.rate != config->sample_rate || + audio_channel_count_from_in_mask(config->channel_mask) != CHANNEL_STEREO || + in->config.format != pcm_format_from_audio_format(config->format) ) { + ret = -EINVAL; } - strncpy(mic_array->device_id, "mic_goldfish", AUDIO_MICROPHONE_ID_MAX_LEN - 1); - mic_array->device = AUDIO_DEVICE_IN_BUILTIN_MIC; - strncpy(mic_array->address, AUDIO_BOTTOM_MICROPHONE_ADDRESS, - AUDIO_DEVICE_MAX_ADDRESS_LEN - 1); - memset(mic_array->channel_mapping, AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED, - sizeof(mic_array->channel_mapping)); - mic_array->location = AUDIO_MICROPHONE_LOCATION_UNKNOWN; - mic_array->group = 0; - mic_array->index_in_the_group = 0; - mic_array->sensitivity = AUDIO_MICROPHONE_SENSITIVITY_UNKNOWN; - mic_array->max_spl = AUDIO_MICROPHONE_SPL_UNKNOWN; - mic_array->min_spl = AUDIO_MICROPHONE_SPL_UNKNOWN; - mic_array->directionality = AUDIO_MICROPHONE_DIRECTIONALITY_UNKNOWN; - mic_array->num_frequency_responses = 0; - mic_array->geometric_location.x = AUDIO_MICROPHONE_COORDINATE_UNKNOWN; - mic_array->geometric_location.y = AUDIO_MICROPHONE_COORDINATE_UNKNOWN; - mic_array->geometric_location.z = AUDIO_MICROPHONE_COORDINATE_UNKNOWN; - mic_array->orientation.x = AUDIO_MICROPHONE_COORDINATE_UNKNOWN; - mic_array->orientation.y = AUDIO_MICROPHONE_COORDINATE_UNKNOWN; - mic_array->orientation.z = AUDIO_MICROPHONE_COORDINATE_UNKNOWN; - - *mic_count = 1; - return 0; -} - -static int adev_create_audio_patch(struct audio_hw_device *dev, - unsigned int num_sources, - const struct audio_port_config *sources, - unsigned int num_sinks, - const struct audio_port_config *sinks, - audio_patch_handle_t *handle) { - if (num_sources != 1 || num_sinks == 0 || num_sinks > AUDIO_PATCH_PORTS_MAX) { - return -EINVAL; - } + ALOGI("adev_open_input_stream selects channels=%d rate=%d format=%d source=%d", + in->config.channels, in->config.rate, in->config.format, source); - if (sources[0].type == AUDIO_PORT_TYPE_DEVICE) { - // If source is a device, the number of sinks should be 1. - if (num_sinks != 1 || sinks[0].type != AUDIO_PORT_TYPE_MIX) { + in->dev = ladev; + in->standby = true; + in->unavailable = false; + in->source = source; + in->devices = devices; + + config->format = in_get_format(&in->stream.common); + config->channel_mask = in_get_channels(&in->stream.common); + config->sample_rate = in_get_sample_rate(&in->stream.common); + + /* If AEC is in the app, only configure based on ECHO_REFERENCE spec. + * If AEC is in the HAL, configure using the given mic stream. */ + bool aecInput = true; +#if !defined(AEC_HAL) + aecInput = (in->source == AUDIO_SOURCE_ECHO_REFERENCE); +#endif + + if ((ret == 0) && aecInput) { + int aec_ret = init_aec_mic_config(ladev->aec, in); + if (aec_ret) { + ALOGE("AEC: Mic config init failed!"); return -EINVAL; } - } else if (sources[0].type == AUDIO_PORT_TYPE_MIX) { - // If source is a mix, all sinks should be device. - for (unsigned int i = 0; i < num_sinks; i++) { - if (sinks[i].type != AUDIO_PORT_TYPE_DEVICE) { - ALOGE("%s() invalid sink type %#x for mix source", __func__, sinks[i].type); - return -EINVAL; - } - } - } else { - // All other cases are invalid. - return -EINVAL; } - struct generic_audio_device* adev = (struct generic_audio_device*) dev; - int ret = 0; - bool generatedPatchHandle = false; - pthread_mutex_lock(&adev->lock); - if (*handle == AUDIO_PATCH_HANDLE_NONE) { - *handle = ++adev->next_patch_handle; - generatedPatchHandle = true; - } - - // Only handle patches for mix->devices and device->mix case. - if (sources[0].type == AUDIO_PORT_TYPE_DEVICE) { - struct generic_stream_in *in = - get_stream_in_by_io_handle_l(adev, sinks[0].ext.mix.handle); - if (in == NULL) { - ALOGE("%s()can not find stream with handle(%d)", __func__, sources[0].ext.mix.handle); - ret = -EINVAL; - goto error; - } - - // Check if the patch handle match the recorded one if a valid patch handle is passed. - if (!generatedPatchHandle && in->patch_handle != *handle) { - ALOGE("%s() the patch handle(%d) does not match recorded one(%d) for stream " - "with handle(%d) when creating audio patch for device->mix", - __func__, *handle, in->patch_handle, in->handle); - ret = -EINVAL; - goto error; - } - pthread_mutex_lock(&in->lock); - in->device = sources[0].ext.device.type; - pthread_mutex_unlock(&in->lock); - in->patch_handle = *handle; + if (ret) { + free(in); } else { - struct generic_stream_out *out = - get_stream_out_by_io_handle_l(adev, sources[0].ext.mix.handle); - if (out == NULL) { - ALOGE("%s()can not find stream with handle(%d)", __func__, sources[0].ext.mix.handle); - ret = -EINVAL; - goto error; - } - - // Check if the patch handle match the recorded one if a valid patch handle is passed. - if (!generatedPatchHandle && out->patch_handle != *handle) { - ALOGE("%s() the patch handle(%d) does not match recorded one(%d) for stream " - "with handle(%d) when creating audio patch for mix->device", - __func__, *handle, out->patch_handle, out->handle); - ret = -EINVAL; - pthread_mutex_unlock(&out->lock); - goto error; - } - pthread_mutex_lock(&out->lock); - for (out->num_devices = 0; out->num_devices < num_sinks; out->num_devices++) { - out->devices[out->num_devices] = sinks[out->num_devices].ext.device.type; - } - pthread_mutex_unlock(&out->lock); - out->patch_handle = *handle; - } - -error: - if (ret != 0 && generatedPatchHandle) { - *handle = AUDIO_PATCH_HANDLE_NONE; + *stream_in = &in->stream; } - pthread_mutex_unlock(&adev->lock); - return 0; -} -// This must be called with adev->lock held. -struct generic_stream_out *get_stream_out_by_patch_handle_l( - struct generic_audio_device *adev, audio_patch_handle_t patch_handle) { - struct listnode *node; - - list_for_each(node, &adev->out_streams) { - struct generic_stream_out *out = node_to_item( - node, struct generic_stream_out, stream_node); - if (out->patch_handle == patch_handle) { - return out; - } - } - return NULL; +#if DEBUG_AEC + remove("/data/local/traces/aec_ref.pcm"); + remove("/data/local/traces/aec_in.pcm"); + remove("/data/local/traces/aec_ref_timestamps.txt"); + remove("/data/local/traces/aec_in_timestamps.txt"); +#endif + return ret; } -// This must be called with adev->lock held. -struct generic_stream_in *get_stream_in_by_patch_handle_l( - struct generic_audio_device *adev, audio_patch_handle_t patch_handle) { - struct listnode *node; - - list_for_each(node, &adev->in_streams) { - struct generic_stream_in *in = node_to_item( - node, struct generic_stream_in, stream_node); - if (in->patch_handle == patch_handle) { - return in; - } - } - return NULL; +static void adev_close_input_stream(struct audio_hw_device *dev, + struct audio_stream_in *stream) +{ + ALOGV("adev_close_input_stream..."); + struct alsa_audio_device *adev = (struct alsa_audio_device *)dev; + destroy_aec_mic_config(adev->aec); + free(stream); + return; } -static int adev_release_audio_patch(struct audio_hw_device *dev, - audio_patch_handle_t patch_handle) { - struct generic_audio_device *adev = (struct generic_audio_device *) dev; - - pthread_mutex_lock(&adev->lock); - struct generic_stream_out *out = get_stream_out_by_patch_handle_l(adev, patch_handle); - if (out != NULL) { - pthread_mutex_lock(&out->lock); - out->num_devices = 0; - memset(out->devices, 0, sizeof(out->devices)); - pthread_mutex_unlock(&out->lock); - out->patch_handle = AUDIO_PATCH_HANDLE_NONE; - pthread_mutex_unlock(&adev->lock); - return 0; - } - struct generic_stream_in *in = get_stream_in_by_patch_handle_l(adev, patch_handle); - if (in != NULL) { - pthread_mutex_lock(&in->lock); - in->device = AUDIO_DEVICE_NONE; - pthread_mutex_unlock(&in->lock); - in->patch_handle = AUDIO_PATCH_HANDLE_NONE; - pthread_mutex_unlock(&adev->lock); - return 0; - } - - pthread_mutex_unlock(&adev->lock); - ALOGW("%s() cannot find stream for patch handle: %d", __func__, patch_handle); - return -EINVAL; +static int adev_dump(const audio_hw_device_t *device, int fd) +{ + ALOGV("adev_dump"); + return 0; } -static int adev_close(hw_device_t *dev) +static int adev_close(hw_device_t *device) { - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - int ret = 0; - if (!adev) - return 0; - - pthread_mutex_lock(&adev_init_lock); - - if (audio_device_ref_count == 0) { - ALOGE("adev_close called when ref_count 0"); - ret = -EINVAL; - goto error; - } - - if ((--audio_device_ref_count) == 0) { - if (adev->mixer) { - mixer_close(adev->mixer); - } - free(adev); - } + ALOGV("adev_close"); -error: - pthread_mutex_unlock(&adev_init_lock); - return ret; + struct alsa_audio_device *adev = (struct alsa_audio_device *)device; + release_aec(adev->aec); + free(device); + return 0; } static int adev_open(const hw_module_t* module, const char* name, - hw_device_t** device) + hw_device_t** device) { - static struct generic_audio_device *adev; + struct alsa_audio_device *adev; + + ALOGV("adev_open: %s", name); if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) return -EINVAL; - pthread_mutex_lock(&adev_init_lock); - if (audio_device_ref_count != 0) { - *device = &adev->device.common; - audio_device_ref_count++; - ALOGV("%s: returning existing instance of adev", __func__); - ALOGV("%s: exit", __func__); - goto unlock; + adev = calloc(1, sizeof(struct alsa_audio_device)); + if (!adev) + return -ENOMEM; + + adev->hw_device.common.tag = HARDWARE_DEVICE_TAG; + adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0; + adev->hw_device.common.module = (struct hw_module_t *) module; + adev->hw_device.common.close = adev_close; + adev->hw_device.init_check = adev_init_check; + adev->hw_device.set_voice_volume = adev_set_voice_volume; + adev->hw_device.set_master_volume = adev_set_master_volume; + adev->hw_device.get_master_volume = adev_get_master_volume; + adev->hw_device.set_master_mute = adev_set_master_mute; + adev->hw_device.get_master_mute = adev_get_master_mute; + adev->hw_device.set_mode = adev_set_mode; + adev->hw_device.set_mic_mute = adev_set_mic_mute; + adev->hw_device.get_mic_mute = adev_get_mic_mute; + adev->hw_device.set_parameters = adev_set_parameters; + adev->hw_device.get_parameters = adev_get_parameters; + adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size; + adev->hw_device.open_output_stream = adev_open_output_stream; + adev->hw_device.close_output_stream = adev_close_output_stream; + adev->hw_device.open_input_stream = adev_open_input_stream; + adev->hw_device.close_input_stream = adev_close_input_stream; + adev->hw_device.dump = adev_dump; + adev->hw_device.get_microphones = adev_get_microphones; + + *device = &adev->hw_device.common; + + adev->mixer = mixer_open(CARD_OUT); + + if (!adev->mixer) { + ALOGE("Unable to open the mixer, aborting."); + return -EINVAL; } - adev = calloc(1, sizeof(struct generic_audio_device)); - - pthread_mutex_init(&adev->lock, (const pthread_mutexattr_t *) NULL); - - adev->device.common.tag = HARDWARE_DEVICE_TAG; - adev->device.common.version = AUDIO_DEVICE_API_VERSION_3_0; - adev->device.common.module = (struct hw_module_t *) module; - adev->device.common.close = adev_close; - - adev->device.init_check = adev_init_check; // no op - adev->device.set_voice_volume = adev_set_voice_volume; // no op - adev->device.set_master_volume = adev_set_master_volume; // no op - adev->device.get_master_volume = adev_get_master_volume; // no op - adev->device.set_master_mute = adev_set_master_mute; // no op - adev->device.get_master_mute = adev_get_master_mute; // no op - adev->device.set_mode = adev_set_mode; // no op - adev->device.set_mic_mute = adev_set_mic_mute; - adev->device.get_mic_mute = adev_get_mic_mute; - adev->device.set_parameters = adev_set_parameters; // no op - adev->device.get_parameters = adev_get_parameters; // no op - adev->device.get_input_buffer_size = adev_get_input_buffer_size; - adev->device.open_output_stream = adev_open_output_stream; - adev->device.close_output_stream = adev_close_output_stream; - adev->device.open_input_stream = adev_open_input_stream; - adev->device.close_input_stream = adev_close_input_stream; - adev->device.dump = adev_dump; - adev->device.get_microphones = adev_get_microphones; - adev->device.create_audio_patch = adev_create_audio_patch; - adev->device.release_audio_patch = adev_release_audio_patch; - - *device = &adev->device.common; - - adev->next_patch_handle = AUDIO_PATCH_HANDLE_NONE; - list_init(&adev->out_streams); - list_init(&adev->in_streams); - - adev->mixer = mixer_open(PCM_CARD); - struct mixer_ctl *ctl; - - // Set default mixer ctls - // Enable channels and set volume - for (int i = 0; i < (int)mixer_get_num_ctls(adev->mixer); i++) { - ctl = mixer_get_ctl(adev->mixer, i); - ALOGD("mixer %d name %s", i, mixer_ctl_get_name(ctl)); - if (!strcmp(mixer_ctl_get_name(ctl), "Master Playback Volume") || - !strcmp(mixer_ctl_get_name(ctl), "Capture Volume")) { - for (int z = 0; z < (int)mixer_ctl_get_num_values(ctl); z++) { - ALOGD("set ctl %d to %d", z, 100); - mixer_ctl_set_percent(ctl, z, 100); - } - continue; - } - if (!strcmp(mixer_ctl_get_name(ctl), "Master Playback Switch") || - !strcmp(mixer_ctl_get_name(ctl), "Capture Switch")) { - for (int z = 0; z < (int)mixer_ctl_get_num_values(ctl); z++) { - ALOGD("set ctl %d to %d", z, 1); - mixer_ctl_set_value(ctl, z, 1); - } - continue; - } + + adev->audio_route = audio_route_init(CARD_OUT, MIXER_XML_PATH); + if (!adev->audio_route) { + ALOGE("%s: Failed to init audio route controls, aborting.", __func__); + return -EINVAL; } - audio_device_ref_count++; + pthread_mutex_lock(&adev->lock); + if (init_aec(CAPTURE_CODEC_SAMPLING_RATE, NUM_AEC_REFERENCE_CHANNELS, + CHANNEL_STEREO, &adev->aec)) { + pthread_mutex_unlock(&adev->lock); + return -EINVAL; + } + pthread_mutex_unlock(&adev->lock); -unlock: - pthread_mutex_unlock(&adev_init_lock); return 0; } @@ -1829,7 +1170,7 @@ struct audio_module HAL_MODULE_INFO_SYM = { .module_api_version = AUDIO_MODULE_API_VERSION_0_1, .hal_api_version = HARDWARE_HAL_API_VERSION, .id = AUDIO_HARDWARE_MODULE_ID, - .name = "Generic audio HW HAL", + .name = "Yukawa audio HW HAL", .author = "The Android Open Source Project", .methods = &hal_module_methods, }, diff --git a/audio/audio_hw.h b/audio/audio_hw.h new file mode 100644 index 0000000..3e8e27c --- /dev/null +++ b/audio/audio_hw.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2019 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 _YUKAWA_AUDIO_HW_H_ +#define _YUKAWA_AUDIO_HW_H_ + +#include +#include + +#include "fir_filter.h" + +#define CARD_OUT 0 +#define PORT_HDMI 0 +#define PORT_INTERNAL_SPEAKER 1 +#define CARD_IN 0 +#define PORT_BUILTIN_MIC 3 + +#define MIXER_XML_PATH "/vendor/etc/mixer_paths.xml" +/* Minimum granularity - Arbitrary but small value */ +#define CODEC_BASE_FRAME_COUNT 32 + +#define CHANNEL_STEREO 2 + +#ifdef AEC_HAL +#define NUM_AEC_REFERENCE_CHANNELS 1 +#else +/* App AEC uses 2-channel reference */ +#define NUM_AEC_REFERENCE_CHANNELS 2 +#endif /* #ifdef AEC_HAL */ + +#define DEBUG_AEC 0 + +#define PCM_OPEN_RETRIES 100 +#define PCM_OPEN_WAIT_TIME_MS 20 + +/* Capture codec parameters */ +/* Set up a capture period of 32 ms: + * CAPTURE_PERIOD = PERIOD_SIZE / SAMPLE_RATE, so (32e-3) = PERIOD_SIZE / (16e3) + * => PERIOD_SIZE = 512 frames, where each "frame" consists of 1 sample of every channel (here, 2ch) */ +#define CAPTURE_PERIOD_MULTIPLIER 16 +#define CAPTURE_PERIOD_SIZE (CODEC_BASE_FRAME_COUNT * CAPTURE_PERIOD_MULTIPLIER) +#define CAPTURE_PERIOD_COUNT 4 +#define CAPTURE_PERIOD_START_THRESHOLD 0 +#define CAPTURE_CODEC_SAMPLING_RATE 16000 + +/* Playback codec parameters */ +/* number of base blocks in a short period (low latency) */ +#define PLAYBACK_PERIOD_MULTIPLIER 32 /* 21 ms */ +/* number of frames per short period (low latency) */ +#define PLAYBACK_PERIOD_SIZE (CODEC_BASE_FRAME_COUNT * PLAYBACK_PERIOD_MULTIPLIER) +/* number of pseudo periods for low latency playback */ +#define PLAYBACK_PERIOD_COUNT 4 +#define PLAYBACK_PERIOD_START_THRESHOLD 2 +#define PLAYBACK_CODEC_SAMPLING_RATE 48000 +#define MIN_WRITE_SLEEP_US 5000 + +#define SPEAKER_EQ_FILE "/vendor/etc/speaker_eq.fir" +#define SPEAKER_MAX_EQ_LENGTH 512 + +struct alsa_audio_device { + struct audio_hw_device hw_device; + + pthread_mutex_t lock; /* see notes in in_read/out_write on mutex acquisition order */ + struct alsa_stream_in *active_input; + struct alsa_stream_out *active_output; + struct audio_route *audio_route; + struct mixer *mixer; + bool mic_mute; + struct aec_t *aec; +}; + +struct alsa_stream_in { + struct audio_stream_in stream; + + pthread_mutex_t lock; /* see note in in_read() on mutex acquisition order */ + audio_devices_t devices; + struct pcm_config config; + struct pcm *pcm; + bool unavailable; + bool standby; + struct alsa_audio_device *dev; + int read_threshold; + unsigned int frames_read; + uint64_t timestamp_nsec; + audio_source_t source; +}; + +struct alsa_stream_out { + struct audio_stream_out stream; + + pthread_mutex_t lock; /* see note in out_write() on mutex acquisition order */ + audio_devices_t devices; + struct pcm_config config; + struct pcm *pcm; + bool unavailable; + int standby; + struct alsa_audio_device *dev; + int write_threshold; + unsigned int frames_written; + struct timespec timestamp; + fir_filter_t* speaker_eq; +}; + +/* 'bytes' are the number of bytes written to audio FIFO, for which 'timestamp' is valid. + * 'available' is the number of frames available to read (for input) or yet to be played + * (for output) frames in the PCM buffer. + * timestamp and available are updated by pcm_get_htimestamp(), so they use the same + * datatypes as the corresponding arguments to that function. */ +struct aec_info { + struct timespec timestamp; + uint64_t timestamp_usec; + unsigned int available; + size_t bytes; +}; + +#endif /* #ifndef _YUKAWA_AUDIO_HW_H_ */ diff --git a/audio/fifo_wrapper.cpp b/audio/fifo_wrapper.cpp new file mode 100644 index 0000000..7bc9079 --- /dev/null +++ b/audio/fifo_wrapper.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2019 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 "audio_utils_fifo_wrapper" +// #define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include "fifo_wrapper.h" + +struct audio_fifo_itfe { + audio_utils_fifo *p_fifo; + audio_utils_fifo_reader *p_fifo_reader; + audio_utils_fifo_writer *p_fifo_writer; + int8_t *p_buffer; +}; + +void *fifo_init(uint32_t bytes, bool reader_throttles_writer) { + struct audio_fifo_itfe *interface = new struct audio_fifo_itfe; + interface->p_buffer = new int8_t[bytes]; + if (interface->p_buffer == NULL) { + ALOGE("Failed to allocate fifo buffer!"); + return NULL; + } + interface->p_fifo = new audio_utils_fifo(bytes, 1, interface->p_buffer, reader_throttles_writer); + interface->p_fifo_writer = new audio_utils_fifo_writer(*interface->p_fifo); + interface->p_fifo_reader = new audio_utils_fifo_reader(*interface->p_fifo); + + return (void *)interface; +} + +void fifo_release(void *fifo_itfe) { + struct audio_fifo_itfe *interface = static_cast(fifo_itfe); + delete interface->p_fifo_writer; + delete interface->p_fifo_reader; + delete interface->p_fifo; + delete[] interface->p_buffer; + delete interface; +} + +ssize_t fifo_read(void *fifo_itfe, void *buffer, size_t bytes) { + struct audio_fifo_itfe *interface = static_cast(fifo_itfe); + return interface->p_fifo_reader->read(buffer, bytes); +} + +ssize_t fifo_write(void *fifo_itfe, void *buffer, size_t bytes) { + struct audio_fifo_itfe *interface = static_cast(fifo_itfe); + return interface->p_fifo_writer->write(buffer, bytes); +} + +ssize_t fifo_available_to_read(void *fifo_itfe) { + struct audio_fifo_itfe *interface = static_cast(fifo_itfe); + return interface->p_fifo_reader->available(); +} + +ssize_t fifo_available_to_write(void *fifo_itfe) { + struct audio_fifo_itfe *interface = static_cast(fifo_itfe); + return interface->p_fifo_writer->available(); +} + +ssize_t fifo_flush(void *fifo_itfe) { + struct audio_fifo_itfe *interface = static_cast(fifo_itfe); + return interface->p_fifo_reader->flush(); +} diff --git a/audio/fifo_wrapper.h b/audio/fifo_wrapper.h new file mode 100644 index 0000000..e9469ef --- /dev/null +++ b/audio/fifo_wrapper.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 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 _AUDIO_FIFO_WRAPPER_H_ +#define _AUDIO_FIFO_WRAPPER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void *fifo_init(uint32_t bytes, bool reader_throttles_writer); +void fifo_release(void *fifo_itfe); +ssize_t fifo_read(void *fifo_itfe, void *buffer, size_t bytes); +ssize_t fifo_write(void *fifo_itfe, void *buffer, size_t bytes); +ssize_t fifo_available_to_read(void *fifo_itfe); +ssize_t fifo_available_to_write(void *fifo_itfe); +ssize_t fifo_flush(void *fifo_itfe); + +#ifdef __cplusplus +} +#endif +#endif /* #ifndef _AUDIO_FIFO_WRAPPER_H_ */ diff --git a/audio/fir_filter.c b/audio/fir_filter.c new file mode 100644 index 0000000..c648fc0 --- /dev/null +++ b/audio/fir_filter.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "audio_hw_fir_filter" +//#define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include +#include +#include + +#include "fir_filter.h" + +#ifdef __ARM_NEON +#include "arm_neon.h" +#endif /* #ifdef __ARM_NEON */ + +fir_filter_t* fir_init(uint32_t channels, fir_filter_mode_t mode, uint32_t filter_length, + uint32_t input_length, int16_t* coeffs) { + if ((channels == 0) || (filter_length == 0) || (coeffs == NULL)) { + ALOGE("%s: Invalid channel count, filter length or coefficient array.", __func__); + return NULL; + } + + fir_filter_t* fir = (fir_filter_t*)calloc(1, sizeof(fir_filter_t)); + if (fir == NULL) { + ALOGE("%s: Unable to allocate memory for fir_filter.", __func__); + return NULL; + } + + fir->channels = channels; + fir->filter_length = filter_length; + /* Default: same filter coeffs for all channels */ + fir->mode = FIR_SINGLE_FILTER; + uint32_t coeff_bytes = fir->filter_length * sizeof(int16_t); + if (mode == FIR_PER_CHANNEL_FILTER) { + fir->mode = FIR_PER_CHANNEL_FILTER; + coeff_bytes = fir->filter_length * fir->channels * sizeof(int16_t); + } + + fir->coeffs = (int16_t*)malloc(coeff_bytes); + if (fir->coeffs == NULL) { + ALOGE("%s: Unable to allocate memory for FIR coeffs", __func__); + goto exit_1; + } + memcpy(fir->coeffs, coeffs, coeff_bytes); + + fir->buffer_size = (input_length + fir->filter_length) * fir->channels; + fir->state = (int16_t*)malloc(fir->buffer_size * sizeof(int16_t)); + if (fir->state == NULL) { + ALOGE("%s: Unable to allocate memory for FIR state", __func__); + goto exit_2; + } + +#ifdef __ARM_NEON + ALOGI("%s: Using ARM Neon", __func__); +#endif /* #ifdef __ARM_NEON */ + + fir_reset(fir); + return fir; + +exit_2: + free(fir->coeffs); +exit_1: + free(fir); + return NULL; +} + +void fir_release(fir_filter_t* fir) { + if (fir == NULL) { + return; + } + free(fir->state); + free(fir->coeffs); + free(fir); +} + +void fir_reset(fir_filter_t* fir) { + if (fir == NULL) { + return; + } + memset(fir->state, 0, fir->buffer_size * sizeof(int16_t)); +} + +void fir_process_interleaved(fir_filter_t* fir, int16_t* input, int16_t* output, uint32_t samples) { + assert(fir != NULL); + + int start_offset = (fir->filter_length - 1) * fir->channels; + memcpy(&fir->state[start_offset], input, samples * fir->channels * sizeof(int16_t)); + // int ch; + bool use_2nd_set_coeffs = (fir->channels > 1) && (fir->mode == FIR_PER_CHANNEL_FILTER); + int16_t* p_coeff_A = &fir->coeffs[0]; + int16_t* p_coeff_B = use_2nd_set_coeffs ? &fir->coeffs[fir->filter_length] : &fir->coeffs[0]; + int16_t* p_output; + for (int ch = 0; ch < fir->channels; ch += 2) { + p_output = &output[ch]; + int offset = start_offset + ch; + for (int s = 0; s < samples; s++) { + int32_t acc_A = 0; + int32_t acc_B = 0; + +#ifdef __ARM_NEON + int32x4_t acc_vec = vdupq_n_s32(0); + for (int k = 0; k < fir->filter_length; k++, offset -= fir->channels) { + int16x4_t coeff_vec = vdup_n_s16(p_coeff_A[k]); + coeff_vec = vset_lane_s16(p_coeff_B[k], coeff_vec, 1); + int16x4_t input_vec = vld1_s16(&fir->state[offset]); + acc_vec = vmlal_s16(acc_vec, coeff_vec, input_vec); + } + acc_A = vgetq_lane_s32(acc_vec, 0); + acc_B = vgetq_lane_s32(acc_vec, 1); +#else + for (int k = 0; k < fir->filter_length; k++, offset -= fir->channels) { + int32_t input_A = (int32_t)(fir->state[offset]); + int32_t coeff_A = (int32_t)(p_coeff_A[k]); + int32_t input_B = (int32_t)(fir->state[offset + 1]); + int32_t coeff_B = (int32_t)(p_coeff_B[k]); + acc_A += (input_A * coeff_A); + acc_B += (input_B * coeff_B); + } +#endif /* #ifdef __ARM_NEON */ + + *p_output = clamp16(acc_A >> 15); + if (ch < fir->channels - 1) { + *(p_output + 1) = clamp16(acc_B >> 15); + } + /* Move to next sample */ + p_output += fir->channels; + offset += (fir->filter_length + 1) * fir->channels; + } + if (use_2nd_set_coeffs) { + p_coeff_A += (fir->filter_length << 1); + p_coeff_B += (fir->filter_length << 1); + } + } + memmove(fir->state, &fir->state[samples * fir->channels], + (fir->filter_length - 1) * fir->channels * sizeof(int16_t)); +} diff --git a/audio/fir_filter.h b/audio/fir_filter.h new file mode 100644 index 0000000..d8c6e91 --- /dev/null +++ b/audio/fir_filter.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIR_FILTER_H +#define FIR_FILTER_H + +#include + +typedef enum fir_filter_mode { FIR_SINGLE_FILTER = 0, FIR_PER_CHANNEL_FILTER } fir_filter_mode_t; + +typedef struct fir_filter { + fir_filter_mode_t mode; + uint32_t channels; + uint32_t filter_length; + uint32_t buffer_size; + int16_t* coeffs; + int16_t* state; +} fir_filter_t; + +fir_filter_t* fir_init(uint32_t channels, fir_filter_mode_t mode, uint32_t filter_length, + uint32_t input_length, int16_t* coeffs); +void fir_release(fir_filter_t* fir); +void fir_reset(fir_filter_t* fir); +void fir_process_interleaved(fir_filter_t* fir, int16_t* input, int16_t* output, uint32_t samples); + +#endif /* #ifndef FIR_FILTER_H */ diff --git a/device-common.mk b/device-common.mk index de39035..88d4221 100644 --- a/device-common.mk +++ b/device-common.mk @@ -119,6 +119,7 @@ PRODUCT_PACKAGES += \ # audio policy configuration USE_XML_AUDIO_POLICY_CONF := 1 PRODUCT_COPY_FILES += \ + $(LOCAL_PATH)/etc/mixer_paths.xml:$(TARGET_COPY_OUT_VENDOR)/etc/mixer_paths.xml \ $(LOCAL_PATH)/etc/audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration.xml \ $(LOCAL_PATH)/etc/audio_policy_configuration_bluetooth_legacy_hal.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration_bluetooth_legacy_hal.xml \ frameworks/av/services/audiopolicy/config/a2dp_audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/a2dp_audio_policy_configuration.xml \ diff --git a/etc/audio_policy_configuration.xml b/etc/audio_policy_configuration.xml index c94718e..fec99cc 100644 --- a/etc/audio_policy_configuration.xml +++ b/etc/audio_policy_configuration.xml @@ -1,5 +1,5 @@ - - - - + + + + + + + - + Speaker Built-In Mic + Echo Reference Speaker @@ -36,10 +61,17 @@ samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/> + + + - + + @@ -49,10 +81,6 @@ - - - - @@ -60,6 +88,11 @@ + + + @@ -69,16 +102,14 @@ sources="primary output"/> - - + diff --git a/etc/mixer_paths.xml b/etc/mixer_paths.xml new file mode 100644 index 0000000..dc28741 --- /dev/null +++ b/etc/mixer_paths.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/qcom/init.qcom.rc b/qcom/init.qcom.rc index 94e9038..f97b502 100644 --- a/qcom/init.qcom.rc +++ b/qcom/init.qcom.rc @@ -32,31 +32,6 @@ on early-init on post-fs start pd_mapper - exec - root -- /system/bin/sleep 1 - exec - system audio -- /system/bin/tinymix "QUAT_MI2S_RX Audio Mixer MultiMedia1" 1 - exec - system audio -- /system/bin/tinymix "QUAT_MI2S_RX Audio Mixer MultiMedia2" 1 - exec - system audio -- /system/bin/tinymix "SLIM RX0 MUX" AIF1_PB - exec - system audio -- /system/bin/tinymix "SLIM RX0 MUX" ZERO - exec - system audio -- /system/bin/tinymix "SLIM RX1 MUX" ZERO - exec - system audio -- /system/bin/tinymix "SLIM RX2 MUX" ZERO - exec - system audio -- /system/bin/tinymix "SLIM RX3 MUX" ZERO - exec - system audio -- /system/bin/tinymix "SLIM RX4 MUX" ZERO - exec - system audio -- /system/bin/tinymix "SLIM RX5 MUX" ZERO - exec - system audio -- /system/bin/tinymix "SLIM RX6 MUX" AIF1_PB - exec - system audio -- /system/bin/tinymix "SLIM RX7 MUX" AIF1_PB - exec - system audio -- /system/bin/tinymix "RX INT7_1 MIX1 INP0" RX6 - exec - system audio -- /system/bin/tinymix "RX INT8_1 MIX1 INP0" RX7 - exec - system audio -- /system/bin/tinymix "COMP7 Switch" 1 - exec - system audio -- /system/bin/tinymix "COMP8 Switch" 1 - exec - system audio -- /system/bin/tinymix "SpkrLeft COMP Switch" 1 - exec - system audio -- /system/bin/tinymix "SpkrLeft BOOST Switch" 1 - exec - system audio -- /system/bin/tinymix "SpkrLeft VISENSE Switch" 0 - exec - system audio -- /system/bin/tinymix "SpkrLeft DAC Switch" 1 - exec - system audio -- /system/bin/tinymix "SpkrRight COMP Switch" 1 - exec - system audio -- /system/bin/tinymix "SpkrRight BOOST Switch" 1 - exec - system audio -- /system/bin/tinymix "SpkrRight VISENSE Switch" 0 - exec - system audio -- /system/bin/tinymix "SpkrRight DAC Switch" 1 - exec - system audio -- /system/bin/tinymix "SLIMBUS_0_RX Audio Mixer MultiMedia2" 1 on post-fs-data mkdir /data/vendor -- cgit v1.2.3 From e24372e861c14654a4eb9449dd3d0a615522f084 Mon Sep 17 00:00:00 2001 From: Sasha Smundak Date: Mon, 23 Nov 2020 22:29:32 -0800 Subject: Remove unnecessary quotes Bug: 173737347 Test: treehugger Change-Id: Id49741240ecfe74aa006e58540c16a4b0d8b8ff4 --- pixel3_mainline/device.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pixel3_mainline/device.mk b/pixel3_mainline/device.mk index e394c60..4f159c5 100644 --- a/pixel3_mainline/device.mk +++ b/pixel3_mainline/device.mk @@ -25,7 +25,7 @@ PRODUCT_COPY_FILES := \ device/linaro/dragonboard/init.common.usb.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/init.pixel3_mainline.usb.rc \ device/linaro/dragonboard/common.kl:$(TARGET_COPY_OUT_VENDOR)/usr/keylayout/pixel3_mainline.kl -ifneq ("$(wildcard $(PIXEL3_KERNEL_DIR)/Image.gz-dtb)","") +ifneq (,$(wildcard $(PIXEL3_KERNEL_DIR)/Image.gz-dtb)) PRODUCT_COPY_FILES += $(PIXEL3_KERNEL_DIR)/Image.gz-dtb:kernel PIXEL3_KERNEL_FOUND := true else -- cgit v1.2.3 From 44f3990603403ab80bf74fece9950efdb22a3eae Mon Sep 17 00:00:00 2001 From: Amit Pundir Date: Tue, 12 Jan 2021 16:45:02 +0530 Subject: db845c: Make it a Virtual A/B device All dynamic partitions are A/B. Signed-off-by: Amit Pundir Change-Id: I9650626b5a463ff9f368680ae8c32b8432fee1e8 --- db845c/device.mk | 10 ++++++++++ fstab.common | 8 ++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/db845c/device.mk b/db845c/device.mk index 2240981..0c2cbf9 100644 --- a/db845c/device.mk +++ b/db845c/device.mk @@ -20,6 +20,16 @@ PRODUCT_SOONG_NAMESPACES += \ # setup dalvik vm configs $(call inherit-product, frameworks/native/build/tablet-10in-xhdpi-2048-dalvik-heap.mk) +# Enable Virtual A/B +AB_OTA_UPDATER := true +AB_OTA_PARTITIONS += \ + product \ + system \ + system_ext \ + vendor + +$(call inherit-product, $(SRC_TARGET_DIR)/product/virtual_ab_ota.mk) + PRODUCT_COPY_FILES := \ $(DB845C_KERNEL_DIR)/Image.gz:kernel \ $(DB845C_KERNEL_DIR)/sdm845-db845c.dtb:dtb.img \ diff --git a/fstab.common b/fstab.common index f9023ad..a0d925f 100644 --- a/fstab.common +++ b/fstab.common @@ -1,9 +1,9 @@ -system /system ext4 noatime,ro,errors=panic wait,logical,first_stage_mount +system /system ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect /dev/block/platform/soc@0/1d84000.ufshc/by-name/userdata /data ext4 discard,noatime,noauto_da_alloc,data=ordered,user_xattr,barrier=1,inlinecrypt wait,formattable,fileencryption=aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized,quota /dev/block/platform/soc@0/1d84000.ufshc/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard wait,formattable /dev/block/platform/soc@0/1d84000.ufshc/by-name/cache /cache ext4 nodev,noatime,nosuid,errors=panic wait /dev/block/platform/soc@0/1d84000.ufshc/by-name/misc /misc emmc defaults defaults /devices/platform/soc@0/8804000.sdhci/mmc_host/mmc* auto auto defaults voldmanaged=sdcard1:auto -vendor /vendor ext4 noatime,ro,errors=panic wait,logical,first_stage_mount -system_ext /system_ext ext4 noatime,ro,errors=panic wait,logical,first_stage_mount -product /product ext4 noatime,ro,errors=panic wait,logical,first_stage_mount +vendor /vendor ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect +system_ext /system_ext ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect +product /product ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect -- cgit v1.2.3 From 04e4b2fb76e75b517b6e5ce7fa9519575a15d4e2 Mon Sep 17 00:00:00 2001 From: Amit Pundir Date: Fri, 15 Jan 2021 00:59:21 +0530 Subject: Revert "db845c: Add support for cache partition" This reverts commit 70f37c65199443d2502da58ecb81a4be28d36d80. With Virtual A/B, we no longer need cache partition for "adb remount" to work with overlayfs. Signed-off-by: Amit Pundir Change-Id: I979e61c4a64a8d0b1c7345491f4924c1d3fa62e0 --- BoardConfigCommon.mk | 3 --- fstab.common | 1 - installer/db845c/flash-all-aosp.sh | 2 -- sepolicy/file_contexts | 1 - 4 files changed, 7 deletions(-) diff --git a/BoardConfigCommon.mk b/BoardConfigCommon.mk index d527c0e..b879d96 100644 --- a/BoardConfigCommon.mk +++ b/BoardConfigCommon.mk @@ -41,9 +41,6 @@ BOARD_SYSTEM_EXTIMAGE_FILE_SYSTEM_TYPE := ext4 TARGET_COPY_OUT_PRODUCT := product BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE := ext4 BOARD_USES_METADATA_PARTITION := true -# Cache partition size: 64M -BOARD_CACHEIMAGE_PARTITION_SIZE := 67108864 -BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE := ext4 # Super partition TARGET_USE_DYNAMIC_PARTITIONS := true BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT := true diff --git a/fstab.common b/fstab.common index a0d925f..c6e1332 100644 --- a/fstab.common +++ b/fstab.common @@ -1,7 +1,6 @@ system /system ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect /dev/block/platform/soc@0/1d84000.ufshc/by-name/userdata /data ext4 discard,noatime,noauto_da_alloc,data=ordered,user_xattr,barrier=1,inlinecrypt wait,formattable,fileencryption=aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized,quota /dev/block/platform/soc@0/1d84000.ufshc/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard wait,formattable -/dev/block/platform/soc@0/1d84000.ufshc/by-name/cache /cache ext4 nodev,noatime,nosuid,errors=panic wait /dev/block/platform/soc@0/1d84000.ufshc/by-name/misc /misc emmc defaults defaults /devices/platform/soc@0/8804000.sdhci/mmc_host/mmc* auto auto defaults voldmanaged=sdcard1:auto vendor /vendor ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect diff --git a/installer/db845c/flash-all-aosp.sh b/installer/db845c/flash-all-aosp.sh index b3c677b..e6b1995 100755 --- a/installer/db845c/flash-all-aosp.sh +++ b/installer/db845c/flash-all-aosp.sh @@ -40,8 +40,6 @@ echo "FLASH-ALL-AOSP: Flash boot img" fastboot flash boot "${ANDROID_PRODUCT_OUT}"/boot.img echo "FLASH-ALL-AOSP: Flash super/dynamic image" fastboot flash super "${ANDROID_PRODUCT_OUT}"/super.img -echo "FLASH-ALL-AOSP: Flash cache image" -fastboot flash cache "${ANDROID_PRODUCT_OUT}"/cache.img echo "FLASH-ALL-AOSP: Flash userdata image" fastboot flash userdata "${ANDROID_PRODUCT_OUT}"/userdata.img diff --git a/sepolicy/file_contexts b/sepolicy/file_contexts index f70cc5f..70ab83c 100644 --- a/sepolicy/file_contexts +++ b/sepolicy/file_contexts @@ -4,7 +4,6 @@ /dev/block/platform/soc@0/1d84000\.ufshc/by-name/metadata u:object_r:metadata_block_device:s0 /dev/block/platform/soc@0/1d84000\.ufshc/by-name/super u:object_r:super_block_device:s0 /dev/block/platform/soc@0/1d84000\.ufshc/by-name/userdata u:object_r:userdata_block_device:s0 -/dev/block/platform/soc@0/1d84000\.ufshc/by-name/cache u:object_r:cache_block_device:s0 /dev/block/platform/soc@0/1d84000\.ufshc/by-name/misc u:object_r:misc_block_device:s0 /dev/dri u:object_r:dri_device:s0 -- cgit v1.2.3 From 0e1b77023eb9c23d9eada65ecc842447704fec0e Mon Sep 17 00:00:00 2001 From: Amit Pundir Date: Tue, 22 Dec 2020 13:37:19 +0530 Subject: db845c: installer: Update bootloader binaries to support boot image header v3 Update db845c bootloader binaries to support Android boot image header v3. Downloaded (build #66) from here: https://snapshots.linaro.org/96boards/dragonboard845c/linaro/rescue/66/ Build description: * Build URL: https://ci.linaro.org/job/lt-qcom-bootloader-dragonboard845c/66/ * ABL source code: https://git.linaro.org/landing-teams/working/qualcomm/abl.git/commit/?id=5ec80d0f198b * Partition table: https://git.linaro.org/landing-teams/working/qualcomm/db-boot-tools.git/tree/dragonboard845c/aosp/partition.xml?id=a8d3103bd7cf Signed-off-by: Amit Pundir Change-Id: I6a058cf44630493cb2edcc4e3839d7ae1b647e3f --- .../MD5SUMS.txt | 42 ++++++++++----------- .../dragonboard-845c-bootloader-ufs-aosp/abl.elf | Bin 151552 -> 151552 bytes .../gpt_backup0.bin | Bin 20480 -> 20480 bytes .../gpt_backup1.bin | Bin 20480 -> 20480 bytes .../gpt_backup2.bin | Bin 20480 -> 20480 bytes .../gpt_backup3.bin | Bin 20480 -> 20480 bytes .../gpt_backup4.bin | Bin 20480 -> 20480 bytes .../gpt_backup5.bin | Bin 20480 -> 20480 bytes .../gpt_both0.bin | Bin 45056 -> 45056 bytes .../gpt_both1.bin | Bin 45056 -> 45056 bytes .../gpt_both2.bin | Bin 45056 -> 45056 bytes .../gpt_both3.bin | Bin 45056 -> 45056 bytes .../gpt_both4.bin | Bin 45056 -> 45056 bytes .../gpt_both5.bin | Bin 45056 -> 45056 bytes .../gpt_main0.bin | Bin 24576 -> 24576 bytes .../gpt_main1.bin | Bin 24576 -> 24576 bytes .../gpt_main2.bin | Bin 24576 -> 24576 bytes .../gpt_main3.bin | Bin 24576 -> 24576 bytes .../gpt_main4.bin | Bin 24576 -> 24576 bytes .../gpt_main5.bin | Bin 24576 -> 24576 bytes .../patch0.xml | 8 ++-- .../rawprogram0.xml | 6 ++- 22 files changed, 29 insertions(+), 27 deletions(-) diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/MD5SUMS.txt b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/MD5SUMS.txt index 61b9063..b28964e 100644 --- a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/MD5SUMS.txt +++ b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/MD5SUMS.txt @@ -1,4 +1,4 @@ -9e5bd5524c1379c511dd92ea33393ad7 abl.elf +bebec2693af4135bd0e55a9733330d4c abl.elf 71c6dd41e387ddb12c8553091928ec39 aop.mbn b6d81b360a5672d80c27430f39153e2c boot-erase.img 40e97319f57ab9d0b60009163ff940c2 BTFM.bin @@ -7,29 +7,29 @@ cbd3f7ab1a261c30e9e3178c0ec09428 cmnlib64.mbn 699e4dc2a0dbac11b255c79422744b44 devcfg.mbn d5cf22da99f6a871d4c7d43ce8eb801a dspso.bin 4400827c0a6689bfe118a67d79b4fcd7 flashall -61362db524d6b1a082aa3e68c5ce5226 gpt_backup0.bin -10711bd7b6c795b396ec7acc6546641b gpt_backup1.bin -1384ab8fa504bed08282b9fdbedd1256 gpt_backup2.bin -f9f43f922865a282bd340731e2e4c05c gpt_backup3.bin -c98f59260b9d839fd66c7a799344763b gpt_backup4.bin -f1dd799d40155b2fb0a13e74dc708ef0 gpt_backup5.bin -62809acaa9deeafbcf228ab3dec80fba gpt_both0.bin -1a45d3cc41bf1f7ab52c35a8dafde7c2 gpt_both1.bin -26156f1cf28c2b03a52dc645e0776a6a gpt_both2.bin -836794cd35e92ac1865bca5bceb3afa8 gpt_both3.bin -2a728d731064cb62a253e05fda09584c gpt_both4.bin -9b30da0d32e99c239a51c3d868960fde gpt_both5.bin -d3d913561434b15f1fd42b5c26b6e514 gpt_main0.bin -42d103f66ffadf2fabe079c864d6ad2f gpt_main1.bin -33f9210eb72379fa4d737f7d968d69fe gpt_main2.bin -41530c11400b67d4efaca893a7bbc99f gpt_main3.bin -2ac0679ed66a373fc2a863dcb17bf6bf gpt_main4.bin -866e4769d16b95bb473441fa79b39d23 gpt_main5.bin +d04ddc2ba6ddc3f46277be0f5110b89c gpt_backup0.bin +419282dd351676dd57bbdbf9071d3e0d gpt_backup1.bin +e4ec698b620dc22e21f8535d0e86974d gpt_backup2.bin +ac76f9ed9c900519ac2674ec57bb3567 gpt_backup3.bin +3344e3a3f0cc9bd6724a6daf54795999 gpt_backup4.bin +5abe36752afdf6906a34446fb07ba577 gpt_backup5.bin +95ee7f7e67da134eb78feaba2632ea88 gpt_both0.bin +2262a9ca99e9a4d0f14e82d72ef3875e gpt_both1.bin +3f5b9188752af8559b62dca9734a412b gpt_both2.bin +beae90cc33e3e49030ea4ae55506d7d5 gpt_both3.bin +1e96d0067787380a271877f03a0d697f gpt_both4.bin +d3e137333ddfad50e598b96d0bfd9099 gpt_both5.bin +1d36ec2fd30f8a36b572912c68b84cd5 gpt_main0.bin +c7430987eba9d90f439b8ee4553cc82d gpt_main1.bin +4545b1e540e2b974a267b431c201a6b5 gpt_main2.bin +d2e476646595d7b7a1e10ca80cb00db4 gpt_main3.bin +f3fab8efdf25c1321e76c46e3706996d gpt_main4.bin +a5e59821587d028dfca32d751b94cb25 gpt_main5.bin 94794668fb0a63c599e754cba52f6517 hyp.mbn 35cc47772102f785807556e03135764a imagefv.elf 1fbaef77827cc531b5b7372ad1ee4937 keymaster64.mbn cbbe399f2c983ad51768f4561587f000 LICENSE -c1c770a035a596c4b13a08789a76a137 patch0.xml +7da8e656c3c01e6471479328af510728 patch0.xml 0780990ee59934bdcaffc918cac99aed patch1.xml 81036277fd056a16c0e418a756a5a835 patch2.xml f1e955eeee449ed57767ac0b87552cf1 patch3.xml @@ -37,7 +37,7 @@ f1e955eeee449ed57767ac0b87552cf1 patch3.xml ab5847dcda2a52572616499f37ff1676 patch5.xml 61e29ca7d21884af0e3a813d3bd0ade1 prog_firehose_ddr.elf 57f570d8896ef6c0e55af6c3dc0940e1 qupv3fw.elf -aea48fb241747a7db9741b05d2cc8a5e rawprogram0.xml +a4335c18367bd7edd478f59482259476 rawprogram0.xml 078978d92fc3c2a0ad0744e5e905e806 rawprogram1.xml e829b09f11eeed7f44caca1b592c91bf rawprogram2.xml e03411d04b290ffe1ea9b993d1f23074 rawprogram3.xml diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/abl.elf b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/abl.elf index a8e5195..74101e0 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/abl.elf and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/abl.elf differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup0.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup0.bin index c293d6c..724c269 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup0.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup0.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup1.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup1.bin index a7df42f..03ea3ce 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup1.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup1.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup2.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup2.bin index 9768f0d..5e4df8f 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup2.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup2.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup3.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup3.bin index 308f3d7..fe98cdc 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup3.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup3.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup4.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup4.bin index 047e1b0..93d0b16 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup4.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup4.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup5.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup5.bin index 51e1a4c..8e601c7 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup5.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_backup5.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both0.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both0.bin index ecb66bf..9c20853 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both0.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both0.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both1.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both1.bin index c16f0bd..dd0730b 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both1.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both1.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both2.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both2.bin index bd359d5..691646b 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both2.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both2.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both3.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both3.bin index ae4516f..4d534b4 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both3.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both3.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both4.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both4.bin index bc2cf44..e96ae6b 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both4.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both4.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both5.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both5.bin index 47be07d..adf440c 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both5.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_both5.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main0.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main0.bin index 9fffcb8..79e1cae 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main0.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main0.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main1.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main1.bin index 33c7c99..b7bbaba 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main1.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main1.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main2.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main2.bin index ea6d98f..cc3f0eb 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main2.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main2.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main3.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main3.bin index ed6134e..12d0a41 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main3.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main3.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main4.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main4.bin index e690bd8..534e26e 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main4.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main4.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main5.bin b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main5.bin index f7c071c..7c12784 100644 Binary files a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main5.bin and b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/gpt_main5.bin differ diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/patch0.xml b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/patch0.xml index 3548ee3..28f4a18 100644 --- a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/patch0.xml +++ b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/patch0.xml @@ -3,10 +3,10 @@ - - - - + + + + diff --git a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/rawprogram0.xml b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/rawprogram0.xml index f9ec76b..f0a03e8 100644 --- a/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/rawprogram0.xml +++ b/installer/db845c/dragonboard-845c-bootloader-ufs-aosp/rawprogram0.xml @@ -3,8 +3,10 @@ - - + + + + -- cgit v1.2.3 From 6d532aebe85c285bfd15fc4347c7478c60bda5d5 Mon Sep 17 00:00:00 2001 From: Amit Pundir Date: Fri, 15 Jan 2021 02:21:28 +0530 Subject: screenrecord: Fix mediacodec selinux and seccomp policy denials Fix mediacodec selinux and seccomp denials for screenrecord to work. mediacodec need gpu access, plus it also crashes with following seccomp error during screenrecord: E android.hardware.media.omx@1.0-service: libminijail[488]: blocked syscall: sysinfo So allow sysinfo syscall for mediacodec by re-using the same seccomp_policy which we use for mediaswcodec (aosp/1238348). Signed-off-by: Amit Pundir Change-Id: I62fd7ef159c520a26be83cd57ec72e1d51adfa52 --- device-common.mk | 1 + sepolicy/mediacodec.te | 1 + 2 files changed, 2 insertions(+) create mode 100644 sepolicy/mediacodec.te diff --git a/device-common.mk b/device-common.mk index 88d4221..918bed0 100644 --- a/device-common.mk +++ b/device-common.mk @@ -139,6 +139,7 @@ PRODUCT_COPY_FILES += \ frameworks/av/media/libstagefright/data/media_codecs_google_audio.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_codecs_google_audio.xml PRODUCT_COPY_FILES += \ + $(LOCAL_PATH)/seccomp_policy/mediaswcodec.policy:$(TARGET_COPY_OUT_VENDOR)/etc/seccomp_policy/mediacodec.policy \ $(LOCAL_PATH)/seccomp_policy/mediaswcodec.policy:$(TARGET_COPY_OUT_VENDOR)/etc/seccomp_policy/mediaswcodec.policy # Copy hardware config file(s) diff --git a/sepolicy/mediacodec.te b/sepolicy/mediacodec.te new file mode 100644 index 0000000..6119c90 --- /dev/null +++ b/sepolicy/mediacodec.te @@ -0,0 +1 @@ +gpu_access(mediacodec) -- cgit v1.2.3 From dd5bd1b45d17408eda074adb5aec317ad5316086 Mon Sep 17 00:00:00 2001 From: Amit Pundir Date: Tue, 22 Dec 2020 13:46:24 +0530 Subject: db845c: Enable boot image header v3 support To enable boot image header v3 support, set "TARGET_USES_BOOT_HDR_V3=true" while building AOSP images for db845c. Build will fall back to boot image header v2 otherwise. Boot image header v3 support depends on the latest bootloader binaries. Run device/linaro/dragonboard/installer/db845c/flash-all-aosp.sh script to update the bootloader binaries on db845c. Signed-off-by: Amit Pundir Change-Id: Iaf565fc25c731a9d42c8fbc550686b588caba5df --- db845c/BoardConfig.mk | 10 ++++++++-- db845c/device.mk | 4 ++++ installer/db845c/README | 11 +++-------- installer/db845c/flash-all-aosp.sh | 2 ++ 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/db845c/BoardConfig.mk b/db845c/BoardConfig.mk index 9d31f97..67120aa 100644 --- a/db845c/BoardConfig.mk +++ b/db845c/BoardConfig.mk @@ -6,10 +6,16 @@ TARGET_BOARD_PLATFORM := db845c TARGET_NO_KERNEL := false BOARD_INCLUDE_DTB_IN_BOOTIMG := true -BOARD_BOOT_HEADER_VERSION := 2 +ifeq ($(TARGET_USES_BOOT_HDR_V3), true) + BOARD_BOOT_HEADER_VERSION := 3 + BOARD_KERNEL_PAGESIZE := 4096 + BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE := 67108864 #64M +else + BOARD_BOOT_HEADER_VERSION := 2 + BOARD_KERNEL_PAGESIZE := 2048 +endif BOARD_MKBOOTIMG_ARGS := --header_version $(BOARD_BOOT_HEADER_VERSION) BOARD_KERNEL_BASE := 0x80000000 -BOARD_KERNEL_PAGESIZE := 2048 BOARD_KERNEL_CMDLINE := earlycon firmware_class.path=/vendor/firmware/ androidboot.hardware=db845c BOARD_KERNEL_CMDLINE += init=/init androidboot.boot_devices=soc@0/1d84000.ufshc printk.devkmsg=on BOARD_KERNEL_CMDLINE += deferred_probe_timeout=30 diff --git a/db845c/device.mk b/db845c/device.mk index 0c2cbf9..b6480a5 100644 --- a/db845c/device.mk +++ b/db845c/device.mk @@ -28,7 +28,11 @@ AB_OTA_PARTITIONS += \ system_ext \ vendor +ifeq ($(TARGET_USES_BOOT_HDR_V3), true) +$(call inherit-product, $(SRC_TARGET_DIR)/product/virtual_ab_ota/launch_with_vendor_ramdisk.mk) +else $(call inherit-product, $(SRC_TARGET_DIR)/product/virtual_ab_ota.mk) +endif PRODUCT_COPY_FILES := \ $(DB845C_KERNEL_DIR)/Image.gz:kernel \ diff --git a/installer/db845c/README b/installer/db845c/README index 61c3a3b..3b86aa9 100644 --- a/installer/db845c/README +++ b/installer/db845c/README @@ -38,16 +38,11 @@ If HDMI is plugged in, you should see a text based Flash the board: ---------------- -Once the board is in fastboot mode, you can then flash it by -running the following from the +Once the board is in fastboot mode, you can then flash bootloader +binaries and AOSP images by running the following script from device/linaro/dragonboard/installer/db845c/ directory: - $ ./flash-all-aosp.sh - - -This will flash the bootloader binaries, AOSP images (userdata.img -and super.img), and will also generate and flash boot.img if kernel -binary (in Image.gz-dtb format) is passed to the script. + $ ./flash-all-aosp.sh Troubleshooting: diff --git a/installer/db845c/flash-all-aosp.sh b/installer/db845c/flash-all-aosp.sh index e6b1995..3451998 100755 --- a/installer/db845c/flash-all-aosp.sh +++ b/installer/db845c/flash-all-aosp.sh @@ -42,5 +42,7 @@ echo "FLASH-ALL-AOSP: Flash super/dynamic image" fastboot flash super "${ANDROID_PRODUCT_OUT}"/super.img echo "FLASH-ALL-AOSP: Flash userdata image" fastboot flash userdata "${ANDROID_PRODUCT_OUT}"/userdata.img +echo "FLASH-ALL-AOSP: Flash vendor_boot image" +fastboot flash vendor_boot "${ANDROID_PRODUCT_OUT}"/vendor_boot.img fastboot reboot -- cgit v1.2.3