[Feature]merge MTK MR3.0 release
Change-Id: I877d3bbcdacfa7d2ab902e6c4c8e740a67069038
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/extcon/chrdet_notifier.h b/src/kernel/linux/v4.19/drivers/misc/mediatek/extcon/chrdet_notifier.h
new file mode 100644
index 0000000..058f863
--- /dev/null
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/extcon/chrdet_notifier.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+#ifndef CHRDET_NOTIFIER_H
+#define CHRDET_NOTIFIER_H
+
+#include <linux/notifier.h>
+
+int register_chrdet_notifier(struct notifier_block *nb);
+int unregister_chrdet_notifier(struct notifier_block *nb);
+
+#endif
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/extcon/extcon-mtk-usb-microb.c b/src/kernel/linux/v4.19/drivers/misc/mediatek/extcon/extcon-mtk-usb-microb.c
new file mode 100644
index 0000000..9f4b2b7
--- /dev/null
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/extcon/extcon-mtk-usb-microb.c
@@ -0,0 +1,363 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 MediaTek Inc.
+ */
+
+#include <linux/extcon-provider.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/usb/role.h>
+#include <linux/workqueue.h>
+
+#include "extcon-mtk-usb-microb.h"
+#include "chrdet_notifier.h"
+
+static bool mtk_usb_extcon_otg_status(struct mtk_extcon_info *extcon)
+{
+ int id;
+ /* check ID and update cable state */
+ id = extcon->id_gpiod ?
+ gpiod_get_value_cansleep(extcon->id_gpiod) : 1;
+
+ dev_info(extcon->dev, "iddig value : %d - %s\n", id,
+ id ? "OTG not detected!" : "OTG detected");
+ return id ? false : true;
+}
+
+static void mtk_usb_extcon_update_role(struct work_struct *work)
+{
+ struct usb_role_info *role = container_of(to_delayed_work(work),
+ struct usb_role_info, dwork);
+ struct mtk_extcon_info *extcon = role->extcon;
+ unsigned int cur_dr, new_dr;
+
+ cur_dr = extcon->c_role;
+ new_dr = role->d_role;
+
+ dev_info(extcon->dev, "cur_dr(%s) new_dr(%s)\n",
+ dual_prop_dr_string[cur_dr], dual_prop_dr_string[new_dr]);
+
+ /* none -> device */
+ if (cur_dr == DUAL_PROP_DR_NONE &&
+ new_dr == DUAL_PROP_DR_DEVICE) {
+ extcon_set_state_sync(extcon->edev, EXTCON_USB, true);
+ /* none -> host */
+ } else if (cur_dr == DUAL_PROP_DR_NONE &&
+ new_dr == DUAL_PROP_DR_HOST) {
+ extcon_set_state_sync(extcon->edev, EXTCON_USB_HOST, true);
+ /* device -> none */
+ } else if (cur_dr == DUAL_PROP_DR_DEVICE &&
+ new_dr == DUAL_PROP_DR_NONE) {
+ extcon_set_state_sync(extcon->edev, EXTCON_USB, false);
+ /* host -> none */
+ } else if (cur_dr == DUAL_PROP_DR_HOST &&
+ new_dr == DUAL_PROP_DR_NONE) {
+ extcon_set_state_sync(extcon->edev, EXTCON_USB_HOST, false);
+ /* device -> host */
+ } else if (cur_dr == DUAL_PROP_DR_DEVICE &&
+ new_dr == DUAL_PROP_DR_HOST) {
+ extcon_set_state_sync(extcon->edev, EXTCON_USB, false);
+ extcon_set_state_sync(extcon->edev, EXTCON_USB_HOST, true);
+ /* host -> device */
+ } else if (cur_dr == DUAL_PROP_DR_HOST &&
+ new_dr == DUAL_PROP_DR_DEVICE) {
+ extcon_set_state_sync(extcon->edev, EXTCON_USB_HOST, false);
+ extcon_set_state_sync(extcon->edev, EXTCON_USB, true);
+ }
+
+ /* usb role switch */
+ if (extcon->role_sw) {
+ if (new_dr == DUAL_PROP_DR_DEVICE)
+ usb_role_switch_set_role(extcon->role_sw,
+ USB_ROLE_DEVICE);
+ else if (new_dr == DUAL_PROP_DR_HOST)
+ usb_role_switch_set_role(extcon->role_sw,
+ USB_ROLE_HOST);
+ else
+ usb_role_switch_set_role(extcon->role_sw,
+ USB_ROLE_NONE);
+ }
+
+ extcon->c_role = new_dr;
+ kfree(role);
+}
+
+static int mtk_usb_extcon_set_role(struct mtk_extcon_info *extcon,
+ unsigned int role)
+{
+ struct usb_role_info *role_info;
+
+ /* create and prepare worker */
+ role_info = kzalloc(sizeof(*role_info), GFP_KERNEL);
+ if (!role_info)
+ return -ENOMEM;
+
+ INIT_DELAYED_WORK(&role_info->dwork, mtk_usb_extcon_update_role);
+
+ role_info->extcon = extcon;
+ role_info->d_role = role;
+ /* issue connection work */
+ queue_delayed_work(extcon->extcon_wq, &role_info->dwork, 0);
+
+ return 0;
+}
+
+static int mtk_pmic_chrdet_notify(struct notifier_block *nb,
+ unsigned long code, void *data)
+{
+ struct mtk_extcon_info *extcon =
+ container_of(nb, struct mtk_extcon_info, chrdet_nb);
+
+ bool otg_state = mtk_usb_extcon_otg_status(extcon);
+
+ if (otg_state) {
+ dev_info(extcon->dev, "device mode bypassed due to OTG detected!\n");
+ return 0;
+ }
+
+ dev_info(extcon->dev,
+ "device mode %s!\n", code ? "detected" : "undetected");
+ if (code)
+ mtk_usb_extcon_set_role(extcon, DUAL_PROP_DR_DEVICE);
+ else
+ mtk_usb_extcon_set_role(extcon, DUAL_PROP_DR_NONE);
+
+ return 0;
+}
+
+static int mtk_usb_extcon_set_vbus(struct mtk_extcon_info *extcon,
+ bool is_on)
+{
+ struct device *dev = extcon->dev;
+
+ if (extcon->vbus_on == is_on)
+ return 0;
+
+ dev_info(dev, "vbus turn %s\n", is_on ? "on" : "off");
+ gpiod_set_value(extcon->drvbus_gpiod, is_on);
+
+ extcon->vbus_on = is_on;
+
+ return 0;
+}
+
+static void mtk_usb_extcon_detect_cable(struct work_struct *work)
+{
+ struct mtk_extcon_info *extcon = container_of(to_delayed_work(work),
+ struct mtk_extcon_info,
+ wq_detcable);
+ bool otg_state = mtk_usb_extcon_otg_status(extcon);
+
+ if (otg_state) {
+ mtk_usb_extcon_set_vbus(extcon, true);
+ mtk_usb_extcon_set_role(extcon, DUAL_PROP_DR_HOST);
+ } else {
+ mtk_usb_extcon_set_vbus(extcon, false);
+ mtk_usb_extcon_set_role(extcon, DUAL_PROP_DR_NONE);
+ }
+}
+
+static irqreturn_t mtk_usb_idpin_handle(int irq, void *dev_id)
+{
+ struct mtk_extcon_info *extcon = dev_id;
+
+ /* issue detection work */
+ queue_delayed_work(system_power_efficient_wq, &extcon->wq_detcable, 0);
+
+ return IRQ_HANDLED;
+}
+
+static int mtk_usb_extcon_id_pin_init(struct mtk_extcon_info *extcon)
+{
+ int ret = 0;
+ bool otg_state;
+
+ extcon->id_gpiod = devm_gpiod_get(extcon->dev, "id", GPIOD_IN);
+
+ if (!extcon->id_gpiod || IS_ERR(extcon->id_gpiod)) {
+ dev_err(extcon->dev, "failed to get id gpio\n");
+ extcon->id_gpiod = NULL;
+ return -EINVAL;
+ }
+
+ extcon->id_irq = gpiod_to_irq(extcon->id_gpiod);
+ if (extcon->id_irq < 0) {
+ dev_err(extcon->dev, "failed to get ID IRQ\n");
+ extcon->id_gpiod = NULL;
+ return -EINVAL;
+ }
+
+ INIT_DELAYED_WORK(&extcon->wq_detcable, mtk_usb_extcon_detect_cable);
+
+ ret = devm_request_threaded_irq(extcon->dev, extcon->id_irq, NULL,
+ mtk_usb_idpin_handle, IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ dev_name(extcon->dev), extcon);
+
+ if (ret < 0) {
+ dev_err(extcon->dev, "failed to request handler for ID IRQ\n");
+ extcon->id_gpiod = NULL;
+ return ret;
+ }
+ enable_irq_wake(extcon->id_irq);
+
+ // get id pin value when boot on
+ otg_state = mtk_usb_extcon_otg_status(extcon);
+ if (otg_state) {
+ mtk_usb_extcon_set_vbus(extcon, true);
+ mtk_usb_extcon_set_role(extcon, DUAL_PROP_DR_HOST);
+ } else {
+ mtk_usb_extcon_set_vbus(extcon, false);
+ mtk_usb_extcon_set_role(extcon, DUAL_PROP_DR_NONE);
+ }
+
+ return 0;
+}
+
+static int mtk_usb_extcon_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mtk_extcon_info *extcon;
+ struct platform_device *conn_pdev;
+ struct device_node *conn_np;
+ int ret;
+
+ extcon = devm_kzalloc(&pdev->dev, sizeof(*extcon), GFP_KERNEL);
+ if (!extcon)
+ return -ENOMEM;
+
+ extcon->dev = dev;
+
+ /* extcon */
+ extcon->edev = devm_extcon_dev_allocate(dev, usb_extcon_cable);
+ if (IS_ERR(extcon->edev)) {
+ dev_err(dev, "failed to allocate extcon device\n");
+ return -ENOMEM;
+ }
+
+ ret = devm_extcon_dev_register(dev, extcon->edev);
+ if (ret < 0) {
+ dev_info(dev, "failed to register extcon device\n");
+ return ret;
+ }
+
+ /* usb role switch */
+ conn_np = of_parse_phandle(dev->of_node, "dev-conn", 0);
+ if (!conn_np) {
+ dev_info(dev, "failed to get dev-conn node\n");
+ return -EINVAL;
+ }
+
+ conn_pdev = of_find_device_by_node(conn_np);
+ if (!conn_pdev) {
+ dev_info(dev, "failed to get dev-conn pdev\n");
+ return -EINVAL;
+ }
+
+ extcon->dev_conn.endpoint[0] = kasprintf(GFP_KERNEL,
+ "%s-role-switch", dev_name(&conn_pdev->dev));
+ extcon->dev_conn.endpoint[1] = dev_name(extcon->dev);
+ extcon->dev_conn.id = "usb-role-switch";
+ device_connection_add(&extcon->dev_conn);
+
+ extcon->role_sw = usb_role_switch_get(extcon->dev);
+ if (IS_ERR(extcon->role_sw)) {
+ device_connection_remove(&extcon->dev_conn);
+ dev_err(dev, "failed to get usb role\n");
+ return PTR_ERR(extcon->role_sw);
+ }
+
+ /* vbus */
+ extcon->drvbus_gpiod =
+ devm_gpiod_get(extcon->dev, "drvbus", GPIOD_OUT_LOW);
+
+ if (!extcon->drvbus_gpiod || IS_ERR(extcon->drvbus_gpiod)) {
+ dev_err(extcon->dev, "failed to get drvbus gpio\n");
+ extcon->drvbus_gpiod = NULL;
+ return -EINVAL;
+ }
+
+ extcon->extcon_wq = create_singlethread_workqueue("extcon_usb");
+ extcon->c_role = DUAL_PROP_DR_NONE;
+ ret = of_property_read_u32(dev->of_node, "usb_mode", &extcon->usb_mode);
+ if (ret) {
+ dev_err(dev, "some properties not found!\n");
+ return ret;
+ }
+
+ /*get id resources*/
+ if (extcon->usb_mode != DEVICE_ONLY) {
+ ret = mtk_usb_extcon_id_pin_init(extcon);
+ if (ret < 0)
+ dev_info(dev, "failed to init id pin\n");
+ }
+
+ if (extcon->usb_mode != OTG_ONLY) {
+ extcon->chrdet_nb.notifier_call = mtk_pmic_chrdet_notify;
+ ret = register_chrdet_notifier(&extcon->chrdet_nb);
+ if (ret < 0)
+ dev_info(dev, "failed to register notifier\n");
+ }
+
+ platform_set_drvdata(pdev, extcon);
+ return 0;
+}
+
+static int mtk_usb_extcon_remove(struct platform_device *pdev)
+{
+ struct mtk_extcon_info *extcon = platform_get_drvdata(pdev);
+
+ if (extcon->dev_conn.id)
+ device_connection_remove(&extcon->dev_conn);
+
+ return 0;
+}
+
+static void mtk_usb_extcon_shutdown(struct platform_device *pdev)
+{
+ struct mtk_extcon_info *extcon = platform_get_drvdata(pdev);
+
+ if (extcon->c_role == DUAL_PROP_DR_HOST) {
+ dev_info(extcon->dev, "set host vbus off when shutdown\n");
+ mtk_usb_extcon_set_vbus(extcon, false);
+ }
+}
+
+static const struct of_device_id mtk_usb_extcon_of_match[] = {
+ { .compatible = "mediatek,extcon-usb-microb", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, mtk_usb_extcon_of_match);
+
+static struct platform_driver mtk_usb_extcon_driver = {
+ .probe = mtk_usb_extcon_probe,
+ .remove = mtk_usb_extcon_remove,
+ .shutdown = mtk_usb_extcon_shutdown,
+ .driver = {
+ .name = "mtk-extcon-usb-microb",
+ .of_match_table = mtk_usb_extcon_of_match,
+ },
+};
+
+static int __init mtk_usb_extcon_init(void)
+{
+ return platform_driver_register(&mtk_usb_extcon_driver);
+}
+late_initcall(mtk_usb_extcon_init);
+
+static void __exit mtk_usb_extcon_exit(void)
+{
+ platform_driver_unregister(&mtk_usb_extcon_driver);
+}
+module_exit(mtk_usb_extcon_exit);
+
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/extcon/extcon-mtk-usb-microb.h b/src/kernel/linux/v4.19/drivers/misc/mediatek/extcon/extcon-mtk-usb-microb.h
new file mode 100644
index 0000000..78abffb
--- /dev/null
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/extcon/extcon-mtk-usb-microb.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 MediaTek Inc.
+ */
+struct mtk_extcon_info {
+ struct device *dev;
+ struct extcon_dev *edev;
+ struct usb_role_switch *role_sw;
+ unsigned int c_role; /* current data role */
+ struct workqueue_struct *extcon_wq;
+ bool vbus_on;
+ struct device_connection dev_conn;
+ struct gpio_desc *id_gpiod;
+ unsigned int id_irq;
+ struct delayed_work wq_detcable;
+ struct gpio_desc *drvbus_gpiod;
+ struct notifier_block chrdet_nb;
+ unsigned int usb_mode;
+};
+
+struct usb_role_info {
+ struct mtk_extcon_info *extcon;
+ struct delayed_work dwork;
+ unsigned int d_role; /* desire data role */
+};
+
+enum {
+ DUAL_PROP_DR_HOST = 0,
+ DUAL_PROP_DR_DEVICE,
+ DUAL_PROP_DR_NONE,
+};
+
+static const unsigned int usb_extcon_cable[] = {
+ EXTCON_USB,
+ EXTCON_USB_HOST,
+ EXTCON_NONE,
+};
+
+static const char * const dual_prop_dr_string[] = {
+ "DUAL_PROP_DR_HOST",
+ "DUAL_PROP_DR_DEVICE",
+ "DUAL_PROP_DR_NONE",
+};
+
+enum {
+ OTG_AND_DEVICE = 0,
+ DEVICE_ONLY,
+ OTG_ONLY,
+};
+
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/extcon/mtk-pmic-chrdet.c b/src/kernel/linux/v4.19/drivers/misc/mediatek/extcon/mtk-pmic-chrdet.c
new file mode 100644
index 0000000..b207da4
--- /dev/null
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/extcon/mtk-pmic-chrdet.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/mt6330/registers.h>
+#include <linux/mfd/mt6330/core.h>
+
+#include "chrdet_notifier.h"
+
+SRCU_NOTIFIER_HEAD(chrdet_notifier_list);
+
+#define MT6330_TOPSTATUS_CHRDET_SHIFT 2
+
+struct mtk_pmic_chrdet_regs {
+ u32 status_reg;
+ u32 status_mask;
+ u32 intsel_reg;
+ u32 intsel_mask;
+};
+
+#define MTK_PMIC_CHRDET_REGS(_status_reg, _status_mask, \
+ _intsel_reg, _intsel_mask) \
+{ \
+ .status_reg = _status_reg, \
+ .status_mask = _status_mask, \
+ .intsel_reg = _intsel_reg, \
+ .intsel_mask = _intsel_mask, \
+}
+
+struct mtk_pmic_regs {
+ const struct mtk_pmic_chrdet_regs chrdet_regs;
+};
+
+static const struct mtk_pmic_regs mt6330_regs = {
+ .chrdet_regs =
+ MTK_PMIC_CHRDET_REGS(MT6330_TOPSTATUS, 0x04,
+ MT6330_PSC_TOP_INT_CON0, 0x20),
+};
+
+struct mtk_pmic_chrdet_info {
+ struct mtk_pmic_chrdet *chrdet;
+ const struct mtk_pmic_chrdet_regs *regs;
+ int irq;
+ bool enable;
+ bool wakeup;
+};
+
+struct mtk_pmic_chrdet {
+ struct device *dev;
+ struct regmap *regmap;
+ struct mtk_pmic_chrdet_info info;
+};
+
+int register_chrdet_notifier(struct notifier_block *nb)
+{
+ int ret;
+ struct device *dev;
+ struct platform_device *pdev;
+ struct mtk_pmic_chrdet *chrdet;
+ u32 top_status = 0, detected = 0;
+
+ dev = bus_find_device_by_name(
+ &platform_bus_type, NULL, "mtk-pmic-chrdet");
+ if (!dev) {
+ pr_err("[%s] No pmic chrdet device!\n", __func__);
+ return 0;
+ }
+ pdev = to_platform_device(dev);
+ if (!pdev) {
+ pr_err("[%s] No pmic chrdet platform device!\n", __func__);
+ return 0;
+ }
+ chrdet = platform_get_drvdata(pdev);
+ if (!chrdet) {
+ pr_err("[%s] No chrdet struct\n", __func__);
+ return 0;
+ }
+
+ regmap_read(chrdet->regmap, chrdet->info.regs->status_reg, &top_status);
+ detected = top_status & (1 << MT6330_TOPSTATUS_CHRDET_SHIFT);
+ pr_info("[%s] chrdet = %s using PMIC\n", __func__,
+ detected ? "detected" : "undetected");
+
+ ret = srcu_notifier_chain_register(&chrdet_notifier_list, nb);
+
+ srcu_notifier_call_chain(&chrdet_notifier_list, detected, NULL);
+ return ret;
+}
+EXPORT_SYMBOL(register_chrdet_notifier);
+
+int unregister_chrdet_notifier(struct notifier_block *nb)
+{
+ return srcu_notifier_chain_unregister(&chrdet_notifier_list, nb);
+}
+EXPORT_SYMBOL(unregister_chrdet_notifier);
+
+static irqreturn_t mtk_pmic_chrdet_irq_handler_thread(int irq, void *data)
+{
+ struct mtk_pmic_chrdet_info *info = data;
+ u32 top_status = 0, detected = 0;
+
+ regmap_read(info->chrdet->regmap, info->regs->status_reg, &top_status);
+
+ detected = top_status & (1 << MT6330_TOPSTATUS_CHRDET_SHIFT);
+
+ pr_info("chrdet = %s using PMIC\n",
+ detected ? "detected" : "undetected");
+
+ srcu_notifier_call_chain(&chrdet_notifier_list, detected, NULL);
+
+ return IRQ_HANDLED;
+}
+
+static int mtk_pmic_chrdet_setup(struct mtk_pmic_chrdet *chrdet,
+ struct mtk_pmic_chrdet_info *info)
+{
+ int ret;
+
+ info->chrdet = chrdet;
+
+ ret = regmap_update_bits(chrdet->regmap, info->regs->intsel_reg,
+ info->regs->intsel_mask,
+ info->regs->intsel_mask);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_request_threaded_irq(chrdet->dev, info->irq, NULL,
+ mtk_pmic_chrdet_irq_handler_thread,
+ IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
+ "mtk-pmic-chrdet", info);
+ if (ret) {
+ pr_err("Failed to request IRQ: %d: %d\n",
+ info->irq, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __maybe_unused mtk_pmic_chrdet_suspend(struct device *dev)
+{
+ struct mtk_pmic_chrdet *chrdet = dev_get_drvdata(dev);
+
+ if (chrdet->info.wakeup)
+ enable_irq_wake(chrdet->info.irq);
+
+ return 0;
+}
+
+static int __maybe_unused mtk_pmic_chrdet_resume(struct device *dev)
+{
+ struct mtk_pmic_chrdet *chrdet = dev_get_drvdata(dev);
+
+ if (chrdet->info.wakeup)
+ disable_irq_wake(chrdet->info.irq);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(mtk_pmic_chrdet_pm_ops, mtk_pmic_chrdet_suspend,
+ mtk_pmic_chrdet_resume);
+
+static const struct of_device_id of_mtk_pmic_chrdet_match_tbl[] = {
+ {
+ .compatible = "mediatek,mt6330-chrdet",
+ .data = &mt6330_regs,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, of_mtk_pmic_chrdet_match_tbl);
+
+static int mtk_pmic_chrdet_probe(struct platform_device *pdev)
+{
+ int error, index = 0;
+ struct mt6330_chip *pmic_chip = dev_get_drvdata(pdev->dev.parent);
+ struct device_node *node = pdev->dev.of_node, *child;
+ struct mtk_pmic_chrdet *chrdet;
+ const struct mtk_pmic_regs *mtk_pmic_regs;
+ const struct of_device_id *of_id =
+ of_match_device(of_mtk_pmic_chrdet_match_tbl, &pdev->dev);
+
+ pr_info("%s\n", __func__);
+
+ if (!of_id)
+ return -ENOMEM;
+
+ chrdet = devm_kzalloc(&pdev->dev, sizeof(*chrdet), GFP_KERNEL);
+ if (!chrdet)
+ return -ENOMEM;
+
+ chrdet->dev = &pdev->dev;
+ chrdet->regmap = pmic_chip->regmap;
+ mtk_pmic_regs = of_id->data;
+
+ for_each_child_of_node(node, child) {
+ chrdet->info.regs = &mtk_pmic_regs->chrdet_regs;
+
+ chrdet->info.irq = platform_get_irq(pdev, index);
+ if (chrdet->info.irq < 0)
+ return chrdet->info.irq;
+
+ if (of_property_read_bool(child, "enable")) {
+ pr_info("chrdet enabled\n");
+ chrdet->info.enable = true;
+
+ if (of_property_read_bool(child, "wakeup-source"))
+ chrdet->info.wakeup = true;
+
+ error = mtk_pmic_chrdet_setup(chrdet, &chrdet->info);
+ if (error) {
+ pr_err("Set chrdet error(%d).\n", error);
+ return error;
+ }
+ } else {
+ pr_info("chrdet disabled\n");
+ }
+ }
+
+ platform_set_drvdata(pdev, chrdet);
+
+ return 0;
+}
+
+static struct platform_driver pmic_chrdet_pdrv = {
+ .probe = mtk_pmic_chrdet_probe,
+ .driver = {
+ .name = "mtk-pmic-chrdet",
+ .of_match_table = of_mtk_pmic_chrdet_match_tbl,
+ .pm = &mtk_pmic_chrdet_pm_ops,
+ },
+};
+
+module_platform_driver(pmic_chrdet_pdrv);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jericho Lee <jericho.lee@mediatek.com>");
+MODULE_DESCRIPTION("MTK pmic-chrdet driver v0.1");
diff --git a/src/multimedia/audio-misc/libmodem-afe-ctrl/LICENSE b/src/multimedia/audio-misc/libmodem-afe-ctrl/LICENSE
new file mode 100644
index 0000000..77f59ed
--- /dev/null
+++ b/src/multimedia/audio-misc/libmodem-afe-ctrl/LICENSE
@@ -0,0 +1,31 @@
+Copyright Statement:
+
+This software/firmware and related documentation ("MediaTek Software") are
+protected under relevant copyright laws. The information contained herein is
+confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+the prior written permission of MediaTek inc. and/or its licensors, any
+reproduction, modification, use or disclosure of MediaTek Software, and
+information contained herein, in whole or in part, shall be strictly
+prohibited.
+
+MediaTek Inc. (C) 2015. All rights reserved.
+
+BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
diff --git a/src/multimedia/audio-misc/libmodem-afe-ctrl/Makefile b/src/multimedia/audio-misc/libmodem-afe-ctrl/Makefile
new file mode 100644
index 0000000..670173d
--- /dev/null
+++ b/src/multimedia/audio-misc/libmodem-afe-ctrl/Makefile
@@ -0,0 +1,34 @@
+#SPDX-License-Identifier: MediaTekProprietary
+$(warning !!!!! target platform=$(TARGET_PLATFORM) !!!!!)
+ifeq ($(strip $(TARGET_PLATFORM)), )
+ DIR_MAKEFILE = mt2635
+else
+ DIR_MAKEFILE = $(TARGET_PLATFORM)
+endif
+
+build:
+ $(warning ########## build libmodem ##########)
+ for i in $(DIR_MAKEFILE); do \
+ (cd $$i && make); \
+ if [ $$? != 0 ]; then \
+ exit 1; \
+ fi \
+ done
+
+install:
+ $(warning ########## install libmodem ##########)
+ for i in $(DIR_MAKEFILE); do \
+ (cd $$i && make install); \
+ if [ $$? != 0 ]; then \
+ exit 1; \
+ fi \
+ done
+
+clean:
+ for i in $(DIR_MAKEFILE); do \
+ (cd $$i && make clean); \
+ if [ $$? != 0 ]; then \
+ exit 1; \
+ fi \
+ done
+
diff --git a/src/multimedia/audio-misc/libmodem-afe-ctrl/mt2735/LICENSE b/src/multimedia/audio-misc/libmodem-afe-ctrl/mt2735/LICENSE
new file mode 100644
index 0000000..77f59ed
--- /dev/null
+++ b/src/multimedia/audio-misc/libmodem-afe-ctrl/mt2735/LICENSE
@@ -0,0 +1,31 @@
+Copyright Statement:
+
+This software/firmware and related documentation ("MediaTek Software") are
+protected under relevant copyright laws. The information contained herein is
+confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+the prior written permission of MediaTek inc. and/or its licensors, any
+reproduction, modification, use or disclosure of MediaTek Software, and
+information contained herein, in whole or in part, shall be strictly
+prohibited.
+
+MediaTek Inc. (C) 2015. All rights reserved.
+
+BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
diff --git a/src/multimedia/audio-misc/libmodem-afe-ctrl/mt2735/Makefile b/src/multimedia/audio-misc/libmodem-afe-ctrl/mt2735/Makefile
new file mode 100644
index 0000000..423882f
--- /dev/null
+++ b/src/multimedia/audio-misc/libmodem-afe-ctrl/mt2735/Makefile
@@ -0,0 +1,43 @@
+#SPDX-License-Identifier: MediaTekProprietary
+PREFIX = ../install
+NAME = modemafectrl
+COMPILER = GNU
+CROSS = arm-linux-
+CROSS_SUP= arm-linux- arm-none-eabi- aarch64-linux-
+GCC = $(CROSS)gcc
+CC = $(GCC)
+CXX = $(CROSS)g++
+OBJDUMP = $(CROSS)objdump
+OBJCOPY = $(CROSS)objcopy
+AR = $(CROSS)ar
+
+OFLAGS ?= -g -O0 -fPIC -Wno-missing-braces
+
+ifeq ($(strip $(CROSS)), arm-linux-)
+ CFLAGS = -mthumb-interwork
+endif
+
+INIT = syss_init
+LDFLAGS = $(BB_LDFLAGS_ADD) -Wl,--hash-style=gnu -L. -L $(ROOT)/lib
+LOCAL_PATH = .
+
+
+all: libmodemafectrl.so
+
+INCLUDE = -Iinclude
+
+libmodemafectrl.so: pcm_ctrl.o
+ $(CC) $(OFLAGS) $(INCLUDE) ${LDFLAGS} -lasound -lmtk_audio_mixer_ctrl -shared -o $@ pcm_ctrl.o
+
+pcm_ctrl.o: include/
+ $(CC) $(OFLAGS) $(INCLUDE) ${CFLAGS} -c src/pcm_ctrl.c -o $@
+
+install:
+ mkdir -p ../include
+ cp -af include/* ../include/
+
+ mkdir -p $(ROOT)/${base_libdir}/
+ cp lib$(NAME).so $(ROOT)/${base_libdir}/
+
+clean:
+ rm -f libmodemafectrl.so
diff --git a/src/multimedia/audio-misc/libmodem-afe-ctrl/mt2735/include/dev_string.h b/src/multimedia/audio-misc/libmodem-afe-ctrl/mt2735/include/dev_string.h
new file mode 100644
index 0000000..d3541a3
--- /dev/null
+++ b/src/multimedia/audio-misc/libmodem-afe-ctrl/mt2735/include/dev_string.h
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef _DEV_STRING_H_
+#define _DEV_STRING_H_
+
+/* modem device name*/
+#define MODEM_DEV_NAME "hw:0,18" //"hw:0,15"
+#define MODEM_BT_DEV_NAME "hw:0,18"
+
+#endif
diff --git a/src/multimedia/audio-misc/libmodem-afe-ctrl/mt2735/include/modem_afe_ctrl.h b/src/multimedia/audio-misc/libmodem-afe-ctrl/mt2735/include/modem_afe_ctrl.h
new file mode 100644
index 0000000..f67a164
--- /dev/null
+++ b/src/multimedia/audio-misc/libmodem-afe-ctrl/mt2735/include/modem_afe_ctrl.h
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+Copyright Statement:
+
+This software/firmware and related documentation ("MediaTek Software") are
+protected under relevant copyright laws. The information contained herein is
+confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+the prior written permission of MediaTek inc. and/or its licensors, any
+reproduction, modification, use or disclosure of MediaTek Software, and
+information contained herein, in whole or in part, shall be strictly
+prohibited.
+
+MediaTek Inc. (C) 2016. All rights reserved.
+
+BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+
+Auther: Garlic Tseng <garlic.tseng@mediatek.com>
+*/
+
+/*
+usage:
+1. call get_default_device to get the system default phonecall device
+2. call enable_phone_call_AFE_path when phone call is enabled
+ (may or may not use default device)
+3. call disable_phone_call_AFE_path when phone call is disabled
+*/
+
+#ifndef _MODEM_ALSA_LIB_H_
+#define _MODEM_ALSA_LIB_H_
+
+typedef enum {
+ DEV_SPK,
+ DEV_SPK_EX,
+ DEV_DIRECT,
+ DEV_DIRECT_LO,
+ DEV_HP,
+ DEV_BT,
+ DEV_DEFAULT,
+ DEV_NUM = DEV_DEFAULT,
+ DEV_INVALID = -1,
+} Audio_device;
+
+/***********************************************
+ * The API below will make request to server. *
+ ***********************************************/
+
+//enable audio path for modem.
+//return value: 0 if success, or negitive error number
+int enable_phone_call_AFE_path(int audio_device);
+
+//close audio path for modem
+//return value: 0 if success, or negitive error number
+int disable_phone_call_AFE_path(void);
+
+//get default device.
+//return value: default device setting
+int get_default_device(void);
+
+//set UL analog gain
+//return value: 0 if success, or negitive error number
+int set_UL_analog_gain(int dB);
+
+//set DL analog gain
+//return value: 0 if success, or negitive error number
+int set_DL_analog_gain(int dB);
+
+//set BT WB on
+//return value: 0 if success, or negitive error number
+int set_BT_WB(int on);
+
+//change device when the phone call is enabled
+//return value: 0 if success, or negitive error number
+int dynamic_switch_phone_call_path(int audio_device);
+
+//set phonecall sample rate
+//return value: 0 if success, or negitive error number
+int set_phonecall_rate(int rate);
+
+
+/***********************************************
+ * IPC define. *
+ ***********************************************/
+
+#define FUNC_ENABLE_PHONE_CALL_AFE_PATH 0
+#define FUNC_DISABLE_PHONE_CALL_AFE_PATH 1
+#define FUNC_GET_DEFAULT_VALUE 2
+#define FUNC_SET_UL_ANALOG_GAIN 3
+#define FUNC_SET_DL_ANALOG_GAIN 4
+#define FUNC_SET_BT_WB 5
+#define FUNC_DYNAMIC_SWITCH_PHONE_CALL_PATH 6
+#define FUNC_SET_PHONE_CALL_SAMPLERATE 7
+
+/***********************************************
+ * default parameter *
+ ***********************************************/
+
+#define FUNC_SET_BT_WB_default 0 //default off
+
+/******************************************************************************
+ * The API below is for service to call. Please use API defined above if you *
+ * are not service. *
+ ******************************************************************************/
+int set_BT_wb(int on);
+int set_phonecall_rate_for_service(int rate);
+
+//enable audio path for modem.
+//return value: 0 if success, or negitive error number
+int enable_phone_call_AFE_path_for_service(int audio_device);
+
+//close audio path for modem
+//return value: 0 if success, or negitive error number
+int disable_phone_call_AFE_path_for_service(void);
+
+//get default device.
+//return value: default device setting
+int get_default_device_for_service(void);
+
+//set UL analog gain
+int set_UL_analog_gain_for_service(int dB);
+
+//set DL analog gain
+int set_DL_analog_gain_for_service(int dB);
+
+//change device when the phone call is enabled
+int dynamic_switch_phone_call_path_for_service(int audio_device);
+
+#endif //_MODEM_ALSA_LIB_H_
+
diff --git a/src/multimedia/audio-misc/libmodem-afe-ctrl/mt2735/src/pcm_ctrl.c b/src/multimedia/audio-misc/libmodem-afe-ctrl/mt2735/src/pcm_ctrl.c
new file mode 100644
index 0000000..cedf569
--- /dev/null
+++ b/src/multimedia/audio-misc/libmodem-afe-ctrl/mt2735/src/pcm_ctrl.c
@@ -0,0 +1,1053 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+Copyright Statement:
+
+This software/firmware and related documentation ("MediaTek Software") are
+protected under relevant copyright laws. The information contained herein is
+confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+the prior written permission of MediaTek inc. and/or its licensors, any
+reproduction, modification, use or disclosure of MediaTek Software, and
+information contained herein, in whole or in part, shall be strictly
+prohibited.
+
+MediaTek Inc. (C) 2016. All rights reserved.
+
+BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+
+Auther: Garlic Tseng <garlic.tseng@mediatek.com>
+*/
+#include <pthread.h>
+#include <error.h>
+#include <signal.h>
+#include <stdio.h>
+#include <alsa/asoundlib.h>
+#include <semaphore.h>
+#include "modem_afe_ctrl.h"
+#include "mixer_ctrl.h"
+#include "dev_string.h"
+
+#include <syslog.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "phonecall_pcm"
+
+#define STR_SIZE 128
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+//#define USE_MIC_0
+
+static int g_device = DEV_DEFAULT;
+static int g_afe_enabled;
+
+/* prevent disable when enable (or vice versa) */
+static pthread_mutex_t g_afe_enabled_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static snd_pcm_t *g_pcm_playback_handle;
+static snd_pcm_t *g_pcm_capture_handle;
+
+static snd_pcm_t *g_pcm_playback_handle_bt;
+
+static int do_enable_AFE_l(void);
+static int do_disable_AFE_l(void);
+
+static int open_start_pcm(void);
+static void close_pcm(void);
+
+static int open_start_bt_pcm(void);
+static void close_bt_pcm(void);
+
+static void store_AFE_original_setting();
+static void restore_AFE_original_setting();
+
+static void do_AFE_open_sequence(int dev);
+static void do_AFE_close_sequence(int dev);
+static void do_bt_open_sequence(void);
+static void do_bt_close_sequence(void);
+static void do_internal_codec_open_sequence(int dev);
+static void do_internal_codec_close_sequence(int dev);
+static void do_ext_codec_open_sequence(int dev);
+static void do_ext_codec_close_sequence(int dev);
+static int is_using_internal_codec(void);
+
+static int do_IPC_call(const char* cmd);
+
+
+typedef enum {
+ MixerName,
+ MixerValue,
+ MixerPairSize,
+} MixerCtrlPair;
+
+typedef char Mixer_pair[MixerPairSize][STR_SIZE];
+typedef char String[STR_SIZE];
+
+/*now we fix playback & record to hs.*/
+/*will remove the constrain after codec reflection finish.*/
+static const String MIXER_BACKUP_LIST_NAME[] = {
+ "I2S0_HD_Mux",
+ "I2S3_HD_Mux",
+ "I2S3_Out_Mux",
+ "OUT1 MUX",
+ "AIN MUX",
+};
+
+static int MIXER_BACKUP_LIST_VALUE[ARRAY_SIZE(MIXER_BACKUP_LIST_NAME)];
+
+static const String INTERCONN_BACKUP_LIST_NAME[] = {
+ /*{mixer name, option name}*/
+ "PCM_2_PB_CH1 I2S0_CH1",
+ "I2S3_CH1 PCM_2_CAP_CH1",
+ "I2S3_CH2 PCM_2_CAP_CH2",
+ "I2S3_CH1 DL1_CH1",
+ "I2S3_CH2 DL1_CH2",
+ "UL2_CH1 I2S0_CH1",
+ "UL2_CH2 I2S0_CH2",
+};
+
+static int INTERCONN_BACKUP_LIST_VALUE[ARRAY_SIZE(INTERCONN_BACKUP_LIST_NAME)];
+
+static const Mixer_pair SPK_ENABLE_SEQ[] = {
+ /*{mixer name, option name}*/
+ {"I2S0_HD_Mux", "Low_Jitter"},
+ {"I2S3_HD_Mux", "Low_Jitter"},
+ {"I2S3_Out_Mux", "Output_Widget"},
+ {"OUT1 MUX", "DAC"},
+ {"Lineout Type", "Differential"},
+ {"BICK Frequency", "32fs"},
+ {"ADC Input Type", "Single-end"},
+ {"AIN MUX", "AIN1"},
+};
+
+static const Mixer_pair HP_ENABLE_SEQ[] = {
+ /*{mixer name, option name}*/
+ {"ETDM_HD_Mux", "Normal"},
+ {"ETDM_PCM1_MUX", "PCM"},
+};
+
+static const Mixer_pair DIRECT_ENABLE_SEQ[] = {
+ /*{mixer name, option name}*/
+ {"ETDM_HD_Mux", "Normal"},
+ {"ETDM_PCM1_MUX", "PCM"},
+};
+
+static const Mixer_pair DIRECT_LO_ENABLE_SEQ[] = {
+ {"ETDM_HD_Mux", "Normal"},
+ {"ETDM_PCM1_MUX", "PCM"},
+};
+
+//TBD
+static const Mixer_pair BT_ENABLE_SEQ[] = {
+ /*{mixer name, option name}*/
+ {"ETDM_HD_Mux", "Normal"},
+};
+
+static const Mixer_pair SPK_DISABLE_SEQ[] = {
+ /*{mixer name, option name}*/
+ {"I2S3_HD_Mux", "Normal"},
+ {"I2S0_HD_Mux", "Normal"},
+ {"I2S3_Out_Mux", "Normal"},
+ {"OUT1 MUX", "VCOM"},
+ {"Lineout Type", "Single-end"},
+};
+
+static const Mixer_pair HP_DISABLE_SEQ[] = {
+ /*{mixer name, option name}*/
+ {"ETDM_HD_Mux", "Normal"},
+ {"ETDM_PCM1_MUX", "PCM"},
+};
+
+static const Mixer_pair DIRECT_DISABLE_SEQ[] = {
+ /*{mixer name, option name}*/
+ {"ETDM_HD_Mux", "Normal"},
+ {"ETDM_PCM1_MUX", "PCM"},
+};
+
+static const Mixer_pair DIRECT_LO_DISABLE_SEQ[] = {
+ /*{mixer name, option name}*/
+ {"ETDM_HD_Mux", "Normal"},
+ {"ETDM_PCM1_MUX", "PCM"},
+};
+
+//TBD
+static const Mixer_pair BT_DISABLE_SEQ[] = {
+ /*{mixer name, option name}*/
+ {"ETDM_HD_Mux", "Normal"},
+};
+
+static const Mixer_pair INT_CODEC_INTERCONN_SEQ[] = {
+ /*{mixer name, option name}*/
+ {"PCM_2_PB_CH1 I2S0_CH1", "1"},
+ {"I2S3_CH1 PCM_2_CAP_CH1", "1"},
+ {"I2S3_CH2 PCM_2_CAP_CH1", "1"},
+};
+
+
+static const Mixer_pair BT_INTERCONN_SEQ[] = {
+ /*{mixer name, option name}*/
+};
+
+/*external codec seq, should modify if new codec applied*/
+static const Mixer_pair EXT_CODEC_ENABLE_SEQ[] = {
+ /*{mixer name, option name}*/
+ {"ETDM_PCM1_MUX", "PCM"},
+};
+
+static const Mixer_pair EXT_CODEC_DISABLE_SEQ[] = {
+ /*{mixer name, option name}*/
+ {"ETDM_HD_Mux", "Normal"},
+ {"ETDM_PCM1_MUX", "PCM"},
+};
+
+static const Mixer_pair EXT_CODEC_INTERCONN_SEQ[] = {
+ /*{mixer name, option name}*/
+ {"Ext_Speaker_Amp", "1"},
+ {"ETDM_PB_CH1 DL1_CH1", "1"},
+ {"ETDM_PB_CH1 DL1_CH2", "1"},
+ {"UL1_CH1 ETDM_CAP_CH1", "1"},
+ {"UL1_CH2 ETDM_CAP_CH1", "1"},
+};
+
+/*external codec seq end*/
+
+/* for BT WB */
+static pthread_mutex_t g_BT_WB_on_lock = PTHREAD_MUTEX_INITIALIZER;
+static int g_BT_WB_on = FUNC_SET_BT_WB_default;
+int set_BT_wb(int on){
+ pthread_mutex_lock(&g_BT_WB_on_lock);
+ g_BT_WB_on = !!on;
+ pthread_mutex_unlock(&g_BT_WB_on_lock);
+ return 0;
+}
+/* for BT WB end*/
+
+static int phonecall_rate = 16000;
+
+int set_phonecall_rate_for_service(int rate)
+{
+ phonecall_rate = rate;
+ return 0;
+}
+
+int enable_phone_call_AFE_path_for_service(int audio_device)
+{
+ int ret;
+
+ pthread_mutex_lock(&g_afe_enabled_lock);
+ if (g_afe_enabled) {
+ printf("%s, modem path already opened.\n", __func__);
+ pthread_mutex_unlock(&g_afe_enabled_lock);
+ return -EBUSY;
+ }
+ printf("%s.YR\n", __func__);
+
+ g_device = audio_device;
+ if (audio_device == DEV_DEFAULT)
+ g_device = get_default_device_for_service();
+
+ ret = do_enable_AFE_l();
+
+ if (ret)
+ printf("%s, pthread_create failed: %d\n", __func__, ret);
+
+ pthread_mutex_unlock(&g_afe_enabled_lock);
+
+ return ret;
+}
+
+int disable_phone_call_AFE_path_for_service(void)
+{
+ int ret;
+
+ pthread_mutex_lock(&g_afe_enabled_lock);
+ if (!g_afe_enabled) {
+ printf("%s, modem path not opened.\n", __func__);
+ pthread_mutex_unlock(&g_afe_enabled_lock);
+ return 0;
+ }
+
+ ret = do_disable_AFE_l();
+ if (ret)
+ printf("%s, do_disable_AFE_l failed: %d\n", __func__, ret);
+
+ pthread_mutex_unlock(&g_afe_enabled_lock);
+ return ret;
+}
+
+/*do enable sequence, need lock outside*/
+static int do_enable_AFE_l(void)
+{
+ int device;
+ int ret;
+
+ device = g_device;
+ do_AFE_open_sequence(device);
+ //ret = open_start_pcm(); //Garlic!!! tmp test BT
+ if (device != DEV_BT)
+ ret = open_start_pcm();
+ else
+ ret = open_start_bt_pcm();
+ if (ret) {
+ printf("%s, open_start_pcm failed: %d\n", __func__, ret);
+ close_pcm();
+ return ret;
+ }
+
+ g_afe_enabled = 1;
+
+ return 0;
+}
+
+/*do disable sequence, need lock outside*/
+static int do_disable_AFE_l(void){
+ int device;
+ device = g_device;
+
+ g_afe_enabled = 0;
+ //close_pcm(); //Garlic!!! tmp test BT
+ if (device != DEV_BT)
+ close_pcm();
+ else
+ close_bt_pcm();
+
+ do_AFE_close_sequence(device);
+ return 0;
+}
+
+int get_default_device_for_service(void)
+{
+ int mix_value;
+
+ mix_value = get_mixer_ctrl_interconn_value("Ext_Speaker_Amp");
+
+ printf("%s, mix_value %d\n", __func__, mix_value);
+
+ if (mix_value==1)
+ return DEV_SPK;
+ else if (mix_value < 0)
+ printf("get_mixer_ctrl_value_int for LOL Mux error!\n");
+
+ /* TODO: add BT device support */
+ printf("no available device, use spk for default\n");
+ return DEV_SPK;
+}
+
+static int open_start_pcm(void)
+{
+ int ret = 0;
+ snd_pcm_hw_params_t *hw_params = NULL;
+ snd_pcm_hw_params_t *hw_params_c = NULL;
+
+ /*pcm interface create*/
+ if ((ret = snd_pcm_open(&g_pcm_playback_handle, MODEM_DEV_NAME,
+ SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
+ printf ("cannot open audio device %s (%s)\n",
+ MODEM_DEV_NAME, snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_open(&g_pcm_capture_handle, MODEM_DEV_NAME,
+ SND_PCM_STREAM_CAPTURE, 0)) < 0) {
+ printf ("cannot open audio device %s (%s)\n",
+ MODEM_DEV_NAME, snd_strerror(ret));
+ return ret;
+ }
+
+ snd_pcm_hw_params_alloca(&hw_params);
+ if (hw_params == NULL) {
+ printf ("cannot allocate hardware parameter structure (%s)\n",
+ snd_strerror(ret));
+ return ret;
+ }
+
+ snd_pcm_hw_params_alloca(&hw_params_c);
+ if (hw_params_c == NULL) {
+ printf ("cannot allocate hardware parameter structure (%s)\n",
+ snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params_any(g_pcm_playback_handle, hw_params)) < 0) {
+ printf ("cannot initialize hardware parameter structure (%s)\n",
+ snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params_any(g_pcm_capture_handle, hw_params_c)) < 0) {
+ printf ("cannot initialize hardware parameter structure (%s)\n",
+ snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params_set_access(g_pcm_playback_handle, hw_params,
+ SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
+ printf ("cannot set access type (%s)\n", snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params_set_access(g_pcm_capture_handle, hw_params_c,
+ SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
+ printf ("cannot set access type (%s)\n", snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params_set_format(g_pcm_playback_handle, hw_params,
+ SND_PCM_FORMAT_S16_LE)) < 0) {
+ printf ("cannot set sample format (%s)\n", snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params_set_format(g_pcm_capture_handle, hw_params_c,
+ SND_PCM_FORMAT_S16_LE)) < 0) {
+ printf ("cannot set sample format (%s)\n", snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params_set_rate(g_pcm_playback_handle, hw_params, phonecall_rate, 0)) < 0) {
+ printf ("cannot set sample rate (%s)\n", snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params_set_rate(g_pcm_capture_handle, hw_params_c, phonecall_rate, 0)) < 0) {
+ printf ("cannot set sample rate (%s)\n", snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params_set_channels(g_pcm_playback_handle, hw_params, 2)) < 0) {
+ printf ("cannot set channel count (%s)\n", snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params_set_channels(g_pcm_capture_handle, hw_params_c, 2)) < 0) {
+ printf ("cannot set channel count (%s)\n", snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params (g_pcm_playback_handle, hw_params)) < 0) {
+ printf ("cannot set parameters(%s)\n", snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params (g_pcm_capture_handle, hw_params_c)) < 0) {
+ printf ("cannot set parameters(%s)\n", snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_prepare(g_pcm_playback_handle)) < 0) {
+ printf ("cannot prepare audio interface for use (%s)\n",
+ snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_prepare(g_pcm_capture_handle)) < 0) {
+ printf ("cannot prepare audio interface for use (%s)\n",
+ snd_strerror(ret));
+ return ret;
+ }
+
+ snd_pcm_start(g_pcm_playback_handle);
+ snd_pcm_start(g_pcm_capture_handle);
+
+ return ret;
+}
+
+
+static int open_start_bt_pcm(void)
+{
+ int ret;
+ snd_pcm_hw_params_t *hw_params = NULL;
+
+ pthread_mutex_lock(&g_BT_WB_on_lock);
+ /*pcm interface create*/
+ if ((ret = snd_pcm_open(&g_pcm_playback_handle_bt, MODEM_BT_DEV_NAME,
+ SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
+ printf ("cannot open audio device %s (%s)\n",
+ MODEM_BT_DEV_NAME, snd_strerror(ret));
+ return ret;
+ }
+
+ snd_pcm_hw_params_alloca(&hw_params);
+ if (hw_params == NULL) {
+ printf ("cannot allocate hardware parameter structure (%s)\n",
+ snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params_any(g_pcm_playback_handle_bt, hw_params)) < 0) {
+ printf ("cannot initialize hardware parameter structure (%s)\n",
+ snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params_set_access(g_pcm_playback_handle_bt, hw_params,
+ SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
+ printf ("cannot set access type (%s)\n", snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params_set_format(g_pcm_playback_handle_bt, hw_params,
+ SND_PCM_FORMAT_S16_LE)) < 0) {
+ printf ("cannot set sample format (%s)\n", snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params_set_rate(g_pcm_playback_handle_bt,
+ hw_params,
+ g_BT_WB_on? 16000: 8000, 0)) < 0) {
+ printf ("cannot set sample rate (%s)\n", snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params_set_channels(g_pcm_playback_handle_bt, hw_params, 1)) < 0) {
+ printf ("cannot set channel count (%s)\n", snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_hw_params (g_pcm_playback_handle_bt, hw_params)) < 0) {
+ printf ("cannot set parameters(%s)\n", snd_strerror(ret));
+ return ret;
+ }
+
+ if ((ret = snd_pcm_prepare(g_pcm_playback_handle_bt)) < 0) {
+ printf ("cannot prepare audio interface for use (%s)\n",
+ snd_strerror(ret));
+ return ret;
+ }
+
+ snd_pcm_start(g_pcm_playback_handle_bt);
+ pthread_mutex_unlock(&g_BT_WB_on_lock);
+
+ return ret;
+}
+
+
+static void close_pcm(void)
+{
+ if (g_pcm_playback_handle != NULL) {
+ snd_pcm_close(g_pcm_playback_handle);
+ g_pcm_playback_handle = NULL;
+ }
+ if (g_pcm_capture_handle != NULL) {
+ snd_pcm_close(g_pcm_capture_handle);
+ g_pcm_capture_handle = NULL;
+ }
+}
+
+static void close_bt_pcm(void)
+{
+ if (g_pcm_playback_handle_bt != NULL) {
+ snd_pcm_close(g_pcm_playback_handle_bt);
+ g_pcm_playback_handle_bt = NULL;
+ }
+}
+
+static void store_AFE_original_setting()
+{
+ int i;
+
+ for(i = 0;i < ARRAY_SIZE(INTERCONN_BACKUP_LIST_NAME); i++)
+ INTERCONN_BACKUP_LIST_VALUE[i] =
+ get_mixer_ctrl_interconn_value(INTERCONN_BACKUP_LIST_NAME[i]);
+
+ for(i = 0;i < ARRAY_SIZE(MIXER_BACKUP_LIST_NAME); i++)
+ MIXER_BACKUP_LIST_VALUE[i] =
+ get_mixer_ctrl_value_int(MIXER_BACKUP_LIST_NAME[i]);
+}
+
+
+
+static void restore_AFE_original_setting()
+{
+ int i, ret;
+ int device;
+
+ for(i = 0;i < ARRAY_SIZE(MIXER_BACKUP_LIST_NAME); i++) {
+ ret = set_mixer_ctrl_value_int(MIXER_BACKUP_LIST_NAME[i],
+ MIXER_BACKUP_LIST_VALUE[i]);
+ if(ret)
+ printf("%s, restore_AFE_original_setting error %d, %s, %d\n",
+ __func__, ret,
+ MIXER_BACKUP_LIST_NAME[i],
+ MIXER_BACKUP_LIST_VALUE[i]);
+ }
+
+ for(i = 0;i < ARRAY_SIZE(INTERCONN_BACKUP_LIST_NAME); i++) {
+ ret = set_mixer_ctrl_interconn_value(INTERCONN_BACKUP_LIST_NAME[i],
+ INTERCONN_BACKUP_LIST_VALUE[i]);
+ if(ret)
+ printf("%s, restore_AFE_original_setting error %d, %s, %d\n",
+ __func__, ret,
+ INTERCONN_BACKUP_LIST_NAME[i],
+ INTERCONN_BACKUP_LIST_VALUE[i]);
+ }
+}
+
+static void do_AFE_open_sequence(int dev)
+{
+ printf("YR %s, dev: %d\n", __func__, dev);
+
+ if (dev == DEV_BT) {
+ do_bt_open_sequence();
+ } else if (is_using_internal_codec()) {
+ store_AFE_original_setting();
+ do_internal_codec_open_sequence(dev);
+ } else {
+ do_ext_codec_open_sequence(dev);
+ }
+}
+
+static void do_AFE_close_sequence(int dev)
+{
+ if (dev == DEV_BT) {
+ do_bt_close_sequence();
+ } else if (is_using_internal_codec()) {
+ do_internal_codec_close_sequence(dev);
+ restore_AFE_original_setting();
+ } else {
+ do_ext_codec_close_sequence(dev);
+ }
+}
+
+static void do_bt_open_sequence(void)
+{
+ int i, ret;
+
+ for(i = 0;i < ARRAY_SIZE(BT_ENABLE_SEQ); i++){
+ ret = set_mixer_ctrl_value_string(BT_ENABLE_SEQ[i][MixerName],
+ BT_ENABLE_SEQ[i][MixerValue]);
+ if(ret)
+ printf("%s, set_mixer_ctrl_value_string error %d, %s, %s\n",
+ __func__, ret,
+ BT_ENABLE_SEQ[i][MixerName],
+ BT_ENABLE_SEQ[i][MixerValue]);
+ }
+
+ for(i = 0;i < ARRAY_SIZE(BT_INTERCONN_SEQ); i++){
+ ret = set_mixer_ctrl_interconn_value(BT_INTERCONN_SEQ[i][MixerName],
+ atoi(BT_INTERCONN_SEQ[i][MixerValue]));
+ if(ret)
+ printf("%s, set_mixer_ctrl_interconn_value error %d, %s, %s\n",
+ __func__, ret,
+ BT_INTERCONN_SEQ[i][MixerName],
+ BT_INTERCONN_SEQ[i][MixerValue]);
+ }
+}
+
+static void do_bt_close_sequence(void)
+{
+ int i, ret;
+
+ for(i = 0;i < ARRAY_SIZE(BT_INTERCONN_SEQ); i++){
+ ret = set_mixer_ctrl_interconn_value(BT_INTERCONN_SEQ[i][MixerName], 0);
+ if(ret)
+ printf("%s, set_mixer_ctrl_interconn_value error %d, %s, 0\n",
+ __func__, ret,
+ BT_INTERCONN_SEQ[i][MixerName]);
+ }
+
+ for(i = 0;i < ARRAY_SIZE(BT_DISABLE_SEQ); i++){
+ ret = set_mixer_ctrl_value_string(BT_DISABLE_SEQ[i][MixerName],
+ BT_DISABLE_SEQ[i][MixerValue]);
+ if(ret)
+ printf("%s, set_mixer_ctrl_value_string error %d, %s, %s\n",
+ __func__, ret,
+ BT_DISABLE_SEQ[i][MixerName],
+ BT_DISABLE_SEQ[i][MixerValue]);
+ }
+}
+
+static void do_internal_codec_open_sequence(int dev)
+{
+ int i, ret;
+ printf("YR %s, dev: %d\n", __func__, dev);
+
+ /*TODO: make it simpler*/
+ switch(dev) {
+ case DEV_SPK:
+ for(i = 0;i < ARRAY_SIZE(SPK_ENABLE_SEQ); i++){
+ ret = set_mixer_ctrl_value_string(SPK_ENABLE_SEQ[i][MixerName],
+ SPK_ENABLE_SEQ[i][MixerValue]);
+ //if(ret)
+ printf("%s,YR set_mixer_ctrl_value_string error %d, %s, %s\n",
+ __func__, ret,
+ SPK_ENABLE_SEQ[i][MixerName],
+ SPK_ENABLE_SEQ[i][MixerValue]);
+ }
+
+ for(i = 0;i < ARRAY_SIZE(INT_CODEC_INTERCONN_SEQ); i++){
+ ret = set_mixer_ctrl_interconn_value(INT_CODEC_INTERCONN_SEQ[i][MixerName],
+ atoi(INT_CODEC_INTERCONN_SEQ[i][MixerValue]));
+ //if(ret)
+ printf("%s,YR set_mixer_ctrl_interconn_value error %d, %s, %s\n",
+ __func__, ret,
+ INT_CODEC_INTERCONN_SEQ[i][MixerName],
+ INT_CODEC_INTERCONN_SEQ[i][MixerValue]);
+ }
+ break;
+ case DEV_HP:
+ for(i = 0;i < ARRAY_SIZE(HP_ENABLE_SEQ); i++){
+ ret = set_mixer_ctrl_value_string(HP_ENABLE_SEQ[i][MixerName],
+ HP_ENABLE_SEQ[i][MixerValue]);
+ if(ret)
+ printf("%s, set_mixer_ctrl_value_string error %d, %s, %s\n",
+ __func__, ret,
+ HP_ENABLE_SEQ[i][MixerName],
+ HP_ENABLE_SEQ[i][MixerValue]);
+ }
+ break;
+ case DEV_DIRECT:
+ for(i = 0;i < ARRAY_SIZE(DIRECT_ENABLE_SEQ); i++){
+ ret = set_mixer_ctrl_value_string(DIRECT_ENABLE_SEQ[i][MixerName],
+ DIRECT_ENABLE_SEQ[i][MixerValue]);
+ if(ret)
+ printf("%s, set_mixer_ctrl_value_string error %d, %s, %s\n",
+ __func__, ret,
+ DIRECT_ENABLE_SEQ[i][MixerName],
+ DIRECT_ENABLE_SEQ[i][MixerValue]);
+ }
+ break;
+ case DEV_DIRECT_LO:
+ for(i = 0;i < ARRAY_SIZE(DIRECT_LO_ENABLE_SEQ); i++){
+ ret = set_mixer_ctrl_value_string(DIRECT_LO_ENABLE_SEQ[i][MixerName],
+ DIRECT_LO_ENABLE_SEQ[i][MixerValue]);
+ if(ret)
+ printf("%s, set_mixer_ctrl_value_string error %d, %s, %s\n",
+ __func__, ret,
+ DIRECT_LO_ENABLE_SEQ[i][MixerName],
+ DIRECT_LO_ENABLE_SEQ[i][MixerValue]);
+ }
+ break;
+ default:
+ printf("%s, device error, device: %d", __func__, dev);
+ break;
+ }
+}
+
+static void do_internal_codec_close_sequence(int dev)
+{
+ int i, ret;
+
+ /*TODO: make it simpler*/
+ switch(dev) {
+ case DEV_SPK:
+ for(i = 0;i < ARRAY_SIZE(SPK_DISABLE_SEQ); i++){
+ ret = set_mixer_ctrl_value_string(SPK_DISABLE_SEQ[i][MixerName],
+ SPK_DISABLE_SEQ[i][MixerValue]);
+ if(ret)
+ printf("%s, set_mixer_ctrl_value_string error %d, %s, %s\n",
+ __func__, ret,
+ SPK_DISABLE_SEQ[i][MixerName],
+ SPK_DISABLE_SEQ[i][MixerValue]);
+ }
+
+ for(i = 0;i < ARRAY_SIZE(INT_CODEC_INTERCONN_SEQ); i++){
+ ret = set_mixer_ctrl_interconn_value(INT_CODEC_INTERCONN_SEQ[i][MixerName], 0);
+ if(ret)
+ printf("%s, set_mixer_ctrl_interconn_value error %d, %s, 0\n",
+ __func__, ret,
+ INT_CODEC_INTERCONN_SEQ[i][MixerName]);
+ }
+ break;
+ case DEV_HP:
+ for(i = 0;i < ARRAY_SIZE(HP_DISABLE_SEQ); i++){
+ ret = set_mixer_ctrl_value_string(HP_DISABLE_SEQ[i][MixerName],
+ HP_DISABLE_SEQ[i][MixerValue]);
+ if(ret)
+ printf("%s, set_mixer_ctrl_value_string error %d, %s, %s\n",
+ __func__, ret,
+ HP_DISABLE_SEQ[i][MixerName],
+ HP_DISABLE_SEQ[i][MixerValue]);
+ }
+ break;
+ case DEV_DIRECT:
+ for(i = 0;i < ARRAY_SIZE(DIRECT_DISABLE_SEQ); i++){
+ ret = set_mixer_ctrl_value_string(DIRECT_DISABLE_SEQ[i][MixerName],
+ DIRECT_DISABLE_SEQ[i][MixerValue]);
+ if(ret)
+ printf("%s, set_mixer_ctrl_value_string error %d, %s, %s\n",
+ __func__, ret,
+ DIRECT_DISABLE_SEQ[i][MixerName],
+ DIRECT_DISABLE_SEQ[i][MixerValue]);
+ }
+ break;
+ case DEV_DIRECT_LO:
+ for(i = 0;i < ARRAY_SIZE(DIRECT_LO_DISABLE_SEQ); i++){
+ ret = set_mixer_ctrl_value_string(DIRECT_LO_DISABLE_SEQ[i][MixerName],
+ DIRECT_LO_DISABLE_SEQ[i][MixerValue]);
+ if(ret)
+ printf("%s, set_mixer_ctrl_value_string error %d, %s, %s\n",
+ __func__, ret,
+ DIRECT_LO_DISABLE_SEQ[i][MixerName],
+ DIRECT_LO_DISABLE_SEQ[i][MixerValue]);
+ }
+ break;
+
+ default:
+ printf("%s, device error, device: %d", __func__, dev);
+ break;
+ }
+}
+
+static void do_ext_codec_open_sequence(int dev)
+{
+ int i, ret;
+
+ for(i = 0;i < ARRAY_SIZE(EXT_CODEC_INTERCONN_SEQ); i++){
+ ret = set_mixer_ctrl_interconn_value(EXT_CODEC_INTERCONN_SEQ[i][MixerName],
+ atoi(EXT_CODEC_INTERCONN_SEQ[i][MixerValue]));
+ if(ret)
+ printf("%s, set_mixer_ctrl_interconn_value error %d, %s, %s\n",
+ __func__, ret,
+ EXT_CODEC_INTERCONN_SEQ[i][MixerName],
+ EXT_CODEC_INTERCONN_SEQ[i][MixerValue]);
+ }
+
+ for(i = 0;i < ARRAY_SIZE(EXT_CODEC_ENABLE_SEQ); i++){
+ ret = set_mixer_ctrl_value_string(EXT_CODEC_ENABLE_SEQ[i][MixerName],
+ EXT_CODEC_ENABLE_SEQ[i][MixerValue]);
+ if(ret)
+ printf("%s, set_mixer_ctrl_value_string error %d, %s, %s\n",
+ __func__, ret,
+ EXT_CODEC_ENABLE_SEQ[i][MixerName],
+ EXT_CODEC_ENABLE_SEQ[i][MixerValue]);
+ }
+}
+
+static void do_ext_codec_close_sequence(int dev)
+{
+ int i, ret;
+
+ for(i = 0;i < ARRAY_SIZE(EXT_CODEC_INTERCONN_SEQ); i++){
+ ret = set_mixer_ctrl_interconn_value(EXT_CODEC_INTERCONN_SEQ[i][MixerName], 0);
+ if(ret)
+ printf("%s, set_mixer_ctrl_interconn_value error %d, %s, 0\n",
+ __func__, ret,
+ EXT_CODEC_INTERCONN_SEQ[i][MixerName]);
+ }
+
+ for(i = 0;i < ARRAY_SIZE(EXT_CODEC_DISABLE_SEQ); i++){
+ ret = set_mixer_ctrl_value_string(EXT_CODEC_DISABLE_SEQ[i][MixerName],
+ EXT_CODEC_DISABLE_SEQ[i][MixerValue]);
+ if(ret)
+ printf("%s, set_mixer_ctrl_value_string error %d, %s, %s\n",
+ __func__, ret,
+ EXT_CODEC_DISABLE_SEQ[i][MixerName],
+ EXT_CODEC_DISABLE_SEQ[i][MixerValue]);
+ }
+}
+
+static int is_using_internal_codec(void)
+{
+ int use_int_codec = get_mixer_ctrl_interconn_value("Ext_Speaker_Amp");
+
+ printf("%s, use_int_codec = %d\n",
+ __func__, use_int_codec);
+
+ return use_int_codec;
+}
+
+int set_UL_analog_gain_for_service(int dB)
+{
+ char ul_gain_char[16];
+
+ pthread_mutex_lock(&g_afe_enabled_lock);
+ if(!g_afe_enabled) {
+ printf("%s, phone call not start!\n", __func__);
+ pthread_mutex_unlock(&g_afe_enabled_lock);
+ return -EPERM;
+ }
+ sprintf(ul_gain_char, "%dDb", dB);
+ /* set_mixer_ctrl_value_string("Audio_PGA1_Setting", ul_gain_char); */
+ /* set_mixer_ctrl_value_string("Audio_PGA2_Setting", ul_gain_char); */
+ pthread_mutex_unlock(&g_afe_enabled_lock);
+
+ return 0;
+}
+
+int set_DL_analog_gain_for_service(int dB)
+{
+ char dl_gain_char[16];
+
+ pthread_mutex_lock(&g_afe_enabled_lock);
+ if(!g_afe_enabled) {
+ printf("%s, phone call not start!\n", __func__);
+ pthread_mutex_unlock(&g_afe_enabled_lock);
+ return -EPERM;
+ }
+ /* set spk gain (-9~8dB)*/
+ sprintf(dl_gain_char, "%dDb", dB-9);
+ /* set_mixer_ctrl_value_string("Lineout_PGAL_GAIN", dl_gain_char); */
+ /* set_mixer_ctrl_value_string("Lineout_PGAR_GAIN", dl_gain_char); */
+
+ /* set hp gain (-9~8dB)*/
+ /* we set hp gain for tuning purpose, not really use them */
+ sprintf(dl_gain_char, "%dDb", dB-9);
+ /* set_mixer_ctrl_value_string("Headset_PGAL_GAIN", dl_gain_char); */
+ /* set_mixer_ctrl_value_string("Headset_PGAR_GAIN", dl_gain_char); */
+ pthread_mutex_unlock(&g_afe_enabled_lock);
+
+ return 0;
+}
+
+int dynamic_switch_phone_call_path_for_service(int audio_device)
+{
+ int ret;
+
+ if (!g_afe_enabled) {
+ printf("%s, phone call not start! no device switch~\n", __func__);
+ return 0;
+ }
+
+ if (audio_device == DEV_DEFAULT) {
+ audio_device = get_default_device_for_service();
+ }
+
+ if (g_device == audio_device) {
+ printf("%s, device not change!\n", __func__);
+ return 0;
+ }
+
+ disable_phone_call_AFE_path_for_service();
+ ret = enable_phone_call_AFE_path_for_service(audio_device);
+ return ret;
+}
+
+/* for client calling */
+//enable audio path for modem.
+//return value: 0 if success, or negitive error number
+int enable_phone_call_AFE_path(int audio_device)
+{
+ char buf[256];
+
+ sprintf(buf, "%d,%d", FUNC_ENABLE_PHONE_CALL_AFE_PATH, audio_device);
+ return do_IPC_call(buf);
+}
+
+//close audio path for modem
+//return value: 0 if success, or negitive error number
+int disable_phone_call_AFE_path(void)
+{
+ char buf[256];
+
+ sprintf(buf, "%d", FUNC_DISABLE_PHONE_CALL_AFE_PATH);
+ return do_IPC_call(buf);
+}
+
+//get default device.
+//return value: default device setting
+int get_default_device(void)
+{
+ char buf[256];
+
+ sprintf(buf, "%d", FUNC_GET_DEFAULT_VALUE);
+ return do_IPC_call(buf);
+}
+
+//set UL analog gain
+//return value: 0 if success, or negitive error number
+int set_UL_analog_gain(int dB)
+{
+ char buf[256];
+ sprintf(buf, "%d,%d", FUNC_SET_UL_ANALOG_GAIN, dB);
+ return do_IPC_call(buf);
+}
+
+//set DL analog gain
+//return value: 0 if success, or negitive error number
+int set_DL_analog_gain(int dB)
+{
+ char buf[256];
+
+ sprintf(buf, "%d,%d", FUNC_SET_DL_ANALOG_GAIN, dB);
+ return do_IPC_call(buf);
+}
+
+//set BT WB on
+//return value: 0 if success, or negitive error number
+int set_BT_WB(int on)
+{
+ char buf[256];
+ sprintf(buf, "%d,%d", FUNC_SET_BT_WB, on);
+ return do_IPC_call(buf);
+}
+
+//change device when the phone call is enabled
+//return value: 0 if success, or negitive error number
+int dynamic_switch_phone_call_path(int audio_device)
+{
+ char buf[256];
+
+ sprintf(buf, "%d,%d", FUNC_DYNAMIC_SWITCH_PHONE_CALL_PATH, audio_device);
+ return do_IPC_call(buf);
+}
+
+//set phonecall sample rate
+//return value: 0 if success, or negitive error number
+int set_phonecall_rate(int rate)
+{
+ char buf[256];
+
+ sprintf(buf, "%d,%d", FUNC_SET_PHONE_CALL_SAMPLERATE, rate);
+ return do_IPC_call(buf);
+}
+
+#define LIBMODEM_AFE_CTRL_IPC_SEM "LIBMODEM_AFE_CTRL_IPC_SEM"
+static int do_IPC_call(const char* cmd)
+{
+ static char *send_cmd_node = "/tmp/libmodem-afe-ctrl/server_rcv";
+ static char *receive_cmd_node = "/tmp/libmodem-afe-ctrl/server_send";
+ int send_cmd_handler;
+ int receive_cmd_handler;
+ int read_size, call_result;
+ sem_t *sem_ipc;
+ char buf[256];
+
+#ifdef IPC_SEQ_DEBUG
+ int cmd_int;
+
+ cmd_int = atoi(cmd);
+ printf("%s_libmodem, cmd_int: %d\n", __func__, cmd_int);
+ fflush(stdout);
+#endif
+
+ sem_ipc = sem_open(LIBMODEM_AFE_CTRL_IPC_SEM, O_CREAT, 0644, 1);
+ if (sem_ipc == SEM_FAILED) {
+ printf("%s sem_open failed, WTF = = \n", __func__);
+ return errno;
+ }
+ sem_wait(sem_ipc);
+
+ send_cmd_handler = open(send_cmd_node, O_WRONLY);
+ receive_cmd_handler = open(receive_cmd_node, O_RDONLY);
+
+ write(send_cmd_handler, cmd, strlen(cmd));
+ read_size = read(receive_cmd_handler, buf, 256);
+
+ buf[read_size] = '\0';
+ call_result = atoi(buf);
+
+ close(send_cmd_handler);
+ close(receive_cmd_handler);
+
+ sem_post(sem_ipc);
+ return call_result;
+}
+
diff --git a/src/multimedia/libspeech_drv/LICENSE b/src/multimedia/libspeech_drv/LICENSE
new file mode 100644
index 0000000..77f59ed
--- /dev/null
+++ b/src/multimedia/libspeech_drv/LICENSE
@@ -0,0 +1,31 @@
+Copyright Statement:
+
+This software/firmware and related documentation ("MediaTek Software") are
+protected under relevant copyright laws. The information contained herein is
+confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+the prior written permission of MediaTek inc. and/or its licensors, any
+reproduction, modification, use or disclosure of MediaTek Software, and
+information contained herein, in whole or in part, shall be strictly
+prohibited.
+
+MediaTek Inc. (C) 2015. All rights reserved.
+
+BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
diff --git a/src/multimedia/libspeech_drv/Makefile b/src/multimedia/libspeech_drv/Makefile
new file mode 100644
index 0000000..f2fadc0
--- /dev/null
+++ b/src/multimedia/libspeech_drv/Makefile
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: MediaTekProprietary
+ifeq ($(strip $(TARGET_PLATFORM)), mt2635)
+ DIR_MAKEFILE = mt2635
+else
+ DIR_MAKEFILE = audio_big_sw
+endif
+
+build:
+ $(warning ########## build libspeech-drv ##########)
+ for i in $(DIR_MAKEFILE); do \
+ (cd $$i && make); \
+ if [ $$? != 0 ]; then \
+ exit 1; \
+ fi \
+ done
+
+install:
+ $(warning ########## install libspeech-drv ##########)
+ for i in $(DIR_MAKEFILE); do \
+ (cd $$i && make install); \
+ if [ $$? != 0 ]; then \
+ exit 1; \
+ fi \
+ done
+
+clean:
+ for i in $(DIR_MAKEFILE); do \
+ (cd $$i && make clean); \
+ if [ $$? != 0 ]; then \
+ exit 1; \
+ fi \
+ done
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/ENH_Parser/Android.mk b/src/multimedia/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/ENH_Parser/Android.mk
new file mode 100644
index 0000000..86f845d
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/ENH_Parser/Android.mk
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: MediaTekProprietary
+LOCAL_PATH := $(my-dir)
+
+############################################################################################################### Vendor
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+LOCAL_C_INCLUDES += \
+ external/libxml2/include \
+ external/icu/libandroidicu/include \
+ $(JNI_H_INCLUDE) \
+ $(MTK_PATH_SOURCE)/external/AudioParamParser/include \
+ $(MTK_PATH_SOURCE)/external/aurisys/interface \
+ $(MTK_PATH_SOURCE)/external/AudioParamParser \
+ $(TOPDIR)vendor/mediatek/proprietary/hardware/audio/common/V3/include \
+ $(TOPDIR)frameworks/av/media/libmedia \
+ $(TOPDIR)frameworks/av/include \
+ $(TOPDIR)hardware/libhardware/include \
+
+# incall handfree DMNR
+ifeq ($(MTK_INCALL_HANDSFREE_DMNR),yes)
+ LOCAL_CFLAGS += -DMTK_INCALL_HANDSFREE_DMNR
+endif
+
+LOCAL_SRC_FILES := \
+ SpeechParser.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ liblog \
+ libutils \
+ libaudioutils \
+ libmedia_helper
+
+LOCAL_MODULE := libspeechparser_vendor
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_MODULE_SUFFIX := .so
+LOCAL_MULTILIB := both
+LOCAL_ARM_MODE := arm
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(MTK_SHARED_LIBRARY)
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/ENH_Parser/SpeechParser.cpp b/src/multimedia/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/ENH_Parser/SpeechParser.cpp
new file mode 100644
index 0000000..1aa2980
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/ENH_Parser/SpeechParser.cpp
@@ -0,0 +1,1480 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechParser"
+#include "SpeechParser.h"
+#include "utstring.h"
+#include <utils/Log.h>
+#include <inttypes.h>
+#include <media/AudioParameter.h>
+#include <assert.h>
+
+
+
+namespace android {
+extern "C" {
+#define XML_FOLDER "/system/etc/audio_param/"
+
+
+#define MAX_BYTE_PARAM_SPEECH 4200
+#define SPH_DUMP_STR_SIZE (500)
+
+#define SPH_PARAM_UNIT_DUMP_STR_SIZE (1024)
+ //--------------------------------------------------------------------------------
+ //audio type: Speech
+#define MAX_NUM_CATEGORY_TYPE_SPEECH 4
+#define MAX_NUM_PARAM_SPEECH 3
+ const String8 audioType_Speech_CategoryType[] = { String8("Band"), String8("Profile"), String8("VolIndex"), String8("Network") };
+ const String8 audioType_Speech_ParamName[] = { String8("speech_mode_para"), String8("sph_in_fir"), String8("sph_out_fir"), String8("sph_in_iir_mic1_dsp"), String8("sph_in_iir_mic2_dsp"), String8("sph_in_iir_enh_dsp"), String8("sph_out_iir_enh_dsp") };
+
+#define NUM_VOLUME_SPEECH 7
+ const char audioType_Speech_CategoryName3[NUM_VOLUME_SPEECH][128] = { "0", "1", "2", "3", "4", "5", "6" };
+ const char audioType_Speech_CategoryName2[PARSER_SPEECH_PROFILE_MAX_NUM][128] = {
+ "Normal",
+ "4_pole_Headset",
+ "Handsfree",
+ "BT_Earphone",
+ "BT_NREC_Off",
+ "MagiConference",
+ "HAC",
+ "Lpbk_Handset",
+ "Lpbk_Headset",
+ "Lpbk_Handsfree",
+ "3_pole_Headset",
+ "5_pole_Headset",
+ "5_pole_Headset+ANC",
+ "Usb_Headset",
+ "Handset_SV",
+ "Handsfree_SV",
+ "Tty_HCO_Handset",
+ "Tty_HCO_Handsfree",
+ "Tty_VCO_Handset",
+ "Tty_VCO_Handsfree"
+ };
+
+ //--------------------------------------------------------------------------------
+ //audio type: SpeechDMNR
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_DMNR 2
+#define MAX_NUM_PARAM_SPEECH_DMNR 1
+ const String8 audioType_SpeechDMNR_CategoryType[] = { String8("Band"), String8("Profile") };
+ const char audioType_SpeechDMNR_CategoryName2[2][128] = { "Handset", "MagiConference" };
+ const String8 audioType_SpeechDMNR_ParamName[] = { String8("dmnr_para") };
+
+ //--------------------------------------------------------------------------------
+ //audio type: SpeechGeneral
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_GENERAL 1
+#define MAX_NUM_PARAM_SPEECH_GENERAL 2
+ const String8 audioType_SpeechGeneral_CategoryType[] = { String8("CategoryLayer") };
+ const char audioType_SpeechGeneral_CategoryName1[1][128] = { "Common" };
+ const String8 audioType_SpeechGeneral_ParamName[] = { String8("speech_common_para"), String8("debug_info") };
+
+ //--------------------------------------------------------------------------------
+ //audio type: SpeechMagiClarity
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_MAGICLARITY 1
+#define MAX_NUM_PARAM_SPEECH_MAGICLARITY 1
+ const String8 audioType_SpeechMagiClarity_CategoryType[] = { String8("CategoryLayer") };
+ const char audioType_SpeechMagiClarity_CategoryName1[1][128] = { "Common" };
+ const String8 audioType_SpeechMagiClarity_ParamName[] = { String8("shape_rx_fir_para") };
+
+ //--------------------------------------------------------------------------------
+ //audio type: SpeechNetwork
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_NETWORK 1
+#define MAX_NUM_PARAM_SPEECH_NETWORK 1
+ const String8 audioType_SpeechNetwork_CategoryType[] = { String8("Network") };
+ const String8 audioType_SpeechNetwork_ParamName[] = { String8("speech_network_support") };
+
+
+ //--------------------------------------------------------------------------------
+ //audio type: SpeechEchoRef
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_ECHOREF 1
+#define MAX_NUM_PARAM_SPEECH_ECHOREF 1
+ const String8 audioType_SpeechEchoRef_CategoryType[] = { String8("Device") };
+ const char audioType_SpeechEchoRef_CategoryName1[1][128] = { "USBAudio" };
+ const String8 audioType_SpeechEchoRef_ParamName[] = { String8("EchoRef_para") };
+
+//--------------------------------------------------------------------------------
+//audio type: SpeechDeReverb
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_DEREVERB 2
+#define MAX_NUM_PARAM_SPEECH_DEREVERB 1
+ const String8 audioType_SpeechDereverb_CategoryType[ ] = {String8("Band"), String8("Profile")};
+ const char audioType_SpeechDereverb_CategoryName2[1][128] = {"Handsfree"};
+ const String8 audioType_SpeechDereverb_ParamName[ ] = {String8("derev_para")};
+
+//--------------------------------------------------------------------------------
+#define ENH_SPH_PARSER_VER 0x0001
+
+ AppHandle *mAppHandle; // = appHandleGetInstance();
+ uint8_t numSpeechNetwork, mSpeechParamVerFirst, mSpeechParamVerLast, numSpeechParam;
+ PARSER_SPEECH_NETWORK_STRUCT mNameForEachSpeechNetwork[12];
+ PARSER_SPEECH_PARAM_SUPPORT_STRUCT mSphParamSupport;
+
+ PARSER_SPEECH_NETWORK_STRUCT mListSpeechNetwork[12];
+ static short SpeechParserInited = 0;
+ static short Parser_time_count = 0;
+
+#define TESTMODE_MAX_LENGTH 20
+
+ char TestMode[TESTMODE_MAX_LENGTH] = "Default";
+
+ // const uint32_t CommonInfo_offset = 9;
+ // const uint32_t DebugInfo_offset = 22;
+ uint32_t MD_version = 0;
+
+ //static const uint32_t SD_SphParamSize = 0xC000; // 48K
+ static const uint32_t SD_SphParamSize = 0x10000; // 64K
+ /*==============================================================================
+ * Lock
+ *============================================================================*/
+ static pthread_rwlock_t spHandleInstLock = PTHREAD_RWLOCK_INITIALIZER;
+
+ EXPORT int spHandleInstWriteLock(const char *callerFun) {
+ int res = 0;
+ while (1) {
+ if (pthread_rwlock_trywrlock(&spHandleInstLock) == 0) {
+ //ALOGD("%s acquired the spHandleInstLock\n", callerFun);
+ break;
+ } else {
+ ALOGE("Cannot lock the spHandleInstLock, delay some time. (the locker is %s)\n", callerFun);
+ usleep(1);
+ }
+ }
+ return res;
+ }
+
+ EXPORT int spHandleInstUnlock() {
+ int res = 0;
+ ALOGV("Unlock spHandleInst lock\n");
+ res = pthread_rwlock_unlock(&spHandleInstLock);
+ return res;
+ }
+
+ /*==============================================================================
+ * Constructor / Destructor / Init / Deinit
+ *============================================================================*/
+ static SpHandle spHandleInst;
+ static int spHandleInited = 0;
+
+ EXPORT SP_STATUS spHandleInit(SpHandle * spHandle) {
+ //ALOGD("%s(), spHandle = 0x%p\n", __FUNCTION__, spHandle);
+ return SP_NO_ERROR;
+ }
+
+ EXPORT SP_STATUS spHandleUninit(SpHandle * spHandle) {
+ //ALOGD("%s(), spHandle = 0x%p\n", __FUNCTION__, spHandle);
+ if (!spHandle) {
+ ALOGW("SpHandle is NULL!\n");
+ return SP_ERROR;
+ } else {
+ /* If spHandle is singleton instance, reset the init info */
+ if (spHandle == &spHandleInst) {
+ spHandleInited = 0;
+ }
+
+ return SP_NO_ERROR;
+ }
+ }
+ /*==============================================================================
+ * Singleton Pattern
+ *============================================================================*/
+ EXPORT SpHandle * spHandleGetInstance() {
+ spHandleInstWriteLock(__FUNCTION__);
+
+ if (!spHandleInited) {
+ spHandleInit(&spHandleInst);
+ spHandleInited = 1;
+ }
+
+ spHandleInstUnlock();
+
+ return &spHandleInst;
+ }
+ /*==============================================================================
+ * Method
+ *============================================================================*/
+
+
+
+ uint16_t sizeByteParaData(DATA_TYPE dataType, uint16_t arraySize) {
+
+ uint16_t sizeUnit = 4;
+ switch (dataType) {
+ case TYPE_INT:
+ sizeUnit = 4;
+ break;
+ case TYPE_UINT:
+ sizeUnit = 4;
+ break;
+ case TYPE_FLOAT:
+ sizeUnit = 4;
+ break;
+ case TYPE_BYTE_ARRAY:
+ sizeUnit = arraySize;
+ break;
+ case TYPE_UBYTE_ARRAY:
+ sizeUnit = arraySize;
+ break;
+ case TYPE_SHORT_ARRAY:
+ sizeUnit = arraySize << 1;
+ break;
+ case TYPE_USHORT_ARRAY:
+ sizeUnit = arraySize << 1;
+ break;
+ case TYPE_INT_ARRAY:
+ sizeUnit = arraySize << 2;
+ break;
+ case TYPE_UINT_ARRAY:
+ sizeUnit = arraySize << 2;
+ break;
+ default:
+ ALOGE("%s(), Not an available dataType(%d)", __FUNCTION__, dataType);
+
+ break;
+
+ }
+
+ ALOGV("-%s(), arraySize=%d, sizeUnit=%d", __FUNCTION__, arraySize, sizeUnit);
+ return sizeUnit;
+ }
+
+ uint16_t SetMDParamDataHdr_SP(Category * cateBand, Category * cateNetwork) {
+ uint16_t dataHeader = 0, MaskNetwork = 0;;
+
+ if (cateBand->name != NULL) {
+ if (strcmp(cateBand->name, "NB") == 0) { //All netwrok use
+ dataHeader = 0x1000;
+ } else if (strcmp(cateBand->name, "WB") == 0) {
+ dataHeader = 0x2000;
+ } else if (strcmp(cateBand->name, "SWB") == 0) {
+ dataHeader = 0x3000;
+ } else if (strcmp(cateBand->name, "FB") == 0) {
+ dataHeader = 0x4000;
+ }
+ } else {
+ dataHeader = 0x1000;
+ }
+
+ if (cateNetwork->name != NULL) {
+ if (strcmp(cateNetwork->name, "GSM") == 0) { //Mapping network to dataHdr
+ MaskNetwork = 0x1;
+ } else if (strcmp(cateNetwork->name, "WCDMA") == 0) {
+ MaskNetwork = 0x2;
+ } else if (strcmp(cateNetwork->name, "WCDMA_FDD") == 0) {
+ MaskNetwork = 0x2;
+ } else if (strcmp(cateNetwork->name, "VoLTE") == 0) {
+ MaskNetwork = 0x4;
+ } else if (strcmp(cateNetwork->name, "ViLTE") == 0) {
+ MaskNetwork = 0x8;
+ } else if (strcmp(cateNetwork->name, "C2K") == 0) {
+ MaskNetwork = 0x10;
+ } else if (strcmp(cateNetwork->name, "VoWifi") == 0) {
+ MaskNetwork = 0x20;
+ } else if (strcmp(cateNetwork->name, "Viwifi") == 0) {
+ MaskNetwork = 0x40;
+ } else if (strcmp(cateNetwork->name, "5G") == 0) {
+ MaskNetwork = 0x80;
+ }
+ }
+
+ dataHeader |= MaskNetwork;
+ return dataHeader;
+ }
+
+ status_t SpeechDataDump_new(char *bufDump, uint16_t idxSphType, const char *nameParam, const char *speechParamData) {
+
+ if (nameParam == NULL) {
+ return NO_ERROR;
+ }
+
+ ALOGV("+%s(), idxSphType=%d", __FUNCTION__, idxSphType);
+ char sphDumpStr[SPH_DUMP_STR_SIZE] = { 0 };
+ int idxDump = 0, sizeDump = 0, DataTypePrint = 0;
+ //speech parameter dump
+
+ switch (idxSphType) {
+ case PARSER_AUDIO_TYPE_SPEECH: {
+ if (strcmp(nameParam, "speech_mode_para") == 0) {
+ sizeDump = 16;
+ } else if (strcmp(nameParam, "sph_in_fir") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_out_fir") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_in_iir_mic1_dsp") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_in_iir_mic2_dsp") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_in_iir_enh_dsp") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_out_iir_enh_dsp") == 0) {
+ sizeDump = 5;
+ }
+ break;
+ }
+ case PARSER_AUDIO_TYPE_SPEECH_GENERAL: {
+ if (strcmp(nameParam, "speech_common_para") == 0) {
+ sizeDump = 12;
+ } else if (strcmp(nameParam, "debug_info") == 0) {
+ sizeDump = 8;
+ }
+ break;
+ }
+ case PARSER_AUDIO_TYPE_SPEECH_NETWORK: {
+ if (strcmp(nameParam, "speech_network_support") == 0) {
+ DataTypePrint = 1;
+ sizeDump = 1;
+ }
+ break;
+ }
+ case PARSER_AUDIO_TYPE_SPEECH_ECHOREF: {
+ if (strcmp(nameParam, "USBAudio") == 0) {
+ sizeDump = 3;
+ }
+ break;
+ }
+ case PARSER_AUDIO_TYPE_SPEECH_MAGICLARITY: {
+ if (strcmp(nameParam, "shape_rx_fir_para") == 0) {
+ sizeDump = 32;
+ }
+ break;
+ }
+ case PARSER_AUDIO_TYPE_SPEECH_DEREVERB: {
+ if (strcmp(nameParam, "derev_para") == 0) {
+ sizeDump = 16;
+ }
+ break;
+ }
+ }
+ snprintf(sphDumpStr, SPH_DUMP_STR_SIZE, "%s[%d]=", nameParam, sizeDump);
+
+ for (idxDump = 0; idxDump < sizeDump; idxDump++) {
+ char sphDumpTemp[100] = { 0 };
+ if (DataTypePrint == 1) {
+ snprintf(sphDumpTemp, 100, "[%d]0x%x,", idxDump, *((uint16_t *)speechParamData + idxDump));
+ } else {
+ snprintf(sphDumpTemp, 100, "[%d]%d,", idxDump, *((uint16_t *)speechParamData + idxDump));
+ }
+ strncat(sphDumpStr, sphDumpTemp, SPH_DUMP_STR_SIZE - 1);
+ }
+
+ if (idxDump != 0 && bufDump != NULL) {
+ strncat(bufDump, sphDumpStr, SPH_DUMP_STR_SIZE - 1);
+ }
+ return NO_ERROR;
+ }
+
+ status_t GetSpeechParamFromAppParser_new(uint16_t idxSphType,
+ PARSER_AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT * paramLayerInfo,
+ char *bufParamUnit,
+ uint16_t *sizeByteTotal,
+ uint16_t Dump_Flag) {
+ ALOGV("+%s(), paramLayerInfo->numCategoryType=0x%x", __FUNCTION__, paramLayerInfo->numCategoryType);
+
+ if (mAppHandle == NULL) {
+ ALOGE("%s() mAppHandle == NULL, Assert!!!", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ char *categoryPath = NULL;
+ ParamUnit *paramUnit = NULL;
+ uint16_t sizeByteParam = 0, idxCount;
+ Param *SpeechParam;
+ UT_string *uts_categoryPath = NULL;
+
+
+
+ /* If user select a category path, just like "NarrowBand / Normal of Handset / Level0" */
+ utstring_new(uts_categoryPath);
+
+ ALOGV("%s(), categoryType.size=%zu, paramName.size=%zu", __FUNCTION__, paramLayerInfo->categoryType.size(), paramLayerInfo->paramName.size());
+ for (idxCount = 0; idxCount < paramLayerInfo->categoryType.size(); idxCount++) {
+ ALOGV("%s(), categoryType[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo->categoryType.at(idxCount).string());
+ }
+ for (idxCount = 0; idxCount < paramLayerInfo->categoryName.size(); idxCount++) {
+ ALOGV("%s(), categoryName[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo->categoryName.at(idxCount).string());
+ }
+
+ for (idxCount = 0; idxCount < paramLayerInfo->numCategoryType; idxCount++) {
+ if (idxCount == paramLayerInfo->numCategoryType - 1) {
+ //last time concat
+ utstring_printf(uts_categoryPath, "%s,%s", (char *)(paramLayerInfo->categoryType.at(idxCount).string()), (char *)(paramLayerInfo->categoryName.at(idxCount).string()));
+ } else {
+ utstring_printf(uts_categoryPath, "%s,%s,", (char *)(paramLayerInfo->categoryType.at(idxCount).string()), (char *)(paramLayerInfo->categoryName.at(idxCount).string()));
+ }
+ }
+ categoryPath = strdup(utstring_body(uts_categoryPath));
+ utstring_free(uts_categoryPath);
+
+ ALOGV("%s() audioTypeName=%s", __FUNCTION__, paramLayerInfo->audioTypeName);
+ /* Query AudioType */
+ AppOps *appOps = appOpsGetInstance();
+ AudioType *audioType = NULL;
+ if (appOps == NULL) {
+ free(categoryPath);
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ } else {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo->audioTypeName);
+ }
+ if (!audioType) {
+ free(categoryPath);
+ ALOGE("%s() can't find audioTypeName=%s, Assert!!!", __FUNCTION__, paramLayerInfo->audioTypeName);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ /* Query the ParamUnit */
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, categoryPath);
+ if (!paramUnit) {
+ appOps->audioTypeUnlock(audioType);
+ ALOGE("%s() can't find paramUnit, Assert!!! audioType=%s, categoryPath=%s", __FUNCTION__, audioType->name, categoryPath);
+ free(categoryPath);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ if (Dump_Flag != 0) {
+ ALOGD("%s() audioType=%s, categoryPath=%s, paramId=%d", __FUNCTION__, audioType->name, categoryPath, paramUnit->paramId);
+ }
+ ALOGV(" (*paramLayerInfo).numParam = %d", (*paramLayerInfo).numParam);
+
+
+ //for speech param dump
+ char *bufParamDump = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(bufParamDump, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ uint16_t SpeechParam_size = 0;
+
+ for (idxCount = 0; idxCount < (*paramLayerInfo).numParam; idxCount++) {
+
+ SpeechParam = appOps->paramUnitGetParamByName(paramUnit, (const char *)paramLayerInfo->paramName.at(idxCount).string());
+ if (SpeechParam) {
+ sizeByteParam = sizeByteParaData((DATA_TYPE)SpeechParam->paramInfo->dataType, SpeechParam->arraySize);
+
+ SpeechParam_size = (uint16_t)(SpeechParam->arraySize);
+
+ //For mode param , if (SpeechParam_size == 48)
+
+ if ((SpeechParam_size == 48) && (idxSphType == PARSER_AUDIO_TYPE_SPEECH)) {
+ SpeechParam_size = 64;
+ }
+
+ if ((idxSphType == PARSER_AUDIO_TYPE_SPEECH) || (idxSphType == PARSER_AUDIO_TYPE_SPEECH_DMNR) || (idxSphType == PARSER_AUDIO_TYPE_SPEECH_GENERAL) || (idxSphType == PARSER_AUDIO_TYPE_SPEECH_MAGICLARITY) || (idxSphType == PARSER_AUDIO_TYPE_SPEECH_DEREVERB)) {
+ //Add parameter total size at first
+ memcpy(bufParamUnit + *sizeByteTotal, &(SpeechParam_size), sizeof(uint16_t));
+ *sizeByteTotal += sizeof(uint16_t);
+ }
+
+ memcpy(bufParamUnit + *sizeByteTotal, SpeechParam->data, sizeByteParam);
+
+ *sizeByteTotal += sizeByteParam;
+
+ //For mode param 48-> 64
+ if ((SpeechParam_size == 64) && (idxSphType == PARSER_AUDIO_TYPE_SPEECH)) {
+ *sizeByteTotal += (16 * 2);
+ // ALOGD("Test for speech param sizeByteTotal = %d", *sizeByteTotal);
+ }
+
+ // add Reserved Words behind the data
+ if (idxSphType == PARSER_AUDIO_TYPE_SPEECH_DMNR) {
+ *sizeByteTotal += (SpeechParam_size * 2);
+ }
+
+ ALOGV("%s() paramName=%s, sizeByteParam=%d",
+ __FUNCTION__, paramLayerInfo->paramName.at(idxCount).string(), sizeByteParam);
+ //speech parameter dump
+ SpeechDataDump_new(bufParamDump, idxSphType, (const char *)paramLayerInfo->paramName.at(idxCount).string(), (const char *)SpeechParam->data);
+ }
+ }
+
+ if (bufParamDump != NULL) {
+ if (bufParamDump[0] != 0) {
+ if (Dump_Flag != 0) {
+ ALOGD("%s(),dump: %s", __FUNCTION__, bufParamDump);
+ }
+ }
+ delete[] bufParamDump;
+ }
+
+ appOps->audioTypeUnlock(audioType);
+ free(categoryPath);
+
+ return NO_ERROR;
+ }
+
+ bool getFeatureOn(const SpeechFeatureType featureType, const uint16_t speechFeatureOn) {
+ uint16_t featureMaskType = 1 << featureType;
+ const bool featureOn = speechFeatureOn & featureMaskType;
+ ALOGV("%s() featureMaskType: 0x%x, featureOn=%d", __FUNCTION__, featureMaskType, featureOn);
+ return featureOn;
+ }
+
+ speech_profile_SP SP_GetSpeechProfile(const SpeechParserAttribute speechParserAttribute) {
+ speech_profile_SP idxSphProfile;
+
+ if (getFeatureOn(SPEECH_FEATURE_LOOPBACK, speechParserAttribute.speechFeatureOn)) {
+ switch (speechParserAttribute.outputDevice) {
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ idxSphProfile = PARSER_SPEECH_PROFILE_LPBK_HANDSFREE;
+ break;
+ case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+ case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+ idxSphProfile = PARSER_SPEECH_PROFILE_LPBK_HEADSET;
+ break;
+ default:
+ idxSphProfile = PARSER_SPEECH_PROFILE_LPBK_HANDSET;
+ break;
+ }
+ } else if (audio_is_bluetooth_sco_device(speechParserAttribute.outputDevice)) {
+ if (getFeatureOn(SPEECH_FEATURE_BTNREC, speechParserAttribute.speechFeatureOn)) {
+
+ idxSphProfile = PARSER_SPEECH_PROFILE_BT_EARPHONE;
+ } else {
+
+ idxSphProfile = PARSER_SPEECH_PROFILE_BT_NREC_OFF;
+ }
+
+ } else {
+
+ switch (speechParserAttribute.outputDevice) {
+ case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+ idxSphProfile = PARSER_SPEECH_PROFILE_3_POLE_HEADSET;
+ break;
+ case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+ idxSphProfile = PARSER_SPEECH_PROFILE_4_POLE_HEADSET;
+ break;
+
+ case AUDIO_DEVICE_OUT_SPEAKER:
+#if defined(MTK_INCALL_HANDSFREE_DMNR)
+ idxSphProfile = PARSER_SPEECH_PROFILE_MAGICONFERENCE;
+#else
+ if (speechParserAttribute.ttyMode == AUD_TTY_OFF) {
+ // if (mSphParamInfo.isSV) {
+ if (getFeatureOn(SPEECH_FEATURE_SUPERVOLUME, speechParserAttribute.speechFeatureOn)) {
+ idxSphProfile = PARSER_SPEECH_PROFILE_HANDSFREE_SV;
+ } else {
+ idxSphProfile = PARSER_SPEECH_PROFILE_HANDSFREE;
+ }
+ } else {
+ switch (speechParserAttribute.ttyMode) {
+ case AUD_TTY_HCO:
+ idxSphProfile = PARSER_SPEECH_PROFILE_TTY_HCO_HANDSFREE;
+ break;
+ case AUD_TTY_VCO:
+ idxSphProfile = PARSER_SPEECH_PROFILE_TTY_VCO_HANDSFREE;
+ break;
+ default:
+ idxSphProfile = PARSER_SPEECH_PROFILE_TTY_HCO_HANDSFREE;
+ break;
+ }
+ }
+#endif
+ break;
+
+ case AUDIO_DEVICE_OUT_USB_DEVICE:
+ idxSphProfile = PARSER_SPEECH_PROFILE_USB_HEADSET;
+ break;
+
+ default:
+ if (getFeatureOn(SPEECH_FEATURE_HAC, speechParserAttribute.speechFeatureOn)) {
+ idxSphProfile = PARSER_SPEECH_PROFILE_HAC;
+
+ } else {
+ if (speechParserAttribute.ttyMode == AUD_TTY_OFF) {
+ // if (mSphParamInfo.isSV) {
+ if (getFeatureOn(SPEECH_FEATURE_SUPERVOLUME, speechParserAttribute.speechFeatureOn)) {
+ idxSphProfile = PARSER_SPEECH_PROFILE_HANDSET_SV;
+ } else {
+ idxSphProfile = PARSER_SPEECH_PROFILE_HANDSET;
+ }
+ } else {
+ switch (speechParserAttribute.ttyMode) {
+ case AUD_TTY_HCO:
+ idxSphProfile = PARSER_SPEECH_PROFILE_TTY_HCO_HANDSET;
+ break;
+ case AUD_TTY_VCO:
+ idxSphProfile = PARSER_SPEECH_PROFILE_TTY_VCO_HANDSET;
+ break;
+ default:
+ idxSphProfile = PARSER_SPEECH_PROFILE_TTY_HCO_HANDSET;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ ALOGD("%s(), idxSphProfile = %d", __FUNCTION__, idxSphProfile);
+
+ return idxSphProfile;
+ }
+
+ void Init() {
+ ALOGD("%s()", __FUNCTION__);
+ InitAppParser();
+ InitSpeechNetwork();
+
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ } else {
+ const char *strSphVersion = appOps->appHandleGetFeatureOptionValue(mAppHandle, "SPH_PARAM_VERSION");
+ if (strSphVersion != NULL) {
+ sscanf(strSphVersion, "%" SCNd8 ".%" SCNd8, &mSpeechParamVerFirst, &mSpeechParamVerLast);
+ switch (mSpeechParamVerFirst) {
+ case 2:
+ mSphParamSupport.isNetworkSupport = true;
+ numSpeechParam = 7;
+ break;
+ case 1:
+ mSphParamSupport.isNetworkSupport = true;
+ numSpeechParam = 3;
+ break;
+ default:
+ mSphParamSupport.isNetworkSupport = false;
+ numSpeechParam = 3;
+ break;
+ }
+ } else {
+ mSpeechParamVerFirst = 0;
+ mSpeechParamVerLast = 0;
+ mSphParamSupport.isNetworkSupport = false;
+ numSpeechParam = 3;
+ }
+
+ const char *strSphTTY = appOps->appHandleGetFeatureOptionValue(mAppHandle, "SPH_PARAM_TTY");
+ if (strSphTTY != NULL) {
+ if (strcmp(strSphTTY, "yes") == 0) {
+ mSphParamSupport.isTTYSupport = true;
+ } else {
+ mSphParamSupport.isTTYSupport = false;
+ }
+ } else {
+ mSphParamSupport.isTTYSupport = false;
+ }
+
+ const char *strSphSV = appOps->appHandleGetFeatureOptionValue(mAppHandle, "SPH_PARAM_SV");
+ if (strSphSV != NULL) {
+ if (strcmp(strSphSV, "yes") == 0) {
+ mSphParamSupport.isSuperVolumeSupport = true;
+ } else {
+ mSphParamSupport.isSuperVolumeSupport = false;
+ }
+ } else {
+ mSphParamSupport.isSuperVolumeSupport = false;
+ }
+ }
+ }
+
+ void InitAppParser() {
+ //ALOGD("+%s()", __FUNCTION__);
+ /* Init AppHandle */
+ //ALOGD("%s() appHandleGetInstance", __FUNCTION__);
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return;
+ }
+ mAppHandle = appOps->appHandleGetInstance();
+ //ALOGD("%s() appHandleRegXmlChangedCb", __FUNCTION__);
+
+ }
+
+ int InitSpeechNetwork() {
+ uint16_t size = 0, idxCount, sizeByteFromApp = 0;
+ char *packedParamUnitFromApp = new char[10];
+ memset(packedParamUnitFromApp, 0, 10);
+
+ PARSER_AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+ memset(¶mLayerInfo, 0, sizeof(PARSER_AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT));
+
+ paramLayerInfo.audioTypeName = (char *)Parser_audioTypeNameList[PARSER_AUDIO_TYPE_SPEECH_NETWORK];
+
+ if (mAppHandle == NULL) {
+ ALOGE("%s() mAppHandle == NULL, Assert!!!", __FUNCTION__);
+ ASSERT(0);
+ }
+
+ /* Query AudioType */
+ AppOps *appOps = appOpsGetInstance();
+ AudioType *audioType = NULL;
+
+ if (appOps != NULL) {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo.audioTypeName);
+ paramLayerInfo.numCategoryType = appOps->audioTypeGetNumOfCategoryType(audioType);//1
+
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_NETWORK;//4
+
+ paramLayerInfo.categoryType.assign(audioType_SpeechNetwork_CategoryType, audioType_SpeechNetwork_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechNetwork_ParamName, audioType_SpeechNetwork_ParamName + paramLayerInfo.numParam);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ // ALOGV("%s(), categoryType.size=%zu, paramName.size=%zu", __FUNCTION__, paramLayerInfo.categoryType.size(), paramLayerInfo.paramName.size());
+ // for (idxCount = 0; idxCount < paramLayerInfo.categoryType.size(); idxCount++) {
+ // ALOGV("%s(), categoryType[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.categoryType.at(idxCount).string());
+ // }
+ // for (idxCount = 0; idxCount < paramLayerInfo.paramName.size(); idxCount++) {
+ // ALOGV("%s(), paramName[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.paramName.at(idxCount).string());
+ // }
+ //-----------
+ //parse layer
+ CategoryType *categoryNetwork = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_SpeechNetwork_CategoryType[0].string());
+ numSpeechNetwork = appOps->categoryTypeGetNumOfCategory(categoryNetwork);
+
+ //parse network
+ for (int i = 0; i < numSpeechNetwork; i++) {
+ Category *CateNetwork = appOps->categoryTypeGetCategoryByIndex(categoryNetwork, i);
+ sizeByteFromApp = 0;
+ //clear
+ while (!paramLayerInfo.categoryName.empty()) {
+ paramLayerInfo.categoryName.pop_back();
+ }
+ strncpy(mListSpeechNetwork[i].name, CateNetwork->name, 128);
+ mListSpeechNetwork[i].name[127] = '\0';
+ //strncpy(mListSpeechNetwork[i].name, CateNetwork->name, 128);
+ paramLayerInfo.categoryName.push_back(String8(CateNetwork->name));//Network
+
+ GetSpeechParamFromAppParser_new(PARSER_AUDIO_TYPE_SPEECH_NETWORK, ¶mLayerInfo, packedParamUnitFromApp, &sizeByteFromApp, 1);
+ mListSpeechNetwork[i].supportBit = *((uint16_t *)packedParamUnitFromApp);
+ size += sizeByteFromApp;
+
+ ALOGD("%s(), i=%d, sizeByteFromApp=%d, supportBit=0x%x",
+ __FUNCTION__, i, sizeByteFromApp, mListSpeechNetwork[i].supportBit);
+ }
+ //ALOGD("-%s(), total size byte=%d", __FUNCTION__, size);
+ } else {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ }
+ //init the Name mapping table for each SpeechNetwork
+ bool IsNetworkFound = false;
+ for (int bitIndex = 0; bitIndex < 12; bitIndex++) {
+ IsNetworkFound = false;
+ for (int NetworkIndex = 0; NetworkIndex < numSpeechNetwork; NetworkIndex++) {
+ if (((mListSpeechNetwork[NetworkIndex].supportBit >> bitIndex) & 1) == 1) {
+ strncpy(mNameForEachSpeechNetwork[bitIndex].name, mListSpeechNetwork[NetworkIndex].name, 128);
+ mNameForEachSpeechNetwork[bitIndex].name[127] = '\0';
+ IsNetworkFound = true;
+ break;
+ }
+ }
+ if (!IsNetworkFound) {
+ strncpy(mNameForEachSpeechNetwork[bitIndex].name, mListSpeechNetwork[0].name, 128);
+ mNameForEachSpeechNetwork[bitIndex].name[127] = '\0';
+ }
+ ALOGV("%s(), mNameForEachSpeechNetwork[%d].name = %s",
+ __FUNCTION__, bitIndex, mNameForEachSpeechNetwork[bitIndex].name);
+ }
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+
+ return size;
+ }
+
+ char *GetNameForEachSpeechNetwork(unsigned char bitIndex) {
+ ALOGD("%s(), mNameForEachSpeechNetwork[%d].name = %s", __FUNCTION__, bitIndex, mNameForEachSpeechNetwork[bitIndex].name);
+ return mNameForEachSpeechNetwork[bitIndex].name;
+ }
+
+ void SetDBGinfoindex10toTestMode(uint16_t dbgindex10) {
+ //uint16_t dbgindex10 = *((uint16_t *)(outBuf->bufferAddr) + count_print + 32);
+
+ switch (dbgindex10) {
+ case 0:
+ strncpy(TestMode, "Default", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 1:
+ strncpy(TestMode, "TMO_FT_F4L", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 2:
+ strncpy(TestMode, "TMO_Lab_AE", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 3:
+ strncpy(TestMode, "ATT_FT_F4L", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 4:
+ strncpy(TestMode, "ATT_Lab_AE", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 5:
+ strncpy(TestMode, "CMCC_FT", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 6:
+ strncpy(TestMode, "CMCC_Lab_AE", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 7:
+ strncpy(TestMode, "CMCC_Benchmark", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 8:
+ strncpy(TestMode, "CT_FT", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 9:
+ strncpy(TestMode, "CT_Lab_AE", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 10:
+ strncpy(TestMode, "CT_Benchmark", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 11:
+ strncpy(TestMode, "CU_FT", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 12:
+ strncpy(TestMode, "CU_Lab_AE", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 13:
+ strncpy(TestMode, "VZW_FT", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 14:
+ strncpy(TestMode, "VZW_Lab", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 15:
+ strncpy(TestMode, "Sprint_FT", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 16:
+ strncpy(TestMode, "Sprint_Lab", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 17:
+ strncpy(TestMode, "TWN_FT", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 18:
+ strncpy(TestMode, "AUX_Mode1", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 19:
+ strncpy(TestMode, "AUX_Mode2", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ case 20:
+ strncpy(TestMode, "AUX_Mode3", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ default:
+ strncpy(TestMode, "Default", TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ break;
+ }
+
+ }
+
+ EXPORT int getParamBuffer(SpHandle * spHandle, SpeechParserAttribute speechParserAttribute, SpeechDataBufType * outBuf) {
+
+ ALOGD("%s, speechParserAttribute inputDevice=%p, outputDevice=%p, idxVolume=%d, driverScenario=%d, speechFeatureOn=%d, ttyMode=%d, outBuf = %p, outBuf->bufferAddr = %p, memorySize=%p, dataSize=%p, TestMode = %s", __FUNCTION__, speechParserAttribute.inputDevice, speechParserAttribute.outputDevice, speechParserAttribute.idxVolume, speechParserAttribute.driverScenario, speechParserAttribute.speechFeatureOn, speechParserAttribute.ttyMode, outBuf, outBuf->bufferAddr, outBuf->memorySize, outBuf->dataSize, TestMode);
+ //ALOGD("%s, outBuf = %p, outBuf->bufferAddr = %p, memorySize=%p, dataSize=%p ", __FUNCTION__, outBuf, outBuf->bufferAddr, outBuf->memorySize, outBuf->dataSize);
+
+ uint32_t MD_version_First, MD_version_Last, MD_version_Last2, MD_version_Last3;
+
+ if (SpeechParserInited == 0) {
+ Init();
+
+ SpeechParserInited = 1;
+ ALOGV("SpeechParser new Init !");
+ }
+
+ MD_version_First = (MD_version >> 12);
+ MD_version_Last = (MD_version >> 8) & (0xF);
+ MD_version_Last2 = (MD_version >> 4) & (0xF);
+ MD_version_Last3 = MD_version & (0xF);
+
+ ALOGD("AP version (XML version) = %d.%d , MD_version = 0x%x = %d.%d.%d.%d", mSpeechParamVerFirst, mSpeechParamVerLast, MD_version, MD_version_First, MD_version_Last, MD_version_Last2, MD_version_Last3);
+
+ //if ((mSpeechParamVerFirst == MD_version_First) && (mSpeechParamVerLast == MD_version_Last)) {
+ // ALOGD("AP(xml) version == MD_version !");
+ //} else {
+ // ALOGD("AP(xml) version != MD_version , version mismatch => use default parameter !");
+ // return -1; //error handle
+ //}
+
+ if ((mSpeechParamVerFirst != MD_version_First) || (mSpeechParamVerLast != MD_version_Last)) {
+ ALOGE("AP(xml) version != MD_version , version mismatch => use default parameter !");
+ return -1; //error handle
+ }
+
+
+ //int EMI_48K_MAX_PAYLOAD_DATA_BYTE = 48 * 1024; // 0xC000 ?
+ int EMI_48K_MAX_PAYLOAD_DATA_BYTE = 64 * 1024; // 0xC000 ?
+ memset(outBuf->bufferAddr, 0, EMI_48K_MAX_PAYLOAD_DATA_BYTE);
+
+ int idxProfile_Speech = 0;
+ uint16_t size = 0, idxCount, sizeByteFromApp = 0;
+ uint16_t numBand = 0, numNetwork = 0, numVolume = 0;
+ int idxVolume = speechParserAttribute.idxVolume;
+ uint16_t EMI_3K_zero = 3 * 1024;
+ uint16_t ParserCheckNum_General_End = 0;
+ uint16_t count_print = 0;
+ int counter;
+
+ //-------------------------------Start General parameter-----------------------------------------------
+
+ SP_SPEECH_PARAM_UNIT_HDR_STRUCT headerParamUnit;
+ memset(&headerParamUnit, 0, sizeof(headerParamUnit));
+
+ headerParamUnit.sphParserVer = ENH_SPH_PARSER_VER;
+ headerParamUnit.ParserCheckingNum = 0x000B;
+ headerParamUnit.SpeechDebugNum = 0x1010;
+ headerParamUnit.Reserved[2] = Parser_time_count;
+ headerParamUnit.Reserved[3] = speechParserAttribute.outputDevice;
+ headerParamUnit.Reserved[4] = (uint16_t)speechParserAttribute.idxVolume;
+ // 5 reserved elements = 0 , Reserved[2] = Parser_time_count; Reserved[3] = speechParserAttribute.outputDevice; Reserved[4] = speechParserAttribute.idxVolume;
+
+ ALOGD("Parser_time_count = %d", Parser_time_count);
+ Parser_time_count++;
+
+ if (Parser_time_count >= 0x100) {
+ Parser_time_count = 0;
+ }
+
+ size += EMI_3K_zero;
+
+ memcpy((char *)outBuf->bufferAddr + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ char *packedParamUnitFromApp = new char[MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp, 0, MAX_BYTE_PARAM_SPEECH);
+
+ PARSER_AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+ memset(¶mLayerInfo, 0, sizeof(PARSER_AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT));
+
+ paramLayerInfo.audioTypeName = (char *)Parser_audioTypeNameList[PARSER_AUDIO_TYPE_SPEECH_GENERAL];
+ paramLayerInfo.numCategoryType = MAX_NUM_CATEGORY_TYPE_SPEECH_GENERAL;//4
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_GENERAL;//4
+
+ paramLayerInfo.categoryType.assign(audioType_SpeechGeneral_CategoryType, audioType_SpeechGeneral_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechGeneral_ParamName, audioType_SpeechGeneral_ParamName + paramLayerInfo.numParam);
+
+ paramLayerInfo.categoryName.push_back(String8(audioType_SpeechGeneral_CategoryName1[0]));
+
+ GetSpeechParamFromAppParser_new(PARSER_AUDIO_TYPE_SPEECH_GENERAL, ¶mLayerInfo, packedParamUnitFromApp, &sizeByteFromApp, 1);
+
+ memcpy((char *)outBuf->bufferAddr + size, packedParamUnitFromApp, sizeByteFromApp);
+ size += sizeByteFromApp;
+
+ //Set Reserved parameters
+ size += 60;
+
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+
+ ParserCheckNum_General_End = 0x0B0B;
+ memcpy((char *)outBuf->bufferAddr + size, &ParserCheckNum_General_End, sizeof(ParserCheckNum_General_End));
+ size += sizeof(ParserCheckNum_General_End);
+ //For reserved
+ size += 6;
+
+ //print the Common parameters , skip EMI and print 0~37
+ //for (count_print = EMI_3K_zero / 2 + 0; count_print < EMI_3K_zero / 2 + 8; count_print++) {
+ // ALOGD("Common, SpeechParam->data [%d] = %p", count_print, *((uint16_t *)(outBuf->bufferAddr) + count_print));
+ //}
+
+ count_print = EMI_3K_zero / 2 + 0;
+
+ SetDBGinfoindex10toTestMode(*((uint16_t *)(outBuf->bufferAddr) + count_print + 32)); //Use DBGinfo index10 value to set TestMode string
+
+ ALOGD("Common, SpeechParam->data [%d] = %p, %p, %p, %p, %p, %p, %p, %p Common ParserCheckingNumEnd [%d] = %p , DebugInfo index10 = %d , TestMode = %s", count_print, *((uint16_t *)(outBuf->bufferAddr) + count_print), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 1)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 2)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 3)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 4)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 5)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 6)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 7)), EMI_3K_zero / 2 + 68, *((uint16_t *)outBuf->bufferAddr + (EMI_3K_zero / 2 + 68)), *((uint16_t *)(outBuf->bufferAddr) + count_print + 32), TestMode);
+
+ //ALOGD(" Common ParserCheckingNumEnd [%d] = %p", EMI_3K_zero / 2 + 68, *((uint16_t *)outBuf->bufferAddr + (EMI_3K_zero / 2 + 68)));
+
+ //End of setting Common Param ****************************************************************************
+
+ //Start setting DMNR format-----------------------------------------------------------------------
+
+ //Start setting DMNR format
+ uint16_t ParserCheckNum_DMNR_End = 0, OutDevice_VoiceBand = 0;
+ uint16_t idxBand = 0, idxProfile = 0;
+ uint16_t numProfile = 0;
+ numBand = 0;
+
+ memset(&headerParamUnit, 0, sizeof(headerParamUnit));
+
+ headerParamUnit.sphParserVer = ENH_SPH_PARSER_VER;
+ headerParamUnit.ParserCheckingNum = 0x000C;
+ headerParamUnit.SpeechDebugNum = 0x1010;
+ // 5 reserved elements = 0
+
+ memcpy((char *)outBuf->bufferAddr + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ memset(¶mLayerInfo, 0, sizeof(PARSER_AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT));
+
+ paramLayerInfo.audioTypeName = (char *)Parser_audioTypeNameList[PARSER_AUDIO_TYPE_SPEECH_DMNR];
+ paramLayerInfo.numCategoryType = MAX_NUM_CATEGORY_TYPE_SPEECH_DMNR;//4
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_DMNR;//4
+ paramLayerInfo.categoryType.assign(audioType_SpeechDMNR_CategoryType, audioType_SpeechDMNR_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechDMNR_ParamName, audioType_SpeechDMNR_ParamName + paramLayerInfo.numParam);
+
+ AppOps *appOps = appOpsGetInstance();
+ AudioType *audioType = NULL;
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ } else {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo.audioTypeName);
+ }
+
+ char *packedParamUnitFromApp_DMNR = new char[MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp_DMNR, 0, MAX_BYTE_PARAM_SPEECH);
+
+ CategoryType *categoryBand = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_SpeechDMNR_CategoryType[0].string());
+ numBand = appOps->categoryTypeGetNumOfCategory(categoryBand);
+ CategoryType *categoryProfile = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_SpeechDMNR_CategoryType[1].string());
+ numProfile = appOps->categoryTypeGetNumOfCategory(categoryProfile);
+
+ for (idxBand = 0; idxBand < numBand; idxBand++) { //NB, WB, SWB
+ for (idxProfile = 0; idxProfile < numProfile; idxProfile++) {
+ sizeByteFromApp = 0;
+
+ Category *CateBand = appOps->categoryTypeGetCategoryByIndex(categoryBand, idxBand);
+ paramLayerInfo.categoryName.push_back(String8(CateBand->name));//Band
+ paramLayerInfo.categoryName.push_back(String8(audioType_SpeechDMNR_CategoryName2[idxProfile]));//Profile
+
+ OutDevice_VoiceBand = ((1 << idxBand) << 12) + (idxProfile + 1);
+ memcpy((char *)outBuf->bufferAddr + size, &OutDevice_VoiceBand, sizeof(OutDevice_VoiceBand));
+ size += sizeof(OutDevice_VoiceBand);
+
+ GetSpeechParamFromAppParser_new(PARSER_AUDIO_TYPE_SPEECH_DMNR, ¶mLayerInfo, packedParamUnitFromApp_DMNR, &sizeByteFromApp, 1);
+
+ memcpy((char *)outBuf->bufferAddr + size, packedParamUnitFromApp_DMNR, sizeByteFromApp);
+ size += sizeByteFromApp;
+
+ paramLayerInfo.categoryName.pop_back();
+ paramLayerInfo.categoryName.pop_back();
+
+ }
+ }
+ if (numBand == 2) { // Doesn't add SWB,FB OutputDevice Type.....0602, if we have SWB XML, modify here
+ size += (242 * 4) * 2; //Bytes reserve for SWB ,FB
+ } else if (numBand == 3) {
+ size += (242 * 2) * 2; //Bytes reserve for FB
+ }
+
+ if (packedParamUnitFromApp_DMNR != NULL) {
+ delete[] packedParamUnitFromApp_DMNR;
+ }
+
+ ParserCheckNum_DMNR_End = 0x0C0C;
+ memcpy((char *)outBuf->bufferAddr + size, &ParserCheckNum_DMNR_End, sizeof(ParserCheckNum_DMNR_End));
+ size += sizeof(ParserCheckNum_DMNR_End);
+ //For reserved
+ size += 6;
+
+ //1~8 DMNR mode param
+ //for (count_print = (EMI_3K_zero / 2 + 72); count_print < (EMI_3K_zero / 2 + 72) + 8; count_print++) {
+ // ALOGD("DMNR, SpeechParam->data [%d] = %p", count_print, *((uint16_t *)(outBuf->bufferAddr) + count_print));
+ //}
+ count_print = (EMI_3K_zero / 2 + 72);
+ ALOGD("DMNR, SpeechParam->data [%d] = %p, %p, %p, %p, %p, %p, %p, %p", count_print, *((uint16_t *)(outBuf->bufferAddr) + count_print), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 1)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 2)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 3)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 4)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 5)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 6)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 7)));
+
+ //End of setting DMNR Param******************************************************************************
+
+ // START MagiClarity-------------------------------------------------------------------
+ uint16_t ParserCheckNum_MagiClarity_End = 0;
+
+ memset(&headerParamUnit, 0, sizeof(headerParamUnit));
+
+ headerParamUnit.sphParserVer = ENH_SPH_PARSER_VER;
+ headerParamUnit.ParserCheckingNum = 0x000D;
+ headerParamUnit.SpeechDebugNum = 0x1010;
+ // 5 reserved elements = 0
+
+ memcpy((char *)outBuf->bufferAddr + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ char *packedParamUnitFromApp_MagiClarity = new char[MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp_MagiClarity, 0, MAX_BYTE_PARAM_SPEECH);
+
+ memset(¶mLayerInfo, 0, sizeof(PARSER_AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT));
+
+ paramLayerInfo.audioTypeName = (char *)Parser_audioTypeNameList[PARSER_AUDIO_TYPE_SPEECH_MAGICLARITY];
+ paramLayerInfo.numCategoryType = MAX_NUM_CATEGORY_TYPE_SPEECH_MAGICLARITY;//4
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_MAGICLARITY;//4
+
+ paramLayerInfo.categoryType.assign(audioType_SpeechMagiClarity_CategoryType, audioType_SpeechMagiClarity_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechMagiClarity_ParamName, audioType_SpeechMagiClarity_ParamName + paramLayerInfo.numParam);
+
+ for (idxCount = 0; idxCount < paramLayerInfo.paramName.size(); idxCount++) {
+ ALOGV("%s(), paramName[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.paramName.at(idxCount).string());
+ }
+
+ paramLayerInfo.categoryName.push_back(String8(audioType_SpeechMagiClarity_CategoryName1[0]));
+
+ sizeByteFromApp = 0;
+ GetSpeechParamFromAppParser_new(PARSER_AUDIO_TYPE_SPEECH_MAGICLARITY, ¶mLayerInfo, packedParamUnitFromApp_MagiClarity, &sizeByteFromApp, 1);
+
+ memcpy((char *)outBuf->bufferAddr + size, packedParamUnitFromApp_MagiClarity, sizeByteFromApp);
+ size += sizeByteFromApp;
+
+ //Set Reserved parameters
+ size += 60;
+
+ if (packedParamUnitFromApp_MagiClarity != NULL) {
+ delete[] packedParamUnitFromApp_MagiClarity;
+ }
+
+ ParserCheckNum_MagiClarity_End = 0x0D0D;
+ memcpy((char *)outBuf->bufferAddr + size, &ParserCheckNum_MagiClarity_End, sizeof(ParserCheckNum_MagiClarity_End));
+ size += sizeof(ParserCheckNum_MagiClarity_End);
+ //For reserved
+ size += 6;
+
+ //for (count_print = EMI_3K_zero / 2 + 72 + 1468; count_print < EMI_3K_zero / 2 + 72 + 1468 + 8; count_print++) {
+ // ALOGD("Magiclarity, SpeechParam->data [%d] = %p", count_print, *((uint16_t *)(outBuf->bufferAddr) + count_print));
+ //}
+
+ count_print = EMI_3K_zero / 2 + 72 + 1468;
+ ALOGD("Magiclarity, SpeechParam->data [%d] = %p, %p, %p, %p, %p, %p, %p, %p", count_print, *((uint16_t *)(outBuf->bufferAddr) + count_print), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 1)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 2)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 3)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 4)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 5)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 6)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 7)));
+ // END of MagiClarity-------------------------------------------------------------------
+
+ //Start setting Speech Param---------------------------------------------------------------------------
+ uint16_t ParserCheckNum_Speech_End = 0, VoiceBand_Network = 0;
+
+ memset(&headerParamUnit, 0, sizeof(headerParamUnit));
+
+ headerParamUnit.sphParserVer = ENH_SPH_PARSER_VER;
+ headerParamUnit.ParserCheckingNum = 0x000A;
+ headerParamUnit.SpeechDebugNum = 0x1010;
+ // 5 reserved elements = 0
+
+ memcpy((char *)outBuf->bufferAddr + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ idxProfile_Speech = SP_GetSpeechProfile(speechParserAttribute);
+
+ //2. xml working structure
+ memset(¶mLayerInfo, 0, sizeof(PARSER_AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT));
+ //-------------
+ paramLayerInfo.audioTypeName = (char *)Parser_audioTypeNameList[PARSER_AUDIO_TYPE_SPEECH];
+
+ //3. get app handle
+ if (mAppHandle == NULL) {
+ ALOGE("%s() mAppHandle == NULL, Assert!!!", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ //4. get xml
+ // Query AudioType
+ appOps = appOpsGetInstance();
+ audioType = NULL;
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ } else {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo.audioTypeName);
+ }
+
+ //5 internal working buffer
+ char *packedParamUnitFromApp_Speech = new char[MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp_Speech, 0, MAX_BYTE_PARAM_SPEECH);
+
+ //4 layers
+ paramLayerInfo.numCategoryType = appOps->audioTypeGetNumOfCategoryType(audioType);//4
+ //paramLayerInfo.numParam = numSpeechParam;// 7 kinds of parameters
+ paramLayerInfo.numParam = 7;
+
+ //push category name "Band","Profile","VolIndex","Network"
+ paramLayerInfo.categoryType.assign(audioType_Speech_CategoryType, audioType_Speech_CategoryType + paramLayerInfo.numCategoryType);
+ //store "speech_mode_para","sph_in_fir","sph_out_fir","sph_in_iir_mic1_dsp","sph_in_iir_mic2_dsp","sph_in_iir_enh_dsp","sph_out_iir_enh_dsp"
+ paramLayerInfo.paramName.assign(audioType_Speech_ParamName, audioType_Speech_ParamName + paramLayerInfo.numParam);
+
+ //parse layer
+ //network ¦WNetwork
+ CategoryType *categoryNetwork = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_Speech_CategoryType[3].string());
+ //band name
+ categoryBand = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_Speech_CategoryType[0].string());
+ //band number
+ numBand = appOps->categoryTypeGetNumOfCategory(categoryBand);
+
+ //network number
+ numNetwork = appOps->categoryTypeGetNumOfCategory(categoryNetwork);
+ //volume name
+ CategoryType *categoryVolume = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_Speech_CategoryType[2].string());
+ CategoryGroup *categoryGroupVolume = appOps->categoryTypeGetCategoryGroupByIndex(categoryVolume, 0);
+ numVolume = appOps->categoryGroupGetNumOfCategory(categoryGroupVolume);
+
+ //log buffer
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ for (int idxNetwork = 0; idxNetwork < 8; idxNetwork++) {//ºô¸ôbit0~7
+ char *nameNetwork = GetNameForEachSpeechNetwork(idxNetwork); //bit 0 "GSM",... put each network name to this
+
+ Category *CateNetwork = appOps->categoryTypeGetCategoryByName(categoryNetwork, nameNetwork);
+ //Category *CateNetwork = appOps->categoryTypeGetCategoryByIndex(categoryNetwork, idxNetwork);
+
+ ALOGV("Ver 1, Network bit %d , name = %s, nameNetwork = %s", idxNetwork, CateNetwork->name, nameNetwork);
+
+ if (idxNetwork == 2) { //idxNetwork 2~4 in 2nd EMI 13K
+ size = (16 + 3) * 1024;
+ } else if (idxNetwork == 5) { //idxNetwork 5~7 in 3nd EMI 13K
+ size = (16 + 16 + 3) * 1024;
+ }
+
+ //parse band
+ for (int idxBand = 0; idxBand < numBand; idxBand++) {
+ sizeByteFromApp = 0;
+ Category *CateBand = appOps->categoryTypeGetCategoryByIndex(categoryBand, idxBand);
+
+ VoiceBand_Network = SetMDParamDataHdr_SP(CateBand, CateNetwork); //set DataHdr Band, Network
+ memcpy((char *)outBuf->bufferAddr + size, &VoiceBand_Network, sizeof(VoiceBand_Network));
+ size += sizeof(VoiceBand_Network);
+
+ while (!paramLayerInfo.categoryName.empty()) {
+ paramLayerInfo.categoryName.pop_back();
+ }
+ //Band
+ paramLayerInfo.categoryName.push_back(String8(CateBand->name));//Band
+ //Profile
+ if (strcmp(TestMode, "Default") != 0) {
+ //ALOGD("TestMode = %s != Default", TestMode);
+ paramLayerInfo.categoryName.push_back(String8(TestMode));
+ } else {
+ paramLayerInfo.categoryName.push_back(String8(audioType_Speech_CategoryName2[idxProfile_Speech]));
+
+ }
+
+ //Volume
+ if (idxVolume > 6 || idxVolume < 0) {
+ paramLayerInfo.categoryName.push_back(String8(audioType_Speech_CategoryName3[3]));//volume
+ ALOGE("%s(), Invalid IdxVolume=0x%x, use 3 !!!", __FUNCTION__, idxVolume);
+ } else {
+ paramLayerInfo.categoryName.push_back(String8(audioType_Speech_CategoryName3[idxVolume]));
+ }
+ paramLayerInfo.categoryName.push_back(String8(nameNetwork));//Network
+
+ for (idxCount = 0; idxCount < paramLayerInfo.categoryName.size(); idxCount++) {
+ ALOGV("%s(), categoryName[%d]= %s",
+ __FUNCTION__, idxCount, paramLayerInfo.categoryName.at(idxCount).string());
+ }
+
+ //For fix log too much issue, only print idxNetwork = 0 => "GSM" network parameter
+ //If Customer request different network for different param, open the dump
+ if (idxNetwork == 0) {
+ GetSpeechParamFromAppParser_new(PARSER_AUDIO_TYPE_SPEECH, ¶mLayerInfo, packedParamUnitFromApp_Speech, &sizeByteFromApp, 1);
+ } else {
+ GetSpeechParamFromAppParser_new(PARSER_AUDIO_TYPE_SPEECH, ¶mLayerInfo, packedParamUnitFromApp_Speech, &sizeByteFromApp, 0);
+ }
+
+ memcpy((char *)outBuf->bufferAddr + size, packedParamUnitFromApp_Speech, sizeByteFromApp);
+ size += sizeByteFromApp;
+
+ size = size + (91 + 43) * 2; //reserve for FIR UL2, Enh IIR UL2
+
+ size += 60; //reserve 30 words
+
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = { 0 };
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "size(b)=%d; total size(b)=%d", sizeByteFromApp, size);
+ strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE - 1);
+ }
+ size += 540 * 2; //Bytes reserve for FB
+ }
+
+ ParserCheckNum_Speech_End = 0x0A0A;
+ memcpy((char *)outBuf->bufferAddr + size, &ParserCheckNum_Speech_End, sizeof(ParserCheckNum_Speech_End));
+ size += sizeof(ParserCheckNum_Speech_End);
+ //For reserved
+ size += 6;
+
+ //End of setting Speech Param*******************************************************************************
+
+ if (packedParamUnitFromApp_Speech != NULL) {
+ delete[] packedParamUnitFromApp_Speech;
+ }
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+
+ outBuf->memorySize = SD_SphParamSize; // 48K, 0xC000
+ outBuf->dataSize = SD_SphParamSize; // 48K, 0xC000
+
+ //for (count_print = (EMI_3K_zero / 2 + 72 + 1468 + 75); count_print < (EMI_3K_zero / 2 + 72 + 1468 + 75) + 8; count_print++) {
+ // ALOGD("Speech, SpeechParam->data [%d] = %p", count_print, *((uint16_t *)(outBuf->bufferAddr) + count_print));
+ //}
+ count_print = (EMI_3K_zero / 2 + 72 + 1468 + 75);
+ ALOGD("Speech, SpeechParam->data [%d] = %p, %p, %p, %p, %p, %p, %p, %p, End of getParamBuffer, outBuf->dataSize = %d ", count_print, *((uint16_t *)(outBuf->bufferAddr) + count_print), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 1)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 2)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 3)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 4)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 5)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 6)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 7)), outBuf->dataSize);
+
+ //ALOGD("End of getParamBuffer, outBuf->dataSize = %d", outBuf->dataSize);
+
+ //Start setting DEREVERB format-----------------------------------------------------------------------------------------
+ ALOGD("[DEREVERB Parsing Start]");
+
+ uint16_t ParserCheckNum_DEREVERB_End = 0;
+
+ OutDevice_VoiceBand = 0;
+ idxBand = 0;
+ idxProfile = 0;
+ numProfile = 0;
+ numBand = 0;
+
+ memset(&headerParamUnit, 0, sizeof(headerParamUnit));
+
+ headerParamUnit.sphParserVer = ENH_SPH_PARSER_VER;
+ headerParamUnit.ParserCheckingNum = 0x000E;
+ headerParamUnit.SpeechDebugNum = 0x1010;
+ // 5 reserved elements = 0
+
+ size = (16 + 16 + 16 + 3) * 1024; //using a new page for Dereverb since the pervious pages are full
+ memcpy((char *)outBuf->bufferAddr + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ memset(¶mLayerInfo, 0, sizeof(PARSER_AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT));
+
+ paramLayerInfo.audioTypeName = (char *)Parser_audioTypeNameList[PARSER_AUDIO_TYPE_SPEECH_DEREVERB];
+ paramLayerInfo.numCategoryType = MAX_NUM_CATEGORY_TYPE_SPEECH_DEREVERB;
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_DEREVERB;
+ paramLayerInfo.categoryType.assign(audioType_SpeechDereverb_CategoryType, audioType_SpeechDereverb_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechDereverb_ParamName, audioType_SpeechDereverb_ParamName + paramLayerInfo.numParam);
+
+ appOps = appOpsGetInstance();
+ audioType = NULL;
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ } else {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo.audioTypeName);
+ }
+
+ char *packedParamUnitFromApp_Dereverb = new char[MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp_Dereverb, 0, MAX_BYTE_PARAM_SPEECH);
+
+ categoryBand = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_SpeechDereverb_CategoryType[0].string());
+ numBand = appOps->categoryTypeGetNumOfCategory(categoryBand);
+ categoryProfile = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_SpeechDereverb_CategoryType[1].string());
+ numProfile = appOps->categoryTypeGetNumOfCategory(categoryProfile);
+
+ for (idxBand = 0; idxBand < numBand; idxBand++) { //NB, WB, SWB
+ for (idxProfile = 0; idxProfile < numProfile; idxProfile++) {
+ sizeByteFromApp = 0;
+
+ Category *CateBand = appOps->categoryTypeGetCategoryByIndex(categoryBand, idxBand);
+ paramLayerInfo.categoryName.push_back(String8(CateBand->name));//Band
+ paramLayerInfo.categoryName.push_back(String8(audioType_SpeechDereverb_CategoryName2[idxProfile]));//Profile
+
+ OutDevice_VoiceBand = ((1 << idxBand) << 12) + (idxProfile + 1);
+ memcpy((char *)outBuf->bufferAddr + size, &OutDevice_VoiceBand, sizeof(OutDevice_VoiceBand));
+ size += sizeof(OutDevice_VoiceBand);
+
+ GetSpeechParamFromAppParser_new(PARSER_AUDIO_TYPE_SPEECH_DEREVERB, ¶mLayerInfo, packedParamUnitFromApp_Dereverb, &sizeByteFromApp, 1);
+
+ memcpy((char *)outBuf->bufferAddr + size, packedParamUnitFromApp_Dereverb, sizeByteFromApp);
+ size += sizeByteFromApp;
+
+ paramLayerInfo.categoryName.pop_back();
+ paramLayerInfo.categoryName.pop_back();
+
+ }
+ }
+
+ if (packedParamUnitFromApp_Dereverb != NULL) {
+ delete[] packedParamUnitFromApp_Dereverb;
+ }
+
+ ParserCheckNum_DEREVERB_End = 0x0E0E;
+ memcpy((char *)outBuf->bufferAddr + size, &ParserCheckNum_DEREVERB_End, sizeof(ParserCheckNum_DEREVERB_End));
+ size += sizeof(ParserCheckNum_DEREVERB_End);
+
+ count_print = (16 + 16 + 16 + 3) * 1024/2;
+ ALOGD("DEREVERB, SpeechParam->data [%d] = %p, %p, %p, %p, %p, %p, %p, %p", count_print, *((uint16_t *)(outBuf->bufferAddr) + count_print), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 1)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 2)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 3)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 4)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 5)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 6)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 7)));
+
+
+ return 0; //general case, return 0 when AP&MD version mismatch, use default param, return -1
+ }
+
+ EXPORT int setKeyValuePair(SpHandle * spHandle, const SpeechStringBufType * keyValuePair) {
+ ALOGD("+%s(): %s", __FUNCTION__, keyValuePair->stringAddr);
+
+ if (keyValuePair->stringAddr == NULL) {
+ ALOGD("%s() keyValuePair->stringAddr == NULL, Assert!!!", __FUNCTION__);
+ }
+
+ char *keyHeader = NULL;
+ char *keyString = NULL;
+ keyHeader = strtok_r(keyValuePair->stringAddr, ",", &keyString);
+
+ //ex:TestMode,TMO_FT_F4L
+ if (strcmp(keyHeader, "TestMode") == 0) {
+ strncpy(TestMode, keyString, TESTMODE_MAX_LENGTH);
+ TestMode[TESTMODE_MAX_LENGTH - 1] = '\0';
+ ALOGD("+%s(): TestMode = %s", __FUNCTION__, TestMode);
+ return 0;
+ } else if (strcmp(keyHeader, SPEECH_PARSER_SET_KEY_PREFIX) != 0) {
+ ALOGE("%s(), Wrong Header: %s, expect:%s", __FUNCTION__, keyHeader, SPEECH_PARSER_SET_KEY_PREFIX);
+ return -EINVAL;
+ }
+
+ AudioParameter param = AudioParameter(String8(keyString));
+ int value;
+
+ if (param.getInt(String8("MDVERSION"), value) == NO_ERROR) {
+ param.remove(String8("MDVERSION"));
+ MD_version = value;
+ ALOGD("%s(): MD_version = 0x%x", __FUNCTION__, MD_version);
+ }
+
+ return 0;
+ }
+
+ EXPORT int getKeyValuePair(SpHandle * spHandle, SpeechStringBufType * keyValuePair) {
+ ALOGD("%s(), keyString:%s", __FUNCTION__, keyValuePair->stringAddr);
+
+ if (keyValuePair->stringAddr == NULL) {
+ ALOGD("%s() keyValuePair->stringAddr == NULL, Assert!!!", __FUNCTION__);
+ }
+
+ char *keyHeader = NULL;
+ char *keyString = NULL;
+ keyHeader = strtok_r(keyValuePair->stringAddr, ",", &keyString);
+
+ if (strcmp(keyHeader, "TestMode") == 0) {
+ keyValuePair->stringAddr = TestMode;
+ ALOGD("%s(), return keyString:%s", __FUNCTION__, keyValuePair->stringAddr);
+
+ return 0;
+ } else if (strcmp(keyHeader, SPEECH_PARSER_GET_KEY_PREFIX) != 0) {
+ ALOGE("%s(), Wrong Header: %s, expect:%s", __FUNCTION__, keyHeader, SPEECH_PARSER_GET_KEY_PREFIX);
+ return -EINVAL;
+ }
+
+ char keyValueString[MAX_SPEECH_PARSER_KEY_LEN];
+ memset((void *)keyValueString, 0, MAX_SPEECH_PARSER_KEY_LEN);
+
+ if (strcmp(keyString, String8("PARAMBUF_SIZE")) == 0) {
+ sprintf(keyValueString, "%d", SD_SphParamSize);
+ }
+ memset(keyValuePair->stringAddr, 0, MAX_SPEECH_PARSER_KEY_LEN);
+ strncpy(keyValuePair->stringAddr, keyValueString, strlen(keyValueString));
+ ALOGD("%s(), return keyString:%s", __FUNCTION__, keyValuePair->stringAddr);
+
+ return 0;
+ }
+
+}
+};
+
+//namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/ENH_Parser/SpeechParser.h b/src/multimedia/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/ENH_Parser/SpeechParser.h
new file mode 100644
index 0000000..c0a7649
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/ENH_Parser/SpeechParser.h
@@ -0,0 +1,374 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef _SPEECH_PARSER_H_
+#define _SPEECH_PARSER_H_
+
+/*****************************************************************************
+* E X T E R N A L R E F E R E N C E S
+******************************************************************************
+*/
+#include "AudioType.h"
+#include <unistd.h>
+#include <vector>
+#include "AudioParamParser.h"
+#include "SpeechParserType.h"
+#include "SpeechFeatureDef.h"
+
+#include "utstring.h"
+#include "uthash.h"
+#include "utlist.h"
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <utils/Log.h>
+
+#include <utils/String8.h>
+#include <media/AudioParameter.h>
+#include "AudioParamParser.h"
+
+
+
+namespace android {
+
+/*****************************************************************************
+* I O C T R L M E S S A G E S
+******************************************************************************
+*/
+
+#define EXPORT
+extern "C" {
+
+ /*****************************************************************************
+ * I O C T R L M E S S A G E S
+ ******************************************************************************
+ */
+
+
+ //Define Struct AudioType
+#ifndef int8_t
+ typedef signed char int8_t;
+#endif
+
+#ifndef uint8_t
+ typedef unsigned char uint8_t;
+#endif
+
+#ifndef int16_t
+ typedef signed short int16_t;
+#endif
+
+#ifndef uint16_t
+ typedef unsigned short uint16_t;
+#endif
+
+#ifndef int32_t
+ typedef signed int int32_t;
+#endif
+
+#ifndef uint32_t
+ typedef unsigned int uint32_t;
+#endif
+
+#ifndef status_t
+ typedef signed int status_t;
+#endif
+
+ //Define Struct SpeechType
+
+ enum speech_mode_SP {
+ PARSER_SPEECH_MODE_NORMAL = 0,
+ PARSER_SPEECH_MODE_EARPHONE = 1,
+ PARSER_SPEECH_MODE_LOUD_SPEAKER = 2,
+ PARSER_SPEECH_MODE_BT_EARPHONE = 3,
+ PARSER_SPEECH_MODE_BT_CORDLESS = 4,
+ PARSER_SPEECH_MODE_BT_CARKIT = 5,
+ PARSER_SPEECH_MODE_MAGIC_CON_CALL = 6,
+ PARSER_SPEECH_MODE_PRESERVED_2 = 7,
+ PARSER_SPEECH_MODE_HAC = 8,
+ PARSER_SPEECH_MODE_USB_AUDIO = 9,
+ PARSER_SPEECH_MODE_NO_CONNECT = 10
+ };
+
+
+ enum speech_type_dynamic_param_SP {
+ PARSER_AUDIO_TYPE_SPEECH = 0,
+ PARSER_AUDIO_TYPE_SPEECH_DMNR = 1,
+ PARSER_AUDIO_TYPE_SPEECH_GENERAL = 2,
+ PARSER_AUDIO_TYPE_SPEECH_MAGICLARITY = 3,
+ PARSER_AUDIO_TYPE_SPEECH_NETWORK = 4,
+ PARSER_AUDIO_TYPE_SPEECH_ECHOREF = 5,
+ PARSER_AUDIO_TYPE_SPEECH_DEREVERB = 6,
+
+
+ PARSER_NUM_AUDIO_TYPE_SPEECH_TYPE // the #types of speech_type_dynamic_param_t
+ };
+
+
+
+
+ const char Parser_audioTypeNameList[8][128] = {
+ "Speech",
+ "SpeechDMNR",
+ "SpeechGeneral",
+ "SpeechMagiClarity",
+ "SpeechNetwork",
+ "SpeechEchoRef",
+ "SpeechDeReverb"
+ };
+
+ /*****************************************************************************
+ * I O C T R L M E S S A G E S
+ ******************************************************************************
+ */
+
+
+
+ typedef struct _PARSER_AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT {
+ char *audioTypeName;
+ char numCategoryType;//4
+ std::vector<String8> categoryType;
+ std::vector<String8> categoryName;
+ char numParam;//4
+ std::vector<String8> paramName;
+ char *logPrintParamUnit;
+ } PARSER_AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT;
+
+ enum speech_profile_SP {
+ PARSER_SPEECH_PROFILE_HANDSET = 0,
+ PARSER_SPEECH_PROFILE_4_POLE_HEADSET = 1,
+ PARSER_SPEECH_PROFILE_HANDSFREE = 2,
+ PARSER_SPEECH_PROFILE_BT_EARPHONE = 3,
+ PARSER_SPEECH_PROFILE_BT_NREC_OFF = 4,
+ PARSER_SPEECH_PROFILE_MAGICONFERENCE = 5,
+ PARSER_SPEECH_PROFILE_HAC = 6,
+ PARSER_SPEECH_PROFILE_LPBK_HANDSET = 7,
+ PARSER_SPEECH_PROFILE_LPBK_HEADSET = 8,
+ PARSER_SPEECH_PROFILE_LPBK_HANDSFREE = 9,
+ PARSER_SPEECH_PROFILE_3_POLE_HEADSET = 10,
+ PARSER_SPEECH_PROFILE_5_POLE_HEADSET = 11,
+ PARSER_SPEECH_PROFILE_5_POLE_HEADSET_ANC = 12,
+ PARSER_SPEECH_PROFILE_USB_HEADSET = 13,
+ PARSER_SPEECH_PROFILE_HANDSET_SV = 14,
+ PARSER_SPEECH_PROFILE_HANDSFREE_SV = 15,
+ PARSER_SPEECH_PROFILE_TTY_HCO_HANDSET = 16,
+ PARSER_SPEECH_PROFILE_TTY_HCO_HANDSFREE = 17,
+ PARSER_SPEECH_PROFILE_TTY_VCO_HANDSET = 18,
+ PARSER_SPEECH_PROFILE_TTY_VCO_HANDSFREE = 19,
+
+ PARSER_SPEECH_PROFILE_MAX_NUM = 20
+ };
+
+ typedef struct _PARSER_SPEECH_PARAM_SUPPORT_STRUCT {
+ bool isNetworkSupport;
+ bool isTTYSupport;
+ bool isSuperVolumeSupport;
+
+ } PARSER_SPEECH_PARAM_SUPPORT_STRUCT;
+
+ typedef struct _PARSER_SPEECH_NETWORK_STRUCT {
+ char name[128];
+ uint16_t supportBit;//4
+
+ } PARSER_SPEECH_NETWORK_STRUCT;
+
+
+ enum tty_param_t_SP {
+ PARSER_TTY_PARAM_OFF = 0,
+ PARSER_TTY_PARAM_HCO = 1,
+ PARSER_TTY_PARAM_VCO = 2
+ };
+
+
+ // Self define struct ( Parser_Info_Struct )
+
+
+ typedef struct _SPEECH_PARAM_INFO {
+ speech_mode_SP SpeechMode;
+ unsigned int u4VolumeIndex;
+ bool bBtHeadsetNrecOn;
+ bool bLPBK;
+ unsigned char uHeadsetPole;
+ bool bSV;
+ unsigned char idxTTY;
+
+ bool isSingleBandTransfer;
+ unsigned char IndexVoiceBandStart;
+
+ } SPEECH_PARAM_INFO;
+
+ typedef struct _Parser_Info_Struct {
+ char *Buffer;
+ SPEECH_PARAM_INFO SphParamInfo_SP;
+ uint16_t MD_version;
+ SpeechScenario Scenario;
+
+ uint32_t CommonInfo_offset;
+ uint32_t DebugInfo_offset;
+
+ speech_type_dynamic_param_SP AP_version;
+ uint16_t Network;
+ uint32_t Buffer_length;
+ } Parser_Info_Struct;
+
+
+ typedef struct _SP_SPEECH_PARAM_UNIT_HDR {
+ uint16_t sphParserVer;
+ uint16_t ParserCheckingNum;
+ uint16_t SpeechDebugNum;
+ uint16_t Reserved[5]; //2 +3
+
+ } SP_SPEECH_PARAM_UNIT_HDR_STRUCT;
+
+
+
+ // Global variable/function public
+
+
+ void Init();
+ void InitAppParser();
+ int InitSpeechNetwork();
+
+
+ uint16_t sizeByteParaData(DATA_TYPE dataType, uint16_t arraySize);
+
+ uint16_t SetMDParamDataHdr_SP(Category *cateBand, Category *cateNetwork);
+
+ bool getFeatureOn(const SpeechFeatureType featureType, const uint16_t speechFeatureOn);
+
+ speech_profile_SP SP_GetSpeechProfile(const SpeechParserAttribute speechParserAttribute);
+
+ char *GetNameForEachSpeechNetwork(unsigned char bitIndex);
+
+ status_t SpeechDataDump_new(char *bufDump, uint16_t idxSphType, const char *nameParam, const char *speechParamData);
+ status_t GetSpeechParamFromAppParser_new(uint16_t idxSphType, PARSER_AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT *paramLayerInfo, char *bufParamUnit, uint16_t *sizeByteTotal, uint16_t Dump_Flag);
+
+ void SetDBGinfoindex10toTestMode(uint16_t dbgindex10);
+ /*****************************************************************************
+ * F U N C T I O N S
+ ******************************************************************************
+ */
+
+#define SP_LIB_NAME "libspeechparser_vendor.so"
+ typedef enum {
+ SP_ERROR = 0,
+ SP_NO_ERROR = 1,
+ } SP_STATUS;
+
+ struct _SpHandle {
+ pthread_rwlock_t lock;
+ pthread_rwlock_t notifyLock;
+ };
+
+ typedef struct _SpHandle SpHandle;
+
+ typedef struct SpOps {
+ void *handle;
+ SpHandle *(*spHandleGetInstance)(void);
+
+ SP_STATUS(*spHandleInit)(SpHandle *spHandle);
+ SP_STATUS(*spHandleUninit)(SpHandle *spHandle);
+
+ int(*getParamBuffer)(SpHandle *spHandle, SpeechParserAttribute speechParserAttribute, SpeechDataBufType *outBuf);
+ int(*setKeyValuePair)(SpHandle *spHandle, const SpeechStringBufType *keyValuePair);
+ int(*getKeyValuePair)(SpHandle *spHandle, SpeechStringBufType *keyValuePair);
+
+ } SpOps;
+
+
+ static SpOps spOps;
+ static short spOpsInited = 0;
+ EXPORT static SpOps *spOpsGetInstance(void) {
+ const char *error;
+ const char *funName = NULL;
+
+ if (spOpsInited == 0) {
+ ALOGD("%s(), init SpOps struct, lib is %s", __FUNCTION__, SP_LIB_NAME);
+
+ /* dlopen */
+ ALOGD("Go to dlopen");
+ spOps.handle = dlopen(SP_LIB_NAME, RTLD_LAZY);
+ if (!spOps.handle) {
+ ALOGE("%s(), dlopen fail! (%s)\n", __FUNCTION__, dlerror());
+ return NULL;
+ }
+ dlerror(); /* Clear any existing error */
+
+
+ ALOGD("Go to spHandleGetInstance");
+ funName = "spHandleGetInstance";
+ spOps.spHandleGetInstance = (SpHandle * (*)(void)) dlsym(spOps.handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ ALOGD("Error to spHandleGetInstance");
+ return NULL;
+ }
+
+ /* spHandle API */
+ ALOGD("Go to spHandleInit");
+ funName = "spHandleInit";
+ spOps.spHandleInit = (SP_STATUS(*)(SpHandle * spHandle)) dlsym(spOps.handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ ALOGD("Error to spHandleInit");
+ return NULL;
+ }
+
+ ALOGD("Go to spHandleUninit");
+ funName = "spHandleUninit";
+ spOps.spHandleUninit = (SP_STATUS(*)(SpHandle * spHandle)) dlsym(spOps.handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ ALOGD("Error to spHandleUninit");
+ return NULL;
+ }
+
+ ALOGD("Go to getParamBuffer");
+ funName = "getParamBuffer";
+ spOps.getParamBuffer = (int(*)(SpHandle * spHandle, SpeechParserAttribute speechParserAttribute, SpeechDataBufType * outBuf)) dlsym(spOps.handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ ALOGD("Error to getParamBuffer");
+ return NULL;
+ }
+
+ ALOGD("Go to setKeyValuePair");
+ funName = "setKeyValuePair";
+ spOps.setKeyValuePair = (int(*)(SpHandle * spHandle, const SpeechStringBufType * keyValuePair)) dlsym(spOps.handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ ALOGD("Error to setKeyValuePair");
+ return NULL;
+ }
+
+ ALOGD("Go to getKeyValuePair");
+ funName = "getKeyValuePair";
+ spOps.getKeyValuePair = (int(*)(SpHandle * spHandle, SpeechStringBufType * keyValuePair)) dlsym(spOps.handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ ALOGD("Error to getKeyValuePair");
+ return NULL;
+ }
+
+ spOpsInited = 1;
+ }
+
+ return &spOps;
+ }
+
+ static void spOpsDelInstance() {
+ if (spOpsInited == 1) {
+ dlclose(spOps.handle);
+ spOps.handle = NULL;
+ spOpsInited = 0;
+ }
+ }
+};
+
+}
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/media/AudioParameter.cpp b/src/multimedia/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/media/AudioParameter.cpp
new file mode 100644
index 0000000..210024b
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/media/AudioParameter.cpp
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+ * Copyright (C) 2006-2011 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 "AudioParameter"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+
+#include <media/AudioParameter.h>
+#include <system/audio.h>
+
+namespace android {
+
+// static
+const char * const AudioParameter::keyRouting = AUDIO_PARAMETER_STREAM_ROUTING;
+const char * const AudioParameter::keySamplingRate = AUDIO_PARAMETER_STREAM_SAMPLING_RATE;
+const char * const AudioParameter::keyFormat = AUDIO_PARAMETER_STREAM_FORMAT;
+const char * const AudioParameter::keyChannels = AUDIO_PARAMETER_STREAM_CHANNELS;
+const char * const AudioParameter::keyFrameCount = AUDIO_PARAMETER_STREAM_FRAME_COUNT;
+const char * const AudioParameter::keyInputSource = AUDIO_PARAMETER_STREAM_INPUT_SOURCE;
+const char * const AudioParameter::keyScreenState = AUDIO_PARAMETER_KEY_SCREEN_STATE;
+const char * const AudioParameter::keyBtNrec = AUDIO_PARAMETER_KEY_BT_NREC;
+const char * const AudioParameter::keyHwAvSync = AUDIO_PARAMETER_HW_AV_SYNC;
+const char * const AudioParameter::keyPresentationId = AUDIO_PARAMETER_STREAM_PRESENTATION_ID;
+const char * const AudioParameter::keyProgramId = AUDIO_PARAMETER_STREAM_PROGRAM_ID;
+const char * const AudioParameter::keyMonoOutput = AUDIO_PARAMETER_MONO_OUTPUT;
+const char * const AudioParameter::keyStreamHwAvSync = AUDIO_PARAMETER_STREAM_HW_AV_SYNC;
+const char * const AudioParameter::keyStreamConnect = AUDIO_PARAMETER_DEVICE_CONNECT;
+const char * const AudioParameter::keyStreamDisconnect = AUDIO_PARAMETER_DEVICE_DISCONNECT;
+const char * const AudioParameter::keyStreamSupportedFormats = AUDIO_PARAMETER_STREAM_SUP_FORMATS;
+const char * const AudioParameter::keyStreamSupportedChannels = AUDIO_PARAMETER_STREAM_SUP_CHANNELS;
+const char * const AudioParameter::keyStreamSupportedSamplingRates =
+ AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES;
+const char * const AudioParameter::valueOn = AUDIO_PARAMETER_VALUE_ON;
+const char * const AudioParameter::valueOff = AUDIO_PARAMETER_VALUE_OFF;
+const char * const AudioParameter::valueListSeparator = AUDIO_PARAMETER_VALUE_LIST_SEPARATOR;
+const char * const AudioParameter::keyReconfigA2dp = AUDIO_PARAMETER_RECONFIG_A2DP;
+const char * const AudioParameter::keyReconfigA2dpSupported = AUDIO_PARAMETER_A2DP_RECONFIG_SUPPORTED;
+
+AudioParameter::AudioParameter(const String8& keyValuePairs)
+{
+ char *str = new char[keyValuePairs.length()+1];
+ mKeyValuePairs = keyValuePairs;
+ char *last;
+
+ strcpy(str, keyValuePairs.string());
+ char *pair = strtok_r(str, ";", &last);
+ while (pair != NULL) {
+ if (strlen(pair) != 0) {
+ size_t eqIdx = strcspn(pair, "=");
+ String8 key = String8(pair, eqIdx);
+ String8 value;
+ if (eqIdx == strlen(pair)) {
+ value = String8("");
+ } else {
+ value = String8(pair + eqIdx + 1);
+ }
+ if (mParameters.indexOfKey(key) < 0) {
+ mParameters.add(key, value);
+ } else {
+ mParameters.replaceValueFor(key, value);
+ }
+ } else {
+ ALOGV("AudioParameter() cstor empty key value pair");
+ }
+ pair = strtok_r(NULL, ";", &last);
+ }
+
+ delete[] str;
+}
+
+AudioParameter::~AudioParameter()
+{
+ mParameters.clear();
+}
+
+String8 AudioParameter::toStringImpl(bool useValues) const
+{
+ String8 str = String8("");
+
+ size_t size = mParameters.size();
+ for (size_t i = 0; i < size; i++) {
+ str += mParameters.keyAt(i);
+ if (useValues) {
+ str += "=";
+ str += mParameters.valueAt(i);
+ }
+ if (i < (size - 1)) str += ";";
+ }
+ return str;
+}
+
+status_t AudioParameter::add(const String8& key, const String8& value)
+{
+ if (mParameters.indexOfKey(key) < 0) {
+ mParameters.add(key, value);
+ return NO_ERROR;
+ } else {
+ mParameters.replaceValueFor(key, value);
+ return ALREADY_EXISTS;
+ }
+}
+
+status_t AudioParameter::addKey(const String8& key)
+{
+ return add(key, String8());
+}
+
+status_t AudioParameter::addInt(const String8& key, const int value)
+{
+ char str[12];
+ if (snprintf(str, 12, "%d", value) > 0) {
+ String8 str8 = String8(str);
+ return add(key, str8);
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::addFloat(const String8& key, const float value)
+{
+ char str[23];
+ if (snprintf(str, 23, "%.10f", value) > 0) {
+ String8 str8 = String8(str);
+ return add(key, str8);
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::remove(const String8& key)
+{
+ if (mParameters.indexOfKey(key) >= 0) {
+ mParameters.removeItem(key);
+ return NO_ERROR;
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::get(const String8& key, String8& value) const
+{
+ if (mParameters.indexOfKey(key) >= 0) {
+ value = mParameters.valueFor(key);
+ return NO_ERROR;
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::getInt(const String8& key, int& value) const
+{
+ String8 str8;
+ status_t result = get(key, str8);
+ value = 0;
+ if (result == NO_ERROR) {
+ int val;
+ if (sscanf(str8.string(), "%d", &val) == 1) {
+ value = val;
+ } else {
+ result = INVALID_OPERATION;
+ }
+ }
+ return result;
+}
+
+status_t AudioParameter::getFloat(const String8& key, float& value) const
+{
+ String8 str8;
+ status_t result = get(key, str8);
+ value = 0;
+ if (result == NO_ERROR) {
+ float val;
+ if (sscanf(str8.string(), "%f", &val) == 1) {
+ value = val;
+ } else {
+ result = INVALID_OPERATION;
+ }
+ }
+ return result;
+}
+
+status_t AudioParameter::getAt(size_t index, String8& key) const
+{
+ if (mParameters.size() > index) {
+ key = mParameters.keyAt(index);
+ return NO_ERROR;
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::getAt(size_t index, String8& key, String8& value) const
+{
+ if (mParameters.size() > index) {
+ key = mParameters.keyAt(index);
+ value = mParameters.valueAt(index);
+ return NO_ERROR;
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+} // namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/media/AudioParameter.h b/src/multimedia/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/media/AudioParameter.h
new file mode 100644
index 0000000..3010d54
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/media/AudioParameter.h
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+ * Copyright (C) 2008-2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIOPARAMETER_H_
+#define ANDROID_AUDIOPARAMETER_H_
+
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class AudioParameter {
+
+public:
+ AudioParameter() {}
+ AudioParameter(const String8& keyValuePairs);
+ virtual ~AudioParameter();
+
+ // reserved parameter keys for changing standard parameters with setParameters() function.
+ // Using these keys is mandatory for AudioFlinger to properly monitor audio output/input
+ // configuration changes and act accordingly.
+ // keyRouting: to change audio routing, value is an int in audio_devices_t
+ // keySamplingRate: to change sampling rate routing, value is an int
+ // keyFormat: to change audio format, value is an int in audio_format_t
+ // keyChannels: to change audio channel configuration, value is an int in audio_channels_t
+ // keyFrameCount: to change audio output frame count, value is an int
+ // keyInputSource: to change audio input source, value is an int in audio_source_t
+ // (defined in media/mediarecorder.h)
+ // keyScreenState: either "on" or "off"
+ static const char * const keyRouting;
+ static const char * const keySamplingRate;
+ static const char * const keyFormat;
+ static const char * const keyChannels;
+ static const char * const keyFrameCount;
+ static const char * const keyInputSource;
+ static const char * const keyScreenState;
+
+ // keyBtNrec: BT SCO Noise Reduction + Echo Cancellation parameters
+ // keyHwAvSync: get HW synchronization source identifier from a device
+ // keyMonoOutput: Enable mono audio playback
+ // keyStreamHwAvSync: set HW synchronization source identifier on a stream
+ static const char * const keyBtNrec;
+ static const char * const keyHwAvSync;
+ static const char * const keyMonoOutput;
+ static const char * const keyStreamHwAvSync;
+
+ // keys for presentation selection
+ // keyPresentationId: Audio presentation identifier
+ // keyProgramId: Audio presentation program identifier
+ static const char * const keyPresentationId;
+ static const char * const keyProgramId;
+
+ // keyAudioLanguagePreferred: Preferred audio language
+ static const char * const keyAudioLanguagePreferred;
+
+ // keyStreamConnect / Disconnect: value is an int in audio_devices_t
+ static const char * const keyStreamConnect;
+ static const char * const keyStreamDisconnect;
+
+ // For querying stream capabilities. All the returned values are lists.
+ // keyStreamSupportedFormats: audio_format_t
+ // keyStreamSupportedChannels: audio_channel_mask_t
+ // keyStreamSupportedSamplingRates: sampling rate values
+ static const char * const keyStreamSupportedFormats;
+ static const char * const keyStreamSupportedChannels;
+ static const char * const keyStreamSupportedSamplingRates;
+
+ static const char * const valueOn;
+ static const char * const valueOff;
+
+ static const char * const valueListSeparator;
+
+ // keyReconfigA2dp: Ask HwModule to reconfigure A2DP offloaded codec
+ // keyReconfigA2dpSupported: Query if HwModule supports A2DP offload codec config
+ static const char * const keyReconfigA2dp;
+ static const char * const keyReconfigA2dpSupported;
+
+ String8 toString() const { return toStringImpl(true); }
+ String8 keysToString() const { return toStringImpl(false); }
+
+ status_t add(const String8& key, const String8& value);
+ status_t addInt(const String8& key, const int value);
+ status_t addKey(const String8& key);
+ status_t addFloat(const String8& key, const float value);
+
+ status_t remove(const String8& key);
+
+ status_t get(const String8& key, String8& value) const;
+ status_t getInt(const String8& key, int& value) const;
+ status_t getFloat(const String8& key, float& value) const;
+ status_t getAt(size_t index, String8& key) const;
+ status_t getAt(size_t index, String8& key, String8& value) const;
+
+ size_t size() const { return mParameters.size(); }
+
+private:
+ String8 mKeyValuePairs;
+ KeyedVector <String8, String8> mParameters;
+
+ String8 toStringImpl(bool useValues) const;
+};
+
+}; // namespace android
+
+#endif /*ANDROID_AUDIOPARAMETER_H_*/
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/Makefile b/src/multimedia/libspeech_drv/audio_big_sw/Makefile
new file mode 100644
index 0000000..5f78b7287
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/Makefile
@@ -0,0 +1,196 @@
+# SPDX-License-Identifier: MediaTekProprietary
+# @see http://mtkswits01/~wimac
+# @see libbase/Makefile
+# @see libbase/Makefile.config
+PREFIX = ../install
+NAME = speech_dmn
+COMPILER = GNU
+CROSS = arm-linux-
+CROSS_SUP= arm-linux- arm-none-eabi- aarch64-linux-
+GCC = $(CROSS)gcc
+CC = $(GCC)
+CXX = $(CROSS)g++
+OBJDUMP = $(CROSS)objdump
+OBJCOPY = $(CROSS)objcopy
+AR = $(CROSS)ar
+
+
+ifeq ($(strip $(TARGET_PLATFORM)), mt2735)
+ OFLAGS = -g -O0 -fPIC -Wno-missing-braces
+else
+ OFLAGS = -g -O0 -fPIC -Wno-missing-braces -march=armv7ve -mfpu=neon-vfpv4 -mfloat-abi=hard -mcpu=cortex-a7
+endif
+
+ifeq ($(strip $(CROSS)), arm-linux-)
+ CFLAGS = -mthumb-interwork
+endif
+
+INIT = syss_init
+LDFLAGS = $(BB_LDFLAGS_ADD) -Wl,--hash-style=gnu -L. -L $(ROOT)/lib
+LOCAL_PATH = .
+
+
+all: libspeech_drv.so speech_daemon libspeechparser_vendor.so
+
+CFLAGS += -DMTK_YOCTO_AUDIO
+
+INCLUDE = -Ios/include \
+ -Ios
+
+INTF_LIB_INCLUDE = -llog \
+ -lpthread
+
+libspeech_drv.so: speech_drv.o
+ $(CC) $(OFLAGS) $(INCLUDE) -llog -shared -o $@ speech_drv.o
+
+speech_drv.o: os/include/speech_drv.h
+ $(CC) $(OFLAGS) $(INCLUDE) $(INTF_LIB_INCLUDE) ${CFLAGS} -c os/drv/speech_drv.c -o $@
+
+#----------------------------------------------------------------------------------------
+
+INCLUDE= -I$(ROOT)/include \
+ -I$(ROOT)/usr/include \
+ -Ihardware/include \
+ -Ios \
+ -Ios/system \
+ -Ios/include \
+ -Isp_hal/utility \
+ -Isp_hal/utility/uthash \
+ -Isp_hal/include \
+ -Isp_hal/V3/include
+
+
+INCLUDE += -IAudioSpeechEnhancement
+INCLUDE += -IAudioSpeechEnhancement/ENH_Parser
+INCLUDE += -IAudioSpeechEnhancement/media
+
+
+CXXSRC= \
+ os/drv/SpeechModemController.cpp \
+ os/drv/MtkAudioSrc.cpp \
+ sp_hal/speech_driver/SpeechDriverNormal.cpp \
+ sp_hal/speech_driver/SpeechMessengerNormal.cpp \
+ sp_hal/speech_driver/SpeechDriverFactory.cpp \
+ sp_hal/speech_driver/SpeechDriverDummy.cpp \
+ sp_hal/speech_driver/SpeechMessageID.cpp \
+ sp_hal/speech_driver/SpeechMessageQueue.cpp \
+ sp_hal/speech_driver/SpeechParserBase.cpp \
+ sp_hal/speech_driver/SpeechShareMemBase.cpp \
+ sp_hal/speech_driver/SpeechExtMemCCCI.cpp \
+ sp_hal/speech_driver/SpeechUtility.cpp \
+ sp_hal/speech_driver/SpeechConfig.cpp \
+ sp_hal/speech_driver/SpeechEnhancementController.cpp \
+ sp_hal/speech_driver/SpeechBGSPlayer.cpp \
+ sp_hal/speech_driver/SpeechEcallController.cpp \
+ sp_hal/speech_driver/SpeechPcm2way.cpp \
+ sp_hal/aud_drv/AudioEventThreadManager.cpp \
+ sp_hal/aud_drv/AudioUtility.cpp \
+ sp_hal/V3/speech_driver/SpeechVMRecorder.cpp \
+ sp_hal/V3/aud_drv/AudioVolumeFactory.cpp \
+ hardware/src/AudioGainTableParamParser.cpp \
+ hardware/src/AudioALSAGainController.cpp \
+ hardware/src/AudioALSAHardwareResourceManager.cpp \
+ hardware/src/WCNChipController.cpp \
+ hardware/src/AudioALSADriverUtility.cpp
+
+ifeq ($(strip $(TARGET_PLATFORM)), mt2735)
+ CXXSRC += sp_hal/speech_driver/SpeechShareMemGen95.cpp
+ CXXSRC += sp_hal/speech_driver/SpeechExtMemUSIP.cpp
+ CXXSRC += hardware/src/SpeechParserGen95.cpp
+else
+ CXXSRC += sp_hal/speech_driver/SpeechShareMemGen93.cpp
+ CXXSRC += hardware/src/SpeechParserGen93.cpp
+endif
+
+
+
+CSRC= \
+ sp_hal/utility/audio_lock.c \
+ sp_hal/utility/audio_time.c
+
+LIB_INCLUDE = -llog \
+ -lpthread \
+ -lxml2 \
+ -laudioparamparser \
+ -lutils
+
+
+CFLAGS += -DMTK_COMBO_MODEM_SUPPORT
+CFLAGS += -DMTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT
+CFLAGS += -DMTK_CCCI_SHARE_BUFFER_SUPPORT
+CFLAGS += -DCONFIG_MT_ENG_BUILD
+CFLAGS += -DMTK_SPEECH_BGS_SUPPORT
+CFLAGS += -DSPH_SR32K
+CFLAGS += -DMTK_AUDIO_GAIN_TABLE
+CFLAGS += -DMTK_NEW_VOL_CONTROL
+CFLAGS += -DMTK_INCALL_DE_REVERB
+CFLAGS += -DMTK_SPEECH_ECALL_SUPPORT
+CFLAGS += -DMTK_AUDIO_TRYLOCK_NOT_SUPPORT
+#CFLAGS += -DMTK_SPEECH_MD_LPBK_TX2RX
+
+ifeq ($(strip $(TARGET_PLATFORM)), mt2735)
+ CFLAGS += -DMTK_SPEECH_USIP_EMI_SUPPORT
+ CFLAGS += -DMTK_DTMF_REMOVAL_SUPPORT
+endif
+
+CXXOBJS=$(CXXSRC:.cpp=.o)
+COBJS=$(CSRC:.c=.o)
+%.o : %.cpp
+ $(CXX) $(OFLAGS) $(INCLUDE) ${CFLAGS} -c -o $@ $<
+%.o : %.c
+ $(CC) $(OFLAGS) $(INCLUDE) ${CFLAGS} -c -o $@ $<
+
+libspeechparser_vendor.so:
+ $(CXX) $(OFLAGS) $(INCLUDE) $(LIB_INCLUDE) ${CFLAGS} -c AudioSpeechEnhancement/ENH_Parser/SpeechParser.cpp -o SpeechParser.o
+ $(CXX) $(OFLAGS) $(INCLUDE) $(LIB_INCLUDE) ${CFLAGS} -c AudioSpeechEnhancement/media/AudioParameter.cpp -o AudioParameter.o
+ $(CXX) ${CFLAGS} SpeechParser.o AudioParameter.o $(LDFLAGS) $(LIBS_PATH) ${LIB_INCLUDE} -shared -o libspeechparser_vendor.so
+
+
+libspeech_dmn.so: $(COBJS) $(CXXOBJS)
+ @echo "DEBUG:COBJS="$(COBJS)
+ @echo "DEBUG:CXXOBJS="$(CXXOBJS)
+ $(CXX) $(SYSPATH) $(COBJS) $(CXXOBJS) ${LDFLAGS} ${LIB_INCLUDE} -shared -o libspeech_dmn.so
+
+#----------------------------------------------------------------------------------------
+
+SRC_DAEMON= \
+ os/drv/SpeechDaemon.cpp
+
+LIB_INCLUDE_DAEMON = -llog \
+ -lpthread \
+ -lspeech_dmn
+
+CXXOBJS_DAEMON=$(SRC_DAEMON:.cpp=.o)
+%.o : %.cpp
+ $(CXX) $(OFLAGS) $(INCLUDE) ${CFLAGS} -c -o $@ $<
+
+speech_daemon: $(CXXOBJS_DAEMON) libspeech_dmn.so
+ @echo "DEBUG:CXXOBJS_DAEMON="$(CXXOBJS_DAEMON)
+ $(CXX) $(SYSPATH) $(LDFLAGS) ${LIB_INCLUDE_DAEMON} $(CXXOBJS_DAEMON) -o speech_daemon
+
+#----------------------------------------------------------------------------------------
+
+install:
+ mkdir -p $(ROOT)/${base_libdir}/
+ cp -af lib$(NAME).so $(ROOT)/${base_libdir}/
+ cp -af libspeech_drv.so $(ROOT)/${base_libdir}/
+ cp -af libspeechparser_vendor.so $(ROOT)/${base_libdir}/
+ chmod a+x speech_daemon
+ mkdir -p $(ROOT)/${base_bindir}/
+ cp -af speech_daemon $(ROOT)/$(base_bindir)/
+
+ mkdir -p ../export_include
+ mkdir -p ../export_include/system
+ mkdir -p ../export_include/hardware
+ mkdir -p ../export_include/utils
+ cp -af sp_hal/include/SpeechFeatureDef.h ../export_include/
+ cp -af sp_hal/include/SpeechType.h ../export_include/
+ cp -af os/include/* ../export_include/
+ cp -af os/system/* ../export_include/system
+ cp -af os/hardware/* ../export_include/hardware
+ cp -af os/utils/* ../export_include/utils
+
+clean:
+ rm -f speech_daemon libspeech_dmn.so libspeech_drv.so libspeechparser_vendor.so
+ rm -f *.o *.d
+ rm -f export_include/*.h
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/hardware/include/MtkAudioComponent.h b/src/multimedia/libspeech_drv/audio_big_sw/hardware/include/MtkAudioComponent.h
new file mode 100644
index 0000000..af466ea
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/hardware/include/MtkAudioComponent.h
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* MediaTek Inc. (C) 2016. All rights reserved.
+ *
+ * Copyright Statement:
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ */
+
+/*
+* Description:
+* This file implements virtual class function for supporting dlopen to use audio
+* post processing.
+*/
+
+#ifndef __AUDIO_COMPONENT_ENGINE_EXP_H__
+#define __AUDIO_COMPONENT_ENGINE_EXP_H__
+#include <utils/String8.h>
+#define BCV_UP_BIT 0
+#define BCV_DOWN_BIT 0x100
+#define BCV_SIMPLE_SHIFT_BIT 0x200
+
+typedef enum {
+ BCV_PAR_SET_PCM_FORMAT,
+ BCV_PAR_GET_PCM_FORMAT,
+ BCV_PAR_SET_SAMPLE_RATE,
+ BCV_PAR_GET_SAMPLE_RATE,
+ BCV_PAR_SET_CHANNEL_NUMBER,
+ BCV_PAR_GET_CHANNEL_NUMBER,
+} BCV_PARAMETER;
+
+typedef enum {
+ BCV_IN_Q1P15_OUT_Q1P31 = BCV_UP_BIT + 0, // 16-bit Q1.15 input, 32-bit Q1.31 output
+ BCV_IN_Q1P31_OUT_Q1P15 = BCV_UP_BIT + 1, // 32-bit Q1.31 input, 16-bit Q1.15 output
+ BCV_IN_Q9P23_OUT_Q1P31 = BCV_UP_BIT + 2, // 32-bit Q9.23 input, 32-bit Q1.31 output
+ BCV_IN_Q1P31_OUT_Q9P23 = BCV_UP_BIT + 3, // 32-bit Q1.31 input, 32-bit Q9.23 output
+ BCV_IN_Q1P15_OUT_Q9P23 = BCV_UP_BIT + 4, // 16-bit Q1.15 input, 32-bit Q9.23 output
+ BCV_IN_Q9P23_OUT_Q1P15 = BCV_UP_BIT + 5, // 32-bit Q9.23 input, 16-bit Q1.15 output
+ BCV_IN_Q1P15_OUT_Q1P23 = BCV_UP_BIT + 6, // 16-bit Q1.15 input, 24-bit Q1.23 output
+ BCV_IN_Q1P23_OUT_Q1P15 = BCV_UP_BIT + 7, // 24-bit Q1.23 input, 16-bit Q1.15 output
+ BCV_IN_Q1P31_OUT_Q1P23 = BCV_UP_BIT + 8, // 32-bit Q1.31 input, 24-bit Q1.23 output
+ BCV_IN_Q1P23_OUT_Q1P31 = BCV_UP_BIT + 9, // 24-bit Q1.23 input, 32-bit Q1.31 output
+ BCV_IN_Q9P23_OUT_Q1P23 = BCV_UP_BIT + 10, // 32-bit Q9.23 input, 24-bit Q1.23 output
+ BCV_IN_Q1P23_OUT_Q9P23 = BCV_UP_BIT + 11, // 24-bit Q1.23 input, 32-bit Q9.23 output
+ BCV_UP_BIT_END = BCV_UP_BIT + 12, // End of up-bits. Do Not use this
+
+ BCV_IN_Q33P31_OUT_Q1P31 = BCV_DOWN_BIT + 0, // 64-bit Q33.31 input, 32-bit Q1.31 output
+ BCV_DOWN_BIT_END = BCV_DOWN_BIT + 1, // End of down-bits. Do Not use this
+
+ BCV_SIMPLE_SHIFT_BIT_END = BCV_SIMPLE_SHIFT_BIT + 0, // End of simple down-bits. Do Not use this
+} BCV_PCM_FORMAT;
+
+typedef enum {
+ SRC_IN_Q1P15_OUT_Q1P15 = 0, // 16-bit Q1.15 input, 16-bit Q1.15 output
+ SRC_IN_Q1P15_OUT_Q1P31 = 1, // 16-bit Q1.15 input, 32-bit Q1.31 output
+ SRC_IN_Q9P23_OUT_Q1P31 = 2, // 32-bit Q9.23 input, 32-bit Q1.31 output
+ SRC_IN_Q1P31_OUT_Q1P31 = 3, // 32-bit Q1.31 input, 32-bit Q1.31 output
+ SRC_IN_END,
+} SRC_PCM_FORMAT;
+
+typedef enum {
+ SRC_PAR_SET_PCM_FORMAT,
+ SRC_PAR_GET_PCM_FORMAT,
+ SRC_PAR_SET_INPUT_SAMPLE_RATE,
+ SRC_PAR_GET_INPUT_SAMPLE_RATE,
+ SRC_PAR_SET_OUTPUT_SAMPLE_RATE,
+ SRC_PAR_GET_OUTPUT_SAMPLE_RATE,
+ SRC_PAR_SET_INPUT_CHANNEL_NUMBER,
+ SRC_PAR_GET_INPUT_CHANNEL_NUMBER,
+ SRC_PAR_SET_OUTPUT_CHANNEL_NUMBER,
+ SRC_PAR_GET_OUTPUT_CHANNEL_NUMBER,
+} SRC_PARAMETER;
+
+typedef enum {
+ BLOUD_PAR_SET_FILTER_TYPE,
+ BLOUD_PAR_SET_WORK_MODE,
+ BLOUD_PAR_SET_CHANNEL_NUMBER,
+ BLOUD_PAR_SET_SAMPLE_RATE,
+ BLOUD_PAR_SET_PCM_FORMAT,
+ BLOUD_PAR_SET_USE_DEFAULT_PARAM,
+ BLOUD_PAR_SET_PREVIEW_PARAM,
+ BLOUD_PAR_SET_USE_DEFAULT_PARAM_SUB,
+ BLOUD_PAR_SET_PREVIEW_PARAM_SUB,
+ BLOUD_PAR_SET_UPDATE_PARAM_TO_SWIP,
+ BLOUD_PAR_SET_SEP_LR_FILTER, //10
+ BLOUD_PAR_SET_STEREO_TO_MONO_MODE,
+ BLOUD_PAR_SET_RAMP_UP,
+ BLOUD_PAR_SET_USE_DEFAULT_PARAM_FORCE_RELOAD,//bypass cache to load parameter
+ BLOUD_PAR_SET_NOISE_FILTER,
+ BLOUD_PAR_SET_LOAD_CACHE_PARAM,
+} BLOUD_PARAMETER;
+
+typedef enum {
+ BLOUD_IN_Q1P15_OUT_Q1P15 = 0, // 16-bit Q1.15 input, 16-bit Q1.15 output
+ BLOUD_IN_Q1P31_OUT_Q1P31 = 1, // 32-bit Q1.31 input, 32-bit Q1.31 output
+} BLOUD_PCM_FORMAT;
+
+typedef enum {
+ BLOUD_S2M_MODE_NONE = 0, // None
+ BLOUD_S2M_MODE_ST2MO2ST = 1, // Stereo to mono to stereo
+} BLOUD_S2M_MODE_ENUM;
+
+typedef enum {
+ DCR_MODE_1 = 0,
+ DCR_MODE_2,
+ DCR_MODE_3
+} DCR_MODE;
+
+typedef enum {
+ DCREMOVE_BIT16 = 0,
+ DCREMOVE_BIT24,
+} DCR_BITDEPTH;
+
+namespace android {
+
+typedef enum {
+ ACE_SUCCESS = 0,
+ ACE_INVALIDE_PARAMETER,
+ ACE_INVALIDE_OPERATION,
+ ACE_NOT_INIT,
+ ACE_NOT_OPEN,
+} ACE_ERRID;
+
+typedef enum {
+ ACE_STATE_NONE,
+ ACE_STATE_INIT,
+ ACE_STATE_OPEN,
+} ACE_STATE;
+
+class AudioComponentEngineBase {
+public:
+ //AudioComponentEngineBase() {};
+ virtual ACE_ERRID setParameter(uint32_t paramID, void *param) = 0;
+ virtual ACE_ERRID getParameter(uint32_t paramID, void *param) = 0;
+ virtual ACE_ERRID open(void) = 0;
+ virtual ACE_ERRID close(void) = 0;
+ virtual ACE_ERRID resetBuffer(void) = 0;
+ /* Return: consumed input buffer size(byte) */
+ virtual ACE_ERRID process(void *pInputBuffer, /* Input, pointer to input buffer */
+ uint32_t *InputSampleCount, /* Input, length(byte) of input buffer */
+ /* Output, length(byte) left in the input buffer after conversion */
+ void *pOutputBuffer, /* Input, pointer to output buffer */
+ uint32_t *OutputSampleCount) = 0; /* Input, length(byte) of output buffer */
+ /* Output, output data length(byte) */
+ virtual ~AudioComponentEngineBase() {};
+};
+
+class MtkAudioBitConverterBase : public AudioComponentEngineBase {
+public:
+ virtual ACE_ERRID setParameter(uint32_t paramID, void *param) = 0;
+ virtual ACE_ERRID getParameter(uint32_t paramID, void *param) = 0;
+ virtual ACE_ERRID open(void) = 0;
+ virtual ACE_ERRID close(void) = 0;
+ virtual ACE_ERRID resetBuffer(void) = 0;
+ virtual ACE_ERRID process(void *pInputBuffer, /* Input, pointer to input buffer */
+ uint32_t *InputSampleCount, /* Input, length(byte) of input buffer */
+ /* Output, length(byte) left in the input buffer after conversion */
+ void *pOutputBuffer, /* Input, pointer to output buffer */
+ uint32_t *OutputSampleCount) = 0; /* Input, length(byte) of output buffer */
+ /* Output, output data length(byte) */
+ virtual ~MtkAudioBitConverterBase() {};
+};
+
+class MtkAudioSrcBase : public AudioComponentEngineBase {
+public:
+ virtual ACE_ERRID setParameter(uint32_t paramID, void *param) = 0;
+ virtual ACE_ERRID getParameter(uint32_t paramID, void *param) = 0;
+ virtual ACE_ERRID open(void) = 0;
+ virtual ACE_ERRID close(void) = 0;
+ virtual ACE_ERRID resetBuffer(void) = 0;
+ virtual ACE_ERRID process(void *pInputBuffer, /* Input, pointer to input buffer */
+ uint32_t *InputSampleCount, /* Input, length(byte) of input buffer */
+ /* Output, length(byte) left in the input buffer after conversion */
+ void *pOutputBuffer, /* Input, pointer to output buffer */
+ uint32_t *OutputSampleCount) = 0; /* Input, length(byte) of output buffer */
+ /* Output, output data length(byte) */
+
+ virtual ACE_ERRID multiChannelOpen(void) = 0;
+ virtual ACE_ERRID multiChannelResetBuffer(void) = 0;
+ virtual ACE_ERRID multiChannelProcess(void *pInputBuffer, /* Input, pointer to input buffer */
+ uint32_t *InputSampleCount, /* Input, length(byte) of input buffer */
+ /* Output, length(byte) left in the input buffer after conversion */
+ void *pOutputBuffer, /* Input, pointer to output buffer */
+ uint32_t *OutputSampleCount) = 0; /* Input, length(byte) of output buffer */
+ /* Output, output data length(byte) */
+ virtual ~MtkAudioSrcBase() {};
+};
+
+class MtkAudioLoudBase : public AudioComponentEngineBase {
+public:
+ virtual ACE_ERRID setParameter(uint32_t paramID, void *param) = 0;
+ virtual ACE_ERRID getParameter(uint32_t paramID, void *param) = 0;
+ virtual ACE_ERRID open(void) = 0;
+ virtual ACE_ERRID close(void) = 0;
+ virtual ACE_ERRID resetBuffer(void) = 0;
+ virtual ACE_ERRID change2ByPass(void) = 0;
+ virtual ACE_ERRID change2Normal(void) = 0;
+ virtual ACE_ERRID process(void *pInputBuffer, /* Input, pointer to input buffer */
+ uint32_t *InputSampleCount, /* Input, length(byte) of input buffer */
+ /* Output, length(byte) left in the input buffer after conversion */
+ void *pOutputBuffer, /* Input, pointer to output buffer */
+ uint32_t *OutputSampleCount) = 0; /* Input, length(byte) of output buffer */
+ /* Output, output data length(byte) */
+ virtual ACE_ERRID setWorkMode(uint32_t chNum, uint32_t smpRate, uint32_t workMode, bool bRampUpEnable) = 0;
+ virtual ACE_ERRID setOutputGain(int32_t gain, uint32_t ramp_sample_cnt) = 0;
+ virtual ACE_ERRID setNotchFilterParam(uint32_t fc, uint32_t bw, int32_t th) = 0;
+ virtual bool isZeroCoeffFilter(void) = 0;
+ virtual ~MtkAudioLoudBase() {};
+ virtual ACE_ERRID setCustSceneName(const char* sceneName) = 0;
+ virtual uint32_t getFilterType(void) = 0;
+ virtual ACE_ERRID getCustSceneName(char* sceneName) = 0;
+};
+
+class MtkAudioDcRemoveBase : public AudioComponentEngineBase {
+public:
+ virtual ACE_ERRID setParameter(uint32_t paramID, void *param) = 0;
+ virtual ACE_ERRID getParameter(uint32_t paramID, void *param) = 0;
+ virtual ACE_ERRID open(void) = 0;
+ virtual ACE_ERRID close(void) = 0;
+ virtual ACE_ERRID resetBuffer(void) = 0;
+ virtual ACE_ERRID process(void *pInputBuffer, /* Input, pointer to input buffer */
+ uint32_t *InputSampleCount, /* Input, length(byte) of input buffer */
+ /* Output, length(byte) left in the input buffer after conversion */
+ void *pOutputBuffer, /* Input, pointer to output buffer */
+ uint32_t *OutputSampleCount) = 0; /* Input, length(byte) of output buffer */
+ virtual ACE_ERRID init(uint32_t channel, uint32_t samplerate, uint32_t dcrMode, uint32_t dBit) = 0;
+ virtual ~MtkAudioDcRemoveBase() {};
+};
+
+class MtkAudioCustParamCacheBase {
+public:
+ virtual ACE_ERRID loadParameter(uint32_t FilterType, void *AudioParam, const char *custScene = NULL) = 0;
+ virtual ACE_ERRID saveParameter(uint32_t FilterType, void *AudioParam, const char *custScene = NULL) = 0;
+ virtual ACE_ERRID saveEncodedParameter(uint32_t FilterType, String8 keys, const char *custScene = NULL) = 0;
+ virtual bool isCacheValid(uint32_t FilterType, const char *custScene = NULL) = 0;
+ virtual ~MtkAudioCustParamCacheBase() {};
+};
+
+extern "C" MtkAudioBitConverterBase *createMtkAudioBitConverter(uint32_t sampling_rate, uint32_t channel_num, BCV_PCM_FORMAT format);
+extern "C" MtkAudioSrcBase *createMtkAudioSrc(uint32_t input_SR, uint32_t input_channel_num, uint32_t output_SR, uint32_t output_channel_num, SRC_PCM_FORMAT format);
+extern "C" MtkAudioLoudBase *createMtkAudioLoud(uint32_t eFLTtype);
+extern "C" MtkAudioDcRemoveBase *createMtkDcRemove(void);
+extern "C" MtkAudioCustParamCacheBase *createMtkAudioCustParamCache(void);
+extern "C" void destroyMtkAudioBitConverter(MtkAudioBitConverterBase *pObject);
+extern "C" void destroyMtkAudioSrc(MtkAudioSrcBase *pObject);
+extern "C" void destroyMtkAudioLoud(MtkAudioLoudBase *pObject);
+extern "C" void destroyMtkAudioDcRemove(MtkAudioDcRemoveBase *pObject);
+extern "C" void destroyMtkAudioCustParamCache(MtkAudioCustParamCacheBase *pObject);
+typedef android::MtkAudioBitConverterBase *create_AudioBitConverter(uint32_t sampling_rate, uint32_t channel_num, BCV_PCM_FORMAT format);
+typedef android::MtkAudioSrcBase *create_AudioSrc(uint32_t input_SR, uint32_t input_channel_num, uint32_t output_SR, uint32_t output_channel_num, SRC_PCM_FORMAT format);
+typedef android::MtkAudioLoudBase *create_AudioLoud(uint32_t eFLTtype);
+typedef android::MtkAudioDcRemoveBase *create_DcRemove();
+typedef android::MtkAudioCustParamCacheBase *create_AudioCustParamCache();
+typedef void destroy_AudioBitConverter(MtkAudioBitConverterBase *pObject);
+typedef void destroy_AudioSrc(MtkAudioSrcBase *pObject);
+typedef void destroy_AudioLoud(MtkAudioLoudBase *pObject);
+typedef void destroy_DcRemove(MtkAudioDcRemoveBase *pObject);
+typedef void destroy_AudioCustParamCache(MtkAudioCustParamCacheBase *pObject);
+
+extern "C" bool MtkAudioLoudEnableXMLCallBack(void);
+
+}; // namespace android
+
+#endif // __AUDIO_COMPONENT_ENGINE_EXP_H__
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/hardware/include/audio_log.h b/src/multimedia/libspeech_drv/audio_big_sw/hardware/include/audio_log.h
new file mode 100644
index 0000000..a7ad241
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/hardware/include/audio_log.h
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_LOG_H
+#define AUDIO_LOG_H
+
+#include <utils/Log.h>
+
+#endif /* end of AUDIO_LOG_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/AudioALSADriverUtility.cpp b/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/AudioALSADriverUtility.cpp
new file mode 100644
index 0000000..246c5a2
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/AudioALSADriverUtility.cpp
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSADriverUtility.h"
+#include <cutils/properties.h>
+#include <AudioLock.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSADriverUtility"
+
+namespace android {
+
+AudioALSADriverUtility *AudioALSADriverUtility::mAudioALSADriverUtility = NULL;
+AudioALSADriverUtility *AudioALSADriverUtility::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSADriverUtility == NULL) {
+ mAudioALSADriverUtility = new AudioALSADriverUtility();
+ }
+ return mAudioALSADriverUtility;
+}
+
+int AudioALSADriverUtility::GetPropertyValue(const char *ProPerty_Key) {
+ int result = 0;
+ char value[PROPERTY_VALUE_MAX];
+ property_get(ProPerty_Key, value, "0");
+ result = atoi(value);
+ return result;
+}
+
+int AudioALSADriverUtility::setPropertyValue(const char *ProPerty_Key, int value) {
+ int result;
+ char valuestring[PROPERTY_VALUE_MAX];
+
+ sprintf(valuestring, "%d", value);
+ property_set(ProPerty_Key, valuestring);
+
+ return 0;
+}
+
+AudioALSADriverUtility::AudioALSADriverUtility() :
+ mMixer(NULL) {
+}
+
+struct mixer_ctl *AudioALSADriverUtility::getMixerCtrlByName(struct mixer *mixer, const char *name) {
+ (void) mixer;
+ (void) name;
+
+ return NULL;
+}
+
+int AudioALSADriverUtility::mixerCtrlGetValue(struct mixer_ctl *ctl, unsigned int id) {
+ (void) ctl;
+ (void) id;
+ return 0;
+}
+
+int AudioALSADriverUtility::mixerCtrlSetValue(struct mixer_ctl *ctl, unsigned int id, int value) {
+ (void) ctl;
+ (void) id;
+ (void) value;
+ return 0;
+}
+
+AudioALSADriverUtility::~AudioALSADriverUtility() {
+ mMixer = NULL;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/AudioALSAGainController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/AudioALSAGainController.cpp
new file mode 100644
index 0000000..b0c0477
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/AudioALSAGainController.cpp
@@ -0,0 +1,817 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAGainController.h"
+#include <SpeechConfig.h>
+#include <SpeechDriverFactory.h>
+#include "AudioLock.h"
+#include <system/audio.h>
+#include "AudioUtility.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioMTKGainController"
+
+#ifdef ALOGG
+#undef ALOGG
+#endif
+#ifdef CONFIG_MT_ENG_BUILD
+#define ALOGG(...) ALOGD(__VA_ARGS__)
+#else
+#define ALOGG(...)
+#endif
+
+
+namespace android {
+/*
+ * =============================================================================
+ * Callback
+ * =============================================================================
+ */
+void xmlChangedCallback(AppHandle *_appHandle, const char *_audioTypeName) {
+ // reload XML file
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return;
+ }
+
+ if (appOps->appHandleReloadAudioType(_appHandle, _audioTypeName) == APP_ERROR) {
+ ALOGE("%s(), Reload xml fail!(audioType = %s)", __FUNCTION__, _audioTypeName);
+ } else {
+ AudioMTKGainController::getInstance()->updateXmlParam(_audioTypeName);
+ }
+}
+/*
+ * =============================================================================
+ * Singleton Pattern
+ * =============================================================================
+ */
+
+AudioMTKGainController *AudioMTKGainController::UniqueVolumeInstance = NULL;
+
+AudioMTKGainController *AudioMTKGainController::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (UniqueVolumeInstance == 0) {
+ ALOGD("%s() +UniqueVolumeInstance", __FUNCTION__);
+ UniqueVolumeInstance = new AudioMTKGainController();
+ ALOGD("%s() -UniqueVolumeInstance", __FUNCTION__);
+ }
+
+ return UniqueVolumeInstance;
+}
+
+AudioMTKGainController::AudioMTKGainController() {
+ ALOGD("%s()", __FUNCTION__);
+ mAudioSpeechEnhanceInfoInstance = NULL;
+ mHardwareResourceManager = NULL;
+ mVoiceVolume = 1.0f;
+ mMasterVolume = 1.0f;
+ mBand = GAIN_SPEECH_NB;
+ mNetwork = GAIN_SPEECH_NETWORK_GSM;
+ mSupportBtVol = false;
+ mSceneIndex = GAIN_SCENE_INDEX_DEFAULT;
+ memset(&mHwVolume, 0xFF, sizeof(mHwVolume));
+ memset(&mHwStream, 0xFF, sizeof(mHwStream));
+ memset(&mHwCaptureInfo, 0, sizeof(mHwCaptureInfo));
+ GainTableParamParser::getInstance()->getSceneList(&mSceneList);
+ allocateGainTable();
+ initVolumeController();
+ mULTotalGain = 184;
+ mHpImpedanceIdx = 0;
+#ifdef MTK_AUDIO_SW_DRE
+ mSWDREMute = false;
+ mMutedHandlerVector.clear();
+ mHasMuteHandler = false;
+ mNumHandler = 0;
+ mFmEnable = false;
+#endif
+ mANCEnable = false;
+ mInitDone = true;
+ mMixer = NULL;
+ mSpkType = AUDIO_SPK_INVALID;
+
+ /* XML changed callback process */
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return;
+ }
+
+ appOps->appHandleRegXmlChangedCb(appOps->appHandleGetInstance(), xmlChangedCallback);
+}
+
+status_t AudioMTKGainController::allocateGainTable() {
+ ALOGD("%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioMTKGainController::freeGainTable() {
+ ALOGD("%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+AudioMTKGainController::~AudioMTKGainController() {
+ freeGainTable();
+}
+
+status_t AudioMTKGainController::initVolumeController() {
+ GainTableParamParser::getInstance()->getGainTableParam(&mGainTable, &mSceneList);
+ GainTableParamParser::getInstance()->getGainTableSpec(&mSpec);
+ return NO_ERROR;
+}
+
+status_t AudioMTKGainController::getSceneGainTableParameter(GainTableForScene *_gainTableForScene) {
+ return NO_ERROR;
+}
+
+status_t AudioMTKGainController::getNonSceneGainTableParameter(GainTableForNonScene *_gainTableForNonScene) {
+ return NO_ERROR;
+}
+
+int AudioMTKGainController::getSceneCount() {
+ return 0;
+}
+
+int AudioMTKGainController::getSceneIndex(const char *scene) {
+ return GAIN_SCENE_INDEX_DEFAULT;
+}
+
+int AudioMTKGainController::getCurrentSceneIndex() {
+ ALOGD("%s(), mSceneIndex = %d", __FUNCTION__, mSceneIndex);
+ return mSceneIndex;
+}
+
+void AudioMTKGainController::setScene(const char *scene) {
+ ALOGD("%s(), scene = %s", __FUNCTION__, scene);
+ mSceneIndex = getSceneIndex(scene);
+}
+
+status_t AudioMTKGainController::initCheck() {
+ return mInitDone;
+}
+
+void AudioMTKGainController::updateXmlParam(const char *_audioTypeName) {
+ ALOGD("%s(), audioType = %s", __FUNCTION__, _audioTypeName);
+
+ bool needResetDlGain = false;
+ bool isMicGainChanged = false;
+
+ if (strcmp(_audioTypeName, SPEECH_VOL_AUDIOTYPE_NAME) == 0) {
+ GainTableParamParser::getInstance()->updateSpeechVol(&mGainTable);
+ isMicGainChanged = true;
+ needResetDlGain = true;
+ }
+
+ // reset mic gain immediately
+ if (needResetDlGain)
+ setAnalogVolume_l(mHwStream.stream,
+ mHwStream.devices,
+ mHwStream.index,
+ mHwStream.mode);
+
+}
+
+status_t AudioMTKGainController::SetCaptureGain(audio_mode_t mode, audio_source_t source, audio_devices_t input_device, audio_devices_t output_devices) {
+ return NO_ERROR;
+}
+
+status_t AudioMTKGainController::setAnalogVolume_l(int stream, int devices, int index, audio_mode_t mode) {
+ ALOGG("setAnalogVolume(), stream %d, devices 0x%x, index %d, mode %d", stream, devices, index, mode);
+ mHwStream.stream = stream;
+ mHwStream.devices = devices;
+ mHwStream.index = index;
+ mHwStream.mode = mode;
+
+ if (isInVoiceCall(mode)) {
+ setVoiceVolume(index, devices, mode);
+ }
+ return NO_ERROR;
+}
+
+
+status_t AudioMTKGainController::speechNetworkChange(unsigned int info) {
+ bool isNetworkSupport = (info & (0x1 << 15)) != 0;
+ GAIN_SPEECH_BAND band;
+ char *netName = NULL;
+ GAIN_SPEECH_NETWORK net;
+
+ if (isNetworkSupport) {
+ band = (GAIN_SPEECH_BAND)((info >> 4) & 0x3); //info[4:5]
+ netName = SpeechConfig::getInstance()->getNameForEachSpeechNetwork(info & 0xf);
+ net = GainTableParamParser::getInstance()->getGainSpeechNetwork(netName);
+ } else {
+ band = (GAIN_SPEECH_BAND)((info >> 3) & 0x7); //info[3:5]
+ net = (GAIN_SPEECH_NETWORK)0;
+ }
+ ALOGD("%s(), info 0x%x, band %d, net %d, netName %s", __FUNCTION__, info, band, net, netName);
+
+ AutoMutex lock(mLock);
+ if (mBand != band || mNetwork != net) {
+ mBand = band;
+ mNetwork = net;
+ if (isInVoiceCall(mHwStream.mode)) {
+ setAnalogVolume_l(mHwStream.stream, mHwStream.devices, mHwStream.index, AUDIO_MODE_IN_CALL);
+ }
+ }
+ return NO_ERROR;
+}
+
+bool AudioMTKGainController::isNbSpeechBand(void) {
+ AutoMutex lock(mLock);
+ return mBand == GAIN_SPEECH_NB;
+}
+
+status_t AudioMTKGainController::setBtVolumeCapability(bool support) {
+ AutoMutex lock(mLock);
+ mSupportBtVol = !support; // if bt device do not support volume , we should
+ return NO_ERROR;
+}
+
+status_t AudioMTKGainController::setAnalogVolume(int stream, int devices, int index, audio_mode_t mode) {
+ return NO_ERROR;
+}
+
+status_t AudioMTKGainController::setNormalVolume(int stream, int index, int devices, audio_mode_t mode) {
+ return NO_ERROR;
+}
+
+int AudioMTKGainController::setSpeakerType(int type) {
+ if (mSpec == NULL) {
+ ALOGE("%s(), error! mSpec == NULL\n",__FUNCTION__);
+ return NO_ERROR;
+ }
+
+ if (mSpkType != type) {
+ switch (type) {
+ case AUDIO_SPK_INTAMP:
+ mSpec->spkAnaType = GAIN_ANA_SPEAKER;
+ break;
+ case AUDIO_SPK_EXTAMP_LO:
+ mSpec->spkAnaType = GAIN_ANA_LINEOUT;
+ break;
+ case AUDIO_SPK_EXTAMP_HP:
+ mSpec->spkAnaType = GAIN_ANA_HEADPHONE;
+ break;
+ default:
+ ALOGW("%s(), error! default set ANA_LINEOUT\n",__FUNCTION__);
+ mSpec->spkAnaType = GAIN_ANA_LINEOUT;
+ break;
+ }
+ mSpkType = type;
+ }
+ ALOGD("%s() type=%d, spkAnaType=%d", __FUNCTION__, type, mSpec->spkAnaType);
+ return NO_ERROR;
+}
+
+
+int16_t AudioMTKGainController::getVoiceDlAnalogGain(int index, int device, audio_mode_t mode) {
+ int16_t gain = 0;
+ uint16_t gainIdx = 0;
+
+ if (!audio_is_bluetooth_sco_device(device)) {
+ // check stream/index range
+ if (!isValidVolIdx(index, mode)) {
+ ALOGW("error, index %d is invalid, use max %d instead", index, GAIN_MAX_SPEECH_VOL_INDEX);
+ index = GAIN_MAX_SPEECH_VOL_INDEX;
+ }
+
+ // get gain device
+ GAIN_DEVICE gainDevice = getGainDevice(device);
+ // set analog gain
+ if (isSpeakerCategory(gainDevice)) {
+ if (mSpec->spkAnaType >= 0 && mSpec->spkAnaType < NUM_GAIN_ANA_TYPE) {
+ gainIdx = (int16_t) mGainTable.nonSceneGain.speechGain[mBand][mNetwork][gainDevice][index].analog[mSpec->spkAnaType];
+ gain = GainTableParamParser::getInstance()->gainIdx2Db(gainIdx, mSpec->spkAnaType);
+
+ }
+ }
+ ALOGD("%s(), gain = %d, index = %d, devices = 0x%x, mode = %d, mBand = %d, mNetwork = %d, gainDevice = %d, spkAnaType=%d",
+ __FUNCTION__, gain, index, device, mode, mBand, mNetwork, gainDevice, mSpec->spkAnaType);
+ }
+ //other case: gain = 0
+ return gain;
+}
+
+uint16_t AudioMTKGainController::getVoiceUlAnalogGain(uint32_t device, audio_mode_t mode) {
+ uint16_t analogDegrade = 0;
+
+ if (device & AUDIO_DEVICE_OUT_EARPIECE ||
+ device & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+ device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+ device & AUDIO_DEVICE_OUT_SPEAKER ||
+ device & AUDIO_DEVICE_OUT_BUS ||
+ device & AUDIO_DEVICE_OUT_USB_DEVICE ||
+ device & AUDIO_DEVICE_OUT_USB_HEADSET) {
+
+ GAIN_MIC_MODE micMode = getGainMicMode(AUDIO_SOURCE_DEFAULT, mode);
+ GAIN_DEVICE gainDevice = getGainDevice(device);
+
+ uint8_t gain = mGainTable.nonSceneGain.speechMicGain[mBand][mNetwork][gainDevice].gain;
+ ALOGD("+%s(), device = 0x%x, mode = %d, mBand = %d, mNetwork = %d, gainDevice = %d, gain = %d, min =%d, max=%d",
+ __FUNCTION__, device, mode, mBand, mNetwork, gainDevice, gain, mSpec->micIdxMin[gainDevice], mSpec->micIdxMax[gainDevice]);
+
+ if (gain > mSpec->micIdxMax[gainDevice]) {
+ gain = mSpec->micIdxMax[gainDevice];
+ }
+ if (gain < mSpec->micIdxMin[gainDevice]) {
+ gain = mSpec->micIdxMin[gainDevice];
+ }
+ uint8_t degradeDb = mSpec->micIdxMax[gainDevice] - gain;
+ analogDegrade = mSpec->ulPgaGainMap[gainDevice][degradeDb];
+ ALOGD("-%s(), analogDegrade =%d, device = 0x%x, mode = %d, mBand = %d, mNetwork = %d, gainDevice = %d, degradeDb =%d",
+ __FUNCTION__, analogDegrade, device, mode, mBand, mNetwork, gainDevice, degradeDb);
+ }
+//other case: gain = 0
+ return analogDegrade;
+}
+
+status_t AudioMTKGainController::setVoiceVolume(int index, int devices, audio_mode_t mode) {
+ ALOGD("%s(), index = %d, devices = 0x%x, mode = %d, mBand = %d, mNetwork = %d, mVoiceVolume = %f",
+ __FUNCTION__, index, devices, mode, mBand, mNetwork, mVoiceVolume);
+
+
+ if (audio_is_bluetooth_sco_device(devices)) {
+ // check stream/index range
+ ALOGD("audio_is_bluetooth_sco_device = %d, mSupportBtVol is %d", true, mSupportBtVol);
+ uint8_t digitalDegradeDb = 0;
+
+ // help tune gain if bt device doesn't support volume ctrl, otherwise pass 0dB
+ if (mSupportBtVol) {
+ digitalDegradeDb = mGainTable.nonSceneGain.speechGain[mBand][mNetwork][GAIN_DEVICE_SPEAKER][index].digital;
+ }
+ ApplyMdDlGain(index == 0 ? 255 : digitalDegradeDb); // modem dl gain
+ ApplyMdUlGain(0);
+
+ return NO_ERROR;
+ } else {
+ // check stream/index range
+ if (!isValidVolIdx(index, mode)) {
+ ALOGW("error, index %d is invalid, use max %d instead", index, GAIN_MAX_SPEECH_VOL_INDEX);
+ index = GAIN_MAX_SPEECH_VOL_INDEX;
+ }
+
+ // get gain device
+ GAIN_DEVICE gainDevice = GAIN_DEVICE_NONE;
+ gainDevice = getGainDevice(devices);
+
+ // set digital gain
+ //setAMPGain(ampgain, AMP_CONTROL_POINT, device);
+ uint8_t digitalDegradeDb = mGainTable.nonSceneGain.speechGain[mBand][mNetwork][gainDevice][index].digital;
+ ApplyMdDlGain(digitalDegradeDb); // modem dl gain
+
+ // mic gain & modem UL gain
+ if (index == 0) { // don't set ul/stf gain when force mute dl
+ return 0;
+ }
+
+ ApplyMicGainByDevice(devices, mode);
+
+ }
+
+ return NO_ERROR;
+}
+
+void AudioMTKGainController::ApplyMicGainByDevice(uint32_t device, audio_mode_t mode) {
+ if (device & AUDIO_DEVICE_OUT_EARPIECE ||
+ device & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+ device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+ device & AUDIO_DEVICE_OUT_SPEAKER ||
+ device & AUDIO_DEVICE_OUT_BUS ||
+ device & AUDIO_DEVICE_OUT_USB_DEVICE ||
+ device & AUDIO_DEVICE_OUT_USB_HEADSET) {
+
+ GAIN_MIC_MODE micMode = getGainMicMode(AUDIO_SOURCE_DEFAULT, mode);
+ GAIN_DEVICE gainDevice = getGainDevice(device);
+
+ ApplyMicGain(micMode, gainDevice, mode);
+ } else if (audio_is_bluetooth_sco_device(device)) {
+ //when use BT_SCO , apply digital to 0db.
+ ApplyMdUlGain(0);
+ }
+}
+
+void AudioMTKGainController::ApplyMicGainForTty(audio_mode_t mode) {
+
+}
+
+GAIN_DEVICE AudioMTKGainController::getGainDevice(audio_devices_t devices) {
+ GAIN_DEVICE gainDevice = GAIN_DEVICE_NONE;
+
+ if (devices & AUDIO_DEVICE_BIT_IN) {
+ /* input device */
+ gainDevice = GAIN_DEVICE_SPEAKER;
+ } else {
+ /* output device */
+ gainDevice = GAIN_DEVICE_SPEAKER;
+ }
+
+ //ALOGG("%s(), input devices = 0x%x, return gainDevice = %d", __FUNCTION__, devices, gainDevice);
+ return gainDevice;
+}
+
+GAIN_DEVICE AudioMTKGainController::getGainDeviceForTty(void) {
+ GAIN_DEVICE gainDeviceForTty = GAIN_DEVICE_NONE;
+ return gainDeviceForTty;
+}
+
+GAIN_MIC_MODE AudioMTKGainController::getGainMicMode(audio_source_t _source, audio_mode_t _mode) {
+ GAIN_MIC_MODE micMode = GAIN_MIC_NORMAL;
+
+ switch (_mode) {
+ case AUDIO_MODE_NORMAL:
+ case AUDIO_MODE_RINGTONE:
+ switch (_source) {
+ case AUDIO_SOURCE_MIC:
+ micMode = GAIN_MIC_NORMAL;
+ break;
+ case AUDIO_SOURCE_VOICE_UPLINK:
+ case AUDIO_SOURCE_VOICE_DOWNLINK:
+ case AUDIO_SOURCE_VOICE_CALL:
+ micMode = GAIN_MIC_VOICE_CALL;
+ break;
+ case AUDIO_SOURCE_CAMCORDER:
+ micMode = GAIN_MIC_CAMCORDER;
+ break;
+ case AUDIO_SOURCE_VOICE_RECOGNITION:
+ micMode = GAIN_MIC_VOICE_RECOGNITION;
+ break;
+ case AUDIO_SOURCE_VOICE_COMMUNICATION:
+ micMode = GAIN_MIC_VOICE_COMMUNICATION;
+ break;
+ case AUDIO_SOURCE_UNPROCESSED:
+ micMode = GAIN_MIC_UNPROCESSED;
+ break;
+ default:
+ micMode = GAIN_MIC_NORMAL;
+ break;
+ }
+ break;
+ case AUDIO_MODE_IN_CALL:
+ micMode = GAIN_MIC_VOICE_CALL;
+ break;
+ case AUDIO_MODE_IN_COMMUNICATION:
+ micMode = GAIN_MIC_VOICE_COMMUNICATION;
+ break;
+ default:
+ ALOGE("%s(), not handled mode %d", __FUNCTION__, _mode);
+ micMode = GAIN_MIC_NORMAL;
+ break;
+ }
+ return micMode;
+}
+
+void AudioMTKGainController::ApplyMdDlGain(int32_t degradeDb) {
+ // set degarde db to mode side, DL part, here use degrade dbg
+ ALOGG("ApplyMdDlGain degradeDb = %d", degradeDb);
+#if 0
+ if (degradeDb >= keyDLDigitalDegradeMax) {
+ degradeDb = keyDLDigitalDegradeMax;
+ }
+
+ SpeechDriverFactory::GetInstance()->GetSpeechDriver()->SetDownlinkGain((-1 * degradeDb) << 2); // degrade db * 4
+#endif
+ SpeechDriverFactory::GetInstance()->GetSpeechDriver()->SetDownlinkGain((-1 * degradeDb));
+}
+
+void AudioMTKGainController::ApplyMdDlEhn1Gain(int32_t Gain) {
+ // set degarde db to mode side, DL part, here use degrade dbg
+ ALOGD("ApplyMdDlEhn1Gain degradeDb = %d", Gain);
+ //SpeechDriverFactory::GetInstance()->GetSpeechDriver()->SetEnh1DownlinkGain(-1 * (Gain) << 2); // degrade db * 4
+ SpeechDriverFactory::GetInstance()->GetSpeechDriver()->SetEnh1DownlinkGain(-1 * (Gain));
+}
+
+void AudioMTKGainController::ApplyMdUlGain(int32_t IncreaseDb) {
+ // set degarde db to mode side, UL part, here use positive gain becasue SW_agc always positive
+ ALOGG("ApplyMdUlGain degradeDb = %d", IncreaseDb);
+
+ //if (mHwVolume.swAgc != IncreaseDb)
+ {
+ mHwVolume.swAgc = IncreaseDb;
+ SpeechDriverFactory::GetInstance()->GetSpeechDriver()->SetUplinkGain(IncreaseDb << 2); // degrade db * 4
+ }
+}
+
+void AudioMTKGainController::ApplyAudioGain(int gain, audio_mode_t mode, GAIN_DEVICE gainDevice) {
+}
+
+int AudioMTKGainController::GetReceiverGain(void) {
+ return 0;
+}
+
+int AudioMTKGainController::GetHeadphoneRGain(void) {
+ return 0;
+}
+int AudioMTKGainController::GetHeadphoneLGain(void) {
+ return 0;
+}
+void AudioMTKGainController::SetReceiverGain(int index) {
+}
+
+void AudioMTKGainController::SetHeadPhoneLGain(int index) {
+}
+
+void AudioMTKGainController::SetHeadPhoneRGain(int index) {
+}
+
+void AudioMTKGainController::setAudioBufferGain(int gain) {
+}
+
+void AudioMTKGainController::setVoiceBufferGain(int gain) {
+}
+
+int AudioMTKGainController::GetSPKGain(void) {
+ return 0;
+}
+
+void AudioMTKGainController::SetSpeakerGain(int index) {
+}
+
+void AudioMTKGainController::setSpeakerGain(int gain) {
+}
+
+void AudioMTKGainController::setAMPGain(void *points __unused, int num __unused, int device __unused) {
+}
+
+void AudioMTKGainController::SetAdcPga1(int gain) {
+}
+void AudioMTKGainController::SetAdcPga2(int gain) {
+}
+
+status_t AudioMTKGainController::ApplyMicGain(uint32_t MicType, int mode) {
+ /* deprecated !!! DO NOT USE !!! */
+ /* The following will be removed */
+ GAIN_MIC_MODE micMode = GAIN_MIC_NORMAL;
+ GAIN_DEVICE gainDevice = GAIN_DEVICE_SPEAKER;
+//ivt force use
+ micMode = GAIN_MIC_VOICE_CALL;
+ gainDevice = GAIN_DEVICE_SPEAKER;
+
+ return ApplyMicGain(micMode, gainDevice, (audio_mode_t)mode);
+}
+
+status_t AudioMTKGainController::ApplyMicGain(GAIN_MIC_MODE _micMode, GAIN_DEVICE _gainDevice, audio_mode_t _mode) {
+ uint8_t analogidx;
+ uint8_t gain = mGainTable.nonSceneGain.speechMicGain[mBand][mNetwork][_gainDevice].gain;
+
+ if (gain > mSpec->micIdxMax[_gainDevice]) {
+ gain = mSpec->micIdxMax[_gainDevice];
+ }
+ if (gain < mSpec->micIdxMin[_gainDevice]) {
+ gain = mSpec->micIdxMin[_gainDevice];
+ }
+
+ uint8_t degradedb = mSpec->micIdxMax[_gainDevice] - gain;
+ short analogdegrade = mSpec->ulPgaGainMap[_gainDevice][degradedb];
+ short swagcmap = isDmicDevice(_gainDevice) ?
+ mSpec->swagcGainMapDmic[_gainDevice][degradedb] : mSpec->swagcGainMap[_gainDevice][degradedb];
+
+ mULTotalGain = UPLINK_GAIN_MAX - ((mSpec->micIdxMax[_gainDevice] - gain) * UPLINK_ONEDB_STEP);
+
+ ALOGD("ApplyMicGain(), mSceneIndex = %d, _mic_mode = %d, _gain_device = %d, mode = %d, micgain = %d, mULTotalGain = %d, mBand %d, mNetwork %d",
+ mSceneIndex, _micMode, _gainDevice, _mode, gain, mULTotalGain, mBand, mNetwork);
+
+ ASSERT(mSpec->ulHwPgaIdxMax != 0);
+
+ if (mSpec->ulHwPgaIdxMax == 0) {
+ ALOGE("%s(), ulHwPgaIdxMax == 0", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ mHwVolume.swAgc = swagcmap;
+ if (isInVoiceCall(_mode)) {
+ ApplyMdUlGain(swagcmap);
+ }
+
+ return NO_ERROR;
+}
+
+short AudioMTKGainController::GetSWMICGain() {
+ return 0;
+}
+status_t AudioMTKGainController::ApplySideTone(uint32_t Mode) {
+ return NO_ERROR;
+}
+
+uint16_t AudioMTKGainController::updateSidetone(int dlPGAGain, int sidetone, uint8_t ulGain) {
+ return 0;
+}
+bool AudioMTKGainController::isInVoiceCall(audio_mode_t mode) {
+ return (mode == AUDIO_MODE_IN_CALL);
+}
+
+bool AudioMTKGainController::isInVoipCall(audio_mode_t mode) {
+ return mode == AUDIO_MODE_IN_COMMUNICATION;
+}
+
+bool AudioMTKGainController::isInCall(audio_mode_t mode) {
+ return (isInVoiceCall(mode) || isInVoipCall(mode));
+}
+
+status_t AudioMTKGainController::setFmVolume(const float fm_volume) {
+ return NO_ERROR;
+}
+int AudioMTKGainController::GetDigitalLinearGain(int _volIdx, audio_devices_t _device, audio_stream_type_t _streamType) {
+ return 0;
+}
+
+float AudioMTKGainController::GetDigitalLogGain(int _volIdx, audio_devices_t _device, audio_stream_type_t _streamType) {
+ return 0;
+}
+
+bool AudioMTKGainController::isValidStreamType(audio_stream_type_t _streamType) {
+ return false;
+}
+
+bool AudioMTKGainController::isValidVolIdx(int _idx, audio_mode_t _mode) {
+ if (isInVoiceCall(_mode)) {
+ return (_idx >= 0 && _idx <= GAIN_MAX_SPEECH_VOL_INDEX);
+ } else {
+ return (_idx >= 0 && _idx <= GAIN_MAX_VOL_INDEX);
+ }
+}
+
+bool AudioMTKGainController::isHeadsetCategory(enum GAIN_DEVICE _gainDevice) {
+ return false;
+}
+
+bool AudioMTKGainController::isEarpieceCategory(enum GAIN_DEVICE _gainDevice) {
+ return false;
+}
+
+bool AudioMTKGainController::isSpeakerCategory(enum GAIN_DEVICE _gainDevice) {
+ return _gainDevice == GAIN_DEVICE_SPEAKER ||
+ _gainDevice == GAIN_DEVICE_SPEAKER_TBOX;
+}
+
+bool AudioMTKGainController::isDmicDevice(enum GAIN_DEVICE _gainDevice) {
+ return false;
+}
+
+uint32_t AudioMTKGainController::getHpImpedanceIdx(int32_t impedance) {
+ return 0;
+}
+
+int AudioMTKGainController::getHpImpedanceCompesateValue(void) {
+ return 0;
+}
+
+int AudioMTKGainController::tuneGainForMasterVolume(int gain, audio_mode_t mode, GAIN_DEVICE gainDevice) {
+ return 0;
+}
+
+int AudioMTKGainController::tuneGainForHpImpedance(int gain, GAIN_DEVICE gainDevice) {
+ return 0;
+}
+/********************************************************************************
+*
+*
+*
+* UnUsed API
+*
+*
+*
+***********************************************************************************/
+
+uint16_t AudioMTKGainController::MappingToDigitalGain(unsigned char Gain __unused) {
+ return 0;
+}
+
+uint16_t AudioMTKGainController::MappingToPGAGain(unsigned char Gain __unused) {
+ return 0;
+}
+
+status_t AudioMTKGainController::setMasterVolume(float v, audio_mode_t mode, uint32_t devices) {
+ return NO_ERROR;
+}
+
+float AudioMTKGainController::getMasterVolume() {
+ return mMasterVolume;
+}
+
+status_t AudioMTKGainController::setVoiceVolume(float v, audio_mode_t mode, uint32_t device) {
+ return NO_ERROR;
+}
+
+float AudioMTKGainController::getVoiceVolume(void) {
+ return mVoiceVolume;
+}
+
+status_t AudioMTKGainController::setVoiceVolume(int MapVolume __unused, uint32_t device __unused) {
+ return INVALID_OPERATION;
+}
+status_t AudioMTKGainController::ApplyVoiceGain(int degradeDb __unused, audio_mode_t mode __unused, uint32_t device __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioMTKGainController::setStreamVolume(int stream __unused, float v __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioMTKGainController::setStreamMute(int stream __unused, bool mute __unused) {
+ return INVALID_OPERATION;
+}
+
+float AudioMTKGainController::getStreamVolume(int stream __unused) {
+ return 1.0;
+}
+
+// should depend on different usage , FM ,MATV and output device to setline in gain
+status_t AudioMTKGainController::SetLineInPlaybackGain(int type __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioMTKGainController::SetLineInRecordingGain(int type __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioMTKGainController::SetSideTone(uint32_t Mode __unused, uint32_t Gain __unused) {
+
+ return INVALID_OPERATION;
+}
+
+uint32_t AudioMTKGainController::GetSideToneGain(uint32_t device __unused) {
+
+ return INVALID_OPERATION;
+}
+
+
+status_t AudioMTKGainController::SetMicGain(uint32_t Mode __unused, uint32_t Gain __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioMTKGainController::SetULTotalGain(uint32_t Mode __unused, unsigned char Gain __unused) {
+ /* deprecated */
+ return NO_ERROR;
+}
+
+status_t AudioMTKGainController::SetDigitalHwGain(uint32_t Mode __unused, uint32_t Gain __unused, uint32_t routes __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioMTKGainController::SetMicGainTuning(uint32_t Mode __unused, uint32_t Gain __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioMTKGainController::SetMicGainTuning(GAIN_MIC_MODE micMode, GAIN_DEVICE gainDevice, uint32_t gainDecimal) {
+ return NO_ERROR;
+}
+
+unsigned short AudioMTKGainController::getMicGainDecimal(GAIN_MIC_MODE micMode, GAIN_DEVICE gainDevice) {
+ return 0;
+}
+
+bool AudioMTKGainController::GetHeadPhoneImpedance(void) {
+ return true;
+}
+
+int AudioMTKGainController::ApplyAudioGainTuning(int Gain __unused, uint32_t mode __unused, uint32_t device __unused) {
+ return 0;
+}
+
+void AudioMTKGainController::SetLinoutRGain(int DegradedBGain __unused) {
+
+}
+
+void AudioMTKGainController::SetLinoutLGain(int DegradedBGain __unused) {
+
+}
+
+uint32_t AudioMTKGainController::GetOffloadGain(float vol_f __unused) {
+ return 0;
+}
+
+void AudioMTKGainController::setANCEnable(bool _enable) {
+}
+
+#ifdef MTK_AUDIO_SW_DRE
+void AudioMTKGainController::registerPlaybackHandler(uint32_t _identity) {
+}
+
+void AudioMTKGainController::removePlaybackHandler(uint32_t _identity) {
+}
+
+void AudioMTKGainController::requestMute(uint32_t _identity, bool _mute) {
+}
+
+void AudioMTKGainController::setFmEnable(bool _enable) {
+}
+
+bool AudioMTKGainController::isOtherModuleWorking() {
+ return false;
+}
+
+void AudioMTKGainController::updateSWDREState(bool _numChanged, bool _muteChanged) {
+}
+
+void AudioMTKGainController::SWDRERampToMute() {
+}
+
+void AudioMTKGainController::SWDRERampToNormal() {
+}
+
+#endif
+}
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/AudioALSAHardwareResourceManager.cpp b/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/AudioALSAHardwareResourceManager.cpp
new file mode 100644
index 0000000..4c8d07e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/AudioALSAHardwareResourceManager.cpp
@@ -0,0 +1,416 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAHardwareResourceManager.h"
+
+
+#include "AudioType.h"
+#include <AudioLock.h>
+#include "AudioAssert.h"
+
+#ifdef MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT
+#include "AudioParamParser.h"
+#endif
+
+#include "AudioSmartPaController.h"
+
+#ifdef MTK_USB_PHONECALL
+#include "AudioUSBPhoneCallController.h"
+#endif
+
+#ifdef USING_EXTAMP_HP
+#include "AudioALSACodecDeviceOutExtSpeakerAmp.h"
+#endif
+
+#ifdef HAVING_RCV_SPK_SWITCH
+#include "AudioALSACodecDeviceOutReceiverSpeakerSwitch.h"
+#endif
+
+#include "WCNChipController.h"
+
+#ifdef MTK_ANC_SUPPORT
+#include "AudioALSAANCController.h"
+#endif
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+#include "AudioALSANLEController.h"
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSAHardwareResourceManager"
+
+static const char *PROPERTY_KEY_EXTDAC = "vendor.audiohal.resource.extdac.support";
+
+#define A2DP_DEFAULT_LANTENCY (100)
+
+namespace android {
+
+static const char *SIDEGEN[] = {
+ "I0I1", "I2", "I3I4", "I5I6",
+ "I7I8", "I9", "I10I11", "I12I13",
+ "I14", "I15I16", "I17I18", "I19I20",
+ "I21I22", "O0O1", "O2", "O3O4",
+ "O5O6", "O7O8", "O9O10", "O11",
+ "O12", "O13O14", "O15O16", "O17O18",
+ "O19O20", "O21O22", "O23O24", "OFF",
+ "O3", "O4", "I25I26", "O25",
+ "O28O29", "I23I24", "O32O33", "I34I35"
+};
+
+static const char *SIDEGEN_SAMEPLRATE[] = {
+ "8K", "11K", "12K", "16K",
+ "22K", "24K", "32K", "44K",
+ "48K", "88k", "96k", "176k",
+ "192k"
+};
+
+static AudioLock mGetInstanceLock;
+AudioALSAHardwareResourceManager *AudioALSAHardwareResourceManager::mAudioALSAHardwareResourceManager = NULL;
+AudioALSAHardwareResourceManager *AudioALSAHardwareResourceManager::getInstance() {
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSAHardwareResourceManager == NULL) {
+ mAudioALSAHardwareResourceManager = new AudioALSAHardwareResourceManager();
+ }
+ ASSERT(mAudioALSAHardwareResourceManager != NULL);
+ return mAudioALSAHardwareResourceManager;
+}
+
+status_t AudioALSAHardwareResourceManager::ResetDevice(void) {
+ return NO_ERROR;
+}
+
+AudioALSAHardwareResourceManager::AudioALSAHardwareResourceManager() :
+ mMixer(NULL),
+ mPcmDL(NULL),
+ mDeviceConfigManager(NULL),
+ mOutputDevices(AUDIO_DEVICE_NONE),
+ mInputDevice(AUDIO_DEVICE_NONE),
+ mOutputDeviceSampleRate(44100),
+ mInputDeviceSampleRate(48000),
+ mIsChangingInputDevice(false),
+ mStartOutputDevicesCount(0),
+ mStartInputDeviceCount(0),
+ mSpeakerStatusChangeCb(NULL),
+#if defined(MTK_AUDIO_MIC_INVERSE) || defined(DEN_PHONE_MIC_INVERSE)
+ mMicInverse(true), // if defined MTK_AUDIO_MIC_INVERSE, default invert main & ref mic
+#else
+ mMicInverse(false),
+#endif
+ mBuiltInMicSpecificType(BUILTIN_MIC_DEFAULT),
+#ifdef MTK_HIFIAUDIO_SUPPORT
+ mHiFiState(false),
+ mHiFiDACStatusCount(0),
+#endif
+ mNumHSPole(4),
+ mHeadchange(false),
+ mSmartPaController(NULL),
+ mSpkPcmOut(NULL),
+ mA2dpDeviceLatency(A2DP_DEFAULT_LANTENCY),
+ mA2dpFwLatency(0) {
+ ALOGD("%s()", __FUNCTION__);
+
+#ifdef CONFIG_MT_ENG_BUILD
+ mLogEnable = 1;
+#else
+ mLogEnable = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);
+#endif
+ mStartInputDeviceSeqeunce.clear();
+
+ mNumPhoneMicSupport = 1;
+
+#ifdef MTK_HIFIAUDIO_SUPPORT
+ mHiFiState = false;
+#endif
+
+}
+
+
+AudioALSAHardwareResourceManager::~AudioALSAHardwareResourceManager() {
+ ALOGD("%s()", __FUNCTION__);
+ AL_AUTOLOCK(mGetInstanceLock);
+ mAudioALSAHardwareResourceManager = NULL;
+}
+
+/**
+ * output devices
+ */
+status_t AudioALSAHardwareResourceManager::setOutputDevice(const audio_devices_t new_devices, const uint32_t sample_rate) {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::startOutputDevice(const audio_devices_t new_devices, const uint32_t SampleRate) {
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::stopOutputDevice() {
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::changeOutputDevice(const audio_devices_t new_devices) {
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::startOutputDevice_l(const audio_devices_t new_devices, const uint32_t SampleRate) {
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::stopOutputDevice_l() {
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::changeOutputDevice_l(const audio_devices_t new_devices, const uint32_t SampleRate) {
+ return NO_ERROR;
+}
+
+bool AudioALSAHardwareResourceManager::isSharedOutDevice(audio_devices_t device) {
+ return true;
+}
+
+/**
+ * input devices
+ */
+status_t AudioALSAHardwareResourceManager::setInputDevice(const audio_devices_t new_devices) {
+ return NO_ERROR;
+}
+
+void AudioALSAHardwareResourceManager::setMIC1Mode(bool isHeadsetMic) {
+ return;
+}
+
+void AudioALSAHardwareResourceManager::setMIC2Mode(bool isHeadsetMic) {
+ return;
+}
+
+void AudioALSAHardwareResourceManager::setMIC3Mode(bool isHeadsetMic) {
+ return;
+}
+
+static void setSingleDmicLoopbackType(builtin_mic_specific_type mBuiltInMicSpecificType,
+ bool mMicInverse, bool enable) {
+ return;
+}
+
+status_t AudioALSAHardwareResourceManager::startInputDevice(const audio_devices_t new_device) {
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::stopInputDevice(const audio_devices_t stop_device) {
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::changeInputDevice(const audio_devices_t new_device) {
+ return NO_ERROR;
+}
+
+
+
+status_t AudioALSAHardwareResourceManager::setHWGain2DigitalGain(const uint32_t gain) {
+ return NO_ERROR;
+}
+
+
+
+status_t AudioALSAHardwareResourceManager::setInterruptRate(const audio_output_flags_t flag,
+ const uint32_t rate) {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::setInterruptRate2(const uint32_t rate) {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::setULInterruptRate(const uint32_t rate) {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::openAddaOutput(const uint32_t sample_rate) {
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::closeAddaOutput() {
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::setSgenMode(const sgen_mode_t sgen_mode) {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::setSgenSampleRate(const sgen_mode_samplerate_t sample_rate) {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::setSgenMute(int channel, bool mute) {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::setSgenFreqDiv(int channel, int freqDiv) {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::EnableSideToneFilter(const bool enable) {
+ return NO_ERROR;
+}
+
+bool AudioALSAHardwareResourceManager::GetExtDacPropertyEnable() {
+ return false;
+}
+
+status_t AudioALSAHardwareResourceManager::SetExtDacGpioEnable(bool bEnable) {
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::setMicType(void) {
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::setSPKCurrentSensor(bool bSwitch) {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::setSPKCurrentSensorPeakDetectorReset(bool bSwitch) {
+ return NO_ERROR;
+}
+
+uint32_t AudioALSAHardwareResourceManager::updatePhoneMicMode() {
+ return 0;
+}
+
+bool AudioALSAHardwareResourceManager::setSpeakerStatusChangeCb(SpeakerStatusChangeCb cb) {
+ mSpeakerStatusChangeCb = cb;
+ return true;
+}
+
+bool AudioALSAHardwareResourceManager::notifyOutputDeviceStatusChange(const audio_devices_t device, const DeviceStatus status) {
+ return true;
+}
+
+audio_devices_t AudioALSAHardwareResourceManager::getOutputDevice() {
+ return mOutputDevices;
+}
+
+audio_devices_t AudioALSAHardwareResourceManager::getInputDevice() {
+ return mInputDevice;
+}
+
+
+status_t AudioALSAHardwareResourceManager::setMicInverse(bool bMicInverse) {
+ return NO_ERROR;
+}
+
+void AudioALSAHardwareResourceManager::EnableAudBufClk(bool bEanble) {
+ return;
+}
+
+
+bool AudioALSAHardwareResourceManager::getMicInverse(void) {
+#if defined(MTK_AUDIO_MIC_INVERSE) || defined(DEN_PHONE_MIC_INVERSE)
+ ALOGD("%s(), mMicInverse = %d", __FUNCTION__, !mMicInverse);
+ return !mMicInverse;
+#else
+ ALOGD("%s(), mMicInverse = %d", __FUNCTION__, mMicInverse);
+ return mMicInverse;
+#endif
+}
+
+
+void AudioALSAHardwareResourceManager::setAudioDebug(const bool enable) {
+ return;
+}
+
+int AudioALSAHardwareResourceManager::setNonSmartPAType() {
+ return 0;
+}
+
+int AudioALSAHardwareResourceManager::getNonSmartPAType() {
+ return AUDIO_SPK_EXTAMP_LO;
+}
+
+status_t AudioALSAHardwareResourceManager::OpenReceiverPath(const uint32_t SampleRate __unused) {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::CloseReceiverPath() {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::OpenHeadphonePath(const uint32_t SampleRate __unused) {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::CloseHeadphonePath() {
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::OpenSpeakerPath(const uint32_t SampleRate) {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::CloseSpeakerPath() {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::OpenHeadphoneSpeakerPath(const uint32_t SampleRate) {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::CloseHeadphoneSpeakerPath() {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::OpenBuiltInMicPath() {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::CloseBuiltInMicPath() {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::OpenBackMicPath() {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::CloseBackMicPath() {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::OpenWiredHeadsetMicPath() {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::CloseWiredHeadsetMicPath() {
+ return NO_ERROR;
+}
+
+void AudioALSAHardwareResourceManager::HpImpeDanceDetect(void) {
+ return;
+}
+
+void AudioALSAHardwareResourceManager::setDPDModule(bool enable) {
+ return;
+}
+
+void AudioALSAHardwareResourceManager::setHeadphoneLowPowerMode(bool enable) {
+ return;
+}
+
+void AudioALSAHardwareResourceManager::setCodecSampleRate(const uint32_t sample_rate) {
+ return;
+}
+
+void AudioALSAHardwareResourceManager::resetA2dpDeviceLatency(void) {
+ mA2dpDeviceLatency = A2DP_DEFAULT_LANTENCY;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/AudioGainTableParamParser.cpp b/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/AudioGainTableParamParser.cpp
new file mode 100644
index 0000000..71db130
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/AudioGainTableParamParser.cpp
@@ -0,0 +1,993 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioGainTableParamParser.h"
+
+#include <utils/Log.h>
+#include "AudioUtility.h"//Mutex/assert
+#include <system/audio.h>
+
+#include <string>
+#if !defined(MTK_YOCTO_AUDIO)
+#include "AudioSmartPaController.h"
+#include "AudioALSAHardwareResourceManager.h"
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "GainTableParamParser"
+
+#ifdef ALOGG
+#undef ALOGG
+#endif
+#ifdef CONFIG_MT_ENG_BUILD
+#define ALOGG(...) ALOGD(__VA_ARGS__)
+#else
+#define ALOGG(...)
+#endif
+
+namespace android {
+
+// Device
+const std::string gppDeviceXmlName[NUM_GAIN_DEVICE] = {
+ "SPK",
+ "SPK_TBOX",
+};
+// Speech
+const std::string gppBandXmlName[NUM_GAIN_SPEECH_BAND] = {
+ "NB",
+ "WB",
+ "SWB"
+};
+
+const std::string gppNetXmlName[NUM_GAIN_SPEECH_NETWORK] = {
+ "GSM"
+};
+
+/*==============================================================================
+ * Singleton Pattern
+ *============================================================================*/
+
+GainTableParamParser *GainTableParamParser::mGainTableParamParser = NULL;
+
+GainTableParamParser *GainTableParamParser::getInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+
+ if (mGainTableParamParser == NULL) {
+ mGainTableParamParser = new GainTableParamParser();
+ }
+ ASSERT(mGainTableParamParser != NULL);
+ return mGainTableParamParser;
+}
+/*==============================================================================
+ * Constructor / Destructor / Init / Deinit
+ *============================================================================*/
+
+GainTableParamParser::GainTableParamParser() {
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(appOps);
+ mAppHandle = NULL;
+ } else {
+ mAppHandle = appOps->appHandleGetInstance();
+ }
+ loadGainTableParam();
+}
+
+GainTableParamParser::~GainTableParamParser() {
+ for (unsigned int i = 0; i < NUM_GAIN_DEVICE; i++) {
+ mMapDlDigital[i].clear();
+ mMapDlAnalog[i].clear();
+ mSpec.swagcGainMap[i].clear();
+ mSpec.swagcGainMapDmic[i].clear();
+ mSpec.ulPgaGainMap[i].clear();
+ }
+}
+
+status_t GainTableParamParser::getGainTableParam(GainTableParam *_gainTable, std::vector<std::string> *sceneList) {
+ ALOGD("%s()", __FUNCTION__);
+ clearTableParam(_gainTable, sceneList->size());
+
+ status_t status = NO_ERROR;
+ _gainTable->sceneCount = (int)(sceneList->size());
+ status |= updateSpeechVol(_gainTable);
+#if !defined(MTK_YOCTO_AUDIO)
+ status |= updatePlaybackDigitalGain(_gainTable, sceneList);
+ status |= updatePlaybackAnalogGain(_gainTable, sceneList);
+ status |= updateRecordVol(_gainTable, sceneList);
+ status |= updateVoIPVol(_gainTable, sceneList);
+ // Ringback tone need to be updated after VOIP for initializing with voice stream gain
+ status |= updateRingbackVol(_gainTable);
+#endif
+ if (status != NO_ERROR) {
+ ALOGE("error, %s() failed, status = %d", __FUNCTION__, status);
+ return status;
+ }
+
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::getCategoryList(AudioType *audioType, std::vector<std::string> *sceneList) {
+ return NO_ERROR;
+}
+
+bool GainTableParamParser::isInSceneList(std::vector<std::string> *sceneList, std::string scene) {
+ return false;
+}
+
+status_t GainTableParamParser::getSceneList(std::vector<std::string> *sceneList) {
+ ALOGD("%s()", __FUNCTION__);
+
+ AudioType *audioType;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ // Initialize scene list and add Default scene
+ sceneList->clear();
+#if !defined(MTK_YOCTO_AUDIO)
+ sceneList->push_back("Default");
+ // Get scene from XML
+ // PlaybackVolDigi
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, PLAY_DIGI_AUDIOTYPE_NAME);
+ if (!audioType) {
+ ALOGW("error: get audioType fail, audioTypeName = %s", PLAY_DIGI_AUDIOTYPE_NAME);
+ return BAD_VALUE;
+ }
+ getCategoryList(audioType, sceneList);
+
+ // PlaybackVolAna
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, PLAY_ANA_AUDIOTYPE_NAME);
+ if (!audioType) {
+ ALOGW("error: get audioType fail, audioTypeName = %s", PLAY_ANA_AUDIOTYPE_NAME);
+ return BAD_VALUE;
+ }
+ getCategoryList(audioType, sceneList);
+
+ // RecordVol
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, REC_VOL_AUDIOTYPE_NAME);
+ if (!audioType) {
+ ALOGW("error: get audioType fail, audioTypeName = %s", REC_VOL_AUDIOTYPE_NAME);
+ return BAD_VALUE;
+ }
+ getCategoryList(audioType, sceneList);
+
+ // VoIPVol
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, VOIP_VOL_AUDIOTYPE_NAME);
+ if (!audioType) {
+ ALOGW("error: get audioType fail, audioTypeName = %s", VOIP_VOL_AUDIOTYPE_NAME);
+ return BAD_VALUE;
+ }
+ getCategoryList(audioType, sceneList);
+#endif
+ for (int i = 0; i < (int)sceneList->size(); i++) {
+ ALOGG("%s(): sceneList[%d] = %s", __FUNCTION__, i, (*sceneList)[i].c_str());
+ }
+
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::getGainTableSpec(GainTableSpec **_gainTableSpec) {
+ *_gainTableSpec = &mSpec;
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::clearTableParam(GainTableParam *_gainTable, int sceneCount) {
+ if (sceneCount != 0) {
+ memset((void *)_gainTable->sceneGain, 0, sceneCount * sizeof(GainTableForScene));
+ }
+ ALOGD("-%s(), sceneCount=%d", __FUNCTION__, sceneCount);
+ memset((void *)&_gainTable->nonSceneGain, 0, sizeof(GainTableForNonScene));
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::updatePlaybackDigitalGain(GainTableParam *_gainTable, std::vector<std::string> *sceneList) {
+ ALOGD("%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::updatePlaybackAnalogGain(GainTableParam *_gainTable, std::vector<std::string> *sceneList) {
+ ALOGD("%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::updateSpeechVol(GainTableParam *_gainTable) {
+ ALOGD("%s()", __FUNCTION__);
+
+ // define xml names
+ char audioTypeName[] = SPEECH_VOL_AUDIOTYPE_NAME;
+ char paramStfName[] = "stf_gain";
+ char paramUlName[] = "ul_gain";
+ char paramDlName[] = "dl_gain";
+
+ const std::string *profileName = gppDeviceXmlName;
+ const std::string *bandName = gppBandXmlName;
+ const std::string *netName = gppNetXmlName;
+
+ // extract parameters from xml
+ AudioType *audioType;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, audioTypeName);
+ if (!audioType) {
+ ALOGW("%s(), error: get audioType fail, audioTypeName = %s", __FUNCTION__, audioTypeName);
+ return BAD_VALUE;
+ }
+
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ for (int net = 0; net < NUM_GAIN_SPEECH_NETWORK; net++) {
+ for (int band = 0; band < NUM_GAIN_SPEECH_BAND; band++) {
+ for (int device = 0; device < NUM_GAIN_DEVICE; device++) {
+ // get param unit using param path
+ std::string paramPath = "Band," +
+ bandName[band] +
+ ",Profile," +
+ profileName[device] +
+ ",Network," +
+ netName[net];
+ ALOGG("%s(), paramPath = %s", __FUNCTION__, paramPath.c_str());
+
+ ParamUnit *paramUnit;
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramPath.c_str());
+ if (!paramUnit) {
+ ALOGV("%s(), warn: get paramUnit fail, paramPath = %s", __FUNCTION__, paramPath.c_str());
+ continue;
+ }
+
+ // Sidetone gain
+ Param *param_stf_gain;
+ param_stf_gain = appOps->paramUnitGetParamByName(paramUnit, paramStfName);
+ if (!param_stf_gain) {
+ ALOGW("%s(), error: get param_stf_gain fail", __FUNCTION__);
+ continue;
+ }
+
+ if (*(short *)param_stf_gain->data > mSpec.sidetoneIdxMax ||
+ *(short *)param_stf_gain->data < mSpec.sidetoneIdxMin) {
+ ALOGW("%s(), error, band %d, device %d, stf_gain = %d out of bound", __FUNCTION__, band, device, *(short *)param_stf_gain->data);
+ }
+ _gainTable->nonSceneGain.sidetoneGain[band][net][device].gain = *(short *)param_stf_gain->data;
+
+ // Uplink gain
+ Param *param_ul_gain;
+ param_ul_gain = appOps->paramUnitGetParamByName(paramUnit, paramUlName);
+ if (!param_ul_gain) {
+ ALOGW("%s(), error: get param_ul_gain fail", __FUNCTION__);
+ continue;
+ }
+
+ if (*(int *)param_ul_gain->data > mSpec.micIdxMax[device] ||
+ *(int *)param_ul_gain->data < mSpec.micIdxMin[device]) {
+ ALOGW("%s(), error, ul_gain = %d out of bound, band %d, device %d", __FUNCTION__, *(int *)param_ul_gain->data, band, device);
+ }
+ _gainTable->nonSceneGain.speechMicGain[band][net][device].gain = *(int *)param_ul_gain->data;
+
+ // Downlink gain
+ Param *param_dl_gain;
+ param_dl_gain = appOps->paramUnitGetParamByName(paramUnit, paramDlName);
+ if (!param_dl_gain) {
+ ALOGW("%s(), error: get param_dl_gain fail", __FUNCTION__);
+ continue;
+ }
+ ALOGV("%s(), get dl done, paramPath = %s, mMapDlAnalogType[%d] = %d", __FUNCTION__, paramPath.c_str(), device, mMapDlAnalogType[device]);
+
+ short *shortArray = (short *)param_dl_gain->data;
+ int arraySize = param_dl_gain->arraySize;
+ if (arraySize + 1 > GAIN_VOL_INDEX_SIZE) {
+ ALOGW("%s(), error, param->arraySize + 1 %d exceed digital array size %d", __FUNCTION__, arraySize, GAIN_VOL_INDEX_SIZE);
+ arraySize = GAIN_VOL_INDEX_SIZE - 1;
+ }
+
+ if (mMapDlDigital[device].size() == 0 ||
+ mMapDlAnalog[device].size() == 0 ||
+ mMapDlDigital[device].size() != mMapDlAnalog[device].size()) {
+ ALOGE("%s(), error, digi & analog map size = %zu & %zu", __FUNCTION__, mMapDlDigital[device].size(),
+ mMapDlAnalog[device].size());
+ continue;
+ }
+
+ // xml 0~6 map to 1~7 here, index 0 is hard code mute
+ for (int i = 0; i < arraySize + 1; i++) {
+ short dl_idx, digital, analog;
+
+ if (i == 0) {
+ dl_idx = shortArray[i];
+ digital = -64;
+ analog = mMapDlAnalog[device][dl_idx];
+ } else {
+ dl_idx = shortArray[i - 1];
+ digital = mMapDlDigital[device][dl_idx];
+ analog = mMapDlAnalog[device][dl_idx];
+ }
+ // set digital gain
+
+ // convert 0~-64 dB to 0~255
+ if (digital > mSpec.digiDbMax) {
+ ALOGW("%s(), error, param out of range, val %d > %d", __FUNCTION__, digital, mSpec.digiDbMax);
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].digital = 0;
+ } else if (digital < mSpec.digiDbMin) {//TINA modify <= to <
+ ALOGV("%s(), error, param out of range, val %d <= %d", __FUNCTION__, digital, mSpec.digiDbMin);
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].digital = mSpec.keyVolumeStep;
+ } else {
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].digital = (digital * -1 * mSpec.keyStepPerDb);
+ }
+
+ // set analog gain
+ if (mMapDlAnalogType[device] < 0 || mMapDlAnalogType[device] >= NUM_GAIN_ANA_TYPE) {
+ if (i == 0) {
+ ALOGG("%s(), \tcontinue, paramPath = %s, mMapDlAnalogType[%d] = %d",
+ __FUNCTION__, paramPath.c_str(), device, mMapDlAnalogType[device]);
+ }
+ continue;
+ }
+
+ if (mMapDlAnalogType[device] == GAIN_ANA_SPEAKER) {
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].analog[mMapDlAnalogType[device]] = spkGainDb2Idx(analog);
+ } else if (mMapDlAnalogType[device] == GAIN_ANA_LINEOUT) {
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].analog[mMapDlAnalogType[device]] = lineoutBufferGainDb2Idx(analog);
+ } else if (mMapDlAnalogType[device] == GAIN_ANA_HEADPHONE) {
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].analog[mMapDlAnalogType[device]] = audioBufferGainDb2Idx(analog);
+ } else { // if (mMapDlAnalogType[device] == GAIN_ANA_HANDSET)
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].analog[mMapDlAnalogType[device]] = voiceBufferGainDb2Idx(analog);
+ }
+
+ ALOGV("%s(), \tvol_idx = %d, dl_gain_idx = %d, digital = %d, analog = %d, digitaldB = %d, analogdB = %d\n",
+ __FUNCTION__,
+ i,
+ dl_idx,
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].digital,
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].analog[mMapDlAnalogType[device]],
+ digital,
+ analog);
+ }
+ }
+ }
+ }
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::updateRecordVol(GainTableParam *_gainTable, std::vector<std::string> *sceneList) {
+ ALOGD("%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::updateVoIPVol(GainTableParam *_gainTable, std::vector<std::string> *sceneList) {
+ ALOGD("%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::updateRingbackVol(GainTableParam *_gainTable) {
+ ALOGD("%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::loadGainTableParam() {
+ ALOGD("%s()", __FUNCTION__);
+ loadGainTableSpec();
+ loadGainTableMapDl();
+ loadGainTableMapUl();
+#if !defined(MTK_YOCTO_AUDIO)
+ loadGainTableHpImpedance();
+#endif
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::loadGainTableSpec() {
+ ALOGD("%s()", __FUNCTION__);
+
+ // define xml names
+ char audioTypeName[] = VOLUME_AUDIOTYPE_NAME;
+
+ // extract parameters from xml
+ AudioType *audioType;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, audioTypeName);
+ if (!audioType) {
+ ALOGE("%s(), error: get audioType fail, audioTypeName = %s", __FUNCTION__, audioTypeName);
+ return BAD_VALUE;
+ }
+ std::string paramPath = "VolumeParam,Common";
+
+ ParamUnit *paramUnit;
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramPath.c_str());
+ if (!paramUnit) {
+ ALOGE("%s(), error: get paramUnit fail, paramPath = %s", __FUNCTION__, paramPath.c_str());
+ return BAD_VALUE;
+ }
+
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ // spec
+ getParam<int>(paramUnit, &mSpec.keyStepPerDb, "step_per_db");
+ ALOGV("%s(), mSpec.keyStepPerDb = %d", __FUNCTION__, mSpec.keyStepPerDb);
+ getParam<float>(paramUnit, &mSpec.keyDbPerStep, "db_per_step");
+ ALOGV("%s(), mSpec.keyDbPerStep = %f", __FUNCTION__, mSpec.keyDbPerStep);
+ getParam<float>(paramUnit, &mSpec.keyVolumeStep, "volume_step");
+ ALOGV("%s(), mSpec.keyVolumeStep = %f", __FUNCTION__, mSpec.keyVolumeStep);
+
+ getParam<int>(paramUnit, &mSpec.digiDbMax, "play_digi_range_max");
+ ALOGV("%s(), mSpec.digiDbMax = %d", __FUNCTION__, mSpec.digiDbMax);
+ getParam<int>(paramUnit, &mSpec.digiDbMin, "play_digi_range_min");
+ ALOGV("%s(), mSpec.digiDbMin = %d", __FUNCTION__, mSpec.digiDbMin);
+ getParam<int>(paramUnit, &mSpec.sidetoneIdxMax, "stf_idx_range_max");
+ ALOGV("%s(), mSpec.sidetoneIdxMax = %d", __FUNCTION__, mSpec.sidetoneIdxMax);
+ getParam<int>(paramUnit, &mSpec.sidetoneIdxMin, "stf_idx_range_min");
+ ALOGV("%s(), mSpec.sidetoneIdxMin = %d", __FUNCTION__, mSpec.sidetoneIdxMin);
+
+ getParam<int>(paramUnit, &mSpec.decRecMax, "dec_rec_max");
+ ALOGV("%s(), mSpec.decRecMax = %d", __FUNCTION__, mSpec.decRecMax);
+ getParam<int>(paramUnit, &mSpec.decRecStepPerDb, "dec_rec_step_per_db");
+ ALOGV("%s(), mSpec.decRecStepPerDb = %d", __FUNCTION__, mSpec.decRecStepPerDb);
+
+ getParam<int>(paramUnit, &mSpec.ulGainOffset, "ul_gain_offset");
+ ALOGV("%s(), mSpec.ulGainOffset = %d", __FUNCTION__, mSpec.ulGainOffset);
+ getParam<int>(paramUnit, &mSpec.ulPgaGainMapMax, "ul_pga_gain_map_max");
+ ALOGV("%s(), mSpec.ulPgaGainMapMax = %d", __FUNCTION__, mSpec.ulPgaGainMapMax);
+ getParam<int>(paramUnit, &mSpec.ulHwPgaIdxMax, "ul_hw_pga_max_idx");
+ ALOGV("%s(), mSpec.ulHwPgaIdxMax = %d", __FUNCTION__, mSpec.ulHwPgaIdxMax);
+
+ // audio buffer gain spec
+ getParamVector<short>(paramUnit, &mSpec.audioBufferGainDb, "audio_buffer_gain_db");
+ getParamVector<short>(paramUnit, &mSpec.audioBufferGainIdx, "audio_buffer_gain_idx");
+ getParamVector(paramUnit, &mSpec.audioBufferGainString, "audio_buffer_gain_string");
+
+ getParam<int>(paramUnit, &mSpec.audioBufferGainPreferMaxIdx, "audio_buffer_gain_prefer_max_idx");
+ getParam(paramUnit, &mSpec.audioBufLMixerName, "audio_buffer_l_mixer_name");
+ getParam(paramUnit, &mSpec.audioBufRMixerName, "audio_buffer_r_mixer_name");
+ ALOGD("%s(), mSpec.audioBufferGainPreferMaxIdx = %d, audioBufLMixerName = %s, audioBufRMixerName = %s",
+ __FUNCTION__,
+ mSpec.audioBufferGainPreferMaxIdx,
+ mSpec.audioBufLMixerName.c_str(),
+ mSpec.audioBufRMixerName.c_str());
+
+ size_t db_size = mSpec.audioBufferGainDb.size();
+ size_t idx_size = mSpec.audioBufferGainIdx.size();
+ size_t str_size = mSpec.audioBufferGainString.size();
+
+ if (db_size != idx_size || db_size != str_size) {
+ ALOGW("%s(), warn: db & idx & str_size mapping array size is not the same, db.size()=%zu, idx.size()=%zu, str_size()=%zu",
+ __FUNCTION__,
+ db_size,
+ idx_size,
+ str_size);
+ }
+
+ mSpec.numAudioBufferGainLevel = (db_size <= idx_size) ? db_size : idx_size;
+
+ for (unsigned int i = 0; i < mSpec.numAudioBufferGainLevel; i++) {
+ // ALOGG("%s(), audio buffer, db = %d, idx = %d", __FUNCTION__, mSpec.audioBufferGainDb[i], mSpec.audioBufferGainIdx[i]);
+ }
+
+ // voice buffer gain spec
+ getParamVector<short>(paramUnit, &mSpec.voiceBufferGainDb, "voice_buffer_gain_db");
+ getParamVector<short>(paramUnit, &mSpec.voiceBufferGainIdx, "voice_buffer_gain_idx");
+ getParamVector(paramUnit, &mSpec.voiceBufferGainString, "voice_buffer_gain_string");
+ getParam<int>(paramUnit, &mSpec.voiceBufferGainPreferMaxIdx, "voice_buffer_gain_prefer_max_idx");
+ getParam(paramUnit, &mSpec.voiceBufMixerName, "voice_buffer_mixer_name");
+ ALOGD("%s(), mSpec.voiceBufferGainPreferMaxIdx = %d, voiceBufMixerName = %s",
+ __FUNCTION__,
+ mSpec.voiceBufferGainPreferMaxIdx,
+ mSpec.voiceBufMixerName.c_str());
+
+ db_size = mSpec.voiceBufferGainDb.size();
+ idx_size = mSpec.voiceBufferGainIdx.size();
+ str_size = mSpec.voiceBufferGainString.size();
+
+ if (db_size != idx_size || db_size != str_size) {
+ ALOGW("%s(), warn: db & idx & str_size mapping array size is not the same, db.size()=%zu, idx.size()=%zu, str_size()=%zu",
+ __FUNCTION__,
+ db_size,
+ idx_size,
+ str_size);
+ }
+
+ mSpec.numVoiceBufferGainLevel = (db_size <= idx_size) ? db_size : idx_size;
+
+ for (unsigned int i = 0; i < mSpec.numVoiceBufferGainLevel; i++) {
+ // ALOGG("%s(), voice buffer, db = %d, idx = %d", __FUNCTION__, mSpec.voiceBufferGainDb[i], mSpec.voiceBufferGainIdx[i]);
+ }
+
+ // lineout buffer gain spec
+ getParamVector<short>(paramUnit, &mSpec.lineoutBufferGainDb, "lineout_buffer_gain_db");
+ getParamVector<short>(paramUnit, &mSpec.lineoutBufferGainIdx, "lineout_buffer_gain_idx");
+ getParamVector(paramUnit, &mSpec.lineoutBufferGainString, "lineout_buffer_gain_string");
+ getParam<int>(paramUnit, &mSpec.lineoutBufferGainPreferMaxIdx, "lineout_buffer_gain_prefer_max_idx");
+ ALOGD("%s(), mSpec.lineoutBufferGainPreferMaxIdx = %d", __FUNCTION__, mSpec.lineoutBufferGainPreferMaxIdx);
+
+ db_size = mSpec.lineoutBufferGainDb.size();
+ idx_size = mSpec.lineoutBufferGainIdx.size();
+ str_size = mSpec.lineoutBufferGainString.size();
+
+ if (db_size != idx_size || db_size != str_size) {
+ ALOGW("%s(), warn: db & idx & str_size mapping array size is not the same, db.size()=%zu, idx.size()=%zu, str_size()=%zu",
+ __FUNCTION__,
+ db_size,
+ idx_size,
+ str_size);
+ }
+
+ mSpec.numLineoutBufferGainLevel = (db_size <= idx_size) ? db_size : idx_size;
+
+ for (unsigned int i = 0; i < mSpec.numLineoutBufferGainLevel; i++) {
+ ALOGG("%s(), lineout buffer, db = %d, idx = %d", __FUNCTION__, mSpec.lineoutBufferGainDb[i], mSpec.lineoutBufferGainIdx[i]);
+ }
+
+ // spk gain spec
+ getParamVector<short>(paramUnit, &mSpec.spkGainDb, "spk_gain_db");
+ getParamVector<short>(paramUnit, &mSpec.spkGainIdx, "spk_gain_idx");
+ getParamVector(paramUnit, &mSpec.spkGainString, "spk_gain_string");
+
+ getParam<GAIN_ANA_TYPE>(paramUnit, &mSpec.spkAnaType, "spk_analog_type");
+ getParam(paramUnit, &mSpec.spkLMixerName, "spk_l_mixer_name");
+ getParam(paramUnit, &mSpec.spkRMixerName, "spk_r_mixer_name");
+ ALOGD("%s(), mSpec.spkAnaType = %d, spkLMixerName = %s, spkRMixerName = %s",
+ __FUNCTION__,
+ mSpec.spkAnaType,
+ mSpec.spkLMixerName.c_str(),
+ mSpec.spkRMixerName.c_str());
+
+
+ db_size = mSpec.spkGainDb.size();
+ idx_size = mSpec.spkGainIdx.size();
+ str_size = mSpec.spkGainString.size();
+
+ if (db_size != idx_size || db_size != str_size) {
+ ALOGW("%s(), warn: db & idx & str_size mapping array size is not the same, db.size()=%zu, idx.size()=%zu, str_size()=%zu",
+ __FUNCTION__,
+ db_size,
+ idx_size,
+ str_size);
+ }
+
+ mSpec.numSpkGainLevel = (db_size <= idx_size) ? db_size : idx_size;
+
+ for (unsigned int i = 0; i < mSpec.numSpkGainLevel; i++) {
+ // ALOGG("%s(), spk, db = %d, idx = %d", __FUNCTION__, mSpec.spkGainDb[i], mSpec.spkGainIdx[i]);
+ }
+
+ // ul gain map
+ getParamVector(paramUnit, &mSpec.ulPgaGainString, "ul_pga_gain_string");
+ getParam(paramUnit, &mSpec.ulPgaLMixerName, "ul_pga_l_mixer_name");
+ getParam(paramUnit, &mSpec.ulPgaRMixerName, "ul_pga_r_mixer_name");
+ ALOGD("%s(), mSpec.ulPgaLMixerName = %s, ulPgaRMixerName = %s",
+ __FUNCTION__,
+ mSpec.ulPgaLMixerName.c_str(), mSpec.ulPgaRMixerName.c_str());
+
+
+ // stf gain map
+ getParamVector<short>(paramUnit, &mSpec.stfGainMap, "stf_gain_map");
+ if ((int)mSpec.stfGainMap.size() != mSpec.sidetoneIdxMax + 1) {
+ ALOGW("%s(), warn: stfGainMap.size %zu != sidetoneIdxMax %d + 1",
+ __FUNCTION__,
+ mSpec.stfGainMap.size(),
+ mSpec.sidetoneIdxMax);
+ }
+
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ return NO_ERROR;
+}
+
+
+status_t GainTableParamParser::loadGainTableMapDl() {
+ ALOGD("%s()", __FUNCTION__);
+
+ // define xml names
+ char audioTypeName[] = GAIN_MAP_AUDIOTYPE_NAME;
+ char paramTotalName[] = "dl_total_gain";
+ char paramDigitalName[] = "dl_digital_gain";
+ char paramAnalogName[] = "dl_analog_gain";
+ char paramAnaTypeName[] = "dl_analog_type";
+
+ const std::string *profileName = gppDeviceXmlName;
+
+ // extract parameters from xml
+ AudioType *audioType;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, audioTypeName);
+ if (!audioType) {
+ ALOGW("%s, error: get audioType fail, audioTypeName = %s", __FUNCTION__, audioTypeName);
+ return BAD_VALUE;
+ }
+
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ for (int device = 0; device < NUM_GAIN_DEVICE; device++) {
+ // get param unit using param path
+ std::string paramPath = "Profile," + profileName[device];
+ ALOGV("%s, paramPath = %s", __FUNCTION__, paramPath.c_str());
+
+ ParamUnit *paramUnit;
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramPath.c_str());
+ if (!paramUnit) {
+ ALOGW("%s, error: get paramUnit fail, paramPath = %s", __FUNCTION__, paramPath.c_str());
+ continue;
+ }
+ Param *param_total;
+ param_total = appOps->paramUnitGetParamByName(paramUnit, paramTotalName);
+ if (!param_total) {
+ ALOGW("%s, error: get param_total fail, param_name = %s", __FUNCTION__, paramTotalName);
+ continue;
+ }
+
+ Param *param_digital;
+ param_digital = appOps->paramUnitGetParamByName(paramUnit, paramDigitalName);
+ if (!param_digital) {
+ ALOGW("%s, error: get param_digital fail, param_name = %s", __FUNCTION__, paramDigitalName);
+ continue;
+ }
+ Param *param_analog;
+ param_analog = appOps->paramUnitGetParamByName(paramUnit, paramAnalogName);
+ if (!param_analog) {
+ ALOGW("%s, error: get param_analog fail, param_name = %s", __FUNCTION__, paramAnalogName);
+ continue;
+ }
+ Param *param_ana_type;
+ param_ana_type = appOps->paramUnitGetParamByName(paramUnit, paramAnaTypeName);
+ if (!param_ana_type) {
+ ALOGW("%s, error: get param_ana_type fail, param_name = %s", __FUNCTION__, paramAnaTypeName);
+ continue;
+ }
+ mMapDlAnalogType[device] = (GAIN_ANA_TYPE) * (int *)param_ana_type->data;
+ ALOGD("%s, mMapDlAnalogType[%d]=%d, spkAnaType=%d", __FUNCTION__, device, mMapDlAnalogType[device], mSpec.spkAnaType);
+
+ if (param_digital->arraySize != param_analog->arraySize) {
+ ALOGE("%s, error: digi & ana mapping array size is not the same, digi.size()=%zu, ana.size()=%zu", __FUNCTION__, param_digital->arraySize, param_analog->arraySize);
+ continue;
+ }
+
+ if (param_total->arraySize != param_digital->arraySize) {
+ ALOGW("%s(), error, total gain && digi & ana array size does not match, total.size()=%zu, digi.size()=%zu", __FUNCTION__, param_total->arraySize, param_digital->arraySize);
+ }
+
+ short *digital_raw = (short *)param_digital->data;
+ mMapDlDigital[device].assign(digital_raw, digital_raw + param_digital->arraySize);
+
+ short *analog_raw = (short *)param_analog->data;
+ mMapDlAnalog[device].assign(analog_raw, analog_raw + param_analog->arraySize);
+
+ for (unsigned int i = 0; i < mMapDlDigital[device].size(); i++) {
+ ALOGV("%s(), digi = %d, ana = %d", __FUNCTION__, mMapDlDigital[device][i], mMapDlAnalog[device][i]);
+ }
+ }
+
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ return NO_ERROR;
+
+}
+
+status_t GainTableParamParser::loadGainTableMapUl() {
+ ALOGD("%s()", __FUNCTION__);
+
+ // define xml names
+ char audioTypeName[] = GAIN_MAP_UL_AUDIOTYPE_NAME;
+ char paramSwagcMapName[] = "swagc_gain_map";
+ char paramSwagcMapDmicName[] = "swagc_gain_map_dmic";
+ char paramUlPgaName[] = "ul_pga_gain_map";
+
+ const std::string *profileName = gppDeviceXmlName;
+
+ // extract parameters from xml
+ AudioType *audioType;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, audioTypeName);
+ if (!audioType) {
+ ALOGW("%s, error: get audioType fail, audioTypeName = %s", __FUNCTION__, audioTypeName);
+ return BAD_VALUE;
+ }
+
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ for (int device = 0; device < NUM_GAIN_DEVICE; device++) {
+ // get param unit using param path
+ std::string paramPath = "Profile," +
+ profileName[device];
+ ALOGG("%s, paramPath = %s", __FUNCTION__, paramPath.c_str());
+
+ ParamUnit *paramUnit;
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramPath.c_str());
+ if (!paramUnit) {
+ ALOGW("%s, error: get paramUnit fail, paramPath = %s", __FUNCTION__, paramPath.c_str());
+ continue;
+ }
+
+ Param *param_swagc;
+ param_swagc = appOps->paramUnitGetParamByName(paramUnit, paramSwagcMapName);
+ if (!param_swagc) {
+ ALOGW("%s, error: get param_swagc fail, param_name = %s", __FUNCTION__, paramSwagcMapName);
+ continue;
+ }
+
+ Param *param_swagc_dmic;
+ param_swagc_dmic = appOps->paramUnitGetParamByName(paramUnit, paramSwagcMapDmicName);
+ if (!param_swagc_dmic) {
+ ALOGW("%s, error: get param_swagc_dmic fail, param_name = %s", __FUNCTION__, paramSwagcMapDmicName);
+ continue;
+ }
+
+ Param *param_ul_pga;
+ param_ul_pga = appOps->paramUnitGetParamByName(paramUnit, paramUlPgaName);
+ if (!param_ul_pga) {
+ ALOGW("%s, error: get param_ul_pga fail, param_name = %s", __FUNCTION__, paramUlPgaName);
+ continue;
+ }
+
+ getParam<int>(paramUnit, &mSpec.micIdxMax[device], "mic_idx_range_max");
+ ALOGG("%s, mSpec.micIdxMax[%d] = %d", __FUNCTION__, device, mSpec.micIdxMax[device]);
+
+ getParam<int>(paramUnit, &mSpec.micIdxMin[device], "mic_idx_range_min");
+ ALOGG("%s, mSpec.micIdxMin[%d] = %d", __FUNCTION__, device, mSpec.micIdxMin[device]);
+
+ if (param_swagc->arraySize != param_ul_pga->arraySize ||
+ param_swagc->arraySize != param_swagc_dmic->arraySize) {
+ ALOGW("%s, error, swagc gain && ul_pga array size does not match, swagc.size()=%zu, pga.size()=%zu, swagc_dmic.size()=%zu", __FUNCTION__, param_swagc->arraySize, param_ul_pga->arraySize, param_swagc_dmic->arraySize, __FUNCTION__);
+ }
+
+ short *swagc_raw = (short *)param_swagc->data;
+ mSpec.swagcGainMap[device].assign(swagc_raw, swagc_raw + param_swagc->arraySize);
+
+ short *swagc_dmic_raw = (short *)param_swagc_dmic->data;
+ mSpec.swagcGainMapDmic[device].assign(swagc_dmic_raw, swagc_dmic_raw + param_swagc_dmic->arraySize);
+
+ short *pga_raw = (short *)param_ul_pga->data;
+ mSpec.ulPgaGainMap[device].assign(pga_raw, pga_raw + param_ul_pga->arraySize);
+
+ for (unsigned int i = 0; i < mSpec.swagcGainMap[device].size(); i++) {
+ ALOGV("%s, swagc = %d, swagc_dmic = %d, pga = %d", __FUNCTION__, mSpec.swagcGainMap[device][i], mSpec.swagcGainMapDmic[device][i], mSpec.ulPgaGainMap[device][i]);
+ }
+ }
+
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::loadGainTableHpImpedance() {
+ ALOGD("%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+/*
+ * Utility functions
+ */
+unsigned int GainTableParamParser::audioBufferGainDb2Idx(int dB) {
+ for (unsigned int i = 0; i < mSpec.numAudioBufferGainLevel; i++) {
+ if (dB == mSpec.audioBufferGainDb[i]) {
+ return mSpec.audioBufferGainIdx[i];
+ }
+ }
+
+ ALOGW("error, %s(), cannot find corresponding BufferGainIdx, return idx 0, %ddB", __FUNCTION__, mSpec.audioBufferGainDb[0]);
+ return 0;
+}
+
+unsigned int GainTableParamParser::voiceBufferGainDb2Idx(int dB) {
+ for (unsigned int i = 0; i < mSpec.numVoiceBufferGainLevel; i++) {
+ if (dB == mSpec.voiceBufferGainDb[i]) {
+ return mSpec.voiceBufferGainIdx[i];
+ }
+ }
+
+ ALOGW("error, %s(), cannot find corresponding BufferGainIdx, return idx 0, %ddB", __FUNCTION__, mSpec.voiceBufferGainDb[0]);
+ return 0;
+}
+
+unsigned int GainTableParamParser::lineoutBufferGainDb2Idx(int dB) {
+ for (unsigned int i = 0; i < mSpec.numLineoutBufferGainLevel; i++) {
+ if (dB == mSpec.lineoutBufferGainDb[i]) {
+ return mSpec.lineoutBufferGainIdx[i];
+ }
+ }
+
+ ALOGW("error, %s(), cannot find corresponding BufferGainIdx, return idx 0, %ddB", __FUNCTION__, mSpec.lineoutBufferGainDb[0]);
+ return 0;
+}
+
+unsigned int GainTableParamParser::spkGainDb2Idx(int dB) {
+ for (size_t i = 0; i < mSpec.numSpkGainLevel; i++) {
+ if (dB == mSpec.spkGainDb[i]) {
+ return mSpec.spkGainIdx[i];
+ }
+ }
+
+ ALOGW("error, %s(), cannot find corresponding BufferGainIdx, return idx 1, %ddB", __FUNCTION__, mSpec.spkGainDb[1]);
+ return 1;
+}
+
+int GainTableParamParser::gainIdx2Db(unsigned int idx, int anaType) {
+ int gainDb = 0;
+ switch (anaType) {
+ case GAIN_ANA_SPEAKER:
+ for (size_t i = 0; i < mSpec.numSpkGainLevel; i++) {
+ if (idx == mSpec.spkGainIdx[i]) {
+ gainDb = mSpec.spkGainDb[i];
+ break;
+ }
+ }
+ break;
+ case GAIN_ANA_LINEOUT:
+ for (size_t i = 0; i < mSpec.numLineoutBufferGainLevel; i++) {
+ if (idx == mSpec.lineoutBufferGainIdx[i]) {
+ gainDb = mSpec.lineoutBufferGainDb[i];
+ break;
+ }
+ }
+ break;
+ case GAIN_ANA_HEADPHONE:
+ for (size_t i = 0; i < mSpec.numAudioBufferGainLevel; i++) {
+ if (idx == mSpec.audioBufferGainIdx[i]) {
+ gainDb = mSpec.audioBufferGainDb[i];
+ break;
+ }
+ }
+ break;
+ default:
+ for (size_t i = 0; i < mSpec.numVoiceBufferGainLevel; i++) {
+ if (idx == mSpec.voiceBufferGainIdx[i]) {
+ gainDb = mSpec.voiceBufferGainDb[i];
+ break;
+ }
+ }
+ }
+ return gainDb;
+}
+
+GAIN_SPEECH_NETWORK GainTableParamParser::getGainSpeechNetwork(const char *name) {
+ for (int i = 0; i < NUM_GAIN_SPEECH_NETWORK; i++) {
+ if (strcmp(name, gppNetXmlName[i].c_str()) == 0) {
+ return (GAIN_SPEECH_NETWORK)i;
+ }
+ }
+
+ ALOGW("%s(), speech network not found, name %s, return 0", __FUNCTION__, name);
+
+ return (GAIN_SPEECH_NETWORK)0;
+}
+
+template<class T>
+status_t GainTableParamParser::getParam(ParamUnit *_paramUnit, T *_param, const char *_paramName) {
+ Param *param;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ param = appOps->paramUnitGetParamByName(_paramUnit, _paramName);
+ if (!param) {
+ ALOGE("error: get param fail, param_name = %s", _paramName);
+ return BAD_VALUE;
+ } else {
+ *_param = *(T *)param->data;
+ }
+
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::getParam(ParamUnit *_paramUnit, std::string *_param, const char *_paramName) {
+ Param *param;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ param = appOps->paramUnitGetParamByName(_paramUnit, _paramName);
+ if (!param) {
+ ALOGE("error: get param fail, param_name = %s", _paramName);
+ return BAD_VALUE;
+ } else {
+ if (param->paramInfo->dataType == TYPE_STR) {
+ *_param = (char *)param->data;
+ } else {
+ ALOGW("warn, param->paramInfo->dataType %d != TYPE_STR %d", param->paramInfo->dataType, TYPE_STR);
+ return BAD_VALUE;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+
+template<class T>
+status_t GainTableParamParser::getParamVector(ParamUnit *_paramUnit, std::vector<T> *_param, const char *_paramName) {
+ Param *param;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ param = appOps->paramUnitGetParamByName(_paramUnit, _paramName);
+ if (!param) {
+ ALOGE("error: get param fail, param_name = %s", _paramName);
+ return BAD_VALUE;
+ } else {
+ T *raw = (T *)param->data;
+ _param->assign(raw, raw + param->arraySize);
+ }
+
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::getParamVector(ParamUnit *_paramUnit, std::vector<std::string> *_param, const char *_paramName) {
+ Param *param;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ param = appOps->paramUnitGetParamByName(_paramUnit, _paramName);
+ if (!param) {
+ ALOGE("%s(),error: get param fail, param_name = %s", __FUNCTION__, _paramName);
+ return BAD_VALUE;
+ } else {
+ if (param->paramInfo->dataType == TYPE_STR) {
+ _param->clear();
+ std::string raw((char *)param->data);
+ ALOGV("%s(),%s = %s", __FUNCTION__, _paramName, raw.c_str());
+
+ ASSERT(!raw.empty());
+
+ int pre_pos = -1;
+ size_t find_pos = raw.find(',', pre_pos + 1);
+
+ std::string sub_str = raw.substr(pre_pos + 1, find_pos - pre_pos - 1);
+ do {
+ _param->push_back(sub_str);
+ //ALOGV("%s(),\t%s", __FUNCTION__, _param->back().c_str());
+ if (find_pos == std::string::npos) {
+ break;
+ }
+ pre_pos = find_pos;
+ find_pos = raw.find(',', pre_pos + 1);
+ sub_str = raw.substr(pre_pos + 1, find_pos - pre_pos - 1);
+ } while (!sub_str.empty());
+ } else {
+ ALOGW("%s(), warn, param->paramInfo->dataType %d != %d", __FUNCTION__, param->paramInfo->dataType, TYPE_STR);
+ return BAD_VALUE;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+
+}
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/SpeechParserGen93.cpp b/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/SpeechParserGen93.cpp
new file mode 100644
index 0000000..237c893
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/SpeechParserGen93.cpp
@@ -0,0 +1,1635 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechParserGen93"
+#include <SpeechParserGen93.h>
+#include <stdlib.h> /* atoi */
+
+#include <utils/Log.h>
+#include <inttypes.h>
+
+#include <AudioLock.h>
+#include <AudioUtility.h>//Mutex/assert
+#include <AudioEventThreadManager.h>
+#include <audio_memory_control.h>
+#include <SpeechUtility.h>
+
+
+namespace android {
+
+#define MAX_BYTE_PARAM_SPEECH 3434
+
+#define SPH_DUMP_STR_SIZE (500)
+#define SPH_PARAM_UNIT_DUMP_STR_SIZE (1024)
+
+static const uint32_t kSphParamSize = 0x3520; // AUDIO_TYPE_SPEECH, => 13K
+
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+
+struct SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT {
+ uint16_t sphParserVer;
+ uint16_t numLayer ;
+ uint16_t numEachLayer ;
+ uint16_t paramHeader[4] ;//Network, VoiceBand, Reserved, Reserved
+ uint16_t sphUnitMagiNum;
+
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT() : sphParserVer(0), numLayer(0),
+ numEachLayer(0), paramHeader(), sphUnitMagiNum(0) {}
+};
+
+struct AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT {
+ char *audioTypeName;
+ char numCategoryType;//4
+ std::vector<String8> categoryType;
+ std::vector<String8> categoryName;
+ char numParam;//4
+ std::vector<String8> paramName;
+ char *logPrintParamUnit;
+
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT() : audioTypeName(NULL), numCategoryType(0),
+ categoryType(), categoryName(), numParam(0), paramName(),
+ logPrintParamUnit(NULL) {}
+};
+
+struct SPEECH_PARAM_INFO_STRUCT {
+ speech_mode_t speechMode;
+ unsigned int idxVolume;
+ bool isBtNrecOn;
+ bool isLPBK;
+ unsigned char numHeadsetPole;
+ bool isSingleBandTransfer;
+ unsigned char idxVoiceBandStart;
+ bool isSV;
+ unsigned char idxTTY;
+
+ SPEECH_PARAM_INFO_STRUCT() : speechMode(SPEECH_MODE_NORMAL), idxVolume(0), isBtNrecOn(0),
+ isLPBK(0), numHeadsetPole(0), isSingleBandTransfer(0), idxVoiceBandStart(0),
+ isSV(0), idxTTY(0) {}
+};
+
+struct SPEECH_PARAM_SUPPORT_STRUCT {
+ bool isNetworkSupport;
+ bool isTTYSupport;
+ bool isSuperVolumeSupport;
+
+ SPEECH_PARAM_SUPPORT_STRUCT() : isNetworkSupport(0), isTTYSupport(0),
+ isSuperVolumeSupport(0) {}
+};
+
+struct SPEECH_NETWORK_STRUCT {
+ char name[128];
+ uint16_t supportBit;//4
+
+ SPEECH_NETWORK_STRUCT() : name(), supportBit(0) {}
+};
+
+enum speech_profile_t {
+ SPEECH_PROFILE_HANDSFREE = 0,
+ SPEECH_PROFILE_TBOX_HANDSFREE = 1,
+ SPEECH_PROFILE_BT_EARPHONE = 2,
+ SPEECH_PROFILE_BT_NREC_OFF = 3,
+
+ SPEECH_PROFILE_MAX_NUM = 4
+};
+
+//--------------------------------------------------------------------------------
+/* XML name */
+const char audioTypeNameList[8][128] = {
+ "Speech",
+ "SpeechDMNR",
+ "SpeechGeneral",
+ "SpeechMagiClarity",
+ "SpeechNetwork",
+ "SpeechEchoRef",
+ "SpeechDeReverb"
+};
+
+//audio type: Speech
+#define MAX_NUM_CATEGORY_TYPE_SPEECH 4
+#define MAX_NUM_PARAM_SPEECH 3
+const String8 audioType_Speech_CategoryType[ ] = {
+ String8("Band"),
+ String8("Profile"),
+ String8("VolIndex"),
+ String8("Network")
+};
+
+const String8 audioType_Speech_ParamName[ ] = {
+ String8("speech_mode_para"),
+ String8("sph_in_fir"),
+ String8("sph_out_fir"),
+ String8("sph_in_iir_mic1_dsp"),
+ String8("sph_in_iir_mic2_dsp"),
+ String8("sph_in_iir_enh_dsp"),
+ String8("sph_out_iir_enh_dsp")
+};
+
+#define NUM_VOLUME_SPEECH 7
+const char audioType_Speech_CategoryName3[NUM_VOLUME_SPEECH][128] = {"0", "1", "2", "3", "4", "5", "6"};
+const char audioType_Speech_CategoryName2[SPEECH_PROFILE_MAX_NUM][128] = {
+ "Handsfree",
+ "TBOX_Handsfree",
+ "BT_Earphone",
+ "BT_NREC_Off"
+};
+
+//--------------------------------------------------------------------------------
+//audio type: SpeechDMNR
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_DMNR 2
+#define MAX_NUM_PARAM_SPEECH_DMNR 1
+const String8 audioType_SpeechDMNR_CategoryType[ ] = {String8("Band"), String8("Profile")};
+const char audioType_SpeechDMNR_CategoryName2[2][128] = {"Handset", "MagiConference"};
+const String8 audioType_SpeechDMNR_ParamName[ ] = {String8("dmnr_para")};
+
+//--------------------------------------------------------------------------------
+//audio type: SpeechGeneral
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_GENERAL 1
+#define MAX_NUM_PARAM_SPEECH_GENERAL 2
+const String8 audioType_SpeechGeneral_CategoryType[ ] = {String8("CategoryLayer")};
+const char audioType_SpeechGeneral_CategoryName1[1][128] = {"Common"};
+const String8 audioType_SpeechGeneral_ParamName[ ] = {String8("speech_common_para"), String8("debug_info")};
+
+//--------------------------------------------------------------------------------
+//audio type: SpeechMagiClarity
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_MAGICLARITY 1
+#define MAX_NUM_PARAM_SPEECH_MAGICLARITY 1
+const String8 audioType_SpeechMagiClarity_CategoryType[ ] = {String8("CategoryLayer")};
+const char audioType_SpeechMagiClarity_CategoryName1[1][128] = {"Common"};
+const String8 audioType_SpeechMagiClarity_ParamName[ ] = {String8("shape_rx_fir_para")};
+
+//--------------------------------------------------------------------------------
+//audio type: SpeechNetwork
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_NETWORK 1
+#define MAX_NUM_PARAM_SPEECH_NETWORK 1
+const String8 audioType_SpeechNetwork_CategoryType[ ] = {String8("Network")};
+const String8 audioType_SpeechNetwork_ParamName[ ] = {String8("speech_network_support")};
+
+
+//--------------------------------------------------------------------------------
+//audio type: SpeechEchoRef
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_ECHOREF 1
+#define MAX_NUM_PARAM_SPEECH_ECHOREF 1
+const String8 audioType_SpeechEchoRef_CategoryType[ ] = {String8("Device")};
+const char audioType_SpeechEchoRef_CategoryName1[1][128] = {"USBAudio"};
+const String8 audioType_SpeechEchoRef_ParamName[ ] = {String8("EchoRef_para")};
+//--------------------------------------------------------------------------------
+//audio type: SpeechDeReverb
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_DEREVERB 2
+#define MAX_NUM_PARAM_SPEECH_DEREVERB 1
+const String8 audioType_SpeechDereverb_CategoryType[ ] = {String8("Band"), String8("Profile")};
+const char audioType_SpeechDereverb_CategoryName2[1][128] = {"Handsfree"};
+const String8 audioType_SpeechDereverb_ParamName[ ] = {String8("derev_para")};
+
+//--------------------------------------------------------------------------------
+
+#define NUM_NEED_UPDATE_XML 4
+#define LEN_XML_NAME 128
+const char needUpdateXmlList[NUM_NEED_UPDATE_XML][LEN_XML_NAME] = {
+ "Speech",
+ "SpeechDMNR",
+ "SpeechGeneral",
+ "SpeechDereverb",
+};
+
+/*==============================================================================
+ * Property keys
+ *============================================================================*/
+
+const char *PROPERTY_KEY_SPEECHLOG_ON = "persist.vendor.audiohal.speech_log_on";
+
+
+/*==============================================================================
+ * Callback Function
+ *============================================================================*/
+void callbackAudioXmlChanged(AppHandle *appHandle, const char *audioTypeName) {
+ ALOGD("+%s(), audioType = %s", __FUNCTION__, audioTypeName);
+
+ // reload XML file
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return;
+ }
+ bool isSpeechParamChanged = false, onlyUpdatedDuringCall = false;
+ int idxXmlNeedUpdate = 0;
+
+ if (appOps->appHandleReloadAudioType(appHandle, audioTypeName) != APP_ERROR) {
+ for (idxXmlNeedUpdate = 0; idxXmlNeedUpdate < NUM_NEED_UPDATE_XML; idxXmlNeedUpdate++) {
+ if (strcmp(audioTypeName, needUpdateXmlList[idxXmlNeedUpdate]) == 0) {
+ isSpeechParamChanged = true;
+ break;
+ }
+ }
+ if (strcmp(audioTypeName, "Speech") == 0) {
+ onlyUpdatedDuringCall = true;
+ }
+
+ if (isSpeechParamChanged) {
+ if (!onlyUpdatedDuringCall) {
+ SpeechParserGen93::getInstance()->mChangedXMLQueue.push_back((speech_type_dynamic_param_t)idxXmlNeedUpdate);
+ AudioEventThreadManager::getInstance()->notifyCallback(AUDIO_EVENT_SPEECH_PARAM_CHANGE, SpeechParserGen93::getInstance());
+ } else if (SpeechParserGen93::getInstance()->mCallOn) {
+ SpeechParserGen93::getInstance()->mChangedXMLQueue.push_back((speech_type_dynamic_param_t)idxXmlNeedUpdate);
+ AudioEventThreadManager::getInstance()->notifyCallback(AUDIO_EVENT_SPEECH_PARAM_CHANGE, SpeechParserGen93::getInstance());
+ }
+ }
+ } else {
+ (void) appHandle;
+ ALOGE("%s(), Reload xml fail!(audioType = %s)", __FUNCTION__, audioTypeName);
+ }
+}
+
+/*
+ * =============================================================================
+ * Singleton Pattern
+ * =============================================================================
+ */
+
+SpeechParserGen93 *SpeechParserGen93::uniqueSpeechParser = NULL;
+
+
+SpeechParserGen93 *SpeechParserGen93::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+ if (uniqueSpeechParser == NULL) {
+ uniqueSpeechParser = new SpeechParserGen93();
+ }
+ ASSERT(uniqueSpeechParser != NULL);
+ return uniqueSpeechParser;
+}
+
+/*
+ * =============================================================================
+ * Constructor / Destructor / Init / Deinit
+ * =============================================================================
+ */
+
+SpeechParserGen93::SpeechParserGen93() {
+ ALOGD("%s()", __FUNCTION__);
+ mSpeechParserAttribute.inputDevice = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ mSpeechParserAttribute.outputDevice = AUDIO_DEVICE_OUT_EARPIECE;
+ mSpeechParserAttribute.idxVolume = 3;
+ mSpeechParserAttribute.driverScenario = SPEECH_SCENARIO_SPEECH_ON;
+ mSpeechParserAttribute.ttyMode = AUD_TTY_OFF;
+ mSpeechParserAttribute.speechFeatureOn = 0;
+ mCallOn = false;
+ mSphParamSupport = NULL;
+ mSphParamInfo = NULL;
+ mListSpeechNetwork = NULL;
+ mNameForEachSpeechNetwork = NULL;
+ mChangedXMLQueue.clear();
+
+ mParamBufSize = getMaxBufferSize();
+ if (mParamBufSize <= 0) {
+ ALOGW("%s() mParamBufSize:%d, get buffer size fail!", __FUNCTION__, mParamBufSize);
+ }
+ init();
+}
+
+SpeechParserGen93::~SpeechParserGen93() {
+ ALOGD("%s()", __FUNCTION__);
+ AUDIO_FREE_POINTER(mParamBuf);
+ AUDIO_FREE_POINTER(mNameForEachSpeechNetwork);
+ AUDIO_FREE_POINTER(mListSpeechNetwork);
+ AUDIO_FREE_POINTER(mSphParamInfo);
+ AUDIO_FREE_POINTER(mSphParamSupport);
+}
+
+void SpeechParserGen93::init() {
+ ALOGD("%s()", __FUNCTION__);
+
+ AUDIO_ALLOC_STRUCT(SPEECH_PARAM_SUPPORT_STRUCT, mSphParamSupport);
+ AUDIO_ALLOC_STRUCT(SPEECH_PARAM_INFO_STRUCT, mSphParamInfo);
+ AUDIO_ALLOC_STRUCT_ARRAY(SPEECH_NETWORK_STRUCT, 12, mListSpeechNetwork);
+ AUDIO_ALLOC_STRUCT_ARRAY(SPEECH_NETWORK_STRUCT, 12, mNameForEachSpeechNetwork);
+
+ initAppParser();
+ initSpeechNetwork();
+
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ } else {
+ const char *strSphVersion = appOps->appHandleGetFeatureOptionValue(mAppHandle, "SPH_PARAM_VERSION");
+ if (strSphVersion != NULL) {
+ sscanf(strSphVersion, "%" SCNd8 ".%" SCNd8, &mSpeechParamVerFirst, &mSpeechParamVerLast);
+ switch (mSpeechParamVerFirst) {
+ case 2:
+ mSphParamSupport->isNetworkSupport = true;
+ mNumSpeechParam = 7;
+ break;
+ case 1:
+ mSphParamSupport->isNetworkSupport = true;
+ mNumSpeechParam = 3;
+ break;
+ default:
+ mSphParamSupport->isNetworkSupport = false;
+ mNumSpeechParam = 3;
+ break;
+ }
+ } else {
+ mSpeechParamVerFirst = 0;
+ mSpeechParamVerLast = 0;
+ mSphParamSupport->isNetworkSupport = false;
+ mNumSpeechParam = 3;
+ }
+ const char *strSphTTY = appOps->appHandleGetFeatureOptionValue(mAppHandle, "SPH_PARAM_TTY");
+ if (strSphTTY != NULL) {
+ if (strcmp(strSphTTY, "yes") == 0) {
+ mSphParamSupport->isTTYSupport = true;
+ } else {
+ mSphParamSupport->isTTYSupport = false;
+ }
+ } else {
+ mSphParamSupport->isTTYSupport = false;
+ }
+
+ const char *strSphSV = appOps->appHandleGetFeatureOptionValue(mAppHandle, "SPH_PARAM_SV");
+ if (strSphSV != NULL) {
+ if (strcmp(strSphSV, "yes") == 0) {
+ mSphParamSupport->isSuperVolumeSupport = true;
+ } else {
+ mSphParamSupport->isSuperVolumeSupport = false;
+ }
+ } else {
+ mSphParamSupport->isSuperVolumeSupport = false;
+ }
+
+ ALOGD("%s() appHandleRegXmlChangedCb", __FUNCTION__);
+ /* XML changed callback process */
+ appOps->appHandleRegXmlChangedCb(mAppHandle, callbackAudioXmlChanged);
+ }
+}
+
+void SpeechParserGen93::deInit() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+/*==============================================================================
+ * SpeechParserGen93 Imeplementation
+ *============================================================================*/
+
+/**
+ * =========================================================================
+ * @brief Parsing param file to get parameters into pOutBuf
+ *
+ * @param speechParserAttribute: the attribute for parser
+ * @param pOutBuf: the output buffer
+ * @param sizeByteOutBuf: the size byte of output buffer
+ *
+ * @return int
+ * =========================================================================
+ */
+
+int SpeechParserGen93::getParamBuffer(SpeechParserAttribute speechParserAttribute, SpeechDataBufType *outBuf) {
+ ALOGV("%s() XML scenario: 0x%x", __FUNCTION__, speechParserAttribute.driverScenario);
+
+ mSpeechParserAttribute.inputDevice = speechParserAttribute.inputDevice;
+ mSpeechParserAttribute.outputDevice = speechParserAttribute.outputDevice;
+ mSpeechParserAttribute.idxVolume = speechParserAttribute.idxVolume;
+ mSpeechParserAttribute.driverScenario = speechParserAttribute.driverScenario;
+ mSpeechParserAttribute.speechFeatureOn = speechParserAttribute.speechFeatureOn;
+ mSpeechParserAttribute.ttyMode = speechParserAttribute.ttyMode;
+ ALOGD("%s() inputDevice:0x%x, outputDevice:0x%x, idxVolume:0x%x, Scenario:0x%x, FeatureOn:0x%x, ttyMode:0x%x",
+ __FUNCTION__, mSpeechParserAttribute.inputDevice, mSpeechParserAttribute.outputDevice,
+ mSpeechParserAttribute.idxVolume, mSpeechParserAttribute.driverScenario,
+ mSpeechParserAttribute.speechFeatureOn, mSpeechParserAttribute.ttyMode);
+
+ if (mSpeechParserAttribute.ttyMode != AUD_TTY_OFF && mSphParamSupport->isTTYSupport == false) {
+ mSpeechParserAttribute.ttyMode = AUD_TTY_OFF;
+ ALOGW("%s(), TTY not support! TTY mode: %d -> %d", __FUNCTION__,
+ speechParserAttribute.ttyMode, mSpeechParserAttribute.ttyMode);
+ }
+
+ if (getFeatureOn(SPEECH_FEATURE_SUPERVOLUME) && mSphParamSupport->isSuperVolumeSupport == false) {
+ mSpeechParserAttribute.speechFeatureOn &= ~(1 << SPEECH_FEATURE_SUPERVOLUME);
+ ALOGW("%s(), SuperVolume not support! FeatureOn: %d -> %d", __FUNCTION__,
+ speechParserAttribute.speechFeatureOn, mSpeechParserAttribute.speechFeatureOn);
+ }
+
+ /* dynamic allocate parser buffer */
+ AUDIO_FREE_POINTER(mParamBuf);
+ AUDIO_ALLOC_BUFFER(mParamBuf, mParamBufSize);
+ if (mParamBuf == NULL) {
+ ALOGW("%s() Allocate Parser Buffer Fail!! expect:%d", __FUNCTION__, mParamBufSize);
+ outBuf->memorySize = 0;
+ outBuf->dataSize = 0;
+ return -ENOMEM;
+ }
+ char *param_buf = (char *)mParamBuf;
+
+ uint32_t concateSize = 0, sizeByte = 0;
+
+ switch (mSpeechParserAttribute.driverScenario) {
+ case SPEECH_SCENARIO_SPEECH_ON:
+ sizeByte = (uint32_t)getSpeechParamUnit(param_buf);
+ concateSize += sizeByte;
+ sizeByte = (uint32_t)getDmnrParamUnit(param_buf + concateSize);
+ concateSize += sizeByte;
+ sizeByte = (uint32_t)getGeneralParamUnit(param_buf + concateSize);
+ concateSize += sizeByte;
+ sizeByte = (uint32_t)getMagiClarityParamUnit(param_buf + concateSize);
+ concateSize += sizeByte;
+#if defined(MTK_INCALL_DE_REVERB)
+ sizeByte = (uint32_t)getDereverbParamUnit(param_buf + concateSize);
+ concateSize += sizeByte;
+#endif
+ break;
+ case SPEECH_SCENARIO_PARAM_CHANGE:
+ if (mChangedXMLQueue.empty() != true) {
+ mIdxAudioType = mChangedXMLQueue.front();
+ mChangedXMLQueue.erase(mChangedXMLQueue.begin());
+ } else {
+ ALOGW("%s() Parameter changed XML queue empty!", __FUNCTION__);
+ }
+ if (mIdxAudioType == AUDIO_TYPE_SPEECH) {
+ sizeByte = (uint32_t)getSpeechParamUnit(param_buf);
+ } else if (mIdxAudioType == AUDIO_TYPE_SPEECH_DMNR) {
+ sizeByte = (uint32_t)getDmnrParamUnit(param_buf);
+ } else if (mIdxAudioType == AUDIO_TYPE_SPEECH_GENERAL) {
+ sizeByte = (uint32_t)getGeneralParamUnit(param_buf + concateSize);
+#if defined(MTK_INCALL_DE_REVERB)
+ } else if (mIdxAudioType == AUDIO_TYPE_SPEECH_DEREVERB) {
+ sizeByte = (uint32_t)getDereverbParamUnit(param_buf);
+#endif
+ } else {
+ ALOGW("%s(), Param Change type not support:%d", __FUNCTION__, mIdxAudioType);
+ }
+ concateSize += sizeByte;
+ break;
+ case SPEECH_SCENARIO_DEVICE_CHANGE:
+ case SPEECH_SCENARIO_VOLUME_CHANGE:
+ case SPEECH_SCENARIO_FEATURE_CHANGE:
+ sizeByte = (uint32_t)getSpeechParamUnit(param_buf);
+ concateSize += sizeByte;
+ break;
+ default:
+ ALOGW("%s(), not support scenario: %d", __FUNCTION__, mSpeechParserAttribute.driverScenario);
+ sizeByte = 0;
+ break;
+ }
+ outBuf->memorySize = kSphParamSize;
+ outBuf->dataSize = concateSize;
+ outBuf->bufferAddr = mParamBuf;
+
+ ALOGV("%s() XML scenario: 0x%x, outBufSize:%d", __FUNCTION__, speechParserAttribute.driverScenario, concateSize);
+
+ return 0;
+}
+
+/**
+ * =========================================================================
+ * @brief set keyString string to library
+ *
+ * @param keyString the "key=value" string
+ * @param sizeKeyString the size byte of string
+ *
+ * @return int
+ * =========================================================================
+ */
+
+int SpeechParserGen93::setKeyValuePair(const SpeechStringBufType *keyValuePair) {
+
+ ALOGD("+%s(): %s", __FUNCTION__, keyValuePair->stringAddr);
+
+ char *keyHeader = NULL;
+ char *keyString = NULL;
+ keyHeader = strtok_r(keyValuePair->stringAddr, ",", &keyString);
+
+ if (strcmp(keyHeader, SPEECH_PARSER_SET_KEY_PREFIX) != 0) {
+ ALOGE("%s(), Wrong Header: %s, expect:%s", __FUNCTION__, keyHeader, SPEECH_PARSER_SET_KEY_PREFIX);
+ return -EINVAL;
+ }
+
+ ALOGV("-%s(): %s", __FUNCTION__, keyValuePair->stringAddr);
+ return 0;
+}
+
+/**
+ * =========================================================================
+ * @brief get keyString string from library
+ *
+ * @param keyString there is only "key" when input,
+ and then library need rewrite "key=value" to keyString
+ * @param sizeKeyString the size byte of string
+ *
+ * @return int
+ * =========================================================================
+ */
+
+int SpeechParserGen93::getKeyValuePair(SpeechStringBufType *keyValuePair) {
+ ALOGV("%s(), keyString:%s", __FUNCTION__, keyValuePair->stringAddr);
+
+ char *keyHeader = NULL;
+ char *keyString = NULL;
+ keyHeader = strtok_r(keyValuePair->stringAddr, ",", &keyString);
+
+ if (strcmp(keyHeader, SPEECH_PARSER_GET_KEY_PREFIX) != 0) {
+ ALOGE("%s(), Wrong Header: %s, expect:%s", __FUNCTION__, keyHeader, SPEECH_PARSER_GET_KEY_PREFIX);
+ return -EINVAL;
+ }
+ char keyValueString[MAX_SPEECH_PARSER_KEY_LEN];
+ memset((void *)keyValueString, 0, MAX_SPEECH_PARSER_KEY_LEN);
+ if (strcmp(keyString, SPEECH_PARSER_PARAMBUF_SIZE) == 0) {
+ sprintf(keyValueString, "%d", kSphParamSize);
+ }
+ keyValuePair->stringAddr = keyValueString;
+ ALOGD("%s(),key:%s , return keyValue:%s", __FUNCTION__, keyString, keyValuePair->stringAddr);
+ return 0;
+}
+/**
+ * =========================================================================
+ * @brief update phone call status from driver
+ *
+ * @param callOn: the phone call status: true(On), false(Off)
+ *
+ * @return int
+ * =========================================================================
+ */
+int SpeechParserGen93::updatePhoneCallStatus(bool callOn) {
+ ALOGV("%s(), callOn:%d", __FUNCTION__, callOn);
+ if (callOn == false) {
+ AUDIO_FREE_POINTER(mParamBuf);
+ }
+ if (mCallOn == callOn) {
+ ALOGW("%s(), callOn(%d) == mCallOn(%d), return",
+ __FUNCTION__, callOn, mCallOn);
+ return 0;
+ }
+ mCallOn = callOn;
+ return 0;
+}
+
+uint32_t SpeechParserGen93::getMaxBufferSize() {
+ uint32_t paramBufSize = 0;
+ char keyString[MAX_SPEECH_PARSER_KEY_LEN];
+ memset((void *)keyString, 0, MAX_SPEECH_PARSER_KEY_LEN);
+
+ SpeechStringBufType keyValuePair;
+ memset(&keyValuePair, 0, sizeof(SpeechStringBufType));
+ keyValuePair.memorySize = strlen(keyString) + 1;
+ keyValuePair.stringSize = strlen(keyString);
+ keyValuePair.stringAddr = keyString;
+
+ sprintf(keyString, "%s,%s", SPEECH_PARSER_GET_KEY_PREFIX, SPEECH_PARSER_PARAMBUF_SIZE);//"SPEECH_PARSER_GET_PARAM,PARAMBUF_SIZE"
+ //get from default parser
+ getKeyValuePair(&keyValuePair);
+ paramBufSize += (uint32_t) atoi(keyValuePair.stringAddr);
+
+ //get from customized parser
+#if defined(CUSTOMIZED_PARSER)
+ SpOps *spOps = spOpsGetInstance();
+ SpHandle *spHandle = spOps->spHandleGetInstance();
+ spOps->getKeyValuePair(spHandle, &keyValuePair);
+ paramBufSize += (uint32_t) atoi(keyValuePair.stringAddr);
+#endif
+
+ ALOGV("%s() paramBufSize:%d", __FUNCTION__, paramBufSize);
+ return paramBufSize;
+
+}
+
+int SpeechParserGen93::getSpeechProfile(const SpeechParserAttribute speechParserAttribute) {
+ speech_profile_t idxSphProfile;
+
+ if (audio_is_bluetooth_sco_device(speechParserAttribute.outputDevice)) {
+ if (getFeatureOn(SPEECH_FEATURE_BTNREC)) {
+ idxSphProfile = SPEECH_PROFILE_BT_EARPHONE;
+ } else {
+ idxSphProfile = SPEECH_PROFILE_BT_NREC_OFF;
+ }
+ } else {
+ switch (speechParserAttribute.outputDevice) {
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ idxSphProfile = SPEECH_PROFILE_HANDSFREE;
+ break;
+ default:
+ idxSphProfile = SPEECH_PROFILE_HANDSFREE;
+ }
+ }
+ ALOGV("%s(), idxSphProfile = %d", __FUNCTION__, idxSphProfile);
+ return idxSphProfile;
+}
+
+int SpeechParserGen93::getDeverbProfile(const SpeechParserAttribute speechParserAttribute) {
+ speech_profile_t idxProfile;
+ switch (speechParserAttribute.outputDevice) {
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ idxProfile = SPEECH_PROFILE_HANDSFREE;
+ break;
+ default:
+ idxProfile = SPEECH_PROFILE_HANDSFREE;
+ }
+ ALOGV("%s(), idxProfile = %d", __FUNCTION__, idxProfile);
+ return idxProfile;
+}
+
+/*==============================================================================
+ * Original SpeechParserGen93 Imeplementation
+ *============================================================================*/
+
+void SpeechParserGen93::initAppParser() {
+ ALOGV("+%s()", __FUNCTION__);
+ /* Init AppHandle */
+ ALOGV("%s() appHandleGetInstance", __FUNCTION__);
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return;
+ }
+ mAppHandle = appOps->appHandleGetInstance();
+ ALOGD("%s() appHandleRegXmlChangedCb", __FUNCTION__);
+
+}
+
+status_t SpeechParserGen93::speechDataDump(char *bufDump,
+ uint16_t idxSphType,
+ const char *nameParam,
+ const char *speechParamData) {
+ if (nameParam == NULL) {
+ return NO_ERROR;
+ }
+ // Speech Log system property
+#if defined(MTK_YOCTO_AUDIO)
+ if (get_uint32_from_property(PROPERTY_KEY_SPEECHLOG_ON) == 0) {
+#if !defined(CONFIG_MT_ENG_BUILD) // user or user debug load
+ return NO_ERROR;
+#endif
+ }
+#else
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_SPEECHLOG_ON, property_value, "0"); //"0": default off
+ if (property_value[0] == '0') {
+#if !defined(CONFIG_MT_ENG_BUILD) // user or user debug load
+ return NO_ERROR;
+#endif
+ }
+#endif
+
+ ALOGV("+%s(), idxSphType=%d", __FUNCTION__, idxSphType);
+ char sphDumpStr[SPH_DUMP_STR_SIZE] = {0};
+ int idxDump = 0, sizeDump = 0, DataTypePrint = 0;
+ //speech parameter dump
+
+ switch (idxSphType) {
+ case AUDIO_TYPE_SPEECH: {
+ if (strcmp(nameParam, "speech_mode_para") == 0) {
+ sizeDump = 16;
+ } else if (strcmp(nameParam, "sph_in_fir") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_out_fir") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_in_iir_mic1_dsp") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_in_iir_mic2_dsp") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_in_iir_enh_dsp") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_out_iir_enh_dsp") == 0) {
+ sizeDump = 5;
+ }
+ break;
+ }
+ case AUDIO_TYPE_SPEECH_GENERAL: {
+ if (strcmp(nameParam, "speech_common_para") == 0) {
+ sizeDump = 12;
+ } else if (strcmp(nameParam, "debug_info") == 0) {
+ sizeDump = 8;
+ }
+ break;
+ }
+ case AUDIO_TYPE_SPEECH_NETWORK: {
+ if (strcmp(nameParam, "speech_network_support") == 0) {
+ DataTypePrint = 1;
+ sizeDump = 1;
+ }
+ break;
+ }
+ case AUDIO_TYPE_SPEECH_ECHOREF: {
+ if (strcmp(nameParam, "USBAudio") == 0) {
+ sizeDump = 3;
+ }
+ break;
+ }
+
+ }
+ snprintf(sphDumpStr, SPH_DUMP_STR_SIZE, "%s[%d]=", nameParam, sizeDump);
+
+ for (idxDump = 0; idxDump < sizeDump; idxDump++) {
+ char sphDumpTemp[100] = {0};
+ if (DataTypePrint == 1) {
+ snprintf(sphDumpTemp, 100, "[%d]0x%x,", idxDump, *((uint16_t *)speechParamData + idxDump));
+ } else {
+ snprintf(sphDumpTemp, 100, "[%d]%d,", idxDump, *((uint16_t *)speechParamData + idxDump));
+ }
+ audio_strncat(sphDumpStr, sphDumpTemp, SPH_DUMP_STR_SIZE);
+ }
+
+ if (idxDump != 0 && bufDump != NULL) {
+ audio_strncat(bufDump, sphDumpStr, SPH_DUMP_STR_SIZE);
+ }
+ return NO_ERROR;
+}
+
+status_t SpeechParserGen93::getSpeechParamFromAppParser(uint16_t idxSphType,
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT *paramLayerInfo,
+ char *bufParamUnit,
+ uint16_t *sizeByteTotal) {
+ ALOGV("+%s(), paramLayerInfo->numCategoryType=0x%x", __FUNCTION__, paramLayerInfo->numCategoryType);
+
+ if (mAppHandle == NULL) {
+ ALOGE("%s() mAppHandle == NULL, Assert!!!", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ char *categoryPath = NULL;
+ ParamUnit *paramUnit = NULL;
+ uint16_t sizeByteParam = 0, idxCount;
+ Param *SpeechParam;
+ UT_string *uts_categoryPath = NULL;
+
+ /* If user select a category path, just like "NarrowBand / Normal of Handset / Level0" */
+ utstring_new(uts_categoryPath);
+
+ ALOGV("%s(), categoryType.size=%zu, paramName.size=%zu", __FUNCTION__, paramLayerInfo->categoryType.size(), paramLayerInfo->paramName.size());
+ for (idxCount = 0; idxCount < paramLayerInfo->categoryType.size() ; idxCount++) {
+ ALOGV("%s(), categoryType[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo->categoryType.at(idxCount).string());
+ }
+ for (idxCount = 0; idxCount < paramLayerInfo->categoryName.size() ; idxCount++) {
+ ALOGV("%s(), categoryName[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo->categoryName.at(idxCount).string());
+ }
+
+
+ for (idxCount = 0; idxCount < paramLayerInfo->numCategoryType ; idxCount++) {
+ if (idxCount == paramLayerInfo->numCategoryType - 1) {
+ //last time concat
+ utstring_printf(uts_categoryPath, "%s,%s", (char *)(paramLayerInfo->categoryType.at(idxCount).string()), (char *)(paramLayerInfo->categoryName.at(idxCount).string()));
+ } else {
+ utstring_printf(uts_categoryPath, "%s,%s,", (char *)(paramLayerInfo->categoryType.at(idxCount).string()), (char *)(paramLayerInfo->categoryName.at(idxCount).string()));
+ }
+ }
+ categoryPath = strdup(utstring_body(uts_categoryPath));
+ utstring_free(uts_categoryPath);
+
+ ALOGV("%s() audioTypeName=%s", __FUNCTION__, paramLayerInfo->audioTypeName);
+ /* Query AudioType */
+ AppOps *appOps = appOpsGetInstance();
+ AudioType *audioType = NULL;
+ if (appOps == NULL) {
+ free(categoryPath);
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ } else {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo->audioTypeName);
+ }
+ if (!audioType) {
+ free(categoryPath);
+ ALOGE("%s() can't find audioTypeName=%s, Assert!!!", __FUNCTION__, paramLayerInfo->audioTypeName);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ /* Query the ParamUnit */
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, categoryPath);
+ if (!paramUnit) {
+ appOps->audioTypeUnlock(audioType);
+ ALOGE("%s() can't find paramUnit, Assert!!! audioType=%s, categoryPath=%s", __FUNCTION__, audioType->name, categoryPath);
+ free(categoryPath);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "(path=%s,id=%d),", categoryPath, paramUnit->paramId);
+ audio_strncat(paramLayerInfo->logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+
+ //for speech param dump
+ char *bufParamDump = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(bufParamDump, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ for (idxCount = 0; idxCount < (*paramLayerInfo).numParam ; idxCount++) {
+
+ SpeechParam = appOps->paramUnitGetParamByName(paramUnit, (const char *)paramLayerInfo->paramName.at(idxCount).string());
+ if (SpeechParam) {
+ sizeByteParam = sizeByteParaData((DATA_TYPE)SpeechParam->paramInfo->dataType, SpeechParam->arraySize);
+ memcpy(bufParamUnit + *sizeByteTotal, SpeechParam->data, sizeByteParam);
+ *sizeByteTotal += sizeByteParam;
+ ALOGV("%s() paramName=%s, sizeByteParam=%d",
+ __FUNCTION__, paramLayerInfo->paramName.at(idxCount).string(), sizeByteParam);
+ //speech parameter dump
+ speechDataDump(bufParamDump, idxSphType, (const char *)paramLayerInfo->paramName.at(idxCount).string(), (const char *)SpeechParam->data);
+ }
+ }
+
+ if (bufParamDump != NULL) {
+ if (bufParamDump[0] != 0) {
+ ALOGD("%s(),dump: %s", __FUNCTION__, bufParamDump);
+ }
+ delete[] bufParamDump;
+ }
+
+ appOps->audioTypeUnlock(audioType);
+ free(categoryPath);
+
+ return NO_ERROR;
+}
+
+uint16_t SpeechParserGen93::sizeByteParaData(uint16_t dataType, uint16_t arraySize) {
+ uint16_t sizeUnit = 4;
+ switch (dataType) {
+ case TYPE_INT:
+ sizeUnit = 4;
+ break;
+ case TYPE_UINT:
+ sizeUnit = 4;
+ break;
+ case TYPE_FLOAT:
+ sizeUnit = 4;
+ break;
+ case TYPE_BYTE_ARRAY:
+ sizeUnit = arraySize;
+ break;
+ case TYPE_UBYTE_ARRAY:
+ sizeUnit = arraySize;
+ break;
+ case TYPE_SHORT_ARRAY:
+ sizeUnit = arraySize << 1;
+ break;
+ case TYPE_USHORT_ARRAY:
+ sizeUnit = arraySize << 1;
+ break;
+ case TYPE_INT_ARRAY:
+ sizeUnit = arraySize << 2;
+ break;
+ case TYPE_UINT_ARRAY:
+ sizeUnit = arraySize << 2;
+ break;
+ default:
+ ALOGE("%s(), Not an available dataType(%d)", __FUNCTION__, dataType);
+
+ break;
+
+ }
+
+ ALOGV("-%s(), arraySize=%d, sizeUnit=%d", __FUNCTION__, arraySize, sizeUnit);
+
+ return sizeUnit;
+
+
+}
+
+status_t SpeechParserGen93::setMDParamUnitHdr(speech_type_dynamic_param_t idxAudioType,
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT *paramUnitHdr,
+ uint16_t configValue) {
+ switch (idxAudioType) {
+ case AUDIO_TYPE_SPEECH:
+ paramUnitHdr->sphUnitMagiNum = 0xAA01;
+ paramUnitHdr->sphParserVer = 1;
+ paramUnitHdr->numLayer = 0x2;
+ paramUnitHdr->paramHeader[0] = 0x1F;//all network use, while modem not check it
+ //Network: bit0: GSM, bit1: WCDMA,.bit2: CDMA, bit3: VoLTE, bit4:C2K
+ if (mSphParamInfo->isSingleBandTransfer) {
+ switch (configValue) {
+ case 0:
+ paramUnitHdr->paramHeader[1] = 0x1;//voice band:NB
+ break;
+ case 1:
+ paramUnitHdr->paramHeader[1] = 0x2;//voice band:WB
+ break;
+
+ default:
+ paramUnitHdr->paramHeader[1] = 0x1;//voice band:NB
+ break;
+ }
+ } else {
+ switch (configValue) {
+ case 1:
+ paramUnitHdr->paramHeader[1] = 0x1;//voice band:NB
+ break;
+ case 2:
+ paramUnitHdr->paramHeader[1] = 0x3;//voice band:NB,WB
+ break;
+ case 3:
+ paramUnitHdr->paramHeader[1] = 0x7;//voice band:NB,WB,SWB
+ break;
+ case 4:
+ paramUnitHdr->paramHeader[1] = 0xF;//voice band:NB,WB,SWB,FB
+ break;
+ default:
+ paramUnitHdr->paramHeader[1] = 0x3;//voice band:NB,WB
+ break;
+ }
+ }
+ paramUnitHdr->paramHeader[2] = (mSpeechParamVerFirst << 4) + mSpeechParamVerLast;
+ ALOGV("%s(), sphUnitMagiNum = 0x%x, SPH_PARAM_VERSION(0x%x)",
+ __FUNCTION__, paramUnitHdr->sphUnitMagiNum, paramUnitHdr->paramHeader[2]);
+ break;
+ case AUDIO_TYPE_SPEECH_DMNR:
+ paramUnitHdr->sphUnitMagiNum = 0xAA03;
+ paramUnitHdr->sphParserVer = 1;
+ paramUnitHdr->numLayer = 0x2;
+ paramUnitHdr->paramHeader[0] = 0x3;//OutputDeviceType
+ switch (configValue) {
+ case 1:
+ paramUnitHdr->paramHeader[1] = 0x1;//voice band:NB
+ break;
+ case 2:
+ paramUnitHdr->paramHeader[1] = 0x3;//voice band:NB,WB
+ break;
+ case 3:
+ paramUnitHdr->paramHeader[1] = 0x7;//voice band:NB,WB,SWB
+ break;
+ case 4:
+ paramUnitHdr->paramHeader[1] = 0xF;//voice band:NB,WB,SWB,FB
+ break;
+ default:
+ paramUnitHdr->paramHeader[1] = 0x3;//voice band:NB,WB
+ break;
+ }
+ paramUnitHdr->paramHeader[2] = (mSpeechParamVerFirst << 4) + mSpeechParamVerLast;
+ ALOGV("%s(), sphUnitMagiNum = 0x%x, Version = 0x%x",
+ __FUNCTION__, paramUnitHdr->sphUnitMagiNum, paramUnitHdr->paramHeader[2]);
+ break;
+ case AUDIO_TYPE_SPEECH_DEREVERB:
+ paramUnitHdr->sphUnitMagiNum = 0xAA11;
+ paramUnitHdr->sphParserVer = 1;
+ paramUnitHdr->numLayer = 0x2;
+ paramUnitHdr->paramHeader[0] = (configValue >> 12) & 0xF;//Supported Devices
+ paramUnitHdr->paramHeader[1] = 0x6;//Supported voice bands: WB,SWB
+ paramUnitHdr->paramHeader[2] = configValue & 0xFFF;
+ ALOGV("%s(), sphUnitMagiNum = 0x%x, device index = %d, param length = %d",
+ __FUNCTION__, paramUnitHdr->sphUnitMagiNum, paramUnitHdr->paramHeader[0], paramUnitHdr->paramHeader[2]);
+ break;
+
+ default:
+ break;
+ }
+
+ // Speech Log system property
+#if defined(MTK_YOCTO_AUDIO)
+ if (get_uint32_from_property(PROPERTY_KEY_SPEECHLOG_ON) == 0)
+#else
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_SPEECHLOG_ON, property_value, "0"); //"0": default off
+ if (property_value[0] == '0')
+#endif
+ {
+ return NO_ERROR;
+ } else {
+ char sphDumpStr[SPH_DUMP_STR_SIZE] = "MDParamUnitHdr ";
+ int idxDump = 0;
+ for (idxDump = 0; idxDump < (int)(sizeof(paramUnitHdr) >> 1); idxDump++) { //uint16_t
+ char sphDumpTemp[100] = {0};
+ snprintf(sphDumpTemp, 100, "[%d]0x%x, ", idxDump, *((uint16_t *)¶mUnitHdr + idxDump));
+ audio_strncat(sphDumpStr, sphDumpTemp, SPH_DUMP_STR_SIZE);
+ }
+ if (idxDump != 0) {
+ ALOGD("%s(), %s", __FUNCTION__, sphDumpStr);
+ }
+ }
+ return NO_ERROR;
+}
+
+uint16_t SpeechParserGen93::setMDParamDataHdr(SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT paramUnitHdr,
+ const char *cateBandName, const char *cateNetworkName) {
+ uint16_t idxCount = 0;
+ uint16_t dataHeader = 0, MaskNetwork = 0;
+ bool bNetworkMatch = false;
+
+ if (cateBandName != NULL) {
+ if (strcmp(cateBandName, "NB") == 0) { //All netwrok use
+ dataHeader = 0x1000;
+ } else if (strcmp(cateBandName, "WB") == 0) {
+ dataHeader = 0x2000;
+ } else if (strcmp(cateBandName, "SWB") == 0) {
+ dataHeader = 0x3000;
+ } else if (strcmp(cateBandName, "FB") == 0) {
+ dataHeader = 0x4000;
+ }
+ } else {
+ dataHeader = 0x1000;
+ }
+ //search matched network
+ if (cateNetworkName != NULL) {
+ for (idxCount = 0; idxCount < mNumSpeechNetwork ; idxCount++) {
+ ALOGV("%s(), cateNetwork= %s, mListSpeechNetwork[%d]=%s",
+ __FUNCTION__, cateNetworkName, idxCount, mListSpeechNetwork[idxCount].name);
+ if (strcmp(cateNetworkName, mListSpeechNetwork[idxCount].name) == 0) {
+ MaskNetwork = mListSpeechNetwork[idxCount].supportBit;
+ ALOGV("%s(), cateNetwork= %s, mListSpeechNetwork[%d]=%s, MaskNetwork=0x%x",
+ __FUNCTION__, cateNetworkName, idxCount, mListSpeechNetwork[idxCount].name, MaskNetwork);
+ bNetworkMatch = true;
+ break;
+ }
+ }
+ if (!bNetworkMatch) {
+ ALOGE("%s(), cateNetwork= %s, mListSpeechNetwork[%d]=%s, bNetworkMatch=%d, NO match!!!",
+ __FUNCTION__, cateNetworkName, idxCount, mListSpeechNetwork[idxCount].name, bNetworkMatch);
+ }
+ }
+ if (!mSphParamSupport->isNetworkSupport) {
+ dataHeader = dataHeader >> 8;
+ MaskNetwork = 0xF;
+ }
+ dataHeader |= MaskNetwork;
+ ALOGV("-%s(), sphUnitMagiNum=0x%x, dataHeader=0x%x, MaskNetwork=0x%x, cateBand=%s",
+ __FUNCTION__, paramUnitHdr.sphUnitMagiNum, dataHeader, MaskNetwork, cateBandName);
+
+ return dataHeader;
+}
+
+int SpeechParserGen93::initSpeechNetwork(void) {
+ uint16_t size = 0, idxCount, sizeByteFromApp = 0;
+ char *packedParamUnitFromApp = new char [10];
+ memset(packedParamUnitFromApp, 0, 10);
+
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+
+ //-------------
+ paramLayerInfo.audioTypeName = (char *) audioTypeNameList[AUDIO_TYPE_SPEECH_NETWORK];
+
+ if (mAppHandle == NULL) {
+ ALOGE("%s() mAppHandle == NULL, Assert!!!", __FUNCTION__);
+ ASSERT(0);
+ }
+
+ /* Query AudioType */
+ AppOps *appOps = appOpsGetInstance();
+ AudioType *audioType = NULL;
+ if (appOps != NULL) {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo.audioTypeName);
+ paramLayerInfo.numCategoryType = appOps->audioTypeGetNumOfCategoryType(audioType);//1
+
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_NETWORK;//4
+
+ paramLayerInfo.categoryType.assign(audioType_SpeechNetwork_CategoryType, audioType_SpeechNetwork_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechNetwork_ParamName, audioType_SpeechNetwork_ParamName + paramLayerInfo.numParam);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ ALOGV("%s(), categoryType.size=%zu, paramName.size=%zu", __FUNCTION__, paramLayerInfo.categoryType.size(), paramLayerInfo.paramName.size());
+ for (idxCount = 0; idxCount < paramLayerInfo.categoryType.size() ; idxCount++) {
+ ALOGV("%s(), categoryType[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.categoryType.at(idxCount).string());
+ }
+ for (idxCount = 0; idxCount < paramLayerInfo.paramName.size() ; idxCount++) {
+ ALOGV("%s(), paramName[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.paramName.at(idxCount).string());
+ }
+ //-----------
+ //parse layer
+ CategoryType *categoryNetwork = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_SpeechNetwork_CategoryType[0].string());
+ mNumSpeechNetwork = appOps->categoryTypeGetNumOfCategory(categoryNetwork);
+
+ //parse network
+ for (int i = 0; i < mNumSpeechNetwork; i++) {
+ Category *CateNetwork = appOps->categoryTypeGetCategoryByIndex(categoryNetwork, i);
+ sizeByteFromApp = 0;
+ //clear
+ while (!paramLayerInfo.categoryName.empty()) {
+ paramLayerInfo.categoryName.pop_back();
+ }
+ audio_strncpy(mListSpeechNetwork[i].name, CateNetwork->name, 128);
+
+ paramLayerInfo.categoryName.push_back(String8(CateNetwork->name));//Network
+
+ getSpeechParamFromAppParser(AUDIO_TYPE_SPEECH_NETWORK, ¶mLayerInfo, packedParamUnitFromApp, &sizeByteFromApp);
+ mListSpeechNetwork[i].supportBit = *((uint16_t *)packedParamUnitFromApp);
+ size += sizeByteFromApp;
+
+ ALOGV("%s(), i=%d, sizeByteFromApp=%d, supportBit=0x%x",
+ __FUNCTION__, i, sizeByteFromApp, mListSpeechNetwork[i].supportBit);
+ }
+ ALOGV("-%s(), total size byte=%d", __FUNCTION__, size);
+ } else {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ }
+ //init the Name mapping table for each SpeechNetwork
+ bool IsNetworkFound = false;
+ for (int bitIndex = 0; bitIndex < 12; bitIndex++) {
+ IsNetworkFound = false;
+ for (int NetworkIndex = 0; NetworkIndex < mNumSpeechNetwork; NetworkIndex++) {
+ if (((mListSpeechNetwork[NetworkIndex].supportBit >> bitIndex) & 1) == 1) {
+ audio_strncpy(mNameForEachSpeechNetwork[bitIndex].name, mListSpeechNetwork[NetworkIndex].name, 128);
+ IsNetworkFound = true;
+ break;
+ }
+ }
+ if (!IsNetworkFound) {
+ audio_strncpy(mNameForEachSpeechNetwork[bitIndex].name, mListSpeechNetwork[0].name, 128);
+ }
+ ALOGV("%s(), mNameForEachSpeechNetwork[%d].name = %s",
+ __FUNCTION__, bitIndex, mNameForEachSpeechNetwork[bitIndex].name);
+ }
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+ return size;
+}
+
+
+int SpeechParserGen93::getSpeechParamUnit(char *bufParamUnit) {
+ uint16_t size = 0, idxCount, sizeByteFromApp = 0;
+ uint16_t dataHeader, idxInfo = 0, idxTmp = 0, numBand = 0, numNetwork = 0, numVolume = 0;
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT headerParamUnit;
+ int idxProfile = 0, parserOption = 0;
+
+ idxProfile = getSpeechProfile(mSpeechParserAttribute);
+ int idxVolume = mSpeechParserAttribute.idxVolume;
+ bool btHeadsetNrecOn = getFeatureOn(SPEECH_FEATURE_BTNREC);
+ mSphParamInfo->isBtNrecOn = btHeadsetNrecOn;
+ mSphParamInfo->idxVolume = idxVolume;
+
+ speech_mode_t sphMode = getSpeechModeByOutputDevice(mSpeechParserAttribute.outputDevice);
+
+ /* 93MD unused */
+ parserOption = 0;
+ //bit 0: dv profile, bit 1: single band, bit 4~7: band number
+ mSphParamInfo->isSingleBandTransfer = (bool)(parserOption & 0x2);
+ mSphParamInfo->idxVoiceBandStart = (unsigned char)((parserOption & 0xf0) >> 4);
+ //-----------------
+
+ ALOGD("+%s(), Volume=0x%x, BtNrecOn=0x%x, Profile=%d, parserOption=0x%x",
+ __FUNCTION__, idxVolume, btHeadsetNrecOn, idxProfile, parserOption);
+
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+ //-------------
+ paramLayerInfo.audioTypeName = (char *) audioTypeNameList[AUDIO_TYPE_SPEECH];
+
+ if (mAppHandle == NULL) {
+ ALOGE("%s() mAppHandle == NULL, Assert!!!", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ /* Query AudioType */
+ AppOps *appOps = appOpsGetInstance();
+ AudioType *audioType = NULL;
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ } else {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo.audioTypeName);
+ }
+
+ char *packedParamUnitFromApp = new char [MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp, 0, MAX_BYTE_PARAM_SPEECH);
+
+ paramLayerInfo.numCategoryType = appOps->audioTypeGetNumOfCategoryType(audioType);
+ paramLayerInfo.numParam = mNumSpeechParam;//4
+
+ paramLayerInfo.categoryType.assign(audioType_Speech_CategoryType, audioType_Speech_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_Speech_ParamName, audioType_Speech_ParamName + paramLayerInfo.numParam);
+
+ ALOGV("%s(), categoryType.size=%zu, paramName.size=%zu",
+ __FUNCTION__, paramLayerInfo.categoryType.size(), paramLayerInfo.paramName.size());
+ for (idxCount = 0; idxCount < paramLayerInfo.categoryType.size() ; idxCount++) {
+ ALOGV("%s(), categoryType[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.categoryType.at(idxCount).string());
+ }
+ for (idxCount = 0; idxCount < paramLayerInfo.paramName.size() ; idxCount++) {
+ ALOGV("%s(), paramName[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.paramName.at(idxCount).string());
+ }
+ //-----------
+
+ //parse layer
+ CategoryType *categoryNetwork = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_Speech_CategoryType[3].string());
+ CategoryType *categoryBand = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_Speech_CategoryType[0].string());
+ numNetwork = appOps->categoryTypeGetNumOfCategory(categoryNetwork);
+ numBand = appOps->categoryTypeGetNumOfCategory(categoryBand);
+
+ CategoryType *categoryVolume = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_Speech_CategoryType[2].string());
+ CategoryGroup *categoryGroupVolume = appOps->categoryTypeGetCategoryGroupByIndex(categoryVolume, 0);
+ numVolume = appOps->categoryGroupGetNumOfCategory(categoryGroupVolume);
+ idxTmp = (numBand & 0xF) << 4;
+ headerParamUnit.numEachLayer = idxTmp + (numNetwork & 0xF);
+ ALOGV("%s(), sphUnitMagiNum= 0x%x, numEachLayer=0x%x", __FUNCTION__, headerParamUnit.sphUnitMagiNum, headerParamUnit.numEachLayer);
+ if (mSphParamInfo->isSingleBandTransfer) {
+ setMDParamUnitHdr(AUDIO_TYPE_SPEECH, &headerParamUnit, mSphParamInfo->idxVoiceBandStart);
+ } else {
+ setMDParamUnitHdr(AUDIO_TYPE_SPEECH, &headerParamUnit, numBand);
+ }
+ ALOGV("%s(), sphUnitMagiNum= 0x%x, numEachLayer=0x%x", __FUNCTION__, headerParamUnit.sphUnitMagiNum, headerParamUnit.numEachLayer);
+ ALOGV("%s(), categoryNetwork= %s, categoryBand = %s, categoryVolume = %s",
+ __FUNCTION__, categoryNetwork->name, categoryBand->name, categoryVolume->name);
+ ALOGV("%s(), numNetwork= %d, numBand = %d, numVolume = %d", __FUNCTION__, numNetwork, numBand, numVolume);
+
+ memcpy(bufParamUnit + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ idxInfo = sphMode & 0xF;
+ ALOGV("%s(), add mode idxInfo=0x%x", __FUNCTION__, idxInfo);
+ idxTmp = idxVolume << 4;
+ idxInfo += idxTmp;
+ ALOGV("%s(), add volume<<4 idxInfo=0x%x, idxTmp=0x%x", __FUNCTION__, idxInfo, idxTmp);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ memcpy(bufParamUnit + size, &idxInfo, sizeof(idxInfo));
+ size += sizeof(idxInfo);
+ //parse network
+ for (int idxNetwork = 0; idxNetwork < numNetwork; idxNetwork++) {
+ Category *CateNetwork = appOps->categoryTypeGetCategoryByIndex(categoryNetwork, idxNetwork);
+ //parse band
+ for (int idxBand = mSphParamInfo->idxVoiceBandStart; idxBand < mSphParamInfo->idxVoiceBandStart + numBand; idxBand++) {
+ sizeByteFromApp = 0;
+ Category *CateBand = appOps->categoryTypeGetCategoryByIndex(categoryBand, idxBand);
+
+ dataHeader = setMDParamDataHdr(headerParamUnit, CateBand->name, CateNetwork->name);
+ memcpy(bufParamUnit + size, &dataHeader, sizeof(dataHeader));
+ size += sizeof(dataHeader);
+ while (!paramLayerInfo.categoryName.empty()) {
+ paramLayerInfo.categoryName.pop_back();
+ }
+ //Band
+ paramLayerInfo.categoryName.push_back(String8(CateBand->name));//Band
+ //Profile
+ paramLayerInfo.categoryName.push_back(String8(audioType_Speech_CategoryName2[idxProfile]));
+ //Volume
+ if (idxVolume > 6 || idxVolume < 0) {
+ paramLayerInfo.categoryName.push_back(String8(audioType_Speech_CategoryName3[3]));//volume
+ ALOGE("%s(), Invalid IdxVolume=0x%x, use 3 !!!", __FUNCTION__, idxVolume);
+ } else {
+ paramLayerInfo.categoryName.push_back(String8(audioType_Speech_CategoryName3[idxVolume]));
+ }
+ paramLayerInfo.categoryName.push_back(String8(CateNetwork->name));//Network
+
+ for (idxCount = 0; idxCount < paramLayerInfo.categoryName.size() ; idxCount++) {
+ ALOGV("%s(), categoryName[%d]= %s",
+ __FUNCTION__, idxCount, paramLayerInfo.categoryName.at(idxCount).string());
+ }
+
+ getSpeechParamFromAppParser(AUDIO_TYPE_SPEECH, ¶mLayerInfo, packedParamUnitFromApp, &sizeByteFromApp);
+
+ memcpy(bufParamUnit + size, packedParamUnitFromApp, sizeByteFromApp);
+ size += sizeByteFromApp;
+
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "size(b)=%d; total size(b)=%d", sizeByteFromApp, size);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ }
+
+ ALOGD("-%s(), MagiNum(0x%x),xml(%s),version(0x%x),%s", __FUNCTION__, headerParamUnit.sphUnitMagiNum,
+ paramLayerInfo.audioTypeName, headerParamUnit.paramHeader[2], paramLayerInfo.logPrintParamUnit);
+ //reset buffer pointer
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+ paramLayerInfo.logPrintParamUnit[0] = '\0';
+ }
+
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+
+ return size;
+}
+
+int SpeechParserGen93::getGeneralParamUnit(char *bufParamUnit) {
+ ALOGV("+%s()", __FUNCTION__);
+ uint16_t size = 0, idxCount = 0, idxCount2 = 0, sizeByteFromApp = 0;
+ uint16_t dataHeader;
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT headerParamUnit;
+
+ headerParamUnit.sphParserVer = 1;
+ headerParamUnit.numLayer = 0x1;
+ headerParamUnit.numEachLayer = 0x1;
+ headerParamUnit.paramHeader[0] = 0x1;//Common
+ headerParamUnit.sphUnitMagiNum = 0xAA02;
+
+ memcpy(bufParamUnit + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ char *packedParamUnitFromApp = new char [MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp, 0, MAX_BYTE_PARAM_SPEECH);
+
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+
+ paramLayerInfo.audioTypeName = (char *) audioTypeNameList[AUDIO_TYPE_SPEECH_GENERAL];
+ paramLayerInfo.numCategoryType = MAX_NUM_CATEGORY_TYPE_SPEECH_GENERAL;//4
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_GENERAL;//4
+
+ paramLayerInfo.categoryType.assign(audioType_SpeechGeneral_CategoryType, audioType_SpeechGeneral_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechGeneral_ParamName, audioType_SpeechGeneral_ParamName + paramLayerInfo.numParam);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ ALOGD("%s(), eParamUnitHdr.sphUnitMagiNum= 0x%x, categoryType.size=%zu, paramName.size=%zu",
+ __FUNCTION__, headerParamUnit.sphUnitMagiNum, paramLayerInfo.categoryType.size(), paramLayerInfo.paramName.size());
+ for (idxCount = 0; idxCount < paramLayerInfo.paramName.size() ; idxCount++) {
+ ALOGV("%s(), paramName[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.paramName.at(idxCount).string());
+ }
+
+ dataHeader = 0x000F;
+ memcpy(bufParamUnit + size, &dataHeader, sizeof(dataHeader));
+ size += sizeof(dataHeader);
+
+ paramLayerInfo.categoryName.push_back(String8(audioType_SpeechGeneral_CategoryName1[0]));
+
+ getSpeechParamFromAppParser(AUDIO_TYPE_SPEECH_GENERAL, ¶mLayerInfo, packedParamUnitFromApp, &sizeByteFromApp);
+
+ memcpy(bufParamUnit + size, packedParamUnitFromApp, sizeByteFromApp);
+ size += sizeByteFromApp;
+
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "total size(b)=%d", size);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ ALOGD("%s(),MagiNum(0x%x),xml(%s), %s",
+ __FUNCTION__, headerParamUnit.sphUnitMagiNum, paramLayerInfo.audioTypeName, paramLayerInfo.logPrintParamUnit);
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+
+ return size;
+}
+
+int SpeechParserGen93::getMagiClarityParamUnit(char *bufParamUnit) {
+ ALOGV("+%s()", __FUNCTION__);
+ uint16_t size = 0, idxCount = 0, idxCount2 = 0, sizeByteFromApp = 0;
+ uint16_t dataHeader;
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT headerParamUnit;
+
+ headerParamUnit.sphParserVer = 1;
+ headerParamUnit.numLayer = 0x1;
+ headerParamUnit.numEachLayer = 0x1;
+ headerParamUnit.paramHeader[0] = 0x1;//Common
+ headerParamUnit.sphUnitMagiNum = 0xAA04;
+
+ memcpy(bufParamUnit + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ char *packedParamUnitFromApp = new char [MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp, 0, MAX_BYTE_PARAM_SPEECH);
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+
+ paramLayerInfo.audioTypeName = (char *) audioTypeNameList[AUDIO_TYPE_SPEECH_MAGICLARITY];
+ paramLayerInfo.numCategoryType = MAX_NUM_CATEGORY_TYPE_SPEECH_MAGICLARITY;//4
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_MAGICLARITY;//4
+
+ paramLayerInfo.categoryType.assign(audioType_SpeechMagiClarity_CategoryType, audioType_SpeechMagiClarity_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechMagiClarity_ParamName, audioType_SpeechMagiClarity_ParamName + paramLayerInfo.numParam);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ for (idxCount = 0; idxCount < paramLayerInfo.paramName.size() ; idxCount++) {
+ ALOGD("%s(), paramName[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.paramName.at(idxCount).string());
+ }
+ dataHeader = 0x000F;
+ memcpy(bufParamUnit + size, &dataHeader, sizeof(dataHeader));
+ size += sizeof(dataHeader);
+
+ paramLayerInfo.categoryName.push_back(String8(audioType_SpeechMagiClarity_CategoryName1[0]));
+
+ getSpeechParamFromAppParser(AUDIO_TYPE_SPEECH_MAGICLARITY, ¶mLayerInfo, packedParamUnitFromApp, &sizeByteFromApp);
+
+ memcpy(bufParamUnit + size, packedParamUnitFromApp, sizeByteFromApp);
+ size += sizeByteFromApp;
+
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "total size(b)=%d", size);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ ALOGD("%s(),MagiNum(0x%x),xml(%s), %s", __FUNCTION__,
+ headerParamUnit.sphUnitMagiNum, paramLayerInfo.audioTypeName, paramLayerInfo.logPrintParamUnit);
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+
+ return size;
+}
+
+int SpeechParserGen93::getDmnrParamUnit(char *bufParamUnit) {
+ ALOGV("+%s()", __FUNCTION__);
+ uint16_t size = 0, idxBand = 0, idxProfile = 0, sizeByteFromApp = 0;
+ uint16_t dataHeader, idxTmp = 0, numBand = 0, numProfile = 0;
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT headerParamUnit;
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+
+ paramLayerInfo.audioTypeName = (char *) audioTypeNameList[AUDIO_TYPE_SPEECH_DMNR];
+ paramLayerInfo.numCategoryType = MAX_NUM_CATEGORY_TYPE_SPEECH_DMNR;//4
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_DMNR;//4
+ paramLayerInfo.categoryType.assign(audioType_SpeechDMNR_CategoryType, audioType_SpeechDMNR_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechDMNR_ParamName, audioType_SpeechDMNR_ParamName + paramLayerInfo.numParam);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ ALOGD("%s(), categoryType.size=%zu, paramName.size=%zu",
+ __FUNCTION__, paramLayerInfo.categoryType.size(), paramLayerInfo.paramName.size());
+ /* Query AudioType */
+ AppOps *appOps = appOpsGetInstance();
+ AudioType *audioType = NULL;
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ } else {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo.audioTypeName);
+ }
+ char *packedParamUnitFromApp = new char [MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp, 0, MAX_BYTE_PARAM_SPEECH);
+
+ CategoryType *categoryBand = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_SpeechDMNR_CategoryType[0].string());
+ numBand = appOps->categoryTypeGetNumOfCategory(categoryBand);
+ CategoryType *categoryProfile = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_SpeechDMNR_CategoryType[1].string());
+ numProfile = appOps->categoryTypeGetNumOfCategory(categoryProfile);
+ idxTmp = (numBand & 0xF) << 4;
+ headerParamUnit.numEachLayer = idxTmp + (numProfile & 0xF);
+ setMDParamUnitHdr(AUDIO_TYPE_SPEECH_DMNR, &headerParamUnit, numBand);
+
+ memcpy(bufParamUnit + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ for (idxBand = 0; idxBand < numBand; idxBand++) { //NB, WB, SWB
+ for (idxProfile = 0; idxProfile < numProfile; idxProfile++) {
+ sizeByteFromApp = 0;
+ dataHeader = ((idxBand + 1) << 4) + (idxProfile + 1);
+ memcpy(bufParamUnit + size, &dataHeader, sizeof(dataHeader));
+ size += sizeof(dataHeader);
+ Category *CateBand = appOps->categoryTypeGetCategoryByIndex(categoryBand, idxBand);
+ paramLayerInfo.categoryName.push_back(String8(CateBand->name));//Band
+ paramLayerInfo.categoryName.push_back(String8(audioType_SpeechDMNR_CategoryName2[idxProfile]));//Profile
+
+ getSpeechParamFromAppParser(AUDIO_TYPE_SPEECH_DMNR, ¶mLayerInfo, packedParamUnitFromApp, &sizeByteFromApp);
+
+ memcpy(bufParamUnit + size, packedParamUnitFromApp, sizeByteFromApp);
+ size += sizeByteFromApp;
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "header=0x%x[%d,%d], size(b)=%d;", dataHeader, idxBand, idxProfile, sizeByteFromApp);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ paramLayerInfo.categoryName.pop_back();
+ paramLayerInfo.categoryName.pop_back();
+
+ }
+ }
+
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "total size(b)=%d", size);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ ALOGD("%s(),MagiNum(0x%x),xml(%s), %s",
+ __FUNCTION__, headerParamUnit.sphUnitMagiNum, paramLayerInfo.audioTypeName, paramLayerInfo.logPrintParamUnit);
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+
+ return size;
+}
+
+int SpeechParserGen93::getDereverbParamUnit(char *bufParamUnit) {
+ ALOGV("+%s()", __FUNCTION__);
+ uint16_t size = 0, idxBand = 0, idxProfile = 0, sizeByteFromApp = 0;
+ uint16_t dataHeader, idxTmp = 0, numBand = 0, numProfile = 0;
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT headerParamUnit;
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+
+ paramLayerInfo.audioTypeName = (char *) audioTypeNameList[AUDIO_TYPE_SPEECH_DEREVERB];
+ paramLayerInfo.numCategoryType = MAX_NUM_CATEGORY_TYPE_SPEECH_DEREVERB;//4
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_DEREVERB;//4
+ paramLayerInfo.categoryType.assign(audioType_SpeechDereverb_CategoryType, audioType_SpeechDereverb_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechDereverb_ParamName, audioType_SpeechDereverb_ParamName + paramLayerInfo.numParam);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ ALOGD("%s(), categoryType.size=%zu, paramName.size=%zu",
+ __FUNCTION__, paramLayerInfo.categoryType.size(), paramLayerInfo.paramName.size());
+ /* Query AudioType */
+ AppOps *appOps = appOpsGetInstance();
+ AudioType *audioType = NULL;
+ if (appOps == NULL) {
+ ALOGE("%s(), appOps == NULL!!!line(%d)", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ } else {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo.audioTypeName);
+ }
+ if (audioType == NULL) {
+ ALOGE("%s(), audioType == NULL!!!xml name(%s), line(%d)", __FUNCTION__, paramLayerInfo.audioTypeName, __LINE__);
+ ASSERT(audioType);
+ return UNKNOWN_ERROR;
+ }
+ char *packedParamUnitFromApp = new char [MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp, 0, MAX_BYTE_PARAM_SPEECH);
+
+ CategoryType *categoryBand = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_SpeechDereverb_CategoryType[0].string());
+ numBand = appOps->categoryTypeGetNumOfCategory(categoryBand);
+ CategoryType *categoryProfile = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_SpeechDereverb_CategoryType[1].string());
+ numProfile = appOps->categoryTypeGetNumOfCategory(categoryProfile);
+ idxTmp = (numBand & 0xF) << 4;
+ headerParamUnit.numEachLayer = idxTmp + (numProfile & 0xF);
+
+ ParamUnit *paramUnit = appOps->audioTypeGetParamUnit(audioType, "");
+ ASSERT(paramUnit);
+ Param *param = appOps->paramUnitGetParamByName(paramUnit, "derev_para");
+ idxProfile = getDeverbProfile(mSpeechParserAttribute);
+
+ uint16_t length = param->arraySize&0xFFF;//0x258
+ uint16_t device = (idxProfile & 0xF) << 12;//0
+ uint16_t headerConfig = device + length;//0x0258
+ setMDParamUnitHdr(AUDIO_TYPE_SPEECH_DEREVERB, &headerParamUnit, headerConfig);
+
+ memcpy(bufParamUnit + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ for (idxBand = 0; idxBand < numBand; idxBand++) { //WB, SWB
+ sizeByteFromApp = 0;
+ dataHeader = idxBand + 1;
+ memcpy(bufParamUnit + size, &dataHeader, sizeof(dataHeader));
+ size += sizeof(dataHeader);
+ Category *CateBand = appOps->categoryTypeGetCategoryByIndex(categoryBand, idxBand);
+ paramLayerInfo.categoryName.push_back(String8(CateBand->name));//Band
+ paramLayerInfo.categoryName.push_back(String8(audioType_SpeechDereverb_CategoryName2[idxProfile]));
+
+ getSpeechParamFromAppParser(AUDIO_TYPE_SPEECH_DEREVERB, ¶mLayerInfo, packedParamUnitFromApp, &sizeByteFromApp);
+
+ memcpy(bufParamUnit + size, packedParamUnitFromApp, sizeByteFromApp);
+ size += sizeByteFromApp;
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "header=0x%x[%d,%d], size(b)=%d;", dataHeader, idxBand, idxProfile, sizeByteFromApp);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ paramLayerInfo.categoryName.pop_back();
+ paramLayerInfo.categoryName.pop_back();
+ }
+
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "total size(b)=%d", size);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ ALOGD("%s(),MagiNum(0x%x),xml(%s), %s",
+ __FUNCTION__, headerParamUnit.sphUnitMagiNum, paramLayerInfo.audioTypeName, paramLayerInfo.logPrintParamUnit);
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+
+ return size;
+}
+
+
+speech_mode_t SpeechParserGen93::getSpeechModeByOutputDevice(const audio_devices_t output_device) {
+ speech_mode_t speech_mode = SPEECH_MODE_NORMAL;
+
+ if (audio_is_bluetooth_sco_device(output_device)) {
+ speech_mode = SPEECH_MODE_BT_EARPHONE;
+ } else if (output_device == AUDIO_DEVICE_OUT_SPEAKER) {
+#if defined(MTK_INCALL_HANDSFREE_DMNR)
+ speech_mode = SPEECH_MODE_MAGIC_CON_CALL;
+#else
+ speech_mode = SPEECH_MODE_LOUD_SPEAKER;
+#endif
+ } else if (output_device == AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+ speech_mode = SPEECH_MODE_EARPHONE;
+ } else if (output_device == AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+ speech_mode = SPEECH_MODE_EARPHONE;
+ }
+#ifdef MTK_USB_PHONECALL
+ else if (output_device == AUDIO_DEVICE_OUT_USB_DEVICE) {
+ speech_mode = SPEECH_MODE_USB_AUDIO;
+ }
+#endif
+ else if (output_device == AUDIO_DEVICE_OUT_EARPIECE) {
+ if (getFeatureOn(SPEECH_FEATURE_HAC)) {
+ speech_mode = SPEECH_MODE_HAC;
+ } else {
+ speech_mode = SPEECH_MODE_NORMAL;
+ }
+ }
+ return speech_mode;
+}
+
+bool SpeechParserGen93::getFeatureOn(const SpeechFeatureType featureType) {
+ uint16_t featureMaskType = 1 << featureType;
+ const bool featureOn = mSpeechParserAttribute.speechFeatureOn & featureMaskType;
+ ALOGV("%s() featureMaskType: 0x%x, featureOn=%d", __FUNCTION__, featureMaskType, featureOn);
+ return featureOn;
+}
+
+
+} // end namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/SpeechParserGen95.cpp b/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/SpeechParserGen95.cpp
new file mode 100644
index 0000000..59b7f13
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/SpeechParserGen95.cpp
@@ -0,0 +1,284 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechParserGen95"
+#include <SpeechParserGen95.h>
+#include <stdlib.h> /* atoi */
+#include <utils/Log.h>
+#include <AudioLock.h>
+#include <AudioAssert.h>//Mutex/assert
+#include <AudioParamParser.h>
+#include <SpeechParser.h>//external/AudioSpeechEnhancement
+#include <AudioEventThreadManager.h>
+
+
+namespace android {
+
+/*
+* =============================================================================
+* define/enum
+* =============================================================================
+*/
+#define NUM_NEED_UPDATE_XML 4
+#define LEN_XML_NAME 128
+const char needUpdateXmlList[NUM_NEED_UPDATE_XML][LEN_XML_NAME] = {
+ "Speech",
+ "SpeechDMNR",
+ "SpeechGeneral",
+ "SpeechDereverb",
+};
+/*==============================================================================
+* Callback Function
+*============================================================================*/
+void callbackAudioXmlChanged(AppHandle *appHandle, const char *audioTypeName) {
+ ALOGD("%s(), audioType = %s", __FUNCTION__, audioTypeName);
+
+ // reload XML file
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return;
+ }
+ bool isSpeechParamChanged = false, onlyUpdatedDuringCall = false;
+ int idxXmlNeedUpdate = 0;
+
+ if (appOps->appHandleReloadAudioType(appHandle, audioTypeName) != APP_ERROR) {
+ for (idxXmlNeedUpdate = 0; idxXmlNeedUpdate < NUM_NEED_UPDATE_XML; idxXmlNeedUpdate++) {
+ if (strcmp(audioTypeName, needUpdateXmlList[idxXmlNeedUpdate]) == 0) {
+ isSpeechParamChanged = true;
+ break;
+ }
+ }
+ if (strcmp(audioTypeName, "Speech") == 0) {
+ onlyUpdatedDuringCall = true;
+ }
+ if (isSpeechParamChanged) {
+ if (!onlyUpdatedDuringCall) {
+ SpeechParserGen95::getInstance()->mChangedXMLQueue.push_back((char *)needUpdateXmlList[idxXmlNeedUpdate]);
+ AudioEventThreadManager::getInstance()->notifyCallback(AUDIO_EVENT_SPEECH_PARAM_CHANGE,
+ SpeechParserGen95::getInstance());
+ } else if (SpeechParserGen95::getInstance()->mCallOn) {
+ SpeechParserGen95::getInstance()->mChangedXMLQueue.push_back((char *)needUpdateXmlList[idxXmlNeedUpdate]);
+ AudioEventThreadManager::getInstance()->notifyCallback(AUDIO_EVENT_SPEECH_PARAM_CHANGE,
+ SpeechParserGen95::getInstance());
+ }
+ }
+ } else {
+ (void) appHandle;
+ ALOGE("%s(), reload xml fail!(audioType = %s)", __FUNCTION__, audioTypeName);
+ }
+}
+
+/*
+* =============================================================================
+* Singleton Pattern
+* =============================================================================
+*/
+SpeechParserGen95 *SpeechParserGen95::uniqueSpeechParser = NULL;
+
+SpeechParserGen95 *SpeechParserGen95::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ ALOGV("%s()", __FUNCTION__);
+ if (uniqueSpeechParser == NULL) {
+ uniqueSpeechParser = new SpeechParserGen95();
+ }
+ ASSERT(uniqueSpeechParser != NULL);
+ return uniqueSpeechParser;
+}
+
+/*
+* =============================================================================
+* class implementation
+* =============================================================================
+*/
+SpeechParserGen95::SpeechParserGen95() {
+ ALOGD("%s()", __FUNCTION__);
+ mSpeechParserAttribute.inputDevice = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ mSpeechParserAttribute.outputDevice = AUDIO_DEVICE_OUT_EARPIECE;
+ mSpeechParserAttribute.idxVolume = 3;
+ mSpeechParserAttribute.driverScenario = SPEECH_SCENARIO_SPEECH_ON;
+ mSpeechParserAttribute.ttyMode = AUD_TTY_OFF;
+ mSpeechParserAttribute.speechFeatureOn = 0;
+ mCallOn = false;
+ mMonitoredXmlName = new char[128];
+ mChangedXMLQueue.clear();
+ mParamBufSize = getMaxBufferSize();
+ if (mParamBufSize <= 0) {
+ ALOGW("%s() mParamBufSize:%d, get buffer size fail!", __FUNCTION__, mParamBufSize);
+ }
+ AppHandle *appHandle = NULL;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ } else {
+ appHandle = appOps->appHandleGetInstance();
+ ALOGD("%s() appHandleRegXmlChangedCb", __FUNCTION__);
+ /* XML changed callback process */
+ appOps->appHandleRegXmlChangedCb(appHandle, callbackAudioXmlChanged);
+ }
+}
+
+SpeechParserGen95::~SpeechParserGen95() {
+ ALOGD("%s()", __FUNCTION__);
+ if (mMonitoredXmlName != NULL) {
+ delete(mMonitoredXmlName);
+ mMonitoredXmlName = NULL;
+ }
+ AUDIO_FREE_POINTER(mParamBuf);
+ mChangedXMLQueue.clear();
+
+}
+/**
+* =========================================================================
+* @brief Parsing param file to get parameters into pOutBuf
+*
+* @param speechParserAttribute: the attribute for parser
+* @param pOutBuf: the output buffer
+*
+* @return int
+* =========================================================================
+*/
+int SpeechParserGen95::getParamBuffer(SpeechParserAttribute speechParserAttribute, SpeechDataBufType *outBuf) {
+ int retval = 0;
+ mSpeechParserAttribute.inputDevice = speechParserAttribute.inputDevice;
+ mSpeechParserAttribute.outputDevice = speechParserAttribute.outputDevice;
+ mSpeechParserAttribute.idxVolume = speechParserAttribute.idxVolume;
+ mSpeechParserAttribute.driverScenario = speechParserAttribute.driverScenario;
+ mSpeechParserAttribute.speechFeatureOn = speechParserAttribute.speechFeatureOn;
+ mSpeechParserAttribute.ttyMode = speechParserAttribute.ttyMode;
+ ALOGD("%s() inputDevice: 0x%x, outputDevice: 0x%x, Volume: 0x%x, Scenario: 0x%x, FeatureOn: 0x%x, ttyMode: 0x%x",
+ __FUNCTION__, mSpeechParserAttribute.inputDevice, mSpeechParserAttribute.outputDevice,
+ mSpeechParserAttribute.idxVolume, mSpeechParserAttribute.driverScenario,
+ mSpeechParserAttribute.speechFeatureOn, mSpeechParserAttribute.ttyMode);
+
+ /* dynamic allocate parser buffer */
+ AUDIO_FREE_POINTER(mParamBuf);
+ AUDIO_ALLOC_BUFFER(mParamBuf, mParamBufSize);
+ if (mParamBuf == NULL) {
+ ALOGW("%s() Allocate Parser Buffer Fail!! expect:%d", __FUNCTION__, mParamBufSize);
+ outBuf->memorySize = 0;
+ outBuf->dataSize = 0;
+ return -ENOMEM;
+ }
+ outBuf->bufferAddr = (char *)mParamBuf;
+ outBuf->memorySize = mParamBufSize;
+ outBuf->dataSize = 0;
+
+ if (mSpeechParserAttribute.driverScenario == SPEECH_SCENARIO_PARAM_CHANGE) {
+ if (mChangedXMLQueue.empty() != true) {
+ mMonitoredXmlName = mChangedXMLQueue.front();
+ mChangedXMLQueue.erase(mChangedXMLQueue.begin());
+ ALOGD("%s() parameter changed (%s)!", __FUNCTION__, mMonitoredXmlName);
+ } else {
+ ALOGW("%s() parameter changed XML queue empty!", __FUNCTION__);
+ }
+ }
+ SpOps *spOps = spOpsGetInstance();
+ SpHandle *spHandle = spOps->spHandleGetInstance();
+ retval = spOps->getParamBuffer(spHandle, mSpeechParserAttribute, outBuf);
+ ALOGD("%s(), scenario: 0x%x, dataSize:%d, retval:%d",
+ __FUNCTION__, speechParserAttribute.driverScenario, outBuf->dataSize, retval);
+
+ return retval;
+}
+
+/**
+* =========================================================================
+* @brief set keyString string to library
+*
+* @param keyString the "key = value" string
+* @param sizeKeyString the size byte of string
+*
+* @return int
+* =========================================================================
+*/
+int SpeechParserGen95::setKeyValuePair(const SpeechStringBufType *keyValuePair) {
+ ALOGD("+%s(), %s stringAddr =%p, memorySize = 0x%x, dataSize = 0x%x",
+ __FUNCTION__,
+ keyValuePair->stringAddr,
+ keyValuePair->stringAddr,
+ keyValuePair->memorySize,
+ keyValuePair->stringSize);
+
+ SpOps *spOps = spOpsGetInstance();
+ SpHandle *spHandle = spOps->spHandleGetInstance();
+ spOps->setKeyValuePair(spHandle, keyValuePair);
+ ALOGD("-%s(), %s", __FUNCTION__, keyValuePair->stringAddr);
+ return 0;
+}
+
+/**
+* =========================================================================
+* @brief get keyString string from library
+*
+* @param keyString there is only "key" when input,
+and then library need rewrite "key = value" to keyString
+* @param sizeKeyString the size byte of string
+*
+* @return int
+* =========================================================================
+*/
+int SpeechParserGen95::getKeyValuePair(SpeechStringBufType *keyValuePair) {
+ ALOGD("+%s(), %s stringAddr = 0x%p, memorySize = 0x%x, dataSize = 0x%x",
+ __FUNCTION__,
+ keyValuePair->stringAddr,
+ keyValuePair->stringAddr,
+ keyValuePair->memorySize,
+ keyValuePair->stringSize);
+ SpOps *spOps = spOpsGetInstance();
+ SpHandle *spHandle = spOps->spHandleGetInstance();
+ spOps->getKeyValuePair(spHandle, keyValuePair);
+ ALOGD("-%s(),%s", __FUNCTION__, keyValuePair->stringAddr);
+ return 0;
+}
+
+/**
+* =========================================================================
+* @brief update phone call status from driver
+*
+* @param callOn: the phone call status: true(On), false(Off)
+*
+* @return int
+* =========================================================================
+*/
+int SpeechParserGen95::updatePhoneCallStatus(bool callOn) {
+ ALOGD("%s(), callOn:%d", __FUNCTION__, callOn);
+ if (callOn == false) {
+ AUDIO_FREE_POINTER(mParamBuf);
+ }
+ if (mCallOn == callOn) {
+ ALOGW("%s(), callOn(%d) == mCallOn(%d), return",
+ __FUNCTION__, callOn, mCallOn);
+ return 0;
+ }
+ mCallOn = callOn;
+ return 0;
+}
+
+uint32_t SpeechParserGen95::getMaxBufferSize() {
+ uint32_t paramBufSize = 0;
+ char keyString[MAX_SPEECH_PARSER_KEY_LEN];
+ memset((void *)keyString, 0, MAX_SPEECH_PARSER_KEY_LEN);
+
+ SpeechStringBufType keyValuePair;
+ memset(&keyValuePair, 0, sizeof(SpeechStringBufType));
+ keyValuePair.memorySize = strlen(keyString) + 1;
+ keyValuePair.stringSize = strlen(keyString);
+ keyValuePair.stringAddr = keyString;
+
+ snprintf(keyString, MAX_SPEECH_PARSER_KEY_LEN, "%s,%s", SPEECH_PARSER_GET_KEY_PREFIX, SPEECH_PARSER_PARAMBUF_SIZE);
+ //get from default parser
+ SpOps *spOps = spOpsGetInstance();
+ SpHandle *spHandle = spOps->spHandleGetInstance();
+ spOps->getKeyValuePair(spHandle, &keyValuePair);
+ paramBufSize = (uint32_t) atoi(keyValuePair.stringAddr);
+ return paramBufSize;
+
+}
+} // end namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/WCNChipController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/WCNChipController.cpp
new file mode 100644
index 0000000..4bca28b
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/hardware/src/WCNChipController.cpp
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "WCNChipController.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "WCNChipController"
+
+//#define MTK_BASIC_PACKAGE//Eenable For WCN test
+
+typedef enum {
+ /* [operation]
+ * Return audio configuration for BT SCO on current chipset
+ * [input param]
+ * A pointer to union type with content of BT_INFO.
+ * Typecasting conversion: (BT_INFO *) param.
+ * [return]
+ * 0 - default, don't care.
+ * [callback]
+ * None.
+ */
+ BT_MTK_OP_AUDIO_GET_CONFIG,
+ /* Audio config related information */
+} bt_mtk_opcode_t;
+
+typedef enum {
+ PCM = 0, // PCM 4 pins interface
+ I2S, // I2S interface
+ MERGE_INTERFACE, // PCM & I2S merge interface
+ CVSD_REMOVAL // SOC consys
+} AUDIO_IF;
+
+typedef enum {
+ SYNC_8K = 0,
+ SYNC_16K
+} SYNC_CLK; // DAIBT sample rate
+
+typedef enum {
+ SHORT_FRAME = 0,
+ LONG_FRAME
+} SYNC_FORMAT; // DAIBT sync
+
+typedef struct {
+ AUDIO_IF hw_if;
+ SYNC_CLK sample_rate;
+ SYNC_FORMAT sync_format;
+ unsigned int bit_len; // bit-length of sync frame in long frame sync
+} AUDIO_CONFIG;
+
+/* Information carring for all OPs (In/Out) */
+typedef union {
+ AUDIO_CONFIG audio_conf;
+} BT_INFO;
+
+namespace android {
+
+/*==============================================================================
+ * Property keys
+ *============================================================================*/
+
+/*==============================================================================
+ * Const Value
+ *============================================================================*/
+
+static const uint32_t kMaxFMChipVolume = 15;
+
+static const char kFmAudPathName[4][16] = {"FM_AUD_ANALOG", "FM_AUD_I2S", "FM_AUD_MRGIF", "FM_AUD_ERR"};
+static const char kFmI2sPadName[3][16] = {"FM_I2S_PAD_CONN", "FM_I2S_PAD_IO", "FM_I2S_PAD_ERR"};
+static const char kFmI2sModeName[3][16] = {"FM_I2S_MASTER", "FM_I2S_SLAVE", "FM_I2S_MODE_ERR"};
+static const char kFmI2sSampleRateName[4][16] = {"FM_I2S_32K", "FM_I2S_44K", "FM_I2S_48K", "FM_I2S_SR_ERR"};
+static const uint32_t kFmI2sSampleRateMapNum[4] = {32000, 44100, 48000, 44100}; // FM_I2S_SR_ERR => use default 44100Hz
+
+/*==============================================================================
+ * Enumerator
+ *============================================================================*/
+
+/*==============================================================================
+ * Singleton Pattern
+ *============================================================================*/
+
+WCNChipController *WCNChipController::mWCNChipController = NULL;
+AUDIO_CONFIG mBTAudioInfo;
+
+
+WCNChipController *WCNChipController::GetInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+
+ if (mWCNChipController == NULL) {
+ mWCNChipController = new WCNChipController();
+ }
+ ASSERT(mWCNChipController != NULL);
+ return mWCNChipController;
+}
+
+/*==============================================================================
+ * Constructor / Destructor / Init / Deinit
+ *============================================================================*/
+
+WCNChipController::WCNChipController() {
+ ALOGD("%s()", __FUNCTION__);
+
+ mInitAudioFMInfoFlag = false;
+ mInitAudioBTInfoFlag = false;
+ mPlatformSupportFM = false;
+
+ mBTAudioInfo.hw_if = MERGE_INTERFACE;
+ mBTAudioInfo.sample_rate = SYNC_8K;
+ mBTAudioInfo.sync_format = SHORT_FRAME;
+ mBTAudioInfo.bit_len = 0;
+ //mBTAudioInfo.security_hi_lo = 0;
+
+ mBTCurrentSamplingRateNumber = 8000;
+}
+
+WCNChipController::~WCNChipController() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+bool WCNChipController::IsBTMergeInterfaceSupported() {
+ return true;
+}
+
+
+
+
+/*==============================================================================
+ * WCN FM Chip Control
+ *============================================================================*/
+
+bool WCNChipController::GetFmChipPowerInfo() {
+ return false;
+}
+
+status_t WCNChipController::SetFmChipVolume(const uint32_t fm_chip_volume) {
+ return NO_ERROR;
+}
+
+
+status_t WCNChipController::SetFmChipSampleRate(const uint32_t sample_rate) {
+ return NO_ERROR;
+}
+
+
+status_t WCNChipController::InitAudioFMInfo() {
+ return NO_ERROR;
+}
+
+#if defined(__LP64__)
+#define AUDIO_BT_LIB_VENDOR_PATH "/vendor/lib64/libbluetooth_mtk_pure.so"
+#define AUDIO_BT_LIB_PATH "/system/lib64/libbluetooth_mtk_pure.so"
+#else
+#define AUDIO_BT_LIB_VENDOR_PATH "/vendor/lib/libbluetooth_mtk_pure.so"
+#define AUDIO_BT_LIB_PATH "/system/lib/libbluetooth_mtk_pure.so"
+#endif
+
+status_t WCNChipController::InitAudioBTInfo() {
+ return NO_ERROR;
+}
+
+bool WCNChipController::IsFMMergeInterfaceSupported() {
+ return false;
+}
+
+
+bool WCNChipController::IsFmChipPadSelConnSys() {
+ return false;
+}
+
+bool WCNChipController::IsFmChipUseSlaveMode() {
+ return false;
+}
+
+uint32_t WCNChipController::GetFmChipSamplingRate() {
+ return 44100; // default setting FM chip sampling rate 44100 Hz
+}
+
+uint32_t WCNChipController::BTChipHWInterface() {
+ return MERGE_INTERFACE; // 0: PCM, 1: I2S, 2: MERGE_INTERFACE, 3: CVSD_REMOVAL
+}
+
+bool WCNChipController::BTUseCVSDRemoval() {
+ return false;
+}
+
+uint32_t WCNChipController::BTChipSamplingRate() {
+#if defined(MTK_BT_SUPPORT)
+ if (mInitAudioBTInfoFlag == false) { InitAudioBTInfo(); }
+ return mBTAudioInfo.sample_rate; //0:SYNC_8K, 1: SYNC_16K
+#else
+ return SYNC_8K; // default setting is NB 8k
+#endif
+}
+
+uint32_t WCNChipController::BTChipSamplingRateNumber() {
+ return (BTChipSamplingRate() == SYNC_8K) ? 8000 : 16000;
+}
+
+uint32_t WCNChipController::BTChipSyncFormat() {
+#if defined(MTK_BT_SUPPORT)
+ if (mInitAudioBTInfoFlag == false) { InitAudioBTInfo(); }
+ return mBTAudioInfo.sync_format; //0:SHORT_FRAME, 1: LONG_FRAME
+#else
+ return 0; // default setting is SHORT_FRAME
+#endif
+}
+
+uint32_t WCNChipController::BTChipSyncLength() {
+#if defined(MTK_BT_SUPPORT)
+ if (mInitAudioBTInfoFlag == false) { InitAudioBTInfo(); }
+ return mBTAudioInfo.bit_len;
+#else
+ return 0; // default setting is 0
+#endif
+}
+
+uint32_t WCNChipController::BTChipSecurityHiLo() {
+ return 0; // WCN does not provide this property
+}
+
+
+void WCNChipController::SetBTCurrentSamplingRateNumber(const uint32_t sample_rate) {
+ ALOGD("%s(), mBTCurrentSamplingRateNumber: %d => %d", __FUNCTION__, mBTCurrentSamplingRateNumber, sample_rate);
+ ASSERT(sample_rate == 8000 || sample_rate == 16000);
+ mBTCurrentSamplingRateNumber = sample_rate;
+}
+
+uint32_t WCNChipController::GetBTCurrentSamplingRateNumber() {
+ return mBTCurrentSamplingRateNumber;
+}
+
+bool WCNChipController::IsSupportFM() {
+ // Don't Change this
+ return mPlatformSupportFM;
+}
+
+bool WCNChipController::IsCustomizedPlatformSupportFM() {
+ // Customer could modify the return value by other methods
+ return false;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/drv/MtkAudioSrc.cpp b/src/multimedia/libspeech_drv/audio_big_sw/os/drv/MtkAudioSrc.cpp
new file mode 100644
index 0000000..cfe811b
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/drv/MtkAudioSrc.cpp
@@ -0,0 +1,329 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* MediaTek Inc. (C) 2016. All rights reserved.
+ *
+ * Copyright Statement:
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ */
+
+/*
+* Description:
+* This file implements Mtk Audio Ssampl Rate Converter
+*/
+
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sched.h>
+#include <fcntl.h>
+
+//#define HAVE_SWIP
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "MtkAudioSrc"
+
+#include <sys/ioctl.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <assert.h>
+#include "MtkAudioSrc.h"
+//#define ENABLE_LOG_AUDIO_SRC
+#ifdef ENABLE_LOG_AUDIO_SRC
+#undef ALOGV
+#define ALOGV(...) ALOGD(__VA_ARGS__)
+#endif
+
+namespace android {
+
+MtkAudioSrc::MtkAudioSrc() {
+ mpTempBuf = NULL;
+ mpInternalBuf = NULL;
+ mBlisrcHandler = NULL;
+ mTempBufSize = 0;
+ mInternalBufSize = 0;
+ mState = ACE_STATE_INIT;
+ memset(&mBlisrcParam, 0, sizeof(mBlisrcParam));
+ ALOGV("MtkAudioSrc Constructor\n");
+}
+
+MtkAudioSrc::MtkAudioSrc(uint32_t input_SR, uint32_t input_channel_num, uint32_t output_SR, uint32_t output_channel_num, SRC_PCM_FORMAT format) {
+ mpTempBuf = NULL;
+ mpInternalBuf = NULL;
+ mBlisrcHandler = NULL;
+ mTempBufSize = 0;
+ mInternalBufSize = 0;
+ mBlisrcParam.PCM_Format = (uint32_t)format;
+ mBlisrcParam.in_sampling_rate = input_SR;
+ mBlisrcParam.ou_sampling_rate = output_SR;
+ mBlisrcParam.in_channel = input_channel_num;
+ mBlisrcParam.ou_channel = output_channel_num;
+ mState = ACE_STATE_INIT;
+ ALOGV("MtkAudioSrc Constructor in SR %d, CH %d; out SR %d, CH %d; format %d\n", input_SR, input_channel_num, output_SR, output_channel_num, format);
+}
+
+MtkAudioSrc::~MtkAudioSrc() {
+ ALOGV("+%s()\n", __FUNCTION__);
+ if (mpTempBuf != NULL) {
+ delete[] mpTempBuf;
+ mpTempBuf = NULL;
+ }
+ if (mpInternalBuf != NULL) {
+ delete[] mpInternalBuf;
+ mpInternalBuf = NULL;
+ }
+ ALOGV("-%s()\n", __FUNCTION__);
+}
+
+ACE_ERRID MtkAudioSrc::setParameter(uint32_t paramID, void *param) {
+ ALOGV("+%s(), paramID %d, param 0x%x\n", __FUNCTION__, paramID, (uint32_t)((long)param));
+ Mutex::Autolock _l(mLock);
+ uint32_t currentParam = (uint32_t)((long)param);
+ if (mState == ACE_STATE_OPEN && paramID != SRC_PAR_SET_INPUT_SAMPLE_RATE) { //Only input sampling rate could be update during process.
+ return ACE_INVALIDE_OPERATION;
+ }
+ switch (paramID) {
+ case SRC_PAR_SET_PCM_FORMAT: {
+ if (currentParam >= SRC_IN_END) {
+ return ACE_INVALIDE_PARAMETER;
+ }
+ mBlisrcParam.PCM_Format = currentParam;
+ break;
+ }
+ case SRC_PAR_SET_INPUT_SAMPLE_RATE: {
+ mBlisrcParam.in_sampling_rate = currentParam;
+ if (mState == ACE_STATE_OPEN) {
+#if defined(HAVE_SWIP)
+ Blisrc_SetSamplingRate(mBlisrcHandler, mBlisrcParam.in_sampling_rate);
+#endif
+ }
+ break;
+ }
+ case SRC_PAR_SET_OUTPUT_SAMPLE_RATE: {
+ mBlisrcParam.ou_sampling_rate = currentParam;
+ break;
+ }
+ case SRC_PAR_SET_INPUT_CHANNEL_NUMBER: {
+ mBlisrcParam.in_channel = currentParam;
+ break;
+ }
+ case SRC_PAR_SET_OUTPUT_CHANNEL_NUMBER: {
+ mBlisrcParam.ou_channel = currentParam;
+ break;
+ }
+ default:
+ return ACE_INVALIDE_PARAMETER;
+ }
+ ALOGV("-%s()\n", __FUNCTION__);
+ return ACE_SUCCESS;
+}
+
+
+ACE_ERRID MtkAudioSrc::getParameter(uint32_t paramID, void *param) {
+ ALOGD("+%s(), paramID %d\n", __FUNCTION__, paramID);
+ Mutex::Autolock _l(mLock);
+ long currentParam = 0;
+ switch (paramID) {
+ case SRC_PAR_GET_PCM_FORMAT: {
+ currentParam = (long)mBlisrcParam.PCM_Format;
+ break;
+ }
+ case SRC_PAR_GET_INPUT_SAMPLE_RATE: {
+ currentParam = (long)mBlisrcParam.in_sampling_rate;
+ break;
+ }
+ case SRC_PAR_GET_OUTPUT_SAMPLE_RATE: {
+ currentParam = (long)mBlisrcParam.ou_sampling_rate;
+ break;
+ }
+ case SRC_PAR_GET_INPUT_CHANNEL_NUMBER: {
+ currentParam = (long)mBlisrcParam.in_channel;
+ break;
+ }
+ case SRC_PAR_GET_OUTPUT_CHANNEL_NUMBER: {
+ currentParam = (long)mBlisrcParam.ou_channel;
+ break;
+ }
+ default:
+ return ACE_INVALIDE_PARAMETER;
+ }
+ param = (void *) currentParam;
+ ALOGD("-%s(), paramID %d, param 0x%x\n", __FUNCTION__, paramID, (uint32_t)((long)param));
+ return ACE_SUCCESS;
+}
+
+ACE_ERRID MtkAudioSrc::open(void) {
+ Mutex::Autolock _l(mLock);
+ if (mState != ACE_STATE_INIT) {
+ ALOGD("%s(), mState != ACE_STATE_INIT\n", __FUNCTION__);
+ return ACE_INVALIDE_OPERATION;
+ }
+ int returnValue;
+#if defined(HAVE_SWIP)
+ returnValue = Blisrc_GetBufferSize(&mInternalBufSize,
+ &mTempBufSize,
+ &mBlisrcParam);
+
+ if (returnValue < 0) {
+ ALOGD("Blisrc_GetBufferSize return err %d\n", returnValue);
+ return ACE_INVALIDE_OPERATION;
+ }
+#endif
+ if (mInternalBufSize > 0) {
+ mpInternalBuf = new char[mInternalBufSize];
+ }
+ if (mTempBufSize > 0) {
+ mpTempBuf = new char[mTempBufSize];
+ }
+#if defined(HAVE_SWIP)
+ Blisrc_Open(&mBlisrcHandler, mpInternalBuf, &mBlisrcParam);
+#endif
+ mState = ACE_STATE_OPEN;
+ ALOGD("%s(), SR %d, CH %d; out SR %d, CH %d; format %d, mState = %d\n",
+ __FUNCTION__, mBlisrcParam.in_sampling_rate, mBlisrcParam.in_channel,
+ mBlisrcParam.ou_sampling_rate, mBlisrcParam.ou_channel,
+ mBlisrcParam.PCM_Format, mState);
+
+ return ACE_SUCCESS;
+}
+
+ACE_ERRID MtkAudioSrc::close(void) {
+ Mutex::Autolock _l(mLock);
+ if (mState != ACE_STATE_OPEN) {
+ ALOGD("%s(), mState != ACE_STATE_OPEN\n", __FUNCTION__);
+ return ACE_INVALIDE_OPERATION;
+ }
+ if (mpTempBuf != NULL) {
+ delete[] mpTempBuf;
+ mpTempBuf = NULL;
+ }
+ if (mpInternalBuf != NULL) {
+ delete[] mpInternalBuf;
+ mpInternalBuf = NULL;
+ }
+ mState = ACE_STATE_INIT;
+ ALOGD("%s(), mState = %d\n", __FUNCTION__, mState);
+ return ACE_SUCCESS;
+}
+
+ACE_ERRID MtkAudioSrc::resetBuffer(void) {
+ ALOGD("+%s()\n", __FUNCTION__);
+ Mutex::Autolock _l(mLock);
+ if (mState != ACE_STATE_OPEN) {
+ return ACE_INVALIDE_OPERATION;
+ }
+#if defined(HAVE_SWIP)
+ Blisrc_Reset(mBlisrcHandler);
+#endif
+ ALOGD("-%s()\n", __FUNCTION__);
+ return ACE_SUCCESS;
+}
+
+ACE_ERRID MtkAudioSrc::process(void *pInputBuffer, /* Input, pointer to input buffer */
+ uint32_t *InputSampleCount, /* Input, length(byte) of input buffer */
+ /* Output, length(byte) left in the input buffer after conversion */
+ void *pOutputBuffer, /* Input, pointer to output buffer */
+ uint32_t *OutputSampleCount) /* Input, length(byte) of output buffer */
+/* Output, output data length(byte) */
+{
+ Mutex::Autolock _l(mLock);
+ if (mState != ACE_STATE_OPEN) {
+ return ACE_INVALIDE_OPERATION;
+ }
+#if defined(HAVE_SWIP)
+ Blisrc_Process(mBlisrcHandler,
+ mpTempBuf,
+ pInputBuffer,
+ InputSampleCount,
+ pOutputBuffer,
+ OutputSampleCount);
+#else
+ memcpy(pOutputBuffer, pInputBuffer, *InputSampleCount);
+ *OutputSampleCount = *InputSampleCount;
+ *InputSampleCount = 0;
+#endif
+ return ACE_SUCCESS;
+}
+
+
+ACE_ERRID MtkAudioSrc::multiChannelOpen(void) {
+ ALOGD("+%s()\n", __FUNCTION__);
+ Mutex::Autolock _l(mLock);
+ if (mState != ACE_STATE_INIT) {
+ return ACE_INVALIDE_OPERATION;
+ }
+ int returnValue;
+#if defined(HAVE_SWIP)
+ returnValue = Blisrc_MultiChannel_GetBufferSize(&mInternalBufSize,
+ &mTempBufSize,
+ &mBlisrcParam);
+
+ if (returnValue < 0) {
+ ALOGD("Blisrc_GetBufferSize return err %d\n", returnValue);
+ return ACE_INVALIDE_OPERATION;
+ }
+#endif
+ if (mInternalBufSize > 0) {
+ mpInternalBuf = new char[mInternalBufSize];
+ }
+ if (mTempBufSize > 0) {
+ mpTempBuf = new char[mTempBufSize];
+ }
+#if defined(HAVE_SWIP)
+ Blisrc_MultiChannel_Open(&mBlisrcHandler, mpInternalBuf, &mBlisrcParam);
+#endif
+ mState = ACE_STATE_OPEN;
+ ALOGD("-%s()\n", __FUNCTION__);
+ return ACE_SUCCESS;
+}
+
+
+ACE_ERRID MtkAudioSrc::multiChannelResetBuffer(void) {
+ ALOGD("+%s()\n", __FUNCTION__);
+ Mutex::Autolock _l(mLock);
+ if (mState != ACE_STATE_OPEN) {
+ return ACE_INVALIDE_OPERATION;
+ }
+#if defined(HAVE_SWIP)
+ Blisrc_MultiChannel_Reset(mBlisrcHandler);
+#endif
+ ALOGD("-%s()\n", __FUNCTION__);
+ return ACE_SUCCESS;
+}
+
+
+ACE_ERRID MtkAudioSrc::multiChannelProcess(void *pInputBuffer, /* Input, pointer to input buffer */
+ uint32_t *InputSampleCount, /* Input, length(byte) of input buffer */
+ /* Output, length(byte) left in the input buffer after conversion */
+ void *pOutputBuffer, /* Input, pointer to output buffer */
+ uint32_t *OutputSampleCount) /* Input, length(byte) of output buffer */
+/* Output, output data length(byte) */
+{
+ ALOGV("+%s(), inputCnt %d, outputCnt %x\n", __FUNCTION__, *InputSampleCount, *OutputSampleCount);
+ Mutex::Autolock _l(mLock);
+ if (mState != ACE_STATE_OPEN) {
+ return ACE_INVALIDE_OPERATION;
+ }
+#if defined(HAVE_SWIP)
+ Blisrc_MultiChannel_Process(mBlisrcHandler,
+ mpTempBuf,
+ pInputBuffer,
+ InputSampleCount,
+ pOutputBuffer,
+ OutputSampleCount);
+#endif
+ ALOGV("-%s(), inputCnt %d, outputCnt %x\n", __FUNCTION__, *InputSampleCount, *OutputSampleCount);
+ return ACE_SUCCESS;
+}
+
+}//namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/drv/SpeechDaemon.cpp b/src/multimedia/libspeech_drv/audio_big_sw/os/drv/SpeechDaemon.cpp
new file mode 100644
index 0000000..1df661a
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/drv/SpeechDaemon.cpp
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <utils/Log.h>
+#include "speech_drv.h"
+#include "SpeechModemController.h"
+#include "SpeechBGSPlayer.h"
+#define LOG_TAG "SPEECH_DAEMON"
+
+using android::SpeechModemController;
+
+#define MAX_CON 20
+
+SPH_MSG msg;
+typedef void(* CALLBACK)(int);
+SpeechModemController *speechModemController;
+
+int do_sph_operation(SPH_REQ *req) {
+ int result = -1;
+
+ ALOGD("%s(), req->id : %d", __FUNCTION__, req->id);
+ switch (req->id) {
+ case SET_SPEECH_ON:
+ if (req->speechOn) {
+ result = SpeechModemController::getInstance()->phoneCallOpen(req->inputDevice, req->outputDevice);
+ } else {
+ result = SpeechModemController::getInstance()->phoneCallClose();
+ }
+ break;
+ case CHANGE_SPEECH_ROUTING:
+ result = SpeechModemController::getInstance()->phoneCallRouting(req->inputDevice, req->outputDevice);
+ break;
+ case VMLOG_RECORD:
+ result = SpeechModemController::getInstance()->configVm(req->vmConfig);
+ break;
+ case DL_VOL_IDX:
+ result = SpeechModemController::getInstance()->setVolumeIndex(req->volumeIdx);
+ break;
+ case GET_UL_ANA_GAIN:
+ result = SpeechModemController::getInstance()->getUlAnalogGain();
+ break;
+ case GET_DL_ANA_GAIN:
+ result = SpeechModemController::getInstance()->getDlAnalogGain();
+ break;
+ case SET_SPK_TYPE:
+ result = SpeechModemController::getInstance()->setSpeakerType(req->speakerType);
+ break;
+ case SET_UL_MUTE:
+ result = SpeechModemController::getInstance()->setUplinkMute(req->muteOn);
+ break;
+ case SET_DL_MUTE:
+ result = SpeechModemController::getInstance()->setDownlinkMute(req->muteOn);
+ break;
+ case GET_UL_MUTE:
+ result = SpeechModemController::getInstance()->getUplinkMute();
+ break;
+ case GET_DL_MUTE:
+ result = SpeechModemController::getInstance()->getDownlinkMute();
+ break;
+ case SET_BT_WBS:
+ result = SpeechModemController::getInstance()->setBtMode(req->btWbsOn);
+ break;
+ case SET_BT_NREC:
+ result = SpeechModemController::getInstance()->setBtNrec(req->btNrecOn);
+ break;
+ case SET_BT_VGS:
+ result = SpeechModemController::getInstance()->setBtVgs(req->btVgsOn);
+ break;
+ case ECALL_SPEECH_ON:
+ if (req->speechOn) {
+ result = SpeechModemController::getInstance()->phoneCallOpen(2, 0x80000004);//speaker, builtin mic
+ } else {
+ result = SpeechModemController::getInstance()->phoneCallClose();
+ }
+ break;
+ case IVS_SWITCH:
+ result = SpeechModemController::getInstance()->eCallIvsSwitch(req->switchOn);
+ break;
+ case IVS_SEND:
+ result = SpeechModemController::getInstance()->eCallIvsSend();
+ break;
+ case PSAP_SWITCH:
+ result = SpeechModemController::getInstance()->eCallPsapSwitch(req->switchOn);
+ break;
+ case PSAP_SEND:
+ result = SpeechModemController::getInstance()->eCallPsapSend();
+ break;
+ case ECALL_MSD:
+ result = SpeechModemController::getInstance()->eCallMsd(req->dataBuf, req->dataSize);
+ break;
+ case ECALL_TESTSEQ_SWITCH:
+ result = SpeechModemController::getInstance()->eCallCtrlSeqSwitch(req->switchOn);
+ break;
+ case ECALL_TESTSEQ:
+ result = SpeechModemController::getInstance()->eCallTxCtrlParam(req->dataBuf, req->dataSize);
+ break;
+ case BGS_OPEN:
+ result = SpeechModemController::getInstance()->bgsOpen(req->sampleRate);
+ break;
+ case BGS_CLOSE:
+ result = SpeechModemController::getInstance()->bgsClose();
+ break;
+ case BGS_WRITE:
+ result = SpeechModemController::getInstance()->bgsWrite(req->dataBuf, req->dataSize);
+ break;
+ default:
+ ALOGW("%s(), wrong request command id(%d)!!!", __FUNCTION__, req->id);
+ break;
+
+ }
+
+ return result;
+}
+
+void control(int fd) {
+ int connfd = fd;
+ int ressend = 0;
+
+ memset(&msg, 0, sizeof(SPH_MSG));
+ int len = recv(connfd, &msg, sizeof(SPH_MSG), 0);
+ if (len < 0) {
+ ALOGE("%s(), receive socket fail. errno = %d", __FUNCTION__, errno);
+ goto CONTROL_FAIL;
+ }
+
+ if (strcmp(msg.cmd, "ACK") == 0) {
+ memset(&msg, 0, sizeof(SPH_MSG));
+ strncpy(msg.cmd, "READY", sizeof(msg.cmd));
+ msg.cmd[sizeof(msg.cmd) - 1] = '\0';
+
+ ressend = send(connfd, &msg, sizeof(SPH_MSG), 0);
+ if (-1 == ressend) {
+ ALOGE("%s(), send socket fail. errno = %d", __FUNCTION__, errno);
+ goto CONTROL_FAIL;
+ }
+
+ memset(&msg, 0, sizeof(SPH_MSG));
+ len = recv(connfd, &msg, sizeof(SPH_MSG), 0);
+ if (len < 0) {
+ ALOGE("%s(), receive socket fail. errno = %d", __FUNCTION__, errno);
+ goto CONTROL_FAIL;
+ }
+ if (strcmp(msg.cmd, "REQ") == 0) {
+ msg.result = do_sph_operation(&msg.req);
+ ressend = send(connfd, &msg, sizeof(SPH_MSG), 0);
+ if (-1 == ressend) {
+ ALOGE("%s(), send socket fail. errno = %d", __FUNCTION__, errno);
+ goto CONTROL_FAIL;
+ }
+ }
+ ALOGD("%s(), communication done. command id = %d, response = %d.", __FUNCTION__, msg.req.id, msg.result);
+
+ }
+
+CONTROL_FAIL:
+ if (connfd >= 0) {
+ close(connfd);
+ }
+
+}
+
+
+int main(void) {
+ ALOGD("%s(), start...", __FUNCTION__);
+ int res = 0;
+ CALLBACK callback = control;
+ bool speech_init = false;
+ unlink(SERVER_SOCK_FILE);
+ int serfd = socket(AF_UNIX, SOCK_STREAM, 0);
+ socklen_t len = sizeof(struct sockaddr);
+ int connfd = 0;
+ int result = 0;
+ if (-1 == serfd) {
+ ALOGD("%s(), open socket fail. errno = %d", __FUNCTION__, errno);
+ goto INIT_FAIL;
+ }
+
+ struct sockaddr_un addr;
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, SERVER_SOCK_FILE, sizeof(addr.sun_path));
+ addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
+ res = bind(serfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un));
+ if (-1 == res) {
+ ALOGE("%s(), bind socket fail. errno = %d", __FUNCTION__, errno);
+ goto INIT_FAIL;
+ }
+ res = listen(serfd, MAX_CON);
+ if (-1 == res) {
+ ALOGE("%s(), Listen to socket fail. errno = %d", __FUNCTION__, errno);
+ goto INIT_FAIL;
+ }
+
+ /*Init*/
+ speechModemController = SpeechModemController::getInstance();
+
+ speech_init = true;
+ ALOGD("%s(), initialized. bind to sever socket %s.", __FUNCTION__, SERVER_SOCK_FILE);
+
+ while (1) {
+ connfd = accept(serfd, (struct sockaddr *)&addr, &len);
+ if (-1 == connfd) {
+ ALOGE("%s(), socket accept fail. errno = %d", __FUNCTION__, errno);
+ goto INIT_FAIL;
+ } else {
+ callback(connfd);
+ }
+ }
+
+
+INIT_FAIL:
+ if (serfd >= 0) {
+ close(serfd);
+ }
+
+ unlink(SERVER_SOCK_FILE);
+ return false;
+}
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/drv/SpeechModemController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/os/drv/SpeechModemController.cpp
new file mode 100644
index 0000000..662097f
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/drv/SpeechModemController.cpp
@@ -0,0 +1,417 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "SpeechModemController.h"
+
+#include "SpeechDriverInterface.h"
+#include "SpeechDriverFactory.h"
+#include <AudioVolumeFactory.h>
+#include "SpeechEnhancementController.h"
+#include "SpeechVMRecorder.h"
+#include <utils/Log.h>
+
+#define LOG_TAG "SpeechModemController"
+
+
+namespace android {
+
+SpeechModemController *SpeechModemController::mSpeechModemController = NULL;
+SpeechModemController *SpeechModemController::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mSpeechModemController == NULL) {
+ mSpeechModemController = new SpeechModemController();
+ }
+ ASSERT(mSpeechModemController != NULL);
+ return mSpeechModemController;
+}
+
+SpeechModemController::SpeechModemController() :
+ mSpeechDriverFactory(SpeechDriverFactory::GetInstance()),
+ mAudioALSAVolumeController(NULL),
+ mUlMute(false),
+ mDlMute(false),
+ mBtMode(0),
+ mBtNrec(true),
+ mSpeechOn(false),
+ mCurrentOutputDevice(AUDIO_DEVICE_OUT_EARPIECE),
+ mCurrentInputDevice(AUDIO_DEVICE_IN_BUILTIN_MIC),
+ mIsEcallIvsOn(false),
+ mIsEcallPsapOn(false),
+ mIsEcallCtrlSeqOn(false),
+ mVolumeIndex(4),
+ mSpkType(-1) {
+
+ initialize();
+}
+
+SpeechModemController::~SpeechModemController() {
+
+}
+
+int SpeechModemController::initialize() {
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ mSpeechDriverFactory->SetActiveModemIndex(MODEM_1);
+ mBGSPlayBuffer = NULL;
+
+ return NO_ERROR;
+}
+
+int SpeechModemController::phoneCallOpen(const audio_devices_t input_device, const audio_devices_t output_devices) {
+ AL_AUTOLOCK(mLock);
+ AL_AUTOLOCK(mCheckOpenLock);
+
+ if (mSpeechOn == true) {
+ ALOGD("%s(), Modem SpeechOn is already open. return.", __FUNCTION__, output_devices, input_device);
+ return NO_ERROR;
+ }
+ ALOGD("+%s(), output_devices = 0x%x, input_device = 0x%x", __FUNCTION__, output_devices, input_device);
+
+ // get speech driver instance
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+
+ // check BT device
+ const bool bt_device_on = audio_is_bluetooth_sco_device(output_devices);
+ const uint32_t sample_rate = calculateSampleRate(bt_device_on);
+ ALOGD("%s(), bt_device_on = %d, sample_rate = %d", __FUNCTION__, bt_device_on, sample_rate);
+
+ // Set MD side sampling rate
+ speechDriver->SetModemSideSamplingRate(sample_rate);
+
+ speechDriver->SetSpeechMode(input_device, output_devices);
+
+ speechDriver->SpeechOn();
+#if defined(MTK_SPEECH_MD_LPBK_TX2RX)
+ speechDriver->SetModemLoopbackPoint(1);
+#endif
+
+ // for the case that customized app set mute before speech on
+ AL_AUTOLOCK(mUlMuteLock);
+ speechDriver->SetUplinkMute(mUlMute);
+
+ // check VM need open
+ SpeechVMRecorder *speechVMRecorder = SpeechVMRecorder::getInstance();
+ if (speechVMRecorder->getVmConfig() == SPEECH_VM_SPEECH) {
+ speechVMRecorder->open();
+ }
+ mCurrentOutputDevice = output_devices;
+ mCurrentInputDevice = input_device;
+ mSpeechOn = true;
+ ALOGD("-%s(), mSpeechOn = %d", __FUNCTION__, mSpeechOn);
+
+ return NO_ERROR;
+}
+
+
+int SpeechModemController::phoneCallClose() {
+ AL_AUTOLOCK(mLock);
+
+ if (mSpeechOn == false) {
+ ALOGD("+%s(), Modem SpeechOn is not open. return.", __FUNCTION__);
+ return NO_ERROR;
+ }
+ ALOGD("+%s(), mSpeechOn = %d", __FUNCTION__, mSpeechOn);
+ const modem_index_t modem_index = mSpeechDriverFactory->GetActiveModemIndex();
+
+ // check VM need close
+ SpeechVMRecorder *speechVMRecorder = SpeechVMRecorder::getInstance();
+ if (speechVMRecorder->getVMRecordStatus() == true) {
+ speechVMRecorder->close();
+ }
+
+ // Get current active speech driver
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+#if defined(MTK_SPEECH_MD_LPBK_TX2RX)
+ speechDriver->SetModemLoopbackPoint(0);
+#endif
+
+ eCallIvsSwitch(false);
+ eCallPsapSwitch(false);
+ eCallCtrlSeqSwitch(false);
+
+ // Speech off
+ if (speechDriver->GetApSideModemStatus(SPEECH_STATUS_MASK) == true) {
+ speechDriver->SpeechOff();
+ } else {
+ ALOGE("%s(), Speech is already closed!!", __FUNCTION__);
+ }
+
+ mSpeechOn = false;
+ ALOGD("-%s(), mSpeechOn = %d", __FUNCTION__, mSpeechOn);
+
+ return NO_ERROR;
+}
+
+int SpeechModemController::phoneCallRouting(const audio_devices_t input_device,
+ const audio_devices_t output_devices) {
+
+ AL_AUTOLOCK(mLock);
+ AL_AUTOLOCK(mCheckOpenLock);
+
+ if (output_devices == mCurrentOutputDevice) {
+ ALOGD("%s(), the same output deivces(0x%x). return.", __FUNCTION__, output_devices, input_device);
+ return NO_ERROR;
+ }
+ ALOGD("+%s(), output_devices = 0x%x, input_device = 0x%x", __FUNCTION__, output_devices, input_device);
+
+ // get speech driver instance
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+
+ // check BT device
+ const bool bt_device_on = audio_is_bluetooth_sco_device(output_devices);
+ const uint32_t sample_rate = calculateSampleRate(bt_device_on);
+ ALOGD("%s(), bt_device_on = %d, sample_rate = %d", __FUNCTION__, bt_device_on, sample_rate);
+
+ // Set MD side sampling rate
+ speechDriver->SetModemSideSamplingRate(sample_rate);
+ speechDriver->SetSpeechMode(input_device, output_devices);
+ return NO_ERROR;
+}
+
+int SpeechModemController::configVm(const uint8_t vmConfig) {
+ ALOGD("%s(), vmConfig=%d", __FUNCTION__, vmConfig);
+ SpeechVMRecorder *speechVMRecorder = SpeechVMRecorder::getInstance();
+ return speechVMRecorder->configVm(vmConfig);
+}
+
+int SpeechModemController::setBtMode(const int mode) {
+ ALOGD("%s(), mBtMode: %d => %d", __FUNCTION__, mBtMode, mode);
+ AL_AUTOLOCK(mLock);
+
+ if (mBtMode != mode) {
+ mBtMode = mode;
+
+ if (mSpeechOn && audio_is_bluetooth_sco_device(mCurrentOutputDevice)) {
+ // Get current active speech driver
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ uint32_t sampleRate = calculateSampleRate(true);
+ speechDriver->switchBTMode(sampleRate);
+ }
+ }
+ return NO_ERROR;
+}
+
+int SpeechModemController::setBtNrec(const bool enable) {
+ ALOGD("%s(), mBtNrec: %d => %d", __FUNCTION__, mBtNrec, enable);
+ AL_AUTOLOCK(mLock);
+
+ if (mBtNrec != enable) {
+ if (mSpeechOn && audio_is_bluetooth_sco_device(mCurrentOutputDevice)) {
+ // Get current active speech driver
+ if (SpeechEnhancementController::GetInstance()->GetBtHeadsetNrecOn() != enable) {
+ SpeechEnhancementController::GetInstance()->SetBtHeadsetNrecOnToAllModem(enable);
+ }
+ }
+ mBtNrec = enable;
+ }
+ return NO_ERROR;
+}
+
+int SpeechModemController::setBtVgs(const bool support) {
+ ALOGD("%s(), mBtVgs: %d => %d", __FUNCTION__, mBtVgs, support);
+ AL_AUTOLOCK(mLock);
+
+ if (mBtVgs != support) {
+ AudioVolumeFactory::CreateAudioVolumeController()->setBtVolumeCapability(support);
+ mBtVgs = support;
+ }
+ return NO_ERROR;
+}
+
+int SpeechModemController::setDlDigitalGain(const int16_t gain) {
+ ALOGD("%s() gain=%d", __FUNCTION__, gain);
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ return speechDriver->SetDownlinkGain(gain);
+}
+
+int SpeechModemController::setUlDigitalGain(const int16_t gain) {
+ ALOGD("%s() gain=%d", __FUNCTION__, gain);
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ return speechDriver->SetUplinkGain(gain);
+}
+
+int SpeechModemController::setSpeakerType(const int type) {
+ if (mSpkType == type) {
+ return NO_ERROR;
+ } else {
+ AudioVolumeFactory::CreateAudioVolumeController()->setSpeakerType(type);
+ mSpkType = type;
+ ALOGD("%s() type=%d, mSpkType=%d", __FUNCTION__, type, mSpkType);
+ return NO_ERROR;
+ }
+}
+
+int SpeechModemController::getUlAnalogGain() {
+ uint16_t gain = 0;
+
+ gain = AudioVolumeFactory::CreateAudioVolumeController()->getVoiceUlAnalogGain(mCurrentOutputDevice,
+ AUDIO_MODE_IN_CALL);
+ ALOGD("%s(), gain=%d, mSpeechOn=%d, mCurrentOutputDevice=%d",
+ __FUNCTION__, gain, mSpeechOn, mCurrentOutputDevice);
+ return (int)gain;
+}
+
+int SpeechModemController::getDlAnalogGain() {
+ int16_t degradeGain = 0;
+ int gain = 0;
+
+ gain = AudioVolumeFactory::CreateAudioVolumeController()->getVoiceDlAnalogGain(mVolumeIndex,
+ mCurrentOutputDevice,
+ AUDIO_MODE_IN_CALL);
+ ALOGD("%s(), gain=%d, mSpeechOn=%d, mVolumeIndex=%d, mCurrentOutputDevice=%d",
+ __FUNCTION__, gain, mSpeechOn, mVolumeIndex, mCurrentOutputDevice);
+ return gain;
+}
+
+int SpeechModemController::setVolumeIndex(const int index) {
+ //mVolumeIndex: valid range 0 to 7
+ //range 1~7(map to xml 0~6), 0 for mute
+ if (index < 0 || index > 7) {
+ ALOGW("%s(), invalid index=%d, valid range is 0 to 7",
+ __FUNCTION__, index);
+ } else {
+ ALOGD("%s(), mVolumeIndex=%d->%d, mCurrentOutputDevice=%d",
+ __FUNCTION__, mVolumeIndex, index, mCurrentOutputDevice);
+ mVolumeIndex = index;
+ AudioVolumeFactory::CreateAudioVolumeController()->setVoiceVolume(index, mCurrentOutputDevice, AUDIO_MODE_IN_CALL);
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ return speechDriver->setMDVolumeIndex(0, 0, mVolumeIndex);
+ }
+ return NO_ERROR;
+}
+
+int SpeechModemController::setUplinkMute(const bool mute) {
+ AL_AUTOLOCK(mUlMuteLock);
+ ALOGD("%s() mute(%d ->%d)", __FUNCTION__, mUlMute, mute);
+ if (mUlMute != mute) {
+ mUlMute = mute;
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ speechDriver->SetUplinkMute(mute);
+ }
+ return NO_ERROR;
+}
+
+int SpeechModemController::setDownlinkMute(const bool mute) {
+ AL_AUTOLOCK(mDlMuteLock);
+ ALOGD("%s() mute(%d ->%d)", __FUNCTION__, mDlMute, mute);
+ if (mDlMute != mute) {
+ mDlMute = mute;
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ speechDriver->SetDownlinkMute(mute);
+ }
+ return NO_ERROR;
+}
+
+bool SpeechModemController::getUplinkMute() {
+ AL_AUTOLOCK(mUlMuteLock);
+ ALOGD("%s() mUlMute=%d", __FUNCTION__, mUlMute);
+ return mUlMute;
+}
+
+bool SpeechModemController::getDownlinkMute() {
+ AL_AUTOLOCK(mDlMuteLock);
+ ALOGD("%s() mDlMute=%d", __FUNCTION__, mDlMute);
+ return mDlMute;
+}
+
+int SpeechModemController::eCallIvsSwitch(bool enable) {
+ ALOGD("%s(), mIsEcallIvsOn(%d->%d)", __FUNCTION__, mIsEcallIvsOn, enable);
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ if (false == speechDriver->GetApSideModemStatus(SPEECH_STATUS_MASK)) {
+ ALOGW("%s(), mIsEcallIvsOn(%d->%d), speech is off, return.", __FUNCTION__, mIsEcallIvsOn, enable);
+ return -EFAULT;
+ }
+ if (mIsEcallIvsOn != enable) {
+ speechDriver->eCallIvsSwitch(enable);
+ mIsEcallIvsOn = enable;
+ }
+ return NO_ERROR;
+}
+
+int SpeechModemController::eCallIvsSend() {
+ ALOGD("%s()", __FUNCTION__);
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ speechDriver->eCallIvsSend();
+
+ return NO_ERROR;
+}
+
+int SpeechModemController::eCallPsapSwitch(bool enable) {
+ ALOGD("%s(), mIsEcallPsapOn(%d->%d)", __FUNCTION__, mIsEcallPsapOn, enable);
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ if (false == speechDriver->GetApSideModemStatus(SPEECH_STATUS_MASK)) {
+ ALOGW("%s(), mIsEcallPsapOn(%d->%d), speech is off, return.", __FUNCTION__, mIsEcallPsapOn, enable);
+ return -EFAULT;
+ }
+ if (mIsEcallPsapOn != enable) {
+ speechDriver->eCallPsapSwitch(enable);
+ mIsEcallPsapOn = enable;
+ }
+ return NO_ERROR;
+}
+
+int SpeechModemController::eCallPsapSend() {
+ ALOGD("%s()", __FUNCTION__);
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ speechDriver->eCallPsapSend();
+
+ return NO_ERROR;
+}
+
+int SpeechModemController::eCallCtrlSeqSwitch(bool enable) {
+ ALOGD("%s(), mIsEcallCtrlSeqOn(%d->%d)", __FUNCTION__, mIsEcallCtrlSeqOn, enable);
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ if (false == speechDriver->GetApSideModemStatus(SPEECH_STATUS_MASK)) {
+ ALOGW("%s(), mIsEcallCtrlSeqOn(%d->%d), speech is off, return.", __FUNCTION__, mIsEcallCtrlSeqOn, enable);
+ return -EFAULT;
+ }
+ if (mIsEcallCtrlSeqOn != enable) {
+ speechDriver->eCallCtrlSeqSwitch(enable);
+ mIsEcallCtrlSeqOn = enable;
+ }
+ return NO_ERROR;
+}
+
+int SpeechModemController::eCallMsd(void *data, uint16_t len) {
+ ALOGD("%s(), len = %d", __FUNCTION__, len);
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ speechDriver->eCallMsd(data, len);
+
+ return NO_ERROR;
+}
+
+int SpeechModemController::eCallTxCtrlParam(void *data, uint16_t len) {
+ ALOGD("%s(), len = %d", __FUNCTION__, len);
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ speechDriver->eCallTxCtrlParam(data, len);
+
+ return NO_ERROR;
+}
+
+int SpeechModemController::bgsOpen(uint32_t sampleRate) {
+ ALOGD("%s(), sampleRate = %d", __FUNCTION__, sampleRate);
+ SpeechDriverInterface *speechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ mBGSPlayBuffer = BGSPlayer::GetInstance()->CreateBGSPlayBuffer(sampleRate, 1, AUDIO_FORMAT_PCM_16_BIT);
+ BGSPlayer::GetInstance()->Open(speechDriver, 0x0, 0xFF);
+
+ return NO_ERROR;
+}
+
+int SpeechModemController::bgsClose() {
+ ALOGD("%s()", __FUNCTION__);
+ BGSPlayer::GetInstance()->Close();
+ BGSPlayer::GetInstance()->DestroyBGSPlayBuffer(mBGSPlayBuffer);
+ mBGSPlayBuffer = NULL;
+
+ return NO_ERROR;
+}
+
+uint32_t SpeechModemController::bgsWrite(void *buf, uint32_t bytes) {
+ uint32_t bytesConsumed = 0;
+ bytesConsumed = BGSPlayer::GetInstance()->Write(mBGSPlayBuffer, buf, bytes);
+ ALOGD("%s(), bytes = %d, bytesConsumed = %d", __FUNCTION__, bytes, bytesConsumed);
+
+ return bytesConsumed;
+}
+
+} // end of namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/drv/speech_drv.c b/src/multimedia/libspeech_drv/audio_big_sw/os/drv/speech_drv.c
new file mode 100644
index 0000000..2314cb9
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/drv/speech_drv.c
@@ -0,0 +1,534 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include "speech_drv.h"
+#include <utils/Log.h>
+
+#undef LOG_TAG
+#define LOG_TAG "SPEECH_CLI"
+
+
+bool send_req(SPH_REQ *request, int *result) {
+ //Create a Client Socket.
+ struct sockaddr_un path;
+ SPH_MSG response = {0};
+
+ /*Socket*/
+ int client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (-1 == client_fd) {
+ ALOGE("%s(), open socket fail. errno = %d", __func__, errno);
+ goto FAIL;
+ }
+
+ /*Bind*/
+ memset(&path, 0, sizeof(path));
+ path.sun_family = AF_UNIX;
+ strncpy(path.sun_path, CLIENT_SOCK_FILE, sizeof(path.sun_path));
+ path.sun_path[sizeof(path.sun_path) - 1] = '\0';
+ int resbind = bind(client_fd, (struct sockaddr *)&path, sizeof(path));
+ if (-1 == resbind) {
+ ALOGE("%s(), bind socket fail. errno = %d", __func__, errno);
+ goto FAIL;
+ }
+
+ /*Ensure that the server socket has appeared.*/
+ int count = 0;
+ while (-1 == access(SERVER_SOCK_FILE, F_OK)) {
+ ALOGE("%s(), The server socket doesn't exist yet. errno = %d", __func__, errno);
+ sleep(1);
+ count ++;
+ if (25 == count) {
+ ALOGE("%s(), Waiting for server socket timeout!!", __func__);
+ goto FAIL;
+ }
+ }
+
+ /*Connect*/
+ memset(&path, 0, sizeof(path));
+ path.sun_family = AF_UNIX;
+ strncpy(path.sun_path, SERVER_SOCK_FILE, sizeof(path.sun_path));
+ path.sun_path[sizeof(path.sun_path) - 1] = '\0';
+ int resconnect = connect(client_fd, (struct sockaddr *)&path, sizeof(path));
+ if (-1 == resconnect) {
+ ALOGE("%s(), connect socket fail. errno = %d", __func__, errno);
+ goto FAIL;
+ }
+
+ strncpy(response.cmd, "ACK", sizeof(response.cmd));
+ response.cmd[sizeof(response.cmd) - 1] = '\0';
+ int ressend = send(client_fd, &response, sizeof(SPH_MSG), 0);
+ if (-1 == ressend) {
+ ALOGE("%s(), send socket fail. errno = %d", __func__, errno);
+ goto FAIL;
+ }
+
+ memset(&response, 0, sizeof(SPH_MSG));
+ int len = recv(client_fd, &response, sizeof(SPH_MSG), 0);
+ if (len < 0) {
+ ALOGE("%s(), receive socket fail. errno = %d", __func__, errno);
+ goto FAIL;
+ }
+
+ if (strcmp(response.cmd, "READY") == 0) {
+ memset(&response, 0, sizeof(SPH_MSG));
+ strncpy(response.cmd, "REQ", sizeof(response.cmd));
+ response.cmd[sizeof(response.cmd) - 1] = '\0';
+ response.req = *request;
+ ressend = send(client_fd, &response, sizeof(SPH_MSG), 0);
+ if (-1 == ressend) {
+ ALOGE("%s(), send socket fail. errno = %d", __func__, errno);
+ goto FAIL;
+ }
+
+ len = recv(client_fd, &response, sizeof(SPH_MSG), 0);
+ if (len < 0) {
+ ALOGE("%s(), receive socket fail. errno = %d", __func__, errno);
+ goto FAIL;
+ }
+
+ *result = response.result;
+
+ close(client_fd);
+ unlink(CLIENT_SOCK_FILE);
+
+ ALOGD("%s(), communication done. command id = %d, response = %d.", __func__, response.req.id, *result);
+
+ return true;
+ }
+
+
+FAIL:
+ if (client_fd >= 0) {
+ close(client_fd);
+ }
+ unlink(CLIENT_SOCK_FILE);
+ return false;
+}
+
+
+/* For normal call setting API */
+int speechdrv_set_speech_on(bool enable, int inputDevice, int outputDevice) {
+ ALOGD("%s(), enable = %d, inputDevice = 0x%x, outputDevice = 0x%x", __func__, enable, inputDevice, outputDevice);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = SET_SPEECH_ON;
+ req.speechOn = enable;
+ req.inputDevice = inputDevice;
+ req.outputDevice = outputDevice;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return false;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_change_speech_device(int inputDevice, int outputDevice) {
+ ALOGD("%s(), inputDevice = 0x%x, outputDevice = 0x%x", __func__, inputDevice, outputDevice);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = CHANGE_SPEECH_ROUTING;
+ req.inputDevice = inputDevice;
+ req.outputDevice = outputDevice;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return false;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_set_vm_on(uint8_t config) {
+ ALOGD("%s(), config = %d", __func__, config);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = VMLOG_RECORD;
+ req.vmConfig = config;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return SPH_REQ_SEND_FAIL;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_get_ul_analog_gain() {
+ ALOGD("%s()", __func__);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = GET_UL_ANA_GAIN;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return SPH_REQ_SEND_FAIL;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_get_dl_analog_gain() {
+ ALOGD("%s()", __func__);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = GET_DL_ANA_GAIN;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return SPH_REQ_SEND_FAIL;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_set_speaker_type(unsigned int type) {
+ ALOGD("%s(), type = %d", __func__, type);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = SET_SPK_TYPE;
+ req.speakerType = type;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return false;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_set_volume_index(unsigned int index, int outputDevice) {
+ ALOGD("%s(), index = %d, outputDevice = 0x%x", __func__, index, outputDevice);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = DL_VOL_IDX;
+ req.volumeIdx = index;
+ req.outputDevice = outputDevice;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return SPH_REQ_SEND_FAIL;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_set_ul_mute(bool enable) {
+ ALOGD("%s(), enable = %d", __func__, enable);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = SET_UL_MUTE;
+ req.muteOn = enable;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return SPH_REQ_SEND_FAIL;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_set_dl_mute(bool enable) {
+ ALOGD("%s(), enable = %d", __func__, enable);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = SET_DL_MUTE;
+ req.muteOn = enable;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return SPH_REQ_SEND_FAIL;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_get_ul_mute_status(void) {
+ ALOGD("%s", __func__);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = GET_UL_MUTE;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return SPH_REQ_SEND_FAIL;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_get_dl_mute_status(void) {
+ ALOGD("%s", __func__);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = GET_DL_MUTE;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return SPH_REQ_SEND_FAIL;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_set_bt_wbs(int enable) {
+ ALOGD("%s(), enable = %d", __func__, enable);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = SET_BT_WBS;
+ req.btWbsOn = enable;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return SPH_REQ_SEND_FAIL;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_set_bt_nrec(bool enable) {
+ ALOGD("%s(), enable = %d", __func__, enable);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = SET_BT_NREC;
+ req.btNrecOn = enable;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return SPH_REQ_SEND_FAIL;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_set_bt_vgs(bool support) {
+ ALOGD("%s(), support = %d", __func__, support);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = SET_BT_VGS;
+ req.btVgsOn = support;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return SPH_REQ_SEND_FAIL;
+ } else {
+ return response;
+ }
+}
+
+/* For eCall API */
+int speechdrv_set_ecall_speech_on(bool enable) {
+ ALOGD("%s(), enable = %d", __func__, enable);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = ECALL_SPEECH_ON;
+ req.speechOn = enable;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return SPH_REQ_SEND_FAIL;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_set_ivs_switch(bool enable) {
+ ALOGD("%s(), enable = %d", __func__, enable);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = IVS_SWITCH;
+ req.switchOn = enable;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return false;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_set_ivs_send(void) {
+ ALOGD("%s", __func__);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = IVS_SEND;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return false;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_set_psap_switch(bool enable) {
+ ALOGD("%s(), enable = %d", __func__, enable);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = PSAP_SWITCH;
+ req.switchOn = enable;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return false;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_set_psap_send(void) {
+ ALOGD("%s", __func__);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = PSAP_SEND;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return false;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_set_ecall_msd(void *buf, uint32_t bytes) {
+ ALOGD("%s(), bytes = %d", __func__, bytes);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = ECALL_MSD;
+ int index;
+
+ memset(req.dataBuf, 0, SPH_BUF_BYTES);
+ for (index = 0; index < bytes; index++) {
+ req.dataBuf[index] = *((char *)(buf) + index);
+ }
+
+ ALOGD("%s: dataBuf[0] = %c.", __func__, req.dataBuf[0]);
+ req.dataSize = bytes;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return false;
+ } else {
+ return response;
+ }
+}
+
+//1. Padding to 9K, if data is less than 9K, fill it with "0".
+//2. Each section of data is one column of the test script.
+//3. len = the MAX number of integers among those columns.
+int speechdrv_set_ecall_testseq(void *buf, uint32_t len) {
+ ALOGD("%s(), len = %d words = %d bytes", __func__, len, len*2);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = ECALL_TESTSEQ;
+ int index, section;
+
+ //Since the test_seq buffer is only 1024 words long.
+ if (1024 < len) {
+ ALOGE("%s: invalid length of test seq(%d) > 1024.", __func__, len);
+ return 1;
+ }
+ memset(req.dataBuf, 0, SPH_BUF_BYTES);
+
+ for (section = 0; section < 3; section++) {
+ //Add one-word-header
+ if (0 == section) {
+ req.dataBuf[0] = 0xAA;
+ }
+
+ if (1 == section) {
+ req.dataBuf[0] = 0xBB;
+ }
+
+ if (2 == section) {
+ req.dataBuf[0] = 0xCC;
+ }
+
+ for (index = 0; index < len; index++) {
+ req.dataBuf[index + 1] = *((int16_t *)(buf) + index + len * section);
+ }
+
+ req.dataSize = (len + 1)*2; //data + 1 word of SYNC header
+
+ ALOGD("%s: dataBuf[0]=0x%x, dataSize = %d words. (before send_req)", __func__, req.dataBuf[0], req.dataSize);
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail. (the %d section)", __func__, section);
+ return SPH_REQ_SEND_FAIL;
+ } else {
+ memset(req.dataBuf, 0, sizeof(req.dataBuf));
+ }
+ }
+ return response;
+}
+
+int speechdrv_set_ecall_testseq_switch(bool enable) {
+ ALOGD("%s(), enable = %d", __func__, enable);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = ECALL_TESTSEQ_SWITCH;
+ req.switchOn = enable;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return SPH_REQ_SEND_FAIL;
+ } else {
+ return response;
+ }
+}
+
+
+/* For BGS API */
+
+int speechdrv_bgs_open(uint32_t sampleRate) {
+ ALOGD("%s(), sampleRate = %d", __func__, sampleRate);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = BGS_OPEN;
+ req.sampleRate = sampleRate;
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return SPH_REQ_SEND_FAIL;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_bgs_close() {
+ ALOGD("%s()", __func__);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = BGS_CLOSE;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return SPH_REQ_SEND_FAIL;
+ } else {
+ return response;
+ }
+}
+
+int speechdrv_bgs_write(void *buf, uint32_t bytes) {
+ ALOGD("%s(), bytes = %d", __func__, bytes);
+ SPH_REQ req = {0};
+ int response = 0;
+ req.id = BGS_WRITE;
+
+ memset(req.dataBuf, 0, SPH_BUF_BYTES);
+ memcpy(req.dataBuf, buf, bytes);
+ req.dataSize = bytes;
+
+ if (!send_req(&req, &response)) {
+ ALOGE("%s: Send request fail.", __func__);
+ return SPH_REQ_SEND_FAIL;
+ } else {
+ return response;
+ }
+}
+
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/hardware/audio_effect-base.h b/src/multimedia/libspeech_drv/audio_big_sw/os/hardware/audio_effect-base.h
new file mode 100644
index 0000000..8795fb1
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/hardware/audio_effect-base.h
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: MediaTekProprietary
+// This file is autogenerated by hidl-gen. Do not edit manually.
+// Source: android.hardware.audio.effect@4.0
+// Root: android.hardware:hardware/interfaces
+
+#ifndef YOCTO_AUDIO_EFFECT_BASE_H
+#define YOCTO_AUDIO_EFFECT_BASE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ EFFECT_FLAG_TYPE_SHIFT = 0,
+ EFFECT_FLAG_TYPE_SIZE = 3,
+ EFFECT_FLAG_TYPE_MASK = 7, // (((1 << TYPE_SIZE) - 1) << TYPE_SHIFT)
+ EFFECT_FLAG_TYPE_INSERT = 0, // (0 << TYPE_SHIFT)
+ EFFECT_FLAG_TYPE_AUXILIARY = 1, // (1 << TYPE_SHIFT)
+ EFFECT_FLAG_TYPE_REPLACE = 2, // (2 << TYPE_SHIFT)
+ EFFECT_FLAG_TYPE_PRE_PROC = 3, // (3 << TYPE_SHIFT)
+ EFFECT_FLAG_TYPE_POST_PROC = 4, // (4 << TYPE_SHIFT)
+ EFFECT_FLAG_INSERT_SHIFT = 3, // (TYPE_SHIFT + TYPE_SIZE)
+ EFFECT_FLAG_INSERT_SIZE = 3,
+ EFFECT_FLAG_INSERT_MASK = 56, // (((1 << INSERT_SIZE) - 1) << INSERT_SHIFT)
+ EFFECT_FLAG_INSERT_ANY = 0, // (0 << INSERT_SHIFT)
+ EFFECT_FLAG_INSERT_FIRST = 8, // (1 << INSERT_SHIFT)
+ EFFECT_FLAG_INSERT_LAST = 16, // (2 << INSERT_SHIFT)
+ EFFECT_FLAG_INSERT_EXCLUSIVE = 24, // (3 << INSERT_SHIFT)
+ EFFECT_FLAG_VOLUME_SHIFT = 6, // (INSERT_SHIFT + INSERT_SIZE)
+ EFFECT_FLAG_VOLUME_SIZE = 3,
+ EFFECT_FLAG_VOLUME_MASK = 448, // (((1 << VOLUME_SIZE) - 1) << VOLUME_SHIFT)
+ EFFECT_FLAG_VOLUME_CTRL = 64, // (1 << VOLUME_SHIFT)
+ EFFECT_FLAG_VOLUME_IND = 128, // (2 << VOLUME_SHIFT)
+ EFFECT_FLAG_VOLUME_NONE = 0, // (0 << VOLUME_SHIFT)
+ EFFECT_FLAG_DEVICE_SHIFT = 9, // (VOLUME_SHIFT + VOLUME_SIZE)
+ EFFECT_FLAG_DEVICE_SIZE = 3,
+ EFFECT_FLAG_DEVICE_MASK = 3584, // (((1 << DEVICE_SIZE) - 1) << DEVICE_SHIFT)
+ EFFECT_FLAG_DEVICE_IND = 512, // (1 << DEVICE_SHIFT)
+ EFFECT_FLAG_DEVICE_NONE = 0, // (0 << DEVICE_SHIFT)
+ EFFECT_FLAG_INPUT_SHIFT = 12, // (DEVICE_SHIFT + DEVICE_SIZE)
+ EFFECT_FLAG_INPUT_SIZE = 2,
+ EFFECT_FLAG_INPUT_MASK = 12288, // (((1 << INPUT_SIZE) - 1) << INPUT_SHIFT)
+ EFFECT_FLAG_INPUT_DIRECT = 4096, // (1 << INPUT_SHIFT)
+ EFFECT_FLAG_INPUT_PROVIDER = 8192, // (2 << INPUT_SHIFT)
+ EFFECT_FLAG_INPUT_BOTH = 12288, // (3 << INPUT_SHIFT)
+ EFFECT_FLAG_OUTPUT_SHIFT = 14, // (INPUT_SHIFT + INPUT_SIZE)
+ EFFECT_FLAG_OUTPUT_SIZE = 2,
+ EFFECT_FLAG_OUTPUT_MASK = 49152, // (((1 << OUTPUT_SIZE) - 1) << OUTPUT_SHIFT)
+ EFFECT_FLAG_OUTPUT_DIRECT = 16384, // (1 << OUTPUT_SHIFT)
+ EFFECT_FLAG_OUTPUT_PROVIDER = 32768, // (2 << OUTPUT_SHIFT)
+ EFFECT_FLAG_OUTPUT_BOTH = 49152, // (3 << OUTPUT_SHIFT)
+ EFFECT_FLAG_HW_ACC_SHIFT = 16, // (OUTPUT_SHIFT + OUTPUT_SIZE)
+ EFFECT_FLAG_HW_ACC_SIZE = 2,
+ EFFECT_FLAG_HW_ACC_MASK = 196608, // (((1 << HW_ACC_SIZE) - 1) << HW_ACC_SHIFT)
+ EFFECT_FLAG_HW_ACC_SIMPLE = 65536, // (1 << HW_ACC_SHIFT)
+ EFFECT_FLAG_HW_ACC_TUNNEL = 131072, // (2 << HW_ACC_SHIFT)
+ EFFECT_FLAG_AUDIO_MODE_SHIFT = 18, // (HW_ACC_SHIFT + HW_ACC_SIZE)
+ EFFECT_FLAG_AUDIO_MODE_SIZE = 2,
+ EFFECT_FLAG_AUDIO_MODE_MASK = 786432, // (((1 << AUDIO_MODE_SIZE) - 1) << AUDIO_MODE_SHIFT)
+ EFFECT_FLAG_AUDIO_MODE_IND = 262144, // (1 << AUDIO_MODE_SHIFT)
+ EFFECT_FLAG_AUDIO_MODE_NONE = 0, // (0 << AUDIO_MODE_SHIFT)
+ EFFECT_FLAG_AUDIO_SOURCE_SHIFT = 20, // (AUDIO_MODE_SHIFT + AUDIO_MODE_SIZE)
+ EFFECT_FLAG_AUDIO_SOURCE_SIZE = 2,
+ EFFECT_FLAG_AUDIO_SOURCE_MASK = 3145728, // (((1 << AUDIO_SOURCE_SIZE) - 1) << AUDIO_SOURCE_SHIFT)
+ EFFECT_FLAG_AUDIO_SOURCE_IND = 1048576, // (1 << AUDIO_SOURCE_SHIFT)
+ EFFECT_FLAG_AUDIO_SOURCE_NONE = 0, // (0 << AUDIO_SOURCE_SHIFT)
+ EFFECT_FLAG_OFFLOAD_SHIFT = 22, // (AUDIO_SOURCE_SHIFT + AUDIO_SOURCE_SIZE)
+ EFFECT_FLAG_OFFLOAD_SIZE = 1,
+ EFFECT_FLAG_OFFLOAD_MASK = 4194304, // (((1 << OFFLOAD_SIZE) - 1) << OFFLOAD_SHIFT)
+ EFFECT_FLAG_OFFLOAD_SUPPORTED = 4194304, // (1 << OFFLOAD_SHIFT)
+ EFFECT_FLAG_NO_PROCESS_SHIFT = 23, // (OFFLOAD_SHIFT + OFFLOAD_SIZE)
+ EFFECT_FLAG_NO_PROCESS_SIZE = 1,
+ EFFECT_FLAG_NO_PROCESS_MASK = 8388608, // (((1 << NO_PROCESS_SIZE) - 1) << NO_PROCESS_SHIFT)
+ EFFECT_FLAG_NO_PROCESS = 8388608, // (1 << NO_PROCESS_SHIFT)
+};
+
+typedef enum {
+ EFFECT_BUFFER_ACCESS_WRITE = 0,
+ EFFECT_BUFFER_ACCESS_READ = 1, // (::android::hardware::audio::effect::V4_0::EffectBufferAccess.ACCESS_WRITE implicitly + 1)
+ EFFECT_BUFFER_ACCESS_ACCUMULATE = 2, // (::android::hardware::audio::effect::V4_0::EffectBufferAccess.ACCESS_READ implicitly + 1)
+} effect_buffer_access_e;
+
+enum {
+ EFFECT_CONFIG_BUFFER = 1,
+ EFFECT_CONFIG_SMP_RATE = 2,
+ EFFECT_CONFIG_CHANNELS = 4,
+ EFFECT_CONFIG_FORMAT = 8,
+ EFFECT_CONFIG_ACC_MODE = 16,
+};
+
+typedef enum {
+ EFFECT_FEATURE_AUX_CHANNELS = 0,
+ EFFECT_FEATURE_CNT = 1, // (::android::hardware::audio::effect::V4_0::EffectFeature.AUX_CHANNELS implicitly + 1)
+} effect_feature_e;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // YOCTO_AUDIO_EFFECT_BASE_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/hardware/audio_effect.h b/src/multimedia/libspeech_drv/audio_big_sw/os/hardware/audio_effect.h
new file mode 100644
index 0000000..1d21cd5
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/hardware/audio_effect.h
@@ -0,0 +1,554 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+ * 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.
+ * 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 YOCTO_AUDIO_EFFECT_CORE_H
+#define YOCTO_AUDIO_EFFECT_CORE_H
+
+#include "system/audio.h"
+#include "audio_effect-base.h"
+
+__BEGIN_DECLS
+
+/////////////////////////////////////////////////
+// Common Definitions
+/////////////////////////////////////////////////
+
+//
+//--- Effect descriptor structure effect_descriptor_t
+//
+
+// This format is used for both "type" and "uuid" fields of the effect descriptor structure.
+// - When used for effect type and the engine is implementing and effect corresponding to a standard
+// OpenSL ES interface, this ID must be the one defined in OpenSLES_IID.h for that interface.
+// - When used as uuid, it should be a unique UUID for this particular implementation.
+typedef audio_uuid_t effect_uuid_t;
+
+// Maximum length of character strings in structures defines by this API.
+#define EFFECT_STRING_LEN_MAX 64
+
+// NULL UUID definition (matches SL_IID_NULL_)
+#define EFFECT_UUID_INITIALIZER { 0xec7178ec, 0xe5e1, 0x4432, 0xa3f4, \
+ { 0x46, 0x57, 0xe6, 0x79, 0x52, 0x10 } }
+static const effect_uuid_t EFFECT_UUID_NULL_ = EFFECT_UUID_INITIALIZER;
+static const effect_uuid_t * const EFFECT_UUID_NULL = &EFFECT_UUID_NULL_;
+static const char * const EFFECT_UUID_NULL_STR = "ec7178ec-e5e1-4432-a3f4-4657e6795210";
+
+// The effect descriptor contains necessary information to facilitate the enumeration of the effect
+// engines present in a library.
+typedef struct effect_descriptor_s {
+ effect_uuid_t type; // UUID of to the OpenSL ES interface implemented by this effect
+ effect_uuid_t uuid; // UUID for this particular implementation
+ uint32_t apiVersion; // Version of the effect control API implemented
+ uint32_t flags; // effect engine capabilities/requirements flags (see below)
+ uint16_t cpuLoad; // CPU load indication (see below)
+ uint16_t memoryUsage; // Data Memory usage (see below)
+ char name[EFFECT_STRING_LEN_MAX]; // human readable effect name
+ char implementor[EFFECT_STRING_LEN_MAX]; // human readable effect implementor name
+} effect_descriptor_t;
+
+#define EFFECT_CONFIG_ALL (EFFECT_CONFIG_BUFFER | \
+ EFFECT_CONFIG_SMP_RATE | \
+ EFFECT_CONFIG_CHANNELS | \
+ EFFECT_CONFIG_FORMAT | \
+ EFFECT_CONFIG_ACC_MODE)
+
+/////////////////////////////////////////////////
+// Effect control interface
+/////////////////////////////////////////////////
+
+//
+//--- Standardized command codes for command() function
+//
+enum effect_command_e {
+ EFFECT_CMD_INIT, // initialize effect engine
+ EFFECT_CMD_SET_CONFIG, // configure effect engine (see effect_config_t)
+ EFFECT_CMD_RESET, // reset effect engine
+ EFFECT_CMD_ENABLE, // enable effect process
+ EFFECT_CMD_DISABLE, // disable effect process
+ EFFECT_CMD_SET_PARAM, // set parameter immediately (see effect_param_t)
+ EFFECT_CMD_SET_PARAM_DEFERRED, // set parameter deferred
+ EFFECT_CMD_SET_PARAM_COMMIT, // commit previous set parameter deferred
+ EFFECT_CMD_GET_PARAM, // get parameter
+ EFFECT_CMD_SET_DEVICE, // set audio device (see audio.h, audio_devices_t)
+ EFFECT_CMD_SET_VOLUME, // set volume
+ EFFECT_CMD_SET_AUDIO_MODE, // set the audio mode (normal, ring, ...)
+ EFFECT_CMD_SET_CONFIG_REVERSE, // configure effect engine reverse stream(see effect_config_t)
+ EFFECT_CMD_SET_INPUT_DEVICE, // set capture device (see audio.h, audio_devices_t)
+ EFFECT_CMD_GET_CONFIG, // read effect engine configuration
+ EFFECT_CMD_GET_CONFIG_REVERSE, // read configure effect engine reverse stream configuration
+ EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS,// get all supported configurations for a feature.
+ EFFECT_CMD_GET_FEATURE_CONFIG, // get current feature configuration
+ EFFECT_CMD_SET_FEATURE_CONFIG, // set current feature configuration
+ EFFECT_CMD_SET_AUDIO_SOURCE, // set the audio source (see audio.h, audio_source_t)
+ EFFECT_CMD_OFFLOAD, // set if effect thread is an offload one,
+ // send the ioHandle of the effect thread
+ EFFECT_CMD_FIRST_PROPRIETARY = 0x10000 // first proprietary command code
+};
+
+//==================================================================================================
+// command: EFFECT_CMD_INIT
+//--------------------------------------------------------------------------------------------------
+// description:
+// Initialize effect engine: All configurations return to default
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: 0
+// data: N/A
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(int)
+// data: status
+//==================================================================================================
+// command: EFFECT_CMD_SET_CONFIG
+//--------------------------------------------------------------------------------------------------
+// description:
+// Apply new audio parameters configurations for input and output buffers
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(effect_config_t)
+// data: effect_config_t
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(int)
+// data: status
+//==================================================================================================
+// command: EFFECT_CMD_RESET
+//--------------------------------------------------------------------------------------------------
+// description:
+// Reset the effect engine. Keep configuration but resets state and buffer content
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: 0
+// data: N/A
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: 0
+// data: N/A
+//==================================================================================================
+// command: EFFECT_CMD_ENABLE
+//--------------------------------------------------------------------------------------------------
+// description:
+// Enable the process. Called by the framework before the first call to process()
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: 0
+// data: N/A
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(int)
+// data: status
+//==================================================================================================
+// command: EFFECT_CMD_DISABLE
+//--------------------------------------------------------------------------------------------------
+// description:
+// Disable the process. Called by the framework after the last call to process()
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: 0
+// data: N/A
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(int)
+// data: status
+//==================================================================================================
+// command: EFFECT_CMD_SET_PARAM
+//--------------------------------------------------------------------------------------------------
+// description:
+// Set a parameter and apply it immediately
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(effect_param_t) + size of param and value
+// data: effect_param_t + param + value. See effect_param_t definition below for value offset
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(int)
+// data: status
+//==================================================================================================
+// command: EFFECT_CMD_SET_PARAM_DEFERRED
+//--------------------------------------------------------------------------------------------------
+// description:
+// Set a parameter but apply it only when receiving EFFECT_CMD_SET_PARAM_COMMIT command
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(effect_param_t) + size of param and value
+// data: effect_param_t + param + value. See effect_param_t definition below for value offset
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: 0
+// data: N/A
+//==================================================================================================
+// command: EFFECT_CMD_SET_PARAM_COMMIT
+//--------------------------------------------------------------------------------------------------
+// description:
+// Apply all previously received EFFECT_CMD_SET_PARAM_DEFERRED commands
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: 0
+// data: N/A
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(int)
+// data: status
+//==================================================================================================
+// command: EFFECT_CMD_GET_PARAM
+//--------------------------------------------------------------------------------------------------
+// description:
+// Get a parameter value
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(effect_param_t) + size of param
+// data: effect_param_t + param
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(effect_param_t) + size of param and value
+// data: effect_param_t + param + value. See effect_param_t definition below for value offset
+//==================================================================================================
+// command: EFFECT_CMD_SET_DEVICE
+//--------------------------------------------------------------------------------------------------
+// description:
+// Set the rendering device the audio output path is connected to. See audio.h, audio_devices_t
+// for device values.
+// The effect implementation must set EFFECT_FLAG_DEVICE_IND flag in its descriptor to receive this
+// command when the device changes
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(uint32_t)
+// data: uint32_t
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: 0
+// data: N/A
+//==================================================================================================
+// command: EFFECT_CMD_SET_VOLUME
+//--------------------------------------------------------------------------------------------------
+// description:
+// Set and get volume. Used by audio framework to delegate volume control to effect engine.
+// The effect implementation must set EFFECT_FLAG_VOLUME_IND or EFFECT_FLAG_VOLUME_CTRL flag in
+// its descriptor to receive this command before every call to process() function
+// If EFFECT_FLAG_VOLUME_CTRL flag is set in the effect descriptor, the effect engine must return
+// the volume that should be applied before the effect is processed. The overall volume (the volume
+// actually applied by the effect engine multiplied by the returned value) should match the value
+// indicated in the command.
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: n * sizeof(uint32_t)
+// data: volume for each channel defined in effect_config_t for output buffer expressed in
+// 8.24 fixed point format
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: n * sizeof(uint32_t) / 0
+// data: - if EFFECT_FLAG_VOLUME_CTRL is set in effect descriptor:
+// volume for each channel defined in effect_config_t for output buffer expressed in
+// 8.24 fixed point format
+// - if EFFECT_FLAG_VOLUME_CTRL is not set in effect descriptor:
+// N/A
+// It is legal to receive a null pointer as pReplyData in which case the effect framework has
+// delegated volume control to another effect
+//==================================================================================================
+// command: EFFECT_CMD_SET_AUDIO_MODE
+//--------------------------------------------------------------------------------------------------
+// description:
+// Set the audio mode. The effect implementation must set EFFECT_FLAG_AUDIO_MODE_IND flag in its
+// descriptor to receive this command when the audio mode changes.
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(uint32_t)
+// data: audio_mode_t
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: 0
+// data: N/A
+//==================================================================================================
+// command: EFFECT_CMD_SET_CONFIG_REVERSE
+//--------------------------------------------------------------------------------------------------
+// description:
+// Apply new audio parameters configurations for input and output buffers of reverse stream.
+// An example of reverse stream is the echo reference supplied to an Acoustic Echo Canceler.
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(effect_config_t)
+// data: effect_config_t
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(int)
+// data: status
+//==================================================================================================
+// command: EFFECT_CMD_SET_INPUT_DEVICE
+//--------------------------------------------------------------------------------------------------
+// description:
+// Set the capture device the audio input path is connected to. See audio.h, audio_devices_t
+// for device values.
+// The effect implementation must set EFFECT_FLAG_DEVICE_IND flag in its descriptor to receive this
+// command when the device changes
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(uint32_t)
+// data: uint32_t
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: 0
+// data: N/A
+//==================================================================================================
+// command: EFFECT_CMD_GET_CONFIG
+//--------------------------------------------------------------------------------------------------
+// description:
+// Read audio parameters configurations for input and output buffers
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: 0
+// data: N/A
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(effect_config_t)
+// data: effect_config_t
+//==================================================================================================
+// command: EFFECT_CMD_GET_CONFIG_REVERSE
+//--------------------------------------------------------------------------------------------------
+// description:
+// Read audio parameters configurations for input and output buffers of reverse stream
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: 0
+// data: N/A
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(effect_config_t)
+// data: effect_config_t
+//==================================================================================================
+// command: EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS
+//--------------------------------------------------------------------------------------------------
+// description:
+// Queries for supported configurations for a particular feature (e.g. get the supported
+// combinations of main and auxiliary channels for a noise suppressor).
+// The command parameter is the feature identifier (See effect_feature_e for a list of defined
+// features) followed by the maximum number of configuration descriptor to return.
+// The reply is composed of:
+// - status (uint32_t):
+// - 0 if feature is supported
+// - -ENOSYS if the feature is not supported,
+// - -ENOMEM if the feature is supported but the total number of supported configurations
+// exceeds the maximum number indicated by the caller.
+// - total number of supported configurations (uint32_t)
+// - an array of configuration descriptors.
+// The actual number of descriptors returned must not exceed the maximum number indicated by
+// the caller.
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: 2 x sizeof(uint32_t)
+// data: effect_feature_e + maximum number of configurations to return
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: 2 x sizeof(uint32_t) + n x sizeof (<config descriptor>)
+// data: status + total number of configurations supported + array of n config descriptors
+//==================================================================================================
+// command: EFFECT_CMD_GET_FEATURE_CONFIG
+//--------------------------------------------------------------------------------------------------
+// description:
+// Retrieves current configuration for a given feature.
+// The reply status is:
+// - 0 if feature is supported
+// - -ENOSYS if the feature is not supported,
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(uint32_t)
+// data: effect_feature_e
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(uint32_t) + sizeof (<config descriptor>)
+// data: status + config descriptor
+//==================================================================================================
+// command: EFFECT_CMD_SET_FEATURE_CONFIG
+//--------------------------------------------------------------------------------------------------
+// description:
+// Sets current configuration for a given feature.
+// The reply status is:
+// - 0 if feature is supported
+// - -ENOSYS if the feature is not supported,
+// - -EINVAL if the configuration is invalid
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(uint32_t) + sizeof (<config descriptor>)
+// data: effect_feature_e + config descriptor
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(uint32_t)
+// data: status
+//==================================================================================================
+// command: EFFECT_CMD_SET_AUDIO_SOURCE
+//--------------------------------------------------------------------------------------------------
+// description:
+// Set the audio source the capture path is configured for (Camcorder, voice recognition...).
+// See audio.h, audio_source_t for values.
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(uint32_t)
+// data: uint32_t
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: 0
+// data: N/A
+//==================================================================================================
+// command: EFFECT_CMD_OFFLOAD
+//--------------------------------------------------------------------------------------------------
+// description:
+// 1.indicate if the playback thread the effect is attached to is offloaded or not
+// 2.update the io handle of the playback thread the effect is attached to
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(effect_offload_param_t)
+// data: effect_offload_param_t
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(uint32_t)
+// data: uint32_t
+//--------------------------------------------------------------------------------------------------
+// command: EFFECT_CMD_FIRST_PROPRIETARY
+//--------------------------------------------------------------------------------------------------
+// description:
+// All proprietary effect commands must use command codes above this value. The size and format of
+// command and response fields is free in this case
+//==================================================================================================
+
+// Audio buffer descriptor used by process(), bufferProvider() functions and buffer_config_t
+// structure. Multi-channel audio is always interleaved. The channel order is from LSB to MSB with
+// regard to the channel mask definition in audio.h, audio_channel_mask_t e.g :
+// Stereo: left, right
+// 5 point 1: front left, front right, front center, low frequency, back left, back right
+// The buffer size is expressed in frame count, a frame being composed of samples for all
+// channels at a given time. Frame size for unspecified format (AUDIO_FORMAT_OTHER) is 8 bit by
+// definition
+typedef struct audio_buffer_s {
+ size_t frameCount; // number of frames in buffer
+ union {
+ void* raw; // raw pointer to start of buffer
+ float* f32; // pointer to float 32 bit data at start of buffer
+ int32_t* s32; // pointer to signed 32 bit data at start of buffer
+ int16_t* s16; // pointer to signed 16 bit data at start of buffer
+ uint8_t* u8; // pointer to unsigned 8 bit data at start of buffer
+ };
+} audio_buffer_t;
+
+// The buffer_provider_s structure contains functions that can be used
+// by the effect engine process() function to query and release input
+// or output audio buffer.
+// The getBuffer() function is called to retrieve a buffer where data
+// should read from or written to by process() function.
+// The releaseBuffer() function MUST be called when the buffer retrieved
+// with getBuffer() is not needed anymore.
+// The process function should use the buffer provider mechanism to retrieve
+// input or output buffer if the inBuffer or outBuffer passed as argument is NULL
+// and the buffer configuration (buffer_config_t) given by the EFFECT_CMD_SET_CONFIG
+// command did not specify an audio buffer.
+
+typedef int32_t (* buffer_function_t)(void *cookie, audio_buffer_t *buffer);
+
+typedef struct buffer_provider_s {
+ buffer_function_t getBuffer; // retrieve next buffer
+ buffer_function_t releaseBuffer; // release used buffer
+ void *cookie; // for use by client of buffer provider functions
+} buffer_provider_t;
+
+// The buffer_config_s structure specifies the input or output audio format
+// to be used by the effect engine.
+typedef struct buffer_config_s {
+ audio_buffer_t buffer; // buffer for use by process() function if not passed explicitly
+ uint32_t samplingRate; // sampling rate
+ uint32_t channels; // channel mask (see audio_channel_mask_t in audio.h)
+ buffer_provider_t bufferProvider; // buffer provider
+ uint8_t format; // Audio format (see audio_format_t in audio.h)
+ uint8_t accessMode; // read/write or accumulate in buffer (effect_buffer_access_e)
+ uint16_t mask; // indicates which of the above fields is valid
+} buffer_config_t;
+
+// EFFECT_FEATURE_AUX_CHANNELS feature configuration descriptor. Describe a combination
+// of main and auxiliary channels supported
+typedef struct channel_config_s {
+ audio_channel_mask_t main_channels; // channel mask for main channels
+ audio_channel_mask_t aux_channels; // channel mask for auxiliary channels
+} channel_config_t;
+
+
+// effect_config_s structure is used to configure audio parameters and buffers for effect engine
+// input and output.
+typedef struct effect_config_s {
+ buffer_config_t inputCfg;
+ buffer_config_t outputCfg;
+} effect_config_t;
+
+
+// effect_param_s structure describes the format of the pCmdData argument of EFFECT_CMD_SET_PARAM
+// command and pCmdData and pReplyData of EFFECT_CMD_GET_PARAM command.
+// psize and vsize represent the actual size of parameter and value.
+//
+// NOTE: the start of value field inside the data field is always on a 32 bit boundary:
+//
+// +-----------+
+// | status | sizeof(int)
+// +-----------+
+// | psize | sizeof(int)
+// +-----------+
+// | vsize | sizeof(int)
+// +-----------+
+// | | | |
+// ~ parameter ~ > psize |
+// | | | > ((psize - 1)/sizeof(int) + 1) * sizeof(int)
+// +-----------+ |
+// | padding | |
+// +-----------+
+// | | |
+// ~ value ~ > vsize
+// | | |
+// +-----------+
+
+typedef struct effect_param_s {
+ int32_t status; // Transaction status (unused for command, used for reply)
+ uint32_t psize; // Parameter size
+ uint32_t vsize; // Value size
+ char data[]; // Start of Parameter + Value data
+} effect_param_t;
+
+// Maximum effect_param_t size
+#define EFFECT_PARAM_SIZE_MAX 65536
+
+// structure used by EFFECT_CMD_OFFLOAD command
+typedef struct effect_offload_param_s {
+ bool isOffload; // true if the playback thread the effect is attached to is offloaded
+ int ioHandle; // io handle of the playback thread the effect is attached to
+} effect_offload_param_t;
+
+typedef struct effect_interface_s **effect_handle_t;
+struct effect_interface_s {
+ int32_t (*process)(effect_handle_t self,
+ audio_buffer_t *inBuffer,
+ audio_buffer_t *outBuffer);
+ int32_t (*command)(effect_handle_t self,
+ uint32_t cmdCode,
+ uint32_t cmdSize,
+ void *pCmdData,
+ uint32_t *replySize,
+ void *pReplyData);
+ int32_t (*get_descriptor)(effect_handle_t self,
+ effect_descriptor_t *pDescriptor);
+ int32_t (*process_reverse)(effect_handle_t self,
+ audio_buffer_t *inBuffer,
+ audio_buffer_t *outBuffer);
+};
+
+__END_DECLS
+
+#endif // YOCTO_AUDIO_EFFECT_CORE_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/include/MtkAudioSrc.h b/src/multimedia/libspeech_drv/audio_big_sw/os/include/MtkAudioSrc.h
new file mode 100644
index 0000000..d272e5f
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/include/MtkAudioSrc.h
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* MediaTek Inc. (C) 2016. All rights reserved.
+ *
+ * Copyright Statement:
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ */
+
+/*
+* Description:
+* This file implements Mtk Audio Ssampl Rate Converter
+*/
+
+#ifndef __MTK_AUDIO_SRC_EXP_H__
+#define __MTK_AUDIO_SRC_EXP_H__
+
+#include <utils/threads.h>
+#include "MtkAudioComponent.h"
+#if defined(HAVE_SWIP)
+extern "C" {
+#include "Blisrc_exp.h"
+}
+#endif
+namespace android {
+
+#if !defined(HAVE_SWIP)
+typedef int Blisrc_Handle;
+typedef struct {
+ uint32_t PCM_Format;
+ uint32_t in_sampling_rate;
+ uint32_t ou_sampling_rate;
+ uint32_t in_channel;
+ uint32_t ou_channel;
+} Blisrc_Param;
+#endif
+
+class MtkAudioSrc : public MtkAudioSrcBase {
+public:
+ MtkAudioSrc();
+ MtkAudioSrc(uint32_t input_SR, uint32_t input_channel_num, uint32_t output_SR, uint32_t output_channel_num, SRC_PCM_FORMAT format);
+ virtual ACE_ERRID setParameter(uint32_t paramID, void *param);
+ virtual ACE_ERRID getParameter(uint32_t paramID, void *param);
+ virtual ACE_ERRID open(void);
+ virtual ACE_ERRID close(void);
+ virtual ACE_ERRID resetBuffer(void);
+ virtual ACE_ERRID process(void *pInputBuffer, /* Input, pointer to input buffer */
+ uint32_t *InputSampleCount, /* Input, length(byte) of input buffer */
+ /* Output, length(byte) left in the input buffer after conversion */
+ void *pOutputBuffer, /* Input, pointer to output buffer */
+ uint32_t *OutputSampleCount); /* Input, length(byte) of output buffer */
+ /* Output, output data length(byte) */
+
+ virtual ACE_ERRID multiChannelOpen(void);
+ virtual ACE_ERRID multiChannelResetBuffer(void);
+ virtual ACE_ERRID multiChannelProcess(void *pInputBuffer, /* Input, pointer to input buffer */
+ uint32_t *InputSampleCount, /* Input, length(byte) of input buffer */
+ /* Output, length(byte) left in the input buffer after conversion */
+ void *pOutputBuffer, /* Input, pointer to output buffer */
+ uint32_t *OutputSampleCount); /* Input, length(byte) of output buffer */
+ /* Output, output data length(byte) */
+ virtual ~MtkAudioSrc();
+private:
+ ACE_STATE mState;
+ uint32_t mTempBufSize; // in byte
+ uint32_t mInternalBufSize; // in byte
+ char *mpTempBuf;
+ char *mpInternalBuf;
+ Blisrc_Param mBlisrcParam;
+ Blisrc_Handle *mBlisrcHandler;
+ Mutex mLock;
+};
+
+}; // namespace android
+
+#endif // __MTK_AUDIO_SRC_EXP_H__
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/include/SpeechModemController.h b/src/multimedia/libspeech_drv/audio_big_sw/os/include/SpeechModemController.h
new file mode 100644
index 0000000..dde67c5
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/include/SpeechModemController.h
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_MODEM_CONTROLLER_H
+#define ANDROID_SPEECH_MODEM_CONTROLLER_H
+
+#include "SpeechType.h"
+#include "SpeechBGSPlayer.h"
+#include "AudioVolumeInterface.h"
+
+#include "AudioLock.h"
+
+namespace android {
+
+class SpeechDriverFactory;
+
+class SpeechModemController {
+public:
+ virtual ~SpeechModemController();
+
+ static SpeechModemController *getInstance();
+
+ virtual int initialize();
+
+ virtual int phoneCallOpen(const audio_devices_t input_device, const audio_devices_t output_devices);
+ virtual int phoneCallClose();
+ virtual int phoneCallRouting(const audio_devices_t input_device, const audio_devices_t output_devices);
+
+ virtual int configVm(const uint8_t vmConfig);
+ virtual int setUlDigitalGain(const int16_t gain);
+ virtual int setDlDigitalGain(const int16_t gain);
+ virtual int setSpeakerType(const int type);
+ virtual int getUlAnalogGain();
+ virtual int getDlAnalogGain();
+ virtual int setVolumeIndex(const int index);
+ virtual int setUplinkMute(const bool mute);
+ virtual int setDownlinkMute(const bool mute);
+ virtual bool getUplinkMute();
+ virtual bool getDownlinkMute();
+ virtual int setBtMode(const int mode);
+ virtual int setBtNrec(const bool enbale);
+ virtual int setBtVgs(const bool support);
+
+ /** ecall */
+ virtual int eCallIvsSwitch(bool enable);
+ virtual int eCallIvsSend() ;
+ virtual int eCallPsapSwitch(bool enable);
+ virtual int eCallPsapSend();
+ virtual int eCallCtrlSeqSwitch(bool enable);
+ virtual int eCallMsd(void *data, uint16_t len);
+ virtual int eCallTxCtrlParam(void *data, uint16_t len);
+
+ virtual int bgsOpen(uint32_t sampleRate);
+ virtual int bgsClose();
+ virtual uint32_t bgsWrite(void *buf, uint32_t bytes);
+
+protected:
+ SpeechModemController();
+
+ inline uint32_t calculateSampleRate(const bool bt_device_on) {
+#if defined(SPH_SR32K)
+ return (bt_device_on == false) ? 32000 : (mBtMode == 0) ? 8000 : 16000;
+#elif defined(SPH_SR48K)
+ return (bt_device_on == false) ? 48000 : (mBtMode == 0) ? 8000 : 16000;
+#else
+ return (bt_device_on == false) ? 16000 : (mBtMode == 0) ? 8000 : 16000;
+#endif
+ }
+
+ SpeechDriverFactory *mSpeechDriverFactory;
+ AudioVolumeInterface *mAudioALSAVolumeController;
+
+ AudioLock mLock;
+ AudioLock mCheckOpenLock;
+ AudioLock mUlMuteLock;
+ AudioLock mDlMuteLock;
+
+ bool mSpeechOn;
+
+ bool mUlMute;
+ bool mDlMute;
+
+ int mBtMode; // BT mode; 0:NB, 1:WB
+ bool mBtNrec; // NR/EC for BT voice call; 0:off, 1:on
+ bool mBtVgs; // VGS support by BT; 0:off, 1:on
+ audio_devices_t mCurrentOutputDevice;
+ audio_devices_t mCurrentInputDevice;
+ BGSPlayBuffer* mBGSPlayBuffer;
+ bool mIsEcallIvsOn;
+ bool mIsEcallPsapOn;
+ bool mIsEcallCtrlSeqOn;
+ unsigned int mVolumeIndex;
+ int mSpkType;
+private:
+ static SpeechModemController *mSpeechModemController; // singleton
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_SPEECH_PHONE_CALL_CONTROLLER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/include/audio_custom_exp.h b/src/multimedia/libspeech_drv/audio_big_sw/os/include/audio_custom_exp.h
new file mode 100644
index 0000000..e76b905
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/include/audio_custom_exp.h
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+/*******************************************************************************
+ *
+ * Filename:
+ * ---------
+ * audio_custom_exp.h
+ *
+ * Project:
+ * --------
+ * ALPS
+ *
+ * Description:
+ * ------------
+ * This file is the header of audio customization related function or definition.
+ *
+ * Author:
+ * -------
+ * ChiPeng
+ *
+***********************************************************************************/
+
+#ifndef AUDIO_CUSTOM_EXP_H
+#define AUDIO_CUSTOM_EXP_H
+
+
+/*********************************************************************************
+**yocto
+***********************************************************************************/
+//#define PROPERTY_VALUE_MAX 256
+#define PATH_MAX 256
+
+/*****************************************************************
+** refine volume
+*****************************************************************/
+#ifdef DEVICE_MAX_VOLUME
+#undef DEVICE_MAX_VOLUME
+#endif
+#define DEVICE_MAX_VOLUME (8)
+#ifdef DEVICE_VOICE_MAX_VOLUME
+#undef DEVICE_VOICE_MAX_VOLUME
+#endif
+#define DEVICE_VOICE_MAX_VOLUME (8)
+#ifdef DEVICE_AMP_MAX_VOLUME
+#undef DEVICE_AMP_MAX_VOLUME
+#endif
+#define DEVICE_AMP_MAX_VOLUME (15)
+#ifdef DEVICE_MIN_VOLUME
+#undef DEVICE_MIN_VOLUME
+#endif
+#define DEVICE_MIN_VOLUME (-4)
+#ifdef DEVICE_VOICE_MIN_VOLUME
+#undef DEVICE_VOICE_MIN_VOLUME
+#endif
+#define DEVICE_VOICE_MIN_VOLUME (-4)
+#ifdef DEVICE_AMP_MIN_VOLUME
+#undef DEVICE_AMP_MIN_VOLUME
+#endif
+#define DEVICE_AMP_MIN_VOLUME (6)
+#ifdef DEVICE_VOLUME_RANGE
+#undef DEVICE_VOLUME_RANGE
+#endif
+#define DEVICE_VOLUME_RANGE (64)
+#ifdef DEVICE_VOLUME_STEP
+#undef DEVICE_VOLUME_STEP
+#endif
+#define DEVICE_VOLUME_STEP (256)
+
+/******************************************************************
+** define Vibration SPK Default Center Freq and RMS
+******************************************************************/
+#ifdef VIBSPK_MV_RMS
+#undef VIBSPK_MV_RMS
+#endif
+#define VIBSPK_MV_RMS (350) //280~560, 70 per step
+#ifdef VIBSPK_DEFAULT_FREQ
+#undef VIBSPK_DEFAULT_FREQ
+#endif
+#define VIBSPK_DEFAULT_FREQ (156) //141~330 Hz
+
+/******************************************************************
+** define using which flag
+******************************************************************/
+//#define USING_CLASSD_AMP // define using which flag
+#ifdef USING_CLASSD_AMP
+#undef USING_CLASSD_AMP
+#endif
+//#define USING_CLASSD_AMP // define using which flag
+//#define EXT_SPK_SUPPORT
+//#define USING_EXTAMP_HP // Headphone output to ExtAMP
+#define USING_EXTAMP_LO // Lineout output to ExtAMP
+
+/******************************************************************
+** define chip delay for NXP
+******************************************************************/
+#ifdef CHIP_DELAY
+#undef CHIP_DELAY
+#endif
+#define CHIP_DELAY (22)
+
+/***************************************************
+* Define phonmic and headset mic mode.
+typedef enum
+{
+ AUDIO_MIC_MODE_ACC = 1,
+ AUDIO_MIC_MODE_DCC = 2,
+ AUDIO_MIC_MODE_DMIC = 3,
+ AUDIO_MIC_MODE_DMIC_LP = 4,
+ AUDIO_MIC_MODE_DCCECMDIFF = 5,
+ AUDIO_MIC_MODE_DCCECMSINGLE = 6,
+} AUDIO_MIC_MODE;
+*****************************************************/
+#ifdef PHONE_MIC_MODE
+#undef PHONE_MIC_MODE
+#endif
+#define PHONE_MIC_MODE (2)
+#ifdef HEADSET_MIC_MODE
+#undef HEADSET_MIC_MODE
+#endif
+#define HEADSET_MIC_MODE (6)
+
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/include/audio_dump_path.h b/src/multimedia/libspeech_drv/audio_big_sw/os/include/audio_dump_path.h
new file mode 100644
index 0000000..3f8ceb5
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/include/audio_dump_path.h
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+/*******************************************************************************
+ *
+ * Filename:
+ * ---------
+ * audio_dump_path.h
+ *
+ * Project:
+ * --------
+ * ALPS
+ *
+ * Description:
+ * ------------
+ * This file is the header of audio dump related function or definition.
+ *
+ * Author:
+ * -------
+ *
+ *
+***********************************************************************************/
+
+#ifndef AUDIO_DUMP_PATH_H
+#define AUDIO_DUMP_PATH_H
+
+
+/*********************************************************************************
+** yocto
+***********************************************************************************/
+#define LOG_PATH_AUDIO_DUMP "/var/log/audio_dump/"
+
+#define LOG_BGS_NAME "/data/vendor/audiohal/audio_dump/BGS"
+#define LOG_BGS_SRC_NAME "/data/vendor/audiohal/audio_dump/BGS_before_Blisrc"
+
+
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/include/speech_drv.h b/src/multimedia/libspeech_drv/audio_big_sw/os/include/speech_drv.h
new file mode 100644
index 0000000..a0ac137
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/include/speech_drv.h
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef _SPEECH_DRV_H_
+#define _SPEECH_DRV_H_
+#include <stdbool.h>
+#include <system/audio.h>
+
+
+#define CLIENT_SOCK_FILE "/tmp/client-sphdrv"
+#define SERVER_SOCK_FILE "/tmp/socket-sphdrv"
+
+//Error code for users
+#define SPH_REQ_SEND_FAIL -200
+#define SPH_BUF_BYTES 2048
+
+enum {
+ SET_SPEECH_ON = 1,
+ CHANGE_SPEECH_ROUTING,
+ ECALL_SPEECH_ON,
+ SET_SPK_TYPE,
+ DL_VOL_IDX,
+ GET_UL_ANA_GAIN,
+ GET_DL_ANA_GAIN,
+ SET_UL_MUTE,
+ SET_DL_MUTE,
+ GET_UL_MUTE,
+ GET_DL_MUTE,
+ IVS_SWITCH,
+ IVS_SEND,
+ PSAP_SWITCH,
+ PSAP_SEND,
+ ECALL_MSD,
+ ECALL_TESTSEQ,
+ ECALL_TESTSEQ_SWITCH,
+ VMLOG_RECORD,
+ PCM_RECORD_ON,
+ PCM_RECORD_OFF,
+ PCM_TYPE,
+ VOICE_RECORD_ON,
+ VOICE_RECORD_OFF,
+ PCM_SAMPLERATE,
+ PCM_CHANNELNUM,
+ BGS_OPEN,
+ BGS_CLOSE,
+ BGS_WRITE,
+ SET_BT_WBS,
+ SET_BT_NREC,
+ SET_BT_VGS,
+};
+
+/*Request Package*/
+typedef struct _SPH_REQ_ {
+ int id;
+ bool speechOn;
+ bool muteOn;
+ int speakerType;
+ unsigned int volumeIdx;
+ bool switchOn;
+ int inputDevice;
+ int outputDevice;
+ uint32_t sampleRate;
+ char dataBuf[SPH_BUF_BYTES];
+ uint32_t dataSize;
+ uint8_t vmConfig;
+ int btWbsOn;
+ bool btNrecOn;
+ bool btVgsOn;
+} SPH_REQ;
+
+typedef struct _SPH_MSG_ {
+ SPH_REQ req;
+ char cmd[64];
+ int result;
+} SPH_MSG;
+
+enum {
+ AUDIO_SPK_INVALID = -1,
+ AUDIO_SPK_INTAMP,
+ AUDIO_SPK_EXTAMP_LO,
+ AUDIO_SPK_EXTAMP_HP,
+ AUDIO_SPK_2_IN_1,
+ AUDIO_SPK_3_IN_1,
+};
+
+
+/* For normal call setting API */
+int speechdrv_set_speech_on(bool enable, int inputDevice, int outputDevice);
+int speechdrv_change_speech_device(int inputDevice, int outputDevice);
+int speechdrv_get_ul_analog_gain();
+int speechdrv_get_dl_analog_gain();
+int speechdrv_set_speaker_type(unsigned int type);
+int speechdrv_set_volume_index(unsigned int index, int outputDevice);
+int speechdrv_set_vm_on(uint8_t config);
+int speechdrv_set_ul_mute(bool enable);
+int speechdrv_set_dl_mute(bool enable);
+int speechdrv_get_ul_mute_status(void);
+int speechdrv_get_dl_mute_status(void);
+int speechdrv_set_bt_wbs(int enable);
+int speechdrv_set_bt_nrec(bool enable);
+int speechdrv_set_bt_vgs(bool support);
+
+/* For eCall API */
+int speechdrv_set_ecall_speech_on(bool enable);
+int speechdrv_set_ivs_switch(bool enable);
+int speechdrv_set_ivs_send(void);
+int speechdrv_set_psap_switch(bool enable);
+int speechdrv_set_psap_send(void);
+int speechdrv_set_ecall_msd(void *buf, uint32_t bytes);
+int speechdrv_set_ecall_testseq_switch(bool enable);
+int speechdrv_set_ecall_testseq(void *buf, uint32_t len);
+
+/* For BGS API */
+int speechdrv_bgs_open(uint32_t sampleRate);
+int speechdrv_bgs_close();
+int speechdrv_bgs_write(void *buf, uint32_t bytes);
+
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/linux/fm.h b/src/multimedia/libspeech_drv/audio_big_sw/os/linux/fm.h
new file mode 100644
index 0000000..d679e8b
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/linux/fm.h
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef YOCTO_FM_H
+#define YOCTO_FM_H
+
+typedef signed int fm_s32;
+
+typedef struct fm_i2s_info
+{
+ fm_s32 status; /*0:FM_I2S_ON, 1:FM_I2S_OFF,2:error*/
+ fm_s32 mode; /*0:FM_I2S_MASTER, 1:FM_I2S_SLAVE,2:error*/
+ fm_s32 rate; /*0:FM_I2S_32K:32000,1:FM_I2S_44K:44100,2:FM_I2S_48K:48000,3:error*/
+} fm_i2s_info_t;
+
+typedef enum
+{
+ FM_AUD_ANALOG = 0,
+ FM_AUD_I2S = 1,
+ FM_AUD_MRGIF = 2,
+ FM_AUD_ERR
+}fm_audio_path_e;
+
+typedef enum
+{
+ FM_I2S_PAD_CONN = 0, //sco fm chip: e.g.6627
+ FM_I2S_PAD_IO = 1, //combo fm chip: e.g.6628
+ FM_I2S_PAD_ERR
+}fm_i2s_pad_sel_e;
+
+typedef struct fm_audio_info
+{
+ fm_audio_path_e aud_path;
+ fm_i2s_info_t i2s_info;
+ fm_i2s_pad_sel_e i2s_pad;
+} fm_audio_info_t;
+
+#endif /* end of YOCTO_FM_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/system/audio-base-utils.h b/src/multimedia/libspeech_drv/audio_big_sw/os/system/audio-base-utils.h
new file mode 100644
index 0000000..5d44423
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/system/audio-base-utils.h
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+ * Copyright (C) 2018 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 YOCTO_AUDIO_BASE_UTILS_H
+#define YOCTO_AUDIO_BASE_UTILS_H
+
+#include "audio-base.h"
+
+/** Define helper values to iterate over enum, extend them or checking value validity.
+ * Those values are compatible with the O corresponding enum values.
+ * They are not macro like similar values in audio.h to avoid conflicting
+ * with the libhardware_legacy audio.h.
+ */
+enum {
+ /** Number of audio stream available to vendors. */
+ AUDIO_STREAM_PUBLIC_CNT = AUDIO_STREAM_ACCESSIBILITY + 1,
+
+#ifndef AUDIO_NO_SYSTEM_DECLARATIONS
+ /** Total number of stream handled by the policy*/
+ AUDIO_STREAM_FOR_POLICY_CNT= AUDIO_STREAM_REROUTING + 1,
+#endif
+
+ /** Total number of stream. */
+ AUDIO_STREAM_CNT = AUDIO_STREAM_PATCH + 1,
+
+ AUDIO_SOURCE_MAX = AUDIO_SOURCE_UNPROCESSED,
+ AUDIO_SOURCE_CNT = AUDIO_SOURCE_MAX + 1,
+
+ AUDIO_MODE_MAX = AUDIO_MODE_IN_COMMUNICATION,
+ AUDIO_MODE_CNT = AUDIO_MODE_MAX + 1,
+
+ /** For retrocompatibility AUDIO_MODE_* and AUDIO_STREAM_* must be signed. */
+ AUDIO_DETAIL_NEGATIVE_VALUE = -1,
+};
+
+enum {
+ AUDIO_CHANNEL_OUT_ALL = AUDIO_CHANNEL_OUT_FRONT_LEFT |
+ AUDIO_CHANNEL_OUT_FRONT_RIGHT |
+ AUDIO_CHANNEL_OUT_FRONT_CENTER |
+ AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
+ AUDIO_CHANNEL_OUT_BACK_LEFT |
+ AUDIO_CHANNEL_OUT_BACK_RIGHT |
+ AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER |
+ AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER |
+ AUDIO_CHANNEL_OUT_BACK_CENTER |
+ AUDIO_CHANNEL_OUT_SIDE_LEFT |
+ AUDIO_CHANNEL_OUT_SIDE_RIGHT |
+ AUDIO_CHANNEL_OUT_TOP_CENTER |
+ AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT |
+ AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER |
+ AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT |
+ AUDIO_CHANNEL_OUT_TOP_BACK_LEFT |
+ AUDIO_CHANNEL_OUT_TOP_BACK_CENTER |
+ AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT |
+ AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT |
+ AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT,
+
+ AUDIO_CHANNEL_IN_ALL = AUDIO_CHANNEL_IN_LEFT |
+ AUDIO_CHANNEL_IN_RIGHT |
+ AUDIO_CHANNEL_IN_FRONT |
+ AUDIO_CHANNEL_IN_BACK|
+ AUDIO_CHANNEL_IN_LEFT_PROCESSED |
+ AUDIO_CHANNEL_IN_RIGHT_PROCESSED |
+ AUDIO_CHANNEL_IN_FRONT_PROCESSED |
+ AUDIO_CHANNEL_IN_BACK_PROCESSED|
+ AUDIO_CHANNEL_IN_PRESSURE |
+ AUDIO_CHANNEL_IN_X_AXIS |
+ AUDIO_CHANNEL_IN_Y_AXIS |
+ AUDIO_CHANNEL_IN_Z_AXIS |
+ AUDIO_CHANNEL_IN_VOICE_UPLINK |
+ AUDIO_CHANNEL_IN_VOICE_DNLINK |
+ AUDIO_CHANNEL_IN_BACK_LEFT |
+ AUDIO_CHANNEL_IN_BACK_RIGHT |
+ AUDIO_CHANNEL_IN_CENTER |
+ AUDIO_CHANNEL_IN_LOW_FREQUENCY |
+ AUDIO_CHANNEL_IN_TOP_LEFT |
+ AUDIO_CHANNEL_IN_TOP_RIGHT,
+
+ AUDIO_DEVICE_OUT_ALL = AUDIO_DEVICE_OUT_EARPIECE |
+ AUDIO_DEVICE_OUT_SPEAKER |
+ AUDIO_DEVICE_OUT_WIRED_HEADSET |
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO |
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER |
+ AUDIO_DEVICE_OUT_HDMI |
+ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
+ AUDIO_DEVICE_OUT_USB_ACCESSORY |
+ AUDIO_DEVICE_OUT_USB_DEVICE |
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX |
+ AUDIO_DEVICE_OUT_TELEPHONY_TX |
+ AUDIO_DEVICE_OUT_LINE |
+ AUDIO_DEVICE_OUT_HDMI_ARC |
+ AUDIO_DEVICE_OUT_SPDIF |
+ AUDIO_DEVICE_OUT_FM |
+ AUDIO_DEVICE_OUT_AUX_LINE |
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE |
+ AUDIO_DEVICE_OUT_IP |
+ AUDIO_DEVICE_OUT_BUS |
+ AUDIO_DEVICE_OUT_PROXY |
+ AUDIO_DEVICE_OUT_USB_HEADSET |
+ AUDIO_DEVICE_OUT_HEARING_AID |
+ AUDIO_DEVICE_OUT_ECHO_CANCELLER |
+ AUDIO_DEVICE_OUT_DEFAULT,
+
+ AUDIO_DEVICE_OUT_ALL_A2DP = AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,
+
+ AUDIO_DEVICE_OUT_ALL_SCO = AUDIO_DEVICE_OUT_BLUETOOTH_SCO |
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT,
+
+ AUDIO_DEVICE_OUT_ALL_USB = AUDIO_DEVICE_OUT_USB_ACCESSORY |
+ AUDIO_DEVICE_OUT_USB_DEVICE |
+ AUDIO_DEVICE_OUT_USB_HEADSET,
+
+ AUDIO_DEVICE_IN_ALL = AUDIO_DEVICE_IN_COMMUNICATION |
+ AUDIO_DEVICE_IN_AMBIENT |
+ AUDIO_DEVICE_IN_BUILTIN_MIC |
+ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET |
+ AUDIO_DEVICE_IN_WIRED_HEADSET |
+ AUDIO_DEVICE_IN_HDMI |
+ AUDIO_DEVICE_IN_TELEPHONY_RX |
+ AUDIO_DEVICE_IN_BACK_MIC |
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX |
+ AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET |
+ AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET |
+ AUDIO_DEVICE_IN_USB_ACCESSORY |
+ AUDIO_DEVICE_IN_USB_DEVICE |
+ AUDIO_DEVICE_IN_FM_TUNER |
+ AUDIO_DEVICE_IN_TV_TUNER |
+ AUDIO_DEVICE_IN_LINE |
+ AUDIO_DEVICE_IN_SPDIF |
+ AUDIO_DEVICE_IN_BLUETOOTH_A2DP |
+ AUDIO_DEVICE_IN_LOOPBACK |
+ AUDIO_DEVICE_IN_IP |
+ AUDIO_DEVICE_IN_BUS |
+ AUDIO_DEVICE_IN_PROXY |
+ AUDIO_DEVICE_IN_USB_HEADSET |
+ AUDIO_DEVICE_IN_BLUETOOTH_BLE |
+ AUDIO_DEVICE_IN_DEFAULT,
+
+ AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
+
+ AUDIO_DEVICE_IN_ALL_USB = AUDIO_DEVICE_IN_USB_ACCESSORY |
+ AUDIO_DEVICE_IN_USB_DEVICE |
+ AUDIO_DEVICE_IN_USB_HEADSET,
+
+ AUDIO_USAGE_MAX = AUDIO_USAGE_ASSISTANT,
+ AUDIO_USAGE_CNT = AUDIO_USAGE_ASSISTANT + 1,
+
+ AUDIO_PORT_CONFIG_ALL = AUDIO_PORT_CONFIG_SAMPLE_RATE |
+ AUDIO_PORT_CONFIG_CHANNEL_MASK |
+ AUDIO_PORT_CONFIG_FORMAT |
+ AUDIO_PORT_CONFIG_GAIN,
+}; // enum
+
+
+#endif // YOCTO_AUDIO_BASE_UTILS_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/system/audio-base.h b/src/multimedia/libspeech_drv/audio_big_sw/os/system/audio-base.h
new file mode 100644
index 0000000..7121af6
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/system/audio-base.h
@@ -0,0 +1,451 @@
+// SPDX-License-Identifier: MediaTekProprietary
+// This file is autogenerated by hidl-gen
+// then manualy edited for retrocompatiblity
+// Source: android.hardware.audio.common@4.0
+// Root: android.hardware:hardware/interfaces
+
+#ifndef YOCTO_AUDIO_BASE_H
+#define YOCTO_AUDIO_BASE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ AUDIO_IO_HANDLE_NONE = 0,
+ AUDIO_MODULE_HANDLE_NONE = 0,
+ AUDIO_PORT_HANDLE_NONE = 0,
+ AUDIO_PATCH_HANDLE_NONE = 0,
+};
+
+typedef enum {
+ AUDIO_STREAM_DEFAULT = -1, // (-1)
+ AUDIO_STREAM_MIN = 0,
+ AUDIO_STREAM_VOICE_CALL = 0,
+ AUDIO_STREAM_SYSTEM = 1,
+ AUDIO_STREAM_RING = 2,
+ AUDIO_STREAM_MUSIC = 3,
+ AUDIO_STREAM_ALARM = 4,
+ AUDIO_STREAM_NOTIFICATION = 5,
+ AUDIO_STREAM_BLUETOOTH_SCO = 6,
+ AUDIO_STREAM_ENFORCED_AUDIBLE = 7,
+ AUDIO_STREAM_DTMF = 8,
+ AUDIO_STREAM_TTS = 9,
+ AUDIO_STREAM_ACCESSIBILITY = 10,
+#ifndef AUDIO_NO_SYSTEM_DECLARATIONS
+ /** For dynamic policy output mixes. Only used by the audio policy */
+ AUDIO_STREAM_REROUTING = 11,
+ /** For audio flinger tracks volume. Only used by the audioflinger */
+ AUDIO_STREAM_PATCH = 12,
+#endif // AUDIO_NO_SYSTEM_DECLARATIONS
+} audio_stream_type_t;
+
+typedef enum {
+ AUDIO_SOURCE_DEFAULT = 0,
+ AUDIO_SOURCE_MIC = 1,
+ AUDIO_SOURCE_VOICE_UPLINK = 2,
+ AUDIO_SOURCE_VOICE_DOWNLINK = 3,
+ AUDIO_SOURCE_VOICE_CALL = 4,
+ AUDIO_SOURCE_CAMCORDER = 5,
+ AUDIO_SOURCE_VOICE_RECOGNITION = 6,
+ AUDIO_SOURCE_VOICE_COMMUNICATION = 7,
+ AUDIO_SOURCE_REMOTE_SUBMIX = 8,
+ AUDIO_SOURCE_UNPROCESSED = 9,
+ AUDIO_SOURCE_FM_TUNER = 1998,
+#ifndef AUDIO_NO_SYSTEM_DECLARATIONS
+ /**
+ * A low-priority, preemptible audio source for for background software
+ * hotword detection. Same tuning as VOICE_RECOGNITION.
+ * Used only internally by the framework.
+ */
+ AUDIO_SOURCE_HOTWORD = 1999,
+#endif // AUDIO_NO_SYSTEM_DECLARATIONS
+} audio_source_t;
+
+typedef enum {
+ AUDIO_SESSION_OUTPUT_STAGE = -1, // (-1)
+ AUDIO_SESSION_OUTPUT_MIX = 0,
+ AUDIO_SESSION_ALLOCATE = 0,
+ AUDIO_SESSION_NONE = 0,
+} audio_session_t;
+
+typedef enum {
+ AUDIO_FORMAT_INVALID = 0xFFFFFFFFu,
+ AUDIO_FORMAT_DEFAULT = 0,
+ AUDIO_FORMAT_PCM = 0x00000000u,
+ AUDIO_FORMAT_MP3 = 0x01000000u,
+ AUDIO_FORMAT_AMR_NB = 0x02000000u,
+ AUDIO_FORMAT_AMR_WB = 0x03000000u,
+ AUDIO_FORMAT_AAC = 0x04000000u,
+ AUDIO_FORMAT_HE_AAC_V1 = 0x05000000u,
+ AUDIO_FORMAT_HE_AAC_V2 = 0x06000000u,
+ AUDIO_FORMAT_VORBIS = 0x07000000u,
+ AUDIO_FORMAT_OPUS = 0x08000000u,
+ AUDIO_FORMAT_AC3 = 0x09000000u,
+ AUDIO_FORMAT_E_AC3 = 0x0A000000u,
+ AUDIO_FORMAT_DTS = 0x0B000000u,
+ AUDIO_FORMAT_DTS_HD = 0x0C000000u,
+ AUDIO_FORMAT_IEC61937 = 0x0D000000u,
+ AUDIO_FORMAT_DOLBY_TRUEHD = 0x0E000000u,
+ AUDIO_FORMAT_EVRC = 0x10000000u,
+ AUDIO_FORMAT_EVRCB = 0x11000000u,
+ AUDIO_FORMAT_EVRCWB = 0x12000000u,
+ AUDIO_FORMAT_EVRCNW = 0x13000000u,
+ AUDIO_FORMAT_AAC_ADIF = 0x14000000u,
+ AUDIO_FORMAT_WMA = 0x15000000u,
+ AUDIO_FORMAT_WMA_PRO = 0x16000000u,
+ AUDIO_FORMAT_AMR_WB_PLUS = 0x17000000u,
+ AUDIO_FORMAT_MP2 = 0x18000000u,
+ AUDIO_FORMAT_QCELP = 0x19000000u,
+ AUDIO_FORMAT_DSD = 0x1A000000u,
+ AUDIO_FORMAT_FLAC = 0x1B000000u,
+ AUDIO_FORMAT_ALAC = 0x1C000000u,
+ AUDIO_FORMAT_APE = 0x1D000000u,
+ AUDIO_FORMAT_AAC_ADTS = 0x1E000000u,
+ AUDIO_FORMAT_SBC = 0x1F000000u,
+ AUDIO_FORMAT_APTX = 0x20000000u,
+ AUDIO_FORMAT_APTX_HD = 0x21000000u,
+ AUDIO_FORMAT_AC4 = 0x22000000u,
+ AUDIO_FORMAT_LDAC = 0x23000000u,
+ AUDIO_FORMAT_MAT = 0x24000000u,
+ AUDIO_FORMAT_MAIN_MASK = 0xFF000000u,
+ AUDIO_FORMAT_SUB_MASK = 0x00FFFFFFu,
+
+ /* Subformats */
+ AUDIO_FORMAT_PCM_SUB_16_BIT = 0x1u,
+ AUDIO_FORMAT_PCM_SUB_8_BIT = 0x2u,
+ AUDIO_FORMAT_PCM_SUB_32_BIT = 0x3u,
+ AUDIO_FORMAT_PCM_SUB_8_24_BIT = 0x4u,
+ AUDIO_FORMAT_PCM_SUB_FLOAT = 0x5u,
+ AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED = 0x6u,
+
+ AUDIO_FORMAT_MP3_SUB_NONE = 0x0u,
+
+ AUDIO_FORMAT_AMR_SUB_NONE = 0x0u,
+
+ AUDIO_FORMAT_AAC_SUB_MAIN = 0x1u,
+ AUDIO_FORMAT_AAC_SUB_LC = 0x2u,
+ AUDIO_FORMAT_AAC_SUB_SSR = 0x4u,
+ AUDIO_FORMAT_AAC_SUB_LTP = 0x8u,
+ AUDIO_FORMAT_AAC_SUB_HE_V1 = 0x10u,
+ AUDIO_FORMAT_AAC_SUB_SCALABLE = 0x20u,
+ AUDIO_FORMAT_AAC_SUB_ERLC = 0x40u,
+ AUDIO_FORMAT_AAC_SUB_LD = 0x80u,
+ AUDIO_FORMAT_AAC_SUB_HE_V2 = 0x100u,
+ AUDIO_FORMAT_AAC_SUB_ELD = 0x200u,
+ AUDIO_FORMAT_AAC_SUB_XHE = 0x300u,
+
+ AUDIO_FORMAT_VORBIS_SUB_NONE = 0x0u,
+
+ AUDIO_FORMAT_E_AC3_SUB_JOC = 0x1u,
+
+ AUDIO_FORMAT_MAT_SUB_1_0 = 0x1u,
+ AUDIO_FORMAT_MAT_SUB_2_0 = 0x2u,
+ AUDIO_FORMAT_MAT_SUB_2_1 = 0x3u,
+
+ /* Aliases */
+ AUDIO_FORMAT_PCM_16_BIT = 0x1u, // (PCM | PCM_SUB_16_BIT)
+ AUDIO_FORMAT_PCM_8_BIT = 0x2u, // (PCM | PCM_SUB_8_BIT)
+ AUDIO_FORMAT_PCM_32_BIT = 0x3u, // (PCM | PCM_SUB_32_BIT)
+ AUDIO_FORMAT_PCM_8_24_BIT = 0x4u, // (PCM | PCM_SUB_8_24_BIT)
+ AUDIO_FORMAT_PCM_FLOAT = 0x5u, // (PCM | PCM_SUB_FLOAT)
+ AUDIO_FORMAT_PCM_24_BIT_PACKED = 0x6u, // (PCM | PCM_SUB_24_BIT_PACKED)
+ AUDIO_FORMAT_AAC_MAIN = 0x4000001u, // (AAC | AAC_SUB_MAIN)
+ AUDIO_FORMAT_AAC_LC = 0x4000002u, // (AAC | AAC_SUB_LC)
+ AUDIO_FORMAT_AAC_SSR = 0x4000004u, // (AAC | AAC_SUB_SSR)
+ AUDIO_FORMAT_AAC_LTP = 0x4000008u, // (AAC | AAC_SUB_LTP)
+ AUDIO_FORMAT_AAC_HE_V1 = 0x4000010u, // (AAC | AAC_SUB_HE_V1)
+ AUDIO_FORMAT_AAC_SCALABLE = 0x4000020u, // (AAC | AAC_SUB_SCALABLE)
+ AUDIO_FORMAT_AAC_ERLC = 0x4000040u, // (AAC | AAC_SUB_ERLC)
+ AUDIO_FORMAT_AAC_LD = 0x4000080u, // (AAC | AAC_SUB_LD)
+ AUDIO_FORMAT_AAC_HE_V2 = 0x4000100u, // (AAC | AAC_SUB_HE_V2)
+ AUDIO_FORMAT_AAC_ELD = 0x4000200u, // (AAC | AAC_SUB_ELD)
+ AUDIO_FORMAT_AAC_XHE = 0x4000300u, // (AAC | AAC_SUB_XHE)
+ AUDIO_FORMAT_AAC_ADTS_MAIN = 0x1e000001u, // (AAC_ADTS | AAC_SUB_MAIN)
+ AUDIO_FORMAT_AAC_ADTS_LC = 0x1e000002u, // (AAC_ADTS | AAC_SUB_LC)
+ AUDIO_FORMAT_AAC_ADTS_SSR = 0x1e000004u, // (AAC_ADTS | AAC_SUB_SSR)
+ AUDIO_FORMAT_AAC_ADTS_LTP = 0x1e000008u, // (AAC_ADTS | AAC_SUB_LTP)
+ AUDIO_FORMAT_AAC_ADTS_HE_V1 = 0x1e000010u, // (AAC_ADTS | AAC_SUB_HE_V1)
+ AUDIO_FORMAT_AAC_ADTS_SCALABLE = 0x1e000020u, // (AAC_ADTS | AAC_SUB_SCALABLE)
+ AUDIO_FORMAT_AAC_ADTS_ERLC = 0x1e000040u, // (AAC_ADTS | AAC_SUB_ERLC)
+ AUDIO_FORMAT_AAC_ADTS_LD = 0x1e000080u, // (AAC_ADTS | AAC_SUB_LD)
+ AUDIO_FORMAT_AAC_ADTS_HE_V2 = 0x1e000100u, // (AAC_ADTS | AAC_SUB_HE_V2)
+ AUDIO_FORMAT_AAC_ADTS_ELD = 0x1e000200u, // (AAC_ADTS | AAC_SUB_ELD)
+ AUDIO_FORMAT_AAC_ADTS_XHE = 0x1e000300u, // (AAC_ADTS | AAC_SUB_XHE)
+ AUDIO_FORMAT_E_AC3_JOC = 0xA000001u, // (E_AC3 | E_AC3_SUB_JOC)
+ AUDIO_FORMAT_MAT_1_0 = 0x24000001u, // (MAT | MAT_SUB_1_0)
+ AUDIO_FORMAT_MAT_2_0 = 0x24000002u, // (MAT | MAT_SUB_2_0)
+ AUDIO_FORMAT_MAT_2_1 = 0x24000003u, // (MAT | MAT_SUB_2_1)
+} audio_format_t;
+
+enum {
+ FCC_2 = 2,
+ FCC_8 = 8,
+};
+
+enum {
+ AUDIO_CHANNEL_REPRESENTATION_POSITION = 0x0u,
+ AUDIO_CHANNEL_REPRESENTATION_INDEX = 0x2u,
+ AUDIO_CHANNEL_NONE = 0x0u,
+ AUDIO_CHANNEL_INVALID = 0xC0000000u,
+
+ AUDIO_CHANNEL_OUT_FRONT_LEFT = 0x1u,
+ AUDIO_CHANNEL_OUT_FRONT_RIGHT = 0x2u,
+ AUDIO_CHANNEL_OUT_FRONT_CENTER = 0x4u,
+ AUDIO_CHANNEL_OUT_LOW_FREQUENCY = 0x8u,
+ AUDIO_CHANNEL_OUT_BACK_LEFT = 0x10u,
+ AUDIO_CHANNEL_OUT_BACK_RIGHT = 0x20u,
+ AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x40u,
+ AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80u,
+ AUDIO_CHANNEL_OUT_BACK_CENTER = 0x100u,
+ AUDIO_CHANNEL_OUT_SIDE_LEFT = 0x200u,
+ AUDIO_CHANNEL_OUT_SIDE_RIGHT = 0x400u,
+ AUDIO_CHANNEL_OUT_TOP_CENTER = 0x800u,
+ AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT = 0x1000u,
+ AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER = 0x2000u,
+ AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT = 0x4000u,
+ AUDIO_CHANNEL_OUT_TOP_BACK_LEFT = 0x8000u,
+ AUDIO_CHANNEL_OUT_TOP_BACK_CENTER = 0x10000u,
+ AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT = 0x20000u,
+ AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT = 0x40000u,
+ AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT = 0x80000u,
+ AUDIO_CHANNEL_OUT_MONO = 0x1u, // OUT_FRONT_LEFT
+ AUDIO_CHANNEL_OUT_STEREO = 0x3u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT
+ AUDIO_CHANNEL_OUT_2POINT1 = 0xBu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_LOW_FREQUENCY
+ AUDIO_CHANNEL_OUT_2POINT0POINT2 = 0xC0003u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT
+ AUDIO_CHANNEL_OUT_2POINT1POINT2 = 0xC000Bu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT | OUT_LOW_FREQUENCY
+ AUDIO_CHANNEL_OUT_3POINT0POINT2 = 0xC0007u, // OUT_FRONT_LEFT | OUT_FRONT_CENTER | OUT_FRONT_RIGHT | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT
+ AUDIO_CHANNEL_OUT_3POINT1POINT2 = 0xC000Fu, // OUT_FRONT_LEFT | OUT_FRONT_CENTER | OUT_FRONT_RIGHT | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT | OUT_LOW_FREQUENCY
+ AUDIO_CHANNEL_OUT_QUAD = 0x33u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_BACK_LEFT | OUT_BACK_RIGHT
+ AUDIO_CHANNEL_OUT_QUAD_BACK = 0x33u, // OUT_QUAD
+ AUDIO_CHANNEL_OUT_QUAD_SIDE = 0x603u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_SIDE_LEFT | OUT_SIDE_RIGHT
+ AUDIO_CHANNEL_OUT_SURROUND = 0x107u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_BACK_CENTER
+ AUDIO_CHANNEL_OUT_PENTA = 0x37u, // OUT_QUAD | OUT_FRONT_CENTER
+ AUDIO_CHANNEL_OUT_5POINT1 = 0x3Fu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT
+ AUDIO_CHANNEL_OUT_5POINT1_BACK = 0x3Fu, // OUT_5POINT1
+ AUDIO_CHANNEL_OUT_5POINT1_SIDE = 0x60Fu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_SIDE_LEFT | OUT_SIDE_RIGHT
+ AUDIO_CHANNEL_OUT_5POINT1POINT2 = 0xC003Fu, // OUT_5POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT
+ AUDIO_CHANNEL_OUT_5POINT1POINT4 = 0x2D03Fu, // OUT_5POINT1 | OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT | OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT
+ AUDIO_CHANNEL_OUT_6POINT1 = 0x13Fu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT | OUT_BACK_CENTER
+ AUDIO_CHANNEL_OUT_7POINT1 = 0x63Fu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT | OUT_SIDE_LEFT | OUT_SIDE_RIGHT
+ AUDIO_CHANNEL_OUT_7POINT1POINT2 = 0xC063Fu, // OUT_7POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT
+ AUDIO_CHANNEL_OUT_7POINT1POINT4 = 0x2D63Fu, // OUT_7POINT1 | OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT | OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT
+
+ AUDIO_CHANNEL_IN_LEFT = 0x4u,
+ AUDIO_CHANNEL_IN_RIGHT = 0x8u,
+ AUDIO_CHANNEL_IN_FRONT = 0x10u,
+ AUDIO_CHANNEL_IN_BACK = 0x20u,
+ AUDIO_CHANNEL_IN_LEFT_PROCESSED = 0x40u,
+ AUDIO_CHANNEL_IN_RIGHT_PROCESSED = 0x80u,
+ AUDIO_CHANNEL_IN_FRONT_PROCESSED = 0x100u,
+ AUDIO_CHANNEL_IN_BACK_PROCESSED = 0x200u,
+ AUDIO_CHANNEL_IN_PRESSURE = 0x400u,
+ AUDIO_CHANNEL_IN_X_AXIS = 0x800u,
+ AUDIO_CHANNEL_IN_Y_AXIS = 0x1000u,
+ AUDIO_CHANNEL_IN_Z_AXIS = 0x2000u,
+ AUDIO_CHANNEL_IN_BACK_LEFT = 0x10000u,
+ AUDIO_CHANNEL_IN_BACK_RIGHT = 0x20000u,
+ AUDIO_CHANNEL_IN_CENTER = 0x40000u,
+ AUDIO_CHANNEL_IN_LOW_FREQUENCY = 0x100000u,
+ AUDIO_CHANNEL_IN_TOP_LEFT = 0x200000u,
+ AUDIO_CHANNEL_IN_TOP_RIGHT = 0x400000u,
+ AUDIO_CHANNEL_IN_VOICE_UPLINK = 0x4000u,
+ AUDIO_CHANNEL_IN_VOICE_DNLINK = 0x8000u,
+ AUDIO_CHANNEL_IN_MONO = 0x10u, // IN_FRONT
+ AUDIO_CHANNEL_IN_STEREO = 0xCu, // IN_LEFT | IN_RIGHT
+ AUDIO_CHANNEL_IN_FRONT_BACK = 0x30u, // IN_FRONT | IN_BACK
+ AUDIO_CHANNEL_IN_6 = 0xFCu, // IN_LEFT | IN_RIGHT | IN_FRONT | IN_BACK | IN_LEFT_PROCESSED | IN_RIGHT_PROCESSED
+ AUDIO_CHANNEL_IN_2POINT0POINT2 = 0x60000Cu, // IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT
+ AUDIO_CHANNEL_IN_2POINT1POINT2 = 0x70000Cu, // IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT | IN_LOW_FREQUENCY
+ AUDIO_CHANNEL_IN_3POINT0POINT2 = 0x64000Cu, // IN_LEFT | IN_CENTER | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT
+ AUDIO_CHANNEL_IN_3POINT1POINT2 = 0x74000Cu, // IN_LEFT | IN_CENTER | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT | IN_LOW_FREQUENCY
+ AUDIO_CHANNEL_IN_5POINT1 = 0x17000Cu, // IN_LEFT | IN_CENTER | IN_RIGHT | IN_BACK_LEFT | IN_BACK_RIGHT | IN_LOW_FREQUENCY
+ AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO = 0x4010u, // IN_VOICE_UPLINK | IN_MONO
+ AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO = 0x8010u, // IN_VOICE_DNLINK | IN_MONO
+ AUDIO_CHANNEL_IN_VOICE_CALL_MONO = 0xC010u, // IN_VOICE_UPLINK_MONO | IN_VOICE_DNLINK_MONO
+
+ AUDIO_CHANNEL_COUNT_MAX = 30u,
+ AUDIO_CHANNEL_INDEX_HDR = 0x80000000u, // REPRESENTATION_INDEX << COUNT_MAX
+ AUDIO_CHANNEL_INDEX_MASK_1 = 0x80000001u, // INDEX_HDR | (1 << 1) - 1
+ AUDIO_CHANNEL_INDEX_MASK_2 = 0x80000003u, // INDEX_HDR | (1 << 2) - 1
+ AUDIO_CHANNEL_INDEX_MASK_3 = 0x80000007u, // INDEX_HDR | (1 << 3) - 1
+ AUDIO_CHANNEL_INDEX_MASK_4 = 0x8000000Fu, // INDEX_HDR | (1 << 4) - 1
+ AUDIO_CHANNEL_INDEX_MASK_5 = 0x8000001Fu, // INDEX_HDR | (1 << 5) - 1
+ AUDIO_CHANNEL_INDEX_MASK_6 = 0x8000003Fu, // INDEX_HDR | (1 << 6) - 1
+ AUDIO_CHANNEL_INDEX_MASK_7 = 0x8000007Fu, // INDEX_HDR | (1 << 7) - 1
+ AUDIO_CHANNEL_INDEX_MASK_8 = 0x800000FFu, // INDEX_HDR | (1 << 8) - 1
+};
+
+typedef enum {
+#ifndef AUDIO_NO_SYSTEM_DECLARATIONS
+ AUDIO_MODE_INVALID = -2, // (-2)
+ AUDIO_MODE_CURRENT = -1, // (-1)
+#endif // AUDIO_NO_SYSTEM_DECLARATIONS
+ AUDIO_MODE_NORMAL = 0,
+ AUDIO_MODE_RINGTONE = 1,
+ AUDIO_MODE_IN_CALL = 2,
+ AUDIO_MODE_IN_COMMUNICATION = 3,
+} audio_mode_t;
+
+enum {
+ AUDIO_DEVICE_NONE = 0x0u,
+ AUDIO_DEVICE_BIT_IN = 0x80000000u,
+ AUDIO_DEVICE_BIT_DEFAULT = 0x40000000u,
+
+ AUDIO_DEVICE_OUT_EARPIECE = 0x1u,
+ AUDIO_DEVICE_OUT_SPEAKER = 0x2u,
+ AUDIO_DEVICE_OUT_WIRED_HEADSET = 0x4u,
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE = 0x8u,
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO = 0x10u,
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20u,
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40u,
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP = 0x80u,
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100u,
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200u,
+ AUDIO_DEVICE_OUT_AUX_DIGITAL = 0x400u,
+ AUDIO_DEVICE_OUT_HDMI = 0x400u, // OUT_AUX_DIGITAL
+ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800u,
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000u,
+ AUDIO_DEVICE_OUT_USB_ACCESSORY = 0x2000u,
+ AUDIO_DEVICE_OUT_USB_DEVICE = 0x4000u,
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX = 0x8000u,
+ AUDIO_DEVICE_OUT_TELEPHONY_TX = 0x10000u,
+ AUDIO_DEVICE_OUT_LINE = 0x20000u,
+ AUDIO_DEVICE_OUT_HDMI_ARC = 0x40000u,
+ AUDIO_DEVICE_OUT_SPDIF = 0x80000u,
+ AUDIO_DEVICE_OUT_FM = 0x100000u,
+ AUDIO_DEVICE_OUT_AUX_LINE = 0x200000u,
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE = 0x400000u,
+ AUDIO_DEVICE_OUT_IP = 0x800000u,
+ AUDIO_DEVICE_OUT_BUS = 0x1000000u,
+ AUDIO_DEVICE_OUT_PROXY = 0x2000000u,
+ AUDIO_DEVICE_OUT_USB_HEADSET = 0x4000000u,
+ AUDIO_DEVICE_OUT_HEARING_AID = 0x8000000u,
+ AUDIO_DEVICE_OUT_ECHO_CANCELLER = 0x10000000u,
+ AUDIO_DEVICE_OUT_DEFAULT = 0x40000000u, // BIT_DEFAULT
+
+ AUDIO_DEVICE_IN_COMMUNICATION = 0x80000001u, // BIT_IN | 0x1
+ AUDIO_DEVICE_IN_AMBIENT = 0x80000002u, // BIT_IN | 0x2
+ AUDIO_DEVICE_IN_BUILTIN_MIC = 0x80000004u, // BIT_IN | 0x4
+ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000008u, // BIT_IN | 0x8
+ AUDIO_DEVICE_IN_WIRED_HEADSET = 0x80000010u, // BIT_IN | 0x10
+ AUDIO_DEVICE_IN_AUX_DIGITAL = 0x80000020u, // BIT_IN | 0x20
+ AUDIO_DEVICE_IN_HDMI = 0x80000020u, // IN_AUX_DIGITAL
+ AUDIO_DEVICE_IN_VOICE_CALL = 0x80000040u, // BIT_IN | 0x40
+ AUDIO_DEVICE_IN_TELEPHONY_RX = 0x80000040u, // IN_VOICE_CALL
+ AUDIO_DEVICE_IN_BACK_MIC = 0x80000080u, // BIT_IN | 0x80
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX = 0x80000100u, // BIT_IN | 0x100
+ AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET = 0x80000200u, // BIT_IN | 0x200
+ AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET = 0x80000400u, // BIT_IN | 0x400
+ AUDIO_DEVICE_IN_USB_ACCESSORY = 0x80000800u, // BIT_IN | 0x800
+ AUDIO_DEVICE_IN_USB_DEVICE = 0x80001000u, // BIT_IN | 0x1000
+ AUDIO_DEVICE_IN_FM_TUNER = 0x80002000u, // BIT_IN | 0x2000
+ AUDIO_DEVICE_IN_TV_TUNER = 0x80004000u, // BIT_IN | 0x4000
+ AUDIO_DEVICE_IN_LINE = 0x80008000u, // BIT_IN | 0x8000
+ AUDIO_DEVICE_IN_SPDIF = 0x80010000u, // BIT_IN | 0x10000
+ AUDIO_DEVICE_IN_BLUETOOTH_A2DP = 0x80020000u, // BIT_IN | 0x20000
+ AUDIO_DEVICE_IN_LOOPBACK = 0x80040000u, // BIT_IN | 0x40000
+ AUDIO_DEVICE_IN_IP = 0x80080000u, // BIT_IN | 0x80000
+ AUDIO_DEVICE_IN_BUS = 0x80100000u, // BIT_IN | 0x100000
+ AUDIO_DEVICE_IN_PROXY = 0x81000000u, // BIT_IN | 0x1000000
+ AUDIO_DEVICE_IN_USB_HEADSET = 0x82000000u, // BIT_IN | 0x2000000
+ AUDIO_DEVICE_IN_BLUETOOTH_BLE = 0x84000000u, // BIT_IN | 0x4000000
+ AUDIO_DEVICE_IN_DEFAULT = 0xC0000000u, // BIT_IN | BIT_DEFAULT
+};
+
+typedef enum {
+ AUDIO_OUTPUT_FLAG_NONE = 0x0,
+ AUDIO_OUTPUT_FLAG_DIRECT = 0x1,
+ AUDIO_OUTPUT_FLAG_PRIMARY = 0x2,
+ AUDIO_OUTPUT_FLAG_FAST = 0x4,
+ AUDIO_OUTPUT_FLAG_DEEP_BUFFER = 0x8,
+ AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD = 0x10,
+ AUDIO_OUTPUT_FLAG_NON_BLOCKING = 0x20,
+ AUDIO_OUTPUT_FLAG_HW_AV_SYNC = 0x40,
+ AUDIO_OUTPUT_FLAG_TTS = 0x80,
+ AUDIO_OUTPUT_FLAG_RAW = 0x100,
+ AUDIO_OUTPUT_FLAG_SYNC = 0x200,
+ AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO = 0x400,
+ AUDIO_OUTPUT_FLAG_DIRECT_PCM = 0x2000,
+ AUDIO_OUTPUT_FLAG_MMAP_NOIRQ = 0x4000,
+ AUDIO_OUTPUT_FLAG_VOIP_RX = 0x8000,
+ AUDIO_OUTPUT_FLAG_INCALL_MUSIC = 0x10000,
+} audio_output_flags_t;
+
+typedef enum {
+ AUDIO_INPUT_FLAG_NONE = 0x0,
+ AUDIO_INPUT_FLAG_FAST = 0x1,
+ AUDIO_INPUT_FLAG_HW_HOTWORD = 0x2,
+ AUDIO_INPUT_FLAG_RAW = 0x4,
+ AUDIO_INPUT_FLAG_SYNC = 0x8,
+ AUDIO_INPUT_FLAG_MMAP_NOIRQ = 0x10,
+ AUDIO_INPUT_FLAG_VOIP_TX = 0x20,
+ AUDIO_INPUT_FLAG_HW_AV_SYNC = 0x40,
+} audio_input_flags_t;
+
+typedef enum {
+ AUDIO_USAGE_UNKNOWN = 0,
+ AUDIO_USAGE_MEDIA = 1,
+ AUDIO_USAGE_VOICE_COMMUNICATION = 2,
+ AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING = 3,
+ AUDIO_USAGE_ALARM = 4,
+ AUDIO_USAGE_NOTIFICATION = 5,
+ AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE = 6,
+#ifndef AUDIO_NO_SYSTEM_DECLARATIONS
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9,
+ AUDIO_USAGE_NOTIFICATION_EVENT = 10,
+#endif // AUDIO_NO_SYSTEM_DECLARATIONS
+ AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY = 11,
+ AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12,
+ AUDIO_USAGE_ASSISTANCE_SONIFICATION = 13,
+ AUDIO_USAGE_GAME = 14,
+ AUDIO_USAGE_VIRTUAL_SOURCE = 15,
+ AUDIO_USAGE_ASSISTANT = 16,
+} audio_usage_t;
+
+typedef enum {
+ AUDIO_CONTENT_TYPE_UNKNOWN = 0u,
+ AUDIO_CONTENT_TYPE_SPEECH = 1u,
+ AUDIO_CONTENT_TYPE_MUSIC = 2u,
+ AUDIO_CONTENT_TYPE_MOVIE = 3u,
+ AUDIO_CONTENT_TYPE_SONIFICATION = 4u,
+} audio_content_type_t;
+
+enum {
+ AUDIO_GAIN_MODE_JOINT = 0x1u,
+ AUDIO_GAIN_MODE_CHANNELS = 0x2u,
+ AUDIO_GAIN_MODE_RAMP = 0x4u,
+};
+
+typedef enum {
+ AUDIO_PORT_ROLE_NONE = 0,
+ AUDIO_PORT_ROLE_SOURCE = 1, // (::android::hardware::audio::common::V4_0::AudioPortRole.NONE implicitly + 1)
+ AUDIO_PORT_ROLE_SINK = 2, // (::android::hardware::audio::common::V4_0::AudioPortRole.SOURCE implicitly + 1)
+} audio_port_role_t;
+
+typedef enum {
+ AUDIO_PORT_TYPE_NONE = 0,
+ AUDIO_PORT_TYPE_DEVICE = 1, // (::android::hardware::audio::common::V4_0::AudioPortType.NONE implicitly + 1)
+ AUDIO_PORT_TYPE_MIX = 2, // (::android::hardware::audio::common::V4_0::AudioPortType.DEVICE implicitly + 1)
+ AUDIO_PORT_TYPE_SESSION = 3, // (::android::hardware::audio::common::V4_0::AudioPortType.MIX implicitly + 1)
+} audio_port_type_t;
+
+enum {
+ AUDIO_PORT_CONFIG_SAMPLE_RATE = 0x1u,
+ AUDIO_PORT_CONFIG_CHANNEL_MASK = 0x2u,
+ AUDIO_PORT_CONFIG_FORMAT = 0x4u,
+ AUDIO_PORT_CONFIG_GAIN = 0x8u,
+};
+
+typedef enum {
+ AUDIO_LATENCY_LOW = 0,
+ AUDIO_LATENCY_NORMAL = 1, // (::android::hardware::audio::common::V4_0::AudioMixLatencyClass.LOW implicitly + 1)
+} audio_mix_latency_class_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // YOCTO_AUDIO_BASE_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/system/audio.h b/src/multimedia/libspeech_drv/audio_big_sw/os/system/audio.h
new file mode 100644
index 0000000..b824029
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/system/audio.h
@@ -0,0 +1,1230 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+ * Copyright (C) 2011 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 YOCTO_AUDIO_H
+#define YOCTO_AUDIO_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <cutils/bitops.h>
+
+#include "audio-base.h"
+#include "audio-base-utils.h"
+
+__BEGIN_DECLS
+
+#define __unused __attribute__((__unused__))
+
+
+/* represents an invalid uid for tracks; the calling or client uid is often substituted. */
+#define AUDIO_UID_INVALID ((uid_t)-1)
+
+/* device address used to refer to the standard remote submix */
+#define AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS "0"
+
+/* AudioFlinger and AudioPolicy services use I/O handles to identify audio sources and sinks */
+typedef int audio_io_handle_t;
+
+typedef uint32_t audio_flags_mask_t;
+
+/* Do not change these values without updating their counterparts
+ * in frameworks/base/media/java/android/media/AudioAttributes.java
+ */
+enum {
+ AUDIO_FLAG_NONE = 0x0,
+ AUDIO_FLAG_AUDIBILITY_ENFORCED = 0x1,
+ AUDIO_FLAG_SECURE = 0x2,
+ AUDIO_FLAG_SCO = 0x4,
+ AUDIO_FLAG_BEACON = 0x8,
+ AUDIO_FLAG_HW_AV_SYNC = 0x10,
+ AUDIO_FLAG_HW_HOTWORD = 0x20,
+ AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY = 0x40,
+ AUDIO_FLAG_BYPASS_MUTE = 0x80,
+ AUDIO_FLAG_LOW_LATENCY = 0x100,
+ AUDIO_FLAG_DEEP_BUFFER = 0x200,
+};
+
+/* Audio attributes */
+#define AUDIO_ATTRIBUTES_TAGS_MAX_SIZE 256
+typedef struct {
+ audio_content_type_t content_type;
+ audio_usage_t usage;
+ audio_source_t source;
+ audio_flags_mask_t flags;
+ char tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE]; /* UTF8 */
+} __attribute__((packed)) audio_attributes_t; // sent through Binder;
+
+/* a unique ID allocated by AudioFlinger for use as an audio_io_handle_t, audio_session_t,
+ * effect ID (int), audio_module_handle_t, and audio_patch_handle_t.
+ * Audio port IDs (audio_port_handle_t) are allocated by AudioPolicy
+ * in a different namespace than AudioFlinger unique IDs.
+ */
+typedef int audio_unique_id_t;
+
+/* Possible uses for an audio_unique_id_t */
+typedef enum {
+ AUDIO_UNIQUE_ID_USE_UNSPECIFIED = 0,
+ AUDIO_UNIQUE_ID_USE_SESSION = 1, // for allocated sessions, not special AUDIO_SESSION_*
+ AUDIO_UNIQUE_ID_USE_MODULE = 2,
+ AUDIO_UNIQUE_ID_USE_EFFECT = 3,
+ AUDIO_UNIQUE_ID_USE_PATCH = 4,
+ AUDIO_UNIQUE_ID_USE_OUTPUT = 5,
+ AUDIO_UNIQUE_ID_USE_INPUT = 6,
+ AUDIO_UNIQUE_ID_USE_PLAYER = 7,
+ AUDIO_UNIQUE_ID_USE_MAX = 8, // must be a power-of-two
+ AUDIO_UNIQUE_ID_USE_MASK = AUDIO_UNIQUE_ID_USE_MAX - 1
+} audio_unique_id_use_t;
+
+/* Return the use of an audio_unique_id_t */
+static inline audio_unique_id_use_t audio_unique_id_get_use(audio_unique_id_t id)
+{
+ return (audio_unique_id_use_t) (id & AUDIO_UNIQUE_ID_USE_MASK);
+}
+
+/* Reserved audio_unique_id_t values. FIXME: not a complete list. */
+#define AUDIO_UNIQUE_ID_ALLOCATE AUDIO_SESSION_ALLOCATE
+
+/* A channel mask per se only defines the presence or absence of a channel, not the order.
+ * But see AUDIO_INTERLEAVE_* below for the platform convention of order.
+ *
+ * audio_channel_mask_t is an opaque type and its internal layout should not
+ * be assumed as it may change in the future.
+ * Instead, always use the functions declared in this header to examine.
+ *
+ * These are the current representations:
+ *
+ * AUDIO_CHANNEL_REPRESENTATION_POSITION
+ * is a channel mask representation for position assignment.
+ * Each low-order bit corresponds to the spatial position of a transducer (output),
+ * or interpretation of channel (input).
+ * The user of a channel mask needs to know the context of whether it is for output or input.
+ * The constants AUDIO_CHANNEL_OUT_* or AUDIO_CHANNEL_IN_* apply to the bits portion.
+ * It is not permitted for no bits to be set.
+ *
+ * AUDIO_CHANNEL_REPRESENTATION_INDEX
+ * is a channel mask representation for index assignment.
+ * Each low-order bit corresponds to a selected channel.
+ * There is no platform interpretation of the various bits.
+ * There is no concept of output or input.
+ * It is not permitted for no bits to be set.
+ *
+ * All other representations are reserved for future use.
+ *
+ * Warning: current representation distinguishes between input and output, but this will not the be
+ * case in future revisions of the platform. Wherever there is an ambiguity between input and output
+ * that is currently resolved by checking the channel mask, the implementer should look for ways to
+ * fix it with additional information outside of the mask.
+ */
+typedef uint32_t audio_channel_mask_t;
+
+/* log(2) of maximum number of representations, not part of public API */
+#define AUDIO_CHANNEL_REPRESENTATION_LOG2 2
+
+/* The return value is undefined if the channel mask is invalid. */
+static inline uint32_t audio_channel_mask_get_bits(audio_channel_mask_t channel)
+{
+ return channel & ((1 << AUDIO_CHANNEL_COUNT_MAX) - 1);
+}
+
+typedef uint32_t audio_channel_representation_t;
+
+/* The return value is undefined if the channel mask is invalid. */
+static inline audio_channel_representation_t audio_channel_mask_get_representation(
+ audio_channel_mask_t channel)
+{
+ // The right shift should be sufficient, but also "and" for safety in case mask is not 32 bits
+ return (audio_channel_representation_t)
+ ((channel >> AUDIO_CHANNEL_COUNT_MAX) & ((1 << AUDIO_CHANNEL_REPRESENTATION_LOG2) - 1));
+}
+
+/* Returns true if the channel mask is valid,
+ * or returns false for AUDIO_CHANNEL_NONE, AUDIO_CHANNEL_INVALID, and other invalid values.
+ * This function is unable to determine whether a channel mask for position assignment
+ * is invalid because an output mask has an invalid output bit set,
+ * or because an input mask has an invalid input bit set.
+ * All other APIs that take a channel mask assume that it is valid.
+ */
+static inline bool audio_channel_mask_is_valid(audio_channel_mask_t channel)
+{
+ uint32_t bits = audio_channel_mask_get_bits(channel);
+ audio_channel_representation_t representation = audio_channel_mask_get_representation(channel);
+ switch (representation) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ break;
+ default:
+ bits = 0;
+ break;
+ }
+ return bits != 0;
+}
+
+/* Not part of public API */
+static inline audio_channel_mask_t audio_channel_mask_from_representation_and_bits(
+ audio_channel_representation_t representation, uint32_t bits)
+{
+ return (audio_channel_mask_t) ((representation << AUDIO_CHANNEL_COUNT_MAX) | bits);
+}
+
+/**
+ * Expresses the convention when stereo audio samples are stored interleaved
+ * in an array. This should improve readability by allowing code to use
+ * symbolic indices instead of hard-coded [0] and [1].
+ *
+ * For multi-channel beyond stereo, the platform convention is that channels
+ * are interleaved in order from least significant channel mask bit to most
+ * significant channel mask bit, with unused bits skipped. Any exceptions
+ * to this convention will be noted at the appropriate API.
+ */
+enum {
+ AUDIO_INTERLEAVE_LEFT = 0,
+ AUDIO_INTERLEAVE_RIGHT = 1,
+};
+
+/* This enum is deprecated */
+typedef enum {
+ AUDIO_IN_ACOUSTICS_NONE = 0,
+ AUDIO_IN_ACOUSTICS_AGC_ENABLE = 0x0001,
+ AUDIO_IN_ACOUSTICS_AGC_DISABLE = 0,
+ AUDIO_IN_ACOUSTICS_NS_ENABLE = 0x0002,
+ AUDIO_IN_ACOUSTICS_NS_DISABLE = 0,
+ AUDIO_IN_ACOUSTICS_TX_IIR_ENABLE = 0x0004,
+ AUDIO_IN_ACOUSTICS_TX_DISABLE = 0,
+} audio_in_acoustics_t;
+
+typedef uint32_t audio_devices_t;
+/**
+ * Stub audio output device. Used in policy configuration file on platforms without audio outputs.
+ * This alias value to AUDIO_DEVICE_OUT_DEFAULT is only used in the audio policy context.
+ */
+#define AUDIO_DEVICE_OUT_STUB AUDIO_DEVICE_OUT_DEFAULT
+/**
+ * Stub audio input device. Used in policy configuration file on platforms without audio inputs.
+ * This alias value to AUDIO_DEVICE_IN_DEFAULT is only used in the audio policy context.
+ */
+#define AUDIO_DEVICE_IN_STUB AUDIO_DEVICE_IN_DEFAULT
+
+/* Additional information about compressed streams offloaded to
+ * hardware playback
+ * The version and size fields must be initialized by the caller by using
+ * one of the constants defined here.
+ * Must be aligned to transmit as raw memory through Binder.
+ */
+typedef struct {
+ uint16_t version; // version of the info structure
+ uint16_t size; // total size of the structure including version and size
+ uint32_t sample_rate; // sample rate in Hz
+ audio_channel_mask_t channel_mask; // channel mask
+ audio_format_t format; // audio format
+ audio_stream_type_t stream_type; // stream type
+ uint32_t bit_rate; // bit rate in bits per second
+ int64_t duration_us; // duration in microseconds, -1 if unknown
+ bool has_video; // true if stream is tied to a video stream
+ bool is_streaming; // true if streaming, false if local playback
+ uint32_t bit_width;
+ uint32_t offload_buffer_size; // offload fragment size
+ audio_usage_t usage;
+} __attribute__((aligned(8))) audio_offload_info_t;
+
+#define AUDIO_MAKE_OFFLOAD_INFO_VERSION(maj,min) \
+ ((((maj) & 0xff) << 8) | ((min) & 0xff))
+
+#define AUDIO_OFFLOAD_INFO_VERSION_0_1 AUDIO_MAKE_OFFLOAD_INFO_VERSION(0, 1)
+#define AUDIO_OFFLOAD_INFO_VERSION_CURRENT AUDIO_OFFLOAD_INFO_VERSION_0_1
+
+static const audio_offload_info_t AUDIO_INFO_INITIALIZER = {
+ /* .version = */ AUDIO_OFFLOAD_INFO_VERSION_CURRENT,
+ /* .size = */ sizeof(audio_offload_info_t),
+ /* .sample_rate = */ 0,
+ /* .channel_mask = */ 0,
+ /* .format = */ AUDIO_FORMAT_DEFAULT,
+ /* .stream_type = */ AUDIO_STREAM_VOICE_CALL,
+ /* .bit_rate = */ 0,
+ /* .duration_us = */ 0,
+ /* .has_video = */ false,
+ /* .is_streaming = */ false,
+ /* .bit_width = */ 16,
+ /* .offload_buffer_size = */ 0,
+ /* .usage = */ AUDIO_USAGE_UNKNOWN
+};
+
+/* common audio stream configuration parameters
+ * You should memset() the entire structure to zero before use to
+ * ensure forward compatibility
+ * Must be aligned to transmit as raw memory through Binder.
+ */
+struct __attribute__((aligned(8))) audio_config {
+ uint32_t sample_rate;
+ audio_channel_mask_t channel_mask;
+ audio_format_t format;
+ audio_offload_info_t offload_info;
+ uint32_t frame_count;
+};
+typedef struct audio_config audio_config_t;
+
+static const audio_config_t AUDIO_CONFIG_INITIALIZER = {
+ /* .sample_rate = */ 0,
+ /* .channel_mask = */ AUDIO_CHANNEL_NONE,
+ /* .format = */ AUDIO_FORMAT_DEFAULT,
+ /* .offload_info = */ {
+ /* .version = */ AUDIO_OFFLOAD_INFO_VERSION_CURRENT,
+ /* .size = */ sizeof(audio_offload_info_t),
+ /* .sample_rate = */ 0,
+ /* .channel_mask = */ 0,
+ /* .format = */ AUDIO_FORMAT_DEFAULT,
+ /* .stream_type = */ AUDIO_STREAM_VOICE_CALL,
+ /* .bit_rate = */ 0,
+ /* .duration_us = */ 0,
+ /* .has_video = */ false,
+ /* .is_streaming = */ false,
+ /* .bit_width = */ 16,
+ /* .offload_buffer_size = */ 0,
+ /* .usage = */ AUDIO_USAGE_UNKNOWN
+ },
+ /* .frame_count = */ 0,
+};
+
+struct audio_config_base {
+ uint32_t sample_rate;
+ audio_channel_mask_t channel_mask;
+ audio_format_t format;
+};
+
+typedef struct audio_config_base audio_config_base_t;
+
+static const audio_config_base_t AUDIO_CONFIG_BASE_INITIALIZER = {
+ /* .sample_rate = */ 0,
+ /* .channel_mask = */ AUDIO_CHANNEL_NONE,
+ /* .format = */ AUDIO_FORMAT_DEFAULT
+};
+
+/* audio hw module handle functions or structures referencing a module */
+typedef int audio_module_handle_t;
+
+/******************************
+ * Volume control
+ *****************************/
+
+/** 3 dB headroom are allowed on float samples (3db = 10^(3/20) = 1.412538).
+* See: https://developer.android.com/reference/android/media/AudioTrack.html#write(float[], int, int, int)
+*/
+#define FLOAT_NOMINAL_RANGE_HEADROOM 1.412538
+
+/* If the audio hardware supports gain control on some audio paths,
+ * the platform can expose them in the audio_policy.conf file. The audio HAL
+ * will then implement gain control functions that will use the following data
+ * structures. */
+
+typedef uint32_t audio_gain_mode_t;
+
+
+/* An audio_gain struct is a representation of a gain stage.
+ * A gain stage is always attached to an audio port. */
+struct audio_gain {
+ audio_gain_mode_t mode; /* e.g. AUDIO_GAIN_MODE_JOINT */
+ audio_channel_mask_t channel_mask; /* channels which gain an be controlled.
+ N/A if AUDIO_GAIN_MODE_CHANNELS is not supported */
+ int min_value; /* minimum gain value in millibels */
+ int max_value; /* maximum gain value in millibels */
+ int default_value; /* default gain value in millibels */
+ unsigned int step_value; /* gain step in millibels */
+ unsigned int min_ramp_ms; /* minimum ramp duration in ms */
+ unsigned int max_ramp_ms; /* maximum ramp duration in ms */
+};
+
+/* The gain configuration structure is used to get or set the gain values of a
+ * given port */
+struct audio_gain_config {
+ int index; /* index of the corresponding audio_gain in the
+ audio_port gains[] table */
+ audio_gain_mode_t mode; /* mode requested for this command */
+ audio_channel_mask_t channel_mask; /* channels which gain value follows.
+ N/A in joint mode */
+
+ // note this "8" is not FCC_8, so it won't need to be changed for > 8 channels
+ int values[sizeof(audio_channel_mask_t) * 8]; /* gain values in millibels
+ for each channel ordered from LSb to MSb in
+ channel mask. The number of values is 1 in joint
+ mode or popcount(channel_mask) */
+ unsigned int ramp_duration_ms; /* ramp duration in ms */
+};
+
+/******************************
+ * Routing control
+ *****************************/
+
+/* Types defined here are used to describe an audio source or sink at internal
+ * framework interfaces (audio policy, patch panel) or at the audio HAL.
+ * Sink and sources are grouped in a concept of “audio port” representing an
+ * audio end point at the edge of the system managed by the module exposing
+ * the interface. */
+
+/* Each port has a unique ID or handle allocated by policy manager */
+typedef int audio_port_handle_t;
+
+/* the maximum length for the human-readable device name */
+#define AUDIO_PORT_MAX_NAME_LEN 128
+
+/* maximum audio device address length */
+#define AUDIO_DEVICE_MAX_ADDRESS_LEN 32
+
+/* extension for audio port configuration structure when the audio port is a
+ * hardware device */
+struct audio_port_config_device_ext {
+ audio_module_handle_t hw_module; /* module the device is attached to */
+ audio_devices_t type; /* device type (e.g AUDIO_DEVICE_OUT_SPEAKER) */
+ char address[AUDIO_DEVICE_MAX_ADDRESS_LEN]; /* device address. "" if N/A */
+};
+
+/* extension for audio port configuration structure when the audio port is a
+ * sub mix */
+struct audio_port_config_mix_ext {
+ audio_module_handle_t hw_module; /* module the stream is attached to */
+ audio_io_handle_t handle; /* I/O handle of the input/output stream */
+ union {
+ //TODO: change use case for output streams: use strategy and mixer attributes
+ audio_stream_type_t stream;
+ audio_source_t source;
+ } usecase;
+};
+
+/* extension for audio port configuration structure when the audio port is an
+ * audio session */
+struct audio_port_config_session_ext {
+ audio_session_t session; /* audio session */
+};
+
+/* audio port configuration structure used to specify a particular configuration of
+ * an audio port */
+struct audio_port_config {
+ audio_port_handle_t id; /* port unique ID */
+ audio_port_role_t role; /* sink or source */
+ audio_port_type_t type; /* device, mix ... */
+ unsigned int config_mask; /* e.g AUDIO_PORT_CONFIG_ALL */
+ unsigned int sample_rate; /* sampling rate in Hz */
+ audio_channel_mask_t channel_mask; /* channel mask if applicable */
+ audio_format_t format; /* format if applicable */
+ struct audio_gain_config gain; /* gain to apply if applicable */
+ union {
+ struct audio_port_config_device_ext device; /* device specific info */
+ struct audio_port_config_mix_ext mix; /* mix specific info */
+ struct audio_port_config_session_ext session; /* session specific info */
+ } ext;
+};
+
+
+/* max number of sampling rates in audio port */
+#define AUDIO_PORT_MAX_SAMPLING_RATES 32
+/* max number of channel masks in audio port */
+#define AUDIO_PORT_MAX_CHANNEL_MASKS 32
+/* max number of audio formats in audio port */
+#define AUDIO_PORT_MAX_FORMATS 32
+/* max number of gain controls in audio port */
+#define AUDIO_PORT_MAX_GAINS 16
+
+/* extension for audio port structure when the audio port is a hardware device */
+struct audio_port_device_ext {
+ audio_module_handle_t hw_module; /* module the device is attached to */
+ audio_devices_t type; /* device type (e.g AUDIO_DEVICE_OUT_SPEAKER) */
+ char address[AUDIO_DEVICE_MAX_ADDRESS_LEN];
+};
+
+/* extension for audio port structure when the audio port is a sub mix */
+struct audio_port_mix_ext {
+ audio_module_handle_t hw_module; /* module the stream is attached to */
+ audio_io_handle_t handle; /* I/O handle of the input.output stream */
+ audio_mix_latency_class_t latency_class; /* latency class */
+ // other attributes: routing strategies
+};
+
+/* extension for audio port structure when the audio port is an audio session */
+struct audio_port_session_ext {
+ audio_session_t session; /* audio session */
+};
+
+struct audio_port {
+ audio_port_handle_t id; /* port unique ID */
+ audio_port_role_t role; /* sink or source */
+ audio_port_type_t type; /* device, mix ... */
+ char name[AUDIO_PORT_MAX_NAME_LEN];
+ unsigned int num_sample_rates; /* number of sampling rates in following array */
+ unsigned int sample_rates[AUDIO_PORT_MAX_SAMPLING_RATES];
+ unsigned int num_channel_masks; /* number of channel masks in following array */
+ audio_channel_mask_t channel_masks[AUDIO_PORT_MAX_CHANNEL_MASKS];
+ unsigned int num_formats; /* number of formats in following array */
+ audio_format_t formats[AUDIO_PORT_MAX_FORMATS];
+ unsigned int num_gains; /* number of gains in following array */
+ struct audio_gain gains[AUDIO_PORT_MAX_GAINS];
+ struct audio_port_config active_config; /* current audio port configuration */
+ union {
+ struct audio_port_device_ext device;
+ struct audio_port_mix_ext mix;
+ struct audio_port_session_ext session;
+ } ext;
+};
+
+/* An audio patch represents a connection between one or more source ports and
+ * one or more sink ports. Patches are connected and disconnected by audio policy manager or by
+ * applications via framework APIs.
+ * Each patch is identified by a handle at the interface used to create that patch. For instance,
+ * when a patch is created by the audio HAL, the HAL allocates and returns a handle.
+ * This handle is unique to a given audio HAL hardware module.
+ * But the same patch receives another system wide unique handle allocated by the framework.
+ * This unique handle is used for all transactions inside the framework.
+ */
+typedef int audio_patch_handle_t;
+
+#define AUDIO_PATCH_PORTS_MAX 16
+
+struct audio_patch {
+ audio_patch_handle_t id; /* patch unique ID */
+ unsigned int num_sources; /* number of sources in following array */
+ struct audio_port_config sources[AUDIO_PATCH_PORTS_MAX];
+ unsigned int num_sinks; /* number of sinks in following array */
+ struct audio_port_config sinks[AUDIO_PATCH_PORTS_MAX];
+};
+
+
+
+/* a HW synchronization source returned by the audio HAL */
+typedef uint32_t audio_hw_sync_t;
+
+/* an invalid HW synchronization source indicating an error */
+#define AUDIO_HW_SYNC_INVALID 0
+
+/**
+ * Mmap buffer descriptor returned by audio_stream->create_mmap_buffer().
+ * note\ Used by streams opened in mmap mode.
+ */
+struct audio_mmap_buffer_info {
+ void* shared_memory_address; /**< base address of mmap memory buffer.
+ For use by local process only */
+ int32_t shared_memory_fd; /**< FD for mmap memory buffer */
+ int32_t buffer_size_frames; /**< total buffer size in frames */
+ int32_t burst_size_frames; /**< transfer size granularity in frames */
+};
+
+/**
+ * Mmap buffer read/write position returned by audio_stream->get_mmap_position().
+ * note\ Used by streams opened in mmap mode.
+ */
+struct audio_mmap_position {
+ int64_t time_nanoseconds; /**< timestamp in ns, CLOCK_MONOTONIC */
+ int32_t position_frames; /**< increasing 32 bit frame count reset when stream->stop()
+ is called */
+};
+
+/** Metadata of a record track for an in stream. */
+typedef struct playback_track_metadata {
+ audio_usage_t usage;
+ audio_content_type_t content_type;
+ float gain; // Normalized linear volume. 0=silence, 1=0dbfs...
+} playback_track_metadata_t;
+
+/** Metadata of a playback track for an out stream. */
+typedef struct record_track_metadata {
+ audio_source_t source;
+ float gain; // Normalized linear volume. 0=silence, 1=0dbfs...
+} record_track_metadata_t;
+
+
+/******************************
+ * Helper functions
+ *****************************/
+
+static inline bool audio_is_output_device(audio_devices_t device)
+{
+ if (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
+ (popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL) == 0))
+ return true;
+ else
+ return false;
+}
+
+static inline bool audio_is_input_device(audio_devices_t device)
+{
+ if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_IN_ALL) == 0))
+ return true;
+ }
+ return false;
+}
+
+static inline bool audio_is_output_devices(audio_devices_t device)
+{
+ return (device & AUDIO_DEVICE_BIT_IN) == 0;
+}
+
+static inline bool audio_is_a2dp_in_device(audio_devices_t device)
+{
+ if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if ((popcount(device) == 1) && (device & AUDIO_DEVICE_IN_BLUETOOTH_A2DP))
+ return true;
+ }
+ return false;
+}
+
+static inline bool audio_is_a2dp_out_device(audio_devices_t device)
+{
+ if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_A2DP))
+ return true;
+ else
+ return false;
+}
+
+// Deprecated - use audio_is_a2dp_out_device() instead
+static inline bool audio_is_a2dp_device(audio_devices_t device)
+{
+ return audio_is_a2dp_out_device(device);
+}
+
+static inline bool audio_is_bluetooth_sco_device(audio_devices_t device)
+{
+ if ((device & AUDIO_DEVICE_BIT_IN) == 0) {
+ if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL_SCO) == 0))
+ return true;
+ } else {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) == 0))
+ return true;
+ }
+
+ return false;
+}
+
+static inline bool audio_is_hearing_aid_out_device(audio_devices_t device)
+{
+ return device == AUDIO_DEVICE_OUT_HEARING_AID;
+}
+
+static inline bool audio_is_usb_out_device(audio_devices_t device)
+{
+ return ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_USB));
+}
+
+static inline bool audio_is_usb_in_device(audio_devices_t device)
+{
+ if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if (popcount(device) == 1 && (device & AUDIO_DEVICE_IN_ALL_USB) != 0)
+ return true;
+ }
+ return false;
+}
+
+/* OBSOLETE - use audio_is_usb_out_device() instead. */
+static inline bool audio_is_usb_device(audio_devices_t device)
+{
+ return audio_is_usb_out_device(device);
+}
+
+static inline bool audio_is_remote_submix_device(audio_devices_t device)
+{
+ if ((audio_is_output_devices(device) &&
+ (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) == AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
+ || (!audio_is_output_devices(device) &&
+ (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) == AUDIO_DEVICE_IN_REMOTE_SUBMIX))
+ return true;
+ else
+ return false;
+}
+
+/* Returns true if:
+ * representation is valid, and
+ * there is at least one channel bit set which _could_ correspond to an input channel, and
+ * there are no channel bits set which could _not_ correspond to an input channel.
+ * Otherwise returns false.
+ */
+static inline bool audio_is_input_channel(audio_channel_mask_t channel)
+{
+ uint32_t bits = audio_channel_mask_get_bits(channel);
+ switch (audio_channel_mask_get_representation(channel)) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ if (bits & ~AUDIO_CHANNEL_IN_ALL) {
+ bits = 0;
+ }
+ // fall through
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ return bits != 0;
+ default:
+ return false;
+ }
+}
+
+/* Returns true if:
+ * representation is valid, and
+ * there is at least one channel bit set which _could_ correspond to an output channel, and
+ * there are no channel bits set which could _not_ correspond to an output channel.
+ * Otherwise returns false.
+ */
+static inline bool audio_is_output_channel(audio_channel_mask_t channel)
+{
+ uint32_t bits = audio_channel_mask_get_bits(channel);
+ switch (audio_channel_mask_get_representation(channel)) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ if (bits & ~AUDIO_CHANNEL_OUT_ALL) {
+ bits = 0;
+ }
+ // fall through
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ return bits != 0;
+ default:
+ return false;
+ }
+}
+
+/* Returns the number of channels from an input channel mask,
+ * used in the context of audio input or recording.
+ * If a channel bit is set which could _not_ correspond to an input channel,
+ * it is excluded from the count.
+ * Returns zero if the representation is invalid.
+ */
+static inline uint32_t audio_channel_count_from_in_mask(audio_channel_mask_t channel)
+{
+ uint32_t bits = audio_channel_mask_get_bits(channel);
+ switch (audio_channel_mask_get_representation(channel)) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ // TODO: We can now merge with from_out_mask and remove anding
+ bits &= AUDIO_CHANNEL_IN_ALL;
+ // fall through
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ return popcount(bits);
+ default:
+ return 0;
+ }
+}
+
+/* Returns the number of channels from an output channel mask,
+ * used in the context of audio output or playback.
+ * If a channel bit is set which could _not_ correspond to an output channel,
+ * it is excluded from the count.
+ * Returns zero if the representation is invalid.
+ */
+static inline uint32_t audio_channel_count_from_out_mask(audio_channel_mask_t channel)
+{
+ uint32_t bits = audio_channel_mask_get_bits(channel);
+ switch (audio_channel_mask_get_representation(channel)) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ // TODO: We can now merge with from_in_mask and remove anding
+ bits &= AUDIO_CHANNEL_OUT_ALL;
+ // fall through
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ return popcount(bits);
+ default:
+ return 0;
+ }
+}
+
+/* Derive a channel mask for index assignment from a channel count.
+ * Returns the matching channel mask,
+ * or AUDIO_CHANNEL_NONE if the channel count is zero,
+ * or AUDIO_CHANNEL_INVALID if the channel count exceeds AUDIO_CHANNEL_COUNT_MAX.
+ */
+static inline audio_channel_mask_t audio_channel_mask_for_index_assignment_from_count(
+ uint32_t channel_count)
+{
+ if (channel_count == 0) {
+ return AUDIO_CHANNEL_NONE;
+ }
+ if (channel_count > AUDIO_CHANNEL_COUNT_MAX) {
+ return AUDIO_CHANNEL_INVALID;
+ }
+ uint32_t bits = (1 << channel_count) - 1;
+ return audio_channel_mask_from_representation_and_bits(
+ AUDIO_CHANNEL_REPRESENTATION_INDEX, bits);
+}
+
+/* Derive an output channel mask for position assignment from a channel count.
+ * This is to be used when the content channel mask is unknown. The 1, 2, 4, 5, 6, 7 and 8 channel
+ * cases are mapped to the standard game/home-theater layouts, but note that 4 is mapped to quad,
+ * and not stereo + FC + mono surround. A channel count of 3 is arbitrarily mapped to stereo + FC
+ * for continuity with stereo.
+ * Returns the matching channel mask,
+ * or AUDIO_CHANNEL_NONE if the channel count is zero,
+ * or AUDIO_CHANNEL_INVALID if the channel count exceeds that of the
+ * configurations for which a default output channel mask is defined.
+ */
+static inline audio_channel_mask_t audio_channel_out_mask_from_count(uint32_t channel_count)
+{
+ uint32_t bits;
+ switch (channel_count) {
+ case 0:
+ return AUDIO_CHANNEL_NONE;
+ case 1:
+ bits = AUDIO_CHANNEL_OUT_MONO;
+ break;
+ case 2:
+ bits = AUDIO_CHANNEL_OUT_STEREO;
+ break;
+ case 3:
+ bits = AUDIO_CHANNEL_OUT_STEREO | AUDIO_CHANNEL_OUT_FRONT_CENTER;
+ break;
+ case 4: // 4.0
+ bits = AUDIO_CHANNEL_OUT_QUAD;
+ break;
+ case 5: // 5.0
+ bits = AUDIO_CHANNEL_OUT_QUAD | AUDIO_CHANNEL_OUT_FRONT_CENTER;
+ break;
+ case 6: // 5.1
+ bits = AUDIO_CHANNEL_OUT_5POINT1;
+ break;
+ case 7: // 6.1
+ bits = AUDIO_CHANNEL_OUT_5POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER;
+ break;
+ case 8:
+ bits = AUDIO_CHANNEL_OUT_7POINT1;
+ break;
+ // FIXME FCC_8
+ default:
+ return AUDIO_CHANNEL_INVALID;
+ }
+ return audio_channel_mask_from_representation_and_bits(
+ AUDIO_CHANNEL_REPRESENTATION_POSITION, bits);
+}
+
+/* Derive a default input channel mask from a channel count.
+ * Assumes a position mask for mono and stereo, or an index mask for channel counts > 2.
+ * Returns the matching channel mask,
+ * or AUDIO_CHANNEL_NONE if the channel count is zero,
+ * or AUDIO_CHANNEL_INVALID if the channel count exceeds that of the
+ * configurations for which a default input channel mask is defined.
+ */
+static inline audio_channel_mask_t audio_channel_in_mask_from_count(uint32_t channel_count)
+{
+ uint32_t bits;
+ switch (channel_count) {
+ case 0:
+ return AUDIO_CHANNEL_NONE;
+ case 1:
+ bits = AUDIO_CHANNEL_IN_MONO;
+ break;
+ case 2:
+ bits = AUDIO_CHANNEL_IN_STEREO;
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ // FIXME FCC_8
+ return audio_channel_mask_for_index_assignment_from_count(channel_count);
+ default:
+ return AUDIO_CHANNEL_INVALID;
+ }
+ return audio_channel_mask_from_representation_and_bits(
+ AUDIO_CHANNEL_REPRESENTATION_POSITION, bits);
+}
+
+static inline audio_channel_mask_t audio_channel_mask_in_to_out(audio_channel_mask_t in)
+{
+ switch (in) {
+ case AUDIO_CHANNEL_IN_MONO:
+ return AUDIO_CHANNEL_OUT_MONO;
+ case AUDIO_CHANNEL_IN_STEREO:
+ return AUDIO_CHANNEL_OUT_STEREO;
+ case AUDIO_CHANNEL_IN_5POINT1:
+ return AUDIO_CHANNEL_OUT_5POINT1;
+ case AUDIO_CHANNEL_IN_3POINT1POINT2:
+ return AUDIO_CHANNEL_OUT_3POINT1POINT2;
+ case AUDIO_CHANNEL_IN_3POINT0POINT2:
+ return AUDIO_CHANNEL_OUT_3POINT0POINT2;
+ case AUDIO_CHANNEL_IN_2POINT1POINT2:
+ return AUDIO_CHANNEL_OUT_2POINT1POINT2;
+ case AUDIO_CHANNEL_IN_2POINT0POINT2:
+ return AUDIO_CHANNEL_OUT_2POINT0POINT2;
+ default:
+ return AUDIO_CHANNEL_INVALID;
+ }
+}
+
+static inline bool audio_is_valid_format(audio_format_t format)
+{
+ switch (format & AUDIO_FORMAT_MAIN_MASK) {
+ case AUDIO_FORMAT_PCM:
+ switch (format) {
+ case AUDIO_FORMAT_PCM_16_BIT:
+ case AUDIO_FORMAT_PCM_8_BIT:
+ case AUDIO_FORMAT_PCM_32_BIT:
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ case AUDIO_FORMAT_PCM_FLOAT:
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ return true;
+ default:
+ return false;
+ }
+ /* not reached */
+ case AUDIO_FORMAT_MP3:
+ case AUDIO_FORMAT_AMR_NB:
+ case AUDIO_FORMAT_AMR_WB:
+ case AUDIO_FORMAT_AAC:
+ case AUDIO_FORMAT_AAC_ADTS:
+ case AUDIO_FORMAT_HE_AAC_V1:
+ case AUDIO_FORMAT_HE_AAC_V2:
+ case AUDIO_FORMAT_AAC_ELD:
+ case AUDIO_FORMAT_AAC_XHE:
+ case AUDIO_FORMAT_VORBIS:
+ case AUDIO_FORMAT_OPUS:
+ case AUDIO_FORMAT_AC3:
+ case AUDIO_FORMAT_E_AC3:
+ case AUDIO_FORMAT_DTS:
+ case AUDIO_FORMAT_DTS_HD:
+ case AUDIO_FORMAT_IEC61937:
+ case AUDIO_FORMAT_DOLBY_TRUEHD:
+ case AUDIO_FORMAT_QCELP:
+ case AUDIO_FORMAT_EVRC:
+ case AUDIO_FORMAT_EVRCB:
+ case AUDIO_FORMAT_EVRCWB:
+ case AUDIO_FORMAT_AAC_ADIF:
+ case AUDIO_FORMAT_AMR_WB_PLUS:
+ case AUDIO_FORMAT_MP2:
+ case AUDIO_FORMAT_EVRCNW:
+ case AUDIO_FORMAT_FLAC:
+ case AUDIO_FORMAT_ALAC:
+ case AUDIO_FORMAT_APE:
+ case AUDIO_FORMAT_WMA:
+ case AUDIO_FORMAT_WMA_PRO:
+ case AUDIO_FORMAT_DSD:
+ case AUDIO_FORMAT_AC4:
+ case AUDIO_FORMAT_LDAC:
+ case AUDIO_FORMAT_E_AC3_JOC:
+ case AUDIO_FORMAT_MAT_1_0:
+ case AUDIO_FORMAT_MAT_2_0:
+ case AUDIO_FORMAT_MAT_2_1:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Extract the primary format, eg. PCM, AC3, etc.
+ */
+static inline audio_format_t audio_get_main_format(audio_format_t format)
+{
+ return (audio_format_t)(format & AUDIO_FORMAT_MAIN_MASK);
+}
+
+/**
+ * Is the data plain PCM samples that can be scaled and mixed?
+ */
+static inline bool audio_is_linear_pcm(audio_format_t format)
+{
+ return (audio_get_main_format(format) == AUDIO_FORMAT_PCM);
+}
+
+/**
+ * For this format, is the number of PCM audio frames directly proportional
+ * to the number of data bytes?
+ *
+ * In other words, is the format transported as PCM audio samples,
+ * but not necessarily scalable or mixable.
+ * This returns true for real PCM, but also for AUDIO_FORMAT_IEC61937,
+ * which is transported as 16 bit PCM audio, but where the encoded data
+ * cannot be mixed or scaled.
+ */
+static inline bool audio_has_proportional_frames(audio_format_t format)
+{
+ audio_format_t mainFormat = audio_get_main_format(format);
+ return (mainFormat == AUDIO_FORMAT_PCM
+ || mainFormat == AUDIO_FORMAT_IEC61937);
+}
+
+static inline size_t audio_bytes_per_sample(audio_format_t format)
+{
+ size_t size = 0;
+
+ switch (format) {
+ case AUDIO_FORMAT_PCM_32_BIT:
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ size = sizeof(int32_t);
+ break;
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ size = sizeof(uint8_t) * 3;
+ break;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ case AUDIO_FORMAT_IEC61937:
+ size = sizeof(int16_t);
+ break;
+ case AUDIO_FORMAT_PCM_8_BIT:
+ size = sizeof(uint8_t);
+ break;
+ case AUDIO_FORMAT_PCM_FLOAT:
+ size = sizeof(float);
+ break;
+ default:
+ break;
+ }
+ return size;
+}
+
+static inline size_t audio_bytes_per_frame(uint32_t channel_count, audio_format_t format)
+{
+ // cannot overflow for reasonable channel_count
+ return channel_count * audio_bytes_per_sample(format);
+}
+
+/* converts device address to string sent to audio HAL via set_parameters */
+static inline char *audio_device_address_to_parameter(audio_devices_t device, const char *address)
+{
+ const size_t kSize = AUDIO_DEVICE_MAX_ADDRESS_LEN + sizeof("a2dp_sink_address=");
+ char param[kSize];
+
+ if (device & AUDIO_DEVICE_OUT_ALL_A2DP)
+ snprintf(param, kSize, "%s=%s", "a2dp_sink_address", address);
+ else if (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
+ snprintf(param, kSize, "%s=%s", "mix", address);
+ else
+ snprintf(param, kSize, "%s", address);
+
+ return strdup(param);
+}
+
+static inline bool audio_device_is_digital(audio_devices_t device) {
+ if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+ // input
+ return (~AUDIO_DEVICE_BIT_IN & device & (AUDIO_DEVICE_IN_ALL_USB |
+ AUDIO_DEVICE_IN_HDMI |
+ AUDIO_DEVICE_IN_SPDIF |
+ AUDIO_DEVICE_IN_IP |
+ AUDIO_DEVICE_IN_BUS)) != 0;
+ } else {
+ // output
+ return (device & (AUDIO_DEVICE_OUT_ALL_USB |
+ AUDIO_DEVICE_OUT_HDMI |
+ AUDIO_DEVICE_OUT_HDMI_ARC |
+ AUDIO_DEVICE_OUT_SPDIF |
+ AUDIO_DEVICE_OUT_IP |
+ AUDIO_DEVICE_OUT_BUS)) != 0;
+ }
+}
+
+// Unique effect ID (can be generated from the following site:
+// http://www.itu.int/ITU-T/asn1/uuid.html)
+// This struct is used for effects identification and in soundtrigger.
+typedef struct audio_uuid_s {
+ uint32_t timeLow;
+ uint16_t timeMid;
+ uint16_t timeHiAndVersion;
+ uint16_t clockSeq;
+ uint8_t node[6];
+} audio_uuid_t;
+
+//TODO: audio_microphone_location_t need to move to HAL v4.0
+typedef enum {
+ AUDIO_MICROPHONE_LOCATION_UNKNOWN = 0,
+ AUDIO_MICROPHONE_LOCATION_MAINBODY = 1,
+ AUDIO_MICROPHONE_LOCATION_MAINBODY_MOVABLE = 2,
+ AUDIO_MICROPHONE_LOCATION_PERIPHERAL = 3,
+ AUDIO_MICROPHONE_LOCATION_CNT = 4,
+} audio_microphone_location_t;
+
+//TODO: audio_microphone_directionality_t need to move to HAL v4.0
+typedef enum {
+ AUDIO_MICROPHONE_DIRECTIONALITY_UNKNOWN = 0,
+ AUDIO_MICROPHONE_DIRECTIONALITY_OMNI = 1,
+ AUDIO_MICROPHONE_DIRECTIONALITY_BI_DIRECTIONAL = 2,
+ AUDIO_MICROPHONE_DIRECTIONALITY_CARDIOID = 3,
+ AUDIO_MICROPHONE_DIRECTIONALITY_HYPER_CARDIOID = 4,
+ AUDIO_MICROPHONE_DIRECTIONALITY_SUPER_CARDIOID = 5,
+ AUDIO_MICROPHONE_DIRECTIONALITY_CNT = 6,
+} audio_microphone_directionality_t;
+
+/* A 3D point which could be used to represent geometric location
+ * or orientation of a microphone.
+ */
+struct audio_microphone_coordinate {
+ float x;
+ float y;
+ float z;
+};
+
+/* An number to indicate which group the microphone locate. Main body is
+ * usually group 0. Developer could use this value to group the microphones
+ * that locate on the same peripheral or attachments.
+ */
+typedef int audio_microphone_group_t;
+
+typedef enum {
+ AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED = 0,
+ AUDIO_MICROPHONE_CHANNEL_MAPPING_DIRECT = 1,
+ AUDIO_MICROPHONE_CHANNEL_MAPPING_PROCESSED = 2,
+ AUDIO_MICROPHONE_CHANNEL_MAPPING_CNT = 3,
+} audio_microphone_channel_mapping_t;
+
+/* the maximum length for the microphone id */
+#define AUDIO_MICROPHONE_ID_MAX_LEN 32
+/* max number of frequency responses in a frequency response table */
+#define AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES 256
+/* max number of microphone */
+#define AUDIO_MICROPHONE_MAX_COUNT 32
+/* the value of unknown spl */
+#define AUDIO_MICROPHONE_SPL_UNKNOWN -FLT_MAX
+/* the value of unknown sensitivity */
+#define AUDIO_MICROPHONE_SENSITIVITY_UNKNOWN -FLT_MAX
+/* the value of unknown coordinate */
+#define AUDIO_MICROPHONE_COORDINATE_UNKNOWN -FLT_MAX
+/* the value used as address when the address of bottom microphone is empty */
+#define AUDIO_BOTTOM_MICROPHONE_ADDRESS "bottom"
+/* the value used as address when the address of back microphone is empty */
+#define AUDIO_BACK_MICROPHONE_ADDRESS "back"
+
+struct audio_microphone_characteristic_t {
+ char device_id[AUDIO_MICROPHONE_ID_MAX_LEN];
+ audio_port_handle_t id;
+ audio_devices_t device;
+ char address[AUDIO_DEVICE_MAX_ADDRESS_LEN];
+ audio_microphone_channel_mapping_t channel_mapping[AUDIO_CHANNEL_COUNT_MAX];
+ audio_microphone_location_t location;
+ audio_microphone_group_t group;
+ unsigned int index_in_the_group;
+ float sensitivity;
+ float max_spl;
+ float min_spl;
+ audio_microphone_directionality_t directionality;
+ unsigned int num_frequency_responses;
+ float frequency_responses[2][AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES];
+ struct audio_microphone_coordinate geometric_location;
+ struct audio_microphone_coordinate orientation;
+};
+
+__END_DECLS
+
+/**
+ * List of known audio HAL modules. This is the base name of the audio HAL
+ * library composed of the "audio." prefix, one of the base names below and
+ * a suffix specific to the device.
+ * e.g: audio.primary.goldfish.so or audio.a2dp.default.so
+ *
+ * The same module names are used in audio policy configuration files.
+ */
+
+#define AUDIO_HARDWARE_MODULE_ID_PRIMARY "primary"
+#define AUDIO_HARDWARE_MODULE_ID_A2DP "a2dp"
+#define AUDIO_HARDWARE_MODULE_ID_USB "usb"
+#define AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX "r_submix"
+#define AUDIO_HARDWARE_MODULE_ID_CODEC_OFFLOAD "codec_offload"
+#define AUDIO_HARDWARE_MODULE_ID_STUB "stub"
+#define AUDIO_HARDWARE_MODULE_ID_HEARING_AID "hearing_aid"
+
+/**
+ * Multi-Stream Decoder (MSD) HAL service name. MSD HAL is used to mix
+ * encoded streams together with PCM streams, producing re-encoded
+ * streams or PCM streams.
+ *
+ * The service must register itself using this name, and audioserver
+ * tries to instantiate a device factory using this name as well.
+ * Note that the HIDL implementation library file name *must* have the
+ * suffix "msd" in order to be picked up by HIDL that is:
+ *
+ * android.hardware.audio@x.x-implmsd.so
+ */
+#define AUDIO_HAL_SERVICE_NAME_MSD "msd"
+
+/**
+ * Parameter definitions.
+ * Note that in the framework code it's recommended to use AudioParameter.h
+ * instead of these preprocessor defines, and for sure avoid just copying
+ * the constant values.
+ */
+
+#define AUDIO_PARAMETER_VALUE_ON "on"
+#define AUDIO_PARAMETER_VALUE_OFF "off"
+
+/**
+ * audio device parameters
+ */
+
+/* BT SCO Noise Reduction + Echo Cancellation parameters */
+#define AUDIO_PARAMETER_KEY_BT_NREC "bt_headset_nrec"
+
+/* Get a new HW synchronization source identifier.
+ * Return a valid source (positive integer) or AUDIO_HW_SYNC_INVALID if an error occurs
+ * or no HW sync is available. */
+#define AUDIO_PARAMETER_HW_AV_SYNC "hw_av_sync"
+
+/* Screen state */
+#define AUDIO_PARAMETER_KEY_SCREEN_STATE "screen_state"
+
+/**
+ * audio stream parameters
+ */
+
+#define AUDIO_PARAMETER_STREAM_ROUTING "routing" /* audio_devices_t */
+#define AUDIO_PARAMETER_STREAM_FORMAT "format" /* audio_format_t */
+#define AUDIO_PARAMETER_STREAM_CHANNELS "channels" /* audio_channel_mask_t */
+#define AUDIO_PARAMETER_STREAM_FRAME_COUNT "frame_count" /* size_t */
+#define AUDIO_PARAMETER_STREAM_INPUT_SOURCE "input_source" /* audio_source_t */
+#define AUDIO_PARAMETER_STREAM_SAMPLING_RATE "sampling_rate" /* uint32_t */
+
+/* Request the presentation id to be decoded by a next gen audio decoder */
+#define AUDIO_PARAMETER_STREAM_PRESENTATION_ID "presentation_id" /* int32_t */
+
+/* Request the program id to be decoded by a next gen audio decoder */
+#define AUDIO_PARAMETER_STREAM_PROGRAM_ID "program_id" /* int32_t */
+
+#define AUDIO_PARAMETER_DEVICE_CONNECT "connect" /* audio_devices_t */
+#define AUDIO_PARAMETER_DEVICE_DISCONNECT "disconnect" /* audio_devices_t */
+
+/* Enable mono audio playback if 1, else should be 0. */
+#define AUDIO_PARAMETER_MONO_OUTPUT "mono_output"
+
+/* Set the HW synchronization source for an output stream. */
+#define AUDIO_PARAMETER_STREAM_HW_AV_SYNC "hw_av_sync"
+
+/* Query supported formats. The response is a '|' separated list of strings from
+ * audio_format_t enum e.g: "sup_formats=AUDIO_FORMAT_PCM_16_BIT" */
+#define AUDIO_PARAMETER_STREAM_SUP_FORMATS "sup_formats"
+/* Query supported channel masks. The response is a '|' separated list of strings from
+ * audio_channel_mask_t enum e.g: "sup_channels=AUDIO_CHANNEL_OUT_STEREO|AUDIO_CHANNEL_OUT_MONO" */
+#define AUDIO_PARAMETER_STREAM_SUP_CHANNELS "sup_channels"
+/* Query supported sampling rates. The response is a '|' separated list of integer values e.g:
+ * "sup_sampling_rates=44100|48000" */
+#define AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES "sup_sampling_rates"
+
+#define AUDIO_PARAMETER_VALUE_LIST_SEPARATOR "|"
+
+/* Reconfigure offloaded A2DP codec */
+#define AUDIO_PARAMETER_RECONFIG_A2DP "reconfigA2dp"
+/* Query if HwModule supports reconfiguration of offloaded A2DP codec */
+#define AUDIO_PARAMETER_A2DP_RECONFIG_SUPPORTED "isReconfigA2dpSupported"
+
+/**
+ * audio codec parameters
+ */
+
+#define AUDIO_OFFLOAD_CODEC_PARAMS "music_offload_codec_param"
+#define AUDIO_OFFLOAD_CODEC_BIT_PER_SAMPLE "music_offload_bit_per_sample"
+#define AUDIO_OFFLOAD_CODEC_BIT_RATE "music_offload_bit_rate"
+#define AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE "music_offload_avg_bit_rate"
+#define AUDIO_OFFLOAD_CODEC_ID "music_offload_codec_id"
+#define AUDIO_OFFLOAD_CODEC_BLOCK_ALIGN "music_offload_block_align"
+#define AUDIO_OFFLOAD_CODEC_SAMPLE_RATE "music_offload_sample_rate"
+#define AUDIO_OFFLOAD_CODEC_ENCODE_OPTION "music_offload_encode_option"
+#define AUDIO_OFFLOAD_CODEC_NUM_CHANNEL "music_offload_num_channels"
+#define AUDIO_OFFLOAD_CODEC_DOWN_SAMPLING "music_offload_down_sampling"
+#define AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES "delay_samples"
+#define AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES "padding_samples"
+
+#endif // YOCTO_AUDIO_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/system/audio_utils/primitives.h b/src/multimedia/libspeech_drv/audio_big_sw/os/system/audio_utils/primitives.h
new file mode 100644
index 0000000..9d0aca1
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/system/audio_utils/primitives.h
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+ * Copyright (C) 2011 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 YOCTO_AUDIO_PRIMITIVES_H
+#define YOCTO_AUDIO_PRIMITIVES_H
+
+#include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+/**
+ * Clamp (aka hard limit or clip) a signed 32-bit sample to 16-bit range.
+ */
+#ifdef __cplusplus
+namespace android {
+#endif
+inline int16_t clamp16(int32_t sample)
+{
+ if ((sample>>15) ^ (sample>>31))
+ sample = 0x7FFF ^ (sample>>31);
+ return sample;
+}
+#ifdef __cplusplus
+} // end namespace android
+#endif
+#endif // YOCTO_AUDIO_PRIMITIVES_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/tinyalsa/asoundlib.h b/src/multimedia/libspeech_drv/audio_big_sw/os/tinyalsa/asoundlib.h
new file mode 100644
index 0000000..f352e4e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/tinyalsa/asoundlib.h
@@ -0,0 +1,306 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* asoundlib.h
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of The Android Open Source Project nor the names of
+** its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+** DAMAGE.
+*/
+
+#ifndef YOCTO_ASOUNDLIB_H
+#define YOCTO_ASOUNDLIB_H
+
+#include <sys/time.h>
+#include <stddef.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*
+ * PCM API
+ */
+
+struct pcm;
+
+#define PCM_OUT 0x00000000
+#define PCM_IN 0x10000000
+#define PCM_MMAP 0x00000001
+#define PCM_NOIRQ 0x00000002
+#define PCM_NORESTART 0x00000004 /* PCM_NORESTART - when set, calls to
+ * pcm_write for a playback stream will not
+ * attempt to restart the stream in the case
+ * of an underflow, but will return -EPIPE
+ * instead. After the first -EPIPE error, the
+ * stream is considered to be stopped, and a
+ * second call to pcm_write will attempt to
+ * restart the stream.
+ */
+#define PCM_MONOTONIC 0x00000008 /* see pcm_get_htimestamp */
+
+/* PCM runtime states */
+#define PCM_STATE_OPEN 0
+#define PCM_STATE_SETUP 1
+#define PCM_STATE_PREPARED 2
+#define PCM_STATE_RUNNING 3
+#define PCM_STATE_XRUN 4
+#define PCM_STATE_DRAINING 5
+#define PCM_STATE_PAUSED 6
+#define PCM_STATE_SUSPENDED 7
+#define PCM_STATE_DISCONNECTED 8
+
+/* Bit formats */
+enum pcm_format {
+ PCM_FORMAT_INVALID = -1,
+ PCM_FORMAT_S16_LE = 0, /* 16-bit signed */
+ PCM_FORMAT_S32_LE, /* 32-bit signed */
+ PCM_FORMAT_S8, /* 8-bit signed */
+ PCM_FORMAT_S24_LE, /* 24-bits in 4-bytes */
+ PCM_FORMAT_S24_3LE, /* 24-bits in 3-bytes */
+
+ PCM_FORMAT_MAX,
+};
+
+/* Bitmask has 256 bits (32 bytes) in asound.h */
+struct pcm_mask {
+ unsigned int bits[32 / sizeof(unsigned int)];
+};
+
+/* Configuration for a stream */
+struct pcm_config {
+ unsigned int channels;
+ unsigned int rate;
+ unsigned int period_size;
+ unsigned int period_count;
+ enum pcm_format format;
+
+ /* Values to use for the ALSA start, stop and silence thresholds. Setting
+ * any one of these values to 0 will cause the default tinyalsa values to be
+ * used instead. Tinyalsa defaults are as follows.
+ *
+ * start_threshold : period_count * period_size
+ * stop_threshold : period_count * period_size
+ * silence_threshold : 0
+ */
+ unsigned int start_threshold;
+ unsigned int stop_threshold;
+ unsigned int silence_threshold;
+
+ /* Minimum number of frames available before pcm_mmap_write() will actually
+ * write into the kernel buffer. Only used if the stream is opened in mmap mode
+ * (pcm_open() called with PCM_MMAP flag set). Use 0 for default.
+ */
+ int avail_min;
+};
+
+/* PCM parameters */
+enum pcm_param
+{
+ /* mask parameters */
+ PCM_PARAM_ACCESS,
+ PCM_PARAM_FORMAT,
+ PCM_PARAM_SUBFORMAT,
+ /* interval parameters */
+ PCM_PARAM_SAMPLE_BITS,
+ PCM_PARAM_FRAME_BITS,
+ PCM_PARAM_CHANNELS,
+ PCM_PARAM_RATE,
+ PCM_PARAM_PERIOD_TIME,
+ PCM_PARAM_PERIOD_SIZE,
+ PCM_PARAM_PERIOD_BYTES,
+ PCM_PARAM_PERIODS,
+ PCM_PARAM_BUFFER_TIME,
+ PCM_PARAM_BUFFER_SIZE,
+ PCM_PARAM_BUFFER_BYTES,
+ PCM_PARAM_TICK_TIME,
+};
+
+/* Mixer control types */
+enum mixer_ctl_type {
+ MIXER_CTL_TYPE_BOOL,
+ MIXER_CTL_TYPE_INT,
+ MIXER_CTL_TYPE_ENUM,
+ MIXER_CTL_TYPE_BYTE,
+ MIXER_CTL_TYPE_IEC958,
+ MIXER_CTL_TYPE_INT64,
+ MIXER_CTL_TYPE_UNKNOWN,
+
+ MIXER_CTL_TYPE_MAX,
+};
+
+/* Open and close a stream */
+struct pcm *pcm_open(unsigned int card, unsigned int device,
+ unsigned int flags, struct pcm_config *config);
+int pcm_close(struct pcm *pcm);
+int pcm_is_ready(struct pcm *pcm);
+
+/* Obtain the parameters for a PCM */
+struct pcm_params *pcm_params_get(unsigned int card, unsigned int device,
+ unsigned int flags);
+void pcm_params_free(struct pcm_params *pcm_params);
+
+struct pcm_mask *pcm_params_get_mask(struct pcm_params *pcm_params,
+ enum pcm_param param);
+unsigned int pcm_params_get_min(struct pcm_params *pcm_params,
+ enum pcm_param param);
+void pcm_params_set_min(struct pcm_params *pcm_params,
+ enum pcm_param param, unsigned int val);
+unsigned int pcm_params_get_max(struct pcm_params *pcm_params,
+ enum pcm_param param);
+void pcm_params_set_max(struct pcm_params *pcm_params,
+ enum pcm_param param, unsigned int val);
+
+/* Converts the pcm parameters to a human readable string.
+ * The string parameter is a caller allocated buffer of size bytes,
+ * which is then filled up to size - 1 and null terminated,
+ * if size is greater than zero.
+ * The return value is the number of bytes copied to string
+ * (not including null termination) if less than size; otherwise,
+ * the number of bytes required for the buffer.
+ */
+int pcm_params_to_string(struct pcm_params *params, char *string, unsigned int size);
+
+/* Returns 1 if the pcm_format is present (format bit set) in
+ * the pcm_params structure; 0 otherwise, or upon unrecognized format.
+ */
+int pcm_params_format_test(struct pcm_params *params, enum pcm_format format);
+
+/* Set and get config */
+int pcm_get_config(struct pcm *pcm, struct pcm_config *config);
+int pcm_set_config(struct pcm *pcm, struct pcm_config *config);
+
+/* Returns a human readable reason for the last error */
+const char *pcm_get_error(struct pcm *pcm);
+
+/* Returns the sample size in bits for a PCM format.
+ * As with ALSA formats, this is the storage size for the format, whereas the
+ * format represents the number of significant bits. For example,
+ * PCM_FORMAT_S24_LE uses 32 bits of storage.
+ */
+unsigned int pcm_format_to_bits(enum pcm_format format);
+
+/* Returns the buffer size (int frames) that should be used for pcm_write. */
+unsigned int pcm_get_buffer_size(struct pcm *pcm);
+unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames);
+unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes);
+
+/* Returns the pcm latency in ms */
+unsigned int pcm_get_latency(struct pcm *pcm);
+
+/* Returns available frames in pcm buffer and corresponding time stamp.
+ * The clock is CLOCK_MONOTONIC if flag PCM_MONOTONIC was specified in pcm_open,
+ * otherwise the clock is CLOCK_REALTIME.
+ * For an input stream, frames available are frames ready for the
+ * application to read.
+ * For an output stream, frames available are the number of empty frames available
+ * for the application to write.
+ */
+int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail,
+ struct timespec *tstamp);
+
+/* Write data to the fifo.
+ * Will start playback on the first write or on a write that
+ * occurs after a fifo underrun.
+ */
+int pcm_write(struct pcm *pcm, const void *data, unsigned int count);
+int pcm_read(struct pcm *pcm, void *data, unsigned int count);
+
+/*
+ * mmap() support.
+ */
+int pcm_mmap_write(struct pcm *pcm, const void *data, unsigned int count);
+int pcm_mmap_read(struct pcm *pcm, void *data, unsigned int count);
+int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset,
+ unsigned int *frames);
+int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames);
+
+/* Prepare the PCM substream to be triggerable */
+int pcm_prepare(struct pcm *pcm);
+/* Start and stop a PCM channel that doesn't transfer data */
+int pcm_start(struct pcm *pcm);
+int pcm_stop(struct pcm *pcm);
+
+/* ioctl function for PCM driver */
+int pcm_ioctl(struct pcm *pcm, int request, ...);
+
+/* Interrupt driven API */
+int pcm_wait(struct pcm *pcm, int timeout);
+
+/* Change avail_min after the stream has been opened with no need to stop the stream.
+ * Only accepted if opened with PCM_MMAP and PCM_NOIRQ flags
+ */
+int pcm_set_avail_min(struct pcm *pcm, int avail_min);
+
+/*
+ * MIXER API
+ */
+
+struct mixer;
+struct mixer_ctl;
+
+/* Open and close a mixer */
+struct mixer *mixer_open(unsigned int card);
+void mixer_close(struct mixer *mixer);
+
+/* Get info about a mixer */
+const char *mixer_get_name(struct mixer *mixer);
+
+/* Obtain mixer controls */
+unsigned int mixer_get_num_ctls(struct mixer *mixer);
+struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id);
+struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name);
+
+/* Get info about mixer controls */
+const char *mixer_ctl_get_name(struct mixer_ctl *ctl);
+enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl);
+const char *mixer_ctl_get_type_string(struct mixer_ctl *ctl);
+unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl);
+unsigned int mixer_ctl_get_num_enums(struct mixer_ctl *ctl);
+const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl,
+ unsigned int enum_id);
+
+/* Some sound cards update their controls due to external events,
+ * such as HDMI EDID byte data changing when an HDMI cable is
+ * connected. This API allows the count of elements to be updated.
+ */
+void mixer_ctl_update(struct mixer_ctl *ctl);
+
+/* Set and get mixer controls */
+int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id);
+int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent);
+
+int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id);
+int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count);
+int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value);
+int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count);
+int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string);
+
+/* Determe range of integer mixer controls */
+int mixer_ctl_get_range_min(struct mixer_ctl *ctl);
+int mixer_ctl_get_range_max(struct mixer_ctl *ctl);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/utils/Errors.h b/src/multimedia/libspeech_drv/audio_big_sw/os/utils/Errors.h
new file mode 100644
index 0000000..b31fdad
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/utils/Errors.h
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+* Copyright (C) 2014 MediaTek Inc.
+* Modification based on code covered by the mentioned copyright
+* and/or permission notice(s).
+*/
+/*
+ * Copyright (C) 2007 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 CAMELLIA_ERRORS_H
+#define CAMELLIA_ERRORS_H
+
+#include <sys/types.h>
+#include <errno.h>
+
+
+// use this type to return error codes
+#ifdef HAVE_MS_C_RUNTIME
+typedef int status_t;
+#else
+typedef int32_t status_t;
+#endif
+
+/* the MS C runtime lacks a few error codes */
+
+/*
+ * Error codes.
+ * All error codes are negative values.
+ */
+
+// Win32 #defines NO_ERROR as well. It has the same value, so there's no
+// real conflict, though it's a bit awkward.
+#ifdef _WIN32
+# undef NO_ERROR
+#endif
+
+enum {
+ OK = 0, // Everything's swell.
+ NO_ERROR = 0, // No errors.
+
+ UNKNOWN_ERROR = (-2147483647-1), // INT32_MIN value
+
+ NO_MEMORY = -ENOMEM,
+ INVALID_OPERATION = -ENOSYS,
+ BAD_VALUE = -EINVAL,
+ BAD_TYPE = (UNKNOWN_ERROR + 1),
+ NAME_NOT_FOUND = -ENOENT,
+ PERMISSION_DENIED = -EPERM,
+ NO_INIT = -ENODEV,
+ ALREADY_EXISTS = -EEXIST,
+ DEAD_OBJECT = -EPIPE,
+ FAILED_TRANSACTION = (UNKNOWN_ERROR + 2),
+ JPARKS_BROKE_IT = -EPIPE,
+#if !defined(HAVE_MS_C_RUNTIME)
+ BAD_INDEX = -EOVERFLOW,
+ NOT_ENOUGH_DATA = -ENODATA,
+ WOULD_BLOCK = -EWOULDBLOCK,
+ TIMED_OUT = -ETIMEDOUT,
+ UNKNOWN_TRANSACTION = -EBADMSG,
+#else
+ BAD_INDEX = -E2BIG,
+ NOT_ENOUGH_DATA = (UNKNOWN_ERROR + 3),
+ WOULD_BLOCK = (UNKNOWN_ERROR + 4),
+ TIMED_OUT = (UNKNOWN_ERROR + 5),
+ UNKNOWN_TRANSACTION = (UNKNOWN_ERROR + 6),
+#endif
+ FDS_NOT_ALLOWED = (UNKNOWN_ERROR + 7),
+#ifdef MTK_AOSP_ENHANCEMENT
+ NO_AUDIO_EFFECT = (UNKNOWN_ERROR + 0xFF),
+#endif
+};
+
+// Restore define; enumeration is in "android" namespace, so the value defined
+// there won't work for Win32 code in a different namespace.
+#ifdef _WIN32
+# define NO_ERROR 0L
+#endif
+
+
+// ---------------------------------------------------------------------------
+
+#endif // CAMELLIA_ERRORS_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/os/utils/Log.h b/src/multimedia/libspeech_drv/audio_big_sw/os/utils/Log.h
new file mode 100644
index 0000000..e96fab1
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/os/utils/Log.h
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef YOCTO_AUDIO_LOG_H
+#define YOCTO_AUDIO_LOG_H
+
+#include <log/log.h>
+
+//#define UT_LOG
+
+#ifdef ALOGD
+#undef ALOGD
+#define ALOGD SLOGD
+#endif
+#ifdef ALOGI
+#undef ALOGI
+#define ALOGI SLOGI
+#endif
+#ifdef ALOGW
+#undef ALOGW
+#define ALOGW SLOGW
+#endif
+#ifdef ALOGE
+#undef ALOGE
+#define ALOGE SLOGE
+#endif
+
+
+#ifdef ALOGV
+#undef ALOGV
+#endif
+
+#ifdef UT_LOG
+#define ALOGV ALOGD
+#else
+#define ALOGV
+#endif
+
+#ifndef AUD_LOG_VV
+#define AUD_LOG_VV ALOGV
+#endif
+
+#ifndef AUD_LOG_V
+#define AUD_LOG_V ALOGV
+#endif
+
+#ifndef AUD_LOG_D
+#define AUD_LOG_D ALOGD
+#endif
+
+#ifndef AUD_LOG_I
+#define AUD_LOG_I ALOGI
+#endif
+
+#ifndef AUD_LOG_W
+#define AUD_LOG_W ALOGW
+#endif
+
+#ifndef AUD_LOG_E
+#define AUD_LOG_E ALOGE
+#endif
+
+#endif /* end of YOCTO_AUDIO_LOG_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAANCController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAANCController.cpp
new file mode 100644
index 0000000..243ade0
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAANCController.cpp
@@ -0,0 +1,314 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAANCController.h"
+
+#include <sys/ioctl.h>
+#include <cutils/properties.h>
+
+#include <AudioLock.h>
+
+#include "AudioALSAHardwareResourceManager.h"
+#include "AudioALSADriverUtility.h"
+
+#include "AudioVolumeFactory.h"
+#include "AudioUtility.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSAANCController"
+
+namespace android {
+
+/*==============================================================================
+ * Property keys
+ *============================================================================*/
+
+
+/*==============================================================================
+ * Const Value
+ *============================================================================*/
+
+/*==============================================================================
+ * Enumerator
+ *============================================================================*/
+
+/*==============================================================================
+ * Singleton Pattern
+ *============================================================================*/
+
+AudioALSAANCController *AudioALSAANCController::mAudioALSAANCController = NULL;
+
+AudioALSAANCController *AudioALSAANCController::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSAANCController == NULL) {
+ mAudioALSAANCController = new AudioALSAANCController();
+ }
+ ASSERT(mAudioALSAANCController != NULL);
+ return mAudioALSAANCController;
+}
+
+/*==============================================================================
+ * Constructor / Destructor / Init / Deinit
+ *============================================================================*/
+
+AudioALSAANCController::AudioALSAANCController() :
+ mHardwareResourceManager(AudioALSAHardwareResourceManager::getInstance()),
+ //mAudioALSAVolumeController(AudioALSAVolumeController::getInstance()),
+ mEnable(false),
+ mIsFivePole(false),
+ mPcm(NULL),
+ mSpeakerEnabled(false),
+ mReceiverEnabled(false),
+ mHeadphoneSpeakerEnabled(false) {
+ ALOGD("%s()", __FUNCTION__);
+
+ mFd = ::open(kANCDevName, O_RDWR);
+
+ if (mFd < 0) {
+ ALOGE("%s() fail to open %s", __FUNCTION__, kANCDevName);
+ } else {
+ ALOGD("%s() open %s success!", __FUNCTION__, kANCDevName);
+
+ ::ioctl(mFd, SET_ANC_CONTROL, 0);
+ }
+
+ mMixer = AudioALSADriverUtility::getInstance()->getMixer();
+ ALOGD("mMixer = %p", mMixer);
+ ASSERT(mMixer != NULL);
+
+
+ // Use System propery
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_ANC_SWITCH, property_value, "1");
+ mSwitch = (bool)atoi(property_value);
+
+ RefreshEnabledDecision_l();
+}
+
+AudioALSAANCController::~AudioALSAANCController() {
+ ALOGD("%s()", __FUNCTION__);
+ if (mFd) {
+ ::close(mFd);
+ mFd = 0;
+ }
+}
+
+bool AudioALSAANCController::setANCSwitch(bool bSwitch) {
+ AL_AUTOLOCK(mLock);
+ ALOGD("%s() bSwitch=%d", __FUNCTION__, bSwitch);
+ mSwitch = bSwitch;
+ property_set(PROPERTY_ANC_SWITCH, mSwitch ? "1" : "0");
+
+ return RefreshEnabledDecision_l();
+}
+
+bool AudioALSAANCController::getANCSwitch() {
+ AL_AUTOLOCK(mLock);
+ ALOGD("%s() mSwitch=%d", __FUNCTION__, mSwitch);
+
+ return mSwitch;
+}
+
+bool AudioALSAANCController::setFivePole(bool isFivePole) {
+ AL_AUTOLOCK(mLock);
+ ALOGD("%s() isFivePole=%d", __FUNCTION__, isFivePole);
+ mIsFivePole = isFivePole;
+
+ return RefreshEnabledDecision_l();
+}
+
+bool AudioALSAANCController::setReceiverEnabled(bool bEnabled) {
+ AL_AUTOLOCK(mLock);
+ ALOGD("%s() bEnabled=%d", __FUNCTION__, bEnabled);
+ mReceiverEnabled = bEnabled;
+
+ return RefreshEnabledDecision_l();
+}
+
+bool AudioALSAANCController::setSpeakerEnabled(bool bEnabled) {
+ AL_AUTOLOCK(mLock);
+ ALOGD("%s() isFivePole=%d", __FUNCTION__, bEnabled);
+ mSpeakerEnabled = bEnabled;
+
+ return RefreshEnabledDecision_l();
+}
+
+bool AudioALSAANCController::setHeadphoneSpeakerEnabled(bool bEnabled) {
+ AL_AUTOLOCK(mLock);
+ ALOGD("%s() isFivePole=%d", __FUNCTION__, bEnabled);
+ mHeadphoneSpeakerEnabled = bEnabled;
+
+ return RefreshEnabledDecision_l();
+}
+
+bool AudioALSAANCController::getFivePole() {
+ ALOGD("%s() mIsFivePole=%d", __FUNCTION__, mIsFivePole);
+ AL_AUTOLOCK(mLock);
+
+ return mIsFivePole;
+}
+
+void AudioALSAANCController::setANCEnable(bool enable) {
+ ALOGD("%s() enable=%d", __FUNCTION__, enable);
+ AL_AUTOLOCK(mLock);
+
+ setANCEnable_l(enable);
+}
+
+void AudioALSAANCController::setANCEnable_l(bool enable) {
+ ALOGD("%s() enable=%d", __FUNCTION__, enable);
+ int kernelResult = -1;
+ if (enable) {
+ mHardwareResourceManager->startInputDevice(AUDIO_DEVICE_IN_WIRED_HEADSET);
+ ALOGD("%s(), mHardwareResourceManager->startInputDevice(AUDIO_DEVICE_IN_WIRED_HEADSET)", __FUNCTION__);
+
+#ifdef MTK_NEW_VOL_CONTROL
+ AudioMTKGainController::getInstance()->setANCEnable(true);
+#endif
+ AudioVolumeInterface *mAudioALSAVolumeController = AudioVolumeFactory::CreateAudioVolumeController();
+ mAudioALSAVolumeController->setMasterVolume(mAudioALSAVolumeController->getMasterVolume(),
+ AUDIO_MODE_CURRENT,
+ AUDIO_DEVICE_OUT_WIRED_HEADSET);
+ mAudioALSAVolumeController->SetCaptureGain(AUDIO_MODE_CURRENT, AUDIO_SOURCE_MIC, AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_OUT_WIRED_HEADSET);
+
+ load_coef_l();
+ upload_coef_l();
+ kernelResult = ::ioctl(mFd, SET_ANC_CONTROL, 81);
+ setHWEnable(true);
+ ALOGD("result %d", kernelResult);
+ } else {
+#ifdef MTK_NEW_VOL_CONTROL
+ AudioMTKGainController::getInstance()->setANCEnable(false);
+#endif
+ setHWEnable(false);
+ mHardwareResourceManager->stopInputDevice(AUDIO_DEVICE_IN_WIRED_HEADSET);
+ ALOGD("%s(), mHardwareResourceManager->stopInputDevice(AUDIO_DEVICE_IN_WIRED_HEADSET)", __FUNCTION__);
+
+ kernelResult = ::ioctl(mFd, SET_ANC_CONTROL, 82);
+ ALOGD("result %d", kernelResult);
+ }
+}
+
+
+bool AudioALSAANCController::RefreshEnabledDecision_l() {
+ ALOGD("%s() mEnable=%d mIsFivePole=%d mSwitch=%d reveiver=%d speaker=%d headphonespeaker=%d", __FUNCTION__,
+ mEnable, mIsFivePole, mSwitch, mReceiverEnabled, mSpeakerEnabled, mHeadphoneSpeakerEnabled);
+ bool newEnable = false;
+ bool isOtherDeviceEnabled = (mReceiverEnabled || mSpeakerEnabled || mHeadphoneSpeakerEnabled);
+
+ newEnable = (mIsFivePole && mSwitch);
+ newEnable = newEnable && !isOtherDeviceEnabled;
+
+ if (newEnable != mEnable) {
+ setANCEnable_l(newEnable);
+ }
+
+ mEnable = newEnable;
+ return mEnable;
+}
+
+void AudioALSAANCController::setHWEnable(bool enable) {
+ ALOGD("%s() enable=%d", __FUNCTION__, enable);
+ struct mixer_ctl *ctl;
+ enum mixer_ctl_type type;
+ unsigned int num_values, i ;
+ ctl = mixer_get_ctl_by_name(mMixer, "Audio_ANC_Switch");
+ type = mixer_ctl_get_type(ctl);
+ num_values = mixer_ctl_get_num_values(ctl);
+
+ if (mixer_ctl_set_enum_by_string(ctl, enable ? "On" : "Off")) {
+ ALOGE("Error: SetSpeakerGain invalid value");
+ }
+}
+
+/*==============================================================================
+ * ANC Control
+ *============================================================================*/
+
+int AudioALSAANCController::setCMD(int cmd) {
+ AL_AUTOLOCK(mLock);
+ int result;
+
+ ALOGD("%s(), CMD = %d", __FUNCTION__, cmd);
+ ALOGD("mFd=%d", mFd);
+
+ switch (cmd) {
+ case 90:
+ memset(anc_coef, 0x0, MAX_TABS * 4);
+ upload_coef_l();
+ cmd = 91;
+ break;
+ case 91:
+ load_coef_l();
+ upload_coef_l();
+ break;
+ case 810:
+ setANCEnable_l(true);
+ return 0;
+
+ break;
+ case 820:
+ setANCEnable_l(false);
+ return 0;
+
+ break;
+ }
+
+ ALOGD("%s(), CMD = %d", __FUNCTION__, cmd);
+ result = ::ioctl(mFd, SET_ANC_CONTROL, cmd);
+ ALOGD("result %d", result);
+ return 0;
+}
+
+bool AudioALSAANCController::getANCEnable() {
+ AL_AUTOLOCK(mLock);
+ ALOGD("+%s(), mEnable = %d =>", __FUNCTION__, mEnable);
+ return mEnable;
+}
+
+void AudioALSAANCController::download_binary() {
+ AL_AUTOLOCK(mLock);
+ ALOGD("+%s()", __FUNCTION__);
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+void AudioALSAANCController::load_coef_l() {
+ ALOGD("+%s()", __FUNCTION__);
+ int tmp_int;
+ FILE *fPtr;
+ fPtr = fopen("/etc/audio_anc_parm.txt", "r");
+ if (fPtr) {
+ for (int i = 0 ; i < MAX_TABS; i++) {
+ if (fscanf(fPtr, "%d", &tmp_int) > 0) {
+ anc_coef[i] = (int)tmp_int;
+ }
+ }
+ fclose(fPtr);
+ }
+ ALOGD("parameter: read done");
+ char tmp[1000];
+ char *cur = (char *)tmp;
+ for (int i = 0 ; i < MAX_TABS; i++) {
+ cur += sprintf((char *)cur, "%d, ", (int)anc_coef[i]);
+ }
+ cur[0] = '\0';
+
+ ALOGD("get parameter: %s", tmp);
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+void AudioALSAANCController::upload_coef_l() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ FILE *fPtr;
+ fPtr = fopen(kANCDevName, "w");
+ if (fPtr) {
+ fwrite(anc_coef, 1, MAX_TABS * 4, fPtr);
+ fclose(fPtr);
+ }
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataClient.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataClient.cpp
new file mode 100644
index 0000000..24ae009
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataClient.cpp
@@ -0,0 +1,2464 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureDataClient.h"
+
+#include "AudioUtility.h"
+
+#include "AudioType.h"
+#include <AudioLock.h>
+
+#include "AudioALSACaptureDataProviderBase.h"
+#include "AudioALSAHardware.h"
+#include "AudioALSAHardwareResourceManager.h"
+#include "AudioVolumeFactory.h"
+#include "SpeechEnhancementController.h"
+
+#include "audio_custom_exp.h"
+
+//BesRecord+++
+#include "AudioCustParamClient.h"
+#if (defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT) && (MTK_AUDIO_TUNING_TOOL_V2_PHASE >= 2))
+#include "AudioParamParser.h"
+#include <string>
+#endif
+//BesRecord---
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+#include "AudioDetectPulse.h"
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataClient"
+
+
+namespace android {
+#define MTK_STREAMIN_VOLUEM_MAX (0x1000)
+#define MTK_STREAMIN_VOLUME_VALID_BIT (12)
+
+//BesRecord+++
+#define VOICE_RECOGNITION_RECORD_SAMPLE_RATE (16000)
+#define HD_RECORD_SAMPLE_RATE (48000)
+#define NORMAL_RECORDING_DEFAULT_MODE (1)
+#define VOICE_REC_RECORDING_DEFAULT_MODE (0)
+#define VOICE_UnLock_RECORDING_DEFAULT_MODE (6)
+#define UNPROCESSED_MODE (26)
+#define FAST_CAPTURE_MODE (28)
+#define SRC_DROP_DATA
+#define ECHOREF_TIME_OFFSET (-4)
+#define DROP_HW_PALSE_TIMES (1)
+#ifndef DROP_MS_AFTER_BESRECORD_PROCESS
+#define DROP_MS_AFTER_BESRECORD_PROCESS 25
+#endif
+#define DROP_MS_FOR_UNPROCESSED_AUDIO_SOURCE 260
+
+//BesRecord---
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+static const uint32_t kClientBufferSize = 0x8000; // 32k
+
+/* Audio Type Declaration */
+#define VOIP_AUDIO_TYPE "VoIP"
+#define VOIPDMNR_AUDIO_TYPE "VoIPDMNR"
+#define VOIPGENERAL_AUDIO_TYPE "VoIPGeneral"
+#define RECORD_AUDIO_TYPE "Record"
+#define RECORDFIR_AUDIO_TYPE "RecordFIR"
+#define RECORDDMNR_AUDIO_TYPE "RecordDMNR"
+
+/* VoIP Categories Decleration */
+#define VOIP_HANDSET_DMNR_PATH "Profile,Handset 2mic NR"
+#define VOIP_HANDSET_NO_DMNR_PATH "Profile,Handset no 2mic NR"
+#define VOIP_3POLE_HEADSET_PATH "Profile,3-pole headset"
+#define VOIP_4POLE_HEADSET_PATH "Profile,4-pole headset"
+#define VOIP_5POLE_HEADSET_PATH "Profile,5-pole headset"
+#define VOIP_5POLE_HEADSET_ANC_PATH "Profile,5-pole headset+ANC"
+#define VOIP_BT_PATH "Profile,BT earphone"
+#define VOIP_BT_NSEC_OFF_PATH "Profile,BT_NREC_Off"
+#define VOIP_HANDSFREE_NR_PATH "Profile,Hands-free 1mic NR"
+#define VOIP_HANDSFREE_NO_NR_PATH "Profile,Hands-free no 1mic NR"
+#define VOIP_COMMON_PATH "CategoryLayer,Common"
+#define VOIP_NO_DMNR_PATH ""
+
+/* VoIP Parameter Decleration */
+#define VOIP_PARAM "voip_mode_para"
+#define VOIP_IN_FIR_PARAM "sph_in_fir"
+#define VOIP_OUT_FIR_PARAM "sph_out_fir"
+#define VOIP_DMNR_PARAM "dmnr_para"
+
+/* VoIPGeneral Category & Parameter Decleration*/
+#define VOIPGENERAL_COMMON_PATH "CategoryLayer,Common"
+#define VOIPGENERAL_PARAM_NAME "voip_common_para"
+
+/* Record Categories Decleration */
+#define RECORD_HANDSET_PATH "Profile,Handset"
+#define RECORD_4POLE_HEADSET_PATH "Profile,4-pole HS"
+#define RECORD_5POLE_HEADSET_PATH "Profile,5-pole HS"
+#define RECORD_5POLE_HEADSET_ANC_PATH "Profile,5-pole HS+ANC"
+#define RECORD_BT_PATH "Profile,BT earphone"
+#define RECORD_VR_PATH "Application,VR"
+#define RECORD_VOICE_UNLOCK_PATH "Application,VoiceUnLk"
+#define RECORD_ASR_PATH "Application,ASR"
+#define RECORD_SND_REC_NORMAL_PATH "Application,SndRecNormal"
+#define RECORD_SND_REC_LECTURE_PATH "Application,SndRecLecture"
+#define RECORD_SND_REC_MEETING_PATH "Application,SndRecMeeting"
+#define RECORD_CAM_REC_NORMAL_PATH "Application,CamRecNormal"
+#define RECORD_CAM_REC_MEETING_PATH "Application,CamRecMeeting"
+#define RECORD_CUSTOMIZATION2_PATH "Application,Customization2"
+#define RECORD_FAST_RECORD_PATH "Application,FastRecord"
+#define RECORD_UNPROCESSED_PATH "Application,Unprocessed"
+#define RECORD_NO_DMNR_PATH ""
+
+/* Record param */
+#define RECORD_PARAM "record_mode_para"
+#define RECORD_IN_FIR1_PARAM "sph_in_fir1"
+#define RECORD_IN_FIR2_PARAM "sph_in_fir2"
+#define RECORD_DMNR_PARAM "dmnr_para"
+
+/* Feature options */
+#define VOIP_NORMAL_DMNR_SUPPORT_FO "VIR_VOIP_NORMAL_DMNR_SUPPORT"
+#define VOIP_HANDSFREE_DMNR_SUPPORT_FO "VIR_VOIP_HANDSFREE_DMNR_SUPPORT"
+
+/* Key of parameters */
+static String8 keyANC_runing = String8("ANC_running");
+
+//debug++
+static bool bTempDebug = false;
+//debug--
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataClient::AudioALSACaptureDataClient(AudioALSACaptureDataProviderBase *pCaptureDataProvider, stream_attribute_t *stream_attribute_target) :
+ mCaptureDataProvider(pCaptureDataProvider),
+ mRawStartFrameCount(0),
+ mAudioSpeechEnhanceInfoInstance(AudioSpeechEnhanceInfo::getInstance()),
+ mStreamAttributeSource(mCaptureDataProvider->getStreamAttributeSource()),
+ mStreamAttributeTarget(stream_attribute_target),
+ mBliSrc(NULL),
+ mMicMute(false),
+ mMuteTransition(false),
+ mSPELayer(NULL),
+ mAudioALSAVolumeController(AudioVolumeFactory::CreateAudioVolumeController()),
+ mChannelRemixOp(CHANNEL_REMIX_NOP),
+ mBesRecTuningEnable(false),
+ //echoref+++
+ mCaptureDataProviderEchoRef(NULL),
+ mStreamAttributeSourceEchoRef(NULL),
+ mStreamAttributeTargetEchoRef(NULL),
+ mBliSrcEchoRef(NULL),
+ mBliSrcEchoRefBesRecord(NULL)
+ //echoref---
+{
+ ALOGD("%s()", __FUNCTION__);
+
+ // init member struct
+ memset((void *)&mEchoRefRawDataBuf, 0, sizeof(mEchoRefRawDataBuf));
+ memset((void *)&mEchoRefSrcDataBuf, 0, sizeof(mEchoRefSrcDataBuf));
+
+ // raw data
+ memset((void *)&mRawDataBuf, 0, sizeof(mRawDataBuf));
+ mRawDataBuf.pBufBase = new char[kClientBufferSize];
+ mRawDataBuf.bufLen = kClientBufferSize;
+ mRawDataBuf.pRead = mRawDataBuf.pBufBase;
+ mRawDataBuf.pWrite = mRawDataBuf.pBufBase;
+ ASSERT(mRawDataBuf.pBufBase != NULL);
+
+ // src data
+ memset((void *)&mSrcDataBuf, 0, sizeof(mSrcDataBuf));
+ mSrcDataBuf.pBufBase = new char[kClientBufferSize];
+ mSrcDataBuf.bufLen = kClientBufferSize;
+ mSrcDataBuf.pRead = mSrcDataBuf.pBufBase;
+ mSrcDataBuf.pWrite = mSrcDataBuf.pBufBase;
+ ASSERT(mSrcDataBuf.pBufBase != NULL);
+
+ // processed data
+ memset((void *)&mProcessedDataBuf, 0, sizeof(mProcessedDataBuf));
+ mProcessedDataBuf.pBufBase = new char[kClientBufferSize];
+ mProcessedDataBuf.bufLen = kClientBufferSize;
+ mProcessedDataBuf.pRead = mProcessedDataBuf.pBufBase;
+ mProcessedDataBuf.pWrite = mProcessedDataBuf.pBufBase;
+ ASSERT(mProcessedDataBuf.pBufBase != NULL);
+
+ //TODO: Sam, move here for temp
+ //BesRecord+++
+#if (!defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT) || (MTK_AUDIO_TUNING_TOOL_V2_PHASE == 1))
+ memset((void *)&mBesRecordSceneTable, 0, sizeof(mBesRecordSceneTable));
+ memset((void *)&mBesRecordParam, 0, sizeof(mBesRecordParam));
+
+ mBesRecordModeIndex = -1;
+ mBesRecordSceneIndex = -1;
+#endif
+ mBesRecordStereoMode = false;
+ mBypassBesRecord = false;
+ mNeedBesRecordSRC = false;
+ mBliSrcHandler1 = NULL;
+ mBliSrcHandler2 = NULL;
+ mBesRecSRCSizeFactor = 1;
+ mBesRecSRCSizeFactor2 = 1;
+ dropBesRecordDataSize = 0;
+ mFirstSRC = true;
+ mFirstEchoSRC = true;
+ mDropMs = 0;
+
+ mSpeechProcessMode = SPE_MODE_REC;
+ mVoIPSpeechEnhancementMask = mStreamAttributeTarget->BesRecord_Info.besrecord_dynamic_mask;
+
+ //BesRecord Config
+ mSPELayer = new SPELayer();
+ if (!mSPELayer) {
+ ALOGE("new SPELayer() FAIL");
+ ASSERT(mSPELayer != NULL);
+ }
+ mAudioCustParamClient = NULL;
+ mAudioCustParamClient = AudioCustParamClient::GetInstance();
+
+ SetCaptureGain();
+ ALOGD("%s(), besrecord_enable=%d, besrecord_scene=%d", __FUNCTION__, mStreamAttributeTarget->BesRecord_Info.besrecord_enable,
+ mStreamAttributeTarget->BesRecord_Info.besrecord_scene);
+ if (mStreamAttributeTarget->BesRecord_Info.besrecord_enable) {
+ LoadBesRecordParams();
+
+ mSPELayer->SetVMDumpEnable(mStreamAttributeTarget->BesRecord_Info.besrecord_tuningEnable || mStreamAttributeTarget->BesRecord_Info.besrecord_dmnr_tuningEnable);
+ mSPELayer->SetVMDumpFileName(mStreamAttributeTarget->BesRecord_Info.besrecord_VMFileName);
+ mSPELayer->SetPlatfromTimeOffset(ECHOREF_TIME_OFFSET); //Default -4ms EchoRef data
+
+ CheckBesRecordBypass();
+ CheckBesRecordMode();
+ ConfigBesRecordParams();
+ StartBesRecord();
+ if (stream_attribute_target->BesRecord_Info.besrecord_voip_enable == true) {
+ // drop data size need to align interrupt rate
+ if (getLatencyTime() < DROP_MS_AFTER_BESRECORD_PROCESS) {
+ mDropMs = (DROP_MS_AFTER_BESRECORD_PROCESS % getLatencyTime() == 0) ? DROP_MS_AFTER_BESRECORD_PROCESS : ((DROP_MS_AFTER_BESRECORD_PROCESS / getLatencyTime()) + DROP_HW_PALSE_TIMES) * getLatencyTime();
+ }
+ dropBesRecordDataSize = (stream_attribute_target->sample_rate / 1000) * mDropMs * stream_attribute_target->num_channels * audio_bytes_per_sample(stream_attribute_target->audio_format);
+ } else {
+ dropBesRecordDataSize = (stream_attribute_target->sample_rate / 1000) * DROP_MS_AFTER_BESRECORD_PROCESS * stream_attribute_target->num_channels * audio_bytes_per_sample(stream_attribute_target->audio_format);
+ }
+
+ ALOGD("sample rate = %d, drop ms = %d, channels = %d, byts per sample = %zu, dropBesRecordDataSize = %d\n",
+ stream_attribute_target->sample_rate, DROP_MS_AFTER_BESRECORD_PROCESS, stream_attribute_target->num_channels, audio_bytes_per_sample(stream_attribute_target->audio_format), dropBesRecordDataSize);
+ } else {
+ if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_UNPROCESSED)
+ {
+ /* For unprocess test, we have to drop these glitch data to avoid the max RMS over the upper bound */
+ dropBesRecordDataSize = (stream_attribute_target->sample_rate / 1000) * DROP_MS_FOR_UNPROCESSED_AUDIO_SOURCE * stream_attribute_target->num_channels * audio_bytes_per_sample(stream_attribute_target->audio_format);
+ }
+ CheckBesRecordStereoModeEnable();
+ }
+
+ //BesRecord---
+ //Android Native Preprocess effect +++
+ mAudioPreProcessEffect = NULL;
+ mAudioPreProcessEffect = new AudioPreProcess(mStreamAttributeTarget);
+ if (!mAudioPreProcessEffect) {
+ ALOGE("new mAudioPreProcessEffect() FAIL");
+ ASSERT(mAudioPreProcessEffect != NULL);
+ }
+ CheckNativeEffect();
+ //Android Native Preprocess effect ---
+
+ // attach client to capture data provider
+ ALOGV("mCaptureDataProvider=%p", mCaptureDataProvider);
+ mCaptureDataProvider->configStreamAttribute(mStreamAttributeTarget); // config attribute for input device
+ mCaptureDataProvider->attach(this); // mStreamAttributeSource will be updated when first client attached
+
+ //assume starts after PCM open
+ mSPELayer->SetUPLinkDropTime(CAPTURE_DROP_MS);
+
+ // init SRC
+ if (mStreamAttributeSource->sample_rate != mStreamAttributeTarget->sample_rate) {
+ ALOGD("sample_rate: %d => %d, num_channels: %d => %d, audio_format: 0x%x => 0x%x",
+ mStreamAttributeSource->sample_rate, mStreamAttributeTarget->sample_rate,
+ mStreamAttributeSource->num_channels, mStreamAttributeSource->num_channels,
+ mStreamAttributeSource->audio_format, mStreamAttributeTarget->audio_format);
+
+ SRC_PCM_FORMAT SrcFormat = mStreamAttributeTarget->audio_format == AUDIO_FORMAT_PCM_16_BIT ? SRC_IN_Q1P15_OUT_Q1P15 : SRC_IN_Q1P31_OUT_Q1P31;
+ mBliSrc = newMtkAudioSrc(
+ mStreamAttributeSource->sample_rate, mStreamAttributeSource->num_channels,
+ mStreamAttributeTarget->sample_rate, mStreamAttributeSource->num_channels,
+ SrcFormat);
+ mBliSrc->open();
+ }
+ if (mStreamAttributeTarget->BesRecord_Info.besrecord_enable) {
+ //move CheckNeedBesRecordSRC to here for mStreamAttributeSource info
+ CheckNeedBesRecordSRC();
+ }
+
+ CheckChannelRemixOp();
+ //debug++
+ bTempDebug = mAudioSpeechEnhanceInfoInstance->GetDebugStatus();
+ //debug--
+}
+
+AudioALSACaptureDataClient::~AudioALSACaptureDataClient() {
+ ALOGD("%s()", __FUNCTION__);
+
+ //EchoRef+++
+ if (mCaptureDataProviderEchoRef != NULL) {
+ ALOGD("%s(), remove EchoRef data provider,mCaptureDataProviderEchoRef=%p", __FUNCTION__, mCaptureDataProviderEchoRef);
+ mSPELayer->SetOutputStreamRunning(false, true);
+ mCaptureDataProviderEchoRef->detach(this);
+ if (mEchoRefRawDataBuf.pBufBase != NULL) { delete[] mEchoRefRawDataBuf.pBufBase; }
+
+ if (mEchoRefSrcDataBuf.pBufBase != NULL) { delete[] mEchoRefSrcDataBuf.pBufBase; }
+ }
+
+ if (mBliSrcEchoRef != NULL) {
+ mBliSrcEchoRef->close();
+ deleteMtkAudioSrc(mBliSrcEchoRef);
+ mBliSrcEchoRef = NULL;
+ }
+
+ if (mBliSrcEchoRefBesRecord != NULL) {
+ mBliSrcEchoRefBesRecord->close();
+ deleteMtkAudioSrc(mBliSrcEchoRefBesRecord);
+ mBliSrcEchoRefBesRecord = NULL;
+ }
+ //EchoRef---
+
+ mCaptureDataProvider->detach(this);
+
+ if (mRawDataBuf.pBufBase != NULL) { delete[] mRawDataBuf.pBufBase; }
+
+ if (mSrcDataBuf.pBufBase != NULL) { delete[] mSrcDataBuf.pBufBase; }
+
+ if (mProcessedDataBuf.pBufBase != NULL) { delete[] mProcessedDataBuf.pBufBase; }
+
+ if (mBliSrc != NULL) {
+ mBliSrc->close();
+ deleteMtkAudioSrc(mBliSrc);
+ mBliSrc = NULL;
+ }
+
+ //TODO: Sam, add here for temp
+ //BesRecord+++
+ StopBesRecord();
+ if (mBliSrcHandler1) {
+ mBliSrcHandler1->close();
+ deleteMtkAudioSrc(mBliSrcHandler1);
+ mBliSrcHandler1 = NULL;
+ }
+
+ if (mBliSrcHandler2) {
+ mBliSrcHandler2->close();
+ deleteMtkAudioSrc(mBliSrcHandler2);
+ mBliSrcHandler2 = NULL;
+ }
+ if (mSPELayer != NULL) { delete mSPELayer; }
+ //BesRecord---
+
+ //Android Native Preprocess effect +++
+ if (mAudioPreProcessEffect != NULL) { delete mAudioPreProcessEffect; }
+ //Android Native Preprocess effect ---
+
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+
+uint32_t AudioALSACaptureDataClient::copyCaptureDataToClient(RingBuf pcm_read_buf) {
+ ALOGV("+%s()", __FUNCTION__);
+ //debug++
+ if (bTempDebug) {
+ ALOGD("%s()+", __FUNCTION__);
+ }
+ //debug--
+
+ AL_LOCK(mLock);
+
+ uint32_t freeSpace = RingBuf_getFreeSpace(&mRawDataBuf);
+ uint32_t dataSize = RingBuf_getDataCount(&pcm_read_buf);
+ if (freeSpace < dataSize) {
+ ALOGE("%s(), mRawDataBuf <= pcm_read_buf, freeSpace(%u) < dataSize(%u), buffer overflow!!", __FUNCTION__, freeSpace, dataSize);
+ RingBuf_copyFromRingBuf(&mRawDataBuf, &pcm_read_buf, freeSpace);
+ } else {
+ RingBuf_copyFromRingBuf(&mRawDataBuf, &pcm_read_buf, dataSize);
+ }
+
+ // SRC
+ uint32_t kNumRawData = RingBuf_getDataCount(&mRawDataBuf); //mRawDataBuf has data with mStreamAttributeSource sample rate
+ uint32_t num_free_space = RingBuf_getFreeSpace(&mSrcDataBuf); //mSrcDataBuf has data with mStreamAttributeTarget sample rate
+
+ //BesRecord PreProcess effect
+ if (((mStreamAttributeTarget->BesRecord_Info.besrecord_enable) && !mBypassBesRecord)) {
+ char *pRawDataLinearBuf = new char[kNumRawData];
+ RingBuf_copyToLinear(pRawDataLinearBuf, &mRawDataBuf, kNumRawData);
+ if (mStreamAttributeSource->audio_format != AUDIO_FORMAT_PCM_16_BIT) {
+ kNumRawData = TransferFormat(pRawDataLinearBuf, mStreamAttributeSource->audio_format, AUDIO_FORMAT_PCM_16_BIT, kNumRawData);
+ }
+#ifdef MTK_LATENCY_DETECT_PULSE
+ AudioDetectPulse::doDetectPulse(TAG_CAPTURE_DATA_CLIENT3, PULSE_LEVEL, 0, (void *)pRawDataLinearBuf,
+ kNumRawData, mStreamAttributeSource->audio_format,
+ mStreamAttributeSource->num_channels, mStreamAttributeSource->sample_rate);
+#endif
+ uint32_t ProcesseddataSize = kNumRawData;
+ uint32_t SRC1outputLength = kNumRawData * mBesRecSRCSizeFactor;
+ char *pSRC1DataLinearBuf = new char[SRC1outputLength];
+
+ char *p_read = pRawDataLinearBuf;
+ uint32_t num_raw_data_left = kNumRawData;
+ uint32_t num_converted_data = SRC1outputLength;
+ uint32_t consumed = num_raw_data_left;
+
+ //transform data format to BesRecord needed
+ if (mNeedBesRecordSRC && (mBliSrcHandler1 != 0)) {
+ mBliSrcHandler1->process((int16_t *)p_read, &num_raw_data_left,
+ (int16_t *)pSRC1DataLinearBuf, &num_converted_data);
+ consumed -= num_raw_data_left;
+
+ p_read += consumed;
+ ALOGV("%s(), num_raw_data_left = %u, num_converted_data = %u",
+ __FUNCTION__, num_raw_data_left, num_converted_data);
+#ifdef SRC_DROP_DATA
+ //Drop first SRC data to let buffer align
+ if ((mStreamAttributeTarget->BesRecord_Info.besrecord_voip_enable) && mFirstSRC) {
+ mFirstSRC = false;
+ delete[] pRawDataLinearBuf;
+ delete[] pSRC1DataLinearBuf;
+ AL_SIGNAL(mLock);
+ AL_UNLOCK(mLock);
+
+ return 0;
+ }
+#endif
+
+ //ASSERT(num_raw_data_left == 0);
+ if (num_raw_data_left > 0) {
+ ALOGW("%s(), BesRecordSRC1 num_raw_data_left(%u) > 0", __FUNCTION__, num_raw_data_left);
+ }
+
+ ProcesseddataSize = BesRecordPreprocess(pSRC1DataLinearBuf, num_converted_data);
+
+ if (ProcesseddataSize == 0) {
+ delete[] pRawDataLinearBuf;
+ delete[] pSRC1DataLinearBuf;
+ AL_SIGNAL(mLock);
+ AL_UNLOCK(mLock);
+
+ ALOGD("-%s(), no BesRecordPreprocess data", __FUNCTION__);
+ return 0;
+ }
+
+ //transform data format back to StreamAttribue needed after BesRecord process
+ if (mBliSrcHandler2 != 0) {
+ uint32_t SRC2outputLength = ProcesseddataSize * mBesRecSRCSizeFactor2;
+ char *pSRC2DataLinearBuf = new char[SRC2outputLength];
+
+ p_read = pSRC1DataLinearBuf;
+ num_raw_data_left = ProcesseddataSize;
+ consumed = ProcesseddataSize;
+
+ mBliSrcHandler2->process((int16_t *)p_read, &num_raw_data_left,
+ (int16_t *)pSRC2DataLinearBuf, &SRC2outputLength);
+
+ consumed -= num_raw_data_left;
+
+ p_read += consumed;
+ ALOGV("%s(), num_raw_data_left = %u, SRC2outputLength = %u",
+ __FUNCTION__, num_raw_data_left, SRC2outputLength);
+
+ //ASSERT(num_raw_data_left == 0);
+ if (num_raw_data_left > 0) {
+ ALOGW("%s(), BesRecord1 SRC2 num_raw_data_left(%u) > 0", __FUNCTION__, num_raw_data_left);
+ }
+
+ if (num_free_space < SRC2outputLength) {
+ ALOGE("%s(), BesRecord1 SRC2outputLength <= mSrcDataBuf num_free_space, num_free_space(%u) < SRC2outputLength(%u), buffer overflow!!", __FUNCTION__, num_free_space, SRC2outputLength);
+ RingBuf_copyFromLinear(&mSrcDataBuf, pSRC2DataLinearBuf, num_free_space);
+ } else {
+ RingBuf_copyFromLinear(&mSrcDataBuf, pSRC2DataLinearBuf, SRC2outputLength);
+ }
+
+ delete[] pSRC2DataLinearBuf;
+ } else {
+ if (num_free_space < ProcesseddataSize) {
+ ALOGE("%s(), BesRecord1 mProcessedDataBuf <= mSrcDataBuf, num_free_space(%u) < ProcesseddataSize(%u), buffer overflow!!", __FUNCTION__, num_free_space, ProcesseddataSize);
+ RingBuf_copyFromLinear(&mSrcDataBuf, pSRC1DataLinearBuf, num_free_space);
+ } else {
+ RingBuf_copyFromLinear(&mSrcDataBuf, pSRC1DataLinearBuf, ProcesseddataSize);
+ }
+ }
+ } else { //no need to tranform data format to BesRecord needed
+ ProcesseddataSize = BesRecordPreprocess(pRawDataLinearBuf, kNumRawData);
+
+ if (ProcesseddataSize == 0) {
+ delete[] pRawDataLinearBuf;
+ delete[] pSRC1DataLinearBuf;
+ AL_SIGNAL(mLock);
+ AL_UNLOCK(mLock);
+ ALOGD("-%s(), no BesRecordPreprocess 2 data", __FUNCTION__);
+ return 0;
+ }
+
+ //transform data format back to StreamAttribue needed after BesRecord processed
+ if (mBliSrcHandler2 != 0) {
+ uint32_t SRC2outputLength = ProcesseddataSize * mBesRecSRCSizeFactor2;
+ char *pSRC2DataLinearBuf = new char[SRC2outputLength];
+
+ p_read = pRawDataLinearBuf;
+ num_raw_data_left = ProcesseddataSize;
+ consumed = ProcesseddataSize;
+
+ mBliSrcHandler2->process((int16_t *)p_read, &num_raw_data_left,
+ (int16_t *)pSRC2DataLinearBuf, &SRC2outputLength);
+
+ consumed -= num_raw_data_left;
+
+ p_read += consumed;
+ ALOGV("%s(), num_raw_data_left = %u, SRC2outputLength = %u",
+ __FUNCTION__, num_raw_data_left, SRC2outputLength);
+
+ //ASSERT(num_raw_data_left == 0);
+ if (num_raw_data_left > 0) {
+ ALOGW("%s(), BesRecord2 SRC2 num_raw_data_left(%u) > 0", __FUNCTION__, num_raw_data_left);
+ }
+
+ if (num_free_space < SRC2outputLength) {
+ ALOGE("%s(), BesRecord2 SRC2outputLength <= mSrcDataBuf num_free_space, num_free_space(%u) < SRC2outputLength(%u), buffer overflow!!", __FUNCTION__, num_free_space, SRC2outputLength);
+ RingBuf_copyFromLinear(&mSrcDataBuf, pSRC2DataLinearBuf, num_free_space);
+ } else {
+ RingBuf_copyFromLinear(&mSrcDataBuf, pSRC2DataLinearBuf, SRC2outputLength);
+ }
+
+ delete[] pSRC2DataLinearBuf;
+ } else {
+ if (num_free_space < ProcesseddataSize) {
+ ALOGE("%s(), BesRecord2 mProcessedDataBuf <= mSrcDataBuf, num_free_space(%u) < ProcesseddataSize(%u), buffer overflow!!", __FUNCTION__, num_free_space, ProcesseddataSize);
+ RingBuf_copyFromLinear(&mSrcDataBuf, pRawDataLinearBuf, num_free_space);
+ } else {
+ RingBuf_copyFromLinear(&mSrcDataBuf, pRawDataLinearBuf, ProcesseddataSize);
+ }
+ }
+ }
+
+ delete[] pRawDataLinearBuf;
+ delete[] pSRC1DataLinearBuf;
+ } else { //no need to do BesRecord PreProcess, transform data to mStreamAttributeTarget format
+ if (mBliSrc == NULL) { // No need SRC
+ if (mStreamAttributeTarget->audio_format != mStreamAttributeSource->audio_format) {
+ char *pRawDataLinearBuf = new char[kNumRawData];
+ RingBuf_copyToLinear(pRawDataLinearBuf, &mRawDataBuf, kNumRawData);
+ kNumRawData = TransferFormat(pRawDataLinearBuf, mStreamAttributeSource->audio_format, mStreamAttributeTarget->audio_format, kNumRawData);
+#ifdef MTK_LATENCY_DETECT_PULSE
+ AudioDetectPulse::doDetectPulse(TAG_CAPTURE_DATA_CLIENT2, PULSE_LEVEL, 0, (void *)pRawDataLinearBuf,
+ kNumRawData, mStreamAttributeSource->audio_format,
+ mStreamAttributeSource->num_channels, mStreamAttributeSource->sample_rate);
+#endif
+ //ASSERT(num_free_space >= kNumRawData);
+ if (num_free_space < kNumRawData) {
+ ALOGW("%s(), num_free_space(%u) < kNumRawData(%u)", __FUNCTION__, num_free_space, kNumRawData);
+ RingBuf_copyFromLinear(&mSrcDataBuf, pRawDataLinearBuf, num_free_space);
+ } else {
+ RingBuf_copyFromLinear(&mSrcDataBuf, pRawDataLinearBuf, kNumRawData);
+ }
+ delete[] pRawDataLinearBuf;
+ } else {
+ if (num_free_space < kNumRawData) {
+ ALOGW("%s(), num_free_space(%u) < kNumRawData(%u)", __FUNCTION__, num_free_space, kNumRawData);
+ RingBuf_copyFromRingBuf(&mSrcDataBuf, &mRawDataBuf, num_free_space);
+ } else {
+ RingBuf_copyFromRingBuf(&mSrcDataBuf, &mRawDataBuf, kNumRawData);
+ }
+ }
+ } else { // Need SRC
+ char *pRawDataLinearBuf = new char[kNumRawData];
+ RingBuf_copyToLinear(pRawDataLinearBuf, &mRawDataBuf, kNumRawData);
+
+ char *pSrcDataLinearBuf = new char[num_free_space];
+ char *p_read = pRawDataLinearBuf;
+ uint32_t num_raw_data_left = kNumRawData;
+ uint32_t num_converted_data = num_free_space; // max convert num_free_space
+ uint32_t consumed = num_raw_data_left;
+
+ if (mStreamAttributeTarget->audio_format == AUDIO_FORMAT_PCM_16_BIT) {
+ if (mStreamAttributeSource->audio_format != mStreamAttributeTarget->audio_format) { //8+24 to 16 bit
+ num_raw_data_left = TransferFormat(pRawDataLinearBuf, mStreamAttributeSource->audio_format, mStreamAttributeTarget->audio_format, num_raw_data_left);
+ }
+ mBliSrc->process((int16_t *)p_read, &num_raw_data_left,
+ (int16_t *)pSrcDataLinearBuf, &num_converted_data);
+ } else {
+ mBliSrc->process((int32_t *)p_read, &num_raw_data_left,
+ (int32_t *)pSrcDataLinearBuf, &num_converted_data);
+
+ if (mStreamAttributeSource->audio_format != mStreamAttributeTarget->audio_format) { //8+24 to 24 bit
+ num_converted_data = TransferFormat(pSrcDataLinearBuf, mStreamAttributeSource->audio_format, mStreamAttributeTarget->audio_format, num_converted_data);
+ }
+ }
+
+ consumed -= num_raw_data_left;
+ p_read += consumed;
+ ALOGV("%s(), num_raw_data_left = %u, num_converted_data = %u", __FUNCTION__, num_raw_data_left, num_converted_data);
+
+ //ASSERT(num_raw_data_left == 0);
+ if (num_raw_data_left > 0) {
+ ALOGW("%s(), num_raw_data_left(%u) > 0", __FUNCTION__, num_raw_data_left);
+ }
+
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+ AudioDetectPulse::doDetectPulse(TAG_CAPTURE_DATA_CLIENT1, PULSE_LEVEL, 0, (void *)pSrcDataLinearBuf,
+ num_converted_data, mStreamAttributeSource->audio_format,
+ mStreamAttributeSource->num_channels, mStreamAttributeSource->sample_rate);
+#endif
+ RingBuf_copyFromLinear(&mSrcDataBuf, pSrcDataLinearBuf, num_converted_data);
+ ALOGV("%s(), dataCount:%u", __FUNCTION__, RingBuf_getDataCount(&mSrcDataBuf));
+
+ delete[] pRawDataLinearBuf;
+ delete[] pSrcDataLinearBuf;
+ }
+ }
+
+ freeSpace = RingBuf_getFreeSpace(&mProcessedDataBuf);
+ dataSize = RingBuf_getDataCount(&mSrcDataBuf);
+ uint32_t ProcessdataSize = dataSize;
+
+ //android native effect, use the same sample rate as mStreamAttributeTarget
+ //Native Preprocess effect+++
+ if ((mAudioPreProcessEffect->num_preprocessors > 0) && (IsVoIPEnable() == false)) {
+ char *pSrcDataLinearBuf = new char[dataSize];
+ uint32_t native_processed_byte = 0;
+ RingBuf_copyToLinear(pSrcDataLinearBuf, &mSrcDataBuf, dataSize);
+
+ if (IsNeedChannelRemix()) {
+ ProcessdataSize = ApplyChannelRemix((short *)pSrcDataLinearBuf, dataSize);
+ }
+
+ native_processed_byte = NativePreprocess(pSrcDataLinearBuf, ProcessdataSize);
+
+ if (freeSpace < native_processed_byte) {
+ ALOGE("%s(), NativeProcess mProcessedDataBuf <= mSrcDataBuf, freeSpace(%u) < native_processed size(%u), buffer overflow!!", __FUNCTION__, native_processed_byte, dataSize);
+ RingBuf_copyFromLinear(&mProcessedDataBuf, pSrcDataLinearBuf, freeSpace);
+ } else {
+ RingBuf_copyFromLinear(&mProcessedDataBuf, pSrcDataLinearBuf, native_processed_byte);
+ }
+
+ delete[] pSrcDataLinearBuf;
+ }
+ //Native Preprocess effect---
+ else { //no need to do native effect, copy data from mSrcDataBuf to mProcessedDataBuf directly
+ if (IsNeedChannelRemix()) {
+ ApplyChannelRemixWithRingBuf(&mSrcDataBuf, &mProcessedDataBuf);
+ } else {
+ if (freeSpace < dataSize) {
+ ALOGE("%s(), mProcessedDataBuf <= mSrcDataBuf, freeSpace(%u) < dataSize(%u), buffer overflow!!",
+ __FUNCTION__, freeSpace, dataSize);
+ RingBuf_copyFromRingBuf(&mProcessedDataBuf, &mSrcDataBuf, freeSpace);
+ } else {
+ RingBuf_copyFromRingBuf(&mProcessedDataBuf, &mSrcDataBuf, dataSize);
+ }
+ }
+ }
+
+ AL_SIGNAL(mLock);
+ AL_UNLOCK(mLock);
+
+ ALOGV("-%s()", __FUNCTION__);
+ //debug++
+ if (bTempDebug) {
+ ALOGD("%s()-", __FUNCTION__);
+ }
+ //debug--
+ return 0;
+}
+
+ssize_t AudioALSACaptureDataClient::read(void *buffer, ssize_t bytes) {
+ ALOGV("+%s(), bytes=%zu", __FUNCTION__, bytes);
+ //debug++
+ if (bTempDebug) {
+ ALOGD("+%s(), bytes=%zu", __FUNCTION__, bytes);
+ }
+ //debug--
+
+ char *pWrite = (char *)buffer;
+ char *pStart = (char *)buffer;
+ uint32_t RingBufferSize = 0;
+ uint32_t ReadDataBytes = bytes;
+
+ int TryCount = 8;
+
+
+ // clean buffer
+ memset(buffer, 0, bytes);
+
+ do {
+ AL_LOCK(mLock);
+ //debug++
+ if (bTempDebug) {
+ ALOGD("%s(), TryCount=%d", __FUNCTION__, TryCount);
+ }
+ //debug--
+
+ CheckNativeEffect(); //add here for alsaStreamIn lock holding
+ CheckDynamicSpeechMask();
+
+ if (dropBesRecordDataSize > 0) {
+ /* Drop distortion data */
+ RingBufferSize = RingBuf_getDataCount(&mProcessedDataBuf);
+ if (RingBufferSize >= dropBesRecordDataSize) {
+ // Drop dropBesRecordDataSize bytes from RingBuffer
+ while (dropBesRecordDataSize > 0) {
+ uint32_t dropSize = dropBesRecordDataSize > ReadDataBytes ? ReadDataBytes : dropBesRecordDataSize;
+ RingBuf_copyToLinear((char *)pWrite, &mProcessedDataBuf, dropSize);
+ dropBesRecordDataSize -= dropSize;
+ }
+ } else {
+ // Drop RingBufferSize from RingBuffer
+ while (RingBufferSize > 0 && dropBesRecordDataSize > 0) {
+ uint32_t dropSize = dropBesRecordDataSize > ReadDataBytes ? ReadDataBytes : dropBesRecordDataSize;
+ dropSize = dropSize > RingBufferSize ? RingBufferSize : dropSize;
+ RingBuf_copyToLinear((char *)pWrite, &mProcessedDataBuf, dropSize);
+ RingBufferSize -= dropSize;
+ dropBesRecordDataSize -= dropSize;
+ }
+ }
+ }
+
+ if (dropBesRecordDataSize == 0) {
+ RingBufferSize = RingBuf_getDataCount(&mProcessedDataBuf);
+ if (RingBufferSize >= ReadDataBytes) { // ring buffer is enough, copy & exit
+ RingBuf_copyToLinear((char *)pWrite, &mProcessedDataBuf, ReadDataBytes);
+ ReadDataBytes = 0;
+ AL_UNLOCK(mLock);
+ break;
+ } else { // ring buffer is not enough, copy all data
+ RingBuf_copyToLinear((char *)pWrite, &mProcessedDataBuf, RingBufferSize);
+ ReadDataBytes -= RingBufferSize;
+ pWrite += RingBufferSize;
+ }
+ }
+
+ // wait for new data
+ if (AL_WAIT_MS(mLock, 300) != NO_ERROR) {
+ ALOGW("%s(), waitRelative fail", __FUNCTION__);
+ AL_UNLOCK(mLock);
+ break;
+ }
+
+ AL_UNLOCK(mLock);
+ TryCount--;
+ } while (ReadDataBytes > 0 && (TryCount != 0 || dropBesRecordDataSize != 0));
+
+ if (IsNeedApplyVolume()) {
+ ApplyVolume(buffer, bytes);
+ }
+
+ if (ReadDataBytes > 0) {
+ ALOGW("-%s(),(Not enough data) ReadDataBytes %d!!", __FUNCTION__, ReadDataBytes);
+ } else {
+ ALOGV("-%s(), ReadDataBytes=%d", __FUNCTION__, ReadDataBytes);
+ }
+
+ //debug++
+ if (bTempDebug) {
+ ALOGD("-%s(), ReadDataBytes=%d", __FUNCTION__, ReadDataBytes);
+ }
+ //debug--
+ return bytes - ReadDataBytes;
+}
+
+#include <inttypes.h>
+
+int AudioALSACaptureDataClient::getCapturePosition(int64_t *frames, int64_t *time) {
+ if (mCaptureDataProvider == NULL || frames == NULL || time == NULL) {
+ return -EINVAL;
+ }
+
+ /* Convert provider sample rate to streamin sample rate*/
+ int ret = mCaptureDataProvider->getCapturePosition(frames, time);
+ *frames = (*frames) * mStreamAttributeTarget->sample_rate / mStreamAttributeSource->sample_rate;
+ ALOGV("%s(), frames = %" PRIu64 ", tar sample = %d, src sample = %d", __FUNCTION__, *frames, mStreamAttributeTarget->sample_rate, mStreamAttributeSource->sample_rate);
+ return ret;
+}
+
+uint32_t AudioALSACaptureDataClient::TransferFormat(char *linear_buffer, audio_format_t src_format, audio_format_t des_format, uint32_t bytes) {
+ uint32_t *ptr_src_bit_r = (uint32_t *)linear_buffer;
+ size_t src_bit = audio_bytes_per_sample(src_format);
+ size_t des_bit = audio_bytes_per_sample(des_format);
+ bool formatchanged = false;
+
+ if (src_bit == 0 || des_bit == 0) {
+ ALOGE("Cannot get bytes per sample for audio_format_t (src_format = %d, des_format = %d)\n", src_format, des_format);
+ return 0;
+ }
+
+ if (des_format == AUDIO_FORMAT_PCM_24_BIT_PACKED) { //convert 8+24 to 24 bit
+ char *ptr_des_bit_r = linear_buffer;
+ int32_t *ptr_des_bit_w = 0;
+ if (src_format == AUDIO_FORMAT_PCM_8_24_BIT) {
+ for (uint32_t i = 1; i < (bytes / src_bit); i++) {
+ ptr_des_bit_r = ptr_des_bit_r + 3;
+ ptr_des_bit_w = (int32_t *)ptr_des_bit_r;
+ memcpy(ptr_des_bit_w, (ptr_src_bit_r + i), sizeof(int));
+ }
+ formatchanged = true;
+ }
+ }
+ if (des_format == AUDIO_FORMAT_PCM_16_BIT) { //convert 8+24 to 16 bit
+ int16_t *ptr_des_bit_w = (int16_t *)linear_buffer;
+ if (src_format == AUDIO_FORMAT_PCM_8_24_BIT) {
+ for (uint32_t i = 0; i < (bytes / src_bit); i++) {
+ *(ptr_des_bit_w + i) = (int16_t)(*(ptr_src_bit_r + i) >> 8);
+ }
+ formatchanged = true;
+ }
+ }
+ ASSERT(formatchanged == true);
+ ASSERT(src_bit != 0);
+
+ bytes = bytes * des_bit / src_bit;
+ return bytes;
+}
+
+bool AudioALSACaptureDataClient::IsNeedApplyVolume() {
+ /* Only real input CaptureDataprovider need to apply volume for mic mute */
+ switch (mCaptureDataProvider->getCaptureDataProviderType()) {
+ case CAPTURE_PROVIDER_NORMAL:
+ case CAPTURE_PROVIDER_BT_SCO:
+ case CAPTURE_PROVIDER_BT_CVSD:
+ case CAPTURE_PROVIDER_TDM_RECORD:
+ case CAPTURE_PROVIDER_EXTERNAL:
+ return true;
+ default :
+ return false;
+ }
+
+ return false;
+}
+
+status_t AudioALSACaptureDataClient::ApplyVolume(void *Buffer, uint32_t BufferSize) {
+ // check if need apply mute
+ if (mMicMute != mStreamAttributeTarget->micmute) {
+ mMicMute = mStreamAttributeTarget->micmute ;
+ mMuteTransition = false;
+ }
+
+ if (mMicMute == true) {
+ // do ramp down
+ if (mMuteTransition == false) {
+ uint32_t count = BufferSize >> 1;
+ float Volume_inverse = (float)(MTK_STREAMIN_VOLUEM_MAX / count) * -1;
+ short *pPcm = (short *)Buffer;
+ int ConsumeSample = 0;
+ int value = 0;
+ while (count) {
+ value = *pPcm * (MTK_STREAMIN_VOLUEM_MAX + (Volume_inverse * ConsumeSample));
+ *pPcm = clamp16(value >> MTK_STREAMIN_VOLUME_VALID_BIT);
+ pPcm++;
+ count--;
+ ConsumeSample ++;
+ //ALOGD("ApplyVolume Volume_inverse = %f ConsumeSample = %d",Volume_inverse,ConsumeSample);
+ }
+ mMuteTransition = true;
+ } else {
+ memset(Buffer, 0, BufferSize);
+ }
+ } else if (mMicMute == false) {
+ // do ramp up
+ if (mMuteTransition == false) {
+ uint32_t count = BufferSize >> 1;
+ float Volume_inverse = (float)(MTK_STREAMIN_VOLUEM_MAX / count);
+ short *pPcm = (short *)Buffer;
+ int ConsumeSample = 0;
+ int value = 0;
+ while (count) {
+ value = *pPcm * (Volume_inverse * ConsumeSample);
+ *pPcm = clamp16(value >> MTK_STREAMIN_VOLUME_VALID_BIT);
+ pPcm++;
+ count--;
+ ConsumeSample ++;
+ //ALOGD("ApplyVolume Volume_inverse = %f ConsumeSample = %d",Volume_inverse,ConsumeSample);
+ }
+ mMuteTransition = true;
+ }
+ }
+ return NO_ERROR;
+}
+
+void AudioALSACaptureDataClient::CheckChannelRemixOp(void) {
+ uint32_t targetChannel = mStreamAttributeTarget->num_channels;
+ uint32_t sourceChannel = mStreamAttributeSource->num_channels;
+
+ if (mStreamAttributeTarget->BesRecord_Info.besrecord_enable) {
+ if (targetChannel == 1) {
+ mChannelRemixOp = CHANNEL_STEREO_DOWNMIX_L_ONLY;
+ } else if (targetChannel == 2 && !mBesRecordStereoMode) {
+ // speech enhancement output data is mono, need to convert to stereo
+ mChannelRemixOp = CHANNEL_STEREO_CROSSMIX_L2R;
+ } else {
+ mChannelRemixOp = CHANNEL_REMIX_NOP;
+ }
+ } else {
+ if (targetChannel == 1 && sourceChannel == 2) {
+ /* For unprocessed audio source, the down channel should refer to L ch only, don't do the channel mix */
+ if (mBesRecordStereoMode && mStreamAttributeTarget->input_source != AUDIO_SOURCE_UNPROCESSED) {
+ mChannelRemixOp = CHANNEL_STEREO_DOWNMIX;
+ } else {
+ mChannelRemixOp = CHANNEL_STEREO_DOWNMIX_L_ONLY;
+ }
+ } else if (targetChannel == 2 && sourceChannel == 1) {
+ mChannelRemixOp = CHANNEL_MONO_TO_STEREO;
+ } else if (targetChannel == 2 && sourceChannel == 2) {
+ if (mBesRecordStereoMode) {
+ mChannelRemixOp = CHANNEL_REMIX_NOP;
+ } else {
+ mChannelRemixOp = CHANNEL_STEREO_CROSSMIX_L2R;
+ }
+ } else {
+ mChannelRemixOp = CHANNEL_REMIX_NOP;
+ }
+ }
+
+ ALOGD("%s(), ch %d->%d (mBesRecordStereoMode = %d, BesRecord enable = %d), ChannelRemixOp = %d",
+ __FUNCTION__,
+ sourceChannel,
+ targetChannel,
+ mBesRecordStereoMode,
+ mStreamAttributeTarget->BesRecord_Info.besrecord_enable,
+ mChannelRemixOp);
+}
+
+ssize_t AudioALSACaptureDataClient::ApplyChannelRemix(short *buffer, size_t bytes) {
+ ssize_t remixSize = 0;
+ uint32_t remixOp = mChannelRemixOp;
+ int frameCount;
+
+ if (remixOp == CHANNEL_STEREO_CROSSMIX_L2R) {
+ frameCount = bytes >> 2;
+
+ for (int i = 0; i < frameCount; i++) {
+ *(buffer + 1) = *buffer;
+ buffer += 2;
+ }
+
+ remixSize = bytes;
+ } else if (remixOp == CHANNEL_STEREO_CROSSMIX_R2L) {
+ frameCount = bytes >> 2;
+
+ for (int i = 0; i < frameCount; i++) {
+ *buffer = *(buffer + 1);
+ buffer += 2;
+ }
+
+ remixSize = bytes;
+ } else if (remixOp == CHANNEL_STEREO_DOWNMIX) {
+ short mix;
+ short *monoBuffer = buffer;
+ frameCount = bytes >> 2;
+
+ for (int i = 0; i < frameCount; i++) {
+ mix = (*buffer + * (buffer + 1)) >> 1;
+ *monoBuffer = mix;
+ monoBuffer++;
+ buffer += 2;
+ }
+
+ remixSize = bytes >> 1;
+ } else if (remixOp == CHANNEL_STEREO_DOWNMIX_L_ONLY) {
+ short *monoBuffer = buffer;
+ frameCount = bytes >> 2;
+
+ for (int i = 0; i < frameCount; i++) {
+ *monoBuffer = *buffer;
+ monoBuffer++;
+ buffer += 2;
+ }
+
+ remixSize = bytes >> 1;
+ } else if (remixOp == CHANNEL_STEREO_DOWNMIX_R_ONLY) {
+ short *monoBuffer = buffer;
+ frameCount = bytes >> 2;
+
+ for (int i = 0; i < frameCount; i++) {
+ *monoBuffer = *(buffer + 1);
+ monoBuffer++;
+ buffer += 2;
+ }
+
+ remixSize = bytes >> 1;
+ } else if (remixOp == CHANNEL_MONO_TO_STEREO) {
+ frameCount = bytes >> 1;
+ short *monoBuffer = buffer + frameCount - 1;
+ short *stereoBuffer = buffer + (frameCount * 2) - 1;
+ short data;
+
+ for (int i = 0; i < frameCount; i++) {
+ data = *monoBuffer--;
+ *stereoBuffer-- = data;
+ *stereoBuffer-- = data;
+ }
+
+ remixSize = bytes << 1;
+ }
+
+ return remixSize;
+}
+
+ssize_t AudioALSACaptureDataClient::ApplyChannelRemixWithRingBuf(RingBuf *srcBuffer, RingBuf *dstBuffer) {
+ ssize_t remixSize = 0;
+ size_t dataSize = RingBuf_getDataCount(srcBuffer);
+ size_t availSize = RingBuf_getFreeSpace(dstBuffer);
+ size_t dataSizeAfterProcess;
+ char *tempBuffer = NULL;
+ size_t tempBufferSize;
+ /*
+ if (dataSize < 0)
+ dataSize = 0;
+ */
+ if (mChannelRemixOp == CHANNEL_MONO_TO_STEREO) {
+ dataSizeAfterProcess = dataSize << 1;
+ } else if (mChannelRemixOp == CHANNEL_STEREO_DOWNMIX ||
+ mChannelRemixOp == CHANNEL_STEREO_DOWNMIX_L_ONLY ||
+ mChannelRemixOp == CHANNEL_STEREO_DOWNMIX_R_ONLY) {
+ dataSizeAfterProcess = dataSize >> 1;
+ } else {
+ dataSizeAfterProcess = dataSize;
+ }
+
+ if (dataSizeAfterProcess > availSize) {
+ ALOGE("%s() availSize(%zu) < dataSizeAfterProcess(%zu), buffer overflow!",
+ __FUNCTION__, availSize, dataSizeAfterProcess);
+ dataSizeAfterProcess = availSize;
+ dataSizeAfterProcess &= 3;
+
+ if (mChannelRemixOp == CHANNEL_MONO_TO_STEREO) {
+ dataSize = dataSizeAfterProcess >> 1;
+ } else if (mChannelRemixOp == CHANNEL_STEREO_DOWNMIX ||
+ mChannelRemixOp == CHANNEL_STEREO_DOWNMIX_L_ONLY ||
+ mChannelRemixOp == CHANNEL_STEREO_DOWNMIX_R_ONLY) {
+ dataSize = dataSizeAfterProcess << 1;
+ } else {
+ dataSize = dataSizeAfterProcess;
+ }
+ }
+ /*
+ if (!dataSizeAfterProcess || dataSize < 0)
+ return 0;
+ */
+ if (!dataSizeAfterProcess) {
+ return 0;
+ }
+
+ tempBufferSize = (dataSizeAfterProcess > dataSize) ? dataSizeAfterProcess : dataSize;
+ tempBuffer = new char[tempBufferSize];
+ if (!tempBuffer) {
+ return 0;
+ }
+
+ RingBuf_copyToLinear(tempBuffer, srcBuffer, dataSize);
+
+ remixSize = ApplyChannelRemix((short *)tempBuffer, dataSize);
+
+ RingBuf_copyFromLinear(dstBuffer, tempBuffer, remixSize);
+
+ if (tempBuffer) {
+ delete[] tempBuffer;
+ }
+
+ return remixSize;
+}
+
+bool AudioALSACaptureDataClient::IsLowLatencyCapture(void) {
+ bool low_latency_on = false;
+ bool voip_on = mStreamAttributeTarget->BesRecord_Info.besrecord_voip_enable;
+
+#ifdef UPLINK_LOW_LATENCY
+ if ((voip_on == false) &&
+ (mStreamAttributeTarget->mAudioInputFlags & AUDIO_INPUT_FLAG_FAST)) {
+ low_latency_on = true;
+ }
+#endif
+
+ ALOGD("%s(), low_latency_on: %d, voip_on: %d", __FUNCTION__, low_latency_on, voip_on);
+ return low_latency_on;
+}
+
+//TODO: Move here for temp solution, need to move to DataProcess
+//BesRecord+++
+
+void AudioALSACaptureDataClient::LoadBesRecordParams(void) {
+#if ((!defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)) || (MTK_AUDIO_TUNING_TOOL_V2_PHASE == 1))
+ uint8_t total_num_scenes = MAX_HD_REC_SCENES;
+ ALOGD("+%s()", __FUNCTION__);
+ // get scene table
+ mAudioSpeechEnhanceInfoInstance->GetPreLoadBesRecordSceneTable(&mBesRecordSceneTable);
+
+ // get hd rec param
+ mAudioSpeechEnhanceInfoInstance->GetPreLoadBesRecordParam(&mBesRecordParam);
+
+ //get VoIP param
+ mAudioSpeechEnhanceInfoInstance->GetPreLoadAudioVoIPParam(&mVOIPParam);
+
+ //get DMNR param
+ if ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_DUAL_MIC) > 0) {
+ mAudioSpeechEnhanceInfoInstance->GetPreLoadDualMicSpeechParam(&mDMNRParam);
+ }
+
+#if 0 // Debug print
+ for (int i = 0; i < total_num_scenes; i++)
+ for (int j = 0; j < NUM_HD_REC_DEVICE_SOURCE; j++) {
+ ALOGD("scene_table[%d][%d] = %d", i, j, mBesRecordSceneTable.scene_table[i][j]);
+ }
+#endif
+ ALOGD("-%s()", __FUNCTION__);
+#endif
+}
+
+int AudioALSACaptureDataClient::SetCaptureGain(void) {
+
+ if (mAudioALSAVolumeController != NULL) {
+ mAudioALSAVolumeController->SetCaptureGain(mStreamAttributeTarget->audio_mode, mStreamAttributeTarget->input_source,
+ mStreamAttributeTarget->input_device, mStreamAttributeTarget->output_devices);
+ }
+ return 0;
+}
+
+int AudioALSACaptureDataClient::CheckBesRecordMode(void) {
+#if ((!defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)) || (MTK_AUDIO_TUNING_TOOL_V2_PHASE == 1))
+ //check the BesRecord mode and scene
+ ALOGD("+%s()", __FUNCTION__);
+ uint8_t modeIndex = 0;
+ int32_t u4SceneIdx = 0;
+ bool RecordModeGet = false;
+
+ if (IsVoIPEnable() == true) {
+ mSpeechProcessMode = SPE_MODE_VOIP;
+ } else if ((mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION1) //MagiASR need AEC
+ || (mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION2)) { //Normal Record + AEC
+ mSpeechProcessMode = SPE_MODE_AECREC;
+ } else {
+ mSpeechProcessMode = SPE_MODE_REC;
+ }
+
+ u4SceneIdx = mStreamAttributeTarget->BesRecord_Info.besrecord_scene;
+ mBesRecordStereoMode = false;
+
+ //special input source case
+ if ((mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_RECOGNITION) || mStreamAttributeTarget->BesRecord_Info.besrecord_tuning16K) {
+ ALOGD("voice recognition case");
+ u4SceneIdx = VOICE_REC_RECORDING_DEFAULT_MODE;
+ } else if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_UNLOCK) {
+ ALOGD("voice unlock case");
+ u4SceneIdx = VOICE_UnLock_RECORDING_DEFAULT_MODE;
+ } else if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION1) {
+ ALOGD("CUSTOMIZATION1 case");
+ u4SceneIdx = VOICE_UnLock_RECORDING_DEFAULT_MODE + 1;
+ } else if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION2) {
+ ALOGD("CUSTOMIZATION2 case");
+ u4SceneIdx = VOICE_UnLock_RECORDING_DEFAULT_MODE + 2;
+ } else if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION3) {
+ ALOGD("CUSTOMIZATION3 case");
+ u4SceneIdx = VOICE_UnLock_RECORDING_DEFAULT_MODE + 3;
+ }
+
+ //for BT record case, use specific params, whether what input source it is.
+ if (mStreamAttributeTarget->input_device == AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+ ALOGD("%s, is BT device", __FUNCTION__);
+ if (mBesRecordSceneTable.scene_table[NORMAL_RECORDING_DEFAULT_MODE][HD_REC_DEVICE_SOURCE_BT_EARPHONE] != 0xFF) {
+ modeIndex = mBesRecordSceneTable.scene_table[NORMAL_RECORDING_DEFAULT_MODE][HD_REC_DEVICE_SOURCE_BT_EARPHONE];
+ ALOGD("%s, get specific BT modeIndex = %d", __FUNCTION__, modeIndex);
+ } else {
+ modeIndex = mBesRecordSceneTable.scene_table[NORMAL_RECORDING_DEFAULT_MODE][HD_REC_DEVICE_SOURCE_HANDSET];
+ }
+ mBesRecordSceneIndex = NORMAL_RECORDING_DEFAULT_MODE;
+ RecordModeGet = true;
+ }
+ //Get the BesRecord Mode from the Record Scene
+ else if ((u4SceneIdx >= 0) && (u4SceneIdx < MAX_HD_REC_SCENES)) {
+ // get mode index
+ if ((mBesRecordSceneTable.scene_table[u4SceneIdx][HD_REC_DEVICE_SOURCE_HEADSET] != 0xFF)
+ && (mStreamAttributeTarget->input_device == AUDIO_DEVICE_IN_WIRED_HEADSET)) {
+ modeIndex = mBesRecordSceneTable.scene_table[u4SceneIdx][HD_REC_DEVICE_SOURCE_HEADSET];
+ ALOGD("%s, is HEADSET device, u4SceneIdx=%d, modeIndex=%d", __FUNCTION__, u4SceneIdx, modeIndex);
+ }
+ // Handset Mic
+ else if (mBesRecordSceneTable.scene_table[u4SceneIdx][HD_REC_DEVICE_SOURCE_HANDSET] != 0xFF) {
+ modeIndex = mBesRecordSceneTable.scene_table[u4SceneIdx][HD_REC_DEVICE_SOURCE_HANDSET];
+ ALOGD("%s, is HANDSET device, u4SceneIdx=%d, modeIndex=%d", __FUNCTION__, u4SceneIdx, modeIndex);
+ /* only stereo flag is true, the stereo record preprocess is enabled */
+ if ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_DUAL_MIC) > 0) {
+ if (mBesRecordParam.hd_rec_map_to_stereo_flag[modeIndex] != 0) {
+ mBesRecordStereoMode = true;
+ }
+ }
+ } else {
+ ALOGD("%s, Handset mode index shoule not be -1, u4SceneIdx=%d, modeIndex=%d", __FUNCTION__, u4SceneIdx, modeIndex);
+ }
+
+#ifdef UPLINK_LOW_LATENCY
+ if (mStreamAttributeTarget->mAudioInputFlags & AUDIO_INPUT_FLAG_FAST) { //(fast_capture)
+ modeIndex = FAST_CAPTURE_MODE;
+ }
+#endif
+
+ if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_UNPROCESSED) {
+ modeIndex = UNPROCESSED_MODE;
+ }
+
+ // Debug print
+ ALOGD("GetBesRecordModeInfo: map_fir_ch1=%d, map_fir_ch2=%d",
+ mBesRecordParam.hd_rec_map_to_fir_for_ch1[modeIndex],
+ mBesRecordParam.hd_rec_map_to_fir_for_ch2[modeIndex]);
+
+ mBesRecordSceneIndex = u4SceneIdx;
+ RecordModeGet = true;
+ }
+
+ //No correct mode get, use default mode parameters
+ if (RecordModeGet == false) {
+ //ALOGD("%s, use default mode mdevices=%x, mAttribute.mPredevices=%x, mHDRecordSceneIndex = %d ", __FUNCTION__,
+ // mAttribute.mdevices, mAttribute.mPredevices, mHDRecordSceneIndex);
+ ALOGD("%s, use default mode input_device=%x, mBesRecordSceneIndex = %d ", __FUNCTION__, mStreamAttributeTarget->input_device, mBesRecordSceneIndex);
+
+ //can not get match HD record mode, use the default one
+ // check if 3rd party camcorder
+ if (mStreamAttributeTarget->input_source != AUDIO_SOURCE_CAMCORDER) { //not camcorder
+#if 0 //TODO:Sam, if Capture handler is reopen when routing, no needed.
+ if (mAttribute.mdevices != mAttribute.mPredevices) { //device changed, use previous scene (since scene not changed), (headset plug in/out during recording case)
+ if (mHDRecordSceneIndex == -1) {
+ mHDRecordSceneIndex = NORMAL_RECORDING_DEFAULT_MODE;
+ }
+ if (mAttribute.mdevices == AUDIO_DEVICE_IN_WIRED_HEADSET) { //headset
+ modeIndex = mhdRecordSceneTable.scene_table[mHDRecordSceneIndex][HD_REC_DEVICE_SOURCE_HEADSET];
+ } else {
+ modeIndex = mhdRecordSceneTable.scene_table[mHDRecordSceneIndex][HD_REC_DEVICE_SOURCE_HANDSET];
+ }
+ } else
+#endif
+ {
+ if (mStreamAttributeTarget->input_device == AUDIO_DEVICE_IN_WIRED_HEADSET) { //headset
+ modeIndex = mBesRecordSceneTable.scene_table[NORMAL_RECORDING_DEFAULT_MODE][HD_REC_DEVICE_SOURCE_HEADSET];
+ } else { //default use internal one
+ modeIndex = mBesRecordSceneTable.scene_table[NORMAL_RECORDING_DEFAULT_MODE][HD_REC_DEVICE_SOURCE_HANDSET];
+ }
+ mBesRecordSceneIndex = NORMAL_RECORDING_DEFAULT_MODE;
+ }
+ } else { //camcoder
+ u4SceneIdx = mBesRecordSceneTable.num_voice_rec_scenes + NORMAL_RECORDING_DEFAULT_MODE;//1:cts verifier offset
+#if 0 //TODO:Sam, if Capture handler is reopen when routing, no needed.
+ if (mAttribute.mdevices != mAttribute.mPredevices) { //device changed, use previous scene
+ if (mHDRecordSceneIndex == -1) {
+ mHDRecordSceneIndex = u4SceneIdx;
+ }
+ if (mAttribute.mdevices == AUDIO_DEVICE_IN_WIRED_HEADSET) { //headset
+ modeIndex = mhdRecordSceneTable.scene_table[mHDRecordSceneIndex][HD_REC_DEVICE_SOURCE_HEADSET];
+ } else {
+ modeIndex = mhdRecordSceneTable.scene_table[mHDRecordSceneIndex][HD_REC_DEVICE_SOURCE_HANDSET];
+ }
+ } else
+#endif
+ {
+ if (mStreamAttributeTarget->input_device == AUDIO_DEVICE_IN_WIRED_HEADSET) { //headset
+ modeIndex = mBesRecordSceneTable.scene_table[u4SceneIdx][HD_REC_DEVICE_SOURCE_HEADSET];
+ } else { //default use internal one
+ modeIndex = mBesRecordSceneTable.scene_table[u4SceneIdx][HD_REC_DEVICE_SOURCE_HANDSET];
+ }
+ mBesRecordSceneIndex = u4SceneIdx;
+ }
+ }
+
+ //also need to configure the channel when use default mode
+ /* only stereo flag is true, the stereo record is enabled */
+ if ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_DUAL_MIC) > 0) {
+ if (mStreamAttributeTarget->input_device == AUDIO_DEVICE_IN_BUILTIN_MIC) { //handset
+ if (mBesRecordParam.hd_rec_map_to_stereo_flag[modeIndex] != 0) {
+ mBesRecordStereoMode = true;
+ }
+ }
+ }
+
+#ifdef UPLINK_LOW_LATENCY
+ if (mStreamAttributeTarget->mAudioInputFlags & AUDIO_INPUT_FLAG_FAST) { //(fast_capture)
+ modeIndex = FAST_CAPTURE_MODE;
+ }
+#endif
+
+ if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_UNPROCESSED) {
+ modeIndex = UNPROCESSED_MODE;
+ }
+
+ }
+
+ ALOGD("-%s(), mBesRecordSceneIndex=%d, modeIndex=%d", __FUNCTION__, mBesRecordSceneIndex, modeIndex);
+ mBesRecordModeIndex = modeIndex;
+ return modeIndex;
+#else
+ return 0;
+#endif
+}
+
+void AudioALSACaptureDataClient::CheckBesRecordStereoModeEnable() {
+ if ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_DUAL_MIC) > 0) {
+ if (mStreamAttributeTarget->input_device == AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ mBesRecordStereoMode = true;
+ ALOGD("%s(), set the mBesRecordStereoMode = true\n", __FUNCTION__);
+ }
+ }
+
+ if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_CALL) {
+ /* For voice call incall record, the valid channel is stereo */
+ mBesRecordStereoMode = true;
+ }
+
+ ALOGD("%s(), mBesRecordStereoMode = %d", __FUNCTION__, mBesRecordStereoMode);
+}
+
+void AudioALSACaptureDataClient::ConfigBesRecordParams(void) {
+ ALOGD("+%s()", __FUNCTION__);
+
+#if (defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT) && (MTK_AUDIO_TUNING_TOOL_V2_PHASE >= 2))
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return;
+ }
+
+ AppHandle *pAppHandle = appOps->appHandleGetInstance();
+ AudioType *VoIPAudioType = appOps->appHandleGetAudioTypeByName(pAppHandle, VOIP_AUDIO_TYPE);
+ AudioType *VoIPDmnrAudioType = appOps->appHandleGetAudioTypeByName(pAppHandle, VOIPDMNR_AUDIO_TYPE);
+ AudioType *VoIPGeneralAudioType = appOps->appHandleGetAudioTypeByName(pAppHandle, VOIPGENERAL_AUDIO_TYPE);
+ AudioType *RecordAudioType = appOps->appHandleGetAudioTypeByName(pAppHandle, RECORD_AUDIO_TYPE);
+ AudioType *RecordFirAudioType = appOps->appHandleGetAudioTypeByName(pAppHandle, RECORDFIR_AUDIO_TYPE);
+ AudioType *RecordDmnrAudioType = appOps->appHandleGetAudioTypeByName(pAppHandle, RECORDDMNR_AUDIO_TYPE);
+ ParamUnit *pParamUnit;
+ Param *pSpeciParam;
+ Param *pCommonParam;
+ Param *pInFirParam;
+ Param *pOutFirParam;
+ Param *pInFir1Param;
+ Param *pInFir2Param;
+ Param *pDmnrParam;
+ std::string categoryPath = "";
+ uWord32 BesRecordEnhanceParas[EnhanceParasNum] = {0};
+ Word16 BesRecordCompenFilter[CompenFilterNum] = {0};
+ Word16 BesRecordDMNRParam[DMNRCalDataNum] = {0};
+ bool bVoIPEnable = IsVoIPEnable();
+ int RoutePath = GetBesRecordRoutePath();
+ SPE_MODE mode = mSpeechProcessMode;
+
+ mBesRecordStereoMode = false;
+
+ // Get mSpeechProcessMode
+ if (bVoIPEnable) {
+ mode = SPE_MODE_VOIP;
+ mSpeechProcessMode = mode;
+ } else if ((mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION1) //MagiASR need AEC
+ || (mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION2)) { //Normal Record + AEC
+ mode = SPE_MODE_AECREC;
+ mSpeechProcessMode = mode;
+ } else {
+ mode = SPE_MODE_REC;
+ mSpeechProcessMode = mode;
+ }
+
+ if (bVoIPEnable) {
+ // Get VoIP category path
+ if (RoutePath == ROUTE_BT) {
+ categoryPath = VOIP_BT_PATH;
+ } else if (RoutePath == ROUTE_BT_NSEC_OFF_PATH) {
+ categoryPath = VOIP_BT_NSEC_OFF_PATH;
+ } else if (RoutePath == ROUTE_EARPHONE) {
+ categoryPath = VOIP_3POLE_HEADSET_PATH;
+ } else if (RoutePath == ROUTE_HEADSET) {
+ switch (AudioALSAHardwareResourceManager::getInstance()->getNumOfHeadsetPole()) {
+ case 4:
+ categoryPath = VOIP_4POLE_HEADSET_PATH;
+ break;
+ case 5:
+ if (AudioALSAHardware::GetInstance()->getParameters(keyANC_runing) == "ANC_running=true") {
+ categoryPath += "," VOIP_5POLE_HEADSET_ANC_PATH;
+ } else {
+ categoryPath += "," VOIP_5POLE_HEADSET_PATH;
+ }
+ break;
+ }
+ } else if (RoutePath == ROUTE_SPEAKER) {
+ if (appOps->appHandleIsFeatureOptionEnabled(pAppHandle, VOIP_HANDSFREE_DMNR_SUPPORT_FO) == 1) {
+ categoryPath = VOIP_HANDSFREE_NR_PATH;
+ } else {
+ categoryPath = VOIP_HANDSFREE_NO_NR_PATH;
+ }
+ } else {
+ if (appOps->appHandleIsFeatureOptionEnabled(pAppHandle, VOIP_NORMAL_DMNR_SUPPORT_FO) == 1) {
+ categoryPath = VOIP_HANDSET_DMNR_PATH;
+ } else {
+ categoryPath = VOIP_HANDSET_NO_DMNR_PATH;
+ }
+ }
+ } else {
+ // Get Record category path
+#ifdef UPLINK_LOW_LATENCY
+ if (mStreamAttributeTarget->mAudioInputFlags & AUDIO_INPUT_FLAG_FAST) {
+ categoryPath += RECORD_FAST_RECORD_PATH;
+ } else
+#endif
+ if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_RECOGNITION) {
+ categoryPath += RECORD_VR_PATH;
+ } else if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_UNLOCK) {
+ categoryPath += RECORD_VOICE_UNLOCK_PATH;
+ CheckBesRecordStereoModeEnable();
+ } else if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION1) {
+ categoryPath += RECORD_ASR_PATH;
+ } else if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION2) {
+ categoryPath += RECORD_CUSTOMIZATION2_PATH;
+ } else if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_UNPROCESSED) {
+ categoryPath += RECORD_UNPROCESSED_PATH;
+ } else {
+ // Sound/Video recording, Get application from besrecord_scene
+ switch (mStreamAttributeTarget->BesRecord_Info.besrecord_scene) {
+ case 1:
+ categoryPath += RECORD_SND_REC_NORMAL_PATH;
+ CheckBesRecordStereoModeEnable();
+ break;
+ case 2:
+ categoryPath += RECORD_SND_REC_MEETING_PATH;
+ CheckBesRecordStereoModeEnable();
+ break;
+ case 3:
+ categoryPath += RECORD_SND_REC_LECTURE_PATH;
+ CheckBesRecordStereoModeEnable();
+ break;
+ case 4:
+ categoryPath += RECORD_CAM_REC_NORMAL_PATH;
+ CheckBesRecordStereoModeEnable();
+ break;
+ case 5:
+ categoryPath += RECORD_CAM_REC_MEETING_PATH;
+ break;
+ default:
+ if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_CAMCORDER) {
+ categoryPath += RECORD_CAM_REC_NORMAL_PATH;
+ CheckBesRecordStereoModeEnable();
+ } else {
+ categoryPath += RECORD_SND_REC_NORMAL_PATH;
+ CheckBesRecordStereoModeEnable();
+ }
+ break;
+ }
+ }
+
+ if (RoutePath == ROUTE_BT) {
+ categoryPath += "," RECORD_BT_PATH;
+ } else if (RoutePath == ROUTE_HEADSET) {
+ switch (AudioALSAHardwareResourceManager::getInstance()->getNumOfHeadsetPole()) {
+ case 4:
+ categoryPath += "," RECORD_4POLE_HEADSET_PATH;
+ break;
+ case 5:
+ if (AudioALSAHardware::GetInstance()->getParameters(keyANC_runing) == "ANC_running=true") {
+ categoryPath += "," RECORD_5POLE_HEADSET_ANC_PATH;
+ } else {
+ categoryPath += "," RECORD_5POLE_HEADSET_PATH;
+ }
+ break;
+ }
+ } else if (RoutePath == ROUTE_SPEAKER) {
+ categoryPath += "," RECORD_HANDSET_PATH;
+ } else {
+ categoryPath += "," RECORD_HANDSET_PATH;
+ }
+ }
+
+ ALOGD("%s(), categoryPath = %s, mBesRecordStereoMode = %d, input_source = %d, input_devices = %x, bVoIPEnable = %d, bypassDualProcess = %d",
+ __FUNCTION__,
+ categoryPath.c_str(),
+ mBesRecordStereoMode,
+ mStreamAttributeTarget->input_source,
+ mStreamAttributeTarget->input_device,
+ bVoIPEnable,
+ mStreamAttributeTarget->BesRecord_Info.besrecord_bypass_dualmicprocess);
+
+ appOps->audioTypeReadLock(VoIPAudioType, __FUNCTION__);
+ appOps->audioTypeReadLock(VoIPDmnrAudioType, __FUNCTION__);
+ appOps->audioTypeReadLock(VoIPGeneralAudioType, __FUNCTION__);
+ appOps->audioTypeReadLock(RecordAudioType, __FUNCTION__);
+ appOps->audioTypeReadLock(RecordFirAudioType, __FUNCTION__);
+ appOps->audioTypeReadLock(RecordDmnrAudioType, __FUNCTION__);
+
+ // set speech parameters+++
+ if (mode == SPE_MODE_VOIP) {
+ pParamUnit = appOps->audioTypeGetParamUnit(VoIPAudioType, categoryPath.c_str());
+ pSpeciParam = appOps->paramUnitGetParamByName(pParamUnit, VOIP_PARAM);
+
+ } else {
+ // record case
+ pParamUnit = appOps->audioTypeGetParamUnit(RecordAudioType, categoryPath.c_str());
+ pSpeciParam = appOps->paramUnitGetParamByName(pParamUnit, RECORD_PARAM);
+ }
+
+ // For DMNR tuning, mode param 47[15] should be set 1
+ if (mStreamAttributeTarget->BesRecord_Info.besrecord_dmnr_tuningEnable) {
+ ((uWord32 *)pSpeciParam->data)[47] |= 0x8000;
+ }
+
+ //common parameters as same as VoIP's
+ pParamUnit = appOps->audioTypeGetParamUnit(VoIPGeneralAudioType, VOIP_COMMON_PATH);
+ pCommonParam = appOps->paramUnitGetParamByName(pParamUnit, VOIPGENERAL_PARAM_NAME);
+
+ ASSERT(pSpeciParam != NULL && pCommonParam != NULL);
+ ASSERT((pSpeciParam->arraySize + pCommonParam->arraySize) <= EnhanceParasNum);
+
+ //pSpeciParam + pCommonParam
+ memcpy(BesRecordEnhanceParas, (uWord32 *)pSpeciParam->data, pSpeciParam->arraySize * sizeof(uWord32));
+ memcpy(&BesRecordEnhanceParas[pSpeciParam->arraySize], (uWord32 *)pCommonParam->data, pCommonParam->arraySize * sizeof(uWord32));
+
+ //AEC off
+ if ((mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
+ (mStreamAttributeTarget->NativePreprocess_Info.PreProcessEffect_AECOn == false) &&
+ (mStreamAttributeTarget->input_device != AUDIO_DEVICE_IN_ALL_SCO)) {
+ BesRecordEnhanceParas[0] = 0;
+ BesRecordEnhanceParas[1] = 479;
+ }
+ mSPELayer->SetEnhPara(mode, BesRecordEnhanceParas);
+ //speech parameters---
+
+ //FIR parameters+++
+ if (mStreamAttributeTarget->BesRecord_Info.besrecord_dmnr_tuningEnable == true) {
+ pParamUnit = appOps->audioTypeGetParamUnit(VoIPAudioType, categoryPath.c_str());
+ pInFirParam = appOps->paramUnitGetParamByName(pParamUnit, VOIP_IN_FIR_PARAM);
+
+ ASSERT(pInFirParam != NULL);
+ ASSERT((pInFirParam->arraySize + pInFirParam->arraySize) <= CompenFilterNum);
+
+ memcpy(BesRecordCompenFilter, (Word16 *)pInFirParam->data, pInFirParam->arraySize * sizeof(Word16)); // UL1
+ memcpy(&BesRecordCompenFilter[pInFirParam->arraySize], (Word16 *)pInFirParam->data, pInFirParam->arraySize * sizeof(Word16)); // UL2
+ } else if (mode == SPE_MODE_VOIP) {
+ pParamUnit = appOps->audioTypeGetParamUnit(VoIPAudioType, categoryPath.c_str());
+ pInFirParam = appOps->paramUnitGetParamByName(pParamUnit, VOIP_IN_FIR_PARAM);
+ pOutFirParam = appOps->paramUnitGetParamByName(pParamUnit, VOIP_OUT_FIR_PARAM);
+
+ ASSERT(pInFirParam != NULL && pOutFirParam != NULL);
+ ASSERT((pInFirParam->arraySize + pInFirParam->arraySize + pOutFirParam->arraySize) <= CompenFilterNum);
+
+ // VoIP FIR parameter have 3 FIR parameter, but 1 FIR parameter work for SWIP limitation.
+ memcpy(BesRecordCompenFilter, (Word16 *)pInFirParam->data, pInFirParam->arraySize * sizeof(Word16)); // UL1
+ memcpy(&BesRecordCompenFilter[pInFirParam->arraySize], (Word16 *)pInFirParam->data, pInFirParam->arraySize * sizeof(Word16)); // UL2
+ memcpy(&BesRecordCompenFilter[pInFirParam->arraySize * 2], (Word16 *)pOutFirParam->data, pOutFirParam->arraySize * sizeof(Word16)); // DL
+ } else {
+ // Record 2 FIR param is work
+ pParamUnit = appOps->audioTypeGetParamUnit(RecordFirAudioType, categoryPath.c_str());
+ pInFir1Param = appOps->paramUnitGetParamByName(pParamUnit, RECORD_IN_FIR1_PARAM);
+ pInFir2Param = appOps->paramUnitGetParamByName(pParamUnit, RECORD_IN_FIR2_PARAM);
+
+ ASSERT(pInFir1Param != NULL && pInFir2Param != NULL);
+ ASSERT((pInFir1Param->arraySize + pInFir2Param->arraySize) <= CompenFilterNum);
+
+ memcpy(BesRecordCompenFilter, (Word16 *)pInFir1Param->data, pInFir1Param->arraySize * sizeof(Word16)); // UL1
+ memcpy(&BesRecordCompenFilter[pInFir1Param->arraySize], (Word16 *)pInFir2Param->data, pInFir2Param->arraySize * sizeof(Word16)); // UL2
+ }
+
+ mSPELayer->SetCompFilter(mode, BesRecordCompenFilter);
+ //FIR parameters---
+
+ //DMNR parameters+++
+ if (((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_DUAL_MIC) > 0) && (mStreamAttributeTarget->BesRecord_Info.besrecord_bypass_dualmicprocess == false)) {
+ //DMNR parameters
+ //google default input source AUDIO_SOURCE_VOICE_RECOGNITION not using DMNR (on/off by parameters)
+ if (((mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_RECOGNITION) || (mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION1)
+ || mStreamAttributeTarget->BesRecord_Info.besrecord_tuning16K || mStreamAttributeTarget->BesRecord_Info.besrecord_dmnr_tuningEnable)
+ && ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_ASR) > 0)) {
+ pParamUnit = appOps->audioTypeGetParamUnit(RecordDmnrAudioType, categoryPath.c_str());
+ pDmnrParam = appOps->paramUnitGetParamByName(pParamUnit, RECORD_DMNR_PARAM);
+
+ ASSERT(pDmnrParam != NULL);
+ ASSERT(pDmnrParam->arraySize <= DMNRCalDataNum);
+
+ memcpy(BesRecordDMNRParam, (Word16 *)pDmnrParam->data, pDmnrParam->arraySize * sizeof(Word16));
+ } else if (mode == SPE_MODE_VOIP) {
+ //receiver path
+ if ((RoutePath == ROUTE_NORMAL) && ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_VOIP_NORMAL_DMNR) > 0)
+ && CheckDynamicSpeechEnhancementMaskOnOff(VOIP_SPH_ENH_DYNAMIC_MASK_DMNR)) {
+ pParamUnit = appOps->audioTypeGetParamUnit(VoIPDmnrAudioType, categoryPath.c_str());
+ pDmnrParam = appOps->paramUnitGetParamByName(pParamUnit, VOIP_DMNR_PARAM);
+
+ ASSERT(pDmnrParam != NULL);
+ ASSERT(pDmnrParam->arraySize <= DMNRCalDataNum);
+
+ memcpy(BesRecordDMNRParam, (Word16 *)pDmnrParam->data, pDmnrParam->arraySize * sizeof(Word16));
+ SetDMNREnable(DMNR_NORMAL, true);
+ }
+ //speaker path
+ else if ((RoutePath == ROUTE_SPEAKER) && ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_VOIP_HANDSFREE_DMNR) > 0)
+ && CheckDynamicSpeechEnhancementMaskOnOff(VOIP_SPH_ENH_DYNAMIC_MASK_LSPK_DMNR)) {
+ pParamUnit = appOps->audioTypeGetParamUnit(VoIPDmnrAudioType, categoryPath.c_str());
+ pDmnrParam = appOps->paramUnitGetParamByName(pParamUnit, VOIP_DMNR_PARAM);
+
+ ASSERT(pDmnrParam != NULL);
+ ASSERT(pDmnrParam->arraySize <= DMNRCalDataNum);
+
+ memcpy(BesRecordDMNRParam, (Word16 *)pDmnrParam->data, pDmnrParam->arraySize * sizeof(Word16));
+ SetDMNREnable(DMNR_HANDSFREE, true);
+ } else {
+ pParamUnit = appOps->audioTypeGetParamUnit(VoIPDmnrAudioType, VOIP_NO_DMNR_PATH);
+ pDmnrParam = appOps->paramUnitGetParamByName(pParamUnit, VOIP_DMNR_PARAM);
+
+ ASSERT(pDmnrParam != NULL);
+ ASSERT(pDmnrParam->arraySize <= DMNRCalDataNum);
+
+ memcpy(BesRecordDMNRParam, (Word16 *)pDmnrParam->data, pDmnrParam->arraySize * sizeof(Word16));
+ SetDMNREnable(DMNR_DISABLE, false);
+ }
+ } else {
+ pParamUnit = appOps->audioTypeGetParamUnit(RecordDmnrAudioType, RECORD_NO_DMNR_PATH);
+ pDmnrParam = appOps->paramUnitGetParamByName(pParamUnit, RECORD_DMNR_PARAM);
+
+ ASSERT(pDmnrParam != NULL);
+ ASSERT(pDmnrParam->arraySize <= DMNRCalDataNum);
+
+ memcpy(BesRecordDMNRParam, (Word16 *)pDmnrParam->data, pDmnrParam->arraySize * sizeof(Word16));
+ }
+ mSPELayer->SetDMNRPara(mode, BesRecordDMNRParam);
+ } else {
+ // no DMNR support DMNR disabled
+ pParamUnit = appOps->audioTypeGetParamUnit(RecordDmnrAudioType, RECORD_NO_DMNR_PATH);
+ pDmnrParam = appOps->paramUnitGetParamByName(pParamUnit, RECORD_DMNR_PARAM);
+
+ ASSERT(pDmnrParam != NULL);
+ ASSERT(pDmnrParam->arraySize <= DMNRCalDataNum);
+
+ memcpy(BesRecordDMNRParam, (Word16 *)pDmnrParam->data, pDmnrParam->arraySize * sizeof(Word16));
+ mSPELayer->SetDMNRPara(mode, BesRecordDMNRParam);
+ SetDMNREnable(DMNR_DISABLE, false);
+ }
+ //DMNR parameters---
+
+ appOps->audioTypeUnlock(VoIPAudioType);
+ appOps->audioTypeUnlock(VoIPDmnrAudioType);
+ appOps->audioTypeUnlock(VoIPGeneralAudioType);
+ appOps->audioTypeUnlock(RecordAudioType);
+ appOps->audioTypeUnlock(RecordFirAudioType);
+ appOps->audioTypeUnlock(RecordDmnrAudioType);
+#else /* Get VoIP/Record parameter from NVRam struct */
+ uWord32 BesRecordEnhanceParas[EnhanceParasNum] = {0};
+ Word16 BesRecordCompenFilter[CompenFilterNum] = {0};
+ Word16 BesRecordDMNRParam[DMNRCalDataNum] = {0};
+
+ bool bVoIPEnable = IsVoIPEnable();
+ int RoutePath = GetBesRecordRoutePath();
+ SPE_MODE mode = mSpeechProcessMode;
+ bool bIsMICInverse = AudioALSAHardwareResourceManager::getInstance()->getMicInverse();
+
+ ALOGD("%s(),mBesRecordStereoMode=%d, input_source= %d, input_devices=%x,mBesRecordModeIndex=%d, bVoIPEnable=%d, mode=%d, bypassDualProcess=%d, bIsMICInverse=%d", __FUNCTION__, mBesRecordStereoMode, mStreamAttributeTarget->input_source,
+ mStreamAttributeTarget->input_device, mBesRecordModeIndex, bVoIPEnable, mode, mStreamAttributeTarget->BesRecord_Info.besrecord_bypass_dualmicprocess, bIsMICInverse);
+
+ //set speech parameters+++
+ for (int i = 0; i < EnhanceParasNum; i++) { //EnhanceParasNum = (16+32)+12(common parameters)
+ if (i < (SPEECH_PARA_NUM + EnhanceModeParasExtNum)) {
+ // Mode parameters
+ if (i < SPEECH_PARA_NUM) {
+ if (mStreamAttributeTarget->BesRecord_Info.besrecord_dmnr_tuningEnable == true) {
+ //specific parameters
+ BesRecordEnhanceParas[i] = mVOIPParam.speech_mode_para[AUDIO_VOIP_DEVICE_NORMAL][i]; //use loud speaker mode speech params
+ } else if (mode == SPE_MODE_VOIP) {
+ //specific parameters
+ if (RoutePath == ROUTE_BT) {
+ BesRecordEnhanceParas[i] = mVOIPParam.speech_mode_para[AUDIO_VOIP_DEVICE_BT][i];
+ } else if (RoutePath == ROUTE_HEADSET) {
+ BesRecordEnhanceParas[i] = mVOIPParam.speech_mode_para[AUDIO_VOIP_DEVICE_HEADSET][i];
+ } else if (RoutePath == ROUTE_SPEAKER) {
+ BesRecordEnhanceParas[i] = mVOIPParam.speech_mode_para[AUDIO_VOIP_DEVICE_SPEAKER][i];
+ } else { //normal receiver case
+ BesRecordEnhanceParas[i] = mVOIPParam.speech_mode_para[AUDIO_VOIP_DEVICE_NORMAL][i];
+ }
+
+ //AEC off
+ if ((mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
+ (mStreamAttributeTarget->NativePreprocess_Info.PreProcessEffect_AECOn == false) &&
+ (mStreamAttributeTarget->input_device != AUDIO_DEVICE_IN_ALL_SCO)) {
+ BesRecordEnhanceParas[0] = 0;
+ BesRecordEnhanceParas[1] = 479;
+ }
+ } else {
+ BesRecordEnhanceParas[i] = mBesRecordParam.hd_rec_speech_mode_para[mBesRecordModeIndex][i];
+ }
+ } else {
+ // Fill with 0 for new mode parameter extension
+ BesRecordEnhanceParas[i] = 0;
+
+ // For DMNR tuning, mode param 47[15] should be set 1
+ if (mStreamAttributeTarget->BesRecord_Info.besrecord_dmnr_tuningEnable) {
+ BesRecordEnhanceParas[47] |= 0x8000;
+ }
+ }
+ } else {
+ //common parameters also use VoIP's
+ BesRecordEnhanceParas[i] = mVOIPParam.speech_common_para[i - (SPEECH_PARA_NUM + EnhanceModeParasExtNum)];
+ }
+ ALOGV("BesRecordEnhanceParas[%u]=%u", i, BesRecordEnhanceParas[i]);
+ }
+
+ mSPELayer->SetEnhPara(mode, BesRecordEnhanceParas);
+ //speech parameters---
+
+ //FIR parameters+++
+ for (int i = 0; i < WB_FIR_NUM; i++) {
+ if (mStreamAttributeTarget->BesRecord_Info.besrecord_dmnr_tuningEnable == true) {
+ BesRecordCompenFilter[i] = mVOIPParam.in_fir[AUDIO_VOIP_DEVICE_NORMAL][i];
+ //ALOGD("BesRecordCompenFilter[%d]=%d", i, BesRecordCompenFilter[i]);
+ BesRecordCompenFilter[i + WB_FIR_NUM] = mVOIPParam.in_fir[AUDIO_VOIP_DEVICE_NORMAL][i];
+ } else if (mode == SPE_MODE_VOIP) {
+ if (RoutePath == ROUTE_BT) {
+ BesRecordCompenFilter[i] = mVOIPParam.in_fir[AUDIO_VOIP_DEVICE_BT][i]; //UL1 params
+ BesRecordCompenFilter[i + WB_FIR_NUM] = mVOIPParam.in_fir[AUDIO_VOIP_DEVICE_BT][i]; //UL2 params
+ BesRecordCompenFilter[i + WB_FIR_NUM * 2] = mVOIPParam.out_fir[AUDIO_VOIP_DEVICE_BT][i]; //DL params
+ } else if (RoutePath == ROUTE_HEADSET) {
+ BesRecordCompenFilter[i] = mVOIPParam.in_fir[AUDIO_VOIP_DEVICE_HEADSET][i]; //UL1 params
+ BesRecordCompenFilter[i + WB_FIR_NUM] = mVOIPParam.in_fir[AUDIO_VOIP_DEVICE_HEADSET][i]; //UL2 params
+ BesRecordCompenFilter[i + WB_FIR_NUM * 2] = mVOIPParam.out_fir[AUDIO_VOIP_DEVICE_HEADSET][i]; //DL params
+ } else if (RoutePath == ROUTE_SPEAKER) {
+ BesRecordCompenFilter[i] = mVOIPParam.in_fir[AUDIO_VOIP_DEVICE_SPEAKER][i]; //UL1 params
+ BesRecordCompenFilter[i + WB_FIR_NUM] = mVOIPParam.in_fir[AUDIO_VOIP_DEVICE_SPEAKER][i]; //UL2 params
+ BesRecordCompenFilter[i + WB_FIR_NUM * 2] = mVOIPParam.out_fir[AUDIO_VOIP_DEVICE_SPEAKER][i]; //DL params
+ } else { //normal receiver case
+ BesRecordCompenFilter[i] = mVOIPParam.in_fir[AUDIO_VOIP_DEVICE_NORMAL][i]; //UL1 params
+ BesRecordCompenFilter[i + WB_FIR_NUM] = mVOIPParam.in_fir[AUDIO_VOIP_DEVICE_NORMAL][i]; //UL2 params
+ BesRecordCompenFilter[i + WB_FIR_NUM * 2] = mVOIPParam.out_fir[AUDIO_VOIP_DEVICE_NORMAL][i]; //DL params
+ }
+ } else {
+ if (bIsMICInverse == false) {
+ BesRecordCompenFilter[i] = mBesRecordParam.hd_rec_fir[mBesRecordParam.hd_rec_map_to_fir_for_ch1[mBesRecordModeIndex]][i];
+ //ALOGD("BesRecordCompenFilter[%d]=%d", i, BesRecordCompenFilter[i]);
+ if (mBesRecordStereoMode) { //stereo, UL2 use different FIR filter
+ BesRecordCompenFilter[i + WB_FIR_NUM] = mBesRecordParam.hd_rec_fir[mBesRecordParam.hd_rec_map_to_fir_for_ch2[mBesRecordModeIndex]][i];
+ } else { //mono, UL2 use the same FIR filter
+ BesRecordCompenFilter[i + WB_FIR_NUM] = mBesRecordParam.hd_rec_fir[mBesRecordParam.hd_rec_map_to_fir_for_ch1[mBesRecordModeIndex]][i];
+ }
+ } else {
+ // Mic inversed, main mic using the reference mic settings
+ BesRecordCompenFilter[i] = mBesRecordParam.hd_rec_fir[mBesRecordParam.hd_rec_map_to_fir_for_ch2[mBesRecordModeIndex]][i];
+ if (mBesRecordStereoMode) {
+ BesRecordCompenFilter[i + WB_FIR_NUM] = mBesRecordParam.hd_rec_fir[mBesRecordParam.hd_rec_map_to_fir_for_ch1[mBesRecordModeIndex]][i];
+ } else { //mono, UL2 use the same FIR filter
+ BesRecordCompenFilter[i + WB_FIR_NUM] = mBesRecordParam.hd_rec_fir[mBesRecordParam.hd_rec_map_to_fir_for_ch2[mBesRecordModeIndex]][i];
+ }
+ }
+ }
+ }
+
+ mSPELayer->SetCompFilter(mode, BesRecordCompenFilter);
+ //FIR parameters---
+
+ //DMNR parameters+++
+ if (((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_DUAL_MIC) > 0) && (mStreamAttributeTarget->BesRecord_Info.besrecord_bypass_dualmicprocess == false)) {
+ //DMNR parameters
+ //google default input source AUDIO_SOURCE_VOICE_RECOGNITION not using DMNR (on/off by parameters)
+ if (((mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_RECOGNITION) || (mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION1)
+ || mStreamAttributeTarget->BesRecord_Info.besrecord_tuning16K || mStreamAttributeTarget->BesRecord_Info.besrecord_dmnr_tuningEnable)
+ && ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_ASR) > 0)) {
+ for (int i = 0; i < NUM_ABFWB_PARAM; i++) {
+ BesRecordDMNRParam[i] = mDMNRParam.ABF_para_VR[i];
+ }
+ } else if (mode == SPE_MODE_VOIP) { //VoIP case
+ //receiver path
+ if ((RoutePath == ROUTE_NORMAL) && ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_VOIP_NORMAL_DMNR) > 0)
+ && CheckDynamicSpeechEnhancementMaskOnOff(VOIP_SPH_ENH_DYNAMIC_MASK_DMNR)) {
+ //enable corresponding DMNR flag
+ for (int i = 0; i < NUM_ABFWB_PARAM; i++) {
+ BesRecordDMNRParam[i] = mDMNRParam.ABF_para_VOIP[i];
+ }
+ SetDMNREnable(DMNR_NORMAL, true);
+ }
+ //speaker path
+ else if ((RoutePath == ROUTE_SPEAKER) && ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_VOIP_HANDSFREE_DMNR) > 0)
+ && CheckDynamicSpeechEnhancementMaskOnOff(VOIP_SPH_ENH_DYNAMIC_MASK_LSPK_DMNR)) {
+ for (int i = 0; i < NUM_ABFWB_PARAM; i++) {
+ BesRecordDMNRParam[i] = mDMNRParam.ABF_para_VOIP_LoudSPK[i];
+ }
+ SetDMNREnable(DMNR_HANDSFREE, true);
+ } else {
+ memset(BesRecordDMNRParam, 0, sizeof(BesRecordDMNRParam));
+ SetDMNREnable(DMNR_DISABLE, false);
+ }
+ } else {
+ memset(BesRecordDMNRParam, 0, sizeof(BesRecordDMNRParam));
+ }
+
+ mSPELayer->SetDMNRPara(mode, BesRecordDMNRParam);
+ } else {
+ memset(BesRecordDMNRParam, 0, sizeof(BesRecordDMNRParam));
+ mSPELayer->SetDMNRPara(mode, BesRecordDMNRParam);
+ SetDMNREnable(DMNR_DISABLE, false);
+ }
+ //DMNR parameters---
+#endif
+
+ //need to config as 16k sample rate for voice recognition(Google's will use 48K preprocess instead) or VoIP or REC+AEC
+ if ((mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION1)
+ || (mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION2)
+ || (mStreamAttributeTarget->BesRecord_Info.besrecord_tuning16K == true) || (IsVoIPEnable() == true)) {
+ if (mode == SPE_MODE_VOIP) { //VoIP case
+ mSPELayer->SetSampleRate(mode, VOICE_RECOGNITION_RECORD_SAMPLE_RATE);
+ mSPELayer->SetAPPTable(mode, WB_VOIP);
+ } else { //voice recognition case
+ mSPELayer->SetSampleRate(mode, VOICE_RECOGNITION_RECORD_SAMPLE_RATE);
+ if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION2) {
+ mSPELayer->SetAPPTable(mode, MONO_AEC_RECORD); //set library do AEC Record
+ } else {
+ mSPELayer->SetAPPTable(mode, SPEECH_RECOGNITION); //set library do voice recognition process or MagiASR
+ }
+ }
+ } else if ((mode == SPE_MODE_REC) && (mStreamAttributeTarget->input_source == AUDIO_SOURCE_UNPROCESSED)) {
+ mSPELayer->SetSampleRate(mode, HD_RECORD_SAMPLE_RATE);
+ mSPELayer->SetAPPTable(mode, LOW_LATENCY_RECORD);
+ } else { //normal record use 48k
+ mSPELayer->SetSampleRate(mode, HD_RECORD_SAMPLE_RATE);
+ if (mBesRecordStereoMode) {
+ mSPELayer->SetAPPTable(mode, STEREO_RECORD); //set library do stereo process
+ } else {
+ mSPELayer->SetAPPTable(mode, MONO_RECORD); //set library do mono process
+ }
+ }
+
+ mSPELayer->SetRoute((SPE_ROUTE)RoutePath);
+
+ //set MIC digital gain to library
+ long gain = mAudioALSAVolumeController->GetSWMICGain();
+ uint8_t TotalGain = mAudioALSAVolumeController->GetULTotalGain();
+ if (mStreamAttributeTarget->input_device == AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+ gain = 0;
+ TotalGain = 0;
+ ALOGD("BT path set Digital MIC gain = 0");
+ }
+ mSPELayer->SetMICDigitalGain(mode, gain);
+ mSPELayer->SetUpLinkTotalGain(mode, TotalGain);
+
+#ifdef UPLINK_LOW_LATENCY
+ if ((mode == SPE_MODE_REC) && (mStreamAttributeTarget->mAudioInputFlags & AUDIO_INPUT_FLAG_FAST)) { //normal record case && if(fast capture)
+ // audio low latency param - record - swip
+ mSPELayer->SetFrameRate(mode, UPLINK_LOW_LATENCY_MS); //can support 1/2/3/5/10ms frame rate for low latency
+ mSPELayer->SetAPPTable(mode, LOW_LATENCY_RECORD); //only for low latency record!!
+ }
+#endif
+
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+void AudioALSACaptureDataClient::StartBesRecord(void) {
+ ALOGD("+%s()", __FUNCTION__);
+ mSPELayer->Start(mSpeechProcessMode);
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+void AudioALSACaptureDataClient::StopBesRecord(void) {
+ ALOGD("+%s()", __FUNCTION__);
+ mSPELayer->Stop();
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+uint32_t AudioALSACaptureDataClient::BesRecordPreprocess(void *buffer, uint32_t bytes) {
+ uint32_t retSize = bytes;
+
+ //ALOGD("+%s()", __FUNCTION__);
+ if (!mBypassBesRecord) {
+ struct InBufferInfo InBufinfo;
+ InBufinfo.pBufBase = (short *)buffer;
+ InBufinfo.BufLen = bytes;
+ InBufinfo.time_stamp_queued = GetSystemTime(false);
+ InBufinfo.bHasRemainInfo = true;
+ InBufinfo.time_stamp_predict = GetCaptureTimeStamp();
+
+ retSize = mSPELayer->Process(&InBufinfo);
+ }
+ //ALOGD("-%s(), bytes=%d, retSize=%d", __FUNCTION__, bytes, retSize);
+
+ return retSize;
+}
+
+int AudioALSACaptureDataClient::GetBesRecordRoutePath(void) {
+ int RoutePath;
+ ALOGD("+%s(), output device = 0x%x, input device = 0x%x", __FUNCTION__, mStreamAttributeTarget->output_devices, mStreamAttributeTarget->input_device);
+
+ if (mStreamAttributeTarget->input_device == AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+ RoutePath = ROUTE_BT;
+ } else if (mStreamAttributeTarget->input_device == AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ RoutePath = ROUTE_HEADSET;
+ } else if (mStreamAttributeTarget->output_devices == AUDIO_DEVICE_OUT_WIRED_HEADPHONE
+ && (mStreamAttributeTarget->input_device == AUDIO_DEVICE_IN_BUILTIN_MIC || mStreamAttributeTarget->input_device == AUDIO_DEVICE_IN_BACK_MIC)) {
+ RoutePath = ROUTE_EARPHONE;
+ } else if (mStreamAttributeTarget->output_devices & AUDIO_DEVICE_OUT_SPEAKER) { //speaker path
+ RoutePath = ROUTE_SPEAKER;
+ } else {
+ RoutePath = ROUTE_NORMAL;
+ }
+
+ return RoutePath;
+}
+
+
+bool AudioALSACaptureDataClient::CheckBesRecordBypass() {
+#if 0 //these input sources will not enable BesRecord while capture handle create (BesRecord_Info.besrecord_enable), keep this function for other purpose in the future
+ if ((mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_UNLOCK) || (mStreamAttributeTarget->input_source == AUDIO_SOURCE_FM_TUNER)) {
+ mBypassBesRecord = true;
+ } else {
+ mBypassBesRecord = false;
+ }
+#endif
+ ALOGD("%s() %d", __FUNCTION__, mBypassBesRecord);
+ return mBypassBesRecord;
+}
+
+bool AudioALSACaptureDataClient::CheckNeedBesRecordSRC() {
+ uint32_t BesRecord_usingsamplerate = HD_RECORD_SAMPLE_RATE;
+
+ if (mStreamAttributeTarget->BesRecord_Info.besrecord_enable == true) {
+ //BesRecord need 16K sample rate data (Google's voice recognition will use 48K process due to new CTS test case)
+ if ((mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION1)
+ || (mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION2)
+ || (mStreamAttributeTarget->BesRecord_Info.besrecord_tuning16K == true) || (IsVoIPEnable() == true)) {
+ BesRecord_usingsamplerate = VOICE_RECOGNITION_RECORD_SAMPLE_RATE;
+ //need src if the stream source sample rate are not the same with BesRecord needed
+ if ((mStreamAttributeSource->sample_rate != VOICE_RECOGNITION_RECORD_SAMPLE_RATE) || (mStreamAttributeSource->num_channels != 2)) {
+ mNeedBesRecordSRC = true;
+ } else {
+ mNeedBesRecordSRC = false;
+ }
+ } else { //BesRecord need 48K sample rate data
+ //need src if the stream source sample rate are not the same with BesRecord needed
+ if ((mStreamAttributeSource->sample_rate != HD_RECORD_SAMPLE_RATE) || (mStreamAttributeSource->num_channels != 2)) {
+ mNeedBesRecordSRC = true;
+ BesRecord_usingsamplerate = HD_RECORD_SAMPLE_RATE;
+ } else {
+ mNeedBesRecordSRC = false;
+ }
+ }
+ ALOGD("%s(), mStreamAttributeSource->sample_rate=%d, mStreamAttributeSource->num_channels=%d, mStreamAttributeTarget->sample_rate=%d,mStreamAttributeTarget->num_channels=%d, BesRecord_usingsamplerate=%d"
+ , __FUNCTION__, mStreamAttributeSource->sample_rate, mStreamAttributeSource->num_channels, mStreamAttributeTarget->sample_rate, mStreamAttributeTarget->num_channels, BesRecord_usingsamplerate);
+
+ //if need to do BesRecord SRC
+ //if (mNeedBesRecordSRC)
+ {
+ if ((mStreamAttributeSource->sample_rate == 0) || (mStreamAttributeSource->num_channels == 0)) {
+ ASSERT(0);
+ }
+ // Need SRC from stream target to BesRecord needed
+ if ((mStreamAttributeSource->sample_rate != BesRecord_usingsamplerate) || (mStreamAttributeSource->num_channels != 2)) {
+
+ mBliSrcHandler1 = newMtkAudioSrc(mStreamAttributeSource->sample_rate, mStreamAttributeSource->num_channels,
+ BesRecord_usingsamplerate, 2, SRC_IN_Q1P15_OUT_Q1P15);
+ mBliSrcHandler1->open();
+ }
+
+ mBesRecSRCSizeFactor = ((BesRecord_usingsamplerate * 2) / (mStreamAttributeSource->sample_rate * mStreamAttributeSource->num_channels)) + 1;
+
+ // Need SRC from BesRecord to stream target needed
+ if (mStreamAttributeTarget->sample_rate != BesRecord_usingsamplerate) {
+ mBliSrcHandler2 = newMtkAudioSrc(BesRecord_usingsamplerate, 2,
+ mStreamAttributeTarget->sample_rate, 2, SRC_IN_Q1P15_OUT_Q1P15);
+ mBliSrcHandler2->open();
+ }
+
+ mBesRecSRCSizeFactor2 = ((mStreamAttributeTarget->sample_rate * 2) / (BesRecord_usingsamplerate * 2)) + 1;
+ }
+ } else {
+ mNeedBesRecordSRC = false;
+ }
+
+ ALOGD("%s(), %d, %d, mBesRecSRCSizeFactor=%d", __FUNCTION__, mNeedBesRecordSRC, BesRecord_usingsamplerate, mBesRecSRCSizeFactor);
+ return mNeedBesRecordSRC;
+}
+
+bool AudioALSACaptureDataClient::IsVoIPEnable(void) {
+ //ALOGV("%s() %d", __FUNCTION__, mStreamAttributeTarget->BesRecord_Info.besrecord_voip_enable);
+ return mStreamAttributeTarget->BesRecord_Info.besrecord_voip_enable;
+}
+
+status_t AudioALSACaptureDataClient::UpdateBesRecParam() {
+ ALOGD("+%s() besrecord_voip_enable %d, besrecord_enable=%d", __FUNCTION__,
+ mStreamAttributeTarget->BesRecord_Info.besrecord_voip_enable, mStreamAttributeTarget->BesRecord_Info.besrecord_enable);
+ if (mStreamAttributeTarget->BesRecord_Info.besrecord_voip_enable && mStreamAttributeTarget->BesRecord_Info.besrecord_enable) {
+ if (mSPELayer->IsSPERunning()) {
+ StopBesRecord();
+ ConfigBesRecordParams();
+ mSPELayer->Standby(); //for doing the time resync
+ StartBesRecord();
+ } else {
+ ConfigBesRecordParams();
+ }
+ }
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+void AudioALSACaptureDataClient::CheckDynamicSpeechMask(void) {
+ if (mStreamAttributeTarget->BesRecord_Info.besrecord_dynamic_mask.dynamic_func != mVoIPSpeechEnhancementMask.dynamic_func) { //need update dynamic mask
+ UpdateDynamicFunction();
+ mVoIPSpeechEnhancementMask = mStreamAttributeTarget->BesRecord_Info.besrecord_dynamic_mask;
+ }
+}
+
+void AudioALSACaptureDataClient::UpdateDynamicFunction(void) {
+ ALOGD("+%s()", __FUNCTION__);
+ int RoutePath = GetBesRecordRoutePath();
+ SPE_MODE mode = mSpeechProcessMode;
+ short DMNRParam[DMNRCalDataNum] = {0};
+ ALOGD("%s(), RoutePath %d, mode %d", __FUNCTION__, RoutePath, mode);
+ //DMNR function update
+ if ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_DUAL_MIC) > 0) {
+#if (defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT) && (MTK_AUDIO_TUNING_TOOL_V2_PHASE >= 2))
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return;
+ }
+
+ AudioType *VoIPDmnrAudioType = appOps->appHandleGetAudioTypeByName(appOps->appHandleGetInstance(), VOIPDMNR_AUDIO_TYPE);
+ appOps->audioTypeReadLock(VoIPDmnrAudioType, __FUNCTION__);
+
+ if ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_DMNR_3_0) > 0) {
+ if (mode == SPE_MODE_VOIP) {
+ //receiver path & receiver DMNR is enabled
+ if ((RoutePath == ROUTE_NORMAL) && CheckDynamicSpeechEnhancementMaskOnOff(VOIP_SPH_ENH_DYNAMIC_MASK_DMNR) &&
+ ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_VOIP_NORMAL_DMNR) > 0)) {
+ ALOGD("enable normal mode DMNR");
+
+ ParamUnit *pParamUnit = appOps->audioTypeGetParamUnit(VoIPDmnrAudioType, VOIP_HANDSET_DMNR_PATH);
+ Param *pDmnrParam = appOps->paramUnitGetParamByName(pParamUnit, VOIP_DMNR_PARAM);
+
+ ASSERT(pDmnrParam != NULL);
+
+ mSPELayer->SetDMNRPara(mode, (Word16 *)pDmnrParam->data);
+ SetDMNREnable(DMNR_NORMAL, true);
+ } else if ((RoutePath == ROUTE_SPEAKER) && CheckDynamicSpeechEnhancementMaskOnOff(VOIP_SPH_ENH_DYNAMIC_MASK_LSPK_DMNR) &&
+ ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_VOIP_HANDSFREE_DMNR) > 0)) { //speaker path
+ ALOGD("enable loudspeaker mode DMNR");
+ ParamUnit *pParamUnit = appOps->audioTypeGetParamUnit(VoIPDmnrAudioType, VOIP_HANDSFREE_NR_PATH);
+ Param *pDmnrParam = appOps->paramUnitGetParamByName(pParamUnit, VOIP_DMNR_PARAM);
+
+ ASSERT(pDmnrParam != NULL);
+
+ mSPELayer->SetDMNRPara(mode, (Word16 *)pDmnrParam->data);
+ SetDMNREnable(DMNR_HANDSFREE, true);
+ } else {
+ ALOGD("disable DMNR");
+ ParamUnit *pParamUnit = appOps->audioTypeGetParamUnit(VoIPDmnrAudioType, VOIP_NO_DMNR_PATH);
+ Param *pDmnrParam = appOps->paramUnitGetParamByName(pParamUnit, VOIP_DMNR_PARAM);
+
+ ASSERT(pDmnrParam != NULL);
+
+ mSPELayer->SetDMNRPara(mode, (Word16 *)pDmnrParam->data);
+ SetDMNREnable(DMNR_DISABLE, false);
+ }
+ }
+ } else {
+ ALOGD("%s(),disable DMNR due to not support", __FUNCTION__);
+
+ ParamUnit *pParamUnit = appOps->audioTypeGetParamUnit(VoIPDmnrAudioType, VOIP_NO_DMNR_PATH);
+ Param *pDmnrParam = appOps->paramUnitGetParamByName(pParamUnit, VOIP_DMNR_PARAM);
+
+ ASSERT(pDmnrParam != NULL);
+
+ mSPELayer->SetDMNRPara(mode, (Word16 *)pDmnrParam->data);
+ SetDMNREnable(DMNR_DISABLE, false);
+ }
+ appOps->audioTypeUnlock(VoIPDmnrAudioType);
+#else
+ if ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_DMNR_3_0) > 0) {
+ if (mode == SPE_MODE_VOIP) {
+ //receiver path & receiver DMNR is enabled
+ if ((RoutePath == ROUTE_NORMAL) && CheckDynamicSpeechEnhancementMaskOnOff(VOIP_SPH_ENH_DYNAMIC_MASK_DMNR) &&
+ ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_VOIP_NORMAL_DMNR) > 0)) {
+ ALOGD("enable normal mode DMNR");
+ //enable corresponding DMNR flag
+ for (int i = 0; i < NUM_ABFWB_PARAM; i++) {
+ DMNRParam[i] = mDMNRParam.ABF_para_VOIP[i];
+ }
+ SetDMNREnable(DMNR_NORMAL, true);
+ } else if ((RoutePath == ROUTE_SPEAKER) && CheckDynamicSpeechEnhancementMaskOnOff(VOIP_SPH_ENH_DYNAMIC_MASK_LSPK_DMNR) &&
+ ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_VOIP_HANDSFREE_DMNR) > 0)) { //speaker path
+ ALOGD("enable loudspeaker mode DMNR");
+ for (int i = 0; i < NUM_ABFWB_PARAM; i++) {
+ DMNRParam[i] = mDMNRParam.ABF_para_VOIP_LoudSPK[i];
+ }
+ SetDMNREnable(DMNR_HANDSFREE, true);
+ } else {
+ ALOGD("disable DMNR");
+ memset(DMNRParam, 0, sizeof(DMNRParam));
+ SetDMNREnable(DMNR_DISABLE, false);
+ }
+ mSPELayer->SetDMNRPara(mode, DMNRParam);
+ }
+ } else {
+ ALOGD("%s(),disable DMNR due to not support", __FUNCTION__);
+ memset(DMNRParam, 0, sizeof(DMNRParam));
+ SetDMNREnable(DMNR_DISABLE, false);
+ mSPELayer->SetDMNRPara(mode, DMNRParam);
+ }
+#endif
+ }
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+bool AudioALSACaptureDataClient::CheckDynamicSpeechEnhancementMaskOnOff(const voip_sph_enh_dynamic_mask_t dynamic_mask_type) {
+ ALOGV("%s() %x, %x", __FUNCTION__, mStreamAttributeTarget->BesRecord_Info.besrecord_dynamic_mask.dynamic_func, dynamic_mask_type);
+ bool bret = false;
+
+ if ((mStreamAttributeTarget->BesRecord_Info.besrecord_dynamic_mask.dynamic_func & dynamic_mask_type) > 0) {
+ bret = true;
+ }
+
+ return bret;
+}
+
+//0: disable DMNR
+//1: normal mode DMNR
+//2: handsfree mode DMNR
+void AudioALSACaptureDataClient::SetDMNREnable(DMNR_TYPE type, bool enable) {
+ ALOGD("%s(), type=%d, bypassDMNR=%d", __FUNCTION__, type, mStreamAttributeTarget->BesRecord_Info.besrecord_bypass_dualmicprocess);
+
+ if (((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_DUAL_MIC) > 0) && (mStreamAttributeTarget->BesRecord_Info.besrecord_bypass_dualmicprocess == false)) {
+ if ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_DMNR_3_0) > 0) {
+ switch (type) {
+ case DMNR_DISABLE :
+ mSPELayer->SetDynamicFuncCtrl(NORMAL_DMNR, false);
+ mSPELayer->SetDynamicFuncCtrl(HANDSFREE_DMNR, false);
+ break;
+ case DMNR_NORMAL :
+ mSPELayer->SetDynamicFuncCtrl(NORMAL_DMNR, enable);
+ break;
+ case DMNR_HANDSFREE :
+ mSPELayer->SetDynamicFuncCtrl(HANDSFREE_DMNR, enable);
+ break;
+ default:
+ mSPELayer->SetDynamicFuncCtrl(NORMAL_DMNR, false);
+ mSPELayer->SetDynamicFuncCtrl(HANDSFREE_DMNR, false);
+ break;
+ }
+ } else {
+
+ ALOGD("%s(), turn off due to not support", __FUNCTION__);
+ mSPELayer->SetDynamicFuncCtrl(NORMAL_DMNR, false);
+ mSPELayer->SetDynamicFuncCtrl(HANDSFREE_DMNR, false);
+ }
+ }
+}
+
+timespec AudioALSACaptureDataClient::GetCaptureTimeStamp(void) {
+ struct timespec capturetime;
+
+ long ret_ns;
+ capturetime.tv_sec = 0;
+ capturetime.tv_nsec = 0;
+
+ if ((mStreamAttributeSource->Time_Info.timestamp_get.tv_sec == 0) && (mStreamAttributeSource->Time_Info.timestamp_get.tv_nsec == 0)) {
+ ALOGE("%s fail", __FUNCTION__);
+ } else {
+ capturetime = mStreamAttributeSource->Time_Info.timestamp_get;
+ ret_ns = mStreamAttributeSource->Time_Info.kernelbuffer_ns;
+ if ((capturetime.tv_nsec - ret_ns) >= 0) {
+ capturetime.tv_nsec -= ret_ns;
+ } else {
+ capturetime.tv_sec -= 1;
+ capturetime.tv_nsec = 1000000000 + capturetime.tv_nsec - ret_ns;
+ }
+ ALOGV("%s, sec= %ld, nsec=%ld, ret_ns = %ld\n", __FUNCTION__, capturetime.tv_sec, capturetime.tv_nsec, ret_ns);
+ }
+
+ return capturetime;
+}
+
+timespec AudioALSACaptureDataClient::GetEchoRefTimeStamp(void) {
+ struct timespec echoreftime;
+
+ long ret_ns;
+ echoreftime.tv_sec = 0;
+ echoreftime.tv_nsec = 0;
+
+ if ((mStreamAttributeSourceEchoRef->Time_Info.timestamp_get.tv_sec == 0) && (mStreamAttributeSourceEchoRef->Time_Info.timestamp_get.tv_nsec == 0)) {
+ ALOGE("%s fail", __FUNCTION__);
+ } else {
+ echoreftime = mStreamAttributeSourceEchoRef->Time_Info.timestamp_get;
+ ret_ns = mStreamAttributeSourceEchoRef->Time_Info.kernelbuffer_ns;
+ if ((echoreftime.tv_nsec - ret_ns) >= 0) {
+ echoreftime.tv_nsec -= ret_ns;
+ } else {
+ echoreftime.tv_sec -= 1;
+ echoreftime.tv_nsec = 1000000000 + echoreftime.tv_nsec - ret_ns;
+ }
+ ALOGV("%s, sec= %ld, nsec=%ld, ret_ns = %ld\n", __FUNCTION__, echoreftime.tv_sec, echoreftime.tv_nsec, ret_ns);
+ }
+
+ return echoreftime;
+}
+
+//BesRecord---
+//#endif //MTK_AUDIO_HD_REC_SUPPORT
+
+//Android Native Preprocess effect +++
+void AudioALSACaptureDataClient::CheckNativeEffect(void) {
+
+ if (mStreamAttributeTarget->NativePreprocess_Info.PreProcessEffect_Update == true) {
+ ALOGD("+%s() %d", __FUNCTION__, mStreamAttributeTarget->NativePreprocess_Info.PreProcessEffect_Count);
+
+ if (mAudioPreProcessEffect != NULL) {
+#if 0
+ for (int i = 0; i < mStreamAttributeTarget->NativePreprocess_Info.PreProcessEffect_Count; i++) {
+ //mAudioPreProcessEffect->removeAudioEffect(mStreamAttributeTarget->NativePreprocess_Info.PreProcessEffect_Record[i]);
+ //mAudioPreProcessEffect->addAudioEffect(mStreamAttributeTarget->NativePreprocess_Info.PreProcessEffect_Record[i]);
+ }
+#endif
+ mAudioPreProcessEffect->CheckNativeEffect();
+ }
+
+ mStreamAttributeTarget->NativePreprocess_Info.PreProcessEffect_Update = false;
+ ALOGD("-%s()", __FUNCTION__);
+ }
+}
+
+uint32_t AudioALSACaptureDataClient::NativePreprocess(void *buffer, uint32_t bytes) {
+ uint32_t retsize = bytes;
+ retsize = mAudioPreProcessEffect->NativePreprocess(buffer, bytes, &mStreamAttributeSource->Time_Info);
+ return retsize;
+}
+
+//Android Native Preprocess effect ---
+
+//EchoRef+++
+void AudioALSACaptureDataClient::AddEchoRefDataProvider(AudioALSACaptureDataProviderBase *pCaptureDataProvider, stream_attribute_t *stream_attribute_target) {
+ ALOGD("+%s()", __FUNCTION__);
+ mStreamAttributeTargetEchoRef = stream_attribute_target;
+ mCaptureDataProviderEchoRef = pCaptureDataProvider;//AudioALSACaptureDataProviderEchoRef::getInstance();
+ mStreamAttributeSourceEchoRef = mCaptureDataProviderEchoRef->getStreamAttributeSource();
+
+ // fix the channel count of echo reference data to stereo since native echo_reference_itfe supports stereo only
+ mStreamAttributeTargetEchoRef->num_channels = 2;
+ mStreamAttributeTargetEchoRef->audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+
+ //check SRC needed and created
+ // raw data
+ memset((void *)&mEchoRefRawDataBuf, 0, sizeof(mEchoRefRawDataBuf));
+ mEchoRefRawDataBuf.pBufBase = new char[kClientBufferSize];
+ mEchoRefRawDataBuf.bufLen = kClientBufferSize;
+ mEchoRefRawDataBuf.pRead = mEchoRefRawDataBuf.pBufBase;
+ mEchoRefRawDataBuf.pWrite = mEchoRefRawDataBuf.pBufBase;
+ ASSERT(mEchoRefRawDataBuf.pBufBase != NULL);
+
+ // src data
+ memset((void *)&mEchoRefSrcDataBuf, 0, sizeof(mEchoRefSrcDataBuf));
+ mEchoRefSrcDataBuf.pBufBase = new char[kClientBufferSize];
+ mEchoRefSrcDataBuf.bufLen = kClientBufferSize;
+ mEchoRefSrcDataBuf.pRead = mEchoRefSrcDataBuf.pBufBase;
+ mEchoRefSrcDataBuf.pWrite = mEchoRefSrcDataBuf.pBufBase;
+ ASSERT(mEchoRefSrcDataBuf.pBufBase != NULL);
+
+ // attach client to capture EchoRef data provider
+ ALOGD("%s(), mCaptureDataProviderEchoRef=%p", __FUNCTION__, mCaptureDataProviderEchoRef);
+ mCaptureDataProviderEchoRef->configStreamAttribute(mStreamAttributeTarget);
+ mCaptureDataProviderEchoRef->attach(this); // mStreamAttributeSource will be updated when first client attached
+
+ // init SRC, this SRC is for Android Native.
+ if (mStreamAttributeSourceEchoRef->sample_rate != mStreamAttributeTargetEchoRef->sample_rate ||
+ mStreamAttributeSourceEchoRef->num_channels != mStreamAttributeTargetEchoRef->num_channels ||
+ mStreamAttributeSourceEchoRef->audio_format != mStreamAttributeTargetEchoRef->audio_format) {
+ mBliSrcEchoRef = newMtkAudioSrc(
+ mStreamAttributeSourceEchoRef->sample_rate, mStreamAttributeSourceEchoRef->num_channels,
+ mStreamAttributeTargetEchoRef->sample_rate, mStreamAttributeTargetEchoRef->num_channels,
+ SRC_IN_Q1P15_OUT_Q1P15); // TODO(Harvey, Ship): 24bit
+ mBliSrcEchoRef->open();
+ }
+
+ // init SRC, this SRC is for MTK VoIP
+ if ((mStreamAttributeTargetEchoRef->sample_rate != 16000) || (mStreamAttributeTargetEchoRef->num_channels != 1)) {
+ mBliSrcEchoRefBesRecord = newMtkAudioSrc(
+ mStreamAttributeTargetEchoRef->sample_rate, mStreamAttributeTargetEchoRef->num_channels,
+ 16000, 1,
+ SRC_IN_Q1P15_OUT_Q1P15);
+ mBliSrcEchoRefBesRecord->open();
+ }
+
+ //assume starts after PCM open
+ mSPELayer->SetDownLinkLatencyTime(mStreamAttributeSourceEchoRef->latency);
+
+ // pcm start if need
+ while (mCaptureDataProvider->getReadThreadReady() == false ||
+ mCaptureDataProviderEchoRef->getReadThreadReady() == false)
+ {
+ usleep(2 * 1000);
+ }
+ ALOGD("readthread all ready! pcm start");
+ mCaptureDataProviderEchoRef->signalPcmStart();
+ mSPELayer->SetOutputStreamRunning(true, true);
+ mSPELayer->SetEchoRefStartTime(GetSystemTime(false));
+ mCaptureDataProvider->signalPcmStart();
+ mSPELayer->SetUPLinkIntrStartTime(GetSystemTime(false));
+
+
+
+ ALOGD("%s(), Source sample_rate=%d, num_channels=%d, audio_format=%d", __FUNCTION__
+ , mStreamAttributeSourceEchoRef->sample_rate, mStreamAttributeSourceEchoRef->num_channels, mStreamAttributeSourceEchoRef->audio_format);
+ ALOGD("%s(), Target sample_rate=%d, num_channels=%d, audio_format=%d", __FUNCTION__
+ , mStreamAttributeTargetEchoRef->sample_rate, mStreamAttributeTargetEchoRef->num_channels, mStreamAttributeTargetEchoRef->audio_format);
+
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+
+//EchoRef data no need to provide to Capture handler
+uint32_t AudioALSACaptureDataClient::copyEchoRefCaptureDataToClient(RingBuf pcm_read_buf) {
+ ALOGV("+%s()", __FUNCTION__);
+
+ uint32_t freeSpace = RingBuf_getFreeSpace(&mEchoRefRawDataBuf);
+ uint32_t dataSize = RingBuf_getDataCount(&pcm_read_buf);
+ if (freeSpace < dataSize) {
+ ALOGE("%s(), mRawDataBuf <= pcm_read_buf, freeSpace(%u) < dataSize(%u), buffer overflow!!", __FUNCTION__, freeSpace, dataSize);
+ RingBuf_copyFromRingBuf(&mEchoRefRawDataBuf, &pcm_read_buf, freeSpace);
+ } else {
+ RingBuf_copyFromRingBuf(&mEchoRefRawDataBuf, &pcm_read_buf, dataSize);
+ }
+
+ // SRC to to Native AEC need format (as StreaminTarget format since AWB data might be the same as DL1 before)
+ const uint32_t kNumRawData = RingBuf_getDataCount(&mEchoRefRawDataBuf);
+ uint32_t num_free_space = RingBuf_getFreeSpace(&mEchoRefSrcDataBuf);
+
+ if (mBliSrcEchoRef == NULL) { // No need SRC
+ //ASSERT(num_free_space >= kNumRawData);
+ if (num_free_space < kNumRawData) {
+ ALOGW("%s(), num_free_space(%u) < kNumRawData(%u)", __FUNCTION__, num_free_space, kNumRawData);
+ RingBuf_copyFromRingBuf(&mEchoRefSrcDataBuf, &mEchoRefRawDataBuf, num_free_space);
+ } else {
+ RingBuf_copyFromRingBuf(&mEchoRefSrcDataBuf, &mEchoRefRawDataBuf, kNumRawData);
+ }
+ } else { // Need SRC
+ char *pEchoRefRawDataLinearBuf = new char[kNumRawData];
+ RingBuf_copyToLinear(pEchoRefRawDataLinearBuf, &mEchoRefRawDataBuf, kNumRawData);
+
+ char *pEchoRefSrcDataLinearBuf = new char[num_free_space];
+
+ char *p_read = pEchoRefRawDataLinearBuf;
+ uint32_t num_raw_data_left = kNumRawData;
+ uint32_t num_converted_data = num_free_space; // max convert num_free_space
+
+ uint32_t consumed = num_raw_data_left;
+ mBliSrcEchoRef->process((int16_t *)p_read, &num_raw_data_left,
+ (int16_t *)pEchoRefSrcDataLinearBuf, &num_converted_data);
+ consumed -= num_raw_data_left;
+
+ p_read += consumed;
+ ALOGV("%s(), num_raw_data_left = %u, num_converted_data = %u",
+ __FUNCTION__, num_raw_data_left, num_converted_data);
+
+ //ASSERT(num_raw_data_left == 0);
+ if (num_raw_data_left > 0) {
+ ALOGW("%s(), num_raw_data_left(%u) > 0", __FUNCTION__, num_raw_data_left);
+ }
+
+ RingBuf_copyFromLinear(&mEchoRefSrcDataBuf, pEchoRefSrcDataLinearBuf, num_converted_data);
+ ALOGV("%s(), dataCount:%u", __FUNCTION__, RingBuf_getDataCount(&mEchoRefSrcDataBuf));
+
+ delete[] pEchoRefRawDataLinearBuf;
+ delete[] pEchoRefSrcDataLinearBuf;
+ }
+
+
+ //for Preprocess
+ const uint32_t kNumEchoRefSrcData = RingBuf_getDataCount(&mEchoRefSrcDataBuf);
+ char *pEchoRefProcessDataLinearBuf = new char[kNumEchoRefSrcData];
+ RingBuf_copyToLinear(pEchoRefProcessDataLinearBuf, &mEchoRefSrcDataBuf, kNumEchoRefSrcData);
+
+#ifdef BOOST_ECHOREF
+ if ((mStreamAttributeTarget->output_devices & AUDIO_DEVICE_OUT_SPEAKER)) {
+ for (uint32_t i = 0; i < kNumEchoRefSrcData / 2 ; i++) {
+ // over flow protection
+ int16_t temp = *((int16_t *)(pEchoRefProcessDataLinearBuf + (i * 2)));
+ if (temp > 8191) {
+ temp = 8191;
+ } else if (temp < -8192) {
+ temp = -8192;
+ }
+ // enhance 12dB
+ temp = temp << 2;
+
+ pEchoRefProcessDataLinearBuf[2 * i] = (char)temp;
+ pEchoRefProcessDataLinearBuf[2 * i + 1] = (char)(temp >> 8);
+ }
+ }
+#endif
+
+ //here to queue the EchoRef data to Native effect, since it doesn't need to SRC here
+ if ((mAudioPreProcessEffect->num_preprocessors > 0)) { //&& echoref is enabled
+ //copy pEchoRefProcessDataLinearBuf to native preprocess for echo ref
+ mAudioPreProcessEffect->WriteEchoRefData(pEchoRefProcessDataLinearBuf, kNumEchoRefSrcData, &mStreamAttributeSourceEchoRef->Time_Info);
+ }
+
+ //If need MTK VoIP process
+ if ((mStreamAttributeTarget->BesRecord_Info.besrecord_enable) && !mBypassBesRecord) {
+ struct InBufferInfo BufInfo;
+ //for MTK native SRC
+ if (mBliSrcEchoRefBesRecord == NULL) { // No need SRC
+ //TODO(Sam),copy pEchoRefProcessDataLinearBuf to MTK echoref data directly
+
+ BufInfo.pBufBase = (short *)pEchoRefProcessDataLinearBuf;
+ BufInfo.BufLen = kNumEchoRefSrcData;
+ BufInfo.time_stamp_queued = GetSystemTime(false);
+ BufInfo.bHasRemainInfo = true;
+ BufInfo.time_stamp_predict = GetEchoRefTimeStamp();
+#ifdef SRC_DROP_DATA
+ if (mFirstEchoSRC == true) {
+ mFirstEchoSRC = false;
+ delete[] pEchoRefProcessDataLinearBuf;
+ return 0;
+ }
+#endif
+ mSPELayer->WriteReferenceBuffer(&BufInfo);
+
+ } else { // Need SRC
+ char *pEchoRefProcessSRCDataLinearBuf = new char[kNumEchoRefSrcData];
+
+ char *p_read = pEchoRefProcessDataLinearBuf;
+ uint32_t num_raw_data_left = kNumEchoRefSrcData;
+ uint32_t num_converted_data = kNumEchoRefSrcData; // max convert num_free_space
+ uint32_t consumed = num_raw_data_left;
+
+ mBliSrcEchoRefBesRecord->process((int16_t *)p_read, &num_raw_data_left,
+ (int16_t *)pEchoRefProcessSRCDataLinearBuf, &num_converted_data);
+ consumed -= num_raw_data_left;
+
+ p_read += consumed;
+ ALOGV("%s(), num_raw_data_left = %u, num_converted_data = %u",
+ __FUNCTION__, num_raw_data_left, num_converted_data);
+
+ //ASSERT(num_raw_data_left == 0);
+ if (num_raw_data_left > 0) {
+ ALOGW("%s(), num_raw_data_left(%u) > 0", __FUNCTION__, num_raw_data_left);
+ }
+
+ //TODO: (Sam )copy pEchoRefSrcDataLinearBuf to MTK VoIP write echo ref data
+ BufInfo.pBufBase = (short *)pEchoRefProcessSRCDataLinearBuf;
+ BufInfo.BufLen = num_converted_data;
+ BufInfo.time_stamp_queued = GetSystemTime(false);
+ BufInfo.bHasRemainInfo = true;
+ BufInfo.time_stamp_predict = GetEchoRefTimeStamp();
+#ifdef SRC_DROP_DATA
+ if (mFirstEchoSRC == true) {
+ mFirstEchoSRC = false;
+ delete[] pEchoRefProcessSRCDataLinearBuf;
+ delete[] pEchoRefProcessDataLinearBuf;
+ return 0;
+ }
+#endif
+ mSPELayer->WriteReferenceBuffer(&BufInfo);
+
+ delete[] pEchoRefProcessSRCDataLinearBuf;
+ }
+ }
+
+ delete[] pEchoRefProcessDataLinearBuf;
+ return 0;
+}
+
+//EchoRef---
+uint32_t AudioALSACaptureDataClient::getLatencyTime() {
+ uint32_t mlatency = UPLINK_NORMAL_LATENCY_MS ; //20ms
+#ifdef UPLINK_LOW_LATENCY
+ if (IsLowLatencyCapture()) {
+ mlatency = UPLINK_LOW_LATENCY_MS; //5ms
+ }
+#endif
+ return mlatency;
+}
+
+} // end of namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataClientAurisysNormal.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataClientAurisysNormal.cpp
new file mode 100644
index 0000000..5b35eae
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataClientAurisysNormal.cpp
@@ -0,0 +1,1429 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureDataClientAurisysNormal.h"
+
+#include <inttypes.h>
+#include <pthread.h>
+#include <sys/prctl.h>
+
+#include <utils/threads.h> /* for ANDROID_PRIORITY_AUDIO */
+
+
+#include "AudioUtility.h"
+#include "SpeechUtility.h"
+
+
+#include "AudioType.h"
+#include <AudioLock.h>
+
+#include "AudioALSACaptureDataProviderBase.h"
+#include "AudioALSAHardwareResourceManager.h"
+
+#include <SpeechEnhancementController.h>
+
+#include "AudioVolumeInterface.h"
+#include "AudioVolumeFactory.h"
+
+
+#include <audio_memory_control.h>
+#include <audio_lock.h>
+#include <audio_ringbuf.h>
+#include <audio_time.h>
+
+
+#include <audio_task.h>
+#include <aurisys_scenario.h>
+
+#include <arsi_type.h>
+#include <aurisys_config.h>
+
+#include <audio_pool_buf_handler.h>
+
+#include <aurisys_utility.h>
+#include <aurisys_controller.h>
+#include <aurisys_lib_manager.h>
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+#include "AudioDetectPulse.h"
+#endif
+
+#include "AudioSmartPaController.h"
+
+#include "AudioParamParser.h"
+
+//Android Native Preprocess effect +++
+#include "AudioPreProcess.h"
+//Android Native Preprocess effect ---
+
+//#undef ALOGV
+//#define ALOGV ALOGD
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACaptureDataClientAurisysNormal"
+
+
+#ifdef AURISYS_ENABLE_LATENCY_DEBUG
+#ifdef LATENCY_LOG
+#undef LATENCY_LOG
+#endif
+#define LATENCY_LOG(x...) ALOGW(x)
+#else
+#define LATENCY_LOG(x...)
+#endif
+
+#define UL_LOCK_MS(al, ms) \
+ ({ \
+ int __RET__ = 0; \
+ if (getNeedAEETimeoutFlg()) { \
+ __RET__ = AL_LOCK_MS(al, ms); \
+ } else { \
+ __RET__ = AL_LOCK_MS_NO_ASSERT(al, ms); \
+ } \
+ __RET__; \
+ })
+
+
+#ifdef AURISYS_DUMP_LOG_V
+#undef AUD_LOG_V
+#define AUD_LOG_V(x...) AUD_LOG_D(x)
+#endif
+
+
+
+namespace android {
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+static AudioLock mAurisysLibManagerLock;
+
+
+#define MTK_STREAMIN_VOLUEM_MAX (0x1000)
+#define MTK_STREAMIN_VOLUME_VALID_BIT (12)
+
+#ifndef UPLINK_DROP_POP_MS
+#define DROP_POP_MS (60)
+#else
+#define DROP_POP_MS (UPLINK_DROP_POP_MS)
+#endif
+
+#ifndef UPLINK_DROP_POP_MS_FOR_UNPROCESSED
+#define DROP_POP_MS_FOR_UNPROCESSED (80)
+#else
+#define DROP_POP_MS_FOR_UNPROCESSED (UPLINK_DROP_POP_MS_FOR_UNPROCESSED)
+#endif
+
+#define MAX_LOCK_TIME_OUT_MS (500)
+#define MAX_PROCESS_DATA_WAIT_TIME_OUT_MS (40)
+
+#ifndef MAX_RAW_DATA_LOCK_TIME_OUT_MS
+#ifdef CONFIG_MT_ENG_BUILD
+#define MAX_RAW_DATA_LOCK_TIME_OUT_MS (500 * 3)
+#else
+#define MAX_RAW_DATA_LOCK_TIME_OUT_MS (500)
+#endif
+#endif
+
+#ifndef MAX_PROCESS_DATA_LOCK_TIME_OUT_MS
+#ifdef CONFIG_MT_ENG_BUILD
+#define MAX_PROCESS_DATA_LOCK_TIME_OUT_MS (500 * 3)
+#else
+#define MAX_PROCESS_DATA_LOCK_TIME_OUT_MS (500)
+#endif
+#endif
+
+
+/*==============================================================================
+ * Utility
+ *============================================================================*/
+
+inline bool isTimeStampStarted(const struct timespec *time_stamp) {
+ return (time_stamp->tv_sec != 0 || time_stamp->tv_nsec != 0);
+}
+
+
+static int calculateTotalTimeSpec(const time_info_struct_t *timeInfo,
+ struct timespec *time_stamp) {
+ long ret_ns = 0;
+
+ if (timeInfo == NULL || time_stamp == NULL) {
+ ASSERT(timeInfo != NULL);
+ ASSERT(time_stamp != NULL);
+ return -1;
+ }
+
+ if (isTimeStampStarted(&timeInfo->timestamp_get) == false) {
+ ALOGE("%s() timestamp_get not start!!", __FUNCTION__);
+ return -1;
+ }
+
+ time_stamp->tv_sec = timeInfo->timestamp_get.tv_sec;
+ time_stamp->tv_nsec = timeInfo->timestamp_get.tv_nsec;
+
+ ret_ns = timeInfo->kernelbuffer_ns;
+ if (time_stamp->tv_nsec >= ret_ns) {
+ time_stamp->tv_nsec -= ret_ns;
+ } else {
+ time_stamp->tv_sec -= 1;
+ time_stamp->tv_nsec = 1000000000 + time_stamp->tv_nsec - ret_ns;
+ }
+ ALOGV("%s(), sec: %ld, nsec: %ld, ret_ns: %ld", __FUNCTION__,
+ time_stamp->tv_sec, time_stamp->tv_nsec, ret_ns);
+
+ return 0;
+}
+
+
+static uint32_t getDiffBufSize(const stream_attribute_t *attribute, uint64_t time_diff_ns) {
+ uint64_t diff_buf_size = 0;
+
+ uint64_t size_per_sample = 0;
+ uint64_t size_per_frame = 0;
+
+
+ size_per_sample = audio_bytes_per_sample(attribute->audio_format);
+ size_per_frame = attribute->num_channels * size_per_sample;
+
+ diff_buf_size = (size_per_frame *
+ attribute->sample_rate *
+ time_diff_ns) / 1000000000;
+ if ((diff_buf_size % size_per_frame) != 0) { // alignment
+ diff_buf_size = ((diff_buf_size / size_per_frame) + 1) * size_per_frame;
+ }
+
+ return (uint32_t)diff_buf_size;
+}
+
+static uint32_t getDropMs(stream_attribute_t *attribute_target) {
+ if (attribute_target->input_source == AUDIO_SOURCE_UNPROCESSED) {
+ return DROP_POP_MS_FOR_UNPROCESSED;
+ } else {
+ return DROP_POP_MS;
+ }
+}
+
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+inline void detectPulseForRingbuf(
+ const PULSE_TAG tag,
+ const audio_ringbuf_t *ringbuf,
+ const stream_attribute_t *attribute) {
+
+ uint32_t data_count = 0;
+ char *linear_buf = NULL;
+ bool malloc_flag = false;
+ uint32_t r2e = 0;
+
+
+ if (ringbuf == NULL || attribute == NULL) {
+ ALOGW("%s(), NULL!!", __FUNCTION__);
+ return;
+ }
+
+ data_count = audio_ringbuf_count(ringbuf);
+ if (data_count == 0) {
+ ALOGW("%s(), data_count = 0!!", __FUNCTION__);
+ return;
+ }
+
+ if (ringbuf->write >= ringbuf->read) {
+ linear_buf = ringbuf->read;
+ } else {
+ malloc_flag = true;
+ linear_buf = (char *)malloc(data_count);
+
+ r2e = (ringbuf->base + ringbuf->size) - ringbuf->read;
+ memcpy(linear_buf, ringbuf->read, r2e);
+ if (data_count > r2e) {
+ memcpy(linear_buf + r2e, ringbuf->base, data_count - r2e);
+ }
+ }
+
+ AudioDetectPulse::doDetectPulse(
+ tag,
+ PULSE_LEVEL,
+ 0,
+ (void *)linear_buf,
+ data_count,
+ attribute->audio_format,
+ attribute->num_channels,
+ attribute->sample_rate);
+
+ if (malloc_flag) {
+ free(linear_buf);
+ }
+}
+#endif
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+AudioALSACaptureDataClientAurisysNormal::AudioALSACaptureDataClientAurisysNormal(
+ AudioALSACaptureDataProviderBase *pCaptureDataProvider,
+ stream_attribute_t *stream_attribute_target,
+ AudioALSACaptureDataProviderBase *pCaptureDataProviderEchoRef) :
+ mStreamAttributeSource(NULL),
+ mStreamAttributeTarget(stream_attribute_target),
+ mCaptureDataProvider(pCaptureDataProvider),
+ mRawStartFrameCount(0),
+ mMicMute(false),
+ mMuteTransition(false),
+ mAudioALSAVolumeController(AudioVolumeFactory::CreateAudioVolumeController()),
+ mEnable(false),
+ mStreamInReopen(false),
+ mProcessThreadLaunched(false),
+ mLatency(0),
+ mRawDataPeriodBufSize(0),
+ mProcessedDataPeriodBufSize(0),
+ mCaptureDataProviderEchoRef(pCaptureDataProviderEchoRef),
+ mStreamAttributeSourceEchoRef(NULL),
+ mEchoRefDataPeriodBufSize(0),
+ mIsEchoRefDataSync(false),
+ mAurisysLibManager(NULL),
+ mManagerConfig(NULL),
+ mAurisysScenario(AURISYS_SCENARIO_INVALID),
+ mAudioPoolBufUlIn(NULL),
+ mAudioPoolBufUlOut(NULL),
+ mAudioPoolBufUlAec(NULL),
+ mAudioPoolBufDlIn(NULL),
+ mAudioPoolBufDlOut(NULL),
+ mLinearOut(NULL),
+ mDropPopSize(0),
+ mAudioPreProcessEffect(NULL) {
+
+ // init var
+ uint32_t drop_ms = 0;
+ uint32_t size_per_sample = 0;
+ uint32_t size_per_frame = 0;
+ int ret = 0;
+
+
+ ALOGD("%s(+)", __FUNCTION__);
+
+
+ // init raw data buf
+ memset((void *)&mRawDataBufTimeStamp, 0, sizeof(mRawDataBufTimeStamp));
+ memset((void *)&mRawDataBuf, 0, sizeof(mRawDataBuf));
+
+ // init processed data buf
+ memset((void *)&mProcessedDataBuf, 0, sizeof(mProcessedDataBuf));
+
+ // init echo ref data buf
+ memset((void *)&mEchoRefDataBufTimeStamp, 0, sizeof(mEchoRefDataBufTimeStamp));
+ memset((void *)&mEchoRefDataBuf, 0, sizeof(mEchoRefDataBuf));
+
+ // config attribute for input device
+ mCaptureDataProvider->configStreamAttribute(mStreamAttributeTarget);
+
+ // get attribute before enable
+ mStreamAttributeSource = mCaptureDataProvider->getStreamAttributeSource();
+ if (IsAECEnable()) {
+ mStreamAttributeSourceEchoRef = mCaptureDataProviderEchoRef->getStreamAttributeSource();
+ }
+
+ // enable before attach
+ mEnable = true;
+
+ // attach client to capture data provider (after data buf ready)
+ mCaptureDataProvider->attach(this);
+ if ((mStreamAttributeSource->input_device == AUDIO_DEVICE_IN_USB_DEVICE) && (getPcmStatus() != true)) {
+ hProcessThread = 0;
+ ALOGD("%s, PCM Open/Read Fail...USB Device is unplugged ?", __FUNCTION__);
+ return;
+ }
+ if (IsAECEnable()) {
+ mCaptureDataProviderEchoRef->configStreamAttribute(mStreamAttributeTarget);
+ mCaptureDataProviderEchoRef->attach(this);
+ }
+
+ // get latency (for library, but not data provider)
+ mLatency = (IsLowLatencyCapture()) ? UPLINK_LOW_LATENCY_MS : UPLINK_NORMAL_LATENCY_MS;
+
+ // get period size
+ mRawDataPeriodBufSize = getPeriodBufSize(mStreamAttributeSource, mLatency);
+ mProcessedDataPeriodBufSize = getPeriodBufSize(mStreamAttributeTarget, mLatency);
+ if (IsAECEnable()) {
+ mEchoRefDataPeriodBufSize = getPeriodBufSize(mStreamAttributeSourceEchoRef, mLatency);
+ }
+ ALOGD("mLatency %u, mRawDataPeriodBufSize %u, mProcessedDataPeriodBufSize %u, mEchoRefDataPeriodBufSize %u",
+ mLatency, mRawDataPeriodBufSize, mProcessedDataPeriodBufSize, mEchoRefDataPeriodBufSize);
+
+ // pcm start if need
+ if (isNeedSyncPcmStart() == true) {
+ if (IsAECEnable() == false) {
+ while (mCaptureDataProvider->getReadThreadReady() == false) {
+ usleep(2 * 1000);
+ }
+ ALOGD("isNeedSyncPcmStart, read thread ready! pcm start");
+ mCaptureDataProvider->signalPcmStart();
+ } else {
+ while (mCaptureDataProvider->getReadThreadReady() == false ||
+ mCaptureDataProviderEchoRef->getReadThreadReady() == false) {
+ usleep(2 * 1000);
+ }
+ ALOGD("isNeedSyncPcmStart, read thread ready! pcm start");
+ mCaptureDataProvider->signalPcmStart();
+ mCaptureDataProviderEchoRef->signalPcmStart();
+ }
+ }
+
+
+ // Gain control // TODO: AudioMTKGainController::SetCaptureGain, multi data client !?
+ AUD_ASSERT(mAudioALSAVolumeController != NULL);
+ if (mAudioALSAVolumeController != NULL) {
+ mAudioALSAVolumeController->SetCaptureGain(mStreamAttributeTarget->audio_mode,
+ mStreamAttributeTarget->input_source,
+ mStreamAttributeTarget->input_device,
+ mStreamAttributeTarget->output_devices);
+ }
+
+ AUDIO_ALLOC_STRUCT(struct data_buf_t, mLinearOut);
+
+ // create lib manager
+ CreateAurisysLibManager();
+
+ //Android Native Preprocess effect +++
+ mAudioPreProcessEffect = new AudioPreProcess(mStreamAttributeTarget); // use the same attribute as stream in
+ ASSERT(mAudioPreProcessEffect != NULL);
+ CheckNativeEffect();
+ //Android Native Preprocess effect ---
+
+
+ // depop
+ drop_ms = getDropMs(mStreamAttributeTarget);
+ if ((drop_ms % mLatency) != 0) { // drop data size need to align interrupt rate
+ drop_ms = ((drop_ms / mLatency) + 1) * mLatency; // cell()
+ }
+ mDropPopSize = (audio_bytes_per_sample(mStreamAttributeTarget->audio_format) *
+ mStreamAttributeTarget->num_channels *
+ mStreamAttributeTarget->sample_rate *
+ drop_ms) / 1000;
+
+ size_per_sample = audio_bytes_per_sample(mStreamAttributeTarget->audio_format);
+ size_per_frame = mStreamAttributeTarget->num_channels * size_per_sample;
+ if ((mDropPopSize % size_per_frame) != 0) { // alignment
+ mDropPopSize = ((mDropPopSize / size_per_frame) + 1) * size_per_frame;
+ }
+ ASSERT(mDropPopSize >= mProcessedDataPeriodBufSize);
+
+
+ // processThread
+ hProcessThread = 0;
+ ret = pthread_create(&hProcessThread, NULL,
+ AudioALSACaptureDataClientAurisysNormal::processThread,
+ (void *)this);
+ ASSERT(ret == 0);
+ ALOGD("%s(-), drop_ms = %d", __FUNCTION__, drop_ms);
+}
+
+
+AudioALSACaptureDataClientAurisysNormal::~AudioALSACaptureDataClientAurisysNormal() {
+ // start to close
+ mEnable = false;
+
+ // terminate processThread thread
+ pthread_join(hProcessThread, NULL);
+ ALOGD("pthread_join hProcessThread done");
+
+ // detach client to capture data provider
+ mCaptureDataProvider->detach(this);
+ ALOGV("mCaptureDataProvider detach done");
+
+ if (IsAECEnable()) {
+ mCaptureDataProviderEchoRef->detach(this);
+ ALOGD("mCaptureDataProviderEchoRef detach done");
+ }
+
+
+
+ // close
+ AL_LOCK_MS(mRawDataBufLock, MAX_LOCK_TIME_OUT_MS);
+ AL_LOCK_MS(mProcessedDataBufLock, MAX_LOCK_TIME_OUT_MS);
+
+
+ //Android Native Preprocess effect +++
+ if (mAudioPreProcessEffect != NULL) { delete mAudioPreProcessEffect; }
+ //Android Native Preprocess effect ---
+
+ DestroyAurisysLibManager();
+
+ AUDIO_FREE_POINTER(mLinearOut);
+
+ AUDIO_FREE_POINTER(mRawDataBuf.base);
+ AUDIO_FREE_POINTER(mProcessedDataBuf.base);
+ AUDIO_FREE_POINTER(mEchoRefDataBuf.base);
+
+
+ AL_UNLOCK(mProcessedDataBufLock);
+ AL_UNLOCK(mRawDataBufLock);
+}
+
+
+uint32_t AudioALSACaptureDataClientAurisysNormal::copyCaptureDataToClient(RingBuf pcm_read_buf) {
+ audio_ringbuf_t pcm_read_buf_wrap;
+ int ret = 0;
+
+ if (mProcessThreadLaunched == false) {
+ ALOGD("%s(), mProcessThreadLaunched == false. return", __FUNCTION__);
+ return 0;
+ }
+
+ if ((mStreamAttributeSource->input_device == AUDIO_DEVICE_IN_USB_DEVICE) && (getPcmStatus() != true)) {
+ ALOGD("%s, PCM Open/Read Fail...USB Device is unplugged ?", __FUNCTION__);
+ AL_SIGNAL(mRawDataBufLock);
+ return 0;
+ }
+ pcm_read_buf_wrap.base = pcm_read_buf.pBufBase;
+ pcm_read_buf_wrap.read = pcm_read_buf.pRead;
+ pcm_read_buf_wrap.write = pcm_read_buf.pWrite;
+ pcm_read_buf_wrap.size = pcm_read_buf.bufLen;
+
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+ if (AudioDetectPulse::getDetectPulse()) {
+ detectPulseForRingbuf(
+ TAG_CAPTURE_DATA_CLIENT5,
+ &pcm_read_buf_wrap,
+ mStreamAttributeSource);
+ }
+#endif
+
+ ret = UL_LOCK_MS(mRawDataBufLock, MAX_RAW_DATA_LOCK_TIME_OUT_MS);
+ if (ret != 0) {
+ handleLockTimeout();
+ }
+ LATENCY_LOG("R+");
+
+ if (mEnable == false) {
+ ALOGV("%s(), mEnable == false. return", __FUNCTION__);
+ AL_SIGNAL(mRawDataBufLock);
+ AL_UNLOCK(mRawDataBufLock);
+ return 0;
+ }
+
+ if (IsAECEnable() == false) {
+ audio_ringbuf_copy_from_ringbuf_all(&mRawDataBuf, &pcm_read_buf_wrap);
+ AL_SIGNAL(mRawDataBufLock);
+ } else {
+ if (mIsEchoRefDataSync == false) {
+ syncEchoRefData(DATA_BUF_UPLINK_IN, &pcm_read_buf_wrap);
+ } else {
+ audio_ringbuf_copy_from_ringbuf_all(&mRawDataBuf, &pcm_read_buf_wrap);
+ }
+
+ if (mIsEchoRefDataSync == true &&
+ audio_ringbuf_count(&mRawDataBuf) >= mRawDataPeriodBufSize &&
+ audio_ringbuf_count(&mEchoRefDataBuf) >= mEchoRefDataPeriodBufSize) {
+ AL_SIGNAL(mRawDataBufLock);
+ }
+ }
+
+ LATENCY_LOG("R-");
+ AL_UNLOCK(mRawDataBufLock);
+ return 0;
+}
+bool AudioALSACaptureDataClientAurisysNormal::getPcmStatus(void) {
+ return (mCaptureDataProvider->getPcmStatus() == NO_ERROR);
+}
+
+void *AudioALSACaptureDataClientAurisysNormal::processThread(void *arg) {
+ char thread_name[128] = {0};
+
+ AudioALSACaptureDataClientAurisysNormal *client = NULL;
+
+ audio_ringbuf_t *raw_ul = NULL;
+ audio_ringbuf_t *raw_aec = NULL;
+ audio_ringbuf_t *processed = NULL;
+
+ aurisys_lib_manager_t *manager = NULL;
+ audio_pool_buf_t *ul_in = NULL;
+ audio_pool_buf_t *ul_out = NULL;
+ audio_pool_buf_t *ul_aec = NULL;
+
+ char *effect_buf = NULL;
+
+ uint32_t frame_idx = 0;
+
+ uint32_t data_count_raw_ul = 0;
+ uint32_t data_count_raw_aec = 0;
+
+ uint32_t data_count = 0;
+ uint32_t data_count_src = 0;
+
+ int wait_result = 0;
+ int ret = 0;
+
+ client = static_cast<AudioALSACaptureDataClientAurisysNormal *>(arg);
+
+ CONFIG_THREAD(thread_name, ANDROID_PRIORITY_AUDIO);
+#ifdef UPLINK_LOW_LATENCY
+ if (client->IsLowLatencyCapture()) {
+ audio_sched_setschedule(0, SCHED_RR, sched_get_priority_min(SCHED_RR));
+ }
+#endif
+
+ /* process thread created */
+ client->mProcessThreadLaunched = true;
+
+ /* get buffer address */
+ raw_ul = &client->mRawDataBuf;
+ raw_aec = &client->mEchoRefDataBuf;
+ processed = &client->mProcessedDataBuf;
+
+ manager = client->mAurisysLibManager;
+ ul_in = client->mAudioPoolBufUlIn;
+ ul_out = client->mAudioPoolBufUlOut;
+ ul_aec = client->mAudioPoolBufUlAec;
+
+
+
+ while (client->mEnable == true) {
+ ALOGV("%s(+)", __FUNCTION__);
+
+ LATENCY_LOG("1.1");
+ if ((client->mStreamAttributeSource->input_device == AUDIO_DEVICE_IN_USB_DEVICE) && (client->getPcmStatus() != true)) {
+ ALOGD("%s, PCM Open/Read Fail...USB Device is unplugged ?", __FUNCTION__);
+ AL_SIGNAL(client->mProcessedDataBufLock);
+ usleep(100);
+ continue;
+ }
+
+ // get data from raw buffer
+ ret = UL_LOCK_MS(client->mRawDataBufLock, MAX_RAW_DATA_LOCK_TIME_OUT_MS);
+ if (ret != 0) {
+ client->handleLockTimeout();
+ }
+
+ LATENCY_LOG("S+");
+ data_count_raw_ul = audio_ringbuf_count(raw_ul);
+ if (client->IsAECEnable()) { data_count_raw_aec = audio_ringbuf_count(raw_aec); }
+
+ // data not reary, wait data
+ if ((data_count_raw_ul < client->mRawDataPeriodBufSize) ||
+ (client->IsAECEnable() == true &&
+ (client->mIsEchoRefDataSync == false ||
+ data_count_raw_aec < client->mEchoRefDataPeriodBufSize))) {
+ LATENCY_LOG("1.2");
+ wait_result = AL_WAIT_MS(client->mRawDataBufLock, MAX_PROCESS_DATA_WAIT_TIME_OUT_MS);
+ LATENCY_LOG("S");
+ if (wait_result != 0) {
+ data_count_raw_ul = audio_ringbuf_count(raw_ul);
+ if (client->IsAECEnable()) {
+ data_count_raw_aec = audio_ringbuf_count(raw_aec);
+ }
+
+ if (client->IsAECEnable() && ((data_count_raw_ul < client->mRawDataPeriodBufSize) ||
+ (data_count_raw_aec < client->mEchoRefDataPeriodBufSize))) {
+ ALOGW("data_count_raw_ul %u, mRawDataPeriodBufSize %u, data_count_raw_aec %u, mEchoRefDataPeriodBufSize %u",
+ data_count_raw_ul, client->mRawDataPeriodBufSize, data_count_raw_aec, client->mEchoRefDataPeriodBufSize);
+ } else if (data_count_raw_ul < client->mRawDataPeriodBufSize) {
+ ALOGW("data_count_raw_ul %u, mRawDataPeriodBufSize %u", data_count_raw_ul, client->mRawDataPeriodBufSize);
+ }
+
+ LATENCY_LOG("S-");
+ AL_UNLOCK(client->mRawDataBufLock);
+ usleep(100);
+ continue;
+ }
+ LATENCY_LOG("1.3");
+
+ if (client->mEnable == false) {
+ ALOGV("%s(), record stopped. return", __FUNCTION__);
+ LATENCY_LOG("S-");
+ AL_UNLOCK(client->mRawDataBufLock);
+ break;
+ }
+
+ data_count_raw_ul = audio_ringbuf_count(raw_ul);
+ ALOGV("data_count_raw_ul %u, mRawDataPeriodBufSize %u",
+ data_count_raw_ul, client->mRawDataPeriodBufSize);
+
+ if (client->IsAECEnable()) {
+ data_count_raw_aec = audio_ringbuf_count(raw_aec);
+ ALOGV("data_count_raw_aec %u, mEchoRefDataPeriodBufSize %u",
+ data_count_raw_aec, client->mEchoRefDataPeriodBufSize);
+ }
+
+ if ((data_count_raw_ul < client->mRawDataPeriodBufSize) ||
+ (client->IsAECEnable() == true &&
+ (client->mIsEchoRefDataSync == false ||
+ data_count_raw_aec < client->mEchoRefDataPeriodBufSize))) {
+ AL_UNLOCK(client->mRawDataBufLock);
+ usleep(100);
+ continue;
+ }
+ }
+
+ LATENCY_LOG("2");
+
+ // make sure data ready
+ if (data_count_raw_ul < client->mRawDataPeriodBufSize) {
+ ALOGE("data_count_raw_ul %u != mRawDataPeriodBufSize %u",
+ data_count_raw_ul, client->mRawDataPeriodBufSize);
+ ASSERT(data_count_raw_ul >= client->mRawDataPeriodBufSize);
+ }
+ if (client->IsAECEnable()) {
+ if (data_count_raw_aec < client->mEchoRefDataPeriodBufSize) {
+ ALOGE("data_count_raw_aec %u != mEchoRefDataPeriodBufSize %u",
+ data_count_raw_aec, client->mEchoRefDataPeriodBufSize);
+ ASSERT(data_count_raw_aec >= client->mEchoRefDataPeriodBufSize);
+ }
+ }
+
+ // copy data
+ audio_pool_buf_copy_from_ringbuf(ul_in, raw_ul, client->mRawDataPeriodBufSize);
+ if (client->IsAECEnable()) {
+ audio_pool_buf_copy_from_ringbuf(ul_aec, raw_aec, client->mEchoRefDataPeriodBufSize);
+ }
+ frame_idx++;
+ LATENCY_LOG("S-");
+ AL_UNLOCK(client->mRawDataBufLock);
+ ALOGV("data_count %u, %dL", audio_ringbuf_count(&ul_in->ringbuf), __LINE__);
+
+
+ // aurisys processThread
+ // TODO: support channel remix in audio_pool_buf_handler.c
+#ifdef MTK_LATENCY_DETECT_PULSE
+ if (AudioDetectPulse::getDetectPulse()) {
+ detectPulseForRingbuf(
+ TAG_CAPTURE_DATA_CLIENT4,
+ &ul_in->ringbuf,
+ client->mStreamAttributeSource);
+ }
+#endif
+ aurisys_process_ul_only(manager,
+ ul_in,
+ ul_out,
+ ul_aec);
+ data_count = audio_ringbuf_count(&ul_out->ringbuf);
+ ALOGV("data_count %u, %dL", data_count, __LINE__);
+ if (data_count == 0) {
+ ALOGD("%s(), frame #%d data_count == 0, %dL", __FUNCTION__, frame_idx, __LINE__);
+ continue;
+ }
+ LATENCY_LOG("3");
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+ if (AudioDetectPulse::getDetectPulse()) {
+ detectPulseForRingbuf(
+ TAG_CAPTURE_DATA_CLIENT3,
+ &ul_out->ringbuf,
+ client->mStreamAttributeTarget);
+ }
+#endif
+
+ // depop
+ if (client->mDropPopSize > 0) {
+ ALOGV("data_count %u, mDropPopSize %u, %dL", data_count, client->mDropPopSize, __LINE__);
+
+ if (data_count >= client->mDropPopSize) {
+ audio_ringbuf_drop_data(&ul_out->ringbuf, client->mDropPopSize);
+ data_count -= client->mDropPopSize;
+ client->mDropPopSize = 0;
+ } else {
+ audio_ringbuf_drop_data(&ul_out->ringbuf, data_count);
+ client->mDropPopSize -= data_count;
+ data_count = 0;
+ }
+ }
+ if (data_count == 0) {
+ ALOGV("%s(), frame #%d data_count == 0, %dL", __FUNCTION__, frame_idx, __LINE__);
+ continue;
+ }
+
+
+ //Native Preprocess effect+++
+ ALOGV("data_count %u, %dL", data_count, __LINE__);
+ audio_pool_buf_copy_to_linear(
+ &client->mLinearOut->p_buffer,
+ &client->mLinearOut->memory_size,
+ ul_out,
+ data_count);
+ effect_buf = (char *)client->mLinearOut->p_buffer;
+ data_count = client->NativePreprocess(effect_buf, data_count);
+ ALOGV("data_count %u, %dL", data_count, __LINE__);
+ if (data_count == 0) {
+ ALOGD("%s(), frame #%d data_count == 0, %dL", __FUNCTION__, frame_idx, __LINE__);
+ continue;
+ }
+ //Native Preprocess effect---
+
+
+ // copy to processed buf and signal read()
+ ret = UL_LOCK_MS(client->mProcessedDataBufLock, MAX_PROCESS_DATA_LOCK_TIME_OUT_MS);
+ if (ret != 0) {
+ client->handleLockTimeout();
+ }
+ audio_ringbuf_copy_from_linear(processed, effect_buf, data_count);
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+ if (AudioDetectPulse::getDetectPulse()) {
+ detectPulseForRingbuf(
+ TAG_CAPTURE_DATA_CLIENT2,
+ processed,
+ client->mStreamAttributeTarget);
+ }
+#endif
+ AL_SIGNAL(client->mProcessedDataBufLock);
+ AL_UNLOCK(client->mProcessedDataBufLock);
+ LATENCY_LOG("4");
+
+ ALOGV("%s(-)", __FUNCTION__);
+ }
+
+
+ ALOGV("%s terminated", thread_name);
+ pthread_exit(NULL);
+ return NULL;
+}
+
+ssize_t AudioALSACaptureDataClientAurisysNormal::read(void *buffer, ssize_t bytes) {
+ ALOGV("%s(+), bytes: %u", __FUNCTION__, (uint32_t)bytes);
+
+ char *write = (char *)buffer;
+ uint32_t data_count = 0;
+ uint32_t left_count_to_read = bytes;
+
+ int try_count = 8;
+ int wait_result = 0;
+ int ret = 0;
+
+ uint32_t wait_ms = 0;
+
+ // clean buffer
+ memset(buffer, 0, bytes);
+
+ // wait time
+ wait_ms = (IsLowLatencyCapture()) ? mLatency * 5 : MAX_PROCESS_DATA_WAIT_TIME_OUT_MS;
+
+ // push clean up handlder for read thread termination
+ CLEANUP_PUSH_ALOCK(mProcessedDataBufLock.getAlock());
+
+ // copy processed data
+ do {
+ ret = UL_LOCK_MS(mProcessedDataBufLock, MAX_PROCESS_DATA_LOCK_TIME_OUT_MS);
+ if (ret != 0) {
+ handleLockTimeout();
+ }
+ data_count = audio_ringbuf_count(&mProcessedDataBuf);
+ if (data_count == 0) {
+ // wait for new data
+ wait_result = AL_WAIT_MS(mProcessedDataBufLock, wait_ms);
+ if ((mStreamAttributeSource->input_device == AUDIO_DEVICE_IN_USB_DEVICE) && (getPcmStatus() != true)) {
+ ALOGD("%s, PCM Open/Read Fail...USB Device is unplugged ?", __FUNCTION__);
+ AL_UNLOCK(mProcessedDataBufLock);
+ left_count_to_read = bytes;
+ break;
+ }
+ if (wait_result != 0) { // something error, exit
+ AL_UNLOCK(mProcessedDataBufLock);
+ try_count--;
+ usleep(100);
+ continue;
+ }
+
+ if (mEnable == false) {
+ ALOGD("%s(), record stopped. return", __FUNCTION__);
+ AL_UNLOCK(mProcessedDataBufLock);
+ break;
+ }
+
+ data_count = audio_ringbuf_count(&mProcessedDataBuf);
+ }
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+ if (AudioDetectPulse::getDetectPulse()) {
+ detectPulseForRingbuf(
+ TAG_CAPTURE_DATA_CLIENT1,
+ &mProcessedDataBuf,
+ mStreamAttributeTarget);
+ }
+#endif
+
+ if (data_count >= left_count_to_read) { // ring buffer is enough, copy & exit
+ audio_ringbuf_copy_to_linear(write, &mProcessedDataBuf, left_count_to_read);
+ AL_UNLOCK(mProcessedDataBufLock);
+ left_count_to_read = 0;
+ break;
+ }
+
+ audio_ringbuf_copy_to_linear((char *)write, &mProcessedDataBuf, data_count);
+ AL_UNLOCK(mProcessedDataBufLock);
+ left_count_to_read -= data_count;
+ write += data_count;
+
+ try_count--;
+ } while (left_count_to_read > 0 && try_count > 0 && mEnable == true);
+
+ // pop clean up handlder for read thread termination
+ CLEANUP_POP_ALOCK(mProcessedDataBufLock.getAlock());
+
+
+ if (left_count_to_read > 0) {
+ ALOGW("left_count_to_read %d!!", left_count_to_read);
+ }
+
+ // apply volume if need
+ bytes -= left_count_to_read;
+ ApplyVolume(buffer, bytes);
+
+
+ ALOGV("%s(-), bytes: %u", __FUNCTION__, (uint32_t)bytes);
+ return bytes;
+}
+
+
+bool AudioALSACaptureDataClientAurisysNormal::IsLowLatencyCapture(void) {
+ bool low_latency_on = false;
+ bool voip_on = IsVoIPEnable();
+ bool aec_on = IsAECEnable();
+
+#ifdef UPLINK_LOW_LATENCY
+ if (voip_on == false && aec_on == false &&
+ (mStreamAttributeTarget->mAudioInputFlags & AUDIO_INPUT_FLAG_FAST)) {
+ low_latency_on = true;
+ }
+#endif
+
+ ALOGV("%s(), low_latency_on: %d, voip_on: %d", __FUNCTION__, low_latency_on, voip_on);
+ return low_latency_on;
+}
+
+
+int AudioALSACaptureDataClientAurisysNormal::getCapturePosition(int64_t *frames, int64_t *time) {
+ if (mCaptureDataProvider == NULL || frames == NULL || time == NULL) {
+ return -EINVAL;
+ }
+
+ /* Convert provider sample rate to streamin sample rate*/
+ int ret = mCaptureDataProvider->getCapturePosition(frames, time);
+ *frames = (*frames) * mStreamAttributeTarget->sample_rate / mStreamAttributeSource->sample_rate;
+ ALOGV("%s(), frames = %" PRIu64 ", tar sample = %d, src sample = %d", __FUNCTION__, *frames, mStreamAttributeTarget->sample_rate, mStreamAttributeSource->sample_rate);
+ return ret;
+}
+
+
+void AudioALSACaptureDataClientAurisysNormal::AddEchoRefDataProvider(
+ AudioALSACaptureDataProviderBase *pCaptureDataProvider,
+ stream_attribute_t *stream_attribute_target) {
+
+ if (!pCaptureDataProvider || !stream_attribute_target) {
+ ALOGE("%s(), NULL! return", __FUNCTION__);
+ return;
+ }
+
+ WARNING("INVALID_OPERATION"); /* already added in ctor */
+ return;
+}
+
+
+uint32_t AudioALSACaptureDataClientAurisysNormal::copyEchoRefCaptureDataToClient(RingBuf pcm_read_buf) {
+ audio_ringbuf_t pcm_read_buf_wrap;
+
+ if (mProcessThreadLaunched == false) {
+ ALOGD("%s(), mProcessThreadLaunched == false. return", __FUNCTION__);
+ return 0;
+ }
+
+ pcm_read_buf_wrap.base = pcm_read_buf.pBufBase;
+ pcm_read_buf_wrap.read = pcm_read_buf.pRead;
+ pcm_read_buf_wrap.write = pcm_read_buf.pWrite;
+ pcm_read_buf_wrap.size = pcm_read_buf.bufLen;
+
+ ASSERT(IsAECEnable());
+
+ AL_LOCK_MS(mRawDataBufLock, MAX_RAW_DATA_LOCK_TIME_OUT_MS);
+ LATENCY_LOG("E+");
+
+ if (mEnable == false) {
+ ALOGV("%s(), mEnable == false. return", __FUNCTION__);
+ AL_SIGNAL(mRawDataBufLock);
+ AL_UNLOCK(mRawDataBufLock);
+ return 0;
+ }
+
+ if (mIsEchoRefDataSync == false) {
+ syncEchoRefData(DATA_BUF_ECHO_REF, &pcm_read_buf_wrap);
+ } else {
+ audio_ringbuf_copy_from_ringbuf_all(&mEchoRefDataBuf, &pcm_read_buf_wrap);
+ }
+
+ if (mIsEchoRefDataSync == true &&
+ audio_ringbuf_count(&mRawDataBuf) >= mRawDataPeriodBufSize &&
+ audio_ringbuf_count(&mEchoRefDataBuf) >= mEchoRefDataPeriodBufSize) {
+ AL_SIGNAL(mRawDataBufLock);
+ }
+
+ LATENCY_LOG("E-");
+ AL_UNLOCK(mRawDataBufLock);
+ return 0;
+}
+
+
+void AudioALSACaptureDataClientAurisysNormal::syncEchoRefData(
+ const uint8_t data_buf_type, /* data_buf_type_t */
+ audio_ringbuf_t *rb) {
+
+ uint64_t time_diff_ns = 0;
+ uint32_t diff_buf_size = 0;
+
+ uint32_t data_count = 0;
+
+ int ret = 0;
+
+
+ ASSERT(IsAECEnable() == true);
+ ASSERT(mIsEchoRefDataSync == false);
+ if (IsAECEnable() == false || mIsEchoRefDataSync == true) {
+ return;
+ }
+
+
+ if (data_buf_type == DATA_BUF_UPLINK_IN) {
+ if (isTimeStampStarted(&mRawDataBufTimeStamp) == false) { // only keep the first timestamp
+ ret = calculateTotalTimeSpec(&mStreamAttributeSource->Time_Info, &mRawDataBufTimeStamp);
+ if (ret != 0) {
+ //ASSERT(ret == 0);
+ return;
+ }
+ ALOGD("%s(UL*), UL in: %lld.%.9ld, EchoRef: %lld.%.9ld", __FUNCTION__,
+ (long long)mRawDataBufTimeStamp.tv_sec,
+ mRawDataBufTimeStamp.tv_nsec,
+ (long long)mEchoRefDataBufTimeStamp.tv_sec,
+ mEchoRefDataBufTimeStamp.tv_nsec);
+ } else {
+ ALOGD("%s(UL), UL in: %lld.%.9ld, EchoRef: %lld.%.9ld", __FUNCTION__,
+ (long long)mStreamAttributeSource->Time_Info.timestamp_get.tv_sec,
+ mStreamAttributeSource->Time_Info.timestamp_get.tv_nsec,
+ (long long)mEchoRefDataBufTimeStamp.tv_sec,
+ mEchoRefDataBufTimeStamp.tv_nsec);
+ }
+
+ if (isTimeStampStarted(&mEchoRefDataBufTimeStamp) == false) { // echo ref data not ready
+ audio_ringbuf_copy_from_ringbuf_all(&mRawDataBuf, rb);
+ } else { // already got echo ref data
+ audio_ringbuf_copy_from_ringbuf_all(&mRawDataBuf, rb);
+
+ if (t1_older_then_t2(&mEchoRefDataBufTimeStamp, &mRawDataBufTimeStamp)) { // ul new
+ time_diff_ns = get_time_diff_ns(&mEchoRefDataBufTimeStamp, &mRawDataBufTimeStamp);
+ diff_buf_size = getDiffBufSize(mStreamAttributeSource, time_diff_ns);
+ ALOGD("%s(), I. time_diff_ms %lf, compensate %u ul data", __FUNCTION__, ((double)time_diff_ns / 1000000), diff_buf_size);
+
+ audio_ringbuf_compensate_value(&mRawDataBuf, 0, diff_buf_size);
+ mIsEchoRefDataSync = true;
+ } else { // aec new
+ time_diff_ns = get_time_diff_ns(&mRawDataBufTimeStamp, &mEchoRefDataBufTimeStamp);
+ diff_buf_size = getDiffBufSize(mStreamAttributeSourceEchoRef, time_diff_ns);
+ ALOGD("%s(), II. time_diff_ms %lf, compensate %u echo ref data", __FUNCTION__, ((double)time_diff_ns / 1000000), diff_buf_size);
+
+ audio_ringbuf_compensate_value(&mEchoRefDataBuf, 0, diff_buf_size);
+ mIsEchoRefDataSync = true;
+ }
+ }
+ } else if (data_buf_type == DATA_BUF_ECHO_REF) {
+ if (isTimeStampStarted(&mEchoRefDataBufTimeStamp) == false) { // only keep the first timestamp
+ ret = calculateTotalTimeSpec(&mStreamAttributeSourceEchoRef->Time_Info, &mEchoRefDataBufTimeStamp);
+ if (ret != 0) {
+ //ASSERT(ret == 0);
+ return;
+ }
+ ALOGD("%s(AEC*), UL in: %lld.%.9ld, EchoRef: %lld.%.9ld", __FUNCTION__,
+ (long long)mRawDataBufTimeStamp.tv_sec,
+ mRawDataBufTimeStamp.tv_nsec,
+ (long long)mEchoRefDataBufTimeStamp.tv_sec,
+ mEchoRefDataBufTimeStamp.tv_nsec);
+ } else {
+ ALOGD("%s(AEC), UL in: %lld.%.9ld, EchoRef: %lld.%.9ld", __FUNCTION__,
+ (long long)mRawDataBufTimeStamp.tv_sec,
+ mRawDataBufTimeStamp.tv_nsec,
+ (long long)mStreamAttributeSourceEchoRef->Time_Info.timestamp_get.tv_sec,
+ mStreamAttributeSourceEchoRef->Time_Info.timestamp_get.tv_nsec);
+ }
+
+ if (isTimeStampStarted(&mRawDataBufTimeStamp) == false) { // ul data not ready
+ audio_ringbuf_copy_from_ringbuf_all(&mEchoRefDataBuf, rb);
+ } else { // already got ul data
+ audio_ringbuf_copy_from_ringbuf_all(&mEchoRefDataBuf, rb);
+
+ if (t1_older_then_t2(&mRawDataBufTimeStamp, &mEchoRefDataBufTimeStamp)) { // aec new
+ time_diff_ns = get_time_diff_ns(&mRawDataBufTimeStamp, &mEchoRefDataBufTimeStamp);
+ diff_buf_size = getDiffBufSize(mStreamAttributeSourceEchoRef, time_diff_ns);
+ ALOGD("%s(), III. time_diff_ms %lf, compensate %u echo ref data", __FUNCTION__, ((double)time_diff_ns / 1000000), diff_buf_size);
+
+ audio_ringbuf_compensate_value(&mEchoRefDataBuf, 0, diff_buf_size);
+ mIsEchoRefDataSync = true;
+ } else { // ul new
+ time_diff_ns = get_time_diff_ns(&mEchoRefDataBufTimeStamp, &mRawDataBufTimeStamp);
+ diff_buf_size = getDiffBufSize(mStreamAttributeSource, time_diff_ns);
+ ALOGD("%s(), IV. time_diff_ms %lf, compensate %u ul data", __FUNCTION__, ((double)time_diff_ns / 1000000), diff_buf_size);
+
+ audio_ringbuf_compensate_value(&mRawDataBuf, 0, diff_buf_size);
+ mIsEchoRefDataSync = true;
+ }
+ }
+ } else {
+ ASSERT(0);
+ }
+
+ if (mIsEchoRefDataSync) { // compensate data will add latency, drop it
+ AUD_LOG_D("+mRawDataBuf data_count %u, mEchoRefDataBuf data_count %u, mRawDataPeriodBufSize = %u, mEchoRefDataPeriodBufSize = %u",
+ audio_ringbuf_count(&mRawDataBuf), audio_ringbuf_count(&mEchoRefDataBuf), mRawDataPeriodBufSize, mEchoRefDataPeriodBufSize);
+ while (audio_ringbuf_count(&mRawDataBuf) >= mRawDataPeriodBufSize &&
+ audio_ringbuf_count(&mEchoRefDataBuf) >= mEchoRefDataPeriodBufSize) {
+ audio_ringbuf_drop_data(&mRawDataBuf, mRawDataPeriodBufSize);
+ audio_ringbuf_drop_data(&mEchoRefDataBuf, mEchoRefDataPeriodBufSize);
+ }
+ AUD_LOG_D("-mRawDataBuf data_count %u, -mEchoRefDataBuf data_count %u", audio_ringbuf_count(&mRawDataBuf), audio_ringbuf_count(&mEchoRefDataBuf));
+ }
+}
+
+
+bool AudioALSACaptureDataClientAurisysNormal::IsNeedApplyVolume() {
+ bool ret = false;
+
+ /* Only real input CaptureDataprovider need to apply volume for mic mute */
+ switch (mCaptureDataProvider->getCaptureDataProviderType()) {
+ case CAPTURE_PROVIDER_NORMAL:
+ case CAPTURE_PROVIDER_BT_SCO:
+ case CAPTURE_PROVIDER_BT_CVSD:
+ case CAPTURE_PROVIDER_TDM_RECORD:
+ case CAPTURE_PROVIDER_EXTERNAL:
+ ret = true;
+ break;
+ default:
+ ret = false;
+ break;
+ }
+
+ return ret;
+}
+
+
+status_t AudioALSACaptureDataClientAurisysNormal::ApplyVolume(void *Buffer, uint32_t BufferSize) {
+ if (IsNeedApplyVolume() == false) {
+ return NO_ERROR;
+ }
+
+ // check if need apply mute
+ if (mMicMute != mStreamAttributeTarget->micmute) {
+ mMicMute = mStreamAttributeTarget->micmute ;
+ mMuteTransition = false;
+ }
+
+ if (mMicMute == true) {
+ // do ramp down
+ if (mMuteTransition == false) {
+ uint32_t count = BufferSize >> 1;
+ float Volume_inverse = ((float)MTK_STREAMIN_VOLUEM_MAX / (float)count) * -1;
+ short *pPcm = (short *)Buffer;
+ int ConsumeSample = 0;
+ int value = 0;
+ while (count) {
+ value = *pPcm * (MTK_STREAMIN_VOLUEM_MAX + (Volume_inverse * ConsumeSample));
+ *pPcm = clamp16(value >> MTK_STREAMIN_VOLUME_VALID_BIT);
+ pPcm++;
+ count--;
+ ConsumeSample ++;
+ //ALOGD("ApplyVolume Volume_inverse = %f ConsumeSample = %d",Volume_inverse,ConsumeSample);
+ }
+ mMuteTransition = true;
+ } else {
+ memset(Buffer, 0, BufferSize);
+ }
+ } else if (mMicMute == false) {
+ // do ramp up
+ if (mMuteTransition == false) {
+ uint32_t count = BufferSize >> 1;
+ float Volume_inverse = ((float)MTK_STREAMIN_VOLUEM_MAX / (float)count);
+ short *pPcm = (short *)Buffer;
+ int ConsumeSample = 0;
+ int value = 0;
+ while (count) {
+ value = *pPcm * (Volume_inverse * ConsumeSample);
+ *pPcm = clamp16(value >> MTK_STREAMIN_VOLUME_VALID_BIT);
+ pPcm++;
+ count--;
+ ConsumeSample ++;
+ //ALOGD("ApplyVolume Volume_inverse = %f ConsumeSample = %d",Volume_inverse,ConsumeSample);
+ }
+ mMuteTransition = true;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+
+/*
+ * =============================================================================
+ * Aurisys Framework 2.0
+ * =============================================================================
+ */
+
+void AudioALSACaptureDataClientAurisysNormal::CreateAurisysLibManager() {
+ uint32_t sample_rate = 0 ;
+ const char* libKey = "MTKSE";
+
+ /* scenario & sample rate */
+ if (IsVoIPEnable()) {
+ mAurisysScenario = (IsAECEnable()) ? AURISYS_SCENARIO_VOIP : AURISYS_SCENARIO_VOIP_WITHOUT_AEC;
+ sample_rate = 16000;
+ } else if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION1 ||
+ mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION2) {
+ ASSERT(IsAECEnable() == true);
+ mAurisysScenario = AURISYS_SCENARIO_RECORD_WITH_AEC;
+ sample_rate = 16000;
+ } else if (IsLowLatencyCapture() || mStreamAttributeTarget->input_source == AUDIO_SOURCE_UNPROCESSED) {
+ mAurisysScenario = AURISYS_SCENARIO_RECORD_LOW_LATENCY;
+ if (mStreamAttributeSource->sample_rate == 16000 ||
+ mStreamAttributeSource->sample_rate == 48000) {
+ sample_rate = mStreamAttributeSource->sample_rate;
+ } else {
+ sample_rate = 48000;
+ }
+ } else if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_RECOGNITION) { /* no echo ref */
+ mAurisysScenario = AURISYS_SCENARIO_RECORD_WITHOUT_AEC;
+ sample_rate = 48000;
+ } else if (mStreamAttributeTarget->input_source == AUDIO_SOURCE_CUSTOMIZATION3 ||
+ mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_CALL ||
+ mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_UPLINK ||
+ mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_DOWNLINK) {
+ mAurisysScenario = AURISYS_SCENARIO_RECORD_WITHOUT_AEC;
+ sample_rate = 16000;
+ } else {
+ mAurisysScenario = AURISYS_SCENARIO_RECORD_WITHOUT_AEC;
+ sample_rate = 48000;
+ }
+
+ /* manager config */
+ AUDIO_ALLOC_STRUCT(struct aurisys_lib_manager_config_t, mManagerConfig);
+
+ mManagerConfig->aurisys_scenario = mAurisysScenario;
+ mManagerConfig->arsi_process_type = ARSI_PROCESS_TYPE_UL_ONLY;
+ mManagerConfig->audio_format = mStreamAttributeSource->audio_format;
+ mManagerConfig->sample_rate = sample_rate;
+ mManagerConfig->frame_size_ms = (uint8_t)mLatency;
+ mManagerConfig->num_channels_ul = mStreamAttributeSource->num_channels;
+ mManagerConfig->num_channels_dl = 2;
+ mManagerConfig->core_type = AURISYS_CORE_HAL;
+
+ ALOGD("%s(), voip: %d, low_latency: %d, aec: %d, input_source: %d, flag: 0x%x => mAurisysScenario: %u",
+ __FUNCTION__,
+ IsVoIPEnable(),
+ IsLowLatencyCapture(),
+ IsAECEnable(),
+ mStreamAttributeTarget->input_source,
+ mStreamAttributeTarget->mAudioInputFlags,
+ mAurisysScenario);
+
+ /* task config */
+ InitArsiTaskConfig(mManagerConfig);
+
+ /* create manager */
+ AL_AUTOLOCK(mAurisysLibManagerLock);
+
+ mAurisysLibManager = create_aurisys_lib_manager(mManagerConfig);
+ InitBufferConfig(mAurisysLibManager);
+
+ aurisys_parsing_param_file(mAurisysLibManager);
+ aurisys_create_arsi_handlers(mAurisysLibManager); /* should init task/buf configs first */
+ aurisys_pool_buf_formatter_init(mAurisysLibManager); /* should init task/buf configs first */
+
+ // Set custom scene information to all UL lib
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps && appOps->appHandleIsFeatureOptionEnabled(appOps->appHandleGetInstance(), "VIR_SCENE_CUSTOMIZATION_SUPPORT"))
+ {
+ /* Apply parameter for scene */
+ const char* scenarioStr = get_string_by_enum_aurisys_scenario(AURISYS_CORE_HAL, mAurisysScenario);
+ String8 key_value_pair = String8::format("HAL,%s,%s,KEY_VALUE,SetAudioCustomScene,%s=SET",
+ scenarioStr,
+ libKey,
+ mStreamAttributeTarget->mCustScene);
+ aurisys_set_parameter(key_value_pair.string());
+
+ key_value_pair = String8::format("HAL,%s,%s,APPLY_PARAM,0=SET", scenarioStr, libKey);
+ aurisys_set_parameter(key_value_pair.string());
+ }
+
+
+ int16_t ulDigitalGain = mAudioALSAVolumeController->GetSWMICGain() << 2; // (unit: 0.25 db)
+ int16_t ulAnalogGain = ((mAudioALSAVolumeController->GetULTotalGain() - 192) / 4 + 34 - mAudioALSAVolumeController->GetSWMICGain()) << 2; // (unit: 0.25 db)
+ if (mStreamAttributeTarget->input_device == AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+ ulDigitalGain = 0;
+ ulAnalogGain = 0;
+ ALOGD("BT path set Digital MIC gain = 0");
+ }
+ aurisys_set_ul_digital_gain(mAurisysLibManager, ulAnalogGain, ulDigitalGain);
+ //aurisys_set_dl_digital_gain(mAurisysLibManager, 0, 0);
+}
+
+
+/* TODO: move to aurisys framework?? add a new struct to keep hal arributes */
+void AudioALSACaptureDataClientAurisysNormal::InitArsiTaskConfig(
+ struct aurisys_lib_manager_config_t *pManagerConfig) {
+ struct arsi_task_config_t *pTaskConfig = &pManagerConfig->task_config;
+
+ /* input device */
+ pTaskConfig->input_device_info.devices = mStreamAttributeTarget->input_device; /* TODO: HAL capture */
+ pTaskConfig->input_device_info.audio_format = mStreamAttributeSource->audio_format;
+ pTaskConfig->input_device_info.sample_rate = mStreamAttributeSource->sample_rate;
+ pTaskConfig->input_device_info.channel_mask = mStreamAttributeSource->audio_channel_mask; /* TODO */
+ pTaskConfig->input_device_info.num_channels = mStreamAttributeSource->num_channels;
+ pTaskConfig->input_device_info.hw_info_mask = 0; /* TODO */
+
+ /* output device (no DL path for record) */
+ pTaskConfig->output_device_info.devices = mStreamAttributeTarget->output_devices;
+ pTaskConfig->output_device_info.audio_format = AUDIO_FORMAT_DEFAULT;
+ pTaskConfig->output_device_info.sample_rate = 0;
+ pTaskConfig->output_device_info.channel_mask = AUDIO_CHANNEL_NONE;
+ pTaskConfig->output_device_info.num_channels = 0;
+ pTaskConfig->output_device_info.hw_info_mask = 0;
+
+ /* task scene */
+ pTaskConfig->task_scene = map_aurisys_scenario_to_task_scene(
+ pManagerConfig->core_type,
+ pManagerConfig->aurisys_scenario);
+
+ /* audio mode */
+ pTaskConfig->audio_mode = mStreamAttributeTarget->audio_mode;
+
+ /* max device capability for allocating memory */
+ pTaskConfig->max_input_device_sample_rate = 48000; /* TODO */
+ pTaskConfig->max_output_device_sample_rate = 48000; /* TODO */
+
+ pTaskConfig->max_input_device_num_channels =
+ AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport();
+ pTaskConfig->max_output_device_num_channels = 2; /* TODO */
+
+ /* flag & source */
+ pTaskConfig->output_flags = 0;
+ pTaskConfig->input_source = mStreamAttributeTarget->input_source;
+ pTaskConfig->input_flags = mStreamAttributeTarget->mAudioInputFlags;
+
+ if (pTaskConfig->output_device_info.devices & AUDIO_DEVICE_OUT_SPEAKER &&
+ AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ pTaskConfig->output_device_info.hw_info_mask = OUTPUT_DEVICE_HW_INFO_SMARTPA_SPEAKER;
+ ALOGV("%s(), SmartPA suppport, pTaskConfig->output_device_info.hw_info_mask = %d",
+ __FUNCTION__, pTaskConfig->output_device_info.hw_info_mask);
+ }
+
+ /* Enhancement feature */
+ if (pTaskConfig->output_device_info.devices == AUDIO_DEVICE_OUT_EARPIECE &&
+ SpeechEnhancementController::GetInstance()->GetHACOn()) {
+ pTaskConfig->enhancement_feature_mask |= ENHANCEMENT_FEATURE_EARPIECE_HAC;
+ }
+
+ if ((pTaskConfig->input_device_info.devices & AUDIO_DEVICE_IN_ALL_SCO)
+ && (pTaskConfig->output_device_info.devices & AUDIO_DEVICE_OUT_ALL_SCO)
+ && SpeechEnhancementController::GetInstance()->GetBtHeadsetNrecOn()) {
+ pTaskConfig->enhancement_feature_mask |= ENHANCEMENT_FEATURE_BT_NREC;
+ }
+
+ if ((pTaskConfig->input_source == AUDIO_SOURCE_VOICE_COMMUNICATION)
+ && (mStreamAttributeTarget->NativePreprocess_Info.PreProcessEffect_AECOn == true)
+ && (pTaskConfig->input_device_info.devices != AUDIO_DEVICE_IN_ALL_SCO)) {
+ pTaskConfig->enhancement_feature_mask |= ENHANCEMENT_FEATURE_EC;
+ }
+
+ dump_task_config(pTaskConfig);
+}
+
+
+void AudioALSACaptureDataClientAurisysNormal::InitBufferConfig(struct aurisys_lib_manager_t *manager) {
+ /* UL in */
+ mAudioPoolBufUlIn = create_audio_pool_buf(manager, DATA_BUF_UPLINK_IN, 0);
+
+ mAudioPoolBufUlIn->buf->b_interleave = 1; /* LRLRLRLR*/
+ mAudioPoolBufUlIn->buf->frame_size_ms = 0;
+ mAudioPoolBufUlIn->buf->num_channels = mStreamAttributeSource->num_channels;
+ mAudioPoolBufUlIn->buf->sample_rate_buffer = mStreamAttributeSource->sample_rate;
+ mAudioPoolBufUlIn->buf->sample_rate_content = mStreamAttributeSource->sample_rate;
+ mAudioPoolBufUlIn->buf->audio_format = mStreamAttributeSource->audio_format;
+
+
+ /* UL out */
+ mAudioPoolBufUlOut = create_audio_pool_buf(manager, DATA_BUF_UPLINK_OUT, 0);
+
+ mAudioPoolBufUlOut->buf->b_interleave = 1; /* LRLRLRLR*/
+ mAudioPoolBufUlOut->buf->frame_size_ms = 0;
+ mAudioPoolBufUlOut->buf->num_channels = mStreamAttributeTarget->num_channels;
+ mAudioPoolBufUlOut->buf->sample_rate_buffer = mStreamAttributeTarget->sample_rate;
+ mAudioPoolBufUlOut->buf->sample_rate_content = mStreamAttributeTarget->sample_rate;
+ mAudioPoolBufUlOut->buf->audio_format = mStreamAttributeTarget->audio_format;
+
+
+ /* Echo Ref */
+ if (IsAECEnable()) {
+ ASSERT(mStreamAttributeSourceEchoRef != NULL);
+ mAudioPoolBufUlAec = create_audio_pool_buf(manager, DATA_BUF_ECHO_REF, 0);
+
+ mAudioPoolBufUlAec->buf->b_interleave = 1; /* LRLRLRLR*/
+ mAudioPoolBufUlAec->buf->frame_size_ms = 0;
+ mAudioPoolBufUlAec->buf->num_channels = mStreamAttributeSourceEchoRef->num_channels;
+ mAudioPoolBufUlAec->buf->sample_rate_buffer = mStreamAttributeSourceEchoRef->sample_rate;
+ mAudioPoolBufUlAec->buf->sample_rate_content = mStreamAttributeSourceEchoRef->sample_rate;
+ mAudioPoolBufUlAec->buf->audio_format = mStreamAttributeSourceEchoRef->audio_format;
+ }
+
+}
+
+
+void AudioALSACaptureDataClientAurisysNormal::DestroyAurisysLibManager() {
+ ALOGD("%s()", __FUNCTION__);
+
+ AL_AUTOLOCK(mAurisysLibManagerLock);
+
+ aurisys_destroy_arsi_handlers(mAurisysLibManager);
+ aurisys_pool_buf_formatter_deinit(mAurisysLibManager);
+ destroy_aurisys_lib_manager(mAurisysLibManager);
+ mAurisysLibManager = NULL;
+
+ /* NOTE: auto destroy audio_pool_buf when destroy_aurisys_lib_manager() */
+ mAudioPoolBufUlIn = NULL;
+ mAudioPoolBufUlOut = NULL;
+ mAudioPoolBufUlAec = NULL;
+ mAudioPoolBufDlIn = NULL;
+ mAudioPoolBufDlOut = NULL;
+
+ AUDIO_FREE_POINTER(mLinearOut->p_buffer);
+ memset(mLinearOut, 0, sizeof(data_buf_t));
+
+ AUDIO_FREE_POINTER(mManagerConfig);
+}
+
+
+//Android Native Preprocess effect +++
+void AudioALSACaptureDataClientAurisysNormal::CheckNativeEffect(void) {
+ if (mStreamAttributeTarget->NativePreprocess_Info.PreProcessEffect_Update == false) {
+ return; // nothing to update
+ }
+
+ ASSERT(mAudioPreProcessEffect != NULL);
+ mAudioPreProcessEffect->CheckNativeEffect();
+ mStreamAttributeTarget->NativePreprocess_Info.PreProcessEffect_Update = false;
+}
+
+
+uint32_t AudioALSACaptureDataClientAurisysNormal::NativePreprocess(void *buffer, uint32_t bytes) {
+ CheckNativeEffect(); // stream in might addAudioEffect/removeAudioEffect
+ if (mAudioPreProcessEffect->num_preprocessors == 0 || IsVoIPEnable() == true) {
+ return bytes;
+ }
+
+ return mAudioPreProcessEffect->NativePreprocess(buffer, bytes, &mStreamAttributeSource->Time_Info);
+}
+//Android Native Preprocess effect ---
+
+
+void AudioALSACaptureDataClientAurisysNormal::handleLockTimeout() {
+ ALOGE("%s(), Lock timeout. Reopen StreamIn", __FUNCTION__);
+ setStreamInReopen(true);
+}
+
+
+} // end of namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataClientDsp.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataClientDsp.cpp
new file mode 100644
index 0000000..4be0e1a
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataClientDsp.cpp
@@ -0,0 +1,735 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureDataClientDsp.h"
+
+#include <inttypes.h>
+#include <pthread.h>
+#include <sys/prctl.h>
+
+
+#include "AudioUtility.h"
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+#include "AudioVolumeInterface.h"
+#include "AudioVolumeFactory.h"
+
+
+#include <audio_memory_control.h>
+#include <audio_lock.h>
+#include <audio_ringbuf.h>
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACaptureDataClientDsp"
+
+#ifndef UPLINK_DROP_POP_MS
+#define DROP_POP_MS (50)
+#else
+#define DROP_POP_MS (UPLINK_DROP_POP_MS)
+#endif
+
+#ifndef UPLINK_DROP_POP_MS_FOR_UNPROCESSED
+#define DROP_POP_MS_FOR_UNPROCESSED (80)
+#else
+#define DROP_POP_MS_FOR_UNPROCESSED (UPLINK_DROP_POP_MS_FOR_UNPROCESSED)
+#endif
+
+
+namespace android {
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+static const uint32_t kRawDataBufferSize = 0x10000; // 64k
+static const uint32_t kProcessedBufferSize = 0x10000; // 64k
+
+static const uint32_t kBliSrcOutputBufferSize = 0x20000; // 128k
+static const uint32_t kMaxPcmDriverBufferSize = 0x20000; // 128k
+
+
+#define MTK_STREAMIN_VOLUEM_MAX (0x1000)
+#define MTK_STREAMIN_VOLUME_VALID_BIT (12)
+
+
+#define MAX_LOCK_TIME_OUT_MS (500)
+#define MAX_WAIT_TIME_OUT_MS (500)
+
+/*==============================================================================
+ * Utility
+ *============================================================================*/
+
+static uint32_t getDropMs(stream_attribute_t *attribute_target) {
+ if (attribute_target->input_source == AUDIO_SOURCE_UNPROCESSED) {
+ return DROP_POP_MS_FOR_UNPROCESSED;
+ } else {
+ return DROP_POP_MS;
+ }
+}
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataClientDsp::AudioALSACaptureDataClientDsp(
+ AudioALSACaptureDataProviderBase *pCaptureDataProvider,
+ stream_attribute_t *stream_attribute_target) :
+ mStreamAttributeSource(NULL),
+ mStreamAttributeTarget(stream_attribute_target),
+ mCaptureDataProvider(pCaptureDataProvider),
+ mRawStartFrameCount(0),
+ mMicMute(false),
+ mMuteTransition(false),
+ mEnable(false),
+ mRawDataBufLinear(NULL),
+ mBliSrc(NULL),
+ mBliSrcOutputBuffer(NULL),
+ mBitConverter(NULL),
+ mBitConverterOutputBuffer(NULL),
+ mDropPopSize(0) {
+
+ // init var
+ AudioVolumeInterface *pVolumeController = NULL;
+ uint32_t latency = 0;
+ uint32_t drop_ms = 0;
+ uint32_t size_per_sample = 0;
+ uint32_t size_per_frame = 0;
+ int ret = 0;
+
+
+ // init raw data buf
+ memset((void *)&mRawDataBuf, 0, sizeof(mRawDataBuf));
+ memset((void *)&mStreamAttributeTargetDSP, 0, sizeof(mStreamAttributeTargetDSP));
+
+ AUDIO_ALLOC_CHAR_BUFFER(mRawDataBuf.base, kRawDataBufferSize);
+ mRawDataBuf.read = mRawDataBuf.base;
+ mRawDataBuf.write = mRawDataBuf.base;
+ mRawDataBuf.size = kRawDataBufferSize;
+ AUDIO_ALLOC_CHAR_BUFFER(mRawDataBufLinear, kRawDataBufferSize);
+
+ // init processed data buf
+ memset((void *)&mProcessedDataBuf, 0, sizeof(mProcessedDataBuf));
+
+ AUDIO_ALLOC_CHAR_BUFFER(mProcessedDataBuf.base, kProcessedBufferSize);
+ mProcessedDataBuf.read = mProcessedDataBuf.base;
+ mProcessedDataBuf.write = mProcessedDataBuf.base;
+ mProcessedDataBuf.size = kProcessedBufferSize;
+
+ configDSPAttribute();
+
+
+ // config attribute for input device
+ mCaptureDataProvider->configStreamAttribute(&mStreamAttributeTargetDSP);
+
+ // get attribute before enable
+ mStreamAttributeSource = mCaptureDataProvider->getStreamAttributeSource();
+
+ // enable before attach
+ mEnable = true;
+
+ // attach client to capture data provider (after data buf ready)
+ mCaptureDataProvider->attach(this);
+
+ mStreamAttributeTargetDSP = mCaptureDataProvider->getStreamAttributeTargetDSP();
+
+ // Gain control // TODO: AudioMTKGainController::SetCaptureGain, multi data client !?
+ pVolumeController = AudioVolumeFactory::CreateAudioVolumeController();
+ AUD_ASSERT(pVolumeController != NULL);
+ if (pVolumeController != NULL) {
+ pVolumeController->SetCaptureGain(mStreamAttributeTarget->audio_mode,
+ mStreamAttributeTarget->input_source,
+ mStreamAttributeTarget->input_device,
+ mStreamAttributeTarget->output_devices);
+ }
+
+
+ // SRC
+ initBliSrc();
+
+ // bit conversion
+ initBitConverter();
+
+
+ // depop
+ latency = mCaptureDataProvider->getLatencyTime();
+ drop_ms = getDropMs(stream_attribute_target);
+ if ((drop_ms % latency) != 0) { // drop data size need to align interrupt rate
+ drop_ms = ((drop_ms / latency) + 1) * latency; // cell()
+ }
+ mDropPopSize = (audio_bytes_per_sample(mStreamAttributeTarget->audio_format) *
+ mStreamAttributeTarget->num_channels *
+ mStreamAttributeTarget->sample_rate *
+ drop_ms) / 1000;
+ size_per_sample = audio_bytes_per_sample(mStreamAttributeTarget->audio_format);
+ size_per_frame = mStreamAttributeTarget->num_channels * size_per_sample;
+ if ((mDropPopSize % size_per_frame) != 0) { // alignment
+ mDropPopSize = ((mDropPopSize / size_per_frame) + 1) * size_per_frame;
+ }
+
+ // processThread
+ hProcessThread = 0;
+ ret = pthread_create(&hProcessThread, NULL,
+ AudioALSACaptureDataClientDsp::processThread,
+ (void *)this);
+ ASSERT(ret == 0);
+ ALOGD("%s(-), drop_ms = %d, latency = %d, mDropPopSize = %d", __FUNCTION__, drop_ms, latency, mDropPopSize);
+}
+
+
+AudioALSACaptureDataClientDsp::~AudioALSACaptureDataClientDsp() {
+ // start to close
+ mEnable = false;
+
+ // terminate processThread thread
+ pthread_join(hProcessThread, NULL);
+ ALOGD("pthread_join hProcessThread done");
+
+ // detach client to capture data provider
+ mCaptureDataProvider->detach(this);
+ ALOGD("mCaptureDataProvider detach done");
+
+
+ // close
+ AL_LOCK_MS(mRawDataBufLock, MAX_LOCK_TIME_OUT_MS);
+ AL_LOCK_MS(mProcessedDataBufLock, MAX_LOCK_TIME_OUT_MS);
+
+
+ // bit conversion
+ deinitBitConverter();
+
+ // SRC
+ deinitBliSrc();
+
+
+ AUDIO_FREE_POINTER(mRawDataBufLinear);
+ AUDIO_FREE_POINTER(mRawDataBuf.base);
+ AUDIO_FREE_POINTER(mProcessedDataBuf.base);
+
+ AL_UNLOCK(mProcessedDataBufLock);
+ AL_UNLOCK(mRawDataBufLock);
+}
+
+
+uint32_t AudioALSACaptureDataClientDsp::copyCaptureDataToClient(RingBuf pcm_read_buf) {
+ audio_ringbuf_t pcm_read_buf_wrap;
+ pcm_read_buf_wrap.base = pcm_read_buf.pBufBase;
+ pcm_read_buf_wrap.read = pcm_read_buf.pRead;
+ pcm_read_buf_wrap.write = pcm_read_buf.pWrite;
+ pcm_read_buf_wrap.size = pcm_read_buf.bufLen;
+
+
+ AL_LOCK_MS(mRawDataBufLock, MAX_LOCK_TIME_OUT_MS);
+ if (mEnable == false) {
+ ALOGD("%s(), mEnable is false. return", __FUNCTION__);
+ AL_SIGNAL(mRawDataBufLock);
+ AL_UNLOCK(mRawDataBufLock);
+ return 0;
+ }
+
+ audio_ringbuf_copy_from_ringbuf_all(&mRawDataBuf, &pcm_read_buf_wrap);
+ AL_SIGNAL(mRawDataBufLock);
+
+ AL_UNLOCK(mRawDataBufLock);
+ return 0;
+}
+
+
+void *AudioALSACaptureDataClientDsp::processThread(void *arg) {
+ char thread_name[128];
+
+ AudioALSACaptureDataClientDsp *client = NULL;
+
+ audio_ringbuf_t *raw_ul = NULL;
+ audio_ringbuf_t *processed = NULL;
+
+ void *pBufferAfterBliSrc = NULL;
+ uint32_t bytesAfterBliSrc = 0;
+
+ void *pBufferAfterBitConvertion = NULL;
+ uint32_t bytesAfterBitConvertion = 0;
+
+ uint32_t data_count = 0;
+ uint32_t free_count = 0;
+
+ int wait_result = 0;
+
+
+ snprintf(thread_name, 64, "%s_%d_%d", __FUNCTION__, getpid(), gettid());
+ prctl(PR_SET_NAME, (unsigned long)thread_name, 0, 0, 0);
+ ALOGD("%s created", thread_name);
+
+
+ client = static_cast<AudioALSACaptureDataClientDsp *>(arg);
+
+ raw_ul = &client->mRawDataBuf;
+ processed = &client->mProcessedDataBuf;
+
+
+ while (client->mEnable == true) {
+ ALOGV("%s(+)", __FUNCTION__);
+
+ // get data from raw buffer
+ AL_LOCK_MS(client->mRawDataBufLock, MAX_LOCK_TIME_OUT_MS);
+ data_count = audio_ringbuf_count(raw_ul);
+
+ // data not reary, wait data
+ if (data_count == 0) {
+ wait_result = AL_WAIT_MS(client->mRawDataBufLock, MAX_WAIT_TIME_OUT_MS);
+ if (wait_result != 0) {
+ AL_UNLOCK(client->mRawDataBufLock);
+ usleep(100);
+ continue;
+ }
+
+ if (client->mEnable == false) {
+ ALOGV("%s(), record stopped. return", __FUNCTION__);
+ AL_UNLOCK(client->mRawDataBufLock);
+ break;
+ }
+
+ data_count = audio_ringbuf_count(raw_ul);
+ ALOGV("data_count %u", data_count);
+ }
+ if (data_count > kRawDataBufferSize) {
+ ALOGE("%s(), Waring! copy size > linear buf size : data_count %u, linear buf size %u", __FUNCTION__, data_count, kRawDataBufferSize);
+ data_count = kRawDataBufferSize;
+ }
+
+ // copy data
+ audio_ringbuf_copy_to_linear(client->mRawDataBufLinear, raw_ul, data_count);
+ AL_UNLOCK(client->mRawDataBufLock);
+
+ // SRC
+ pBufferAfterBliSrc = NULL;
+ bytesAfterBliSrc = 0;
+ client->doBliSrc(client->mRawDataBufLinear, data_count, &pBufferAfterBliSrc, &bytesAfterBliSrc);
+
+ // bit conversion
+ pBufferAfterBitConvertion = NULL;
+ bytesAfterBitConvertion = 0;
+ client->doBitConversion(pBufferAfterBliSrc, bytesAfterBliSrc, &pBufferAfterBitConvertion, &bytesAfterBitConvertion);
+
+ // depop
+ if (client->mDropPopSize > 0) {
+ ALOGV("data_count %u, mDropPopSize %u, %dL", bytesAfterBitConvertion, client->mDropPopSize, __LINE__);
+
+ if (bytesAfterBitConvertion > client->mDropPopSize) {
+ pBufferAfterBitConvertion = ((char *)pBufferAfterBitConvertion) + client->mDropPopSize;
+ bytesAfterBitConvertion -= client->mDropPopSize;
+ client->mDropPopSize = 0;
+ } else {
+ client->mDropPopSize -= bytesAfterBitConvertion;
+ bytesAfterBitConvertion = 0;
+ }
+ }
+
+ if (bytesAfterBitConvertion == 0) {
+ ALOGV("%s(), data_count == 0, %dL", __FUNCTION__, __LINE__);
+ continue;
+ }
+
+ // copy to processed buf and signal read()
+ AL_LOCK_MS(client->mProcessedDataBufLock, MAX_LOCK_TIME_OUT_MS);
+ free_count = audio_ringbuf_free_space(processed);
+ if (bytesAfterBitConvertion > free_count) {
+ AUD_LOG_W("%s(), bytesAfterBitConvertion %u > processed buf free_count %u",
+ __FUNCTION__, bytesAfterBitConvertion, free_count);
+ bytesAfterBitConvertion = free_count;
+ }
+ audio_ringbuf_copy_from_linear(processed, (char *)pBufferAfterBitConvertion, bytesAfterBitConvertion);
+ AL_SIGNAL(client->mProcessedDataBufLock);
+ AL_UNLOCK(client->mProcessedDataBufLock);
+
+ ALOGV("%s(-)", __FUNCTION__);
+ }
+
+
+ ALOGV("%s terminated", thread_name);
+ pthread_exit(NULL);
+ return NULL;
+}
+
+ssize_t AudioALSACaptureDataClientDsp::read(void *buffer, ssize_t bytes) {
+ ALOGV("%s(+), bytes: %u", __FUNCTION__, (uint32_t)bytes);
+
+ char *write = (char *)buffer;
+ uint32_t data_count = 0;
+ uint32_t left_count_to_read = bytes;
+
+ int try_count = 8;
+ int wait_result = 0;
+
+
+ // clean buffer
+ memset(buffer, 0, bytes);
+
+ // copy processed data
+ do {
+ AL_LOCK_MS(mProcessedDataBufLock, MAX_LOCK_TIME_OUT_MS);
+ data_count = audio_ringbuf_count(&mProcessedDataBuf);
+ if (data_count == 0) {
+ // wait for new data
+ wait_result = AL_WAIT_MS(mProcessedDataBufLock, MAX_WAIT_TIME_OUT_MS);
+ if (wait_result != 0) { // something error, exit
+ AL_UNLOCK(mProcessedDataBufLock);
+ try_count--;
+ break;
+ }
+
+ if (mEnable == false) {
+ ALOGD("%s(), record stopped. return", __FUNCTION__);
+ AL_UNLOCK(mProcessedDataBufLock);
+ break;
+ }
+
+ data_count = audio_ringbuf_count(&mProcessedDataBuf);
+ }
+
+ if (data_count >= left_count_to_read) { // ring buffer is enough, copy & exit
+ audio_ringbuf_copy_to_linear(write, &mProcessedDataBuf, left_count_to_read);
+ AL_UNLOCK(mProcessedDataBufLock);
+ left_count_to_read = 0;
+ break;
+ }
+
+ audio_ringbuf_copy_to_linear((char *)write, &mProcessedDataBuf, data_count);
+ AL_UNLOCK(mProcessedDataBufLock);
+ left_count_to_read -= data_count;
+ write += data_count;
+
+ try_count--;
+ } while (left_count_to_read > 0 && try_count > 0 && mEnable == true);
+
+ if (left_count_to_read > 0) {
+ ALOGW("left_count_to_read %d!!", left_count_to_read);
+ }
+
+ // apply volume if need
+ bytes -= left_count_to_read;
+
+ ALOGV("%s(-), bytes: %u", __FUNCTION__, (uint32_t)bytes);
+ return bytes;
+}
+
+
+bool AudioALSACaptureDataClientDsp::IsLowLatencyCapture(void) {
+ bool low_latency_on = false;
+ bool voip_on = mStreamAttributeTarget->BesRecord_Info.besrecord_voip_enable;
+
+#ifdef UPLINK_LOW_LATENCY
+ if ((voip_on == false) &&
+ (mStreamAttributeTarget->mAudioInputFlags & AUDIO_INPUT_FLAG_FAST)) {
+ low_latency_on = true;
+ }
+#endif
+
+ ALOGD("%s(), low_latency_on: %d, voip_on: %d", __FUNCTION__, low_latency_on, voip_on);
+ return low_latency_on;
+}
+
+
+int AudioALSACaptureDataClientDsp::getCapturePosition(int64_t *frames, int64_t *time) {
+ if (mCaptureDataProvider == NULL || frames == NULL || time == NULL) {
+ return -EINVAL;
+ }
+
+ /* Convert provider sample rate to streamin sample rate*/
+ int ret = mCaptureDataProvider->getCapturePosition(frames, time);
+ *frames = (*frames) * mStreamAttributeTarget->sample_rate / mStreamAttributeSource->sample_rate;
+ ALOGV("%s(), frames = %" PRIu64 ", tar sample = %d, src sample = %d", __FUNCTION__, *frames, mStreamAttributeTarget->sample_rate, mStreamAttributeSource->sample_rate);
+ return ret;
+}
+
+
+void AudioALSACaptureDataClientDsp::AddEchoRefDataProvider(
+ AudioALSACaptureDataProviderBase *pCaptureDataProvider,
+ stream_attribute_t *stream_attribute_target) {
+
+ if (!pCaptureDataProvider || !stream_attribute_target) {
+ ALOGE("%s(), NULL! return", __FUNCTION__);
+ return;
+ }
+
+ WARNING("INVALID_OPERATION"); /* already added in ctor */
+ return;
+}
+
+
+uint32_t AudioALSACaptureDataClientDsp::copyEchoRefCaptureDataToClient(RingBuf pcm_read_buf) {
+
+ if (!pcm_read_buf.pBufBase) {
+ ALOGE("%s(), NULL! return", __FUNCTION__);
+ return -1;
+ }
+
+ WARNING("INVALID_OPERATION"); /* not support */
+ return -1;
+}
+
+
+bool AudioALSACaptureDataClientDsp::IsNeedApplyVolume() {
+ bool ret = false;
+
+ /* Only real input CaptureDataprovider need to apply volume for mic mute */
+ switch (mCaptureDataProvider->getCaptureDataProviderType()) {
+ case CAPTURE_PROVIDER_NORMAL:
+ case CAPTURE_PROVIDER_BT_SCO:
+ case CAPTURE_PROVIDER_BT_CVSD:
+ case CAPTURE_PROVIDER_TDM_RECORD:
+ case CAPTURE_PROVIDER_EXTERNAL:
+ ret = true;
+ break;
+ default:
+ ret = false;
+ break;
+ }
+
+ return ret;
+}
+
+
+status_t AudioALSACaptureDataClientDsp::ApplyVolume(void *Buffer, uint32_t BufferSize) {
+ if (IsNeedApplyVolume() == false) {
+ return NO_ERROR;
+ }
+
+ // check if need apply mute
+ if (mMicMute != mStreamAttributeTarget->micmute) {
+ mMicMute = mStreamAttributeTarget->micmute ;
+ mMuteTransition = false;
+ }
+
+ if (mMicMute == true) {
+ // do ramp down
+ if (mMuteTransition == false) {
+ uint32_t count = BufferSize >> 1;
+ float Volume_inverse = ((float)MTK_STREAMIN_VOLUEM_MAX / (float)count) * -1;
+ short *pPcm = (short *)Buffer;
+ int ConsumeSample = 0;
+ int value = 0;
+ while (count) {
+ value = *pPcm * (MTK_STREAMIN_VOLUEM_MAX + (Volume_inverse * ConsumeSample));
+ *pPcm = clamp16(value >> MTK_STREAMIN_VOLUME_VALID_BIT);
+ pPcm++;
+ count--;
+ ConsumeSample ++;
+ //ALOGD("ApplyVolume Volume_inverse = %f ConsumeSample = %d",Volume_inverse,ConsumeSample);
+ }
+ mMuteTransition = true;
+ } else {
+ memset(Buffer, 0, BufferSize);
+ }
+ } else if (mMicMute == false) {
+ // do ramp up
+ if (mMuteTransition == false) {
+ uint32_t count = BufferSize >> 1;
+ float Volume_inverse = ((float)MTK_STREAMIN_VOLUEM_MAX / (float)count);
+ short *pPcm = (short *)Buffer;
+ int ConsumeSample = 0;
+ int value = 0;
+ while (count) {
+ value = *pPcm * (Volume_inverse * ConsumeSample);
+ *pPcm = clamp16(value >> MTK_STREAMIN_VOLUME_VALID_BIT);
+ pPcm++;
+ count--;
+ ConsumeSample ++;
+ //ALOGD("ApplyVolume Volume_inverse = %f ConsumeSample = %d",Volume_inverse,ConsumeSample);
+ }
+ mMuteTransition = true;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+void AudioALSACaptureDataClientDsp::configDSPAttribute() {
+
+ mStreamAttributeTargetDSP.sample_rate = 48000;
+ mStreamAttributeTargetDSP.audio_mode = mStreamAttributeTarget->audio_mode;
+ mStreamAttributeTargetDSP.input_device = mStreamAttributeTarget->input_device;
+ mStreamAttributeTargetDSP.mAudioInputFlags = mStreamAttributeTarget->mAudioInputFlags;
+ mStreamAttributeTargetDSP.input_source = mStreamAttributeTarget->input_source;
+ mStreamAttributeTargetDSP.output_devices = mStreamAttributeTarget->output_devices;
+ mStreamAttributeTargetDSP.mVoIPEnable = mStreamAttributeTarget->mVoIPEnable;
+ mStreamAttributeTargetDSP.NativePreprocess_Info = mStreamAttributeTarget->NativePreprocess_Info;
+
+ if ((isVoIPEnable() ||
+ mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
+ mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_CALL ||
+ mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_UPLINK ||
+ mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_DOWNLINK) &&
+ mStreamAttributeTarget->sample_rate == 16000) {
+ mStreamAttributeTargetDSP.sample_rate = 16000;
+ }
+
+ ALOGD("%s(), voip: %d, low_latency: %d, input_source: %d, flag: 0x%x, sample_rate: %d",
+ __FUNCTION__,
+ isVoIPEnable(),
+ IsLowLatencyCapture(),
+ mStreamAttributeTargetDSP.input_source,
+ mStreamAttributeTargetDSP.mAudioInputFlags,
+ mStreamAttributeTargetDSP.sample_rate);
+
+}
+
+status_t AudioALSACaptureDataClientDsp::initBliSrc() {
+ SRC_PCM_FORMAT src_pcm_format = SRC_IN_END;
+
+ const stream_attribute_t *source = &mStreamAttributeTargetDSP;
+ const stream_attribute_t *target = mStreamAttributeTarget;
+
+ // init BLI SRC if need
+ if ((source->sample_rate != target->sample_rate) ||
+ (source->num_channels != target->num_channels) ||
+ (source->audio_format == AUDIO_FORMAT_PCM_8_24_BIT &&
+ target->audio_format == AUDIO_FORMAT_PCM_16_BIT)) {
+ switch (source->audio_format) {
+ case AUDIO_FORMAT_PCM_16_BIT:
+ src_pcm_format = SRC_IN_Q1P15_OUT_Q1P15;
+ break;
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ if (target->audio_format == AUDIO_FORMAT_PCM_16_BIT) {
+ AUD_LOG_V("SRC_IN_Q9P23_OUT_Q1P31");
+ src_pcm_format = SRC_IN_Q9P23_OUT_Q1P31; /* NOTE: sync with BCV_IN_Q1P31_OUT_Q1P15 */
+ } else {
+ AUD_WARNING("SRC not support AUDIO_FORMAT_PCM_8_24_BIT!!");
+ }
+ break;
+ case AUDIO_FORMAT_PCM_32_BIT:
+ src_pcm_format = SRC_IN_Q1P31_OUT_Q1P31;
+ break;
+ default:
+ AUD_LOG_W("%s(), SRC format not support (%d->%d)", __FUNCTION__, source->audio_format, target->audio_format);
+ src_pcm_format = SRC_IN_END;
+ AUD_WARNING("audio_format error!");
+ break;
+ }
+
+ AUD_LOG_D("=>%s(), sample_rate: %d => %d, num_channels: %d => %d, audio_format: 0x%x, 0x%x, SRC_PCM_FORMAT = %d", __FUNCTION__,
+ source->sample_rate, target->sample_rate,
+ source->num_channels, target->num_channels,
+ source->audio_format, target->audio_format,
+ src_pcm_format);
+
+ mBliSrc = newMtkAudioSrc(
+ mStreamAttributeTargetDSP.sample_rate, mStreamAttributeTargetDSP.num_channels,
+ mStreamAttributeTarget->sample_rate, mStreamAttributeTarget->num_channels,
+ src_pcm_format);
+ ASSERT(mBliSrc != NULL);
+ mBliSrc->open();
+
+ AUDIO_ALLOC_CHAR_BUFFER(mBliSrcOutputBuffer, kBliSrcOutputBufferSize);
+ }
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureDataClientDsp::deinitBliSrc() {
+ // deinit BLI SRC if need
+ if (mBliSrc != NULL) {
+ mBliSrc->close();
+ deleteMtkAudioSrc(mBliSrc);
+ mBliSrc = NULL;
+ }
+
+ AUDIO_FREE_POINTER(mBliSrcOutputBuffer);
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureDataClientDsp::doBliSrc(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes) {
+ if (mBliSrc == NULL) { // No need SRC
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ } else {
+ char *p_read = (char *)pInBuffer;
+ uint32_t num_raw_data_left = inBytes;
+ uint32_t num_converted_data = kBliSrcOutputBufferSize; // max convert num_free_space
+
+ uint32_t consumed = num_raw_data_left;
+ mBliSrc->process((int16_t *)p_read, &num_raw_data_left,
+ (int16_t *)mBliSrcOutputBuffer, &num_converted_data);
+ consumed -= num_raw_data_left;
+ p_read += consumed;
+
+ ALOGV("%s(), num_raw_data_left = %u, num_converted_data = %u",
+ __FUNCTION__, num_raw_data_left, num_converted_data);
+
+ if (num_raw_data_left > 0) {
+ ALOGW("%s(), num_raw_data_left(%u) > 0", __FUNCTION__, num_raw_data_left);
+ ASSERT(num_raw_data_left == 0);
+ }
+
+ *ppOutBuffer = mBliSrcOutputBuffer;
+ *pOutBytes = num_converted_data;
+ }
+
+ ASSERT(*ppOutBuffer != NULL && *pOutBytes != 0);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureDataClientDsp::initBitConverter() {
+ BCV_PCM_FORMAT bcv_pcm_format;
+
+ const stream_attribute_t *source = &mStreamAttributeTargetDSP;
+ const stream_attribute_t *target = mStreamAttributeTarget;
+
+ // init bit converter if need
+ if (source->audio_format != target->audio_format) {
+ bcv_pcm_format = get_bcv_pcm_format(source->audio_format, target->audio_format);
+
+ mBitConverter = newMtkAudioBitConverter(
+ source->sample_rate,
+ (source->num_channels > 2) ? 2 : source->num_channels,
+ bcv_pcm_format);
+
+ ASSERT(mBitConverter != NULL);
+ mBitConverter->open();
+ mBitConverter->resetBuffer();
+
+ AUDIO_ALLOC_CHAR_BUFFER(mBitConverterOutputBuffer, kMaxPcmDriverBufferSize);
+
+ AUD_LOG_D("=>%s(), audio_format: 0x%x => 0x%x, bcv_pcm_format = 0x%x",
+ __FUNCTION__, source->audio_format, target->audio_format, bcv_pcm_format);
+ }
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureDataClientDsp::deinitBitConverter() {
+ // deinit bit converter if need
+ if (mBitConverter != NULL) {
+ mBitConverter->close();
+ deleteMtkAudioBitConverter(mBitConverter);
+ mBitConverter = NULL;
+ }
+
+ AUDIO_FREE_POINTER(mBitConverterOutputBuffer);
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureDataClientDsp::doBitConversion(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes) {
+ if (mBitConverter != NULL) {
+ *pOutBytes = kMaxPcmDriverBufferSize;
+ mBitConverter->process(pInBuffer, &inBytes, (void *)mBitConverterOutputBuffer, pOutBytes);
+ *ppOutBuffer = mBitConverterOutputBuffer;
+ } else {
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ }
+
+ ASSERT(*ppOutBuffer != NULL && *pOutBytes != 0);
+ return NO_ERROR;
+}
+
+
+} // end of namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataClientSyncIO.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataClientSyncIO.cpp
new file mode 100644
index 0000000..8b83672
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataClientSyncIO.cpp
@@ -0,0 +1,695 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureDataClientSyncIO.h"
+
+#include <inttypes.h>
+#include <pthread.h>
+#include <sys/prctl.h>
+
+
+#include "AudioUtility.h"
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+#include "AudioVolumeInterface.h"
+#include "AudioVolumeFactory.h"
+
+
+#include <audio_memory_control.h>
+#include <audio_lock.h>
+#include <audio_ringbuf.h>
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACaptureDataClientSyncIO"
+
+#ifdef UPLINK_UNPROCESSED_DROP_CHIP_MS
+#define UPLINK_UNPROCESSED_DROP_MS (UPLINK_UNPROCESSED_DROP_CHIP_MS)
+#else
+#define UPLINK_UNPROCESSED_DROP_MS (260)
+#endif
+
+namespace android {
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+static const uint32_t kRawDataBufferSize = 0x10000; // 64k
+static const uint32_t kProcessedBufferSize = 0x10000; // 64k
+
+static const uint32_t kBliSrcOutputBufferSize = 0x20000; // 128k
+static const uint32_t kMaxPcmDriverBufferSize = 0x20000; // 128k
+
+
+#define MTK_STREAMIN_VOLUEM_MAX (0x1000)
+#define MTK_STREAMIN_VOLUME_VALID_BIT (12)
+
+
+#define MAX_LOCK_TIME_OUT_MS (500)
+#define MAX_WAIT_TIME_OUT_MS (500)
+
+/*==============================================================================
+ * Utility
+ *============================================================================*/
+
+static uint32_t getDropMs(stream_attribute_t *mStreamAttributeTarget) {
+ uint32_t dropMs = 0;
+ if ((mStreamAttributeTarget->input_source == AUDIO_SOURCE_UNPROCESSED) &&
+ (mStreamAttributeTarget->input_device & AUDIO_DEVICE_IN_BUILTIN_MIC)) {
+ return UPLINK_UNPROCESSED_DROP_MS;
+ }
+
+ return dropMs;
+}
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataClientSyncIO::AudioALSACaptureDataClientSyncIO(
+ AudioALSACaptureDataProviderBase *pCaptureDataProvider,
+ stream_attribute_t *stream_attribute_target) :
+ mStreamAttributeSource(NULL),
+ mStreamAttributeTarget(stream_attribute_target),
+ mCaptureDataProvider(pCaptureDataProvider),
+ mRawStartFrameCount(0),
+ mMicMute(false),
+ mMuteTransition(false),
+ mEnable(false),
+ mRawDataBufLinear(NULL),
+ mBliSrc(NULL),
+ mBliSrcOutputBuffer(NULL),
+ mBitConverter(NULL),
+ mBitConverterOutputBuffer(NULL),
+ mDropPopSize(0) {
+
+ // init var
+ AudioVolumeInterface *pVolumeController = NULL;
+ uint32_t latency = 0;
+ uint32_t drop_ms = 0;
+ uint32_t size_per_sample = 0;
+ uint32_t size_per_frame = 0;
+ int ret = 0;
+
+
+ ALOGD("%s(+)", __FUNCTION__);
+
+
+ // init raw data buf
+ memset((void *)&mRawDataBuf, 0, sizeof(mRawDataBuf));
+
+ AUDIO_ALLOC_CHAR_BUFFER(mRawDataBuf.base, kRawDataBufferSize);
+ mRawDataBuf.read = mRawDataBuf.base;
+ mRawDataBuf.write = mRawDataBuf.base;
+ mRawDataBuf.size = kRawDataBufferSize;
+ AUDIO_ALLOC_CHAR_BUFFER(mRawDataBufLinear, kRawDataBufferSize);
+
+ // init processed data buf
+ memset((void *)&mProcessedDataBuf, 0, sizeof(mProcessedDataBuf));
+
+ AUDIO_ALLOC_CHAR_BUFFER(mProcessedDataBuf.base, kProcessedBufferSize);
+ mProcessedDataBuf.read = mProcessedDataBuf.base;
+ mProcessedDataBuf.write = mProcessedDataBuf.base;
+ mProcessedDataBuf.size = kProcessedBufferSize;
+
+
+ // config attribute for input device
+ mCaptureDataProvider->configStreamAttribute(mStreamAttributeTarget);
+
+ // get attribute before enable
+ mStreamAttributeSource = mCaptureDataProvider->getStreamAttributeSource();
+
+ // enable before attach
+ mEnable = true;
+
+ // attach client to capture data provider (after data buf ready)
+ mCaptureDataProvider->attach(this);
+
+ // Gain control // TODO: AudioMTKGainController::SetCaptureGain, multi data client !?
+ pVolumeController = AudioVolumeFactory::CreateAudioVolumeController();
+ AUD_ASSERT(pVolumeController != NULL);
+ if (pVolumeController != NULL) {
+ pVolumeController->SetCaptureGain(mStreamAttributeTarget->audio_mode,
+ mStreamAttributeTarget->input_source,
+ mStreamAttributeTarget->input_device,
+ mStreamAttributeTarget->output_devices);
+ }
+
+
+ // SRC
+ initBliSrc();
+
+ // bit conversion
+ initBitConverter();
+
+
+ // depop
+ latency = mCaptureDataProvider->getLatencyTime();
+ drop_ms = getDropMs(stream_attribute_target);
+ if ((drop_ms % latency) != 0) { // drop data size need to align interrupt rate
+ drop_ms = ((drop_ms / latency) + 1) * latency; // cell()
+ }
+ mDropPopSize = (audio_bytes_per_sample(mStreamAttributeTarget->audio_format) *
+ mStreamAttributeTarget->num_channels *
+ mStreamAttributeTarget->sample_rate *
+ drop_ms) / 1000;
+ size_per_sample = audio_bytes_per_sample(mStreamAttributeTarget->audio_format);
+ size_per_frame = mStreamAttributeTarget->num_channels * size_per_sample;
+ if ((mDropPopSize % size_per_frame) != 0) { // alignment
+ mDropPopSize = ((mDropPopSize / size_per_frame) + 1) * size_per_frame;
+ }
+
+ // processThread
+ hProcessThread = 0;
+ ret = pthread_create(&hProcessThread, NULL,
+ AudioALSACaptureDataClientSyncIO::processThread,
+ (void *)this);
+ ASSERT(ret == 0);
+ ALOGD("%s(-), drop_ms = %d, latency = %d, mDropPopSize = %d", __FUNCTION__, drop_ms, latency, mDropPopSize);
+}
+
+
+AudioALSACaptureDataClientSyncIO::~AudioALSACaptureDataClientSyncIO() {
+ // start to close
+ mEnable = false;
+
+ // terminate processThread thread
+ pthread_join(hProcessThread, NULL);
+ ALOGD("pthread_join hProcessThread done");
+
+ // detach client to capture data provider
+ mCaptureDataProvider->detach(this);
+ ALOGD("mCaptureDataProvider detach done");
+
+
+ // close
+ AL_LOCK_MS(mRawDataBufLock, MAX_LOCK_TIME_OUT_MS);
+ AL_LOCK_MS(mProcessedDataBufLock, MAX_LOCK_TIME_OUT_MS);
+
+
+ // bit conversion
+ deinitBitConverter();
+
+ // SRC
+ deinitBliSrc();
+
+
+ AUDIO_FREE_POINTER(mRawDataBufLinear);
+ AUDIO_FREE_POINTER(mRawDataBuf.base);
+ AUDIO_FREE_POINTER(mProcessedDataBuf.base);
+
+ AL_UNLOCK(mProcessedDataBufLock);
+ AL_UNLOCK(mRawDataBufLock);
+}
+
+
+uint32_t AudioALSACaptureDataClientSyncIO::copyCaptureDataToClient(RingBuf pcm_read_buf) {
+ audio_ringbuf_t pcm_read_buf_wrap;
+ pcm_read_buf_wrap.base = pcm_read_buf.pBufBase;
+ pcm_read_buf_wrap.read = pcm_read_buf.pRead;
+ pcm_read_buf_wrap.write = pcm_read_buf.pWrite;
+ pcm_read_buf_wrap.size = pcm_read_buf.bufLen;
+
+
+ AL_LOCK_MS(mRawDataBufLock, MAX_LOCK_TIME_OUT_MS);
+ if (mEnable == false) {
+ ALOGD("%s(), mEnable is false. return", __FUNCTION__);
+ AL_SIGNAL(mRawDataBufLock);
+ AL_UNLOCK(mRawDataBufLock);
+ return 0;
+ }
+
+ audio_ringbuf_copy_from_ringbuf_all(&mRawDataBuf, &pcm_read_buf_wrap);
+ AL_SIGNAL(mRawDataBufLock);
+
+ AL_UNLOCK(mRawDataBufLock);
+ return 0;
+}
+
+
+void *AudioALSACaptureDataClientSyncIO::processThread(void *arg) {
+ char thread_name[128];
+
+ AudioALSACaptureDataClientSyncIO *client = NULL;
+
+ audio_ringbuf_t *raw_ul = NULL;
+ audio_ringbuf_t *processed = NULL;
+
+ void *pBufferAfterBliSrc = NULL;
+ uint32_t bytesAfterBliSrc = 0;
+
+ void *pBufferAfterBitConvertion = NULL;
+ uint32_t bytesAfterBitConvertion = 0;
+
+ uint32_t data_count = 0;
+ uint32_t free_count = 0;
+
+ int wait_result = 0;
+
+
+ snprintf(thread_name, 64, "%s_%d_%d", __FUNCTION__, getpid(), gettid());
+ prctl(PR_SET_NAME, (unsigned long)thread_name, 0, 0, 0);
+ ALOGD("%s created", thread_name);
+
+
+ client = static_cast<AudioALSACaptureDataClientSyncIO *>(arg);
+
+ raw_ul = &client->mRawDataBuf;
+ processed = &client->mProcessedDataBuf;
+
+
+ while (client->mEnable == true) {
+ ALOGV("%s(+)", __FUNCTION__);
+
+ // get data from raw buffer
+ AL_LOCK_MS(client->mRawDataBufLock, MAX_LOCK_TIME_OUT_MS);
+ data_count = audio_ringbuf_count(raw_ul);
+
+ // data not reary, wait data
+ if (data_count == 0) {
+ wait_result = AL_WAIT_MS(client->mRawDataBufLock, MAX_WAIT_TIME_OUT_MS);
+ if (wait_result != 0) {
+ AL_UNLOCK(client->mRawDataBufLock);
+ usleep(100);
+ continue;
+ }
+
+ if (client->mEnable == false) {
+ ALOGV("%s(), record stopped. return", __FUNCTION__);
+ AL_UNLOCK(client->mRawDataBufLock);
+ break;
+ }
+
+ data_count = audio_ringbuf_count(raw_ul);
+ ALOGV("data_count %u", data_count);
+ }
+
+ // copy data
+ audio_ringbuf_copy_to_linear(client->mRawDataBufLinear, raw_ul, data_count);
+ AL_UNLOCK(client->mRawDataBufLock);
+
+ // SRC
+ pBufferAfterBliSrc = NULL;
+ bytesAfterBliSrc = 0;
+ client->doBliSrc(client->mRawDataBufLinear, data_count, &pBufferAfterBliSrc, &bytesAfterBliSrc);
+
+ // bit conversion
+ pBufferAfterBitConvertion = NULL;
+ bytesAfterBitConvertion = 0;
+ client->doBitConversion(pBufferAfterBliSrc, bytesAfterBliSrc, &pBufferAfterBitConvertion, &bytesAfterBitConvertion);
+
+ // depop
+ if (client->mDropPopSize > 0) {
+ ALOGV("data_count %u, mDropPopSize %u, %dL", bytesAfterBitConvertion, client->mDropPopSize, __LINE__);
+
+ if (bytesAfterBitConvertion > client->mDropPopSize) {
+ pBufferAfterBitConvertion = ((char *)pBufferAfterBitConvertion) + client->mDropPopSize;
+ bytesAfterBitConvertion -= client->mDropPopSize;
+ client->mDropPopSize = 0;
+ } else {
+ client->mDropPopSize -= bytesAfterBitConvertion;
+ bytesAfterBitConvertion = 0;
+ }
+ }
+
+ if (bytesAfterBitConvertion == 0) {
+ ALOGV("%s(), data_count == 0, %dL", __FUNCTION__, __LINE__);
+ continue;
+ }
+
+ // copy to processed buf and signal read()
+ AL_LOCK_MS(client->mProcessedDataBufLock, MAX_LOCK_TIME_OUT_MS);
+ free_count = audio_ringbuf_free_space(processed);
+ if (bytesAfterBitConvertion > free_count) {
+ AUD_LOG_W("%s(), bytesAfterBitConvertion %u > processed buf free_count %u",
+ __FUNCTION__, bytesAfterBitConvertion, free_count);
+ bytesAfterBitConvertion = free_count;
+ }
+ audio_ringbuf_copy_from_linear(processed, (char *)pBufferAfterBitConvertion, bytesAfterBitConvertion);
+ AL_SIGNAL(client->mProcessedDataBufLock);
+ AL_UNLOCK(client->mProcessedDataBufLock);
+
+ ALOGV("%s(-)", __FUNCTION__);
+ }
+
+
+ ALOGV("%s terminated", thread_name);
+ pthread_exit(NULL);
+ return NULL;
+}
+
+ssize_t AudioALSACaptureDataClientSyncIO::read(void *buffer, ssize_t bytes) {
+ ALOGV("%s(+), bytes: %u", __FUNCTION__, (uint32_t)bytes);
+
+ char *write = (char *)buffer;
+ uint32_t data_count = 0;
+ uint32_t left_count_to_read = bytes;
+
+ int try_count = 8;
+ int wait_result = 0;
+
+
+ // clean buffer
+ memset(buffer, 0, bytes);
+
+ // copy processed data
+ do {
+ AL_LOCK_MS(mProcessedDataBufLock, MAX_LOCK_TIME_OUT_MS);
+ data_count = audio_ringbuf_count(&mProcessedDataBuf);
+ if (data_count == 0) {
+ // wait for new data
+ wait_result = AL_WAIT_MS(mProcessedDataBufLock, MAX_WAIT_TIME_OUT_MS);
+ if (wait_result != 0) { // something error, exit
+ AL_UNLOCK(mProcessedDataBufLock);
+ try_count--;
+ break;
+ }
+
+ if (mEnable == false) {
+ ALOGD("%s(), record stopped. return", __FUNCTION__);
+ AL_UNLOCK(mProcessedDataBufLock);
+ break;
+ }
+
+ data_count = audio_ringbuf_count(&mProcessedDataBuf);
+ }
+
+ if (data_count >= left_count_to_read) { // ring buffer is enough, copy & exit
+ audio_ringbuf_copy_to_linear(write, &mProcessedDataBuf, left_count_to_read);
+ AL_UNLOCK(mProcessedDataBufLock);
+ left_count_to_read = 0;
+ break;
+ }
+
+ audio_ringbuf_copy_to_linear((char *)write, &mProcessedDataBuf, data_count);
+ AL_UNLOCK(mProcessedDataBufLock);
+ left_count_to_read -= data_count;
+ write += data_count;
+
+ try_count--;
+ } while (left_count_to_read > 0 && try_count > 0 && mEnable == true);
+
+ if (left_count_to_read > 0) {
+ ALOGW("left_count_to_read %d!!", left_count_to_read);
+ }
+
+ // apply volume if need
+ bytes -= left_count_to_read;
+
+ ALOGV("%s(-), bytes: %u", __FUNCTION__, (uint32_t)bytes);
+ return bytes;
+}
+
+
+bool AudioALSACaptureDataClientSyncIO::IsLowLatencyCapture(void) {
+ bool low_latency_on = false;
+ bool voip_on = mStreamAttributeTarget->BesRecord_Info.besrecord_voip_enable;
+
+#ifdef UPLINK_LOW_LATENCY
+ if ((voip_on == false) &&
+ (mStreamAttributeTarget->mAudioInputFlags & AUDIO_INPUT_FLAG_FAST)) {
+ low_latency_on = true;
+ }
+#endif
+
+ ALOGD("%s(), low_latency_on: %d, voip_on: %d", __FUNCTION__, low_latency_on, voip_on);
+ return low_latency_on;
+}
+
+
+int AudioALSACaptureDataClientSyncIO::getCapturePosition(int64_t *frames, int64_t *time) {
+ if (mCaptureDataProvider == NULL || frames == NULL || time == NULL) {
+ return -EINVAL;
+ }
+
+ /* Convert provider sample rate to streamin sample rate*/
+ int ret = mCaptureDataProvider->getCapturePosition(frames, time);
+ *frames = (*frames) * mStreamAttributeTarget->sample_rate / mStreamAttributeSource->sample_rate;
+ ALOGV("%s(), frames = %" PRIu64 ", tar sample = %d, src sample = %d", __FUNCTION__, *frames, mStreamAttributeTarget->sample_rate, mStreamAttributeSource->sample_rate);
+ return ret;
+}
+
+
+void AudioALSACaptureDataClientSyncIO::AddEchoRefDataProvider(
+ AudioALSACaptureDataProviderBase *pCaptureDataProvider,
+ stream_attribute_t *stream_attribute_target) {
+
+ if (!pCaptureDataProvider || !stream_attribute_target) {
+ ALOGE("%s(), NULL! return", __FUNCTION__);
+ return;
+ }
+
+ WARNING("INVALID_OPERATION"); /* already added in ctor */
+ return;
+}
+
+
+uint32_t AudioALSACaptureDataClientSyncIO::copyEchoRefCaptureDataToClient(RingBuf pcm_read_buf) {
+
+ if (!pcm_read_buf.pBufBase) {
+ ALOGE("%s(), NULL! return", __FUNCTION__);
+ return -1;
+ }
+
+ WARNING("INVALID_OPERATION"); /* not support */
+ return -1;
+}
+
+
+bool AudioALSACaptureDataClientSyncIO::IsNeedApplyVolume() {
+ bool ret = false;
+
+ /* Only real input CaptureDataprovider need to apply volume for mic mute */
+ switch (mCaptureDataProvider->getCaptureDataProviderType()) {
+ case CAPTURE_PROVIDER_NORMAL:
+ case CAPTURE_PROVIDER_BT_SCO:
+ case CAPTURE_PROVIDER_BT_CVSD:
+ case CAPTURE_PROVIDER_TDM_RECORD:
+ case CAPTURE_PROVIDER_EXTERNAL:
+ ret = true;
+ break;
+ default:
+ ret = false;
+ break;
+ }
+
+ return ret;
+}
+
+
+status_t AudioALSACaptureDataClientSyncIO::ApplyVolume(void *Buffer, uint32_t BufferSize) {
+ if (IsNeedApplyVolume() == false) {
+ return NO_ERROR;
+ }
+
+ // check if need apply mute
+ if (mMicMute != mStreamAttributeTarget->micmute) {
+ mMicMute = mStreamAttributeTarget->micmute ;
+ mMuteTransition = false;
+ }
+
+ if (mMicMute == true) {
+ // do ramp down
+ if (mMuteTransition == false) {
+ uint32_t count = BufferSize >> 1;
+ float Volume_inverse = ((float)MTK_STREAMIN_VOLUEM_MAX / (float)count) * -1;
+ short *pPcm = (short *)Buffer;
+ int ConsumeSample = 0;
+ int value = 0;
+ while (count) {
+ value = *pPcm * (MTK_STREAMIN_VOLUEM_MAX + (Volume_inverse * ConsumeSample));
+ *pPcm = clamp16(value >> MTK_STREAMIN_VOLUME_VALID_BIT);
+ pPcm++;
+ count--;
+ ConsumeSample ++;
+ //ALOGD("ApplyVolume Volume_inverse = %f ConsumeSample = %d",Volume_inverse,ConsumeSample);
+ }
+ mMuteTransition = true;
+ } else {
+ memset(Buffer, 0, BufferSize);
+ }
+ } else if (mMicMute == false) {
+ // do ramp up
+ if (mMuteTransition == false) {
+ uint32_t count = BufferSize >> 1;
+ float Volume_inverse = ((float)MTK_STREAMIN_VOLUEM_MAX / (float)count);
+ short *pPcm = (short *)Buffer;
+ int ConsumeSample = 0;
+ int value = 0;
+ while (count) {
+ value = *pPcm * (Volume_inverse * ConsumeSample);
+ *pPcm = clamp16(value >> MTK_STREAMIN_VOLUME_VALID_BIT);
+ pPcm++;
+ count--;
+ ConsumeSample ++;
+ //ALOGD("ApplyVolume Volume_inverse = %f ConsumeSample = %d",Volume_inverse,ConsumeSample);
+ }
+ mMuteTransition = true;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureDataClientSyncIO::initBliSrc() {
+ SRC_PCM_FORMAT src_pcm_format = SRC_IN_END;
+
+ const stream_attribute_t *source = mStreamAttributeSource;
+ const stream_attribute_t *target = mStreamAttributeTarget;
+
+ // init BLI SRC if need
+ if ((source->sample_rate != target->sample_rate) ||
+ (source->num_channels != target->num_channels) ||
+ (source->audio_format == AUDIO_FORMAT_PCM_8_24_BIT &&
+ target->audio_format == AUDIO_FORMAT_PCM_16_BIT)) {
+ switch (source->audio_format) {
+ case AUDIO_FORMAT_PCM_16_BIT:
+ src_pcm_format = SRC_IN_Q1P15_OUT_Q1P15;
+ break;
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ if (target->audio_format == AUDIO_FORMAT_PCM_16_BIT) {
+ AUD_LOG_V("SRC_IN_Q9P23_OUT_Q1P31");
+ src_pcm_format = SRC_IN_Q9P23_OUT_Q1P31; /* NOTE: sync with BCV_IN_Q1P31_OUT_Q1P15 */
+ } else {
+ AUD_WARNING("SRC not support AUDIO_FORMAT_PCM_8_24_BIT!!");
+ }
+ break;
+ case AUDIO_FORMAT_PCM_32_BIT:
+ src_pcm_format = SRC_IN_Q1P31_OUT_Q1P31;
+ break;
+ default:
+ AUD_LOG_W("%s(), SRC format not support (%d->%d)", __FUNCTION__, source->audio_format, target->audio_format);
+ src_pcm_format = SRC_IN_END;
+ AUD_WARNING("audio_format error!");
+ break;
+ }
+
+ AUD_LOG_D("=>%s(), sample_rate: %d => %d, num_channels: %d => %d, audio_format: 0x%x, 0x%x, SRC_PCM_FORMAT = %d", __FUNCTION__,
+ source->sample_rate, target->sample_rate,
+ source->num_channels, target->num_channels,
+ source->audio_format, target->audio_format,
+ src_pcm_format);
+
+ mBliSrc = newMtkAudioSrc(
+ mStreamAttributeSource->sample_rate, mStreamAttributeSource->num_channels,
+ mStreamAttributeTarget->sample_rate, mStreamAttributeTarget->num_channels,
+ src_pcm_format);
+ ASSERT(mBliSrc != NULL);
+ mBliSrc->open();
+
+ AUDIO_ALLOC_CHAR_BUFFER(mBliSrcOutputBuffer, kBliSrcOutputBufferSize);
+ }
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureDataClientSyncIO::deinitBliSrc() {
+ // deinit BLI SRC if need
+ if (mBliSrc != NULL) {
+ mBliSrc->close();
+ deleteMtkAudioSrc(mBliSrc);
+ mBliSrc = NULL;
+ }
+
+ AUDIO_FREE_POINTER(mBliSrcOutputBuffer);
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureDataClientSyncIO::doBliSrc(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes) {
+ if (mBliSrc == NULL) { // No need SRC
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ } else {
+ char *p_read = (char *)pInBuffer;
+ uint32_t num_raw_data_left = inBytes;
+ uint32_t num_converted_data = kBliSrcOutputBufferSize; // max convert num_free_space
+
+ uint32_t consumed = num_raw_data_left;
+ mBliSrc->process((int16_t *)p_read, &num_raw_data_left,
+ (int16_t *)mBliSrcOutputBuffer, &num_converted_data);
+ consumed -= num_raw_data_left;
+ p_read += consumed;
+
+ ALOGV("%s(), num_raw_data_left = %u, num_converted_data = %u",
+ __FUNCTION__, num_raw_data_left, num_converted_data);
+
+ if (num_raw_data_left > 0) {
+ ALOGW("%s(), num_raw_data_left(%u) > 0", __FUNCTION__, num_raw_data_left);
+ ASSERT(num_raw_data_left == 0);
+ }
+
+ *ppOutBuffer = mBliSrcOutputBuffer;
+ *pOutBytes = num_converted_data;
+ }
+
+ ASSERT(*ppOutBuffer != NULL && *pOutBytes != 0);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureDataClientSyncIO::initBitConverter() {
+ BCV_PCM_FORMAT bcv_pcm_format;
+
+ const stream_attribute_t *source = mStreamAttributeSource;
+ const stream_attribute_t *target = mStreamAttributeTarget;
+
+ // init bit converter if need
+ if (source->audio_format != target->audio_format) {
+ bcv_pcm_format = get_bcv_pcm_format(source->audio_format, target->audio_format);
+
+ mBitConverter = newMtkAudioBitConverter(
+ source->sample_rate,
+ (source->num_channels > 2) ? 2 : source->num_channels,
+ bcv_pcm_format);
+
+ ASSERT(mBitConverter != NULL);
+ mBitConverter->open();
+ mBitConverter->resetBuffer();
+
+ AUDIO_ALLOC_CHAR_BUFFER(mBitConverterOutputBuffer, kMaxPcmDriverBufferSize);
+
+ AUD_LOG_D("=>%s(), audio_format: 0x%x => 0x%x, bcv_pcm_format = 0x%x",
+ __FUNCTION__, source->audio_format, target->audio_format, bcv_pcm_format);
+ }
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureDataClientSyncIO::deinitBitConverter() {
+ // deinit bit converter if need
+ if (mBitConverter != NULL) {
+ mBitConverter->close();
+ deleteMtkAudioBitConverter(mBitConverter);
+ mBitConverter = NULL;
+ }
+
+ AUDIO_FREE_POINTER(mBitConverterOutputBuffer);
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureDataClientSyncIO::doBitConversion(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes) {
+ if (mBitConverter != NULL) {
+ *pOutBytes = kMaxPcmDriverBufferSize;
+ mBitConverter->process(pInBuffer, &inBytes, (void *)mBitConverterOutputBuffer, pOutBytes);
+ *ppOutBuffer = mBitConverterOutputBuffer;
+ } else {
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ }
+
+ ASSERT(*ppOutBuffer != NULL && *pOutBytes != 0);
+ return NO_ERROR;
+}
+
+
+} // end of namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderAAudio.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderAAudio.cpp
new file mode 100644
index 0000000..bbf6cf9
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderAAudio.cpp
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: MediaTekProprietary
+
+#include "AudioALSACaptureDataProviderAAudio.h"
+#include "AudioALSADriverUtility.h"
+
+#if defined(MTK_AUDIO_KS)
+#include "AudioALSADeviceConfigManager.h"
+#endif
+
+#include <audio_utils/clock.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderAAudio"
+
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+
+
+/*==============================================================================
+ * Utility
+ *============================================================================*/
+
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataProviderAAudio *AudioALSACaptureDataProviderAAudio::mAudioALSACaptureDataProviderAAudio = NULL;
+AudioALSACaptureDataProviderAAudio *AudioALSACaptureDataProviderAAudio::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACaptureDataProviderAAudio == NULL) {
+ ALOGD("%s, new instance", __func__);
+ mAudioALSACaptureDataProviderAAudio = new AudioALSACaptureDataProviderAAudio();
+ }
+ ASSERT(mAudioALSACaptureDataProviderAAudio != NULL);
+ return mAudioALSACaptureDataProviderAAudio;
+}
+
+
+void AudioALSACaptureDataProviderAAudio::freeInstance() {
+ static AudioLock mFreeInstanceLock;
+ AL_AUTOLOCK(mFreeInstanceLock);
+
+ if (mAudioALSACaptureDataProviderAAudio != NULL) {
+ ALOGD("%s, delete instance", __func__);
+ delete mAudioALSACaptureDataProviderAAudio;
+ mAudioALSACaptureDataProviderAAudio = NULL;
+ }
+}
+
+
+AudioALSACaptureDataProviderAAudio::AudioALSACaptureDataProviderAAudio():
+ mMixer(AudioALSADriverUtility::getInstance()->getMixer()),
+ mTime_nanoseconds(0),
+ mPosition_frames(0),
+ mMin_size_frames(0) {
+ ALOGD("%s()", __FUNCTION__);
+
+ memset((void *)&mCreateMmapTime, 0, sizeof(mCreateMmapTime));
+
+ mCaptureDataProviderType = CAPTURE_PROVIDER_NORMAL;
+}
+
+
+AudioALSACaptureDataProviderAAudio::~AudioALSACaptureDataProviderAAudio() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureDataProviderAAudio::open() {
+
+ ALOGD("%s(+), source format %d, rate %d, ch %d", __FUNCTION__,
+ mStreamAttributeSource.audio_format,
+ mStreamAttributeSource.sample_rate,
+ mStreamAttributeSource.num_channels);
+
+ ASSERT(mEnable == false);
+
+ int pcmindex = 0;
+ int cardindex = 0;
+
+#if defined(MTK_AUDIO_KS)
+ pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmCapture7);
+ cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmCapture7);
+ ALOGD("%s(+), cardindex = %d, pcmindex = %d", __FUNCTION__, cardindex, pcmindex);
+#else
+ ALOGE("%s(), MMAP only support KS!", __FUNCTION__);
+ ASSERT(0);
+#endif
+
+ mConfig.channels = mStreamAttributeSource.num_channels;
+ mConfig.rate = mStreamAttributeSource.sample_rate;
+ mConfig.format = (mStreamAttributeSource.audio_format == AUDIO_FORMAT_PCM_16_BIT) ?
+ PCM_FORMAT_S16_LE : PCM_FORMAT_S32_LE;
+
+ int bytesPerSample = (mStreamAttributeSource.audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4;
+
+ // period_size & period_count
+ int max_framecount = MAX_MMAP_HW_BUFFER_SIZE / mConfig.channels / bytesPerSample;
+ int min_framecount = MMAP_UL_PERIOD_SIZE * MIN_MMAP_PERIOD_COUNT;
+
+ if (mMin_size_frames < min_framecount) {
+ mMin_size_frames = min_framecount;
+ }
+ else if (mMin_size_frames > MAX_MMAP_FRAME_COUNT) {
+ mMin_size_frames = MAX_MMAP_FRAME_COUNT;
+ }
+
+ mConfig.period_count = 2;
+ mConfig.period_size = (mMin_size_frames - 1) / mConfig.period_count + 1;
+ mMin_size_frames = mConfig.period_count * mConfig.period_size;
+
+ int scenario = (mMin_size_frames <= max_framecount) ? 1 : 0;
+ ALOGD("%s(), set mmap_record_scenario %d", __FUNCTION__, scenario);
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "mmap_record_scenario"), 0, scenario)) {
+ ALOGW("%s(), mmap_record_scenario enable fail", __FUNCTION__);
+ }
+
+
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = INT32_MAX;
+ mConfig.silence_threshold = 0;
+ ALOGD("mConfig format: %d, channels: %d, rate: %d, period_size: %d, period_count: %d, latency: %d",
+ mConfig.format, mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mlatency);
+
+#if defined(MTK_AUDIO_KS)
+ mApTurnOnSequence = AUDIO_CTL_ADDA_TO_CAPTURE7;
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+
+ // set pmic before pcm prepare
+ enablePmicInputDevice(true);
+
+#if !defined(CONFIG_MT_ENG_BUILD)
+ // need to set after query pcm_params_get, since shutdown will clear this state
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "record_xrun_assert"), 0, 1)) {
+ ALOGW("%s(), record_xrun_assert enable fail", __FUNCTION__);
+ }
+#endif
+#endif
+
+ mStreamAttributeSource.buffer_size = mConfig.period_size * mConfig.period_count * mConfig.channels *
+ bytesPerSample;
+
+
+ // enable pcm
+ ASSERT(mPcm == NULL);
+ unsigned int flag = PCM_IN | PCM_MONOTONIC | PCM_MMAP | PCM_NOIRQ;
+ openPcmDriverWithFlag(pcmindex, flag);
+
+ ASSERT(mPcm != NULL && pcm_is_ready(mPcm) == true);
+ ALOGV("%s(), mPcm = %p", __FUNCTION__, mPcm);
+
+ int prepare_error = pcm_prepare(mPcm);
+ if (prepare_error != 0) {
+ ASSERT(0);
+ pcm_close(mPcm);
+ mPcm = NULL;
+ return UNKNOWN_ERROR;
+ }
+
+ mStart = false;
+
+ ALOGD("%s(-)", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureDataProviderAAudio::close() {
+ ALOGD("%s()", __FUNCTION__);
+
+#if defined(MTK_AUDIO_KS) && !defined(CONFIG_MT_ENG_BUILD)
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "record_xrun_assert"), 0, 0)) {
+ ALOGW("%s(), record_xrun_assert disable fail", __FUNCTION__);
+ }
+#endif
+
+ mEnable = false;
+
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ pcm_stop(mPcm);
+ pcm_close(mPcm);
+ mPcm = NULL;
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+
+ ALOGD("%s(), set mmap_record_scenario 0", __FUNCTION__);
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "mmap_record_scenario"), 0, 0)) {
+ ALOGW("%s(), mmap_record_scenario disable fail", __FUNCTION__);
+ }
+#endif
+
+ enablePmicInputDevice(false);
+
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureDataProviderAAudio::start() {
+ ALOGD("+%s", __FUNCTION__);
+
+ int ret = INVALID_OPERATION;
+
+ if (mPcm == NULL) {
+ ALOGW("%s, mPcm == NULL !", __FUNCTION__);
+ return ret;
+ }
+
+ // drop glitch
+ uint64_t sleepUs = 0;
+ uint64_t sleepUsMax = 30 * 1000; // 30ms
+ struct timespec curTime;
+
+ clock_gettime(CLOCK_MONOTONIC, &curTime);
+ sleepUs = get_time_diff_ns(&mCreateMmapTime, &curTime) / 1000;
+
+ if (sleepUs < sleepUsMax) {
+ sleepUs = sleepUsMax - sleepUs;
+ ALOGD("%s, drop glitch %ld ms", __FUNCTION__, (long)sleepUs);
+ usleep(sleepUs);
+ }
+
+
+ ret = pcm_start(mPcm);
+ if (ret < 0) {
+ ALOGE("%s: pcm_start fail %d, %s", __FUNCTION__, ret, pcm_get_error(mPcm));
+ }
+
+ ALOGD("-%s", __FUNCTION__);
+ return ret;
+}
+
+
+status_t AudioALSACaptureDataProviderAAudio::stop() {
+ int ret = INVALID_OPERATION;
+ ALOGD("+%s", __FUNCTION__);
+
+ if (mPcm == NULL) {
+ ALOGW("%s, mPcm == NULL !", __FUNCTION__);
+ return ret;
+ }
+
+ ret = pcm_stop(mPcm);
+ if (ret < 0) {
+ ALOGE("%s: pcm_stop fail %d", __FUNCTION__, ret);
+ }
+
+ ALOGD("-%s", __FUNCTION__);
+ return ret;
+}
+
+
+status_t AudioALSACaptureDataProviderAAudio::createMmapBuffer(int32_t min_size_frames,
+ struct audio_mmap_buffer_info *info) {
+ unsigned int offset = 0;
+ unsigned int frames = 0;
+ uint32_t buffer_size = 0;
+ int ret = INVALID_OPERATION;
+ ALOGD("+%s, min_size_frames %d", __FUNCTION__, min_size_frames);
+
+ mMin_size_frames = min_size_frames;
+
+ // open pcm
+ open();
+
+ if (mPcm == NULL) {
+ ALOGW("%s, mPcm == NULL !", __FUNCTION__);
+ return ret;
+ }
+ // drop glitch
+ clock_gettime(CLOCK_MONOTONIC, &mCreateMmapTime);
+
+
+ ret = pcm_mmap_begin(mPcm, &info->shared_memory_address, &offset, &frames);
+ if (ret < 0) {
+ goto exit;
+ }
+
+ info->buffer_size_frames = pcm_get_buffer_size(mPcm);
+ info->burst_size_frames = MMAP_UL_PERIOD_SIZE;
+ buffer_size = pcm_frames_to_bytes(mPcm, info->buffer_size_frames);
+
+ info->shared_memory_fd = mixer_ctl_get_value(mixer_get_ctl_by_name(mMixer, "aaudio_ul_mmap_fd"), 0);
+ if (info->shared_memory_fd == 0) {
+ // share mode
+ info->shared_memory_fd = pcm_get_poll_fd(mPcm);
+ ALOGD("%s+, shared fd %d", __FUNCTION__, info->shared_memory_fd);
+ } else {
+ info->buffer_size_frames *= -1;
+ }
+
+ memset(info->shared_memory_address, 0, buffer_size);
+
+ ALOGD("%s: fd %d, buffer address %p, buffer_size_frames %d %d, burst_size_frames %d", __FUNCTION__,
+ info->shared_memory_fd, info->shared_memory_address, info->buffer_size_frames,
+ buffer_size, info->burst_size_frames);
+
+exit:
+ if (ret != 0) {
+ if (mPcm != NULL) {
+ pcm_close(mPcm);
+ mPcm = NULL;
+ }
+ }
+
+ ALOGD("-%s", __FUNCTION__);
+ return ret;
+}
+
+
+status_t AudioALSACaptureDataProviderAAudio::getMmapPosition(struct audio_mmap_position *position) {
+ int ret = INVALID_OPERATION;
+
+ if (mPcm == NULL) {
+ ALOGW("%s, mPcm == NULL !", __FUNCTION__);
+ return ret;
+ }
+
+ struct timespec ts = { 0, 0 };
+ ret = pcm_mmap_get_hw_ptr(mPcm, (unsigned int *)&position->position_frames, &ts);
+ if (ret < 0) {
+ ALOGE("%s: %s", __FUNCTION__, pcm_get_error(mPcm));
+ return ret;
+ }
+ position->time_nanoseconds = audio_utils_ns_from_timespec(&ts);
+
+#if 0
+ // correction
+ if (mTime_nanoseconds == 0) {
+ mTime_nanoseconds = position->time_nanoseconds;
+ mPosition_frames = position->position_frames;
+ ALOGD("%s, assign time_nanoseconds %lld, mPosition_frames %d", __func__, (long long)mTime_nanoseconds, mPosition_frames);
+ } else {
+ position->position_frames = (position->time_nanoseconds - mTime_nanoseconds) * 48 / 1000000 + mPosition_frames;
+ }
+#endif
+
+ if (position->position_frames < 0) {
+ ALOGD("%s, time_nanoseconds %lld, mPosition_frames %d", __FUNCTION__,
+ (long long)position->time_nanoseconds, position->position_frames);
+ }
+
+ return ret;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderANC.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderANC.cpp
new file mode 100644
index 0000000..9f115e7
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderANC.cpp
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderANC"
+
+#include "AudioALSACaptureDataProviderANC.h"
+
+#include <pthread.h>
+
+#include <sys/prctl.h>
+
+#include "AudioALSADriverUtility.h"
+#include "AudioType.h"
+
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+static const uint32_t kReadBufferSize = 0x2000; // 8k
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataProviderANC *AudioALSACaptureDataProviderANC::mAudioALSACaptureDataProviderANC = NULL;
+AudioALSACaptureDataProviderANC *AudioALSACaptureDataProviderANC::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACaptureDataProviderANC == NULL) {
+ mAudioALSACaptureDataProviderANC = new AudioALSACaptureDataProviderANC();
+ }
+ ASSERT(mAudioALSACaptureDataProviderANC != NULL);
+ return mAudioALSACaptureDataProviderANC;
+}
+
+AudioALSACaptureDataProviderANC::AudioALSACaptureDataProviderANC() {
+ ALOGD("%s()", __FUNCTION__);
+
+ mConfig.channels = 2;
+ mConfig.rate = 16000;
+
+ // Buffer size: 2048(period_size) * 2(ch) * 2(byte) * 8(period_count) = 64 kb
+ mConfig.period_size = 2048;
+ mConfig.period_count = 8;
+ mConfig.format = PCM_FORMAT_S16_LE;
+
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+
+ mCaptureDataProviderType = CAPTURE_PROVIDER_ANC;
+ hReadThread = 0;
+}
+
+AudioALSACaptureDataProviderANC::~AudioALSACaptureDataProviderANC() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureDataProviderANC::open() {
+ ALOGD("%s()", __FUNCTION__);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ASSERT(mEnable == false);
+
+ // config attribute (will used in client SRC/Enh/... later) // TODO(Harvey): query this
+ mStreamAttributeSource.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ mStreamAttributeSource.num_channels = popcount(mStreamAttributeSource.audio_channel_mask);
+ mStreamAttributeSource.sample_rate = 16000;
+
+ // Reset frames readed counter
+ mStreamAttributeSource.Time_Info.total_frames_readed = 0;
+
+ OpenPCMDump(LOG_TAG);
+
+ // enable pcm
+ ASSERT(mPcm == NULL);
+ //Todo: NEED chipeng provide 4 types
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmMRGrxCapture);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmMRGrxCapture);
+
+ mPcm = pcm_open(cardIdx, pcmIdx, PCM_IN, &mConfig);
+ ASSERT(mPcm != NULL && pcm_is_ready(mPcm) == true);
+ ALOGV("%s(), mPcm = %p", __FUNCTION__, mPcm);
+
+ pcm_start(mPcm);
+
+ // create reading thread
+ mEnable = true;
+ int ret = pthread_create(&hReadThread, NULL, AudioALSACaptureDataProviderANC::readThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureDataProviderANC::close() {
+ ALOGD("%s()", __FUNCTION__);
+
+ mEnable = false;
+ pthread_join(hReadThread, NULL);
+ ALOGD("pthread_join hReadThread done");
+
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ClosePCMDump();
+
+ pcm_stop(mPcm);
+ pcm_close(mPcm);
+ mPcm = NULL;
+
+ return NO_ERROR;
+}
+
+
+void *AudioALSACaptureDataProviderANC::readThread(void *arg) {
+ prctl(PR_SET_NAME, (unsigned long)__FUNCTION__, 0, 0, 0);
+
+#ifdef MTK_AUDIO_ADJUST_PRIORITY
+#define RTPM_PRIO_AUDIO_RECORD (77)
+ // force to set priority
+ struct sched_param sched_p;
+ sched_getparam(0, &sched_p);
+ sched_p.sched_priority = RTPM_PRIO_AUDIO_RECORD + 1;
+ if (0 != sched_setscheduler(0, SCHED_RR, &sched_p)) {
+ ALOGE("[%s] failed, errno: %d", __FUNCTION__, errno);
+ } else {
+ sched_p.sched_priority = RTPM_PRIO_AUDIO_CCCI_THREAD;
+ sched_getparam(0, &sched_p);
+ ALOGD("sched_setscheduler ok, priority: %d", sched_p.sched_priority);
+ }
+#endif
+ ALOGD("+%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+
+
+
+ status_t retval = NO_ERROR;
+ AudioALSACaptureDataProviderANC *pDataProvider = static_cast<AudioALSACaptureDataProviderANC *>(arg);
+
+ uint32_t open_index = pDataProvider->mOpenIndex;
+
+ // read raw data from alsa driver
+ char linear_buffer[kReadBufferSize];
+ while (pDataProvider->mEnable == true) {
+ if (open_index != pDataProvider->mOpenIndex) {
+ ALOGD("%s(), open_index(%d) != mOpenIndex(%d), return", __FUNCTION__, open_index, pDataProvider->mOpenIndex);
+ break;
+ }
+
+ ASSERT(pDataProvider->mPcm != NULL);
+ int retval = pcm_read(pDataProvider->mPcm, linear_buffer, kReadBufferSize);
+ if (retval != 0) {
+ ALOGE("%s(), pcm_read() error, retval = %d", __FUNCTION__, retval);
+ }
+
+ // use ringbuf format to save buffer info
+ pDataProvider->mPcmReadBuf.pBufBase = linear_buffer;
+ pDataProvider->mPcmReadBuf.bufLen = kReadBufferSize + 1; // +1: avoid pRead == pWrite
+ pDataProvider->mPcmReadBuf.pRead = linear_buffer;
+ pDataProvider->mPcmReadBuf.pWrite = linear_buffer + kReadBufferSize;
+
+ pDataProvider->provideCaptureDataToAllClients(open_index);
+ }
+
+ ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ pthread_exit(NULL);
+ return NULL;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderBTCVSD.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderBTCVSD.cpp
new file mode 100644
index 0000000..1ce9290
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderBTCVSD.cpp
@@ -0,0 +1,747 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureDataProviderBTCVSD.h"
+
+#include <math.h>
+#include <pthread.h>
+
+#include <sys/prctl.h>
+
+#include "AudioType.h"
+
+#include "WCNChipController.h"
+
+#include "AudioBTCVSDDef.h"
+#include "AudioBTCVSDControl.h"
+#include "AudioALSADriverUtility.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderBTCVSD"
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+#define PCM_READ_MS 60
+#define BT_IRQ_PERIOD_US 22500
+//#define DEBUG_TIMESTAMP
+
+#ifdef DEBUG_TIMESTAMP
+#define SHOW_TIMESTAMP(format, args...) ALOGD(format, ##args)
+#else
+#define SHOW_TIMESTAMP(format, args...)
+#endif
+
+namespace android {
+
+static bool mBTMode_Open;
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataProviderBTCVSD *AudioALSACaptureDataProviderBTCVSD::mAudioALSACaptureDataProviderBTCVSD = NULL;
+AudioALSACaptureDataProviderBTCVSD *AudioALSACaptureDataProviderBTCVSD::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACaptureDataProviderBTCVSD == NULL) {
+ mAudioALSACaptureDataProviderBTCVSD = new AudioALSACaptureDataProviderBTCVSD();
+ }
+ ASSERT(mAudioALSACaptureDataProviderBTCVSD != NULL);
+ return mAudioALSACaptureDataProviderBTCVSD;
+}
+
+AudioALSACaptureDataProviderBTCVSD::AudioALSACaptureDataProviderBTCVSD() :
+ mWCNChipController(WCNChipController::GetInstance()),
+ mAudioBTCVSDControl(AudioBTCVSDControl::getInstance()),
+ mMixer(AudioALSADriverUtility::getInstance()->getMixer()),
+ mBTIrqReceived(false),
+ hReadThread(0),
+ mReadBufferSize(0),
+ mBliSrc(NULL),
+ mBliSrcOutputBuffer(NULL),
+#ifndef MTK_SUPPORT_BTCVSD_ALSA
+ mFd2(mAudioBTCVSDControl->getFd())
+#else
+ mFd2(0)
+#endif
+{
+ ALOGD("%s()", __FUNCTION__);
+
+ mCaptureDataProviderType = CAPTURE_PROVIDER_BT_CVSD;
+
+ /* Init EchoRef Resource */
+ memset(&mCaptureStartTime, 0, sizeof(mCaptureStartTime));
+
+ /* Init EchoRef Resource */
+ memset(&mEstimatedBufferTimeStamp, 0, sizeof(mEstimatedBufferTimeStamp));
+
+ /* Init timestamp*/
+ memset(&mNewtime, 0, sizeof(mNewtime));
+ memset(&mOldtime, 0, sizeof(mOldtime));
+ memset(&mOldCVSDReadTime, 0, sizeof(mOldCVSDReadTime));
+ memset(mTimerec, 0, sizeof(mTimerec));
+}
+
+AudioALSACaptureDataProviderBTCVSD::~AudioALSACaptureDataProviderBTCVSD() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureDataProviderBTCVSD::open() {
+ ASSERT(mEnable == false);
+
+ // config attribute (will used in client SRC/Enh/... later)
+ mStreamAttributeSource.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_MONO;
+ mStreamAttributeSource.num_channels = popcount(mStreamAttributeSource.audio_channel_mask);
+ mStreamAttributeSource.sample_rate = mWCNChipController->GetBTCurrentSamplingRateNumber();
+
+ /* Reset frames readed counter & mCaptureStartTime */
+ mStreamAttributeSource.Time_Info.total_frames_readed = 0;
+ memset((void *)&mCaptureStartTime, 0, sizeof(mCaptureStartTime));
+ memset((void *)&mEstimatedBufferTimeStamp, 0, sizeof(mEstimatedBufferTimeStamp));
+
+ if (mAudioBTCVSDControl->BT_SCO_isWideBand() == true) {
+ mReadBufferSize = MSBC_PCM_FRAME_BYTE * 6 * 2; // 16k mono->48k stereo
+ } else {
+ mReadBufferSize = SCO_RX_PCM8K_BUF_SIZE * 12 * 2; // 8k mono->48k stereo
+ }
+
+ mBTMode_Open = mAudioBTCVSDControl->BT_SCO_isWideBand();
+ initBliSrc();
+ ALOGD("%s(), audio_format = %d, audio_channel_mask=%x, num_channels=%d, sample_rate=%d", __FUNCTION__,
+ mStreamAttributeSource.audio_format, mStreamAttributeSource.audio_channel_mask, mStreamAttributeSource.num_channels, mStreamAttributeSource.sample_rate);
+
+ OpenPCMDump(LOG_TAG);
+
+ // enable bt cvsd driver
+#ifdef MTK_SUPPORT_BTCVSD_ALSA
+#if 0
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmBTCVSDCapture);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmBTCVSDCapture);
+
+ struct pcm_params *params;
+ params = pcm_params_get(cardindex, pcmindex, PCM_OUT);
+ if (params == NULL) {
+ ALOGD("Device does not exist.\n");
+ }
+
+ // HW pcm config
+ mConfig.channels = mStreamAttributeSource.num_channels;
+ mConfig.rate = mStreamAttributeSource.sample_rate;
+ mConfig.period_count = 2;
+ mConfig.period_size = 1024;//(mStreamAttributeTarget.buffer_size / (mConfig.channels * mConfig.period_count)) / ((mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4);
+ mConfig.format = PCM_FORMAT_S16_LE;//transferAudioFormatToPcmFormat(mStreamAttributeTarget.audio_format);
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+ ALOGD("%s(), mConfig: channels = %d, rate = %d, period_size = %d, period_count = %d, format = %d, pcmindex=%d",
+ __FUNCTION__, mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mConfig.format, pcmindex);
+
+ // open pcm driver
+ openPcmDriver(pcmindex);
+ //openPcmDriver(25);
+#else
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = mStreamAttributeSource.num_channels;
+ mConfig.rate = mStreamAttributeSource.sample_rate;
+ mConfig.period_size = 1024;
+ mConfig.period_count = 2;
+ mConfig.format = PCM_FORMAT_S16_LE;
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+
+ ASSERT(mPcm == NULL);
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmBTCVSDCapture);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmBTCVSDCapture);
+ mPcm = pcm_open(cardIdx, pcmIdx, PCM_IN, &mConfig);
+ ASSERT(mPcm != NULL && pcm_is_ready(mPcm) == true);
+ mAudioBTCVSDControl->BT_SCO_RX_Begin(mFd2);
+ if (isNeedSyncPcmStart() == false) {
+ pcm_start(mPcm);
+ } else {
+ mStart = false;
+ mReadThreadReady = false;
+ }
+#endif
+#else
+ mAudioBTCVSDControl->BT_SCO_RX_Begin(mFd2);
+#endif
+
+ // create reading thread
+ mEnable = true;
+ int ret = pthread_create(&hReadThread, NULL, AudioALSACaptureDataProviderBTCVSD::readThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureDataProviderBTCVSD::close() {
+ ALOGD("%s()", __FUNCTION__);
+
+ mEnable = false;
+ pthread_join(hReadThread, NULL);
+ ALOGD("pthread_join hReadThread done");
+
+
+ ClosePCMDump();
+
+ mAudioBTCVSDControl->BT_SCO_RX_End(mFd2);
+
+#ifdef MTK_SUPPORT_BTCVSD_ALSA
+ pcm_stop(mPcm);
+ pcm_close(mPcm);
+ mPcm = NULL;
+#endif
+ return NO_ERROR;
+}
+
+
+void *AudioALSACaptureDataProviderBTCVSD::readThread(void *arg) {
+ prctl(PR_SET_NAME, (unsigned long)__FUNCTION__, 0, 0, 0);
+
+ ALOGD("+%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+
+ status_t retval = NO_ERROR;
+ AudioALSACaptureDataProviderBTCVSD *pDataProvider = static_cast<AudioALSACaptureDataProviderBTCVSD *>(arg);
+
+ pDataProvider->setThreadPriority();
+
+ uint32_t open_index = pDataProvider->mOpenIndex;
+
+ pDataProvider->waitPcmStart();
+
+ // read raw data from alsa driver
+ uint32_t read_size = 0;
+ char linear_buffer[MSBC_PCM_FRAME_BYTE * 6 * 2]; // fixed at size for WB
+ while (pDataProvider->mEnable == true) {
+ if (open_index != pDataProvider->mOpenIndex) {
+ ALOGD("%s(), open_index(%d) != mOpenIndex(%d), return", __FUNCTION__, open_index, pDataProvider->mOpenIndex);
+ break;
+ }
+
+
+ if (pDataProvider->mPCMDumpFile) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->mTimerec[0] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+ }
+
+ bool isMuteData = false;
+ struct timespec bufferTimeStamp;
+ read_size = pDataProvider->readDataFromBTCVSD(linear_buffer, &isMuteData, &bufferTimeStamp);
+ if (read_size == 0) {
+ ALOGW("%s(), read_size == 0", __FUNCTION__);
+ continue;
+ }
+
+ if (pDataProvider->mPCMDumpFile) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->mTimerec[2] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+ }
+
+ // SRC
+ void *pBufferAfterBliSrc = NULL;
+ uint32_t bytesAfterBliSrc = 0;
+ pDataProvider->doBliSrc(linear_buffer, read_size, &pBufferAfterBliSrc, &bytesAfterBliSrc);
+
+ /* Update capture start time if needed */
+ pDataProvider->updateStartTimeStamp(bufferTimeStamp);
+
+ /* check the time stamp is match the estimatedTimeStamp, if not, compensate it! */
+ if (!isMuteData && !pDataProvider->isBufferTimeStampMatchEstimated(bufferTimeStamp)) {
+ double timeDiff = calc_time_diff(bufferTimeStamp, pDataProvider->mEstimatedBufferTimeStamp);
+ if (timeDiff > 0) {
+ /* bufferTimeStamp > mEstimatedBufferTimeStamp ==> provide extra timeDiff mute data to provider */
+ uint32_t compensateBytes = convertMsToBytes((int)(timeDiff * 1000), &pDataProvider->mStreamAttributeSource);
+ compensateBytes = compensateBytes - compensateBytes % (pDataProvider->mStreamAttributeSource.num_channels * audio_bytes_per_sample(pDataProvider->mStreamAttributeSource.audio_format));
+
+ char *compensateBuffer = new char[compensateBytes];
+ memset(compensateBuffer, 0, compensateBytes);
+
+ pDataProvider->mPcmReadBuf.pBufBase = (char *)compensateBuffer;
+ pDataProvider->mPcmReadBuf.bufLen = compensateBytes + 1; // +1: avoid pRead == pWrite
+ pDataProvider->mPcmReadBuf.pRead = (char *)pDataProvider->mPcmReadBuf.pBufBase;
+ pDataProvider->mPcmReadBuf.pWrite = (char *)pDataProvider->mPcmReadBuf.pBufBase + compensateBytes;
+
+ /* Update capture timestamp by start time */
+ pDataProvider->updateCaptureTimeStampByStartTime(compensateBytes);
+
+ SHOW_TIMESTAMP("%s(), compensateBytes = %d, newTimeStamp = %ld.%09ld",
+ __FUNCTION__, compensateBytes, pDataProvider->mStreamAttributeSource.Time_Info.timestamp_get.tv_sec, pDataProvider->mStreamAttributeSource.Time_Info.timestamp_get.tv_nsec);
+
+ pDataProvider->provideCaptureDataToAllClients(open_index);
+
+ delete[] compensateBuffer;
+ } else {
+ /* mEstimatedBufferTimeStamp > bufferTimeStamp ==> drop extra UL data */
+ uint32_t dropBytes = convertMsToBytes((int)(fabs(timeDiff) * 1000), &pDataProvider->mStreamAttributeSource);
+ dropBytes = dropBytes - dropBytes % (pDataProvider->mStreamAttributeSource.num_channels * audio_bytes_per_sample(pDataProvider->mStreamAttributeSource.audio_format));
+ if (dropBytes > bytesAfterBliSrc) {
+ SHOW_TIMESTAMP("%s() all data timeout, drop all data! (dropBytes = %d, available bytes = %d)", __FUNCTION__, dropBytes, bytesAfterBliSrc);
+ continue;
+ }
+
+ bytesAfterBliSrc -= dropBytes;
+ pBufferAfterBliSrc = ((char *)pBufferAfterBliSrc) + dropBytes;
+
+ SHOW_TIMESTAMP("%s(), dropBytes = %d, timeDiff = %lf, bytesAfterBliSrc = %d", __FUNCTION__, dropBytes, timeDiff, bytesAfterBliSrc);
+ }
+ }
+
+ /*
+ * Change the data provider reported data size from 60ms -> 20ms,
+ * Because changing the read buffer size is not easy, so we divide the report data size here
+ */
+ ssize_t frameBytes = pDataProvider->mStreamAttributeSource.num_channels * audio_bytes_per_sample(pDataProvider->mStreamAttributeSource.audio_format);
+ ssize_t totalFrameSize = bytesAfterBliSrc / frameBytes;
+ ssize_t maxProvideFrameSize = pDataProvider->mStreamAttributeSource.sample_rate * pDataProvider->getLatencyTime() / 1000;
+ ssize_t providedFrameSize = 0;
+ ALOGV("%s(), FrameBytes = %zu, bytesAfterBliSrc = %d, totalFrameSize = %zu, maxProvideFrameSize = %zu", __FUNCTION__, frameBytes, bytesAfterBliSrc, totalFrameSize, maxProvideFrameSize);
+
+ while (providedFrameSize < totalFrameSize) {
+ ssize_t remainFrameSize = totalFrameSize - providedFrameSize;
+ ssize_t frameSize = 0;
+ ssize_t bufferSize = 0;
+ if (remainFrameSize > maxProvideFrameSize) {
+ frameSize = maxProvideFrameSize;
+ } else {
+ frameSize = remainFrameSize;
+ }
+ bufferSize = frameSize * frameBytes;
+ ALOGV("%s(), frameSize = %zu, bufferSize = %zu, providedFrameSize = %zu/%zu", __FUNCTION__, frameSize, bufferSize, providedFrameSize, totalFrameSize);
+
+ // use ringbuf format to save buffer info
+ pDataProvider->mPcmReadBuf.pBufBase = (char *)pBufferAfterBliSrc + providedFrameSize * frameBytes;
+ pDataProvider->mPcmReadBuf.bufLen = bufferSize + 1; // +1: avoid pRead == pWrite
+ pDataProvider->mPcmReadBuf.pRead = (char *)pDataProvider->mPcmReadBuf.pBufBase;
+ pDataProvider->mPcmReadBuf.pWrite = (char *)pDataProvider->mPcmReadBuf.pBufBase + bufferSize;
+
+ /* update capture timestamp by start time */
+ pDataProvider->updateCaptureTimeStampByStartTime(bufferSize);
+
+ ALOGV("%s(), read size = %zu, newTimeStamp = %ld.%09ld",
+ __FUNCTION__, bufferSize, pDataProvider->mStreamAttributeSource.Time_Info.timestamp_get.tv_sec, pDataProvider->mStreamAttributeSource.Time_Info.timestamp_get.tv_nsec);
+
+ pDataProvider->provideCaptureDataToAllClients(open_index);
+ providedFrameSize += frameSize;
+ }
+
+ if (pDataProvider->mPCMDumpFile) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->mTimerec[3] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+
+ ALOGD("%s, latency_in_us,%1.6lf,%1.6lf,%1.6lf,%1.6lf,%1.6lf", __FUNCTION__, pDataProvider->mTimerec[0], pDataProvider->mTimerec[1], pDataProvider->mTimerec[2], pDataProvider->mTimerec[3], pDataProvider->mTimerec[4]);
+ }
+ }
+
+ pDataProvider->deinitBliSrc();
+
+ pDataProvider->mBTIrqReceived = false;
+
+ ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ pthread_exit(NULL);
+ return NULL;
+}
+
+uint32_t AudioALSACaptureDataProviderBTCVSD::readDataFromBTCVSD(void *linear_buffer, bool *isMuteData, struct timespec *bufferTimeStamp) {
+ ALOGV("+%s()", __FUNCTION__);
+
+ *isMuteData = false;
+
+ uint8_t *cvsd_raw_data = mAudioBTCVSDControl->BT_SCO_RX_GetCVSDTempInBuf();
+
+#ifdef MTK_SUPPORT_BTCVSD_ALSA
+ ASSERT(mPcm != NULL);
+
+ // make sure receiving bt irq before start reading
+ if (!mBTIrqReceived) {
+ if (pcm_prepare(mPcm)) {
+ ALOGE("%s(), pcm_prepare(%p) == false due to %s", __FUNCTION__, mPcm, pcm_get_error(mPcm));
+ }
+
+ struct mixer_ctl *ctl;
+ unsigned int num_values, i;
+ int index = 0;
+ ctl = mixer_get_ctl_by_name(mMixer, "btcvsd_rx_irq_received");
+ num_values = mixer_ctl_get_num_values(ctl);
+ for (i = 0; i < num_values; i++) {
+ index = mixer_ctl_get_value(ctl, i);
+ ALOGV("%s(), btcvsd_rx_irq_received, i = %d, index = %d", __FUNCTION__, i, index);
+ }
+ mBTIrqReceived = index != 0;
+ }
+
+ float returnMuteDataMs = 0.0f; /* If we cannot read data from kernel, return mute data first */
+
+ if (mBTIrqReceived) {
+ // check if enough data in kernel
+ struct timespec timeStamp;
+ unsigned int avail;
+ if (pcm_get_htimestamp(mPcm, &avail, &timeStamp) != 0) {
+ ALOGV("%s(), pcm_get_htimestamp fail %s\n", __FUNCTION__, pcm_get_error(mPcm));
+ } else {
+ if ((BTSCO_CVSD_RX_TEMPINPUTBUF_SIZE / (mConfig.channels * pcm_format_to_bits(mConfig.format) / 8)) > avail) {
+ ALOGW("%s(), read size %u, avail %u, skip write",
+ __FUNCTION__, BTSCO_CVSD_RX_TEMPINPUTBUF_SIZE, avail);
+ usleep(BT_IRQ_PERIOD_US);
+ return 0;
+ }
+ }
+
+ int retval = pcm_read(mPcm, cvsd_raw_data, BTSCO_CVSD_RX_TEMPINPUTBUF_SIZE);
+ if (retval != 0) {
+ // read fail, return mute data
+ ALOGE("%s(), pcm_read() error, retval = %d, fail due to %s", __FUNCTION__, retval, pcm_get_error(mPcm));
+ returnMuteDataMs = 60.0f;
+ } else {
+ // check if timeout during read bt data
+ struct mixer_ctl *ctl = mixer_get_ctl_by_name(mMixer, "btcvsd_rx_timeout");
+ int index = mixer_ctl_get_value(ctl, 0);
+ bool rx_timeout = index != 0;
+ ALOGV("%s(), btcvsd_rx_timeout, rx_timeout %d, index %d", __FUNCTION__, rx_timeout, index);
+ if (rx_timeout) {
+ // read timeout, return mute data
+ ALOGE("%s(), rx_timeout %d, index %d, return mute data", __FUNCTION__, rx_timeout, index);
+ returnMuteDataMs = 60.0f;
+ }
+ }
+ } else {
+ // IRQ not received, return mute data
+ ALOGW("%s(), mBTIrqReceived = %d", __FUNCTION__, mBTIrqReceived);
+ returnMuteDataMs = 22.5f;
+ }
+
+ if (returnMuteDataMs != 0.0f) {
+ *isMuteData = true;
+ *bufferTimeStamp = getCurrentTimeStamp();
+ uint32_t muteBytes = mAudioBTCVSDControl->BT_SCO_isWideBand() ? returnMuteDataMs * 16 * 2 : returnMuteDataMs * 8 * 2;
+ usleep(returnMuteDataMs * 1000); // bt irq interval is 22.5ms
+ memset(linear_buffer, 0, MSBC_PCM_FRAME_BYTE * 6 * 2);
+
+ return muteBytes;
+ }
+
+#else
+ uint32_t raw_data_size = ::read(mFd2, cvsd_raw_data, BTSCO_CVSD_RX_TEMPINPUTBUF_SIZE);
+ ALOGV("%s(), cvsd_raw_data = %p, raw_data_size = %d", __FUNCTION__, cvsd_raw_data, raw_data_size);
+
+ if (raw_data_size == 0) {
+ ALOGE("%s(), raw_data_size == 0", __FUNCTION__);
+ return 0;
+ }
+#endif
+
+ if (getKernelTimeStamp(bufferTimeStamp) != NO_ERROR) {
+ ALOGE("%s(), Cannot get kernel timestamp correctly!", __FUNCTION__);
+ }
+
+ SHOW_TIMESTAMP("%s() isMuteData = %d, bufferTimeStamp = %ld.%09ld", __FUNCTION__, *isMuteData, bufferTimeStamp->tv_sec, bufferTimeStamp->tv_nsec);
+
+
+ uint8_t *inbuf = mAudioBTCVSDControl->BT_SCO_RX_GetCVSDInBuf();
+ uint32_t insize = SCO_RX_PLC_SIZE;
+
+ uint8_t *outbuf = NULL;
+ uint32_t outsize = 0;
+ if (mAudioBTCVSDControl->BT_SCO_isWideBand() == true) {
+ outbuf = mAudioBTCVSDControl->BT_SCO_RX_GetMSBCOutBuf();
+ outsize = MSBC_PCM_FRAME_BYTE;
+ } else {
+ outbuf = mAudioBTCVSDControl->BT_SCO_RX_GetCVSDOutBuf();
+ outsize = SCO_RX_PCM8K_BUF_SIZE;
+ }
+
+ uint8_t *workbuf = mAudioBTCVSDControl->BT_SCO_RX_GetCVSDWorkBuf();
+ uint32_t workbufsize = SCO_RX_PCM64K_BUF_SIZE;
+
+
+ uint8_t packetvalid = 0;
+ uint32_t total_read_size = 0;
+ uint32_t bytes = BTSCO_CVSD_RX_INBUF_SIZE;
+ do {
+ memcpy(inbuf, cvsd_raw_data, SCO_RX_PLC_SIZE);
+ cvsd_raw_data += SCO_RX_PLC_SIZE;
+
+ packetvalid = *cvsd_raw_data; // parser packet valid info for each 30-byte packet
+ //packetvalid = 1; // force packvalid to 1 for test
+ cvsd_raw_data += BTSCO_CVSD_PACKET_VALID_SIZE;
+
+ insize = SCO_RX_PLC_SIZE;
+
+ if (mBTMode_Open != mAudioBTCVSDControl->BT_SCO_isWideBand()) {
+ ALOGW("%s(), BTSCO change mode(WB %d) after RX_Begin!!!skip write", __FUNCTION__, mAudioBTCVSDControl->BT_SCO_isWideBand());
+ mAudioBTCVSDControl->BT_SCO_RX_End(mFd2);
+ mAudioBTCVSDControl->BT_SCO_RX_Begin(mFd2);
+ mBTMode_Open = mAudioBTCVSDControl->BT_SCO_isWideBand();
+
+ if (mAudioBTCVSDControl->BT_SCO_isWideBand() == true) {
+ mReadBufferSize = MSBC_PCM_FRAME_BYTE * 6 * 2; // 16k mono->48k stereo
+ } else {
+ mReadBufferSize = SCO_RX_PCM8K_BUF_SIZE * 12 * 2; // 8k mono->48k stereo
+ }
+
+ // enable bli src when needed
+ initBliSrc();
+ return 0;
+ }
+
+ outsize = (mAudioBTCVSDControl->BT_SCO_isWideBand() == true) ? MSBC_PCM_FRAME_BYTE : SCO_RX_PCM8K_BUF_SIZE;
+ ALOGV("btsco_process_RX_CVSD/MSBC(+), insize = %d, outsize = %d, packetvalid = %u", insize, outsize, packetvalid);
+
+ if (mAudioBTCVSDControl->BT_SCO_isWideBand() == true) {
+ mAudioBTCVSDControl->btsco_process_RX_MSBC(inbuf, &insize, outbuf, &outsize, workbuf, packetvalid);
+ } else {
+ mAudioBTCVSDControl->btsco_process_RX_CVSD(inbuf, &insize, outbuf, &outsize, workbuf, workbufsize, packetvalid);
+ }
+ inbuf += SCO_RX_PLC_SIZE;
+ bytes -= insize;
+ ALOGV("btsco_process_RX_CVSD/MSBC(-), insize = %d, outsize = %d, bytes = %d", insize, outsize, bytes);
+
+
+ if (outsize > 0) {
+ if (total_read_size + outsize <= mReadBufferSize) {
+ memcpy(linear_buffer, outbuf, outsize);
+ } else {
+ ALOGE("%s(), total_read_size %u + outsize %u > mReadBufferSize %u, bytes %u", __FUNCTION__, total_read_size, outsize, mReadBufferSize, bytes);
+ ASSERT(total_read_size + outsize <= mReadBufferSize);
+ if (total_read_size < mReadBufferSize) {
+ outsize = mReadBufferSize - total_read_size;
+ memcpy(linear_buffer, outbuf, outsize);
+ } else {
+ break;
+ }
+ }
+ linear_buffer = ((char *)linear_buffer) + outsize;
+ total_read_size += outsize;
+ }
+ } while (bytes > 0 && total_read_size < mReadBufferSize);
+
+
+ ALOGV("+%s(), total_read_size = %u", __FUNCTION__, total_read_size);
+ return total_read_size;
+}
+
+static const uint32_t kBliSrcOutputBufferSize = 0x10000; // 64k
+status_t AudioALSACaptureDataProviderBTCVSD::initBliSrc() {
+ ALOGD("%s(), bt band = %d, mStreamAttributeSource.sample_rate = %u mBliSrc = %p", __FUNCTION__,
+ mAudioBTCVSDControl->BT_SCO_isWideBand(), mStreamAttributeSource.sample_rate, mBliSrc);
+
+ bool needSrc = false;
+ // bt band and rate is not match, need src
+ if ((mAudioBTCVSDControl->BT_SCO_isWideBand() && mStreamAttributeSource.sample_rate != 16000) ||
+ (!mAudioBTCVSDControl->BT_SCO_isWideBand() && mStreamAttributeSource.sample_rate != 8000)) {
+ needSrc = true;
+
+ }
+
+ // always recreate blisrc
+ if (mBliSrc) {
+ deinitBliSrc();
+ }
+
+ // init BLI SRC if need
+ if (!mBliSrc && needSrc) {
+ SRC_PCM_FORMAT src_pcm_format = SRC_IN_Q1P15_OUT_Q1P15;
+
+ mBliSrc = newMtkAudioSrc(
+ mAudioBTCVSDControl->BT_SCO_isWideBand() ? 16000 : 8000, 1,
+ mStreamAttributeSource.sample_rate, mStreamAttributeSource.num_channels,
+ src_pcm_format);
+
+ ASSERT(mBliSrc != NULL);
+ mBliSrc->open();
+
+ mBliSrcOutputBuffer = new char[kBliSrcOutputBufferSize];
+ ASSERT(mBliSrcOutputBuffer != NULL);
+ }
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureDataProviderBTCVSD::deinitBliSrc() {
+ // deinit BLI SRC if need
+ if (mBliSrc != NULL) {
+ mBliSrc->close();
+ deleteMtkAudioSrc(mBliSrc);
+ mBliSrc = NULL;
+ }
+
+ if (mBliSrcOutputBuffer != NULL) {
+ delete[] mBliSrcOutputBuffer;
+ mBliSrcOutputBuffer = NULL;
+ }
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureDataProviderBTCVSD::doBliSrc(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes) {
+ if (mBliSrc == NULL) { // No need SRC
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ } else {
+ char *p_read = (char *)pInBuffer;
+ uint32_t num_raw_data_left = inBytes;
+ uint32_t num_converted_data = kBliSrcOutputBufferSize; // max convert num_free_space
+
+ uint32_t consumed = num_raw_data_left;
+ mBliSrc->process((int16_t *)p_read, &num_raw_data_left,
+ (int16_t *)mBliSrcOutputBuffer, &num_converted_data);
+ consumed -= num_raw_data_left;
+ p_read += consumed;
+
+ ALOGV("%s(), num_raw_data_left = %u, num_converted_data = %u",
+ __FUNCTION__, num_raw_data_left, num_converted_data);
+
+ if (num_raw_data_left > 0) {
+ ALOGW("%s(), num_raw_data_left(%u) > 0", __FUNCTION__, num_raw_data_left);
+ ASSERT(num_raw_data_left == 0);
+ }
+
+ *ppOutBuffer = mBliSrcOutputBuffer;
+ *pOutBytes = num_converted_data;
+ }
+
+ ASSERT(*ppOutBuffer != NULL && *pOutBytes != 0);
+ return NO_ERROR;
+}
+
+uint32_t AudioALSACaptureDataProviderBTCVSD::getLatencyTime() {
+ mlatency = UPLINK_NORMAL_LATENCY_MS ; //20ms
+ return mlatency;
+}
+
+bool AudioALSACaptureDataProviderBTCVSD::isBufferTimeStampMatchEstimated(struct timespec timeStamp) {
+ if (mEstimatedBufferTimeStamp.tv_sec == 0 && mEstimatedBufferTimeStamp.tv_nsec == 0) {
+ return true;
+ }
+
+ double timeDiff = calc_time_diff(timeStamp, mEstimatedBufferTimeStamp);
+ bool isMatch = false;
+
+ if (fabs(timeDiff) <= (PCM_READ_MS / 1000.0f)) {
+ isMatch = true;
+
+ SHOW_TIMESTAMP("%s(), %s, timeDiff = %1.6lf (Estimated = %ld.%09ld, buffer = %ld.%09ld)",
+ __FUNCTION__, isMatch ? "Match" : "NOT match", timeDiff,
+ mEstimatedBufferTimeStamp.tv_sec, mEstimatedBufferTimeStamp.tv_nsec,
+ timeStamp.tv_sec, timeStamp.tv_nsec);
+ } else {
+ ALOGW("%s(), %s, timeDiff = %1.6lf (Estimated = %ld.%09ld, buffer = %ld.%09ld)",
+ __FUNCTION__, isMatch ? "Match" : "NOT match", timeDiff,
+ mEstimatedBufferTimeStamp.tv_sec, mEstimatedBufferTimeStamp.tv_nsec,
+ timeStamp.tv_sec, timeStamp.tv_nsec);
+ }
+
+ return isMatch;
+}
+
+status_t AudioALSACaptureDataProviderBTCVSD::getKernelTimeStamp(struct timespec *captureStartTime) {
+ /* get timestamp from driver*/
+ TimeBufferInfo *pTimeBufferInfo = NULL;
+
+#ifdef MTK_SUPPORT_BTCVSD_ALSA
+ struct mixer_ctl *ctl;
+ unsigned int num_values, i;
+ int index = 0;
+ TimeBufferInfo timeBufferInfo;
+
+ /* get timestamp from driver*/
+ ctl = mixer_get_ctl_by_name(mMixer, "btcvsd_rx_timestamp");
+ int ret_val = mixer_ctl_get_array(ctl, &timeBufferInfo, sizeof(timeBufferInfo));
+ if (ret_val < 0) {
+ ALOGE("%s() mixer_ctl_get_array() failed (error %d)", __FUNCTION__, ret_val);
+ return BAD_VALUE;
+ }
+
+ pTimeBufferInfo = &timeBufferInfo;
+#else
+ pTimeBufferInfo = (TimeBufferInfo *)(mAudioBTCVSDControl->BT_SCO_RX_GetTimeBufferInfo());
+#endif
+ uint64_t timeStamp = pTimeBufferInfo->timestampUS - pTimeBufferInfo->dataCountEquiTime;
+ captureStartTime->tv_sec = timeStamp / 1000000000;
+ captureStartTime->tv_nsec = timeStamp % 1000000000;
+
+ ALOGV("%s(), kernel captureStartTime = %ld.%09ld",
+ __FUNCTION__, captureStartTime->tv_sec, captureStartTime->tv_nsec);
+
+ return NO_ERROR;
+}
+
+struct timespec AudioALSACaptureDataProviderBTCVSD::getCurrentTimeStamp() {
+ struct timespec currentTime;
+
+ clock_gettime(CLOCK_MONOTONIC, ¤tTime);
+
+ ALOGV("%s(), timestamp = %ld.%09ld", __FUNCTION__, currentTime.tv_sec, currentTime.tv_nsec);
+
+ return currentTime;
+}
+
+status_t AudioALSACaptureDataProviderBTCVSD::updateStartTimeStamp(struct timespec timeStamp) {
+ if (mCaptureStartTime.tv_sec == 0 && mCaptureStartTime.tv_nsec == 0) {
+ mCaptureStartTime = timeStamp;
+
+ SHOW_TIMESTAMP("%s(), set start timestamp = %ld.%09ld",
+ __FUNCTION__, mCaptureStartTime.tv_sec, mCaptureStartTime.tv_nsec);
+
+ return NO_ERROR;
+ }
+
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSACaptureDataProviderBTCVSD::updateCaptureTimeStampByStartTime(uint32_t readBytes) {
+ ALOGV("%s()", __FUNCTION__);
+
+ if (mCaptureStartTime.tv_sec == 0 && mCaptureStartTime.tv_nsec == 0) {
+ ALOGW("No valid mCaptureStartTime! Don't update timestamp info.");
+ return BAD_VALUE;
+ }
+
+ /* Update timeInfo structure */
+ uint32_t bytesPerSample = audio_bytes_per_sample(mStreamAttributeSource.audio_format);
+ if (bytesPerSample == 0) {
+ ALOGW("audio_format is invalid! (%d)", mStreamAttributeSource.audio_format);
+ return BAD_VALUE;
+ }
+
+ uint32_t readFrames = readBytes / bytesPerSample / mStreamAttributeSource.num_channels;
+ time_info_struct_t *timeInfo = &mStreamAttributeSource.Time_Info;
+
+ timeInfo->frameInfo_get = 0; // Already counted in mCaptureStartTime
+ timeInfo->buffer_per_time = 0; // Already counted in mCaptureStartTime
+ timeInfo->kernelbuffer_ns = 0;
+ calculateTimeStampByFrames(mCaptureStartTime, timeInfo->total_frames_readed, mStreamAttributeSource, &timeInfo->timestamp_get);
+
+ /* Update total_frames_readed after timestamp calculation */
+ timeInfo->total_frames_readed += readFrames;
+
+ SHOW_TIMESTAMP("%s(), read size = %d, readFrames = %d (bytesPerSample = %d, ch = %d, new total_frames_readed = %d), timestamp = %ld.%09ld -> %ld.%09ld",
+ __FUNCTION__,
+ readBytes, readFrames, bytesPerSample, mStreamAttributeSource.num_channels, timeInfo->total_frames_readed,
+ mCaptureStartTime.tv_sec, mCaptureStartTime.tv_nsec,
+ timeInfo->timestamp_get.tv_sec, timeInfo->timestamp_get.tv_nsec);
+
+ /* Write time stamp to cache to avoid getCapturePosition performance issue */
+ AL_LOCK(mTimeStampLock);
+ mCaptureFramesReaded = timeInfo->total_frames_readed;
+ mCaptureTimeStamp = timeInfo->timestamp_get;
+ AL_UNLOCK(mTimeStampLock);
+
+ /* Update next estimated timestamp */
+ calculateTimeStampByFrames(mCaptureStartTime, timeInfo->total_frames_readed, mStreamAttributeSource, &mEstimatedBufferTimeStamp);
+ SHOW_TIMESTAMP("%s(), estimated next buffer timestamp = %ld.%09ld",
+ __FUNCTION__, mEstimatedBufferTimeStamp.tv_sec, mEstimatedBufferTimeStamp.tv_nsec);
+
+ return NO_ERROR;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderBTSCO.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderBTSCO.cpp
new file mode 100644
index 0000000..36b3bc1
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderBTSCO.cpp
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACaptureDataProviderBTSCO"
+
+#include "AudioALSACaptureDataProviderBTSCO.h"
+
+#include <pthread.h>
+
+#include <sys/prctl.h>
+
+#include "AudioALSADriverUtility.h"
+#include "AudioType.h"
+
+#include "WCNChipController.h"
+#include "AudioALSAStreamManager.h"
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+static uint32_t kReadBufferSize = 0;
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataProviderBTSCO *AudioALSACaptureDataProviderBTSCO::mAudioALSACaptureDataProviderBTSCO = NULL;
+AudioALSACaptureDataProviderBTSCO *AudioALSACaptureDataProviderBTSCO::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACaptureDataProviderBTSCO == NULL) {
+ mAudioALSACaptureDataProviderBTSCO = new AudioALSACaptureDataProviderBTSCO();
+ }
+ ASSERT(mAudioALSACaptureDataProviderBTSCO != NULL);
+ return mAudioALSACaptureDataProviderBTSCO;
+}
+
+AudioALSACaptureDataProviderBTSCO::AudioALSACaptureDataProviderBTSCO() :
+ mWCNChipController(WCNChipController::GetInstance()),
+ hReadThread(0) {
+ ALOGD("%s()", __FUNCTION__);
+
+ mCaptureDataProviderType = CAPTURE_PROVIDER_BT_SCO;
+ memset(&mNewtime, 0, sizeof(mNewtime));
+ memset(&mOldtime, 0, sizeof(mOldtime));
+ memset(timerec, 0, sizeof(timerec));
+}
+
+AudioALSACaptureDataProviderBTSCO::~AudioALSACaptureDataProviderBTSCO() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureDataProviderBTSCO::open() {
+ ALOGD("%s()", __FUNCTION__);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ASSERT(mEnable == false);
+
+ // config attribute (will used in client SRC/Enh/... later) // TODO(Harvey): query this
+ mStreamAttributeSource.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_MONO;
+ mStreamAttributeSource.num_channels = popcount(mStreamAttributeSource.audio_channel_mask);
+ mStreamAttributeSource.sample_rate = mWCNChipController->GetBTCurrentSamplingRateNumber();
+
+ // Reset frames readed counter
+ mStreamAttributeSource.Time_Info.total_frames_readed = 0;
+
+
+ // pcm config
+ mConfig.channels = mStreamAttributeSource.num_channels;
+ mConfig.rate = mStreamAttributeSource.sample_rate;
+
+ mlatency = UPLINK_NORMAL_LATENCY_MS ; //20ms
+#ifdef UPLINK_LOW_LATENCY
+ if (HasLowLatencyCapture()) { mlatency = UPLINK_LOW_LATENCY_MS; }
+#endif
+
+ mConfig.period_size = (mlatency * mConfig.rate) / 1000;
+ mConfig.period_count = 4;
+ mConfig.format = PCM_FORMAT_S16_LE;
+
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+
+ kReadBufferSize = mConfig.period_size * mConfig.channels * (pcm_format_to_bits(mConfig.format) / 8);
+
+ ALOGD("%s(), audio_format = %d, audio_channel_mask=%x, num_channels=%d, sample_rate=%d", __FUNCTION__,
+ mStreamAttributeSource.audio_format, mStreamAttributeSource.audio_channel_mask, mStreamAttributeSource.num_channels, mStreamAttributeSource.sample_rate);
+
+ ALOGD("%s(), format = %d, channels=%d, rate=%d, kReadBufferSize %u", __FUNCTION__,
+ mConfig.format, mConfig.channels, mConfig.rate, kReadBufferSize);
+
+ OpenPCMDump(LOG_TAG);
+
+ // enable pcm
+ ASSERT(mPcm == NULL);
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVOIPCallBTCapture);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVOIPCallBTCapture);
+ mPcm = pcm_open(cardIdx, pcmIdx, PCM_IN | PCM_MONOTONIC, &mConfig);
+ ASSERT(mPcm != NULL && pcm_is_ready(mPcm) == true);
+ ALOGV("%s(), mPcm = %p", __FUNCTION__, mPcm);
+
+ if (isNeedSyncPcmStart() == false) {
+ pcm_start(mPcm);
+ } else {
+ mStart = false;
+ mReadThreadReady = false;
+ }
+
+ // create reading thread
+ mEnable = true;
+ int ret = pthread_create(&hReadThread, NULL, AudioALSACaptureDataProviderBTSCO::readThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureDataProviderBTSCO::close() {
+ ALOGD("%s()", __FUNCTION__);
+
+ mEnable = false;
+ pthread_join(hReadThread, NULL);
+ ALOGD("pthread_join hReadThread done");
+
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ClosePCMDump();
+
+ pcm_stop(mPcm);
+ pcm_close(mPcm);
+ mPcm = NULL;
+
+ return NO_ERROR;
+}
+
+void *AudioALSACaptureDataProviderBTSCO::readThread(void *arg) {
+ prctl(PR_SET_NAME, (unsigned long)__FUNCTION__, 0, 0, 0);
+
+ ALOGD("+%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+
+ status_t retval = NO_ERROR;
+ AudioALSACaptureDataProviderBTSCO *pDataProvider = static_cast<AudioALSACaptureDataProviderBTSCO *>(arg);
+ pDataProvider->setThreadPriority();
+
+ uint32_t open_index = pDataProvider->mOpenIndex;
+
+ pDataProvider->waitPcmStart();
+
+ // read raw data from alsa driver
+ char linear_buffer[kReadBufferSize];
+ while (pDataProvider->mEnable == true) {
+ if (open_index != pDataProvider->mOpenIndex) {
+ ALOGD("%s(), open_index(%d) != mOpenIndex(%d), return", __FUNCTION__, open_index, pDataProvider->mOpenIndex);
+ break;
+ }
+
+ ASSERT(pDataProvider->mPcm != NULL);
+
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[0] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+
+ int retval = pcm_read(pDataProvider->mPcm, linear_buffer, kReadBufferSize);
+ if (retval != 0) {
+ ALOGE("%s(), pcm_read() error, retval = %d", __FUNCTION__, retval);
+ }
+
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[1] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+
+
+ //struct timespec tempTimeStamp;
+ pDataProvider->GetCaptureTimeStamp(&pDataProvider->mStreamAttributeSource.Time_Info, kReadBufferSize);
+
+ // use ringbuf format to save buffer info
+ pDataProvider->mPcmReadBuf.pBufBase = linear_buffer;
+ pDataProvider->mPcmReadBuf.bufLen = kReadBufferSize + 1; // +1: avoid pRead == pWrite
+ pDataProvider->mPcmReadBuf.pRead = linear_buffer;
+ pDataProvider->mPcmReadBuf.pWrite = linear_buffer + kReadBufferSize;
+
+ pDataProvider->provideCaptureDataToAllClients(open_index);
+
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[2] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+ ALOGD("%s, latency_in_us,%1.6lf,%1.6lf,%1.6lf", __FUNCTION__, pDataProvider->timerec[0], pDataProvider->timerec[1], pDataProvider->timerec[2]);
+ }
+
+ ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ pthread_exit(NULL);
+ return NULL;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderBase.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderBase.cpp
new file mode 100644
index 0000000..eecc494
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderBase.cpp
@@ -0,0 +1,657 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureDataProviderBase.h"
+
+#include <inttypes.h>
+#include <utils/threads.h>
+
+#include "AudioType.h"
+#include <AudioLock.h>
+
+#include <audio_lock.h>
+
+#include "IAudioALSACaptureDataClient.h"
+#include "AudioALSAHardwareResourceManager.h"
+
+#ifdef MTK_AUDIO_SCP_SUPPORT
+#include <AudioMessengerIPI.h>
+#endif
+
+#ifdef MTK_AUDIODSP_SUPPORT
+#include <audio_task.h>
+#include "AudioDspType.h"
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACaptureDataProviderBase"
+
+
+namespace android {
+#ifdef MTK_AUDIODSP_SUPPORT
+uint32_t AudioALSACaptureDataProviderBase::mDumpFileNumDsp = 0;
+#endif
+
+int AudioALSACaptureDataProviderBase::mDumpFileNum = 0;
+status_t AudioALSACaptureDataProviderBase::mPcmStatus = NO_ERROR;
+AudioALSACaptureDataProviderBase::AudioALSACaptureDataProviderBase() :
+#ifdef MTK_AUDIO_SCP_SUPPORT
+ mAudioMessengerIPI(AudioMessengerIPI::getInstance()),
+#else
+ mAudioMessengerIPI(NULL),
+#endif
+ mHardwareResourceManager(AudioALSAHardwareResourceManager::getInstance()),
+ mCaptureFramesReaded(0),
+ mEnable(false),
+ mOpenIndex(0),
+ mPcm(NULL),
+ mStart(true),
+ mReadThreadReady(true),
+ mCaptureDataProviderType(CAPTURE_PROVIDER_BASE),
+ mPcmflag(0),
+ audio_pcm_read_wrapper_fp(NULL) {
+ ALOGD("%s(), %p", __FUNCTION__, this);
+
+ mCaptureDataClientVector.clear();
+
+ memset((void *)&mPcmReadBuf, 0, sizeof(mPcmReadBuf));
+
+ memset((void *)&mConfig, 0, sizeof(mConfig));
+
+ memset((void *)&mStreamAttributeSource, 0, sizeof(mStreamAttributeSource));
+
+ memset((void *)&mStreamAttributeTargetDSP, 0, sizeof(mStreamAttributeTargetDSP));
+
+ memset((void *)&mCaptureTimeStamp, 0, sizeof(timespec));
+
+ mPCMDumpFile = NULL;
+ mPCMDumpFile4ch = NULL;
+
+ mlatency = UPLINK_NORMAL_LATENCY_MS;
+
+ audio_pcm_read_wrapper_fp = pcm_read;
+
+ mPcmStatus = NO_ERROR;
+
+#ifdef MTK_AUDIODSP_SUPPORT
+ mDumpFileNameDsp;
+ mPCMDumpFileDsp = NULL;
+ for (int i = 0; i < DEBUG_PCMDUMP_NUM; i++) {
+ pcmin_dump_array[i] = NULL;
+ }
+#endif
+}
+
+AudioALSACaptureDataProviderBase::~AudioALSACaptureDataProviderBase() {
+ ALOGD("%s(), %p", __FUNCTION__, this);
+}
+
+
+status_t AudioALSACaptureDataProviderBase::openPcmDriver(const unsigned int device) {
+ return openPcmDriverWithFlag(device, PCM_IN);
+}
+
+status_t AudioALSACaptureDataProviderBase::openPcmDriverWithFlag(const unsigned int device, unsigned int flag) {
+ ALOGD("+%s(), pcm device = %d", __FUNCTION__, device);
+
+ ASSERT(mPcm == NULL);
+ mPcmflag = flag;
+ mPcm = pcm_open(AudioALSADeviceParser::getInstance()->GetCardIndex(), device, flag, &mConfig);
+ if (mPcm == NULL) {
+ ALOGE("%s(), mPcm == NULL!!", __FUNCTION__);
+ } else if (pcm_is_ready(mPcm) == false) {
+ ALOGE("%s(), pcm_is_ready(%p) == false due to %s, close pcm.", __FUNCTION__, mPcm, pcm_get_error(mPcm));
+ pcm_close(mPcm);
+ mPcm = NULL;
+ } else {
+ if (!(mStreamAttributeSource.mAudioInputFlags & AUDIO_INPUT_FLAG_MMAP_NOIRQ)) {
+ pcm_start(mPcm);
+ }
+ }
+
+ if (flag & PCM_MMAP) {
+ audio_pcm_read_wrapper_fp = pcm_mmap_read;
+ } else {
+ audio_pcm_read_wrapper_fp = pcm_read;
+ }
+
+ ALOGD("-%s(), mPcm = %p", __FUNCTION__, mPcm);
+ ASSERT(mPcm != NULL);
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureDataProviderBase::closePcmDriver() {
+ ALOGD("+%s(), mPcm = %p", __FUNCTION__, mPcm);
+
+ if (mPcm != NULL) {
+ pcm_stop(mPcm);
+ pcm_close(mPcm);
+ mPcm = NULL;
+ }
+
+ ALOGD("-%s(), mPcm = %p", __FUNCTION__, mPcm);
+ return NO_ERROR;
+}
+
+void AudioALSACaptureDataProviderBase::enablePmicInputDevice(bool enable) {
+ if (mCaptureDataProviderType == CAPTURE_PROVIDER_NORMAL || mCaptureDataProviderType == CAPTURE_PROVIDER_DSP) {
+ ALOGV("%s(+), enable=%d", __FUNCTION__, enable);
+ if (enable == true) {
+ mHardwareResourceManager->startInputDevice(mStreamAttributeSource.input_device);
+ } else {
+ mHardwareResourceManager->stopInputDevice(mStreamAttributeSource.input_device);
+ }
+ }
+}
+
+void AudioALSACaptureDataProviderBase::attach(IAudioALSACaptureDataClient *pCaptureDataClient) {
+ uint32_t size = 0;
+
+ AL_LOCK(mEnableLock);
+
+ // add client
+ AL_LOCK(mClientLock);
+ ALOGD("%s(), %p, mCaptureDataClientVector.size()=%u, Identity=%p, mCaptureDataProviderType = %d", __FUNCTION__, this,
+ (uint32_t)mCaptureDataClientVector.size(),
+ pCaptureDataClient->getIdentity(),
+ mCaptureDataProviderType);
+ mCaptureDataClientVector.add(pCaptureDataClient->getIdentity(), pCaptureDataClient);
+ size = (uint32_t)mCaptureDataClientVector.size();
+
+ // For concurrent case, we have to calculate their frames by getRawStartFrameCount()
+ if (size > 1 && mCaptureDataProviderType != CAPTURE_PROVIDER_ECHOREF &&
+ mCaptureDataProviderType != CAPTURE_PROVIDER_ECHOREF_BTSCO &&
+ mCaptureDataProviderType != CAPTURE_PROVIDER_ECHOREF_BTCVSD &&
+ mCaptureDataProviderType != CAPTURE_PROVIDER_ECHOREF_EXT) {
+ int64_t time = 0;
+ int64_t frameCount = 0;
+ getCapturePosition(&frameCount, &time);
+ pCaptureDataClient->setRawStartFrameCount(frameCount);
+ }
+ AL_UNLOCK(mClientLock);
+
+ // open pcm interface when 1st attach
+ if (size == 1) {
+ mOpenIndex++;
+ open();
+ } else {
+ enablePmicInputDevice(true);
+ }
+
+ AL_UNLOCK(mEnableLock);
+ ALOGV("%s(-), size=%u", __FUNCTION__, size);
+}
+
+
+void AudioALSACaptureDataProviderBase::detach(IAudioALSACaptureDataClient *pCaptureDataClient) {
+ uint32_t size = 0;
+
+ AL_LOCK(mEnableLock);
+
+ // remove client
+ AL_LOCK(mClientLock);
+ ALOGD("%s(), %p, mCaptureDataClientVector.size()=%u, Identity=%p", __FUNCTION__, this,
+ (uint32_t)mCaptureDataClientVector.size(),
+ pCaptureDataClient->getIdentity());
+ mCaptureDataClientVector.removeItem(pCaptureDataClient->getIdentity());
+ size = (uint32_t)mCaptureDataClientVector.size();
+ AL_UNLOCK(mClientLock);
+
+
+ enablePmicInputDevice(false);
+
+ // close pcm interface when there is no client attached
+ if (size == 0) {
+ close();
+ }
+
+ AL_UNLOCK(mEnableLock);
+ ALOGV("%s(-), size=%u", __FUNCTION__, size);
+}
+
+
+void AudioALSACaptureDataProviderBase::provideCaptureDataToAllClients(const uint32_t open_index) {
+ ALOGV("+%s()", __FUNCTION__);
+
+ if (open_index != mOpenIndex) {
+ ALOGD("%s(), open_index(%d) != mOpenIndex(%d), return", __FUNCTION__, open_index, mOpenIndex);
+ return;
+ }
+
+ IAudioALSACaptureDataClient *pCaptureDataClient = NULL;
+
+ WritePcmDumpData();
+
+ AL_LOCK(mClientLock);
+ for (size_t i = 0; i < mCaptureDataClientVector.size(); i++) {
+ pCaptureDataClient = mCaptureDataClientVector[i];
+ pCaptureDataClient->copyCaptureDataToClient(mPcmReadBuf);
+ }
+ AL_UNLOCK(mClientLock);
+
+ ALOGV("-%s()", __FUNCTION__);
+}
+
+
+bool AudioALSACaptureDataProviderBase::isNeedSyncPcmStart() {
+ bool retval = false;
+
+ AL_LOCK(mClientLock);
+ retval = (mCaptureDataClientVector.size() == 0)
+ ? false
+ : mCaptureDataClientVector[0]->isNeedSyncPcmStart();
+ AL_UNLOCK(mClientLock);
+
+ return retval;
+}
+
+
+void AudioALSACaptureDataProviderBase::signalPcmStart() { /* for client */
+ AL_LOCK(mStartLock);
+
+ if (mStart == true || mPcm == NULL || isNeedSyncPcmStart() == false) {
+ AL_UNLOCK(mStartLock);
+ return;
+ }
+
+ AL_SIGNAL(mStartLock);
+ AL_UNLOCK(mStartLock);
+}
+
+int AudioALSACaptureDataProviderBase::pcmRead(struct pcm *mpcm, void *data, unsigned int count) {
+ return audio_pcm_read_wrapper_fp(mpcm, data, count);
+}
+
+void AudioALSACaptureDataProviderBase::waitPcmStart() { /* for read thread */
+ int wait_result = 0;
+
+ AL_LOCK(mStartLock);
+
+ mReadThreadReady = true;
+
+ if (mStart == true || mPcm == NULL) {
+ AL_UNLOCK(mStartLock);
+ return;
+ }
+
+ if (isNeedSyncPcmStart() == true) {
+ wait_result = AL_WAIT_MS(mStartLock, 100);
+ if (wait_result != 0) {
+ ALOGW("%s() wait fail", __FUNCTION__);
+ }
+ }
+
+ ALOGD("pcm_start");
+ pcm_start(mPcm);
+ mStart = true;
+ AL_UNLOCK(mStartLock);
+}
+
+
+bool AudioALSACaptureDataProviderBase::HasLowLatencyCapture(void) {
+ bool bRet = false;
+ IAudioALSACaptureDataClient *pCaptureDataClient = NULL;
+
+ AL_LOCK(mClientLock);
+ for (size_t i = 0; i < mCaptureDataClientVector.size(); i++) {
+ pCaptureDataClient = mCaptureDataClientVector[i];
+ if (pCaptureDataClient->IsLowLatencyCapture()) {
+ bRet = true;
+ break;
+ }
+ }
+ AL_UNLOCK(mClientLock);
+
+ ALOGV("%s(), bRet=%d", __FUNCTION__, bRet);
+ return bRet;
+}
+
+void AudioALSACaptureDataProviderBase::setThreadPriority(void) {
+#ifdef UPLINK_LOW_LATENCY
+ if (HasLowLatencyCapture()) {
+ audio_sched_setschedule(0, SCHED_RR, sched_get_priority_min(SCHED_RR));
+ } else
+#endif
+ {
+ audio_sched_setschedule(0, SCHED_NORMAL, sched_get_priority_max(SCHED_NORMAL));
+ }
+}
+
+void AudioALSACaptureDataProviderBase::OpenPCMDump(const char *class_name) {
+ ALOGV("%s(), mCaptureDataProviderType=%d", __FUNCTION__, mCaptureDataProviderType);
+ char mDumpFileName[128];
+
+ snprintf(mDumpFileName, sizeof(mDumpFileName) - 1, "%s%d.%s.pcm", streamin, mDumpFileNum, class_name);
+
+ mPCMDumpFile = NULL;
+ mPCMDumpFile = AudioOpendumpPCMFile(mDumpFileName, streamin_propty);
+
+
+ char mDumpFileName4ch[128];
+ if (mConfig.channels == 4) {
+ snprintf(mDumpFileName4ch, sizeof(mDumpFileName4ch) - 1, "%s%d.%s_4ch.pcm", streamin, mDumpFileNum, class_name);
+ mPCMDumpFile4ch = AudioOpendumpPCMFile(mDumpFileName4ch, streamin_propty);
+ if (mPCMDumpFile4ch != NULL) {
+ ALOGD("%s mDumpFileName4ch = %s", __FUNCTION__, mDumpFileName4ch);
+ }
+ }
+
+ if (mPCMDumpFile != NULL) {
+ ALOGD("%s DumpFileName = %s", __FUNCTION__, mDumpFileName);
+
+ mDumpFileNum++;
+ mDumpFileNum %= MAX_DUMP_NUM;
+ }
+}
+
+void AudioALSACaptureDataProviderBase::ClosePCMDump() {
+ if (mPCMDumpFile) {
+ AudioCloseDumpPCMFile(mPCMDumpFile);
+ ALOGD("%s(), mCaptureDataProviderType=%d", __FUNCTION__, mCaptureDataProviderType);
+ mPCMDumpFile = NULL;
+ }
+
+ if (mPCMDumpFile4ch) {
+ AudioCloseDumpPCMFile(mPCMDumpFile4ch);
+ mPCMDumpFile4ch = NULL;
+ }
+}
+
+void AudioALSACaptureDataProviderBase::WritePcmDumpData(void) {
+ if (mPCMDumpFile) {
+ //ALOGD("%s()", __FUNCTION__);
+ if (mPcmReadBuf.pWrite >= mPcmReadBuf.pRead) {
+ AudioDumpPCMData((void *)mPcmReadBuf.pRead, mPcmReadBuf.pWrite - mPcmReadBuf.pRead, mPCMDumpFile);
+ } else {
+ AudioDumpPCMData((void *)mPcmReadBuf.pRead, mPcmReadBuf.pBufEnd - mPcmReadBuf.pRead, mPCMDumpFile);
+ AudioDumpPCMData((void *)mPcmReadBuf.pBufBase, mPcmReadBuf.pWrite - mPcmReadBuf.pBufBase, mPCMDumpFile);
+ }
+ }
+}
+
+#ifdef MTK_AUDIODSP_SUPPORT
+void AudioALSACaptureDataProviderBase::OpenPCMDumpDsp(const char *className) {
+#define MAX_TASKNAME_LEN (128)
+
+ const char *audio_dump = "/data/vendor/audiohal/audio_dump";
+
+ char mDumpFileName[128];
+ char task_name[MAX_TASKNAME_LEN] = "capture_ul1";
+ char value[PROPERTY_VALUE_MAX];
+ uint8_t pcmdump_task_id = TASK_SCENE_CAPTURE_UL1;
+ int i, dsp_taskdump_property = 0;
+ struct ipi_msg_t ipi_msg;
+ FILE *pcm_dump = NULL;
+ property_get(streamindsp_propty, value, "0");
+ dsp_taskdump_property = atoi(value);
+
+ ALOGD("dsp_taskdump_property = %d", dsp_taskdump_property);
+
+ if (dsp_taskdump_property) {
+ for (i = 0; i < DEBUG_PCMDUMP_NUM; i++) {
+ sprintf(mDumpFileName, "%s/%s.%d.%d.%d.%s_point%d.pcm",
+ audio_dump, className, mDumpFileNumDsp, getpid(), gettid(), task_name, i);
+ mPCMDumpFileDsp = AudioOpendumpPCMFile(mDumpFileName, streamindsp_propty);
+ if (mPCMDumpFileDsp != NULL) {
+ ALOGD("%s DumpFileName = %s", __FUNCTION__, mDumpFileName);
+ }
+ set_task_pcmdump_info(pcmdump_task_id, i, (void *)mPCMDumpFileDsp);
+ }
+
+ // send PCM_DUMP_ENABLE ipi to DSP
+ mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ pcmdump_task_id, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_BYPASS_ACK,
+ AUDIO_DSP_TASK_PCMDUMP_ON, dsp_taskdump_property, 0,
+ NULL);
+
+
+ for (i = 0; i < DEBUG_PCMDUMP_NUM; i++) {
+ get_task_pcmdump_info(TASK_SCENE_CAPTURE_UL1, i, (void **)&pcm_dump);
+ if (pcm_dump == NULL) {
+ sprintf(mDumpFileName, "%s/%s.%d.%d.%d.%s_point%d.pcm",
+ audio_dump, className, mDumpFileNumDsp, getpid(), gettid(), task_name, i);
+ mPCMDumpFileDsp = AudioOpendumpPCMFile(mDumpFileName, streamindsp_propty);
+ if (mPCMDumpFileDsp != NULL) {
+ ALOGD("%s DumpFileName = %s", __FUNCTION__, mDumpFileName);
+ }
+ set_task_pcmdump_info(pcmdump_task_id, i, (void *)mPCMDumpFileDsp);
+ }
+ }
+
+ mDumpFileNumDsp++;
+ mDumpFileNumDsp %= MAX_DUMP_NUM;
+ } else {
+ mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ pcmdump_task_id, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_BYPASS_ACK,
+ AUDIO_DSP_TASK_PCMDUMP_ON, dsp_taskdump_property, 0,
+ NULL);
+ }
+
+}
+
+void AudioALSACaptureDataProviderBase::ClosePCMDumpDsp(void) {
+ char value[PROPERTY_VALUE_MAX];
+ uint8_t pcmdump_task_id = TASK_SCENE_CAPTURE_UL1;
+ int dsp_taskdump_property;
+ FILE *pcm_dump = NULL;
+ int i;
+
+ ALOGD("%s", __FUNCTION__);
+
+
+ for (i = 0; i < DEBUG_PCMDUMP_NUM; i++) {
+ get_task_pcmdump_info(pcmdump_task_id, i, (void **)&pcm_dump);
+ if (pcm_dump != NULL) {
+ ALOGD("%s AudioCloseDumpPCMFile", __FUNCTION__);
+ AudioCloseDumpPCMFile(pcm_dump);
+ set_task_pcmdump_info(pcmdump_task_id, i, NULL);
+ }
+ }
+}
+
+void AudioALSACaptureDataProviderBase::get_task_pcmdump_info(int task_id, int param, void **pcm_dump) {
+ *pcm_dump = pcmin_dump_array[param];
+ ALOGD("%s() %p %d %d\n", __FUNCTION__, *((FILE **)pcm_dump), task_id, param);
+}
+
+void AudioALSACaptureDataProviderBase::set_task_pcmdump_info(int task_id, int param, void *pcm_dump) {
+ pcmin_dump_array[param] = (FILE *)pcm_dump;
+ ALOGD("%s() %p %d %d\n", __FUNCTION__, pcmin_dump_array[param], task_id, param);
+}
+
+void AudioALSACaptureDataProviderBase::processDmaMsg(
+ struct ipi_msg_t *msg,
+ void *buf,
+ uint32_t size) {
+ FILE *pcm_dump = NULL;
+
+ ALOGD("%s() msg_id=0x%x, task_scene=%d, param2=0x%x, size=%d\n",
+ __FUNCTION__, msg->msg_id, msg->task_scene, msg->param2, size);
+
+ switch (msg->msg_id) {
+ case AUDIO_DSP_TASK_PCMDUMP_DATA:
+ get_task_pcmdump_info(msg->task_scene, msg->param2, (void **)&pcm_dump);
+ if (pcm_dump != NULL) {
+ AudioDumpPCMData(buf, size, pcm_dump);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void AudioALSACaptureDataProviderBase::processDmaMsgWrapper(
+ struct ipi_msg_t *msg,
+ void *buf,
+ uint32_t size,
+ void *arg) {
+
+ AudioALSACaptureDataProviderBase *pAudioALSACaptureDataProviderBase =
+ static_cast<AudioALSACaptureDataProviderBase *>(arg);
+
+ if (pAudioALSACaptureDataProviderBase != NULL) {
+ pAudioALSACaptureDataProviderBase->processDmaMsg(msg, buf, size);
+ }
+}
+
+#endif
+
+//echoref+++
+void AudioALSACaptureDataProviderBase::provideEchoRefCaptureDataToAllClients(const uint32_t open_index) {
+ ALOGV("+%s()", __FUNCTION__);
+
+ if (open_index != mOpenIndex) {
+ ALOGD("%s(), open_index(%d) != mOpenIndex(%d), return", __FUNCTION__, open_index, mOpenIndex);
+ return;
+ }
+
+ IAudioALSACaptureDataClient *pCaptureDataClient = NULL;
+
+ WritePcmDumpData();
+
+ AL_LOCK(mClientLock);
+ for (size_t i = 0; i < mCaptureDataClientVector.size(); i++) {
+ pCaptureDataClient = mCaptureDataClientVector[i];
+ pCaptureDataClient->copyEchoRefCaptureDataToClient(mPcmReadBuf);
+ }
+ AL_UNLOCK(mClientLock);
+
+
+ ALOGV("-%s()", __FUNCTION__);
+}
+//echoref---
+
+
+status_t AudioALSACaptureDataProviderBase::GetCaptureTimeStamp(time_info_struct_t *Time_Info, unsigned int read_size) {
+ status_t retval = NO_ERROR;
+
+ ALOGV("%s()", __FUNCTION__);
+ ASSERT(mPcm != NULL);
+
+ long ret_ns;
+ size_t avail;
+ Time_Info->timestamp_get.tv_sec = 0;
+ Time_Info->timestamp_get.tv_nsec = 0;
+ Time_Info->frameInfo_get = 0;
+ Time_Info->buffer_per_time = 0;
+ Time_Info->kernelbuffer_ns = 0;
+
+ //ALOGD("%s(), Going to check pcm_get_htimestamp", __FUNCTION__);
+ int ret = pcm_get_htimestamp(mPcm, &Time_Info->frameInfo_get, &Time_Info->timestamp_get);
+ if (ret == 0) {
+ Time_Info->buffer_per_time = pcm_bytes_to_frames(mPcm, read_size);
+ Time_Info->kernelbuffer_ns = 1000000000 / mStreamAttributeSource.sample_rate * (Time_Info->buffer_per_time + Time_Info->frameInfo_get);
+ Time_Info->total_frames_readed += Time_Info->buffer_per_time;
+ ALOGV("%s(), pcm_get_htimestamp sec= %ld, nsec=%ld, frameInfo_get = %u, buffer_per_time=%u, ret_ns = %lu, read_size = %u\n",
+ __FUNCTION__, Time_Info->timestamp_get.tv_sec, Time_Info->timestamp_get.tv_nsec, Time_Info->frameInfo_get,
+ Time_Info->buffer_per_time, Time_Info->kernelbuffer_ns, read_size);
+
+ // Write time stamp to cache to avoid getCapturePosition performance issue
+ AL_LOCK(mTimeStampLock);
+ mCaptureFramesReaded = Time_Info->total_frames_readed;
+ mCaptureTimeStamp = Time_Info->timestamp_get;
+ AL_UNLOCK(mTimeStampLock);
+#if 0
+ if ((TimeStamp->tv_nsec - ret_ns) >= 0) {
+ TimeStamp->tv_nsec -= ret_ns;
+ } else {
+ TimeStamp->tv_sec -= 1;
+ TimeStamp->tv_nsec = 1000000000 + TimeStamp->tv_nsec - ret_ns;
+ }
+
+ ALOGD("%s calculate pcm_get_htimestamp sec= %ld, nsec=%ld, avail = %d, ret_ns = %ld\n",
+ __FUNCTION__, TimeStamp->tv_sec, TimeStamp->tv_nsec, avail, ret_ns);
+#endif
+ } else {
+ ALOGE("%s pcm_get_htimestamp fail, ret: %d, pcm_get_error: %s, time: %lld.%.9ld, frameInfo_get = %u",
+ __FUNCTION__, ret, pcm_get_error(mPcm),
+ (long long)Time_Info->timestamp_get.tv_sec,
+ Time_Info->timestamp_get.tv_nsec,
+ Time_Info->frameInfo_get);
+ retval = UNKNOWN_ERROR;
+ }
+ return retval;
+}
+
+
+void AudioALSACaptureDataProviderBase::configStreamAttribute(const stream_attribute_t *attribute) {
+ AL_LOCK(mEnableLock);
+
+ ALOGD("%s(), audio_mode: %d => %d, input_device: 0x%x => 0x%x, flag: 0x%x => 0x%x, input_source: %d->%d, output_device: 0x%x => 0x%x, DSP out sample_rate: %d => %d",
+ __FUNCTION__,
+ mStreamAttributeSource.audio_mode, attribute->audio_mode,
+ mStreamAttributeSource.input_device, attribute->input_device,
+ mStreamAttributeSource.mAudioInputFlags, attribute->mAudioInputFlags,
+ mStreamAttributeSource.input_source, attribute->input_source,
+ mStreamAttributeSource.output_devices, attribute->output_devices,
+ mStreamAttributeTargetDSP.sample_rate, attribute->sample_rate);
+
+ if (mEnable == false) {
+ mStreamAttributeSource.audio_mode = attribute->audio_mode;
+ mStreamAttributeSource.input_device = attribute->input_device;
+ mStreamAttributeSource.mAudioInputFlags = attribute->mAudioInputFlags;
+ mStreamAttributeSource.input_source = attribute->input_source;
+ mStreamAttributeSource.output_devices = attribute->output_devices;
+ mStreamAttributeSource.mVoIPEnable = attribute->mVoIPEnable;
+ mStreamAttributeTargetDSP.audio_mode = attribute->audio_mode;
+ mStreamAttributeTargetDSP.input_device = attribute->input_device;
+ mStreamAttributeTargetDSP.mAudioInputFlags = attribute->mAudioInputFlags;
+ mStreamAttributeTargetDSP.input_source = attribute->input_source;
+ mStreamAttributeTargetDSP.output_devices = attribute->output_devices;
+ mStreamAttributeTargetDSP.mVoIPEnable = attribute->mVoIPEnable;
+ mStreamAttributeTargetDSP.sample_rate = attribute->sample_rate;
+ mStreamAttributeTargetDSP.NativePreprocess_Info = attribute->NativePreprocess_Info;
+
+ if (mStreamAttributeSource.mAudioInputFlags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) {
+ mStreamAttributeSource.audio_format = (attribute->audio_format == AUDIO_FORMAT_PCM_32_BIT) ?
+ AUDIO_FORMAT_PCM_8_24_BIT : AUDIO_FORMAT_PCM_16_BIT;
+ mStreamAttributeSource.audio_channel_mask = attribute->audio_channel_mask;
+ mStreamAttributeSource.num_channels = attribute->num_channels;
+ mStreamAttributeSource.sample_rate = attribute->sample_rate;
+ }
+ } else {
+ ALOGW("%s(), already enabled!! bypass config", __FUNCTION__);
+ }
+
+ AL_UNLOCK(mEnableLock);
+}
+
+
+int AudioALSACaptureDataProviderBase::getCapturePosition(int64_t *frames, int64_t *time) {
+ AL_LOCK(mTimeStampLock);
+ *frames = mCaptureFramesReaded;
+ *time = mCaptureTimeStamp.tv_sec * 1000000000LL + mCaptureTimeStamp.tv_nsec;
+ ALOGV("%s(), return frames = %" PRIu64 ", time = %" PRIu64 "", __FUNCTION__, *frames, *time);
+ AL_UNLOCK(mTimeStampLock);
+
+ return 0;
+}
+
+status_t AudioALSACaptureDataProviderBase::getPcmStatus() {
+ ALOGD("%s()", __FUNCTION__);
+ return mPcmStatus;
+}
+
+status_t AudioALSACaptureDataProviderBase::start() {
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureDataProviderBase::stop() {
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureDataProviderBase::createMmapBuffer(int32_t min_size_frames __unused,
+ struct audio_mmap_buffer_info *info __unused) {
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureDataProviderBase::getMmapPosition(struct audio_mmap_position *position __unused) {
+ return NO_ERROR;
+}
+
+} // end of namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderDsp.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderDsp.cpp
new file mode 100644
index 0000000..7077c5a
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderDsp.cpp
@@ -0,0 +1,711 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderDsp"
+
+#include "AudioALSACaptureDataProviderDsp.h"
+
+#include <pthread.h>
+#include <sys/prctl.h>
+
+#include "AudioALSADriverUtility.h"
+#include "AudioType.h"
+#include "AudioSpeechEnhanceInfo.h"
+#include "AudioALSASpeechPhoneCallController.h"
+#include "AudioALSAStreamManager.h"
+#include "AudioALSAHardwareResourceManager.h"
+#include "AudioDspStreamManager.h"
+#include <audio_task.h>
+#include "AudioUtility.h"
+#include <AudioMessengerIPI.h>
+#include <AudioVolumeInterface.h>
+#include <AudioVolumeFactory.h>
+#include "AudioSmartPaController.h"
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+#include <aurisys_scenario_dsp.h>
+#include <arsi_type.h>
+#include <aurisys_config.h>
+#endif
+
+#if defined(MTK_AUDIO_KS)
+#include "AudioALSADeviceConfigManager.h"
+#endif
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+#include "AudioDetectPulse.h"
+#endif
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+
+
+#define AUDIO_CHANNEL_IN_3MIC (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT | AUDIO_CHANNEL_IN_BACK)
+#define AUDIO_CHANNEL_IN_4MIC (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT | AUDIO_CHANNEL_IN_BACK) // ch4 == ch3
+
+#define UPLINK_SET_AMICDCC_BUFFER_TIME_MS 80
+#define UPLINK_HIFI3_LOW_LATENCY_MS 10
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+
+static uint32_t kReadBufferSize = 0;
+static const uint32_t kDCRReadBufferSize = 0x2EE00; //48K\stereo\1s data , calculate 1time/sec
+
+//static FILE *pDCCalFile = NULL;
+static bool btempDebug = false;
+
+
+/*==============================================================================
+ * Utility
+ *============================================================================*/
+
+#define LINEAR_4CH_TO_3CH(linear_buf, data_size, type) \
+ ({ \
+ uint32_t __channel_size = (data_size >> 2); \
+ uint32_t __num_sample = __channel_size / sizeof(type); \
+ uint32_t __data_size_3ch = __channel_size * 3; \
+ type *__linear_4ch = (type *)(linear_buf); \
+ type *__linear_3ch = (type *)(linear_buf); \
+ uint32_t __idx_sample = 0; \
+ for (__idx_sample = 0; __idx_sample < __num_sample; __idx_sample++) { \
+ memcpy(__linear_3ch, __linear_4ch, 3 * sizeof(type)); \
+ __linear_3ch += 3; \
+ __linear_4ch += 4; \
+ } \
+ __data_size_3ch; \
+ })
+
+
+static uint32_t doDownMixFrom4chTo3ch(void *linear_buf, uint32_t data_size, uint32_t audio_format) {
+ if (audio_format == AUDIO_FORMAT_PCM_16_BIT) {
+ return LINEAR_4CH_TO_3CH(linear_buf, data_size, int16_t);
+ } else if (audio_format == AUDIO_FORMAT_PCM_32_BIT ||
+ audio_format == AUDIO_FORMAT_PCM_8_24_BIT) {
+ return LINEAR_4CH_TO_3CH(linear_buf, data_size, int32_t);
+ } else {
+ return 0;
+ }
+}
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataProviderDsp *AudioALSACaptureDataProviderDsp::mAudioALSACaptureDataProviderDsp = NULL;
+AudioALSACaptureDataProviderDsp *AudioALSACaptureDataProviderDsp::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACaptureDataProviderDsp == NULL) {
+ mAudioALSACaptureDataProviderDsp = new AudioALSACaptureDataProviderDsp();
+ }
+ ASSERT(mAudioALSACaptureDataProviderDsp != NULL);
+ return mAudioALSACaptureDataProviderDsp;
+}
+
+AudioALSACaptureDataProviderDsp::AudioALSACaptureDataProviderDsp():
+ mMixer(AudioALSADriverUtility::getInstance()->getMixer()),
+ mDspHwPcm(NULL),
+ mDspHwRefPcm(NULL),
+ hReadThread(0),
+ mCaptureDropSize(0),
+ mAudioALSAVolumeController(AudioVolumeFactory::CreateAudioVolumeController()) {
+ ALOGD("%s()", __FUNCTION__);
+
+ mCaptureDataProviderType = CAPTURE_PROVIDER_DSP;
+ memset(&mNewtime, 0, sizeof(mNewtime));
+ memset(&mOldtime, 0, sizeof(mOldtime));
+ memset(timerec, 0, sizeof(timerec));
+ memset(&mDsphwConfig, 0, sizeof(mDsphwConfig));
+ memset(&mDsphwRefConfig, 0, sizeof(mDsphwRefConfig));
+ mPCMDumpFileDsp = NULL;
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ mAurisysLibManager = NULL;
+ mAurisysDspConfig = NULL;
+#endif
+ for (int i = 0; i < DEBUG_PCMDUMP_NUM; i++) {
+ pcmin_dump_array[i] = NULL;
+ }
+}
+
+AudioALSACaptureDataProviderDsp::~AudioALSACaptureDataProviderDsp() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+int AudioALSACaptureDataProviderDsp::setAfeDspShareMem(bool condition) {
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "adsp_capture_sharemem_scenario"), 0, condition)) {
+ ALOGW("%s(), enable fail", __FUNCTION__);
+ return -1;
+ }
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "adsp_ref_sharemem_scenario"), 0, condition)) {
+ ALOGW("%s(), enable fail", __FUNCTION__);
+ return -1;
+ }
+ return 0;
+}
+
+int AudioALSACaptureDataProviderDsp::setDspRuntimeEn(bool condition) {
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "dsp_captureul1_runtime_en"), 0, condition)) {
+ ALOGW("%s(), enable fail", __FUNCTION__);
+ return -1;
+ }
+ return 0;
+}
+
+status_t AudioALSACaptureDataProviderDsp::openDspHwPcm() {
+
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmCapture1);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmCapture1);
+
+ /* allocate the same with dsp platform drver */
+ mDsphwConfig.stop_threshold = ~(0U);
+ ALOGD("mDsphwConfig format: %d, channels: %d, rate: %d, period_size: %d, period_count: %d",
+ mDsphwConfig.format, mDsphwConfig.channels, mDsphwConfig.rate, mDsphwConfig.period_size, mDsphwConfig.period_count);
+
+ mDspHwPcm = pcm_open(cardindex, pcmindex, PCM_IN | PCM_MONOTONIC, &mDsphwConfig);
+ ASSERT(mDspHwPcm != NULL);
+ ALOGD("%s(), mDspHwPcm = %p", __FUNCTION__, mDspHwPcm);
+
+ if (pcm_prepare(mDspHwPcm) != 0) {
+ ALOGE("%s(), pcm_prepare(%p) == false due to %s, close pcm.", __FUNCTION__, mDspHwPcm, pcm_get_error(mDspHwPcm));
+ ASSERT(0);
+ pcm_close(mDspHwPcm);
+ mDspHwPcm = NULL;
+ return UNKNOWN_ERROR;
+ }
+
+ if (pcm_start(mDspHwPcm) != 0) {
+ ASSERT(0);
+ pcm_close(mDspHwPcm);
+ mDspHwPcm = NULL;
+ return UNKNOWN_ERROR;
+ }
+
+ return 0;
+}
+
+
+status_t AudioALSACaptureDataProviderDsp::openDspHwRefPcm() {
+
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmCapture2);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmCapture2);
+
+
+ mDsphwRefConfig.stop_threshold = ~(0U);
+
+#ifdef MTK_AUDIODSP_SUPPORT
+ if (AudioSmartPaController::getInstance()->isHwDspSpkProtect(mStreamAttributeSource.output_devices)) {
+ int i2sIn = AudioSmartPaController::getInstance()->getI2sInSelect();
+ AudioSmartPaController::getInstance()->setI2sHD(true, i2sIn);
+ mDspRefTurnOnSequence = i2sIn == AUDIO_I2S0 ?
+ AUDIO_CTL_I2S0_TO_CAPTURE2 : AUDIO_CTL_I2S2_TO_CAPTURE2;
+ } else if (AudioSmartPaController::getInstance()->isSwDspSpkProtect(mStreamAttributeSource.output_devices)) {
+ if (AudioDspStreamManager::getInstance()->getDspPlaybackEnable() == true) {
+ mDspRefTurnOnSequence = AUDIO_CTL_DL_MEMIF_TO_CAPTURE2_SPEAKER_HIFI3;
+ } else {
+ mDspRefTurnOnSequence = AUDIO_CTL_DL_MEMIF_TO_CAPTURE2; //todo: remove this
+ }
+ } else if (mStreamAttributeSource.output_devices & AUDIO_DEVICE_OUT_SPEAKER) {
+ mDspRefTurnOnSequence = AUDIO_CTL_DL_MEMIF_TO_CAPTURE2_SPEAKER_HIFI3; //SmartPA W/o DSP
+ } else {
+ if (AudioDspStreamManager::getInstance()->getDspPlaybackEnable() == true) {
+ mDspRefTurnOnSequence = AUDIO_CTL_DL_PLAYBACK_TO_CAPTURE2_NON_SPEAKER_HIFI3;
+ } else {
+ mDspRefTurnOnSequence = AUDIO_CTL_DL_MEMIF_TO_CAPTURE2;
+ }
+ }
+#else
+ mDspRefTurnOnSequence = AUDIO_CTL_DL_MEMIF_TO_CAPTURE2;
+#endif
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mDspRefTurnOnSequence);
+
+ ALOGD("mDsphwConfig format: %d, channels: %d, rate: %d, period_size: %d, period_count: %d",
+ mDsphwConfig.format, mDsphwConfig.channels, mDsphwConfig.rate, mDsphwConfig.period_size, mDsphwConfig.period_count);
+
+ mDspHwRefPcm = pcm_open(cardindex, pcmindex, PCM_IN | PCM_MONOTONIC, &mDsphwRefConfig);
+ ASSERT(mDspHwRefPcm != NULL);
+ ALOGD("%s(), mDspHwRefPcm = %p", __FUNCTION__, mDspHwRefPcm);
+
+ if (pcm_prepare(mDspHwRefPcm) != 0) {
+ ALOGE("%s(), pcm_prepare(%p) == false due to %s, close pcm.", __FUNCTION__, mDspHwRefPcm, pcm_get_error(mDspHwRefPcm));
+ ASSERT(0);
+ pcm_close(mDspHwRefPcm);
+ mDspHwRefPcm = NULL;
+ return UNKNOWN_ERROR;
+ }
+
+ if (pcm_start(mDspHwRefPcm) != 0) {
+ ASSERT(0);
+ pcm_close(mDspHwRefPcm);
+ mDspHwRefPcm = NULL;
+ return UNKNOWN_ERROR;
+ }
+
+ return 0;
+}
+
+
+status_t AudioALSACaptureDataProviderDsp::open() {
+
+ ALOGV("%s(+)", __FUNCTION__);
+
+ ASSERT(mEnable == false);
+
+ unsigned int feature_id = getDspFeatureID(mStreamAttributeSource.mAudioInputFlags);
+
+ setAfeDspShareMem(true);
+ setDspRuntimeEn(true);
+ mAudioMessengerIPI->registerAdspFeature(feature_id);
+
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmCaptureDspUl1);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmCaptureDspUl1);
+ mApTurnOnSequence = AUDIO_CTL_ADDA_TO_CAPTURE1;
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+
+ bool audiomode = AudioALSAStreamManager::getInstance()->isModeInPhoneCall(); // TODO: should not use AudioALSAStreamManager.......
+ ALOGD("%s(+), audiomode=%d, cardindex = %d, pcmindex = %d feature_id = %x", __FUNCTION__, audiomode, cardindex, pcmindex, feature_id);
+
+ struct pcm_params *params;
+ params = pcm_params_get(cardindex, pcmindex, PCM_IN);
+ if (params == NULL) {
+ ALOGD("Device does not exist.\n");
+ }
+
+#if defined(MTK_AUDIO_KS)
+ enablePmicInputDevice(true);
+
+ // need to set after query pcm_params_get, since shutdown will clear this state
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "record_xrun_assert"), 0, 0)) {
+ ALOGW("%s(), record_xrun_assert enable fail", __FUNCTION__);
+ }
+#endif
+
+ {
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+ unsigned int buffersizemax = pcm_params_get_max(params, PCM_PARAM_BUFFER_BYTES);
+ pcm_params_free(params);
+ bool bHifiRecord = AudioSpeechEnhanceInfo::getInstance()->GetHifiRecord();
+ //debug++
+ btempDebug = AudioSpeechEnhanceInfo::getInstance()->GetDebugStatus();
+ ALOGD("buffersizemax: %d, bHifiRecord: %d, btempDebug: %d", buffersizemax, bHifiRecord, btempDebug);
+
+#ifndef MTK_AURISYS_FRAMEWORK_SUPPORT
+ mConfig.channels = 2; // non aurisys... use 2ch
+#else
+ if (mStreamAttributeSource.input_device == AUDIO_DEVICE_IN_WIRED_HEADSET ||
+ mStreamAttributeSource.input_source == AUDIO_SOURCE_UNPROCESSED) {
+ mConfig.channels = 1;
+ } else if (mStreamAttributeSource.input_device == AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ mConfig.channels = AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport();
+
+ switch (mConfig.channels) {
+ case 1:
+ case 2:
+ break;
+ case 3:
+ ALOGV("alsa not support 3ch... use 4ch"); // ch4 is same as ch3
+ mConfig.channels = 4;
+ break;
+ case 4:
+ break;
+ default:
+ ALOGW("mConfig.channels = %d!! use 2ch", mConfig.channels);
+ mConfig.channels = 2;
+ }
+ } else {
+ ALOGW("device 0x%x not support... use 2ch", mStreamAttributeSource.input_device);
+ mConfig.channels = 2;
+ }
+#endif // end of MTK_AURISYS_FRAMEWORK_SUPPORT
+
+
+ mConfig.period_count = 4;
+ if (isNeedSyncPcmStart() == true) {
+ mConfig.period_count = 6;
+ }
+ mConfig.rate = 48000;
+
+ mlatency = UPLINK_NORMAL_LATENCY_MS ; //20ms
+#ifdef UPLINK_LOW_LATENCY
+ if (HasLowLatencyCapture()) { mlatency = UPLINK_HIFI3_LOW_LATENCY_MS; }
+#endif
+
+ if (bHifiRecord == true) {
+ mConfig.rate = 96000;
+ }
+
+
+ if (audiomode == true) {
+ //if not BT phonecall
+ if (!(audio_is_bluetooth_sco_device(mStreamAttributeSource.output_devices))) {
+ uint32_t sampleRate = AudioALSASpeechPhoneCallController::getInstance()->getSampleRate();
+ if (sampleRate != 0) {
+ mConfig.rate = sampleRate;
+ ALOGD("Phone call mode active, change smaple rate: audiomode=%d, mConfig.rate=%d", audiomode, mConfig.rate);
+ }
+ }
+ }
+
+ if (mlatency == UPLINK_HIFI3_LOW_LATENCY_MS) {
+ mConfig.period_count = 40 / UPLINK_HIFI3_LOW_LATENCY_MS; // latency/count : 1/40, 2/20, 3/13, 5/8;
+ }
+
+#ifdef RECORD_INPUT_24BITS
+ mConfig.format = PCM_FORMAT_S24_LE;
+ mStreamAttributeSource.audio_format = AUDIO_FORMAT_PCM_8_24_BIT;
+#else
+ mConfig.format = PCM_FORMAT_S16_LE;
+ mStreamAttributeSource.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+#endif
+
+ /* config attribute (will used in client SRC/Enh/... later) */
+ switch (mConfig.channels) {
+ case 1:
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_MONO;
+ break;
+ case 2:
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ break;
+ case 3:
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_3MIC;
+ break;
+ case 4:
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_4MIC;
+ break;
+ default:
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ }
+
+ mStreamAttributeSource.num_channels = mConfig.channels;
+ mStreamAttributeSource.sample_rate = mConfig.rate; //48000;
+
+ /* Reset frames readed counter */
+ mStreamAttributeSource.Time_Info.total_frames_readed = 0;
+
+#ifdef UPLINK_LOW_LATENCY
+ mConfig.period_size = getPeriodBufSize(&mStreamAttributeSource, mlatency) / mConfig.channels / (pcm_format_to_bits(mConfig.format) / 8); //period size will impact the interrupt interval
+#else
+ mConfig.period_size = (buffersizemax / mConfig.channels / (pcm_format_to_bits(mConfig.format) / 8) / mConfig.period_count;
+#endif
+
+ // should set mStreamAttributeSource.num_channels after getPeriodBufSize
+ if (mConfig.channels == 4) {
+ ALOGV("src not support 4ch -> 3ch... use 3ch");
+ mStreamAttributeSource.num_channels = 3;
+ }
+
+ mStreamAttributeSource.buffer_size = mConfig.period_size * mConfig.period_count * mConfig.channels *
+ (pcm_format_to_bits(mConfig.format) / 8);
+ mStreamAttributeSource.latency = mlatency;
+
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = mConfig.period_size * mConfig.period_count;
+ mConfig.silence_threshold = 0;
+ /* allocate the same with dsp platform drver */
+ memcpy(&mDsphwRefConfig, &mConfig, sizeof(struct pcm_config));
+ memcpy(&mDsphwConfig, &mConfig, sizeof(struct pcm_config));
+
+ ALOGD("mConfig format: %d, channels: %d, rate: %d, period_size: %d, period_count: %d, latency: %d, kReadBufferSize: %u, mCaptureDropSize: %u",
+ mConfig.format, mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mlatency, kReadBufferSize, mCaptureDropSize);
+
+ // enable pcm
+ ASSERT(mPcm == NULL);
+
+ mAudioMessengerIPI->registerDmaCbk(
+ TASK_SCENE_CAPTURE_UL1,
+ 0x10000,
+ 0x48000,
+ processDmaMsgWrapper,
+ this);
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ stream_attribute_t *streamAttributeEchoRef = NULL;
+ uint32_t aurisys_scenario = 0xFFFFFFFF;
+ uint8_t arsi_process_type = ARSI_PROCESS_TYPE_UL_ONLY;
+ struct aurisys_gain_config_t gain_config;
+ memset(&gain_config, 0, sizeof(gain_config));
+
+ if (mStreamAttributeSource.mVoIPEnable) {
+ streamAttributeEchoRef = &mStreamAttributeSource;
+ aurisys_scenario = AURISYS_SCENARIO_DSP_VOIP;
+ arsi_process_type = ARSI_PROCESS_TYPE_UL_ONLY; //ARSI_PROCESS_TYPE_UL_AND_DL;
+#ifdef UPLINK_LOW_LATENCY
+ } else if (HasLowLatencyCapture()) {
+ streamAttributeEchoRef = NULL;
+ aurisys_scenario = AURISYS_SCENARIO_DSP_RECORD_FAST;
+#endif
+ } else {
+ streamAttributeEchoRef = NULL;
+ aurisys_scenario = AURISYS_SCENARIO_DSP_RECORD;
+ }
+
+ mAudioALSAVolumeController->SetCaptureGain(mStreamAttributeSource.audio_mode,
+ mStreamAttributeSource.input_source,
+ mStreamAttributeSource.input_device,
+ mStreamAttributeSource.output_devices);
+ gain_config.ul_digital_gain = mAudioALSAVolumeController->GetSWMICGain() << 2; // (unit: 0.25 db)
+ gain_config.ul_analog_gain = ((mAudioALSAVolumeController->GetULTotalGain() - 192) / 4 + 34
+ - mAudioALSAVolumeController->GetSWMICGain()) << 2; // (unit: 0.25 db)
+
+ mStreamAttributeTargetDSP.audio_format = mStreamAttributeSource.audio_format;
+ mStreamAttributeTargetDSP.num_channels = mStreamAttributeSource.num_channels;
+ mStreamAttributeTargetDSP.buffer_size = mStreamAttributeSource.buffer_size;
+ mStreamAttributeTargetDSP.latency = mStreamAttributeSource.latency;
+ mStreamAttributeTargetDSP.audio_channel_mask = mStreamAttributeSource.audio_channel_mask;
+ kReadBufferSize = getPeriodBufSize(&mStreamAttributeTargetDSP, mlatency);
+
+ if (mConfig.rate != mStreamAttributeTargetDSP.sample_rate) {
+ mConfig.rate = mStreamAttributeTargetDSP.sample_rate;
+#ifdef UPLINK_LOW_LATENCY
+ mConfig.period_size = kReadBufferSize / mConfig.channels / (pcm_format_to_bits(mConfig.format) / 8); //period size will impact the interrupt interval
+#else
+ mConfig.period_size = (buffersizemax / mConfig.channels / (pcm_format_to_bits(mConfig.format) / 8) / mConfig.period_count;
+#endif
+ mConfig.stop_threshold = mConfig.period_size * mConfig.period_count;
+ }
+
+ ALOGD("mConfig format: %d, channels: %d, rate: %d, period_size: %d, period_count: %d, latency: %d, kReadBufferSize: %u, mCaptureDropSize: %u",
+ mConfig.format, mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mlatency, kReadBufferSize, mCaptureDropSize);
+
+
+ AudioDspStreamManager::getInstance()->CreateAurisysLibManager(
+ &mAurisysLibManager,
+ &mAurisysDspConfig,
+ TASK_SCENE_CAPTURE_UL1,
+ aurisys_scenario,
+ arsi_process_type,
+ mStreamAttributeSource.audio_mode,
+ &mStreamAttributeSource,
+ &mStreamAttributeTargetDSP,
+ streamAttributeEchoRef,
+ &gain_config);
+#endif
+
+ OpenPCMDump(LOG_TAG);
+ OpenPCMDumpDsp(LOG_TAG);
+
+#if defined(CAPTURE_MMAP) // must be after pcm open
+ unsigned int flag = PCM_IN | PCM_MONOTONIC | PCM_MMAP;
+ openPcmDriverWithFlag(pcmindex, flag);
+#else
+ mPcm = pcm_open(cardindex, pcmindex, PCM_IN | PCM_MONOTONIC, &mConfig);
+#endif
+ ASSERT(mPcm != NULL && pcm_is_ready(mPcm) == true);
+ ALOGD("%s(), mPcm = %p", __FUNCTION__, mPcm);
+
+ int prepare_error = pcm_prepare(mPcm);
+ if (prepare_error != 0) {
+ ASSERT(0);
+ pcm_close(mPcm);
+ mPcm = NULL;
+ return UNKNOWN_ERROR;
+ }
+
+ openDspHwPcm();
+
+ if ((mStreamAttributeSource.mVoIPEnable == true) || (mStreamAttributeSource.input_source == AUDIO_SOURCE_CUSTOMIZATION2)) {
+ openDspHwRefPcm();
+ }
+ mStart = false;
+ mReadThreadReady = false;
+ }
+
+ // create reading thread
+ mEnable = true;
+ int ret = pthread_create(&hReadThread, NULL, AudioALSACaptureDataProviderDsp::readThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create hReadThread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ ALOGD("%s(-)", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureDataProviderDsp::closeDspHwPcm() {
+ ALOGD("%s()", __FUNCTION__);
+ if (pcm_stop(mDspHwPcm) != 0) {
+ ALOGE("%s() pcm_stop hReadThread fail!!", __FUNCTION__);
+ }
+ pcm_close(mDspHwPcm);
+
+ return 0;
+}
+
+status_t AudioALSACaptureDataProviderDsp::closeDspHwRefPcm() {
+ ALOGD("%s()", __FUNCTION__);
+
+ if (pcm_stop(mDspHwRefPcm) != 0) {
+ ALOGE("%s() pcm_stop hReadThread fail!!", __FUNCTION__);
+ }
+ pcm_close(mDspHwRefPcm);
+
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mDspRefTurnOnSequence);
+#endif
+
+ return 0;
+}
+
+
+status_t AudioALSACaptureDataProviderDsp::close() {
+ ALOGD("%s()", __FUNCTION__);
+
+#if defined(MTK_AUDIO_KS)
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "record_xrun_assert"), 0, 0)) {
+ ALOGW("%s(), record_xrun_assert disable fail", __FUNCTION__);
+ }
+#endif
+
+ mEnable = false;
+ unsigned int feature_id = getDspFeatureID(mStreamAttributeSource.mAudioInputFlags);
+ pthread_join(hReadThread, NULL);
+ ALOGD("pthread_join hReadThread done");
+
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ClosePCMDump();
+ ClosePCMDumpDsp();
+
+ pcm_stop(mPcm);
+ pcm_close(mPcm);
+ if ((mStreamAttributeSource.mVoIPEnable == true) || (mStreamAttributeSource.input_source == AUDIO_SOURCE_CUSTOMIZATION2)) {
+ closeDspHwRefPcm();
+ }
+ closeDspHwPcm();
+ mPcm = NULL;
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+#endif
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ AudioDspStreamManager::getInstance()->DestroyAurisysLibManager(
+ &mAurisysLibManager, &mAurisysDspConfig, TASK_SCENE_CAPTURE_UL1);
+#endif
+ mAudioMessengerIPI->deregisterDmaCbk(TASK_SCENE_CAPTURE_UL1);
+ mAudioMessengerIPI->deregisterAdspFeature(feature_id);
+
+ setAfeDspShareMem(false);
+ setDspRuntimeEn(false);
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+void *AudioALSACaptureDataProviderDsp::readThread(void *arg) {
+ status_t retval = NO_ERROR;
+ int ret = 0;
+ uint32_t counter = 1;
+
+ AudioALSACaptureDataProviderDsp *pDataProvider = static_cast<AudioALSACaptureDataProviderDsp *>(arg);
+
+ uint32_t open_index = pDataProvider->mOpenIndex;
+
+ char nameset[32];
+ sprintf(nameset, "%s%d", __FUNCTION__, pDataProvider->mCaptureDataProviderType);
+ prctl(PR_SET_NAME, (unsigned long)nameset, 0, 0, 0);
+ pDataProvider->setThreadPriority();
+
+ ALOGD("+%s(), pid: %d, tid: %d, kReadBufferSize=0x%x, open_index=%d, UPLINK_SET_AMICDCC_BUFFER_TIME_MS = %d, counter=%d ", __FUNCTION__, getpid(), gettid(), kReadBufferSize, open_index, UPLINK_SET_AMICDCC_BUFFER_TIME_MS, counter);
+
+ pDataProvider->waitPcmStart();
+
+ // read raw data from alsa driver
+ char linear_buffer[kReadBufferSize];
+ uint32_t Read_Size = kReadBufferSize;
+ uint32_t kReadBufferSize_new;
+ while (pDataProvider->mEnable == true) {
+ ASSERT(open_index == pDataProvider->mOpenIndex);
+ ASSERT(pDataProvider->mPcm != NULL);
+
+ if (btempDebug) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[0] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+ }
+
+ ret = pDataProvider->pcmRead(pDataProvider->mPcm, linear_buffer, kReadBufferSize);
+ if (ret != 0) {
+ ALOGE("%s(), pcm_read() error, retval = %d", __FUNCTION__, retval);
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mOldtime);
+ continue;
+ }
+
+ //struct timespec tempTimeStamp;
+ retval = pDataProvider->GetCaptureTimeStamp(&pDataProvider->mStreamAttributeSource.Time_Info, kReadBufferSize);
+
+ if (btempDebug) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[1] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+ }
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+ stream_attribute_t *attribute = &(pDataProvider->mStreamAttributeSource);
+ AudioDetectPulse::doDetectPulse(TAG_CAPTURE_DATA_PROVIDER, PULSE_LEVEL, 0, (void *)linear_buffer,
+ kReadBufferSize, attribute->audio_format, attribute->num_channels,
+ attribute->sample_rate);
+#endif
+
+ if (pDataProvider->mConfig.channels == 4 && pDataProvider->mPCMDumpFile4ch) {
+ AudioDumpPCMData(linear_buffer, kReadBufferSize, pDataProvider->mPCMDumpFile4ch);
+ }
+
+ // 4ch to 3ch
+ if (pDataProvider->mConfig.channels == 4 &&
+ pDataProvider->mStreamAttributeSource.num_channels == 3) {
+ Read_Size = doDownMixFrom4chTo3ch(
+ linear_buffer,
+ kReadBufferSize,
+ pDataProvider->mStreamAttributeSource.audio_format);
+ } else {
+ Read_Size = kReadBufferSize;
+ }
+
+ // Adjust AMIC 3DB Corner clock setting
+ if (counter <= (UPLINK_SET_AMICDCC_BUFFER_TIME_MS / pDataProvider->mlatency)) {
+ if (counter == (UPLINK_SET_AMICDCC_BUFFER_TIME_MS / pDataProvider->mlatency)) {
+ pDataProvider->adjustSpike();
+ }
+ counter++;
+ }
+
+ // use ringbuf format to save buffer info
+ pDataProvider->mPcmReadBuf.pBufBase = linear_buffer;
+ pDataProvider->mPcmReadBuf.bufLen = Read_Size + 1; // +1: avoid pRead == pWrite
+ pDataProvider->mPcmReadBuf.pRead = linear_buffer;
+ pDataProvider->mPcmReadBuf.pWrite = linear_buffer + Read_Size;
+ pDataProvider->provideCaptureDataToAllClients(open_index);
+
+ if (btempDebug) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[2] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+
+ ALOGD("%s, latency_in_us,%1.6lf,%1.6lf,%1.6lf", __FUNCTION__, pDataProvider->timerec[0], pDataProvider->timerec[1], pDataProvider->timerec[2]);
+ }
+ }
+
+ ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ pthread_exit(NULL);
+ return NULL;
+}
+
+void AudioALSACaptureDataProviderDsp::adjustSpike() {
+ status_t retval = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mAudioALSACaptureDataProviderDsp->mMixer, "Audio_AMIC_DCC_Setting"), "On");
+ if (retval != 0) {
+ ALOGD("%s(), Can not find Audio_AMIC_DCC_Setting!", __FUNCTION__);
+ }
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderEchoRef.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderEchoRef.cpp
new file mode 100644
index 0000000..b041127
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderEchoRef.cpp
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderEchoRef"
+
+#include "AudioALSACaptureDataProviderEchoRef.h"
+
+#include <pthread.h>
+
+#include <sys/prctl.h>
+
+#include "AudioType.h"
+
+#include "AudioALSADriverUtility.h"
+#include "AudioALSASampleRateController.h"
+#include "AudioALSAStreamManager.h"
+#if defined(MTK_AUDIO_KS)
+#include "AudioALSADeviceConfigManager.h"
+#endif
+
+#if defined(MTK_AUDIODSP_SUPPORT)
+#include "AudioDspStreamManager.h"
+#endif
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+static uint32_t kReadBufferSize = 0 ;
+
+static bool btempDebug = false;
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataProviderEchoRef *AudioALSACaptureDataProviderEchoRef::mAudioALSACaptureDataProviderEchoRef = NULL;
+AudioALSACaptureDataProviderEchoRef *AudioALSACaptureDataProviderEchoRef::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACaptureDataProviderEchoRef == NULL) {
+ mAudioALSACaptureDataProviderEchoRef = new AudioALSACaptureDataProviderEchoRef();
+ }
+ ASSERT(mAudioALSACaptureDataProviderEchoRef != NULL);
+ return mAudioALSACaptureDataProviderEchoRef;
+}
+
+AudioALSACaptureDataProviderEchoRef::AudioALSACaptureDataProviderEchoRef():
+ mMixer(AudioALSADriverUtility::getInstance()->getMixer()),
+ hReadThread(0) {
+ ALOGD("%s()", __FUNCTION__);
+ memset(&mNewtime, 0, sizeof(mNewtime));
+ memset(&mOldtime, 0, sizeof(mOldtime));
+ mCaptureDataProviderType = CAPTURE_PROVIDER_ECHOREF;
+}
+
+AudioALSACaptureDataProviderEchoRef::~AudioALSACaptureDataProviderEchoRef() {
+ ALOGV("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureDataProviderEchoRef::open() {
+ ALOGV("%s()", __FUNCTION__);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+ ASSERT(mEnable == false);
+
+ AudioALSASampleRateController *pAudioALSASampleRateController = AudioALSASampleRateController::getInstance();
+ pAudioALSASampleRateController->setScenarioStatus(PLAYBACK_SCENARIO_ECHO_REF);
+
+
+ // config attribute (will used in client SRC/Enh/... later) // TODO(Sam): query the mConfig?
+ mStreamAttributeSource.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ mStreamAttributeSource.num_channels = popcount(mStreamAttributeSource.audio_channel_mask);
+ mStreamAttributeSource.sample_rate = pAudioALSASampleRateController->getPrimaryStreamOutSampleRate();
+
+ // Reset frames readed counter
+ mStreamAttributeSource.Time_Info.total_frames_readed = 0;
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ mlatency = UPLINK_NORMAL_LATENCY_MS;
+
+#ifdef UPLINK_LOW_LATENCY
+ if (HasLowLatencyCapture()) { mlatency = UPLINK_LOW_LATENCY_MS; }
+#endif
+#else
+ mlatency = UPLINK_LOW_LATENCY_MS;
+
+#ifdef UPLINK_LOW_LATENCY
+ if (HasLowLatencyCapture()) { mlatency /= 2; }
+#endif
+#endif
+
+ mConfig.rate = mStreamAttributeSource.sample_rate;
+ mConfig.channels = mStreamAttributeSource.num_channels;
+ mConfig.format = PCM_FORMAT_S16_LE;
+ kReadBufferSize = getPeriodBufSize(&mStreamAttributeSource, mlatency);
+#if 0 // cause latency issue...... = =a
+ kReadBufferSize &= 0xFFFFFFC0; // (DL1)44.1K\20ms data\stereo\2byte\(Align64byte)
+#endif
+ //Buffer size: 2048(period_size) * 2(ch) * 2(byte) * 8(period_count) = 64 kb
+ mConfig.period_size = kReadBufferSize / mConfig.channels / (pcm_format_to_bits(mConfig.format) / 8);
+ mConfig.period_count = 160 / mlatency;
+
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+
+
+#if 0
+ //latency time, set as DataProvider buffer size
+ mStreamAttributeSource.latency = (kReadBufferSize * 1000) / (mStreamAttributeSource.num_channels * mStreamAttributeSource.sample_rate *
+ (mStreamAttributeSource.audio_format == AUDIO_FORMAT_PCM_8_BIT ? 1 : //8 1byte/frame
+ (mStreamAttributeSource.audio_format == AUDIO_FORMAT_PCM_32_BIT ? 4 : //24bit 3bytes/frame
+ 2))); //default 2bytes/sample
+#else
+ //latency time, set as hardware buffer size
+ mStreamAttributeSource.latency = (mConfig.period_size * mConfig.period_count * 1000) / mConfig.rate;
+#endif
+
+ ALOGD("%s(), audio_format = %d, output_device=0x%x, audio_channel_mask=%x, num_channels=%d, sample_rate=%d, buf_total_latency=%dms", __FUNCTION__,
+ mStreamAttributeSource.audio_format, mStreamAttributeSource.output_devices, mStreamAttributeSource.audio_channel_mask, mStreamAttributeSource.num_channels, mStreamAttributeSource.sample_rate, mStreamAttributeSource.latency);
+
+ ALOGD("%s(), format = %d, channels=%d, rate=%d, period_size=%d, period_count=%d,latency=%d,kReadBufferSize=%d", __FUNCTION__,
+ mConfig.format, mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mlatency, kReadBufferSize);
+
+
+ OpenPCMDump(LOG_TAG);
+
+ btempDebug = AudioSpeechEnhanceInfo::getInstance()->GetDebugStatus();
+
+#if defined(MTK_AUDIO_KS)
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmCapture2);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmCapture2);
+#ifdef MTK_AUDIODSP_SUPPORT
+ if (mStreamAttributeSource.output_devices & AUDIO_DEVICE_OUT_SPEAKER) {
+ if (AudioDspStreamManager::getInstance()->getDspPlaybackEnable() == true) {
+ mApTurnOnSequence = AUDIO_CTL_DL_MEMIF_TO_CAPTURE2_SPEAKER_HIFI3;
+ } else {
+ mApTurnOnSequence = AUDIO_CTL_DL_MEMIF_TO_CAPTURE2;
+ }
+ } else {
+ if (AudioDspStreamManager::getInstance()->getDspPlaybackEnable() == true) {
+ mApTurnOnSequence = AUDIO_CTL_DL_PLAYBACK_TO_CAPTURE2_NON_SPEAKER_HIFI3;
+ } else {
+ mApTurnOnSequence = AUDIO_CTL_DL_MEMIF_TO_CAPTURE2; //todo: remove this
+ }
+ }
+#else
+ mApTurnOnSequence = AUDIO_CTL_DL_MEMIF_TO_CAPTURE2;
+#endif
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+
+ // need to set after query pcm_params_get, since shutdown will clear this state
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "echo_ref_xrun_assert"), 0, 1)) {
+ ALOGW("%s(), echo_ref_xrun_assert enable fail", __FUNCTION__);
+ }
+#else
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmDl1AwbCapture);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmDl1AwbCapture);
+#endif
+
+ // enable pcm
+ ASSERT(mPcm == NULL);
+ mPcm = pcm_open(cardIdx, pcmIdx, PCM_IN | PCM_MONOTONIC, &mConfig);
+ ASSERT(mPcm != NULL && pcm_is_ready(mPcm) == true);
+
+ mStart = false;
+ mReadThreadReady = false;
+
+
+ // create reading thread
+ mEnable = true;
+ int ret = pthread_create(&hReadThread, NULL, AudioALSACaptureDataProviderEchoRef::readThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureDataProviderEchoRef::close() {
+ ALOGD("%s()", __FUNCTION__);
+
+#if defined(MTK_AUDIO_KS)
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "echo_ref_xrun_assert"), 0, 0)) {
+ ALOGW("%s(), echo_ref_xrun_assert disable fail", __FUNCTION__);
+ }
+#endif
+
+ mEnable = false;
+ pthread_join(hReadThread, NULL);
+ ALOGV("pthread_join hReadThread done");
+
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ClosePCMDump();
+
+ pcm_stop(mPcm);
+ pcm_close(mPcm);
+ mPcm = NULL;
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+#endif
+
+ AudioALSASampleRateController *pAudioALSASampleRateController = AudioALSASampleRateController::getInstance();
+ pAudioALSASampleRateController->resetScenarioStatus(PLAYBACK_SCENARIO_ECHO_REF);
+
+ return NO_ERROR;
+}
+
+void *AudioALSACaptureDataProviderEchoRef::readThread(void *arg) {
+ status_t ret = NO_ERROR;
+ int retval = 0;
+
+ AudioALSACaptureDataProviderEchoRef *pDataProvider = static_cast<AudioALSACaptureDataProviderEchoRef *>(arg);
+
+ uint32_t open_index = pDataProvider->mOpenIndex;
+
+ char nameset[32];
+ sprintf(nameset, "%s%d", __FUNCTION__, pDataProvider->mCaptureDataProviderType);
+ prctl(PR_SET_NAME, (unsigned long)nameset, 0, 0, 0);
+ pDataProvider->setThreadPriority();
+
+
+ ALOGD("+%s(), pid: %d, tid: %d, kReadBufferSize=%x", __FUNCTION__, getpid(), gettid(), kReadBufferSize);
+
+ pDataProvider->waitPcmStart();
+
+ // read raw data from alsa driver
+ char linear_buffer[kReadBufferSize];
+ while (pDataProvider->mEnable == true) {
+ ASSERT(open_index == pDataProvider->mOpenIndex);
+ ASSERT(pDataProvider->mPcm != NULL);
+
+ if (btempDebug) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[0] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+ }
+
+ int retval = pcm_read(pDataProvider->mPcm, linear_buffer, kReadBufferSize);
+ if (retval != 0) {
+ ALOGE("%s(), pcm_read() error, retval = %d", __FUNCTION__, retval);
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mOldtime);
+ continue;
+ }
+
+ //struct timespec tempTimeStamp;
+ ret = pDataProvider->GetCaptureTimeStamp(&pDataProvider->mStreamAttributeSource.Time_Info, kReadBufferSize);
+#if 0
+ if (ret != NO_ERROR) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mOldtime);
+ continue;
+ }
+#endif
+
+ if (btempDebug) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[1] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+ }
+
+ // use ringbuf format to save buffer info
+ pDataProvider->mPcmReadBuf.pBufBase = linear_buffer;
+ pDataProvider->mPcmReadBuf.bufLen = kReadBufferSize + 1; // +1: avoid pRead == pWrite
+ pDataProvider->mPcmReadBuf.pRead = linear_buffer;
+ pDataProvider->mPcmReadBuf.pWrite = linear_buffer + kReadBufferSize;
+
+ //Provide EchoRef data
+#if 0
+ pDataProvider->provideCaptureDataToAllClients(open_index);
+#else
+ pDataProvider->provideEchoRefCaptureDataToAllClients(open_index);
+#endif
+
+ if (btempDebug) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[2] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+
+ ALOGD("%s, latency_in_us,%1.6lf,%1.6lf,%1.6lf", __FUNCTION__, pDataProvider->timerec[0], pDataProvider->timerec[1], pDataProvider->timerec[2]);
+ }
+ }
+
+ ALOGV("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ pthread_exit(NULL);
+ return NULL;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderEchoRefBTCVSD.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderEchoRefBTCVSD.cpp
new file mode 100644
index 0000000..f2244fc
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderEchoRefBTCVSD.cpp
@@ -0,0 +1,437 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderEchoRefBTCVSD"
+
+#include "AudioALSACaptureDataProviderEchoRefBTCVSD.h"
+
+#include <math.h>
+#include <pthread.h>
+
+#include <sys/prctl.h>
+
+#include "AudioType.h"
+
+#include "AudioALSADriverUtility.h"
+#include "AudioALSAPlaybackHandlerBTCVSD.h"
+#include "AudioALSASampleRateController.h"
+#include "WCNChipController.h"
+
+//#define DEBUG_TIMESTAMP
+
+#ifdef DEBUG_TIMESTAMP
+#define SHOW_TIMESTAMP(format, args...) ALOGD(format, ##args)
+#else
+#define SHOW_TIMESTAMP(format, args...)
+#endif
+
+#define MAX_LOCK_TIME_OUT_MS (500)
+#define MAX_READ_DATA_TIME_OUT_MS (60)
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+static uint32_t kReadBufferSize = 0;
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataProviderEchoRefBTCVSD *AudioALSACaptureDataProviderEchoRefBTCVSD::mAudioALSACaptureDataProviderEchoRefBTCVSD = NULL;
+AudioALSACaptureDataProviderEchoRefBTCVSD *AudioALSACaptureDataProviderEchoRefBTCVSD::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACaptureDataProviderEchoRefBTCVSD == NULL) {
+ mAudioALSACaptureDataProviderEchoRefBTCVSD = new AudioALSACaptureDataProviderEchoRefBTCVSD();
+ }
+ ASSERT(mAudioALSACaptureDataProviderEchoRefBTCVSD != NULL);
+ return mAudioALSACaptureDataProviderEchoRefBTCVSD;
+}
+
+AudioALSACaptureDataProviderEchoRefBTCVSD::AudioALSACaptureDataProviderEchoRefBTCVSD() :
+ mTotalCaptureBufSize(0),
+ mWCNChipController(WCNChipController::GetInstance()),
+ hReadThread(0) {
+ ALOGD("%s()", __FUNCTION__);
+
+ mCaptureDataProviderType = CAPTURE_PROVIDER_ECHOREF_BTCVSD;
+
+ memset((void *)&mDataRingBuf, 0, sizeof(mDataRingBuf));
+
+ memset((void *)&mCaptureStartTime, 0, sizeof(mCaptureStartTime));
+
+ memset((void *)&mEstimateTimeStamp, 0, sizeof(mEstimateTimeStamp));
+
+ memset((void *)&mNewtime, 0, sizeof(mNewtime));
+
+ memset((void *)&mOldtime, 0, sizeof(mOldtime));
+}
+
+AudioALSACaptureDataProviderEchoRefBTCVSD::~AudioALSACaptureDataProviderEchoRefBTCVSD() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureDataProviderEchoRefBTCVSD::open() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ ASSERT(mEnable == false);
+
+ AudioALSASampleRateController *pAudioALSASampleRateController = AudioALSASampleRateController::getInstance();
+ pAudioALSASampleRateController->setScenarioStatus(PLAYBACK_SCENARIO_ECHO_REF);
+
+ // config attribute (will used in client SRC/Enh/... later) // TODO(Sam): query the mConfig?
+ mStreamAttributeSource.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ mStreamAttributeSource.num_channels = popcount(mStreamAttributeSource.audio_channel_mask);
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ mStreamAttributeSource.sample_rate = mWCNChipController->GetBTCurrentSamplingRateNumber();
+#else
+ mStreamAttributeSource.sample_rate = pAudioALSASampleRateController->getPrimaryStreamOutSampleRate();
+#endif
+ mStreamAttributeSource.latency = UPLINK_NORMAL_LATENCY_MS;
+
+ uint32_t frameBytes = mStreamAttributeSource.num_channels * audio_bytes_per_sample(mStreamAttributeSource.audio_format);
+ kReadBufferSize = (mStreamAttributeSource.sample_rate * mStreamAttributeSource.latency / 1000) * frameBytes;
+
+ /* Reset buffer & timestamp info */
+ initDataRingBuf(kReadBufferSize * 10);
+ resetTimeStampInfo();
+
+ ALOGD("%s(), audio_format = %d, audio_channel_mask=%x, num_channels=%d, sample_rate=%d, latency=%dms", __FUNCTION__,
+ mStreamAttributeSource.audio_format, mStreamAttributeSource.audio_channel_mask, mStreamAttributeSource.num_channels, mStreamAttributeSource.sample_rate, mStreamAttributeSource.latency);
+
+ OpenPCMDump(LOG_TAG);
+
+ // create reading thread
+ mEnable = true;
+ int ret = pthread_create(&hReadThread, NULL, AudioALSACaptureDataProviderEchoRefBTCVSD::readThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ ALOGD("-%s()", __FUNCTION__);
+
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureDataProviderEchoRefBTCVSD::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ if (mEnable == true) {
+ mEnable = false;
+
+ /* Signal the echo ref data waiting to avoid deadlock */
+ signalDataWaiting();
+
+ ClosePCMDump();
+
+
+ AudioALSASampleRateController *pAudioALSASampleRateController = AudioALSASampleRateController::getInstance();
+ pAudioALSASampleRateController->resetScenarioStatus(PLAYBACK_SCENARIO_ECHO_REF);
+
+ deinitDataRingBuf();
+ }
+
+ ALOGD("-%s()", __FUNCTION__);
+
+ return NO_ERROR;
+}
+
+void *AudioALSACaptureDataProviderEchoRefBTCVSD::readThread(void *arg) {
+ status_t retval = NO_ERROR;
+ AudioALSACaptureDataProviderEchoRefBTCVSD *pDataProvider = static_cast<AudioALSACaptureDataProviderEchoRefBTCVSD *>(arg);
+
+ uint32_t open_index = pDataProvider->mOpenIndex;
+
+ char nameset[32];
+ sprintf(nameset, "%s%d", __FUNCTION__, pDataProvider->mCaptureDataProviderType);
+ prctl(PR_SET_NAME, (unsigned long)nameset, 0, 0, 0);
+ pDataProvider->setThreadPriority();
+
+ ALOGD("+%s(), pid: %d, tid: %d, kReadBufferSize=%x", __FUNCTION__, getpid(), gettid(), kReadBufferSize);
+
+ // read raw data from alsa driver
+ char linear_buffer[kReadBufferSize];
+ while (pDataProvider->mEnable == true) {
+ ASSERT(open_index == pDataProvider->mOpenIndex);
+
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[0] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+
+ /* Get capture timestamp by start tiem */
+ pDataProvider->GetCaptureTimeStampByStartTime(&pDataProvider->mStreamAttributeSource.Time_Info);
+
+ ALOGV("%s(), EchoRef_mTotalEchoRefBufSize = unknown, read size = %d, newTimeStamp = %ld.%09ld",
+ __FUNCTION__, kReadBufferSize, pDataProvider->mStreamAttributeSource.Time_Info.timestamp_get.tv_sec, pDataProvider->mStreamAttributeSource.Time_Info.timestamp_get.tv_nsec);
+
+ /* Read data from internal ring buffer */
+ int retval = pDataProvider->readData(linear_buffer, kReadBufferSize);
+ if (retval != NO_ERROR) {
+ if (open_index != pDataProvider->mOpenIndex || pDataProvider->mEnable == false) {
+ ALOGD("%s(), DataProvider closed, exit thread. (index: %d -> %d, enable: %d)",
+ __FUNCTION__, open_index, pDataProvider->mOpenIndex, pDataProvider->mEnable);
+ break;
+ }
+
+ ALOGE("%s(), readData() error, retval = %d", __FUNCTION__, retval);
+ continue;
+ }
+
+ pDataProvider->mPcmReadBuf.pBufBase = linear_buffer;
+ pDataProvider->mPcmReadBuf.bufLen = kReadBufferSize + 1; // +1: avoid pRead == pWrite
+ pDataProvider->mPcmReadBuf.pRead = linear_buffer;
+ pDataProvider->mPcmReadBuf.pWrite = linear_buffer + kReadBufferSize;
+
+
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[1] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+
+ pDataProvider->provideEchoRefCaptureDataToAllClients(open_index);
+
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[2] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+ ALOGV("%s, latency_in_us,%1.6lf,%1.6lf,%1.6lf", __FUNCTION__, pDataProvider->timerec[0], pDataProvider->timerec[1], pDataProvider->timerec[2]);
+ }
+
+ ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ pthread_exit(NULL);
+ return NULL;
+}
+
+
+void AudioALSACaptureDataProviderEchoRefBTCVSD::initDataRingBuf(uint32_t size) {
+ ALOGD("+%s()", __FUNCTION__);
+
+ AL_LOCK_MS(mDataBufLock, MAX_LOCK_TIME_OUT_MS);
+
+ if (mDataRingBuf.pBufBase) {
+ delete[] mDataRingBuf.pBufBase;
+ }
+
+ mDataRingBuf.pBufBase = new char[size];
+ mDataRingBuf.bufLen = size;
+ mDataRingBuf.pRead = mDataRingBuf.pBufBase;
+ mDataRingBuf.pWrite = mDataRingBuf.pBufBase;
+
+ AL_UNLOCK(mDataBufLock);
+
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+void AudioALSACaptureDataProviderEchoRefBTCVSD::deinitDataRingBuf() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ AL_LOCK_MS(mDataBufLock, MAX_LOCK_TIME_OUT_MS);
+
+ if (mDataRingBuf.pBufBase) {
+ delete[] mDataRingBuf.pBufBase;
+ memset(&mDataRingBuf, 0, sizeof(mDataRingBuf));
+ }
+
+ AL_UNLOCK(mDataBufLock);
+
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+void AudioALSACaptureDataProviderEchoRefBTCVSD::resetTimeStampInfo() {
+ // Reset timestamp struct
+ mCaptureStartTime.tv_nsec = 0;
+ mCaptureStartTime.tv_sec = 0;
+
+ mEstimateTimeStamp.tv_nsec = 0;
+ mEstimateTimeStamp.tv_sec = 0;
+
+ // Reset total data read counter
+ mTotalCaptureBufSize = 0;
+}
+
+uint32_t AudioALSACaptureDataProviderEchoRefBTCVSD::compensateSilenceData(uint32_t msec, RingBuf *ringBuf) {
+ // DL data is not enough, compensate silence data
+ uint32_t compensateBytes = msec * mStreamAttributeSource.num_channels * audio_bytes_per_sample(mStreamAttributeSource.audio_format) * mStreamAttributeSource.sample_rate / 1000;
+ compensateBytes = compensateBytes - compensateBytes % (mStreamAttributeSource.num_channels * audio_bytes_per_sample(mStreamAttributeSource.audio_format));
+
+ int freeSpace = RingBuf_getFreeSpace(ringBuf);
+ if ((uint32_t)freeSpace >= compensateBytes) {
+ ALOGD("%s() msec = %d, compensateBytes = %d",
+ __FUNCTION__,
+ msec,
+ compensateBytes);
+
+ RingBuf_fillZero(ringBuf, compensateBytes);
+ } else {
+ ALOGE("%s(), buffer overflow! (msec = %d, %d < %d)", __FUNCTION__, msec, freeSpace, compensateBytes);
+ freeSpace = freeSpace - freeSpace % (mStreamAttributeSource.num_channels * audio_bytes_per_sample(mStreamAttributeSource.audio_format));
+ RingBuf_fillZero(ringBuf, freeSpace);
+ compensateBytes = freeSpace;
+ }
+
+ return compensateBytes;
+}
+
+// TODO(JH): change name to writeEchoRefData?
+status_t AudioALSACaptureDataProviderEchoRefBTCVSD::writeData(const char *data, uint32_t dataSize, struct timespec *timestamp) {
+ status_t ret = NO_ERROR;
+ ALOGV("+%s()", __FUNCTION__);
+
+ /* Push pcm data to echoref buffer */
+ AL_LOCK_MS(mDataBufLock, MAX_LOCK_TIME_OUT_MS);
+
+ if ((uint32_t)RingBuf_getFreeSpace(&mDataRingBuf) < dataSize) {
+ ASSERT(1);
+ ALOGE("%s(), data buffer overflow! (%d > %d)", __FUNCTION__, dataSize, RingBuf_getFreeSpace(&mDataRingBuf));
+ // TODO(JH): buffer overflow, resync?
+ ret = -ENOSYS;
+ } else {
+ /* Using new time stamp to update mCaptureStartTime if mCaptureStartTime not set */
+ updateStartTimeStamp(timestamp);
+
+ bool compensateData = false;
+ bool writeData = false;
+ int timeDiff = (int)round(calc_time_diff((*timestamp), mEstimateTimeStamp) * 1000);
+ uint32_t compensateBytes = 0;
+
+ if (timeDiff != 0 && (mEstimateTimeStamp.tv_sec != 0 || mEstimateTimeStamp.tv_nsec != 0)) {
+ if (timeDiff > 0) {
+ // Data is not enough, compensate it.
+ compensateData = true;
+ writeData = true;
+ } else {
+ // DL data is out of date, ignore this data
+ compensateData = false;
+ writeData = false;
+ }
+ } else {
+ // Normal case, just wrie data, no compensation
+ compensateData = false;
+ writeData = true;
+ }
+
+ SHOW_TIMESTAMP("%s() timeDiff = %d (%ld.%09ld->%ld.%09ld), compensateData = %d, writeData = %d",
+ __FUNCTION__,
+ timeDiff,
+ mEstimateTimeStamp.tv_sec, mEstimateTimeStamp.tv_nsec,
+ timestamp->tv_sec, timestamp->tv_nsec,
+ compensateData,
+ writeData);
+
+ if (compensateData) {
+ /* If this buffer's time stamp is not expected, compensate it. (my caused by DL open/close) */
+ compensateBytes = compensateSilenceData((uint32_t)timeDiff, &mDataRingBuf);
+ }
+
+ if (writeData) {
+ if (((uint32_t)RingBuf_getFreeSpace(&mDataRingBuf) >= dataSize)) {
+ /* Write new data */
+ RingBuf_copyFromLinear(&mDataRingBuf, (const char *)data, dataSize);
+ dataSize += compensateBytes;
+ } else {
+ dataSize = compensateBytes;
+ }
+ /* Calculate mEstimateTimeStamp */
+ calculateTimeStampByBytes(*timestamp, dataSize, mStreamAttributeSource, &mEstimateTimeStamp);
+
+ SHOW_TIMESTAMP("%s() update mEstimateTimeStamp (%ld.%09ld->%ld.%09ld)",
+ __FUNCTION__,
+ timestamp->tv_sec, timestamp->tv_nsec,
+ mEstimateTimeStamp.tv_sec, mEstimateTimeStamp.tv_nsec);
+ }
+ SHOW_TIMESTAMP("%s(), write data size = %d (free = %d), signal...", __FUNCTION__, dataSize, RingBuf_getFreeSpace(&mDataRingBuf));
+
+ /* Notify provider thread */
+ AL_SIGNAL(mDataBufLock);
+ }
+
+ AL_UNLOCK(mDataBufLock);
+
+ ALOGV("-%s()", __FUNCTION__);
+
+ return ret;
+}
+
+status_t AudioALSACaptureDataProviderEchoRefBTCVSD::readData(char *buffer, uint32_t size) {
+ ALOGV("+%s()", __FUNCTION__);
+
+ AL_LOCK_MS(mDataBufLock, MAX_LOCK_TIME_OUT_MS);
+
+ while ((uint32_t)RingBuf_getDataCount(&mDataRingBuf) < size) {
+ SHOW_TIMESTAMP("%s(), echoref data is not enough, waiting... (data size = %d, read size = %d)", __FUNCTION__, RingBuf_getDataCount(&mDataRingBuf), size);
+ if (AL_WAIT_MS(mDataBufLock, MAX_READ_DATA_TIME_OUT_MS) != 0) {
+ SHOW_TIMESTAMP("-%s(), wait timeout! (data size = %d, read size = %d)", __FUNCTION__, RingBuf_getDataCount(&mDataRingBuf), size);
+ AL_UNLOCK(mDataBufLock);
+ return -ETIMEDOUT;
+ }
+
+ SHOW_TIMESTAMP("-%s(), echoref data is comming, wake up... (data size = %d, read size = %d)", __FUNCTION__, RingBuf_getDataCount(&mDataRingBuf), size);
+
+ if (mEnable == false) {
+ SHOW_TIMESTAMP("-%s(), closed, exit readData()", __FUNCTION__);
+ AL_UNLOCK(mDataBufLock);
+ return -ENOSYS;
+ }
+ }
+
+ /* Read data from DataRingBuf */
+ uint32_t srcDataSize = RingBuf_getDataCount(&mDataRingBuf);
+ uint32_t copyBufSize = size > srcDataSize ? srcDataSize : size;
+ RingBuf_copyToLinear(buffer, &mDataRingBuf, copyBufSize);
+ SHOW_TIMESTAMP("%s(), read data size = %d (dstFreeSize = %d, srcDataSize = %d)", __FUNCTION__, copyBufSize, size, srcDataSize);
+
+ updateTotalCaptureBufSize(copyBufSize);
+
+ AL_UNLOCK(mDataBufLock);
+
+ ALOGV("-%s()", __FUNCTION__);
+
+ return NO_ERROR;
+}
+
+void AudioALSACaptureDataProviderEchoRefBTCVSD::signalDataWaiting() {
+ ALOGV("+%s()", __FUNCTION__);
+ AL_LOCK_MS(mDataBufLock, MAX_LOCK_TIME_OUT_MS);
+ AL_SIGNAL(mDataBufLock);
+ AL_UNLOCK(mDataBufLock);
+ ALOGV("-%s()", __FUNCTION__);
+}
+
+void AudioALSACaptureDataProviderEchoRefBTCVSD::updateTotalCaptureBufSize(uint32_t captureSize) {
+ mTotalCaptureBufSize += captureSize;
+}
+
+void AudioALSACaptureDataProviderEchoRefBTCVSD::updateStartTimeStamp(struct timespec *timeStamp) {
+ if (mCaptureStartTime.tv_sec == 0 && mCaptureStartTime.tv_nsec == 0) {
+ if (timeStamp) {
+ mCaptureStartTime = *timeStamp;
+ } else {
+ clock_gettime(CLOCK_REALTIME, &mCaptureStartTime); // Use CLOCK_REALTIME to align kernel timestamp format
+ }
+ ALOGD("%s(), update DataProvider(%d) start timestamp (%ld.%09ld), mTotalCaptureBufSize = %d", __FUNCTION__, mCaptureDataProviderType, mCaptureStartTime.tv_sec, mCaptureStartTime.tv_nsec, mTotalCaptureBufSize);
+ } else {
+ ALOGV("%s(), DataProvider(%d) start timestamp (%ld.%09ld), mTotalCaptureBufSize = %d", __FUNCTION__, mCaptureDataProviderType, mCaptureStartTime.tv_sec, mCaptureStartTime.tv_nsec, mTotalCaptureBufSize);
+ }
+}
+
+status_t AudioALSACaptureDataProviderEchoRefBTCVSD::GetCaptureTimeStampByStartTime(time_info_struct_t *timeInfo) {
+ timeInfo->buffer_per_time = 0;
+ timeInfo->kernelbuffer_ns = 0;
+ timeInfo->frameInfo_get = 0;
+ calculateTimeStampByBytes(mCaptureStartTime, mTotalCaptureBufSize, mStreamAttributeSource, &timeInfo->timestamp_get);
+
+ return NO_ERROR;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderEchoRefBTSCO.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderEchoRefBTSCO.cpp
new file mode 100644
index 0000000..82012f3
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderEchoRefBTSCO.cpp
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureDataProviderEchoRefBTSCO.h"
+
+#include <pthread.h>
+
+#include <sys/prctl.h>
+
+#include "AudioALSADriverUtility.h"
+#include "AudioType.h"
+#include "WCNChipController.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderEchoRefBTSCO"
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+//static const uint32_t kReadBufferSize = 0x1B90; // 44.1K\stereo\40ms data (framebase: get 40ms data/per time), downlink sample rate(DL1)
+static const uint32_t kReadBufferSize = 0x500; // 16K\stereo\20 ms data
+
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataProviderEchoRefBTSCO *AudioALSACaptureDataProviderEchoRefBTSCO::mAudioALSACaptureDataProviderEchoRefBTSCO = NULL;
+AudioALSACaptureDataProviderEchoRefBTSCO *AudioALSACaptureDataProviderEchoRefBTSCO::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACaptureDataProviderEchoRefBTSCO == NULL) {
+ mAudioALSACaptureDataProviderEchoRefBTSCO = new AudioALSACaptureDataProviderEchoRefBTSCO();
+ }
+ ASSERT(mAudioALSACaptureDataProviderEchoRefBTSCO != NULL);
+ return mAudioALSACaptureDataProviderEchoRefBTSCO;
+}
+
+AudioALSACaptureDataProviderEchoRefBTSCO::AudioALSACaptureDataProviderEchoRefBTSCO() :
+ mWCNChipController(WCNChipController::GetInstance()),
+ hReadThread(0) {
+ ALOGD("%s()", __FUNCTION__);
+
+ mCaptureDataProviderType = CAPTURE_PROVIDER_ECHOREF_BTSCO;
+ memset(&mNewtime, 0, sizeof(mNewtime));
+ memset(&mOldtime, 0, sizeof(mOldtime));
+}
+
+AudioALSACaptureDataProviderEchoRefBTSCO::~AudioALSACaptureDataProviderEchoRefBTSCO() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureDataProviderEchoRefBTSCO::open() {
+ ALOGD("%s()", __FUNCTION__);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ASSERT(mEnable == false);
+
+ // config attribute (will used in client SRC/Enh/... later) // TODO(Sam): query the mConfig?
+ mStreamAttributeSource.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ mStreamAttributeSource.num_channels = popcount(mStreamAttributeSource.audio_channel_mask);
+ mStreamAttributeSource.sample_rate = mWCNChipController->GetBTCurrentSamplingRateNumber();
+
+ // Reset frames readed counter
+ mStreamAttributeSource.Time_Info.total_frames_readed = 0;
+
+
+ mConfig.channels = mStreamAttributeSource.num_channels;
+ mConfig.rate = mStreamAttributeSource.sample_rate;
+
+ // Buffer size: 2048(period_size) * 2(ch) * 2(byte) * 8(period_count) = 64 kb
+ mConfig.period_size = 2048;
+ mConfig.period_count = 8;
+ mConfig.format = PCM_FORMAT_S16_LE;
+
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+
+
+#if 0
+ //latency time, set as DataProvider buffer size
+ mStreamAttributeSource.latency = (kReadBufferSize * 1000) / (mStreamAttributeSource.num_channels * mStreamAttributeSource.sample_rate *
+ (mStreamAttributeSource.audio_format == AUDIO_FORMAT_PCM_8_BIT ? 1 : //8 1byte/frame
+ (mStreamAttributeSource.audio_format == AUDIO_FORMAT_PCM_32_BIT ? 4 : //24bit 3bytes/frame
+ 2))); //default 2bytes/sample
+#else
+ //latency time, set as hardware buffer size
+ mStreamAttributeSource.latency = (mConfig.period_size * mConfig.period_count * 1000) / mConfig.rate;
+#endif
+
+ ALOGD("%s(), audio_format = %d, audio_channel_mask=%x, num_channels=%d, sample_rate=%d, latency=%dms", __FUNCTION__,
+ mStreamAttributeSource.audio_format, mStreamAttributeSource.audio_channel_mask, mStreamAttributeSource.num_channels, mStreamAttributeSource.sample_rate, mStreamAttributeSource.latency);
+
+ ALOGD("%s(), format = %d, channels=%d, rate=%d", __FUNCTION__,
+ mConfig.format, mConfig.channels, mConfig.rate);
+
+ OpenPCMDump(LOG_TAG);
+
+ // enable pcm
+ ASSERT(mPcm == NULL);
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmDl1AwbCapture);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmDl1AwbCapture);
+ mPcm = pcm_open(cardIdx, pcmIdx, PCM_IN | PCM_MONOTONIC, &mConfig);
+ ASSERT(mPcm != NULL && pcm_is_ready(mPcm) == true);
+
+ mStart = false;
+ mReadThreadReady = false;
+
+ // create reading thread
+ mEnable = true;
+ int ret = pthread_create(&hReadThread, NULL, AudioALSACaptureDataProviderEchoRefBTSCO::readThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureDataProviderEchoRefBTSCO::close() {
+ ALOGD("%s()", __FUNCTION__);
+
+ mEnable = false;
+ pthread_join(hReadThread, NULL);
+ ALOGD("pthread_join hReadThread done");
+
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ClosePCMDump();
+
+ pcm_stop(mPcm);
+ pcm_close(mPcm);
+ mPcm = NULL;
+
+ return NO_ERROR;
+}
+
+void *AudioALSACaptureDataProviderEchoRefBTSCO::readThread(void *arg) {
+ status_t retval = NO_ERROR;
+ AudioALSACaptureDataProviderEchoRefBTSCO *pDataProvider = static_cast<AudioALSACaptureDataProviderEchoRefBTSCO *>(arg);
+
+ uint32_t open_index = pDataProvider->mOpenIndex;
+
+ char nameset[32];
+ sprintf(nameset, "%s%d", __FUNCTION__, pDataProvider->mCaptureDataProviderType);
+ prctl(PR_SET_NAME, (unsigned long)nameset, 0, 0, 0);
+ pDataProvider->setThreadPriority();
+
+
+ ALOGD("+%s(), pid: %d, tid: %d, kReadBufferSize=%x", __FUNCTION__, getpid(), gettid(), kReadBufferSize);
+
+ pDataProvider->waitPcmStart();
+
+ // read raw data from alsa driver
+ char linear_buffer[kReadBufferSize];
+ while (pDataProvider->mEnable == true) {
+ if (open_index != pDataProvider->mOpenIndex) {
+ ALOGD("%s(), open_index(%d) != mOpenIndex(%d), return", __FUNCTION__, open_index, pDataProvider->mOpenIndex);
+ break;
+ }
+
+ ASSERT(pDataProvider->mPcm != NULL);
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[0] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+
+ int retval = pcm_read(pDataProvider->mPcm, linear_buffer, kReadBufferSize);
+ if (retval != 0) {
+ ALOGE("%s(), pcm_read() error, retval = %d", __FUNCTION__, retval);
+ }
+
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[1] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+
+ pDataProvider->GetCaptureTimeStamp(&pDataProvider->mStreamAttributeSource.Time_Info, kReadBufferSize);
+
+ // use ringbuf format to save buffer info
+ pDataProvider->mPcmReadBuf.pBufBase = linear_buffer;
+ pDataProvider->mPcmReadBuf.bufLen = kReadBufferSize + 1; // +1: avoid pRead == pWrite
+ pDataProvider->mPcmReadBuf.pRead = linear_buffer;
+ pDataProvider->mPcmReadBuf.pWrite = linear_buffer + kReadBufferSize;
+
+ //Provide EchoRef data
+#if 0
+ pDataProvider->provideCaptureDataToAllClients(open_index);
+#else
+ pDataProvider->provideEchoRefCaptureDataToAllClients(open_index);
+#endif
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[2] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+ ALOGD("%s, latency_in_us,%1.6lf,%1.6lf,%1.6lf", __FUNCTION__, pDataProvider->timerec[0], pDataProvider->timerec[1], pDataProvider->timerec[2]);
+ }
+
+ ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ pthread_exit(NULL);
+ return NULL;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderEchoRefExt.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderEchoRefExt.cpp
new file mode 100644
index 0000000..6cdf215
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderEchoRefExt.cpp
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureDataProviderEchoRefExt.h"
+
+#include <pthread.h>
+
+#include <sys/prctl.h>
+
+#include "AudioType.h"
+#include "AudioALSADriverUtility.h"
+#include "AudioALSASampleRateController.h"
+#include "AudioALSAStreamManager.h"
+#if defined(MTK_AUDIO_KS)
+#include "AudioALSADeviceConfigManager.h"
+#endif
+
+#include "AudioSmartPaController.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderEchoRefExt"
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+
+namespace android {
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+static uint32_t kReadBufferSize = 0;
+
+static bool btempDebug = false;
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataProviderEchoRefExt *AudioALSACaptureDataProviderEchoRefExt::mAudioALSACaptureDataProviderEchoRefExt = NULL;
+AudioALSACaptureDataProviderEchoRefExt *AudioALSACaptureDataProviderEchoRefExt::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACaptureDataProviderEchoRefExt == NULL) {
+ mAudioALSACaptureDataProviderEchoRefExt = new AudioALSACaptureDataProviderEchoRefExt();
+ }
+ ASSERT(mAudioALSACaptureDataProviderEchoRefExt != NULL);
+ return mAudioALSACaptureDataProviderEchoRefExt;
+}
+
+AudioALSACaptureDataProviderEchoRefExt::AudioALSACaptureDataProviderEchoRefExt():
+ mMixer(AudioALSADriverUtility::getInstance()->getMixer()),
+ mSmartPaController(AudioSmartPaController::getInstance()),
+ hReadThread(0) {
+ ALOGD("%s()", __FUNCTION__);
+
+ mCaptureDataProviderType = CAPTURE_PROVIDER_ECHOREF_EXT;
+ memset(&mNewtime, 0, sizeof(mNewtime));
+ memset(&mOldtime, 0, sizeof(mOldtime));
+}
+
+AudioALSACaptureDataProviderEchoRefExt::~AudioALSACaptureDataProviderEchoRefExt() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureDataProviderEchoRefExt::open() {
+ ALOGD("%s()", __FUNCTION__);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ASSERT(mEnable == false);
+
+ AudioALSASampleRateController *pAudioALSASampleRateController = AudioALSASampleRateController::getInstance();
+ pAudioALSASampleRateController->setScenarioStatus(PLAYBACK_SCENARIO_ECHO_REF_EXT);
+
+ // config attribute (will used in client SRC/Enh/... later) // TODO(Sam): query the mConfig?
+ mStreamAttributeSource.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ mStreamAttributeSource.num_channels = popcount(mStreamAttributeSource.audio_channel_mask);
+ mStreamAttributeSource.sample_rate = AudioALSASampleRateController::getInstance()->getPrimaryStreamOutSampleRate();
+
+ // Reset frames readed counter
+ mStreamAttributeSource.Time_Info.total_frames_readed = 0;
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ mlatency = UPLINK_NORMAL_LATENCY_MS;
+
+#ifdef UPLINK_LOW_LATENCY
+ if (HasLowLatencyCapture()) { mlatency = UPLINK_LOW_LATENCY_MS; }
+#endif
+#else
+ mlatency = UPLINK_LOW_LATENCY_MS;
+
+#ifdef UPLINK_LOW_LATENCY
+ if (HasLowLatencyCapture()) { mlatency /= 2; }
+#endif
+#endif
+
+ mConfig.rate = mStreamAttributeSource.sample_rate;
+ mConfig.channels = mStreamAttributeSource.num_channels;
+ if(!AudioSmartPaController::getInstance()->isInCalibration()) {
+ mConfig.format = PCM_FORMAT_S16_LE;
+ } else {
+ mConfig.format = PCM_FORMAT_S24_LE;
+ }
+ kReadBufferSize = getPeriodBufSize(&mStreamAttributeSource, mlatency);
+#if 0 // cause latency issue...... = =a
+ kReadBufferSize &= 0xFFFFFFC0; // (DL1)44.1K\20ms data\stereo\2byte\(Align64byte)
+#endif
+ mConfig.period_size = kReadBufferSize / mConfig.channels / (pcm_format_to_bits(mConfig.format) / 8);
+ mConfig.period_count = 160 / mlatency;
+
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+
+
+#if 0
+ //latency time, set as DataProvider buffer size
+ mStreamAttributeSource.latency = (kReadBufferSize * 1000) / (mStreamAttributeSource.num_channels * mStreamAttributeSource.sample_rate *
+ (mStreamAttributeSource.audio_format == AUDIO_FORMAT_PCM_8_BIT ? 1 : //8 1byte/frame
+ (mStreamAttributeSource.audio_format == AUDIO_FORMAT_PCM_32_BIT ? 4 : //24bit 3bytes/frame
+ 2))); //default 2bytes/sample
+#else
+ //latency time, set as hardware buffer size
+ mStreamAttributeSource.latency = (mConfig.period_size * mConfig.period_count * 1000) / mConfig.rate;
+#endif
+
+ ALOGD("%s(), audio_format = %d, audio_channel_mask=%x, num_channels=%d, sample_rate=%d, buf_total_latency=%dms", __FUNCTION__,
+ mStreamAttributeSource.audio_format, mStreamAttributeSource.audio_channel_mask, mStreamAttributeSource.num_channels, mStreamAttributeSource.sample_rate, mStreamAttributeSource.latency);
+
+ ALOGD("%s(), format = %d, channels=%d, rate=%d, period_size=%d, period_count=%d,latency=%d,kReadBufferSize=%d", __FUNCTION__,
+ mConfig.format, mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mlatency, kReadBufferSize);
+
+ if(!AudioSmartPaController::getInstance()->isInCalibration()) {
+ OpenPCMDump(LOG_TAG);
+ } else {
+ OpenPCMDump("AudioALSACaptureDataProvider_ivdump");
+ }
+
+ btempDebug = AudioSpeechEnhanceInfo::getInstance()->GetDebugStatus();
+
+#if defined(MTK_AUDIO_KS)
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmCapture2);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmCapture2);
+ if (AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ int i2sIn = mSmartPaController->getI2sInSelect();
+ mSmartPaController->setI2sHD(true, i2sIn);
+
+ mApTurnOnSequence = i2sIn == AUDIO_I2S0 ?
+ AUDIO_CTL_I2S0_TO_CAPTURE2 : AUDIO_CTL_I2S2_TO_CAPTURE2;
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+ }
+
+ // need to set after query pcm_params_get, since shutdown will clear this state
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "echo_ref_xrun_assert"), 0, 1)) {
+ ALOGW("%s(), echo_ref_xrun_assert enable fail", __FUNCTION__);
+ }
+#else
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmI2SAwbCapture);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmI2SAwbCapture);
+#endif
+
+ // enable pcm
+ ASSERT(mPcm == NULL);
+ mPcm = pcm_open(cardIdx, pcmIdx, PCM_IN | PCM_MONOTONIC, &mConfig);
+ ASSERT(mPcm != NULL && pcm_is_ready(mPcm) == true);
+
+ mStart = false;
+ mReadThreadReady = false;
+
+ // create reading thread
+ mEnable = true;
+ int ret = pthread_create(&hReadThread, NULL, AudioALSACaptureDataProviderEchoRefExt::readThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureDataProviderEchoRefExt::close() {
+ ALOGD("%s()", __FUNCTION__);
+
+#if defined(MTK_AUDIO_KS)
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "echo_ref_xrun_assert"), 0, 0)) {
+ ALOGW("%s(), echo_ref_xrun_assert disable fail", __FUNCTION__);
+ }
+#endif
+
+ mEnable = false;
+ pthread_join(hReadThread, NULL);
+ ALOGD("pthread_join hReadThread done");
+
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ClosePCMDump();
+
+ pcm_stop(mPcm);
+ pcm_close(mPcm);
+ mPcm = NULL;
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+ if (AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ mSmartPaController->setI2sHD(false, mSmartPaController->getI2sInSelect());
+ }
+#endif
+
+ AudioALSASampleRateController *pAudioALSASampleRateController = AudioALSASampleRateController::getInstance();
+ pAudioALSASampleRateController->resetScenarioStatus(PLAYBACK_SCENARIO_ECHO_REF_EXT);
+
+ return NO_ERROR;
+}
+
+void *AudioALSACaptureDataProviderEchoRefExt::readThread(void *arg) {
+ status_t ret = NO_ERROR;
+ int retval = 0;
+
+ AudioALSACaptureDataProviderEchoRefExt *pDataProvider = static_cast<AudioALSACaptureDataProviderEchoRefExt *>(arg);
+
+ uint32_t open_index = pDataProvider->mOpenIndex;
+
+ char nameset[32];
+ sprintf(nameset, "%s%d", __FUNCTION__, pDataProvider->mCaptureDataProviderType);
+ prctl(PR_SET_NAME, (unsigned long)nameset, 0, 0, 0);
+ pDataProvider->setThreadPriority();
+
+
+ ALOGD("+%s(), pid: %d, tid: %d, kReadBufferSize=%x", __FUNCTION__, getpid(), gettid(), kReadBufferSize);
+
+ pDataProvider->waitPcmStart();
+
+ // read raw data from alsa driver
+ char linear_buffer[kReadBufferSize];
+ while (pDataProvider->mEnable == true) {
+ ASSERT(open_index == pDataProvider->mOpenIndex);
+ ASSERT(pDataProvider->mPcm != NULL);
+
+ if (btempDebug) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[0] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+ }
+
+ retval = pcm_read(pDataProvider->mPcm, linear_buffer, kReadBufferSize);
+ if (retval != 0) {
+ ALOGE("%s(), pcm_read() error, retval = %d", __FUNCTION__, retval);
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mOldtime);
+ continue;
+ }
+
+ //struct timespec tempTimeStamp;
+ ret = pDataProvider->GetCaptureTimeStamp(&pDataProvider->mStreamAttributeSource.Time_Info, kReadBufferSize);
+#if 0
+ if (ret != NO_ERROR) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mOldtime);
+ continue;
+ }
+#endif
+
+ if (btempDebug) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[1] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+ }
+
+ // use ringbuf format to save buffer info
+ pDataProvider->mPcmReadBuf.pBufBase = linear_buffer;
+ pDataProvider->mPcmReadBuf.bufLen = kReadBufferSize + 1; // +1: avoid pRead == pWrite
+ pDataProvider->mPcmReadBuf.pRead = linear_buffer;
+ pDataProvider->mPcmReadBuf.pWrite = linear_buffer + kReadBufferSize;
+
+ //Provide EchoRef data
+#if 0 //for check the echoref data got
+ pDataProvider->provideCaptureDataToAllClients(open_index);
+#else
+ if(!AudioSmartPaController::getInstance()->isInCalibration()) {
+ pDataProvider->provideEchoRefCaptureDataToAllClients(open_index);
+ } else {
+ pDataProvider->provideCaptureDataToAllClients(open_index);
+ }
+#endif
+
+ if (btempDebug) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[2] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+
+ ALOGD("%s, latency_in_us,%1.6lf,%1.6lf,%1.6lf", __FUNCTION__, pDataProvider->timerec[0], pDataProvider->timerec[1], pDataProvider->timerec[2]);
+ }
+ }
+
+ ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ pthread_exit(NULL);
+ return NULL;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderEchoRefUsb.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderEchoRefUsb.cpp
new file mode 100644
index 0000000..4faeb5e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderEchoRefUsb.cpp
@@ -0,0 +1,430 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureDataProviderEchoRefUsb.h"
+
+#include <pthread.h>
+
+//#include <linux/rtpm_prio.h>
+#include <sys/prctl.h>
+
+#include "AudioALSADriverUtility.h"
+#include "AudioALSAPlaybackHandlerUsb.h"
+#include "AudioType.h"
+#include "AudioALSASampleRateController.h"
+#include <math.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACaptureDataProviderEchoRefUsb"
+//#define DEBUG_TIMESTAMP
+#ifdef DEBUG_TIMESTAMP
+#define SHOW_TIMESTAMP(format, args...) ALOGD(format, ##args)
+#else
+#define SHOW_TIMESTAMP(format, args...)
+#endif
+
+#define MAX_LOCK_TIME_OUT_MS (500)
+#define MAX_READ_DATA_TIME_OUT_MS (60)
+
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+static uint32_t kReadBufferSize = 0;
+
+//static const uint32_t kEchoRefBufferSize = kReadBufferSize * 10;
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataProviderEchoRefUsb *AudioALSACaptureDataProviderEchoRefUsb::mAudioALSACaptureDataProviderEchoRefUsb = NULL;
+AudioALSACaptureDataProviderEchoRefUsb *AudioALSACaptureDataProviderEchoRefUsb::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACaptureDataProviderEchoRefUsb == NULL) {
+ mAudioALSACaptureDataProviderEchoRefUsb = new AudioALSACaptureDataProviderEchoRefUsb();
+ }
+ ASSERT(mAudioALSACaptureDataProviderEchoRefUsb != NULL);
+ return mAudioALSACaptureDataProviderEchoRefUsb;
+}
+
+AudioALSACaptureDataProviderEchoRefUsb::AudioALSACaptureDataProviderEchoRefUsb():
+ mTotalCaptureBufSize(0),
+ hReadThread(0) {
+ ALOGD("%s()", __FUNCTION__);
+ mCaptureDataProviderType = CAPTURE_PROVIDER_ECHOREF_USB;
+ mPlaybackHandlerUsb = NULL;
+ mlatency = 15;
+ memset((void *)&mCaptureStartTime, 0, sizeof(mCaptureStartTime));
+
+ memset((void *)&mEstimateTimeStamp, 0, sizeof(mEstimateTimeStamp));
+
+ memset((void *)&mNewtime, 0, sizeof(mNewtime));
+
+ memset((void *)&mOldtime, 0, sizeof(mOldtime));
+
+ memset((void *)&mDataRingBuf, 0, sizeof(mDataRingBuf));
+}
+
+AudioALSACaptureDataProviderEchoRefUsb::~AudioALSACaptureDataProviderEchoRefUsb() {
+ ALOGD("%s()", __FUNCTION__);
+
+ deinitDataRingBuf();
+}
+
+
+status_t AudioALSACaptureDataProviderEchoRefUsb::open() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ ASSERT(mEnable == false);
+ AudioALSASampleRateController *pAudioALSASampleRateController = AudioALSASampleRateController::getInstance();
+ pAudioALSASampleRateController->setScenarioStatus(PLAYBACK_SCENARIO_ECHO_REF);
+
+ uint32_t frameBytes = mStreamAttributeSource.num_channels * audio_bytes_per_sample(mStreamAttributeSource.audio_format);
+ kReadBufferSize = (mStreamAttributeSource.sample_rate * mStreamAttributeSource.latency / 1000) * frameBytes;
+
+ /* Reset buffer & timestamp info */
+ initDataRingBuf(kReadBufferSize * 10);
+ resetTimeStampInfo();
+
+ ALOGD("%s(), audio_format = %d, audio_channel_mask=%x, num_channels=%d, sample_rate=%d, latency=%dms", __FUNCTION__,
+ mStreamAttributeSource.audio_format, mStreamAttributeSource.audio_channel_mask, mStreamAttributeSource.num_channels, mStreamAttributeSource.sample_rate, mStreamAttributeSource.latency);
+
+ OpenPCMDump(LOG_TAG);
+
+ // create reading thread
+ mEnable = true;
+ int ret = pthread_create(&hReadThread, NULL, AudioALSACaptureDataProviderEchoRefUsb::readThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ ALOGD("-%s()", __FUNCTION__);
+
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureDataProviderEchoRefUsb::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ if (mEnable == true) {
+ mEnable = false;
+ pthread_join(hReadThread, NULL);
+
+ /* Signal the echo ref data waiting to avoid deadlock */
+ signalDataWaiting();
+ ClosePCMDump();
+ AudioALSASampleRateController *pAudioALSASampleRateController = AudioALSASampleRateController::getInstance();
+ pAudioALSASampleRateController->resetScenarioStatus(PLAYBACK_SCENARIO_ECHO_REF);
+
+ deinitDataRingBuf();
+ }
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+void AudioALSACaptureDataProviderEchoRefUsb::initEchoRefInfo(stream_attribute_t stream_attribute_source_usb) {
+ ALOGD("%s()", __FUNCTION__);
+ mStreamAttributeSource = stream_attribute_source_usb;
+ mStreamAttributeSource.latency = 16;
+ mStreamAttributeSource.Time_Info.total_frames_readed = 0;
+}
+
+void *AudioALSACaptureDataProviderEchoRefUsb::readThread(void *arg) {
+ pthread_detach(pthread_self());
+
+ status_t retval = NO_ERROR;
+ AudioALSACaptureDataProviderEchoRefUsb *pDataProvider = static_cast<AudioALSACaptureDataProviderEchoRefUsb *>(arg);
+
+ uint32_t open_index = pDataProvider->mOpenIndex;
+
+ char nameset[32];
+ sprintf(nameset, "%s%d", __FUNCTION__, pDataProvider->mCaptureDataProviderType);
+ prctl(PR_SET_NAME, (unsigned long)nameset, 0, 0, 0);
+ pDataProvider->setThreadPriority();
+
+ ALOGD("+%s(), pid: %d, tid: %d, kReadBufferSize=%x", __FUNCTION__, getpid(), gettid(), kReadBufferSize);
+
+
+ // read raw data from alsa driver
+ char linear_buffer[kReadBufferSize];
+ while (pDataProvider->mEnable == true) {
+ if (open_index != pDataProvider->mOpenIndex) {
+ ALOGD("%s(), open_index(%d) != mOpenIndex(%d), return", __FUNCTION__, open_index, pDataProvider->mOpenIndex);
+ break;
+ }
+
+
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[0] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+
+ /* Get capture timestamp by start tiem */
+ pDataProvider->GetCaptureTimeStampByStartTime(&pDataProvider->mStreamAttributeSource.Time_Info);
+
+ ALOGV("%s(), EchoRef_mTotalEchoRefBufSize = unknown, read size = %d, newTimeStamp = %ld.%09ld",
+ __FUNCTION__, kReadBufferSize, pDataProvider->mStreamAttributeSource.Time_Info.timestamp_get.tv_sec, pDataProvider->mStreamAttributeSource.Time_Info.timestamp_get.tv_nsec);
+
+ /* Read data from internal ring buffer */
+ int retval = pDataProvider->readData(linear_buffer, kReadBufferSize);
+ if (retval != NO_ERROR) {
+ ALOGD("%s(), readData() error, retval = %d", __FUNCTION__, retval);
+ continue;
+ }
+
+ pDataProvider->mPcmReadBuf.pBufBase = linear_buffer;
+ pDataProvider->mPcmReadBuf.bufLen = kReadBufferSize + 1; // +1: avoid pRead == pWrite
+ pDataProvider->mPcmReadBuf.pRead = linear_buffer;
+ pDataProvider->mPcmReadBuf.pWrite = linear_buffer + kReadBufferSize;
+
+
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[1] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+
+ pDataProvider->provideEchoRefCaptureDataToAllClients(open_index);
+
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[2] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+ ALOGD("%s, latency_in_us,%1.6lf,%1.6lf,%1.6lf", __FUNCTION__, pDataProvider->timerec[0], pDataProvider->timerec[1], pDataProvider->timerec[2]);
+ }
+
+ ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ pthread_exit(NULL);
+ return NULL;
+}
+
+
+void AudioALSACaptureDataProviderEchoRefUsb::initDataRingBuf(uint32_t size) {
+ ALOGD("+%s()", __FUNCTION__);
+
+ AL_LOCK_MS(mDataBufLock, MAX_LOCK_TIME_OUT_MS);
+
+ if (mDataRingBuf.pBufBase) {
+ delete[] mDataRingBuf.pBufBase;
+ }
+
+ mDataRingBuf.pBufBase = new char[size];
+ mDataRingBuf.bufLen = size;
+ mDataRingBuf.pRead = mDataRingBuf.pBufBase;
+ mDataRingBuf.pWrite = mDataRingBuf.pBufBase;
+
+ AL_UNLOCK(mDataBufLock);
+
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+void AudioALSACaptureDataProviderEchoRefUsb::deinitDataRingBuf() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ AL_LOCK_MS(mDataBufLock, MAX_LOCK_TIME_OUT_MS);
+
+ if (mDataRingBuf.pBufBase) {
+ delete[] mDataRingBuf.pBufBase;
+ memset(&mDataRingBuf, 0, sizeof(mDataRingBuf));
+ }
+
+ AL_UNLOCK(mDataBufLock);
+
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+void AudioALSACaptureDataProviderEchoRefUsb::resetTimeStampInfo() {
+ // Reset timestamp struct
+ mCaptureStartTime.tv_nsec = 0;
+ mCaptureStartTime.tv_sec = 0;
+
+ mEstimateTimeStamp.tv_nsec = 0;
+ mEstimateTimeStamp.tv_sec = 0;
+
+ // Reset total data read counter
+ mTotalCaptureBufSize = 0;
+}
+
+uint32_t AudioALSACaptureDataProviderEchoRefUsb::compensateSilenceData(uint32_t msec, RingBuf *ringBuf) {
+ // DL data is not enough, compensate silence data
+ uint32_t compensateBytes = msec * mStreamAttributeSource.num_channels * audio_bytes_per_sample(mStreamAttributeSource.audio_format) * mStreamAttributeSource.sample_rate / 1000;
+ compensateBytes = compensateBytes - compensateBytes % (mStreamAttributeSource.num_channels * audio_bytes_per_sample(mStreamAttributeSource.audio_format));
+
+ int freeSpace = RingBuf_getFreeSpace(ringBuf);
+ if ((uint32_t)freeSpace >= compensateBytes) {
+ ALOGD("%s() msec = %d, compensateBytes = %d",
+ __FUNCTION__,
+ msec,
+ compensateBytes);
+
+ RingBuf_fillZero(ringBuf, compensateBytes);
+ } else {
+ ALOGE("%s(), buffer overflow! (msec = %d, %d < %d)", __FUNCTION__, msec, freeSpace, compensateBytes);
+ freeSpace = freeSpace - freeSpace % (mStreamAttributeSource.num_channels * audio_bytes_per_sample(mStreamAttributeSource.audio_format));
+ RingBuf_fillZero(ringBuf, freeSpace);
+ compensateBytes = freeSpace;
+ }
+
+ return compensateBytes;
+}
+
+// TODO(JH): change name to writeEchoRefData?
+status_t AudioALSACaptureDataProviderEchoRefUsb::writeData(const char *data, uint32_t dataSize, struct timespec *timestamp) {
+ status_t ret = NO_ERROR;
+ ALOGV("+%s()", __FUNCTION__);
+
+ /* Push pcm data to echoref buffer */
+ AL_LOCK_MS(mDataBufLock, MAX_LOCK_TIME_OUT_MS);
+
+ if ((uint32_t)RingBuf_getFreeSpace(&mDataRingBuf) < dataSize) {
+ ASSERT(1);
+ ALOGE("%s(), data buffer overflow! (%d > %d)", __FUNCTION__, dataSize, RingBuf_getFreeSpace(&mDataRingBuf));
+ // TODO(JH): buffer overflow, resync?
+ ret = -ENOSYS;
+ } else {
+ /* Using new time stamp to update mCaptureStartTime if mCaptureStartTime not set */
+ updateStartTimeStamp(timestamp);
+
+ bool compensateData = false;
+ bool writeData = false;
+ int timeDiff = (int)round(calc_time_diff((*timestamp), mEstimateTimeStamp) * 1000);
+ uint32_t compensateBytes = 0;
+
+ if (timeDiff != 0 && (mEstimateTimeStamp.tv_sec != 0 || mEstimateTimeStamp.tv_nsec != 0)) {
+ if (timeDiff > 0) {
+ // Data is not enough, compensate it.
+ compensateData = true;
+ writeData = true;
+ } else {
+ // DL data is out of date, ignore this data
+ compensateData = false;
+ writeData = false;
+ }
+ } else {
+ // Normal case, just wrie data, no compensation
+ compensateData = false;
+ writeData = true;
+ }
+
+ SHOW_TIMESTAMP("%s() timeDiff = %d (%ld.%09ld->%ld.%09ld), compensateData = %d, writeData = %d",
+ __FUNCTION__,
+ timeDiff,
+ mEstimateTimeStamp.tv_sec, mEstimateTimeStamp.tv_nsec,
+ timestamp->tv_sec, timestamp->tv_nsec,
+ compensateData,
+ writeData);
+
+ if (compensateData) {
+ /* If this buffer's time stamp is not expected, compensate it. (my caused by DL open/close) */
+ compensateBytes = compensateSilenceData((uint32_t)timeDiff, &mDataRingBuf);
+ }
+
+ if (writeData) {
+ if (((uint32_t)RingBuf_getFreeSpace(&mDataRingBuf) >= dataSize)) {
+ /* Write new data */
+ RingBuf_copyFromLinear(&mDataRingBuf, (const char *)data, dataSize);
+ dataSize += compensateBytes;
+ } else {
+ dataSize = compensateBytes;
+ }
+ /* Calculate mEstimateTimeStamp */
+ calculateTimeStampByBytes(*timestamp, dataSize, mStreamAttributeSource, &mEstimateTimeStamp);
+
+ SHOW_TIMESTAMP("%s() update mEstimateTimeStamp (%ld.%09ld->%ld.%09ld)",
+ __FUNCTION__,
+ timestamp->tv_sec, timestamp->tv_nsec,
+ mEstimateTimeStamp.tv_sec, mEstimateTimeStamp.tv_nsec);
+ }
+ SHOW_TIMESTAMP("%s(), write data size = %d (free = %d), signal...", __FUNCTION__, dataSize, RingBuf_getFreeSpace(&mDataRingBuf));
+
+ /* Notify provider thread */
+ AL_SIGNAL(mDataBufLock);
+ }
+
+ AL_UNLOCK(mDataBufLock);
+
+ ALOGV("-%s()", __FUNCTION__);
+
+ return ret;
+}
+
+status_t AudioALSACaptureDataProviderEchoRefUsb::readData(char *buffer, uint32_t size) {
+ ALOGV("+%s()", __FUNCTION__);
+
+ AL_LOCK_MS(mDataBufLock, MAX_LOCK_TIME_OUT_MS);
+
+ while ((uint32_t)RingBuf_getDataCount(&mDataRingBuf) < size) {
+ SHOW_TIMESTAMP("%s(), echoref data is not enough, waiting...", __FUNCTION__);
+ if (AL_WAIT_MS(mDataBufLock, MAX_READ_DATA_TIME_OUT_MS) != 0) {
+ SHOW_TIMESTAMP("-%s(), wait timeout! (data size = %d, read size = %d)", __FUNCTION__, RingBuf_getDataCount(&mDataRingBuf), size);
+ AL_UNLOCK(mDataBufLock);
+ return -ETIMEDOUT;
+ }
+
+ SHOW_TIMESTAMP("-%s(), echoref data is comming, wake up... (data size = %d, read size = %d)", __FUNCTION__, RingBuf_getDataCount(&mDataRingBuf), size);
+
+ if (mEnable == false) {
+ SHOW_TIMESTAMP("-%s(), closed, exit readData()", __FUNCTION__);
+ AL_UNLOCK(mDataBufLock);
+ return -ENOSYS;
+ }
+ }
+
+ /* Read data from DataRingBuf */
+ uint32_t srcDataSize = RingBuf_getDataCount(&mDataRingBuf);
+ uint32_t copyBufSize = size > srcDataSize ? srcDataSize : size;
+ RingBuf_copyToLinear(buffer, &mDataRingBuf, copyBufSize);
+ SHOW_TIMESTAMP("%s(), read data size = %d (dstFreeSize = %d, srcDataSize = %d)", __FUNCTION__, copyBufSize, size, srcDataSize);
+
+ updateTotalCaptureBufSize(copyBufSize);
+
+ AL_UNLOCK(mDataBufLock);
+
+ ALOGV("-%s()", __FUNCTION__);
+
+ return NO_ERROR;
+}
+
+void AudioALSACaptureDataProviderEchoRefUsb::signalDataWaiting() {
+ ALOGV("+%s()", __FUNCTION__);
+ AL_LOCK_MS(mDataBufLock, MAX_LOCK_TIME_OUT_MS);
+ AL_SIGNAL(mDataBufLock);
+ AL_UNLOCK(mDataBufLock);
+ ALOGV("-%s()", __FUNCTION__);
+}
+
+void AudioALSACaptureDataProviderEchoRefUsb::updateTotalCaptureBufSize(uint32_t captureSize) {
+ mTotalCaptureBufSize += captureSize;
+}
+
+void AudioALSACaptureDataProviderEchoRefUsb::updateStartTimeStamp(struct timespec *timeStamp) {
+ if (mCaptureStartTime.tv_sec == 0 && mCaptureStartTime.tv_nsec == 0) {
+ if (timeStamp) {
+ mCaptureStartTime = *timeStamp;
+ } else {
+ clock_gettime(CLOCK_REALTIME, &mCaptureStartTime); // Use CLOCK_REALTIME to align kernel timestamp format
+ }
+ ALOGD("%s(), update DataProvider(%d) start timestamp (%ld.%09ld), mTotalCaptureBufSize = %d", __FUNCTION__, mCaptureDataProviderType, mCaptureStartTime.tv_sec, mCaptureStartTime.tv_nsec, mTotalCaptureBufSize);
+ } else {
+ ALOGV("%s(), DataProvider(%d) start timestamp (%ld.%09ld), mTotalCaptureBufSize = %d", __FUNCTION__, mCaptureDataProviderType, mCaptureStartTime.tv_sec, mCaptureStartTime.tv_nsec, mTotalCaptureBufSize);
+ }
+}
+
+status_t AudioALSACaptureDataProviderEchoRefUsb::GetCaptureTimeStampByStartTime(time_info_struct_t *timeInfo) {
+ timeInfo->buffer_per_time = 0;
+ timeInfo->kernelbuffer_ns = 0;
+ timeInfo->frameInfo_get = 0;
+ calculateTimeStampByBytes(mCaptureStartTime, mTotalCaptureBufSize, mStreamAttributeSource, &timeInfo->timestamp_get);
+
+ return NO_ERROR;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderFMRadio.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderFMRadio.cpp
new file mode 100644
index 0000000..81b8e63
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderFMRadio.cpp
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureDataProviderFMRadio.h"
+
+#include <pthread.h>
+
+#include <sys/prctl.h>
+
+#include "AudioType.h"
+#include "AudioALSADriverUtility.h"
+#include "AudioALSAFMController.h"
+#include "WCNChipController.h"
+
+#include "AudioALSADeviceParser.h"
+#include "AudioALSAStreamManager.h"
+#if defined(MTK_AUDIO_KS)
+#include "AudioALSADeviceConfigManager.h"
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderFMRadio"
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+static const uint32_t kReadBufferSize = 0x2000; // 8k
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataProviderFMRadio *AudioALSACaptureDataProviderFMRadio::mAudioALSACaptureDataProviderFMRadio = NULL;
+AudioALSACaptureDataProviderFMRadio *AudioALSACaptureDataProviderFMRadio::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACaptureDataProviderFMRadio == NULL) {
+ mAudioALSACaptureDataProviderFMRadio = new AudioALSACaptureDataProviderFMRadio();
+ }
+ ASSERT(mAudioALSACaptureDataProviderFMRadio != NULL);
+ return mAudioALSACaptureDataProviderFMRadio;
+}
+
+AudioALSACaptureDataProviderFMRadio::AudioALSACaptureDataProviderFMRadio() {
+ ALOGD("%s()", __FUNCTION__);
+
+ mConfig.channels = 2;
+ mConfig.rate = AudioALSAFMController::getInstance()->getFmUplinkSamplingRate();//44100;
+
+ // Buffer size: 2048(period_size) * 2(ch) * 2(byte) * 4(period_count) = 32 kb
+ mConfig.period_size = 2048;
+ mConfig.period_count = 4;
+ mConfig.format = PCM_FORMAT_S16_LE;
+
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+
+ mCaptureDataProviderType = CAPTURE_PROVIDER_FM_RADIO;
+ hReadThread = 0;
+}
+
+AudioALSACaptureDataProviderFMRadio::~AudioALSACaptureDataProviderFMRadio() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureDataProviderFMRadio::open() {
+ ALOGD("%s()", __FUNCTION__);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ASSERT(mEnable == false);
+
+ // config attribute (will used in client SRC/Enh/... later) // TODO(Harvey): query this
+ mStreamAttributeSource.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ mStreamAttributeSource.num_channels = popcount(mStreamAttributeSource.audio_channel_mask);
+ mStreamAttributeSource.sample_rate = AudioALSAFMController::getInstance()->getFmUplinkSamplingRate();
+
+ // Reset frames readed counter
+ mStreamAttributeSource.Time_Info.total_frames_readed = 0;
+
+ mConfig.channels = mStreamAttributeSource.num_channels;
+ mConfig.rate = mStreamAttributeSource.sample_rate;
+ // Buffer size: 2048(period_size) * 2(ch) * 2(byte) * 4(period_count) = 32 kb
+ mConfig.period_size = 2048;
+ mConfig.period_count = 4;
+ mConfig.format = PCM_FORMAT_S16_LE;
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+ OpenPCMDump(LOG_TAG);
+
+ // Get pcm open Info
+ int card_index = -1;
+ int pcm_index = -1;
+
+#if defined(MTK_AUDIO_KS)
+ pcm_index = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmCapture3);
+ card_index = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmCapture3);
+ mApTurnOnSequence = AUDIO_CTL_CONNSYS_TO_CAPTURE3;
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+#else
+ if (WCNChipController::GetInstance()->IsFMMergeInterfaceSupported() == true) {
+ card_index = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmMRGrxCapture);
+ pcm_index = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmMRGrxCapture);
+ } else {
+ card_index = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmFMI2SCapture);
+ pcm_index = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmFMI2SCapture);
+ }
+#endif
+ ALOGD("%s(), card_index = %d, pcm_index = %d", __FUNCTION__, card_index, pcm_index);
+
+ // enable pcm
+ ASSERT(mPcm == NULL);
+ mPcm = pcm_open(card_index, pcm_index, PCM_IN, &mConfig);
+ ASSERT(mPcm != NULL && pcm_is_ready(mPcm) == true);
+ ALOGV("%s(), mPcm = %p", __FUNCTION__, mPcm);
+
+ pcm_start(mPcm);
+
+ // create reading thread
+ mEnable = true;
+ int ret = pthread_create(&hReadThread, NULL, AudioALSACaptureDataProviderFMRadio::readThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureDataProviderFMRadio::close() {
+ ALOGD("%s()", __FUNCTION__);
+
+ mEnable = false;
+ pthread_join(hReadThread, NULL);
+ ALOGD("pthread_join hReadThread done");
+
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ClosePCMDump();
+
+ pcm_stop(mPcm);
+ pcm_close(mPcm);
+ mPcm = NULL;
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+#endif
+
+ return NO_ERROR;
+}
+
+
+void *AudioALSACaptureDataProviderFMRadio::readThread(void *arg) {
+ prctl(PR_SET_NAME, (unsigned long)__FUNCTION__, 0, 0, 0);
+
+ ALOGD("+%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+
+ AudioALSACaptureDataProviderFMRadio *pDataProvider = static_cast<AudioALSACaptureDataProviderFMRadio *>(arg);
+
+ pDataProvider->setThreadPriority();
+
+ uint32_t open_index = pDataProvider->mOpenIndex;
+
+ // read raw data from alsa driver
+ char linear_buffer[kReadBufferSize];
+ while (pDataProvider->mEnable == true) {
+ if (open_index != pDataProvider->mOpenIndex) {
+ ALOGD("%s(), open_index(%d) != mOpenIndex(%d), return", __FUNCTION__, open_index, pDataProvider->mOpenIndex);
+ break;
+ }
+
+ ASSERT(pDataProvider->mPcm != NULL);
+ int retval = pcm_read(pDataProvider->mPcm, linear_buffer, kReadBufferSize);
+ if (retval != 0) {
+ ALOGE("%s(), pcm_read() error, retval = %d", __FUNCTION__, retval);
+ }
+
+ // use ringbuf format to save buffer info
+ pDataProvider->mPcmReadBuf.pBufBase = linear_buffer;
+ pDataProvider->mPcmReadBuf.bufLen = kReadBufferSize + 1; // +1: avoid pRead == pWrite
+ pDataProvider->mPcmReadBuf.pRead = linear_buffer;
+ pDataProvider->mPcmReadBuf.pWrite = linear_buffer + kReadBufferSize;
+
+ pDataProvider->provideCaptureDataToAllClients(open_index);
+ }
+
+ ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ pthread_exit(NULL);
+ return NULL;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderModemDai.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderModemDai.cpp
new file mode 100644
index 0000000..6fdb77e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderModemDai.cpp
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureDataProviderModemDai.h"
+#include <pthread.h>
+#include <sys/prctl.h>
+#include "AudioALSADeviceParser.h"
+#include "AudioALSADriverUtility.h"
+#include "AudioType.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderModemDai"
+
+#define MODDAI_USING_24BITS
+
+namespace android {
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataProviderModemDai *AudioALSACaptureDataProviderModemDai::mAudioALSACaptureDataProviderModemDai = NULL;
+AudioALSACaptureDataProviderModemDai *AudioALSACaptureDataProviderModemDai::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACaptureDataProviderModemDai == NULL) {
+ mAudioALSACaptureDataProviderModemDai = new AudioALSACaptureDataProviderModemDai();
+ }
+ ASSERT(mAudioALSACaptureDataProviderModemDai != NULL);
+ return mAudioALSACaptureDataProviderModemDai;
+}
+
+AudioALSACaptureDataProviderModemDai::AudioALSACaptureDataProviderModemDai() {
+ ALOGD("%s()", __FUNCTION__);
+
+ mConfig.channels = kModDaiChanel;
+ mConfig.rate = kModDaiSampleRate;
+
+ mConfig.period_size = kModDaiReadPeriodSize;
+ mConfig.period_count = kModDaiReadBufferCount;
+
+#ifdef MODDAI_USING_24BITS
+ mConfig.format = PCM_FORMAT_S32_LE;
+#else
+ mConfig.format = PCM_FORMAT_S16_LE;
+#endif
+
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+
+ mCaptureDataProviderType = CAPTURE_PROVIDER_AP_VOICE_DL;
+ hReadThread = 0;
+}
+
+AudioALSACaptureDataProviderModemDai::~AudioALSACaptureDataProviderModemDai() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureDataProviderModemDai::open() {
+ ALOGD("%s()", __FUNCTION__);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ASSERT(mEnable == false);
+ mStreamAttributeSource.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_MONO;
+ mStreamAttributeSource.num_channels = popcount(mStreamAttributeSource.audio_channel_mask);
+ mStreamAttributeSource.sample_rate = kModDaiSampleRate;
+
+ // Reset frames readed counter
+ mStreamAttributeSource.Time_Info.total_frames_readed = 0;
+
+
+ OpenPCMDump(LOG_TAG);
+
+ // enable pcm
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceDaiCapture);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVoiceDaiCapture);
+ ALOGD("AudioALSACaptureDataProviderModemDai::open() pcmindex = %d", pcmindex);
+
+ openPcmDriver(pcmindex);
+
+ // create reading thread
+ mEnable = true;
+ int ret = pthread_create(&hReadThread, NULL, AudioALSACaptureDataProviderModemDai::readThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureDataProviderModemDai::close() {
+ ALOGD("%s()", __FUNCTION__);
+
+ mEnable = false;
+ pthread_join(hReadThread, NULL);
+ ALOGD("pthread_join hReadThread done");
+
+ ALOGD("%s() getStreamSramDramLock ", __FUNCTION__);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ClosePCMDump();
+
+ closePcmDriver();
+
+ return NO_ERROR;
+}
+
+
+void *AudioALSACaptureDataProviderModemDai::readThread(void *arg) {
+
+ ALOGD("+%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+
+ AudioALSACaptureDataProviderModemDai *pDataProvider = static_cast<AudioALSACaptureDataProviderModemDai *>(arg);
+
+ pDataProvider->setThreadPriority();
+
+ uint32_t open_index = pDataProvider->mOpenIndex;
+ int ReformatSize = 0;
+ // read raw data from alsa driver
+ char linear_buffer[kModDaiReadBufferSize];
+ while (pDataProvider->mEnable == true) {
+ if (open_index != pDataProvider->mOpenIndex) {
+ ALOGD("%s(), open_index(%d) != mOpenIndex(%d), return", __FUNCTION__, open_index, pDataProvider->mOpenIndex);
+ break;
+ }
+
+ ASSERT(pDataProvider->mPcm != NULL);
+ int retval = pcm_read(pDataProvider->mPcm, linear_buffer, kModDaiReadBufferSize);
+
+#ifdef MODDAI_USING_24BITS
+ ReformatSize = FormatTransfer(PCM_FORMAT_S32_LE, PCM_FORMAT_S16_LE, (void *)linear_buffer, kModDaiReadBufferSize);
+#else
+ ReformatSize = FormatTransfer(PCM_FORMAT_S16_LE, PCM_FORMAT_S16_LE, (void *)linear_buffer, kModDaiReadBufferSize);
+#endif
+
+ //ALOGD("pcm_read kModDaiReadBufferSize= %d ReformatSize = %d",kModDaiReadBufferSize,ReformatSize);
+ if (retval != 0) {
+ ALOGE("%s(), pcm_read() error, retval = %d", __FUNCTION__, retval);
+ }
+
+ // use ringbuf format to save buffer info
+ pDataProvider->mPcmReadBuf.pBufBase = linear_buffer;
+ pDataProvider->mPcmReadBuf.bufLen = ReformatSize + 1; // +1: avoid pRead == pWrite
+ pDataProvider->mPcmReadBuf.pRead = linear_buffer;
+ pDataProvider->mPcmReadBuf.pWrite = linear_buffer + ReformatSize;
+
+ pDataProvider->provideCaptureDataToAllClients(open_index);
+ }
+
+ ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ return NULL;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderNormal.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderNormal.cpp
new file mode 100644
index 0000000..b62f8f2
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderNormal.cpp
@@ -0,0 +1,505 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderNormal"
+
+#include "AudioALSACaptureDataProviderNormal.h"
+
+#include <pthread.h>
+#include <sys/prctl.h>
+
+#include "AudioALSADriverUtility.h"
+#include "AudioType.h"
+#include "AudioSpeechEnhanceInfo.h"
+#include "AudioALSASpeechPhoneCallController.h"
+#include "AudioALSAStreamManager.h"
+#include "AudioALSAHardwareResourceManager.h"
+
+#if defined(MTK_AUDIO_KS)
+#include "AudioALSADeviceConfigManager.h"
+#endif
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+#include "AudioDetectPulse.h"
+#endif
+
+
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+
+
+#define AUDIO_CHANNEL_IN_3MIC (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT | AUDIO_CHANNEL_IN_BACK)
+#define AUDIO_CHANNEL_IN_4MIC (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT | AUDIO_CHANNEL_IN_BACK) // ch4 == ch3
+
+#define UPLINK_SET_AMICDCC_BUFFER_TIME_MS 80
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+
+static uint32_t kReadBufferSize = 0;
+static const uint32_t kDCRReadBufferSize = 0x2EE00; //48K\stereo\1s data , calculate 1time/sec
+
+//static FILE *pDCCalFile = NULL;
+static bool btempDebug = false;
+
+
+
+/*==============================================================================
+ * Utility
+ *============================================================================*/
+
+#define LINEAR_4CH_TO_3CH(linear_buf, data_size, type) \
+ ({ \
+ uint32_t __channel_size = (data_size >> 2); \
+ uint32_t __num_sample = __channel_size / sizeof(type); \
+ uint32_t __data_size_3ch = __channel_size * 3; \
+ type *__linear_4ch = (type *)(linear_buf); \
+ type *__linear_3ch = (type *)(linear_buf); \
+ uint32_t __idx_sample = 0; \
+ for (__idx_sample = 0; __idx_sample < __num_sample; __idx_sample++) { \
+ memcpy(__linear_3ch, __linear_4ch, 3 * sizeof(type)); \
+ __linear_3ch += 3; \
+ __linear_4ch += 4; \
+ } \
+ __data_size_3ch; \
+ })
+
+
+static uint32_t doDownMixFrom4chTo3ch(void *linear_buf, uint32_t data_size, uint32_t audio_format) {
+ if (audio_format == AUDIO_FORMAT_PCM_16_BIT) {
+ return LINEAR_4CH_TO_3CH(linear_buf, data_size, int16_t);
+ } else if (audio_format == AUDIO_FORMAT_PCM_32_BIT ||
+ audio_format == AUDIO_FORMAT_PCM_8_24_BIT) {
+ return LINEAR_4CH_TO_3CH(linear_buf, data_size, int32_t);
+ } else {
+ return 0;
+ }
+}
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataProviderNormal *AudioALSACaptureDataProviderNormal::mAudioALSACaptureDataProviderNormal = NULL;
+AudioALSACaptureDataProviderNormal *AudioALSACaptureDataProviderNormal::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACaptureDataProviderNormal == NULL) {
+ mAudioALSACaptureDataProviderNormal = new AudioALSACaptureDataProviderNormal();
+ }
+ ASSERT(mAudioALSACaptureDataProviderNormal != NULL);
+ return mAudioALSACaptureDataProviderNormal;
+}
+
+AudioALSACaptureDataProviderNormal::AudioALSACaptureDataProviderNormal():
+ mMixer(AudioALSADriverUtility::getInstance()->getMixer()),
+ hReadThread(0),
+ mCaptureDropSize(0) {
+ ALOGD("%s()", __FUNCTION__);
+
+ mCaptureDataProviderType = CAPTURE_PROVIDER_NORMAL;
+ memset(&mNewtime, 0, sizeof(mNewtime));
+ memset(&mOldtime, 0, sizeof(mOldtime));
+ memset(timerec, 0, sizeof(timerec));
+}
+
+AudioALSACaptureDataProviderNormal::~AudioALSACaptureDataProviderNormal() {
+ ALOGV("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureDataProviderNormal::open() {
+
+ ALOGV("%s(+)", __FUNCTION__);
+
+ ASSERT(mEnable == false);
+
+#if defined(MTK_AUDIO_KS)
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmCapture1);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmCapture1);
+#else
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmUl1Capture);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmUl1Capture);
+#endif
+ bool audiomode = AudioALSAStreamManager::getInstance()->isModeInPhoneCall(); // TODO: should not use AudioALSAStreamManager.......
+ ALOGD("%s(+), audiomode=%d, cardindex = %d, pcmindex = %d", __FUNCTION__, audiomode, cardindex, pcmindex);
+
+ struct pcm_params *params;
+ params = pcm_params_get(cardindex, pcmindex, PCM_IN);
+ if (params == NULL) {
+ ALOGD("Device does not exist.\n");
+ }
+
+ {
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+ unsigned int buffersizemax = pcm_params_get_max(params, PCM_PARAM_BUFFER_BYTES);
+ pcm_params_free(params);
+ bool bHifiRecord = AudioSpeechEnhanceInfo::getInstance()->GetHifiRecord();
+ //debug++
+ btempDebug = AudioSpeechEnhanceInfo::getInstance()->GetDebugStatus();
+ ALOGD("buffersizemax: %d, bHifiRecord: %d, btempDebug: %d", buffersizemax, bHifiRecord, btempDebug);
+ //debug--
+
+
+#ifndef MTK_AURISYS_FRAMEWORK_SUPPORT
+ mConfig.channels = 2; // non aurisys... use 2ch
+#else
+ if (mStreamAttributeSource.input_source == AUDIO_SOURCE_UNPROCESSED) {
+ mConfig.channels = 1;
+ } else if (mStreamAttributeSource.input_device == AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ mConfig.channels = AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport();
+
+ switch (mConfig.channels) {
+ case 1:
+ case 2:
+ break;
+ case 3:
+ ALOGV("alsa not support 3ch... use 4ch"); // ch4 is same as ch3
+ mConfig.channels = 4;
+ break;
+ case 4:
+ break;
+ default:
+ ALOGW("mConfig.channels = %d!! use 2ch", mConfig.channels);
+ mConfig.channels = 2;
+ }
+ } else if (mStreamAttributeSource.input_device == AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ switch (AudioALSAHardwareResourceManager::getInstance()->getNumOfHeadsetPole()) {
+ case 4:
+ mConfig.channels = 1;
+ break;
+ case 5:
+ mConfig.channels = 2;
+ break;
+ default:
+ mConfig.channels = 1;
+ ALOGE("%s(), can't found matched pole number, use 1 ch", __FUNCTION__);
+ break;
+ }
+ } else {
+ ALOGW("device 0x%x not support... use 2ch", mStreamAttributeSource.input_device);
+ mConfig.channels = 2;
+ }
+#endif // end of MTK_AURISYS_FRAMEWORK_SUPPORT
+
+
+ mConfig.period_count = 4;
+ if (isNeedSyncPcmStart() == true) {
+ mConfig.period_count = 6;
+ }
+ mConfig.rate = 48000;
+
+ mlatency = UPLINK_NORMAL_LATENCY_MS ; //20ms
+#ifdef UPLINK_LOW_LATENCY
+ if (HasLowLatencyCapture()) { mlatency = UPLINK_LOW_LATENCY_MS; }
+#endif
+
+ if (bHifiRecord == true) {
+ mConfig.rate = 96000;
+ }
+
+#ifdef MTK_DMIC_SR_LIMIT
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_DMIC)) {
+ if (mStreamAttributeSource.input_device != AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ mConfig.rate = 32000;
+ }
+ }
+#endif
+
+ if (audiomode == true) {
+ //if not BT phonecall
+ if (!(audio_is_bluetooth_sco_device(mStreamAttributeSource.output_devices))) {
+ uint32_t sampleRate = AudioALSASpeechPhoneCallController::getInstance()->getSampleRate();
+ if (sampleRate != 0) {
+ mConfig.rate = sampleRate;
+ ALOGD("Phone call mode active, change smaple rate: audiomode=%d, mConfig.rate=%d", audiomode, mConfig.rate);
+ }
+ }
+ }
+
+ if (mlatency == UPLINK_LOW_LATENCY_MS) {
+ mConfig.period_count = 40 / UPLINK_LOW_LATENCY_MS; // latency/count : 1/40, 2/20, 3/13, 5/8;
+ }
+
+#ifdef RECORD_INPUT_24BITS
+#if defined(MTK_AUDIO_KS)
+ mConfig.format = PCM_FORMAT_S24_LE;
+#else
+ mConfig.format = PCM_FORMAT_S32_LE;
+#endif
+ mStreamAttributeSource.audio_format = AUDIO_FORMAT_PCM_8_24_BIT;
+#else
+ mConfig.format = PCM_FORMAT_S16_LE;
+ mStreamAttributeSource.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+#endif
+
+ // config attribute (will used in client SRC/Enh/... later)
+ switch (mConfig.channels) {
+ case 1:
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_MONO;
+ break;
+ case 2:
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ break;
+ case 3:
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_3MIC;
+ break;
+ case 4:
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_4MIC;
+ break;
+ default:
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ }
+
+ mStreamAttributeSource.num_channels = mConfig.channels;
+ mStreamAttributeSource.sample_rate = mConfig.rate; //48000;
+#ifdef MTK_DMIC_SR_LIMIT
+ mStreamAttributeSource.sample_rate = mConfig.rate; //32000;
+#endif
+
+ // Reset frames readed counter
+ mStreamAttributeSource.Time_Info.total_frames_readed = 0;
+
+ kReadBufferSize = getPeriodBufSize(&mStreamAttributeSource, mlatency);
+#if 0 // cause latency issue...... = =a
+ kReadBufferSize &= 0xFFFFFFC0; // (UL)48K\5ms data\stereo\4byte\(Align64byte)
+#endif
+
+
+ // should set mStreamAttributeSource.num_channels after getPeriodBufSize
+ if (mConfig.channels == 4) {
+ ALOGV("src not support 4ch -> 3ch... use 3ch");
+ mStreamAttributeSource.num_channels = 3;
+ }
+
+#ifdef UPLINK_LOW_LATENCY
+ mConfig.period_size = kReadBufferSize / mConfig.channels / (pcm_format_to_bits(mConfig.format) / 8); //period size will impact the interrupt interval
+#else
+ mConfig.period_size = (buffersizemax / mConfig.channels / (pcm_format_to_bits(mConfig.format) / 8) / mConfig.period_count);
+#endif
+
+ mStreamAttributeSource.buffer_size = mConfig.period_size * mConfig.period_count * mConfig.channels *
+ (pcm_format_to_bits(mConfig.format) / 8);
+
+ mConfig.start_threshold = 0;
+#if defined(MTK_AUDIO_KS)
+ mConfig.stop_threshold = mConfig.period_size * mConfig.period_count;
+#else
+ mConfig.stop_threshold = 0;
+#endif
+ mConfig.silence_threshold = 0;
+
+ OpenPCMDump(LOG_TAG);
+
+ ALOGD("mConfig format: %d, channels: %d, rate: %d, period_size: %d, period_count: %d, latency: %d, kReadBufferSize: %u, mCaptureDropSize: %u",
+ mConfig.format, mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mlatency, kReadBufferSize, mCaptureDropSize);
+
+#if defined(MTK_AUDIO_KS)
+ if (mConfig.channels > 2) {
+ mApTurnOnSequence = AUDIO_CTL_ADDA_TO_CAPTURE1_4CH;
+ } else {
+ mApTurnOnSequence = AUDIO_CTL_ADDA_TO_CAPTURE1;
+ }
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+
+ // set pmic before pcm prepare
+ enablePmicInputDevice(true);
+
+#if !defined(CONFIG_MT_ENG_BUILD)
+ // need to set after query pcm_params_get, since shutdown will clear this state
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "record_xrun_assert"), 0, 1)) {
+ ALOGW("%s(), record_xrun_assert enable fail", __FUNCTION__);
+ }
+#endif
+#endif
+
+ // enable pcm
+ ASSERT(mPcm == NULL);
+#if defined(CAPTURE_MMAP) // must be after pcm open
+ unsigned int flag = PCM_IN | PCM_MONOTONIC | PCM_MMAP;
+ openPcmDriverWithFlag(pcmindex, flag);
+#else
+ mPcm = pcm_open(cardindex, pcmindex, PCM_IN | PCM_MONOTONIC, &mConfig);
+#endif
+ ASSERT(mPcm != NULL && pcm_is_ready(mPcm) == true);
+ ALOGV("%s(), mPcm = %p", __FUNCTION__, mPcm);
+
+ int prepare_error = pcm_prepare(mPcm);
+ if (prepare_error != 0) {
+ ASSERT(0);
+ pcm_close(mPcm);
+ mPcm = NULL;
+ return UNKNOWN_ERROR;
+ }
+#if !defined(MTK_AUDIO_KS)
+ // Need to enable PMIC device before AFE to reduce mute data in the beginning
+ enablePmicInputDevice(true);
+#endif
+ mStart = false;
+ mReadThreadReady = false;
+ }
+ // create reading thread
+ mEnable = true;
+ int ret = pthread_create(&hReadThread, NULL, AudioALSACaptureDataProviderNormal::readThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create hReadThread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ ALOGD("%s(-)", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureDataProviderNormal::close() {
+ ALOGD("%s()", __FUNCTION__);
+
+#if defined(MTK_AUDIO_KS) && !defined(CONFIG_MT_ENG_BUILD)
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "record_xrun_assert"), 0, 0)) {
+ ALOGW("%s(), record_xrun_assert disable fail", __FUNCTION__);
+ }
+#endif
+
+ mEnable = false;
+ pthread_join(hReadThread, NULL);
+ ALOGD("pthread_join hReadThread done");
+
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ClosePCMDump();
+
+ pcm_stop(mPcm);
+ pcm_close(mPcm);
+ mPcm = NULL;
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+#endif
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+void *AudioALSACaptureDataProviderNormal::readThread(void *arg) {
+ status_t retval = NO_ERROR;
+ int ret = 0;
+ uint32_t counter = 1;
+
+ AudioALSACaptureDataProviderNormal *pDataProvider = static_cast<AudioALSACaptureDataProviderNormal *>(arg);
+
+ uint32_t open_index = pDataProvider->mOpenIndex;
+
+ char nameset[32];
+ sprintf(nameset, "%s%d", __FUNCTION__, pDataProvider->mCaptureDataProviderType);
+ prctl(PR_SET_NAME, (unsigned long)nameset, 0, 0, 0);
+ pDataProvider->setThreadPriority();
+
+ ALOGD("+%s(), pid: %d, tid: %d, kReadBufferSize=0x%x, open_index=%d, UPLINK_SET_AMICDCC_BUFFER_TIME_MS = %d, counter=%d ", __FUNCTION__, getpid(), gettid(), kReadBufferSize, open_index, UPLINK_SET_AMICDCC_BUFFER_TIME_MS, counter);
+
+ pDataProvider->waitPcmStart();
+
+ // read raw data from alsa driver
+ char linear_buffer[kReadBufferSize];
+ uint32_t Read_Size = kReadBufferSize;
+ uint32_t kReadBufferSize_new;
+ while (pDataProvider->mEnable == true) {
+ ASSERT(open_index == pDataProvider->mOpenIndex);
+ ASSERT(pDataProvider->mPcm != NULL);
+
+ if (btempDebug) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[0] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+ }
+
+ ret = pDataProvider->pcmRead(pDataProvider->mPcm, linear_buffer, kReadBufferSize);
+ if (ret != 0) {
+ ALOGE("%s(), pcm_read() error, retval = %d", __FUNCTION__, retval);
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mOldtime);
+ continue;
+ }
+
+ //struct timespec tempTimeStamp;
+ retval = pDataProvider->GetCaptureTimeStamp(&pDataProvider->mStreamAttributeSource.Time_Info, kReadBufferSize);
+#if 0
+ if (retval != NO_ERROR) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mOldtime);
+ continue;
+ }
+#endif
+
+ if (btempDebug) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[1] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+ }
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+ stream_attribute_t *attribute = &(pDataProvider->mStreamAttributeSource);
+ AudioDetectPulse::doDetectPulse(TAG_CAPTURE_DATA_PROVIDER, PULSE_LEVEL, 0, (void *)linear_buffer,
+ kReadBufferSize, attribute->audio_format, attribute->num_channels,
+ attribute->sample_rate);
+#endif
+
+ if (pDataProvider->mConfig.channels == 4 && pDataProvider->mPCMDumpFile4ch) {
+ AudioDumpPCMData(linear_buffer, kReadBufferSize, pDataProvider->mPCMDumpFile4ch);
+ }
+
+ // 4ch to 3ch
+ if (pDataProvider->mConfig.channels == 4 &&
+ pDataProvider->mStreamAttributeSource.num_channels == 3) {
+ Read_Size = doDownMixFrom4chTo3ch(
+ linear_buffer,
+ kReadBufferSize,
+ pDataProvider->mStreamAttributeSource.audio_format);
+ } else {
+ Read_Size = kReadBufferSize;
+ }
+
+ // Adjust AMIC 3DB Corner clock setting
+ if (counter <= (UPLINK_SET_AMICDCC_BUFFER_TIME_MS / pDataProvider->mlatency)) {
+ if (counter == (UPLINK_SET_AMICDCC_BUFFER_TIME_MS / pDataProvider->mlatency)) {
+ pDataProvider->adjustSpike();
+ }
+ counter++;
+ }
+
+ // use ringbuf format to save buffer info
+ pDataProvider->mPcmReadBuf.pBufBase = linear_buffer;
+ pDataProvider->mPcmReadBuf.bufLen = Read_Size + 1; // +1: avoid pRead == pWrite
+ pDataProvider->mPcmReadBuf.pRead = linear_buffer;
+ pDataProvider->mPcmReadBuf.pWrite = linear_buffer + Read_Size;
+ pDataProvider->provideCaptureDataToAllClients(open_index);
+
+ if (btempDebug) {
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[2] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+
+ ALOGD("%s, latency_in_us,%1.6lf,%1.6lf,%1.6lf", __FUNCTION__, pDataProvider->timerec[0], pDataProvider->timerec[1], pDataProvider->timerec[2]);
+ }
+ }
+
+ ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ pthread_exit(NULL);
+ return NULL;
+}
+
+void AudioALSACaptureDataProviderNormal::adjustSpike()
+{
+ status_t retval = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mAudioALSACaptureDataProviderNormal->mMixer, "Audio_AMIC_DCC_Setting"), "On");
+ if (retval != 0) {
+ ALOGD("%s(), Can not find Audio_AMIC_DCC_Setting!", __FUNCTION__);
+ }
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderTDM.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderTDM.cpp
new file mode 100644
index 0000000..fc21123
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderTDM.cpp
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureDataProviderTDM.h"
+
+#include <pthread.h>
+
+#include <sys/prctl.h>
+
+#include "AudioType.h"
+#include "AudioALSADriverUtility.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderTDM"
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+static const uint32_t kReadBufferSize = 0x2000; // 8k
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataProviderTDM *AudioALSACaptureDataProviderTDM::mAudioALSACaptureDataProviderTDM = NULL;
+AudioALSACaptureDataProviderTDM *AudioALSACaptureDataProviderTDM::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACaptureDataProviderTDM == NULL) {
+ mAudioALSACaptureDataProviderTDM = new AudioALSACaptureDataProviderTDM();
+ }
+ ASSERT(mAudioALSACaptureDataProviderTDM != NULL);
+ return mAudioALSACaptureDataProviderTDM;
+}
+
+AudioALSACaptureDataProviderTDM::AudioALSACaptureDataProviderTDM():
+ hReadThread(0) {
+ ALOGD("%s()", __FUNCTION__);
+
+ mConfig.channels = 2;
+ mConfig.rate = 44100;
+
+ // Buffer size: 2048(period_size) * 2(ch) * 2(byte) * 2(period_count) = 16 kb
+ mConfig.period_size = 2048;
+ mConfig.period_count = 2;
+ mConfig.format = PCM_FORMAT_S16_LE;
+
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+
+ mCaptureDataProviderType = CAPTURE_PROVIDER_TDM_RECORD;
+}
+
+AudioALSACaptureDataProviderTDM::~AudioALSACaptureDataProviderTDM() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureDataProviderTDM::open() {
+ ALOGD("%s()", __FUNCTION__);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ASSERT(mEnable == false);
+
+ // config attribute (will used in client SRC/Enh/... later) // TODO(Harvey): query this
+ mStreamAttributeSource.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ mStreamAttributeSource.num_channels = popcount(mStreamAttributeSource.audio_channel_mask);
+ mStreamAttributeSource.sample_rate = 44100;
+
+ // Reset frames readed counter
+ mStreamAttributeSource.Time_Info.total_frames_readed = 0;
+
+
+ OpenPCMDump(LOG_TAG);
+
+ // enable pcm
+ ASSERT(mPcm == NULL);
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmTDMLoopback);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmTDMLoopback);
+ mPcm = pcm_open(cardIdx, pcmIdx, PCM_IN, &mConfig);
+
+ ASSERT(mPcm != NULL && pcm_is_ready(mPcm) == true);
+ ALOGV("%s(), mPcm = %p", __FUNCTION__, mPcm);
+
+ pcm_start(mPcm);
+
+ // create reading thread
+ mEnable = true;
+ int ret = pthread_create(&hReadThread, NULL, AudioALSACaptureDataProviderTDM::readThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureDataProviderTDM::close() {
+ ALOGD("%s()", __FUNCTION__);
+
+ mEnable = false;
+ pthread_join(hReadThread, NULL);
+ ALOGD("pthread_join hReadThread done");
+
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ClosePCMDump();
+
+ pcm_stop(mPcm);
+ pcm_close(mPcm);
+ mPcm = NULL;
+
+ return NO_ERROR;
+}
+
+
+void *AudioALSACaptureDataProviderTDM::readThread(void *arg) {
+ prctl(PR_SET_NAME, (unsigned long)__FUNCTION__, 0, 0, 0);
+
+ ALOGD("+%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+
+ AudioALSACaptureDataProviderTDM *pDataProvider = static_cast<AudioALSACaptureDataProviderTDM *>(arg);
+
+ pDataProvider->setThreadPriority();
+
+ uint32_t open_index = pDataProvider->mOpenIndex;
+
+ // read raw data from alsa driver
+ char linear_buffer[kReadBufferSize];
+ while (pDataProvider->mEnable == true) {
+ if (open_index != pDataProvider->mOpenIndex) {
+ ALOGD("%s(), open_index(%d) != mOpenIndex(%d), return", __FUNCTION__, open_index, pDataProvider->mOpenIndex);
+ break;
+ }
+
+ ASSERT(pDataProvider->mPcm != NULL);
+ int retval = pcm_read(pDataProvider->mPcm, linear_buffer, kReadBufferSize);
+ if (retval != 0) {
+ ALOGE("%s(), pcm_read() error, retval = %d", __FUNCTION__, retval);
+ }
+
+ // use ringbuf format to save buffer info
+ pDataProvider->mPcmReadBuf.pBufBase = linear_buffer;
+ pDataProvider->mPcmReadBuf.bufLen = kReadBufferSize + 1; // +1: avoid pRead == pWrite
+ pDataProvider->mPcmReadBuf.pRead = linear_buffer;
+ pDataProvider->mPcmReadBuf.pWrite = linear_buffer + kReadBufferSize;
+
+ pDataProvider->provideCaptureDataToAllClients(open_index);
+ }
+
+ ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ pthread_exit(NULL);
+ return NULL;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderUsb.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderUsb.cpp
new file mode 100644
index 0000000..6e0c45e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderUsb.cpp
@@ -0,0 +1,296 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderUsb"
+
+#include "AudioALSACaptureDataProviderUsb.h"
+//#include "AudioType.h"
+
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <sys/prctl.h>
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <log/log.h>
+#include <cutils/str_parms.h>
+#include <cutils/properties.h>
+#include "AudioALSADriverUtility.h"
+
+#include <hardware/audio.h>
+//#include <hardware/audio_alsaops.h>
+#include <hardware/hardware.h>
+
+#include <system/audio.h>
+
+#include "IAudioALSACaptureDataClient.h"
+#include "AudioALSAStreamManager.h"
+
+extern "C" {
+ //#include <tinyalsa/asoundlib.h>
+#include "alsa_device_profile.h"
+#include "alsa_device_proxy.h"
+#include "alsa_logging.h"
+#include <audio_utils/channels.h>
+}
+
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+#ifdef DEBUG_TIMESTAMP
+#define SHOW_TIMESTAMP(format, args...) ALOGD(format, ##args)
+#else
+#define SHOW_TIMESTAMP(format, args...)
+#endif
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+
+static uint32_t kReadBufferSize = 0;
+static alsa_device_proxy *usbProxy = NULL;
+static bool usbVoipMode = false;
+//static FILE *pDCCalFile = NULL;
+static bool btempDebug = false;
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataProviderUsb *AudioALSACaptureDataProviderUsb::mAudioALSACaptureDataProviderUsb = NULL;
+
+AudioALSACaptureDataProviderUsb *AudioALSACaptureDataProviderUsb::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACaptureDataProviderUsb == NULL) {
+ mAudioALSACaptureDataProviderUsb = new AudioALSACaptureDataProviderUsb();
+ }
+ ASSERT(mAudioALSACaptureDataProviderUsb != NULL);
+ return mAudioALSACaptureDataProviderUsb;
+}
+
+AudioALSACaptureDataProviderUsb::AudioALSACaptureDataProviderUsb():
+ hReadThread(0) {
+ ALOGD("%s()", __FUNCTION__);
+ memset(&mNewtime, 0, sizeof(mNewtime));
+ memset(&mOldtime, 0, sizeof(mOldtime));
+ memset(timerec, 0, sizeof(timerec));
+ memset((void *)&mCaptureStartTime, 0, sizeof(mCaptureStartTime));
+ memset((void *)&mEstimatedBufferTimeStamp, 0, sizeof(mEstimatedBufferTimeStamp));
+ mlatency = 16;
+}
+
+AudioALSACaptureDataProviderUsb::~AudioALSACaptureDataProviderUsb() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+void AudioALSACaptureDataProviderUsb::initUsbInfo(stream_attribute_t stream_attribute_source_usb, alsa_device_proxy *proxy, size_t buffer_size, bool enable) {
+ usbProxy = proxy;
+ kReadBufferSize = (uint32_t)buffer_size;
+ usbVoipMode = false;
+ mStreamAttributeSource = stream_attribute_source_usb;
+ mStreamAttributeSource.BesRecord_Info.besrecord_voip_enable = false;
+ mStreamAttributeSource.mVoIPEnable = false;
+ mStreamAttributeSource.audio_mode = AUDIO_MODE_NORMAL;
+ mPcmStatus = NO_ERROR;
+ bool audiomode = AudioALSAStreamManager::getInstance()->isModeInVoipCall();
+ ALOGD("%s(), kReadBufferSize = %d, enable = %d, mStreamAttributeSource.input_source = %d ,audiomode = %d", __FUNCTION__, kReadBufferSize, enable, mStreamAttributeSource.input_source, audiomode);
+
+ if ((mStreamAttributeSource.input_source == AUDIO_SOURCE_VOICE_COMMUNICATION) || (audiomode == true)) {
+ usbVoipMode = true;
+ if (enable == true) {
+ mStreamAttributeSource.BesRecord_Info.besrecord_voip_enable = true;
+ mStreamAttributeSource.mVoIPEnable = true;
+ mStreamAttributeSource.audio_mode = AUDIO_MODE_IN_COMMUNICATION;
+ } else {
+ // LIB Parser error handling
+ mStreamAttributeSource.input_source = AUDIO_SOURCE_MIC;
+ }
+ }
+}
+
+bool AudioALSACaptureDataProviderUsb::isNeedEchoRefData() {
+ ALOGD("%s(), usbVoipMode = %d, mStreamAttributeSource.input_source = %d", __FUNCTION__, usbVoipMode, mStreamAttributeSource.input_source);
+ if (usbVoipMode == true) {
+ return true;
+ }
+ return false;
+}
+
+status_t AudioALSACaptureDataProviderUsb::open() {
+ ALOGD("%s()", __FUNCTION__);
+
+ ASSERT(mEnable == false);
+ mCaptureDataProviderType = CAPTURE_PROVIDER_USB;
+ /* Reset frames readed counter & mCaptureStartTime */
+ mStreamAttributeSource.Time_Info.total_frames_readed = 0;
+ memset((void *)&mCaptureStartTime, 0, sizeof(mCaptureStartTime));
+ memset((void *)&mEstimatedBufferTimeStamp, 0, sizeof(mEstimatedBufferTimeStamp));
+ mEnable = true;
+
+ int ret_thread = pthread_create(&hReadThread, NULL, AudioALSACaptureDataProviderUsb::readThread, (void *)this);
+ if (ret_thread != 0) {
+ ALOGD("%s(),pthread_create fail", __FUNCTION__);
+ mEnable = false;
+ pthread_join(hReadThread, NULL);
+ proxy_close(usbProxy);
+ //ASSERT((ret == 0)&&(ret_thread == 0));
+ mPcmStatus = BAD_VALUE;
+ return mPcmStatus;
+ } else {
+ mPcmStatus = NO_ERROR;
+ }
+ mPcm = usbProxy->pcm;
+ OpenPCMDump(LOG_TAG);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureDataProviderUsb::close() {
+ ALOGD("%s(), kReadBufferSize = %d", __FUNCTION__, kReadBufferSize);
+ if (mEnable == true) {
+ mEnable = false;
+ pthread_join(hReadThread, NULL);
+ ALOGD("pthread_join hReadThread done");
+ ClosePCMDump();
+ mPcm = NULL;
+ }
+ return NO_ERROR;
+}
+
+void *AudioALSACaptureDataProviderUsb::readThread(void *arg) {
+ ALOGD("+%s1(), kReadBufferSize = %d", __FUNCTION__, kReadBufferSize);
+ int ret = 0;
+
+ status_t retval = NO_ERROR;
+ AudioALSACaptureDataProviderUsb *pDataProvider = static_cast<AudioALSACaptureDataProviderUsb *>(arg);
+
+ uint32_t open_index = pDataProvider->mOpenIndex;
+
+ char nameset[32];
+ sprintf(nameset, "%s%d", __FUNCTION__, pDataProvider->mCaptureDataProviderType);
+ prctl(PR_SET_NAME, (unsigned long)nameset, 0, 0, 0);
+ pDataProvider->setThreadPriority();
+ ALOGD("+%s2(), pid: %d, tid: %d, kReadBufferSize = %d, open_index=%d", __FUNCTION__, getpid(), gettid(), kReadBufferSize, open_index);
+
+
+ // read raw data from alsa driver
+ char linear_buffer[kReadBufferSize];
+ uint32_t Read_Size = kReadBufferSize;
+ while (pDataProvider->mEnable == true) {
+ if (open_index != pDataProvider->mOpenIndex) {
+ ALOGD("%s(), open_index(%d) != mOpenIndex(%d), return", __FUNCTION__, open_index, pDataProvider->mOpenIndex);
+ break;
+ }
+
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[0] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+
+ int retval = proxy_read(usbProxy, linear_buffer, kReadBufferSize);
+ if (retval != 0) {
+ ALOGD("%s(), proxy_read fail", __FUNCTION__);
+ usleep(15000);
+ mPcmStatus = BAD_VALUE;
+ continue;
+ }
+ mPcmStatus = NO_ERROR;
+ retval = pDataProvider->GetCaptureTimeStamp(&pDataProvider->mStreamAttributeSource.Time_Info, kReadBufferSize);
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[1] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+ /* Update capture start time if needed */
+ pDataProvider->updateStartTimeStamp(pDataProvider->mStreamAttributeSource.Time_Info.timestamp_get);
+
+ //use ringbuf format to save buffer info
+ pDataProvider->mPcmReadBuf.pBufBase = linear_buffer;
+ pDataProvider->mPcmReadBuf.bufLen = kReadBufferSize + 1; // +1: avoid pRead == pWrite
+ pDataProvider->mPcmReadBuf.pRead = linear_buffer;
+ pDataProvider->mPcmReadBuf.pWrite = linear_buffer + kReadBufferSize;
+
+ /* update capture timestamp by start time */
+ pDataProvider->updateCaptureTimeStampByStartTime(kReadBufferSize);
+
+ pDataProvider->provideCaptureDataToAllClients(open_index);
+
+ clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime);
+ pDataProvider->timerec[2] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime);
+ pDataProvider->mOldtime = pDataProvider->mNewtime;
+ if (pDataProvider->mPCMDumpFile || btempDebug) {
+ ALOGD("%s, latency_in_us,%1.6lf,%1.6lf,%1.6lf", __FUNCTION__, pDataProvider->timerec[0], pDataProvider->timerec[1], pDataProvider->timerec[2]);
+ }
+ }
+
+ ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ pthread_exit(NULL);
+ return NULL;
+
+
+}
+
+status_t AudioALSACaptureDataProviderUsb::updateStartTimeStamp(struct timespec timeStamp) {
+ if (mCaptureStartTime.tv_sec == 0 && mCaptureStartTime.tv_nsec == 0) {
+ mCaptureStartTime = timeStamp;
+
+ ALOGD("%s(), set start timestamp = %ld.%09ld",
+ __FUNCTION__, mCaptureStartTime.tv_sec, mCaptureStartTime.tv_nsec);
+
+ return NO_ERROR;
+ }
+
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSACaptureDataProviderUsb::updateCaptureTimeStampByStartTime(uint32_t readBytes) {
+ ALOGV("%s()", __FUNCTION__);
+
+ if (mCaptureStartTime.tv_sec == 0 && mCaptureStartTime.tv_nsec == 0) {
+ ALOGW("No valid mCaptureStartTime! Don't update timestamp info.");
+ return BAD_VALUE;
+ }
+
+ /* Update timeInfo structure */
+ uint32_t bytesPerSample = audio_bytes_per_sample(mStreamAttributeSource.audio_format);
+ if (bytesPerSample == 0) {
+ ALOGW("audio_format is invalid! (%d)", mStreamAttributeSource.audio_format);
+ return BAD_VALUE;
+ }
+ uint32_t readFrames = readBytes / bytesPerSample / mStreamAttributeSource.num_channels;
+ time_info_struct_t *timeInfo = &mStreamAttributeSource.Time_Info;
+
+ timeInfo->frameInfo_get = 0; // Already counted in mCaptureStartTime
+ timeInfo->buffer_per_time = 0; // Already counted in mCaptureStartTime
+ timeInfo->kernelbuffer_ns = 0;
+ calculateTimeStampByFrames(mCaptureStartTime, timeInfo->total_frames_readed, mStreamAttributeSource, &timeInfo->timestamp_get);
+
+ /* Update total_frames_readed after timestamp calculation */
+ timeInfo->total_frames_readed += readFrames;
+
+ ALOGV("%s(), read size = %d, readFrames = %d (bytesPerSample = %d, ch = %d, new total_frames_readed = %d), timestamp = %ld.%09ld -> %ld.%09ld",
+ __FUNCTION__,
+ readBytes, readFrames, bytesPerSample, mStreamAttributeSource.num_channels, timeInfo->total_frames_readed,
+ mCaptureStartTime.tv_sec, mCaptureStartTime.tv_nsec,
+ timeInfo->timestamp_get.tv_sec, timeInfo->timestamp_get.tv_nsec);
+
+ /* Write time stamp to cache to avoid getCapturePosition performance issue */
+ AL_LOCK(mTimeStampLock);
+ mCaptureFramesReaded = timeInfo->total_frames_readed;
+ mCaptureTimeStamp = timeInfo->timestamp_get;
+ AL_UNLOCK(mTimeStampLock);
+
+ return NO_ERROR;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderVOW.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderVOW.cpp
new file mode 100644
index 0000000..5e238b8
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderVOW.cpp
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderVOW"
+
+#include "AudioALSACaptureDataProviderVOW.h"
+
+#include <pthread.h>
+
+#include <sys/prctl.h>
+
+#include "AudioType.h"
+
+#include <hardware_legacy/power.h>
+
+static const char VOW_DEBUG_WAKELOCK_NAME[] = "VOW_DEBUG_WAKELOCK_NAME";
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+//extend buffer for seamless record and normal debug dump together case
+static const uint32_t kReadBufferSize = 0x10400; //0xFA00 + 0x0A00;
+
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataProviderVOW *AudioALSACaptureDataProviderVOW::mAudioALSACaptureDataProviderVOW = NULL;
+AudioALSACaptureDataProviderVOW *AudioALSACaptureDataProviderVOW::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACaptureDataProviderVOW == NULL) {
+ mAudioALSACaptureDataProviderVOW = new AudioALSACaptureDataProviderVOW();
+ }
+ ASSERT(mAudioALSACaptureDataProviderVOW != NULL);
+ ALOGD("%s(), mAudioALSACaptureDataProviderVOW=%p", __FUNCTION__, mAudioALSACaptureDataProviderVOW);
+ return mAudioALSACaptureDataProviderVOW;
+}
+
+AudioALSACaptureDataProviderVOW::AudioALSACaptureDataProviderVOW() {
+ //use for VOW phase 2 debug tempory. Read from VOW kernel driver, not from PCM
+ ALOGD("%s()", __FUNCTION__);
+
+ mCaptureDataProviderType = CAPTURE_PROVIDER_VOW;
+ hReadThread = 0;
+ memset(&vow_info_buf, 0, sizeof(vow_info_buf));
+ mFd = 0;
+ mFd = ::open("/dev/vow", O_RDONLY);
+
+ if (mFd == 0) {
+ ALOGE("%s(), open mFd fail", __FUNCTION__);
+ ASSERT(mFd != 0);
+ }
+ ALOGD("mFd: %d", mFd);
+ ALOGD("%s()-", __FUNCTION__);
+}
+
+AudioALSACaptureDataProviderVOW::~AudioALSACaptureDataProviderVOW() {
+ ALOGD("%s()", __FUNCTION__);
+ if (mFd > 0) {
+ ::close(mFd);
+ mFd = 0;
+ }
+ ALOGD("%s()-", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureDataProviderVOW::open() {
+ ALOGD("%s()+", __FUNCTION__);
+ ASSERT(mEnable == false);
+
+ // config attribute (will used in client SRC/Enh/... later) // TODO(Harvey): query this
+ mStreamAttributeSource.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ mStreamAttributeSource.audio_channel_mask = AUDIO_CHANNEL_IN_MONO;
+ mStreamAttributeSource.num_channels = popcount(mStreamAttributeSource.audio_channel_mask);
+ mStreamAttributeSource.sample_rate = 16000;
+
+ // Reset frames readed counter
+ mStreamAttributeSource.Time_Info.total_frames_readed = 0;
+
+
+ OpenPCMDump(LOG_TAG);
+
+ //open VOW driver
+ // enable pcm
+ // here open audio hardware for register setting
+
+ if (mFd == 0) {
+ ALOGE("%s(), open mFd fail", __FUNCTION__);
+ ASSERT(mFd != 0);
+ }
+
+ memset(&vow_info_buf, 0, sizeof(vow_info_buf));
+
+ // create reading thread
+ //mOpenIndex++;
+ mEnable = true;
+ int ret = pthread_create(&hReadThread, NULL, AudioALSACaptureDataProviderVOW::readThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, VOW_DEBUG_WAKELOCK_NAME);
+ ALOGD("%s()-", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureDataProviderVOW::close() {
+ ALOGD("%s()", __FUNCTION__);
+ int ret;
+
+ mEnable = false;
+ /* first, let vow kernel stop send data */
+ ret = ::ioctl(mFd, VOW_SET_CONTROL, (unsigned int)VOWControlCmd_DisableDebug);
+ ALOGD("%s(), VOWControlCmd_DisableDebug set, ret = %d", __FUNCTION__, ret);
+ if (ret != 0) {
+ ALOGE("%s(), VOWControlCmd_DisableDebug error, ret = %d", __FUNCTION__, ret);
+ }
+ /* second, stop the pthread */
+ pthread_join(hReadThread, NULL);
+ ALOGD("pthread_join hReadThread done");
+
+ ClosePCMDump();
+
+ //close VOW kernel driver
+ release_wake_lock(VOW_DEBUG_WAKELOCK_NAME);
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+void AudioALSACaptureDataProviderVOW::WriteVOWPcmData() {
+ ALOGV("+%s()", __FUNCTION__);
+ if (mPCMDumpFile) {
+ //ALOGD("%s()", __FUNCTION__);
+ AudioDumpPCMData((void *)vow_info_buf.addr, vow_info_buf.size, mPCMDumpFile);
+ }
+ ALOGV("-%s()", __FUNCTION__);
+}
+
+void *AudioALSACaptureDataProviderVOW::readThread(void *arg) {
+ AudioALSACaptureDataProviderVOW *pDataProvider = static_cast<AudioALSACaptureDataProviderVOW *>(arg);
+ uint32_t open_index = pDataProvider->mOpenIndex;
+
+ char nameset[32];
+ sprintf(nameset, "%s%d", __FUNCTION__, pDataProvider->mCaptureDataProviderType);
+ prctl(PR_SET_NAME, (unsigned long)nameset, 0, 0, 0);
+ pDataProvider->setThreadPriority();
+
+ ALOGD("+%s(), pid: %d, tid: %d, kReadBufferSize=%x", __FUNCTION__, getpid(), gettid(), kReadBufferSize);
+
+ // read raw data from alsa driver
+ char linear_buffer[kReadBufferSize];
+ uint32_t Read_Size = kReadBufferSize;
+ uint32_t return_size;
+ //memset(linear_buffer, 0xCCCC, Read_Size);
+ bool enable_debug = false;
+ pDataProvider->vow_info_buf.addr = (long)linear_buffer;
+ pDataProvider->vow_info_buf.size = (long)Read_Size;
+ pDataProvider->vow_info_buf.return_size_addr = (long)&return_size;
+ unsigned long vow_info = (unsigned long)&pDataProvider->vow_info_buf;
+
+ ALOGD("%s(), vow_info = %lu, addr=%lu, size=%ld", __FUNCTION__, vow_info, pDataProvider->vow_info_buf.addr, pDataProvider->vow_info_buf.size);
+
+ int ret = ::ioctl(pDataProvider->mFd, VOW_SET_APREG_INFO, vow_info);
+ ALOGD("%s(), VOW_SET_APREG_INFO set, ret = %d", __FUNCTION__, ret);
+ if (ret != 0) {
+ ALOGE("%s(), VOW_SET_APREG_INFO error, ret = %d", __FUNCTION__, ret);
+ }
+
+ /*ret = ::ioctl(pDataProvider->mFd, VOW_SET_CONTROL, (unsigned int)VOWControlCmd_EnableDebug);
+ ALOGD("%s(), VOWControlCmd_EnableDebug set, ret = %d", __FUNCTION__, ret);
+ if (ret != 0)
+ {
+ ALOGE("%s(), VOWControlCmd_EnableDebug error, ret = %d", __FUNCTION__, ret);
+ }*/
+
+ while (pDataProvider->mEnable == true) {
+#if 0
+ if (open_index != pDataProvider->mOpenIndex) {
+ ALOGD("%s(), open_index(%d) != mOpenIndex(%d), return", __FUNCTION__, open_index, pDataProvider->mOpenIndex);
+ break;
+ }
+#endif
+
+ //ASSERT(pDataProvider->mPcm != NULL);
+ if (!enable_debug) {
+ ALOGI("%s(), VOWControlCmd_EnableDebug set, ret = %d", __FUNCTION__, ret);
+ ret = ::ioctl(pDataProvider->mFd, VOW_SET_CONTROL, (unsigned int)VOWControlCmd_EnableDebug);
+ if (ret != 0) {
+ ALOGE("%s(), VOWControlCmd_EnableDebug error, ret = %d", __FUNCTION__, ret);
+ }
+ enable_debug = true;
+ }
+ int retval = ::ioctl(pDataProvider->mFd, VOW_SET_CONTROL, (unsigned int)VOWControlCmd_ReadVoiceData);
+ //usleep(30 * 1000);
+ if (retval != 0) {
+ ALOGE("%s(), pcm_read() error, retval = %d", __FUNCTION__, retval);
+ } else {
+ ALOGV("%s(), pcm_read() retval = %d", __FUNCTION__, retval);
+ }
+ if (return_size > kReadBufferSize) {
+ return_size = kReadBufferSize;
+ }
+ pDataProvider->mPcmReadBuf.pBufBase = linear_buffer;
+ //pDataProvider->mPcmReadBuf.bufLen = kReadBufferSize + 1; // +1: avoid pRead == pWrite
+ pDataProvider->mPcmReadBuf.bufLen = return_size + 1;
+ pDataProvider->mPcmReadBuf.pRead = linear_buffer;
+ pDataProvider->mPcmReadBuf.pWrite = linear_buffer + return_size;
+ pDataProvider->provideCaptureDataToAllClients(open_index);
+ //pDataProvider->WriteVOWPcmData();
+
+ }
+
+ ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ pthread_exit(NULL);
+ return NULL;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderVoice.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderVoice.cpp
new file mode 100644
index 0000000..9f845af
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderVoice.cpp
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureDataProviderVoice.h"
+
+#include <pthread.h>
+
+#include <sys/prctl.h>
+
+#include "AudioType.h"
+
+#include "SpeechDriverFactory.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderVoice"
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+static const uint32_t kReadBufferSize = 0x2000; // 8k
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSACaptureDataProviderVoice *AudioALSACaptureDataProviderVoice::mAudioALSACaptureDataProviderVoice = NULL;
+AudioALSACaptureDataProviderVoice *AudioALSACaptureDataProviderVoice::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACaptureDataProviderVoice == NULL) {
+ mAudioALSACaptureDataProviderVoice = new AudioALSACaptureDataProviderVoice();
+ }
+ ASSERT(mAudioALSACaptureDataProviderVoice != NULL);
+ return mAudioALSACaptureDataProviderVoice;
+}
+
+AudioALSACaptureDataProviderVoice::AudioALSACaptureDataProviderVoice() {
+ ALOGD("%s()", __FUNCTION__);
+ mCaptureDataProviderType = CAPTURE_PROVIDER_FM_RADIO;
+}
+
+AudioALSACaptureDataProviderVoice::~AudioALSACaptureDataProviderVoice() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureDataProviderVoice::open() {
+ ALOGD("%s()", __FUNCTION__);
+
+ ASSERT(mEnable == false);
+
+ // config attribute (will used in client SRC/Enh/... later)
+ SpeechDriverInterface *pSpeechDriver = SpeechDriverFactory::GetInstance()->GetSpeechDriver();
+
+ mStreamAttributeSource.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ mStreamAttributeSource.num_channels = pSpeechDriver->GetRecordChannelNumber();
+ mStreamAttributeSource.audio_channel_mask = (mStreamAttributeSource.num_channels == 1) ? AUDIO_CHANNEL_IN_MONO : AUDIO_CHANNEL_IN_STEREO;
+ mStreamAttributeSource.sample_rate = pSpeechDriver->GetRecordSampleRate();
+
+ // Reset frames readed counter
+ mStreamAttributeSource.Time_Info.total_frames_readed = 0;
+
+
+ mEnable = true;
+
+ OpenPCMDump(LOG_TAG);
+
+ return SpeechDriverFactory::GetInstance()->GetSpeechDriver()->recordOn();
+}
+
+status_t AudioALSACaptureDataProviderVoice::close() {
+ ALOGD("%s()", __FUNCTION__);
+
+ mEnable = false;
+
+ ClosePCMDump();
+ return SpeechDriverFactory::GetInstance()->GetSpeechDriver()->recordOff();
+}
+
+status_t AudioALSACaptureDataProviderVoice::provideModemRecordDataToProvider(RingBuf modem_record_buf) {
+ if (mEnable == false) {
+ ALOGW("%s(), mEnable == false, return", __FUNCTION__);
+ return NO_INIT;
+ }
+
+ mPcmReadBuf = modem_record_buf;
+ ALOGV("%s(), pBufBase(%p), bufLen(%d), pRead(%p), pWrite(%p)",
+ __FUNCTION__,
+ mPcmReadBuf.pBufBase,
+ mPcmReadBuf.bufLen,
+ mPcmReadBuf.pRead,
+ mPcmReadBuf.pWrite);
+
+
+ provideCaptureDataToAllClients(mOpenIndex);
+
+ return NO_ERROR;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderVoiceDL.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderVoiceDL.cpp
new file mode 100644
index 0000000..b7a3b45
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderVoiceDL.cpp
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureDataProviderVoiceDL.h"
+
+#include <pthread.h>
+
+#include <sys/prctl.h>
+
+#include "AudioType.h"
+
+#include "SpeechDataProcessingHandler.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderDL"
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+AudioLock mCaptureDataProviderVoiceDLLock;
+AudioALSACaptureDataProviderVoiceDL *AudioALSACaptureDataProviderVoiceDL::mAudioALSACaptureDataProviderVoiceDL = NULL;
+AudioALSACaptureDataProviderVoiceDL *AudioALSACaptureDataProviderVoiceDL::getInstance() {
+ AL_AUTOLOCK(mCaptureDataProviderVoiceDLLock);
+
+ if (mAudioALSACaptureDataProviderVoiceDL == NULL) {
+ mAudioALSACaptureDataProviderVoiceDL = new AudioALSACaptureDataProviderVoiceDL();
+ }
+ ASSERT(mAudioALSACaptureDataProviderVoiceDL != NULL);
+ return mAudioALSACaptureDataProviderVoiceDL;
+}
+
+bool AudioALSACaptureDataProviderVoiceDL::hasInstance() {
+ return mAudioALSACaptureDataProviderVoiceDL != NULL ? true : false;
+}
+
+AudioALSACaptureDataProviderVoiceDL::AudioALSACaptureDataProviderVoiceDL() {
+ ALOGD("%s()", __FUNCTION__);
+ mCaptureDataProviderType = CAPTURE_PROVIDER_VOICE;
+ memset(&mRawDataRingBuf, 0, sizeof(mRawDataRingBuf));
+ mPeriodBufferSize = 0;
+}
+
+AudioALSACaptureDataProviderVoiceDL::~AudioALSACaptureDataProviderVoiceDL() {
+ ALOGD("+%s()\n", __FUNCTION__);
+ AL_AUTOLOCK(mCaptureDataProviderVoiceDLLock);
+
+ mAudioALSACaptureDataProviderVoiceDL = NULL;
+ SpeechDataProcessingHandler::destoryInstanceSafely();
+ ALOGD("-%s()\n", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureDataProviderVoiceDL::open() {
+ ALOGD("%s()", __FUNCTION__);
+
+ ASSERT(mEnable == false);
+
+ SpeechDataProcessingHandler::getInstance()->getStreamAttributeSource(SpeechDataProcessingHandler::VOICE_DL_CALLER, &mStreamAttributeSource);
+
+ mPeriodBufferSize = getPeriodBufSize(&mStreamAttributeSource, UPLINK_NORMAL_LATENCY_MS);
+ mRawDataRingBuf.bufLen = mPeriodBufferSize * 4;
+
+ /* Setup ringbuf */
+ mRawDataRingBuf.pBufBase = new char[mRawDataRingBuf.bufLen];
+ mRawDataRingBuf.pRead = mRawDataRingBuf.pBufBase;
+ mRawDataRingBuf.pWrite = mRawDataRingBuf.pBufBase;
+ mRawDataRingBuf.pBufEnd = mRawDataRingBuf.pBufBase + mRawDataRingBuf.bufLen;
+
+ ALOGD("%s(), mStreamAttributeSource: audio_format = %d, num_channels = %d, audio_channel_mask = %x, sample_rate = %d, periodBufferSize = %d\n",
+ __FUNCTION__, mStreamAttributeSource.audio_format, mStreamAttributeSource.num_channels, mStreamAttributeSource.audio_channel_mask, mStreamAttributeSource.sample_rate, mPeriodBufferSize);
+
+ mEnable = true;
+
+ OpenPCMDump(LOG_TAG);
+
+ return SpeechDataProcessingHandler::getInstance()->recordOn(RECORD_TYPE_DL);
+}
+
+status_t AudioALSACaptureDataProviderVoiceDL::close() {
+ ALOGD("%s()", __FUNCTION__);
+
+ mEnable = false;
+
+ delete[] mRawDataRingBuf.pBufBase;
+ memset(&mRawDataRingBuf, 0, sizeof(mRawDataRingBuf));
+
+ ClosePCMDump();
+ return SpeechDataProcessingHandler::getInstance()->recordOff(RECORD_TYPE_DL);
+}
+
+status_t AudioALSACaptureDataProviderVoiceDL::provideModemRecordDataToProvider(RingBuf modem_record_buf) {
+ if (mEnable == false) {
+ //ALOGW("%s(), already closed, return", __FUNCTION__);
+ return NO_INIT;
+ }
+
+ int cntInRingBufs = RingBuf_getDataCount(&modem_record_buf);
+ int freeSpaceInRingBuft = RingBuf_getFreeSpace(&mRawDataRingBuf);
+
+ RingBuf_copyFromRingBuf(&mRawDataRingBuf, &modem_record_buf, RingBuf_getDataCount(&modem_record_buf));
+
+ if ((uint32_t)RingBuf_getDataCount(&mRawDataRingBuf) >= mPeriodBufferSize) {
+ mPcmReadBuf = mRawDataRingBuf;
+ ALOGD("%s(), Data enough(%d), pBufBase(%p), bufLen(%d), pRead(%p), pWrite(%p)",
+ __FUNCTION__,
+ RingBuf_getDataCount(&mPcmReadBuf),
+ mPcmReadBuf.pBufBase,
+ mPcmReadBuf.bufLen,
+ mPcmReadBuf.pRead,
+ mPcmReadBuf.pWrite);
+
+ provideCaptureDataToAllClients(mOpenIndex);
+
+ // All data consumed, reset ring buf
+ mRawDataRingBuf.pRead = mRawDataRingBuf.pWrite;
+ } else {
+ ALOGD("%s(), Data is not enough(%d), pBufBase(%p), bufLen(%d), pRead(%p), pWrite(%p)",
+ __FUNCTION__,
+ RingBuf_getDataCount(&mRawDataRingBuf),
+ mRawDataRingBuf.pBufBase,
+ mRawDataRingBuf.bufLen,
+ mRawDataRingBuf.pRead,
+ mRawDataRingBuf.pWrite);
+ }
+ return NO_ERROR;
+}
+
+
+} // end of namespace android
+
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderVoiceMix.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderVoiceMix.cpp
new file mode 100644
index 0000000..a8eae2c
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderVoiceMix.cpp
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureDataProviderVoiceMix.h"
+
+#include <pthread.h>
+
+#include <sys/prctl.h>
+
+#include "AudioType.h"
+
+#include "SpeechDataProcessingHandler.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderMix"
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+AudioLock mCaptureDataProviderVoiceMixLock;
+AudioALSACaptureDataProviderVoiceMix *AudioALSACaptureDataProviderVoiceMix::mAudioALSACaptureDataProviderVoiceMix = NULL;
+AudioALSACaptureDataProviderVoiceMix *AudioALSACaptureDataProviderVoiceMix::getInstance() {
+ AL_AUTOLOCK(mCaptureDataProviderVoiceMixLock);
+
+ if (mAudioALSACaptureDataProviderVoiceMix == NULL) {
+ mAudioALSACaptureDataProviderVoiceMix = new AudioALSACaptureDataProviderVoiceMix();
+ }
+ ASSERT(mAudioALSACaptureDataProviderVoiceMix != NULL);
+ return mAudioALSACaptureDataProviderVoiceMix;
+}
+
+bool AudioALSACaptureDataProviderVoiceMix::hasInstance() {
+ return mAudioALSACaptureDataProviderVoiceMix != NULL ? true : false;
+}
+
+AudioALSACaptureDataProviderVoiceMix::AudioALSACaptureDataProviderVoiceMix() {
+ ALOGD("%s()", __FUNCTION__);
+ mCaptureDataProviderType = CAPTURE_PROVIDER_VOICE;
+ memset(&mRawDataRingBuf, 0, sizeof(mRawDataRingBuf));
+ mPeriodBufferSize = 0;
+}
+
+AudioALSACaptureDataProviderVoiceMix::~AudioALSACaptureDataProviderVoiceMix() {
+ ALOGD("+%s()\n", __FUNCTION__);
+ AL_AUTOLOCK(mCaptureDataProviderVoiceMixLock);
+
+ mAudioALSACaptureDataProviderVoiceMix = NULL;
+ SpeechDataProcessingHandler::destoryInstanceSafely();
+ ALOGD("-%s()\n", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureDataProviderVoiceMix::open() {
+ ALOGD("%s()", __FUNCTION__);
+
+ ASSERT(mEnable == false);
+
+ SpeechDataProcessingHandler::getInstance()->getStreamAttributeSource(SpeechDataProcessingHandler::VOICE_MIX_CALLER, &mStreamAttributeSource);
+
+ mPeriodBufferSize = getPeriodBufSize(&mStreamAttributeSource, UPLINK_NORMAL_LATENCY_MS);
+ mRawDataRingBuf.bufLen = mPeriodBufferSize * 4;
+
+ /* Setup ringbuf */
+ mRawDataRingBuf.pBufBase = new char[mRawDataRingBuf.bufLen];
+ mRawDataRingBuf.pRead = mRawDataRingBuf.pBufBase;
+ mRawDataRingBuf.pWrite = mRawDataRingBuf.pBufBase;
+ mRawDataRingBuf.pBufEnd = mRawDataRingBuf.pBufBase + mRawDataRingBuf.bufLen;
+
+ ALOGD("%s(), mStreamAttributeSource: audio_format = %d, num_channels = %d, audio_channel_mask = %x, sample_rate = %d, periodBufferSize = %d\n",
+ __FUNCTION__, mStreamAttributeSource.audio_format, mStreamAttributeSource.num_channels, mStreamAttributeSource.audio_channel_mask, mStreamAttributeSource.sample_rate, mPeriodBufferSize);
+
+ mEnable = true;
+
+ OpenPCMDump(LOG_TAG);
+
+ return SpeechDataProcessingHandler::getInstance()->recordOn(RECORD_TYPE_MIX);
+}
+
+status_t AudioALSACaptureDataProviderVoiceMix::close() {
+ ALOGD("%s()", __FUNCTION__);
+
+ mEnable = false;
+
+ delete[] mRawDataRingBuf.pBufBase;
+ memset(&mRawDataRingBuf, 0, sizeof(mRawDataRingBuf));
+
+ ClosePCMDump();
+
+ return SpeechDataProcessingHandler::getInstance()->recordOff(RECORD_TYPE_MIX);
+}
+
+status_t AudioALSACaptureDataProviderVoiceMix::provideModemRecordDataToProvider(RingBuf modem_record_buf) {
+ if (mEnable == false) {
+ //ALOGW("%s(), already closed, return", __FUNCTION__);
+ return NO_INIT;
+ }
+
+ int cntInRingBufs = RingBuf_getDataCount(&modem_record_buf);
+ int freeSpaceInRingBuft = RingBuf_getFreeSpace(&mRawDataRingBuf);
+
+ RingBuf_copyFromRingBuf(&mRawDataRingBuf, &modem_record_buf, RingBuf_getDataCount(&modem_record_buf));
+
+ if ((uint32_t)RingBuf_getDataCount(&mRawDataRingBuf) >= mPeriodBufferSize) {
+ mPcmReadBuf = mRawDataRingBuf;
+ ALOGD("%s(), Data enough(%d), pBufBase(%p), bufLen(%d), pRead(%p), pWrite(%p)",
+ __FUNCTION__,
+ RingBuf_getDataCount(&mPcmReadBuf),
+ mPcmReadBuf.pBufBase,
+ mPcmReadBuf.bufLen,
+ mPcmReadBuf.pRead,
+ mPcmReadBuf.pWrite);
+
+ provideCaptureDataToAllClients(mOpenIndex);
+
+ // All data consumed, reset ring buf
+ mRawDataRingBuf.pRead = mRawDataRingBuf.pWrite;
+ } else {
+ ALOGD("%s(), Data is not enough(%d), pBufBase(%p), bufLen(%d), pRead(%p), pWrite(%p)",
+ __FUNCTION__,
+ RingBuf_getDataCount(&mRawDataRingBuf),
+ mRawDataRingBuf.pBufBase,
+ mRawDataRingBuf.bufLen,
+ mRawDataRingBuf.pRead,
+ mRawDataRingBuf.pWrite);
+ }
+
+ return NO_ERROR;
+}
+
+
+} // end of namespace android
+
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderVoiceUL.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderVoiceUL.cpp
new file mode 100644
index 0000000..f3d0086
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureDataProviderVoiceUL.cpp
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureDataProviderVoiceUL.h"
+
+#include <pthread.h>
+
+#include <sys/prctl.h>
+
+#include "AudioType.h"
+
+#include "SpeechDataProcessingHandler.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureDataProviderUL"
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+AudioLock mCaptureDataProviderVoiceULLock;
+AudioALSACaptureDataProviderVoiceUL *AudioALSACaptureDataProviderVoiceUL::mAudioALSACaptureDataProviderVoiceUL = NULL;
+AudioALSACaptureDataProviderVoiceUL *AudioALSACaptureDataProviderVoiceUL::getInstance() {
+ AL_AUTOLOCK(mCaptureDataProviderVoiceULLock);
+
+ if (mAudioALSACaptureDataProviderVoiceUL == NULL) {
+ mAudioALSACaptureDataProviderVoiceUL = new AudioALSACaptureDataProviderVoiceUL();
+ }
+ ASSERT(mAudioALSACaptureDataProviderVoiceUL != NULL);
+ return mAudioALSACaptureDataProviderVoiceUL;
+}
+
+bool AudioALSACaptureDataProviderVoiceUL::hasInstance() {
+ return mAudioALSACaptureDataProviderVoiceUL != NULL ? true : false;
+}
+
+AudioALSACaptureDataProviderVoiceUL::AudioALSACaptureDataProviderVoiceUL() {
+ ALOGD("%s()", __FUNCTION__);
+ mCaptureDataProviderType = CAPTURE_PROVIDER_VOICE;
+ memset(&mRawDataRingBuf, 0, sizeof(mRawDataRingBuf));
+ mPeriodBufferSize = 0;
+}
+
+AudioALSACaptureDataProviderVoiceUL::~AudioALSACaptureDataProviderVoiceUL() {
+ ALOGD("+%s()\n", __FUNCTION__);
+ AL_AUTOLOCK(mCaptureDataProviderVoiceULLock);
+
+ mAudioALSACaptureDataProviderVoiceUL = NULL;
+ SpeechDataProcessingHandler::destoryInstanceSafely();
+
+ ALOGD("-%s()\n", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureDataProviderVoiceUL::open() {
+ ALOGD("%s()", __FUNCTION__);
+ ASSERT(mEnable == false);
+
+ SpeechDataProcessingHandler::getInstance()->getStreamAttributeSource(SpeechDataProcessingHandler::VOICE_UL_CALLER, &mStreamAttributeSource);
+ mPeriodBufferSize = getPeriodBufSize(&mStreamAttributeSource, UPLINK_NORMAL_LATENCY_MS);
+ mRawDataRingBuf.bufLen = mPeriodBufferSize * 4;
+
+ /* Setup ringbuf */
+ mRawDataRingBuf.pBufBase = new char[mRawDataRingBuf.bufLen];
+ mRawDataRingBuf.pRead = mRawDataRingBuf.pBufBase;
+ mRawDataRingBuf.pWrite = mRawDataRingBuf.pBufBase;
+ mRawDataRingBuf.pBufEnd = mRawDataRingBuf.pBufBase + mRawDataRingBuf.bufLen;
+
+ ALOGD("%s(), mStreamAttributeSource: audio_format = %d, num_channels = %d, audio_channel_mask = %x, sample_rate = %d, periodBufferSize = %d\n",
+ __FUNCTION__, mStreamAttributeSource.audio_format, mStreamAttributeSource.num_channels, mStreamAttributeSource.audio_channel_mask, mStreamAttributeSource.sample_rate, mPeriodBufferSize);
+
+ mEnable = true;
+
+ OpenPCMDump(LOG_TAG);
+
+ return SpeechDataProcessingHandler::getInstance()->recordOn(RECORD_TYPE_UL);
+}
+
+status_t AudioALSACaptureDataProviderVoiceUL::close() {
+ ALOGD("%s()", __FUNCTION__);
+
+ mEnable = false;
+
+ delete[] mRawDataRingBuf.pBufBase;
+ memset(&mRawDataRingBuf, 0, sizeof(mRawDataRingBuf));
+
+ ClosePCMDump();
+
+ return SpeechDataProcessingHandler::getInstance()->recordOff(RECORD_TYPE_UL);
+}
+
+status_t AudioALSACaptureDataProviderVoiceUL::provideModemRecordDataToProvider(RingBuf modem_record_buf) {
+ if (mEnable == false) {
+ //ALOGW("%s(), already closed, return", __FUNCTION__);
+ return NO_INIT;
+ }
+
+ int cntInRingBufs = RingBuf_getDataCount(&modem_record_buf);
+ int freeSpaceInRingBuft = RingBuf_getFreeSpace(&mRawDataRingBuf);
+
+ RingBuf_copyFromRingBuf(&mRawDataRingBuf, &modem_record_buf, RingBuf_getDataCount(&modem_record_buf));
+
+ if ((uint32_t)RingBuf_getDataCount(&mRawDataRingBuf) >= mPeriodBufferSize) {
+ mPcmReadBuf = mRawDataRingBuf;
+ ALOGV("%s(), Data enough(%d), pBufBase(%p), bufLen(%d), pRead(%p), pWrite(%p)",
+ __FUNCTION__,
+ RingBuf_getDataCount(&mPcmReadBuf),
+ mPcmReadBuf.pBufBase,
+ mPcmReadBuf.bufLen,
+ mPcmReadBuf.pRead,
+ mPcmReadBuf.pWrite);
+
+ provideCaptureDataToAllClients(mOpenIndex);
+
+ // All data consumed, reset ring buf
+ mRawDataRingBuf.pRead = mRawDataRingBuf.pWrite;
+ } else {
+ ALOGD("%s(), Data is not enough(%d), pBufBase(%p), bufLen(%d), pRead(%p), pWrite(%p)",
+ __FUNCTION__,
+ RingBuf_getDataCount(&mRawDataRingBuf),
+ mRawDataRingBuf.pBufBase,
+ mRawDataRingBuf.bufLen,
+ mRawDataRingBuf.pRead,
+ mRawDataRingBuf.pWrite);
+ }
+
+ return NO_ERROR;
+}
+
+
+} // end of namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerAAudio.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerAAudio.cpp
new file mode 100644
index 0000000..01f47e5
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerAAudio.cpp
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureHandlerAAudio.h"
+#include "AudioALSAHardwareResourceManager.h"
+#include "AudioALSACaptureDataProviderAAudio.h"
+#include "AudioVolumeFactory.h"
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureHandlerAAudio"
+
+namespace android {
+
+
+AudioALSACaptureHandlerAAudio::AudioALSACaptureHandlerAAudio(stream_attribute_t *stream_attribute_target) :
+ AudioALSACaptureHandlerBase(stream_attribute_target),
+ mDataProvider(NULL) {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+AudioALSACaptureHandlerAAudio::~AudioALSACaptureHandlerAAudio() {
+ ALOGD("+%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureHandlerAAudio::init() {
+ ALOGD("%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerAAudio::open() {
+ ALOGD("+%s()", __FUNCTION__);
+
+#if defined(MTK_POWERHAL_AUDIO_LATENCY)
+ if (mStreamAttributeSource.mPowerHalEnable) {
+ power_hal_hint(POWERHAL_LATENCY_UL, true);
+ }
+#endif
+
+
+ mDataProvider = AudioALSACaptureDataProviderAAudio::getInstance();
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerAAudio::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ mDataProvider->close();
+ AudioALSACaptureDataProviderAAudio::freeInstance();
+
+#if defined(MTK_POWERHAL_AUDIO_LATENCY)
+ if (mStreamAttributeSource.mPowerHalEnable) {
+ power_hal_hint(POWERHAL_LATENCY_UL, false);
+ }
+#endif
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerAAudio::routing(const audio_devices_t input_device) {
+ ALOGD("+%s()", __FUNCTION__);
+
+ mHardwareResourceManager->changeInputDevice(input_device);
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+ssize_t AudioALSACaptureHandlerAAudio::read(void *buffer __unused, ssize_t bytes __unused) {
+ ALOGD("%s()", __FUNCTION__);
+ return bytes;
+}
+
+
+status_t AudioALSACaptureHandlerAAudio::start() {
+ ALOGD("+%s", __FUNCTION__);
+
+ int ret = INVALID_OPERATION;
+ if (mDataProvider) {
+ ret = mDataProvider->start();
+ }
+
+ ALOGD("-%s", __FUNCTION__);
+ return ret;
+}
+
+
+status_t AudioALSACaptureHandlerAAudio::stop() {
+ ALOGD("+%s", __FUNCTION__);
+
+ int ret = INVALID_OPERATION;
+ if (mDataProvider) {
+ ret = mDataProvider->stop();
+ }
+
+ ALOGD("-%s", __FUNCTION__);
+ return ret;
+}
+
+
+status_t AudioALSACaptureHandlerAAudio::createMmapBuffer(int32_t min_size_frames,
+ struct audio_mmap_buffer_info *info) {
+ ALOGD("+%s", __FUNCTION__);
+
+ int ret = INVALID_OPERATION;
+
+ // create AudioALSACaptureDataProviderAAudio
+ open();
+
+ // apply gain
+ AudioVolumeInterface *pVolume = AudioVolumeFactory::CreateAudioVolumeController();
+ pVolume->SetCaptureGain(mStreamAttributeTarget->audio_mode, mStreamAttributeTarget->input_source,
+ mStreamAttributeTarget->input_device, mStreamAttributeTarget->output_devices);
+
+ if (mDataProvider) {
+ // config attribute for input device
+ mDataProvider->configStreamAttribute(mStreamAttributeTarget);
+
+ // create mmap buffer
+ ret = mDataProvider->createMmapBuffer(min_size_frames, info);
+ }
+
+ ALOGD("-%s", __FUNCTION__);
+ return ret;
+}
+
+
+status_t AudioALSACaptureHandlerAAudio::getMmapPosition(struct audio_mmap_position *position) {
+ int ret = INVALID_OPERATION;
+ //ALOGD("+%s", __FUNCTION__);
+
+ if (mDataProvider) {
+ ret = mDataProvider->getMmapPosition(position);
+ }
+
+ //ALOGD("-%s", __FUNCTION__);
+ return ret;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerAEC.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerAEC.cpp
new file mode 100644
index 0000000..cff128c
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerAEC.cpp
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureHandlerAEC.h"
+
+#include "AudioALSAHardwareResourceManager.h"
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+#include "AudioALSACaptureDataClientAurisysNormal.h"
+#endif
+#include "AudioALSACaptureDataClient.h"
+#include "AudioALSACaptureDataProviderNormal.h"
+#include "AudioALSACaptureDataProviderBTSCO.h"
+#include "AudioALSACaptureDataProviderBTCVSD.h"
+#include "AudioALSACaptureDataProviderEchoRef.h"
+#include "AudioALSACaptureDataProviderEchoRefBTCVSD.h"
+#include "AudioALSACaptureDataProviderEchoRefBTSCO.h"
+#include "AudioALSACaptureDataProviderEchoRefExt.h"
+
+#include "AudioSmartPaController.h"
+
+#include "WCNChipController.h"
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+#include "AudioDetectPulse.h"
+#endif
+
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACaptureHandlerAEC"
+
+namespace android {
+
+//static FILE *pOutFile = NULL;
+
+AudioALSACaptureHandlerAEC::AudioALSACaptureHandlerAEC(stream_attribute_t *stream_attribute_target) :
+ AudioALSACaptureHandlerBase(stream_attribute_target) {
+ ALOGD("%s()", __FUNCTION__);
+
+ init();
+}
+
+
+AudioALSACaptureHandlerAEC::~AudioALSACaptureHandlerAEC() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureHandlerAEC::init() {
+ mCaptureHandlerType = CAPTURE_HANDLER_AEC;
+ memset(&mStreamAttributeTargetEchoRef, 0, sizeof(mStreamAttributeTargetEchoRef));
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerAEC::open() {
+
+ ALOGD("+%s(), input_device = 0x%x, input_source = 0x%x, sample_rate=%d, num_channels=%d, output_devices=0x%x", __FUNCTION__,
+ mStreamAttributeTarget->input_device,
+ mStreamAttributeTarget->input_source,
+ mStreamAttributeTarget->sample_rate,
+ mStreamAttributeTarget->num_channels,
+ mStreamAttributeTarget->output_devices);
+
+ ASSERT(mCaptureDataClient == NULL);
+
+#if 0 //enable for check EchoRef data is correct
+ //mCaptureDataClient = new AudioALSACaptureDataClient(AudioALSACaptureDataProviderNormal::getInstance(), mStreamAttributeTarget);
+ //mCaptureDataClient = new AudioALSACaptureDataClient(AudioALSACaptureDataProviderEchoRef::getInstance(), mStreamAttributeTarget);
+ mCaptureDataClient = new AudioALSACaptureDataClient(AudioALSACaptureDataProviderEchoRefExt::getInstance(), mStreamAttributeTarget);
+#else
+
+ /* get data provider singleton for mic source */
+ AudioALSACaptureDataProviderBase *pDataProvider = NULL;
+
+ if (mStreamAttributeTarget->input_device == AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+ // open BT data provider
+ if (WCNChipController::GetInstance()->IsBTMergeInterfaceSupported() == true) {
+ pDataProvider = AudioALSACaptureDataProviderBTSCO::getInstance();
+ } else {
+ pDataProvider = AudioALSACaptureDataProviderBTCVSD::getInstance();
+ }
+ } else {
+ pDataProvider = AudioALSACaptureDataProviderNormal::getInstance();
+ }
+ ASSERT(pDataProvider != NULL);
+
+
+ /* get data provider singleton for echo ref */
+ AudioALSACaptureDataProviderBase *pDataProviderEchoRef = NULL;
+
+ if (AudioSmartPaController::getInstance()->isHwDspSpkProtect(mStreamAttributeTarget->output_devices)) {
+ pDataProviderEchoRef = AudioALSACaptureDataProviderEchoRefExt::getInstance();
+ } else if (mStreamAttributeTarget->input_device == AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+ // open BT echoref data provider
+ if (WCNChipController::GetInstance()->IsBTMergeInterfaceSupported() == true) {
+ pDataProviderEchoRef = AudioALSACaptureDataProviderEchoRefBTSCO::getInstance();
+ } else {
+ pDataProviderEchoRef = AudioALSACaptureDataProviderEchoRefBTCVSD::getInstance();
+ }
+ } else {
+ pDataProviderEchoRef = AudioALSACaptureDataProviderEchoRef::getInstance();
+ }
+
+ ASSERT(pDataProviderEchoRef != NULL);
+
+
+ /* new data client */
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ mCaptureDataClient = new AudioALSACaptureDataClientAurisysNormal(
+ pDataProvider,
+ mStreamAttributeTarget,
+ pDataProviderEchoRef);
+#else
+ mCaptureDataClient = new AudioALSACaptureDataClient(pDataProvider, mStreamAttributeTarget);
+ if (mCaptureDataClient != NULL) {
+ memcpy(&mStreamAttributeTargetEchoRef, mStreamAttributeTarget, sizeof(stream_attribute_t));
+ mCaptureDataClient->AddEchoRefDataProvider(pDataProviderEchoRef, &mStreamAttributeTargetEchoRef);
+ }
+#endif
+#endif //end of "enable for check EchoRef data is correct"
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerAEC::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ ASSERT(mCaptureDataClient != NULL);
+ delete mCaptureDataClient;
+ mCaptureDataClient = NULL;
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerAEC::routing(const audio_devices_t input_device) {
+ if (mStreamAttributeTarget->output_devices & AUDIO_DEVICE_OUT_ALL_SCO) {
+ mStreamAttributeTarget->input_device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ }
+
+ mHardwareResourceManager->changeInputDevice(input_device);
+ return NO_ERROR;
+}
+
+
+ssize_t AudioALSACaptureHandlerAEC::read(void *buffer, ssize_t bytes) {
+ ALOGV("%s()", __FUNCTION__);
+
+ mCaptureDataClient->read(buffer, bytes);
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+ AudioDetectPulse::doDetectPulse(TAG_CAPTURE_HANDLER, PULSE_LEVEL, 0, (void *)buffer,
+ bytes, mStreamAttributeTarget->audio_format,
+ mStreamAttributeTarget->num_channels,
+ mStreamAttributeTarget->sample_rate);
+#endif
+
+#if 0
+ if (pOutFile != NULL) {
+ fwrite(buffer, sizeof(char), bytes, pOutFile);
+ }
+#endif
+
+ return bytes;
+}
+
+status_t AudioALSACaptureHandlerAEC::UpdateBesRecParam() {
+ ALOGD("+%s()", __FUNCTION__);
+ if (mCaptureDataClient != NULL) {
+ mCaptureDataClient->UpdateBesRecParam();
+ }
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerANC.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerANC.cpp
new file mode 100644
index 0000000..0315022
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerANC.cpp
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureHandlerANC.h"
+
+#include "AudioALSACaptureDataClient.h"
+#include "AudioALSACaptureDataProviderANC.h"
+#include "AudioALSAStreamManager.h"
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACaptureHandlerANC"
+
+namespace android {
+
+AudioALSACaptureHandlerANC::AudioALSACaptureHandlerANC(stream_attribute_t *stream_attribute_target) :
+ AudioALSACaptureHandlerBase(stream_attribute_target) {
+ ALOGD("%s()", __FUNCTION__);
+
+ init();
+}
+
+
+AudioALSACaptureHandlerANC::~AudioALSACaptureHandlerANC() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureHandlerANC::init() {
+ ALOGD("%s()", __FUNCTION__);
+ mCaptureHandlerType = CAPTURE_HANDLER_ANC;
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerANC::open() {
+ ALOGD("+%s(), input_device = 0x%x, input_source = 0x%x",
+ __FUNCTION__, mStreamAttributeTarget->input_device, mStreamAttributeTarget->input_source);
+ if (mSupportConcurrencyInCall == false && AudioALSAStreamManager::getInstance()->isModeInPhoneCall() == true) {
+ mCaptureDataClient = NULL;
+ ALOGD("-%s() don't support ANC Record at incall mode", __FUNCTION__);
+ return NO_ERROR;
+ }
+ // TODO: check ANC is already opened?
+
+ ASSERT(mCaptureDataClient == NULL);
+ mCaptureDataClient = new AudioALSACaptureDataClient(AudioALSACaptureDataProviderANC::getInstance(), mStreamAttributeTarget);
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerANC::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ if (mCaptureDataClient != NULL) {
+ //ASSERT(mCaptureDataClient != NULL);
+ delete mCaptureDataClient;
+ }
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerANC::routing(const audio_devices_t input_device __unused) {
+ WARNING("Not support!!");
+ return INVALID_OPERATION;
+}
+
+
+ssize_t AudioALSACaptureHandlerANC::read(void *buffer, ssize_t bytes) {
+ ALOGV("%s()", __FUNCTION__);
+ if (mCaptureDataClient == NULL) {
+ memset(buffer, 0, bytes);
+ size_t wordSize = 0;
+ switch (mStreamAttributeTarget->audio_format) {
+ case AUDIO_FORMAT_PCM_8_BIT: {
+ wordSize = sizeof(int8_t);
+ break;
+ }
+ case AUDIO_FORMAT_PCM_16_BIT: {
+ wordSize = sizeof(int16_t);
+ break;
+ }
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ case AUDIO_FORMAT_PCM_32_BIT: {
+ wordSize = sizeof(int32_t);
+ break;
+ }
+ default: {
+ wordSize = sizeof(int16_t);
+ ALOGW("%s(), wrong format(0x%x), default use wordSize = %zu", __FUNCTION__, mStreamAttributeTarget->audio_format, wordSize);
+ break;
+ }
+ }
+ size_t sleepus = ((bytes * 1000) / ((mStreamAttributeTarget->sample_rate / 1000) * mStreamAttributeTarget->num_channels * wordSize));
+ ALOGD("%s(), sleepus = %zu", __FUNCTION__, sleepus);
+ usleep(sleepus);
+ return bytes;
+ }
+ return mCaptureDataClient->read(buffer, bytes);
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerBT.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerBT.cpp
new file mode 100644
index 0000000..f3fc9e7
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerBT.cpp
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureHandlerBT.h"
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+#include "AudioALSACaptureDataClientAurisysNormal.h"
+#else
+#include "AudioALSACaptureDataClient.h"
+#endif
+#include "AudioALSACaptureDataProviderBTSCO.h"
+#include "AudioALSACaptureDataProviderBTCVSD.h"
+
+#include "WCNChipController.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureHandlerBT"
+
+namespace android {
+
+AudioALSACaptureHandlerBT::AudioALSACaptureHandlerBT(stream_attribute_t *stream_attribute_target) :
+ AudioALSACaptureHandlerBase(stream_attribute_target) {
+ ALOGD("%s()", __FUNCTION__);
+ // Should reopen to routing to use HandlerVoice when BTCVSD
+ mSupportConcurrencyInCall = false;
+ init();
+}
+
+
+AudioALSACaptureHandlerBT::~AudioALSACaptureHandlerBT() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureHandlerBT::init() {
+ ALOGD("%s()", __FUNCTION__);
+ mCaptureHandlerType = CAPTURE_HANDLER_BT;
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerBT::open() {
+ ALOGD("+%s(), input_device = 0x%x, input_source = 0x%x",
+ __FUNCTION__, mStreamAttributeTarget->input_device, mStreamAttributeTarget->input_source);
+
+ ASSERT(mCaptureDataClient == NULL);
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ if (WCNChipController::GetInstance()->IsBTMergeInterfaceSupported() == true) {
+ mCaptureDataClient = new AudioALSACaptureDataClientAurisysNormal(AudioALSACaptureDataProviderBTSCO::getInstance(), mStreamAttributeTarget, NULL);
+ } else {
+ mCaptureDataClient = new AudioALSACaptureDataClientAurisysNormal(AudioALSACaptureDataProviderBTCVSD::getInstance(), mStreamAttributeTarget, NULL);
+ }
+#else
+ if (WCNChipController::GetInstance()->IsBTMergeInterfaceSupported() == true) {
+ mCaptureDataClient = new AudioALSACaptureDataClient(AudioALSACaptureDataProviderBTSCO::getInstance(), mStreamAttributeTarget);
+ } else {
+ mCaptureDataClient = new AudioALSACaptureDataClient(AudioALSACaptureDataProviderBTCVSD::getInstance(), mStreamAttributeTarget);
+ }
+#endif
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerBT::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ ASSERT(mCaptureDataClient != NULL);
+ delete mCaptureDataClient;
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerBT::routing(const audio_devices_t input_device __unused) {
+ WARNING("Not support!!");
+ return INVALID_OPERATION;
+}
+
+
+ssize_t AudioALSACaptureHandlerBT::read(void *buffer, ssize_t bytes) {
+ ALOGV("%s()", __FUNCTION__);
+
+ return mCaptureDataClient->read(buffer, bytes);
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerBase.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerBase.cpp
new file mode 100644
index 0000000..838dd0b
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerBase.cpp
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureHandlerBase.h"
+
+#include "IAudioALSACaptureDataClient.h"
+#include "AudioALSADataProcessor.h"
+#include "AudioALSAHardwareResourceManager.h"
+
+//#include "AudioALSACaptureDataProvider.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureHandlerBase"
+
+namespace android {
+
+AudioALSACaptureHandlerBase::AudioALSACaptureHandlerBase(stream_attribute_t *stream_attribute_target) :
+ mHardwareResourceManager(AudioALSAHardwareResourceManager::getInstance()),
+ mCaptureDataClient(NULL),
+ mStreamAttributeTarget(stream_attribute_target),
+ mSupportConcurrencyInCall(false),
+ mCaptureHandlerType(CAPTURE_HANDLER_BASE),
+ mDataProcessor(AudioALSADataProcessor::getInstance()),
+ mIdentity(0xFFFFFFFF) {
+ ALOGV("%s()", __FUNCTION__);
+
+ init();
+}
+
+
+AudioALSACaptureHandlerBase::~AudioALSACaptureHandlerBase() {
+ ALOGV("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureHandlerBase::init() {
+ return NO_ERROR;
+}
+
+int64_t AudioALSACaptureHandlerBase::getRawStartFrameCount() {
+ return mCaptureDataClient->getRawStartFrameCount();
+}
+
+status_t AudioALSACaptureHandlerBase::UpdateBesRecParam() {
+ ALOGD("%s()", __FUNCTION__);
+
+ return NO_ERROR;
+}
+
+bool AudioALSACaptureHandlerBase::isSupportConcurrencyInCall() {
+ ALOGD("%s()", __FUNCTION__);
+
+ return mSupportConcurrencyInCall;
+}
+
+capture_handler_t AudioALSACaptureHandlerBase::getCaptureHandlerType() {
+ ALOGD("%s(), mCaptureHandlerType = %x", __FUNCTION__, mCaptureHandlerType);
+ return mCaptureHandlerType;
+}
+
+int AudioALSACaptureHandlerBase::getCapturePosition(int64_t *frames, int64_t *time) {
+ if (mCaptureDataClient == NULL || frames == NULL || time == NULL) {
+ return -ENODATA;
+ }
+
+ return mCaptureDataClient->getCapturePosition(frames, time);
+}
+
+status_t AudioALSACaptureHandlerBase::setLowLatencyMode(bool mode, size_t kernel_buffer_size, size_t reduce_size, bool bforce) {
+ if (kernel_buffer_size == 0) {
+ return NO_ERROR;
+ }
+ const stream_attribute_t *attribute = mCaptureDataClient->getStreamAttributeSource();
+ size_t hal_frame_count = (attribute->sample_rate) * UPLINK_NORMAL_LATENCY_MS / 1000;
+ if (reduce_size == 0) {
+ reduce_size = hal_frame_count;
+ }
+ int rate = mode ? hal_frame_count : ((attribute->buffer_size / (attribute->num_channels) / ((attribute->audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4)) - reduce_size);
+ ALOGD("%s, kernel_buffer_size %zu, rate %d , mode = %d , channel %d, format %d, bforce = %d", __FUNCTION__, kernel_buffer_size, rate, mode, attribute->num_channels, attribute->audio_format, bforce );
+ return mHardwareResourceManager->setULInterruptRate(rate);
+}
+
+bool AudioALSACaptureHandlerBase::getStreamInReopen() {
+ return mCaptureDataClient->getStreamInReopen();
+}
+
+void AudioALSACaptureHandlerBase::setStreamInReopen(bool state) {
+ return mCaptureDataClient->setStreamInReopen(state);
+}
+
+status_t AudioALSACaptureHandlerBase::start() {
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureHandlerBase::stop() {
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureHandlerBase::createMmapBuffer(int32_t min_size_frames __unused,
+ struct audio_mmap_buffer_info *info __unused) {
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureHandlerBase::getMmapPosition(struct audio_mmap_position *position __unused) {
+ return NO_ERROR;
+}
+
+} // end of namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerDsp.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerDsp.cpp
new file mode 100644
index 0000000..8c59c34
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerDsp.cpp
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureHandlerDsp.h"
+#include "AudioALSAHardwareResourceManager.h"
+#include "AudioALSACaptureDataClientDsp.h"
+#include "AudioALSACaptureDataProviderDsp.h"
+
+#include "AudioVUnlockDL.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACaptureHandlerDsp"
+
+namespace android {
+
+//static FILE *pOutFile = NULL;
+
+AudioALSACaptureHandlerDsp::AudioALSACaptureHandlerDsp(stream_attribute_t *stream_attribute_target) :
+ AudioALSACaptureHandlerBase(stream_attribute_target) {
+ ALOGD("%s()", __FUNCTION__);
+
+ init();
+}
+
+
+AudioALSACaptureHandlerDsp::~AudioALSACaptureHandlerDsp() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ ALOGD("%-s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureHandlerDsp::init() {
+ ALOGD("%s()", __FUNCTION__);
+ mCaptureHandlerType = CAPTURE_HANDLER_DSP;
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerDsp::open() {
+ ALOGD("+%s(), input_device = 0x%x, input_source = 0x%x, sample_rate=%d, num_channels=%d",
+ __FUNCTION__, mStreamAttributeTarget->input_device, mStreamAttributeTarget->input_source, mStreamAttributeTarget->sample_rate,
+ mStreamAttributeTarget->num_channels);
+
+ ASSERT(mCaptureDataClient == NULL);
+
+ mCaptureDataClient = new AudioALSACaptureDataClientDsp(AudioALSACaptureDataProviderDsp::getInstance(), mStreamAttributeTarget);
+
+
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ struct timespec systemtime;
+ memset(&systemtime, 0, sizeof(timespec));
+ VUnlockhdl->SetUplinkStartTime(systemtime, 1);
+ }
+ //===========================================
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerDsp::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ ASSERT(mCaptureDataClient != NULL);
+ delete mCaptureDataClient;
+
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ struct timespec systemtime;
+ memset(&systemtime, 0, sizeof(timespec));
+ VUnlockhdl->SetUplinkStartTime(systemtime, 1);
+ }
+ //===========================================
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerDsp::routing(const audio_devices_t input_device) {
+ mHardwareResourceManager->changeInputDevice(input_device);
+ return NO_ERROR;
+}
+
+
+ssize_t AudioALSACaptureHandlerDsp::read(void *buffer, ssize_t bytes) {
+ ALOGV("%s()", __FUNCTION__);
+
+ bytes = mCaptureDataClient->read(buffer, bytes);
+#if 0 //remove dump here which might cause process too long due to SD performance
+ if (pOutFile != NULL) {
+ fwrite(buffer, sizeof(char), bytes, pOutFile);
+ }
+#endif
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ struct timespec systemtime;
+ memset(&systemtime, 0, sizeof(timespec));
+ VUnlockhdl->SetUplinkStartTime(systemtime, 0);
+ }
+ //===========================================
+
+ return bytes;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerFMRadio.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerFMRadio.cpp
new file mode 100644
index 0000000..b41bb0e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerFMRadio.cpp
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureHandlerFMRadio.h"
+
+#include "AudioALSACaptureDataClient.h"
+#include "AudioALSACaptureDataProviderFMRadio.h"
+#include "AudioALSAStreamManager.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+
+#define LOG_TAG "AudioALSACaptureHandlerFMRadio"
+
+namespace android {
+
+AudioALSACaptureHandlerFMRadio::AudioALSACaptureHandlerFMRadio(stream_attribute_t *stream_attribute_target) :
+ AudioALSACaptureHandlerBase(stream_attribute_target) {
+ ALOGD("%s()", __FUNCTION__);
+ mSupportConcurrencyInCall = true;
+ init();
+}
+
+
+AudioALSACaptureHandlerFMRadio::~AudioALSACaptureHandlerFMRadio() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureHandlerFMRadio::init() {
+ ALOGD("%s()", __FUNCTION__);
+ mCaptureHandlerType = CAPTURE_HANDLER_FM_RADIO;
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerFMRadio::open() {
+ ALOGD("+%s(), input_device = 0x%x, input_source = 0x%x",
+ __FUNCTION__, mStreamAttributeTarget->input_device, mStreamAttributeTarget->input_source);
+
+ //For Google FM, app keeps recording when entering into InCall or InCommunication Mode
+ if (mSupportConcurrencyInCall == false && (AudioALSAStreamManager::getInstance()->isModeInPhoneCall() == true || AudioALSAStreamManager::getInstance()->isModeInVoipCall() == true)) {
+ mCaptureDataClient = NULL;
+ ALOGD("-%s() don't support FM Record at incall mode", __FUNCTION__);
+ return NO_ERROR;
+ } else if (AudioALSAStreamManager::getInstance()->getFmEnable() == false) { //For Google FM, app keeps recording when entering into Normal Mode from InCall
+ ALOGW("StreamIn resume FM enable (App keep reading,howerver HAL disable FM for InCall)");
+ AudioALSAStreamManager::getInstance()->setFmEnable(true, true, false);
+ }
+ // TODO(Harvey): check FM is already opened?
+
+ ASSERT(mCaptureDataClient == NULL);
+ mCaptureDataClient = new AudioALSACaptureDataClient(AudioALSACaptureDataProviderFMRadio::getInstance(), mStreamAttributeTarget);
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerFMRadio::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ if (mCaptureDataClient != NULL) {
+ //ASSERT(mCaptureDataClient != NULL);
+ delete mCaptureDataClient;
+ }
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerFMRadio::routing(const audio_devices_t input_device __unused) {
+ WARNING("Not support!!");
+ return INVALID_OPERATION;
+}
+
+
+ssize_t AudioALSACaptureHandlerFMRadio::read(void *buffer, ssize_t bytes) {
+ ALOGV("%s()", __FUNCTION__);
+
+ if (mCaptureDataClient == NULL) {
+ memset(buffer, 0, bytes);
+ size_t wordSize = 0;
+ switch (mStreamAttributeTarget->audio_format) {
+ case AUDIO_FORMAT_PCM_8_BIT: {
+ wordSize = sizeof(int8_t);
+ break;
+ }
+ case AUDIO_FORMAT_PCM_16_BIT: {
+ wordSize = sizeof(int16_t);
+ break;
+ }
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ case AUDIO_FORMAT_PCM_32_BIT: {
+ wordSize = sizeof(int32_t);
+ break;
+ }
+ default: {
+ wordSize = sizeof(int16_t);
+ ALOGW("%s(), wrong format(0x%x), default use wordSize = %zu", __FUNCTION__, mStreamAttributeTarget->audio_format, wordSize);
+ break;
+ }
+ }
+ size_t sleepus = ((bytes * 1000) / ((mStreamAttributeTarget->sample_rate / 1000) * mStreamAttributeTarget->num_channels * wordSize));
+ ALOGD("%s(), sleepus = %zu", __FUNCTION__, sleepus);
+ usleep(sleepus);
+ return bytes;
+ }
+
+ return mCaptureDataClient->read(buffer, bytes);
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerModemDai.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerModemDai.cpp
new file mode 100644
index 0000000..ed4d1dd
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerModemDai.cpp
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: MediaTekProprietary
+
+#if defined(MTK_SPEAKER_MONITOR_SPEECH_SUPPORT)
+
+#include "AudioALSACaptureHandlerModemDai.h"
+
+#include "AudioALSAHardwareResourceManager.h"
+
+#include "AudioALSACaptureDataClient.h"
+#include "AudioALSACaptureDataProviderModemDai.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureHandlerModemDai"
+
+namespace android {
+
+static FILE *pOutFile = NULL;
+
+AudioALSACaptureHandlerModemDai::AudioALSACaptureHandlerModemDai(stream_attribute_t *stream_attribute_target) :
+ AudioALSACaptureHandlerBase(stream_attribute_target) {
+ ALOGD("%s()", __FUNCTION__);
+ init();
+}
+
+
+AudioALSACaptureHandlerModemDai::~AudioALSACaptureHandlerModemDai() {
+ ALOGD("%s()+", __FUNCTION__);
+}
+
+status_t AudioALSACaptureHandlerModemDai::init() {
+ ALOGD("%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSACaptureHandlerModemDai::open() {
+ ALOGD("+%s(), input_device = 0x%x, input_source = 0x%x",
+ __FUNCTION__, mStreamAttributeTarget->input_device, mStreamAttributeTarget->input_source);
+
+ ASSERT(mCaptureDataClient == NULL);
+ mCaptureDataClient = new AudioALSACaptureDataClient(AudioALSACaptureDataProviderModemDai::getInstance(), mStreamAttributeTarget);
+
+ //pOutFile = fopen("/data/vendor/audiohal/SpkMonitor_MD.pcm", "wb");
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerModemDai::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ ASSERT(mCaptureDataClient != NULL);
+ delete mCaptureDataClient;
+ if (pOutFile != NULL) {
+ fclose(pOutFile);
+ }
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerModemDai::routing(const audio_devices_t input_device) {
+ //mHardwareResourceManager->changeInputDevice(input_device);
+ //Do not routing. It should be fixed.
+ return NO_ERROR;
+}
+
+
+ssize_t AudioALSACaptureHandlerModemDai::read(void *buffer, ssize_t bytes) {
+ ALOGV("%s()", __FUNCTION__);
+
+ mCaptureDataClient->read(buffer, bytes);
+ if (pOutFile != NULL) {
+ fwrite(buffer, sizeof(char), bytes, pOutFile);
+ }
+ return bytes;
+}
+
+} // end of namespace android
+#endif //end of defined(MTK_SPEAKER_MONITOR_SPEECH_SUPPORT)
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerNormal.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerNormal.cpp
new file mode 100644
index 0000000..caa6059
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerNormal.cpp
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureHandlerNormal.h"
+
+#include "AudioALSAHardwareResourceManager.h"
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+#include "AudioALSACaptureDataClientAurisysNormal.h"
+#else
+#include "AudioALSACaptureDataClient.h"
+#endif
+#include "AudioALSACaptureDataProviderNormal.h"
+
+#include "AudioVUnlockDL.h"
+
+#include "AudioSmartPaController.h"
+#include "AudioALSACaptureDataProviderEchoRefExt.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureHandlerNormal"
+
+namespace android {
+
+//static FILE *pOutFile = NULL;
+
+AudioALSACaptureHandlerNormal::AudioALSACaptureHandlerNormal(stream_attribute_t *stream_attribute_target) :
+ AudioALSACaptureHandlerBase(stream_attribute_target) {
+ ALOGD("%s()", __FUNCTION__);
+
+ init();
+}
+
+
+AudioALSACaptureHandlerNormal::~AudioALSACaptureHandlerNormal() {
+ ALOGV("+%s()", __FUNCTION__);
+ ALOGV("%-s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureHandlerNormal::init() {
+ ALOGD("%s()", __FUNCTION__);
+ mCaptureHandlerType = CAPTURE_HANDLER_NORMAL;
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerNormal::open() {
+ ALOGD("+%s(), input_device = 0x%x, input_source = 0x%x, sample_rate=%d, num_channels=%d",
+ __FUNCTION__, mStreamAttributeTarget->input_device, mStreamAttributeTarget->input_source, mStreamAttributeTarget->sample_rate,
+ mStreamAttributeTarget->num_channels);
+
+#if defined(MTK_POWERHAL_AUDIO_LATENCY)
+ if (mStreamAttributeTarget->mAudioInputFlags & AUDIO_INPUT_FLAG_FAST
+ || mStreamAttributeTarget->input_source == AUDIO_SOURCE_VOICE_COMMUNICATION
+ || mStreamAttributeTarget->audio_mode == AUDIO_MODE_IN_COMMUNICATION) {
+ power_hal_hint(POWERHAL_LATENCY_UL, true);
+ ALOGD("Power hal enabled for UL\n");
+ }
+#endif
+
+ ASSERT(mCaptureDataClient == NULL);
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ if(!AudioSmartPaController::getInstance()->isInCalibration()) {
+ mCaptureDataClient = new AudioALSACaptureDataClientAurisysNormal(AudioALSACaptureDataProviderNormal::getInstance(), mStreamAttributeTarget, NULL); // NULL: w/o AEC
+ } else {
+ mCaptureDataClient = new AudioALSACaptureDataClientAurisysNormal(AudioALSACaptureDataProviderEchoRefExt::getInstance(), mStreamAttributeTarget, NULL); // NULL: w/o AEC
+ }
+#else
+ if(!AudioSmartPaController::getInstance()->isInCalibration()) {
+ mCaptureDataClient = new AudioALSACaptureDataClient(AudioALSACaptureDataProviderNormal::getInstance(), mStreamAttributeTarget);
+ } else {
+ mCaptureDataClient = new AudioALSACaptureDataClient(AudioALSACaptureDataProviderEchoRefExt::getInstance(), mStreamAttributeTarget);
+ }
+#endif
+
+
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ struct timespec systemtime;
+ memset(&systemtime, 0, sizeof(timespec));
+ VUnlockhdl->SetUplinkStartTime(systemtime, 1);
+ }
+ //===========================================
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerNormal::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ ASSERT(mCaptureDataClient != NULL);
+ delete mCaptureDataClient;
+
+
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ struct timespec systemtime;
+ memset(&systemtime, 0, sizeof(timespec));
+ VUnlockhdl->SetUplinkStartTime(systemtime, 1);
+ }
+ //===========================================
+
+#if defined(MTK_POWERHAL_AUDIO_LATENCY)
+ if (mStreamAttributeTarget->mAudioInputFlags & AUDIO_INPUT_FLAG_FAST) {
+ power_hal_hint(POWERHAL_LATENCY_UL, false);
+ }
+#endif
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerNormal::routing(const audio_devices_t input_device) {
+ mHardwareResourceManager->changeInputDevice(input_device);
+ return NO_ERROR;
+}
+
+
+ssize_t AudioALSACaptureHandlerNormal::read(void *buffer, ssize_t bytes) {
+ ALOGV("%s()", __FUNCTION__);
+
+ bytes = mCaptureDataClient->read(buffer, bytes);
+#if 0 //remove dump here which might cause process too long due to SD performance
+ if (pOutFile != NULL) {
+ fwrite(buffer, sizeof(char), bytes, pOutFile);
+ }
+#endif
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ struct timespec systemtime;
+ memset(&systemtime, 0, sizeof(timespec));
+ VUnlockhdl->SetUplinkStartTime(systemtime, 0);
+ }
+ //===========================================
+
+ return bytes;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerSyncIO.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerSyncIO.cpp
new file mode 100644
index 0000000..02754f1
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerSyncIO.cpp
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureHandlerSyncIO.h"
+#include "AudioALSAHardwareResourceManager.h"
+#include "AudioALSACaptureDataClientSyncIO.h"
+#include "AudioALSACaptureDataProviderNormal.h"
+#include "AudioVUnlockDL.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACaptureHandlerSyncIO"
+
+namespace android {
+
+//static FILE *pOutFile = NULL;
+
+AudioALSACaptureHandlerSyncIO::AudioALSACaptureHandlerSyncIO(stream_attribute_t *stream_attribute_target) :
+ AudioALSACaptureHandlerBase(stream_attribute_target) {
+ ALOGD("%s()", __FUNCTION__);
+
+ init();
+}
+
+
+AudioALSACaptureHandlerSyncIO::~AudioALSACaptureHandlerSyncIO() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ ALOGD("%-s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureHandlerSyncIO::init() {
+ ALOGD("%s()", __FUNCTION__);
+ mCaptureHandlerType = CAPTURE_HANDLER_SYNCIO;
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerSyncIO::open() {
+ ALOGD("+%s(), input_device = 0x%x, input_source = 0x%x, sample_rate=%d, num_channels=%d",
+ __FUNCTION__, mStreamAttributeTarget->input_device, mStreamAttributeTarget->input_source, mStreamAttributeTarget->sample_rate,
+ mStreamAttributeTarget->num_channels);
+
+ ASSERT(mCaptureDataClient == NULL);
+ mCaptureDataClient = new AudioALSACaptureDataClientSyncIO(AudioALSACaptureDataProviderNormal::getInstance(), mStreamAttributeTarget);
+
+
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ struct timespec systemtime;
+ memset(&systemtime, 0, sizeof(timespec));
+ VUnlockhdl->SetUplinkStartTime(systemtime, 1);
+ }
+ //===========================================
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerSyncIO::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ ASSERT(mCaptureDataClient != NULL);
+ delete mCaptureDataClient;
+
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ struct timespec systemtime;
+ memset(&systemtime, 0, sizeof(timespec));
+ VUnlockhdl->SetUplinkStartTime(systemtime, 1);
+ }
+ //===========================================
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerSyncIO::routing(const audio_devices_t input_device) {
+ mHardwareResourceManager->changeInputDevice(input_device);
+ return NO_ERROR;
+}
+
+
+ssize_t AudioALSACaptureHandlerSyncIO::read(void *buffer, ssize_t bytes) {
+ ALOGV("%s()", __FUNCTION__);
+
+ mCaptureDataClient->read(buffer, bytes);
+#if 0 //remove dump here which might cause process too long due to SD performance
+ if (pOutFile != NULL) {
+ fwrite(buffer, sizeof(char), bytes, pOutFile);
+ }
+#endif
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ struct timespec systemtime;
+ memset(&systemtime, 0, sizeof(timespec));
+ VUnlockhdl->SetUplinkStartTime(systemtime, 0);
+ }
+ //===========================================
+
+ return bytes;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerTDM.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerTDM.cpp
new file mode 100644
index 0000000..f3eadd6
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerTDM.cpp
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureHandlerTDM.h"
+
+#include "AudioALSAHardwareResourceManager.h"
+
+#include "AudioALSACaptureDataClient.h"
+#include "AudioALSACaptureDataProviderTDM.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureHandlerTDM"
+
+namespace android {
+
+static FILE *pOutFile = NULL;
+
+AudioALSACaptureHandlerTDM::AudioALSACaptureHandlerTDM(stream_attribute_t *stream_attribute_target) :
+ AudioALSACaptureHandlerBase(stream_attribute_target) {
+ ALOGD("%s()", __FUNCTION__);
+
+ init();
+}
+
+
+AudioALSACaptureHandlerTDM::~AudioALSACaptureHandlerTDM() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ ALOGD("%-s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureHandlerTDM::init() {
+ ALOGD("%s()", __FUNCTION__);
+ mCaptureHandlerType = CAPTURE_HANDLER_TDM;
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerTDM::open() {
+ ALOGD("+%s(), input_device = 0x%x, input_source = 0x%x, sample_rate=%d, num_channels=%d",
+ __FUNCTION__, mStreamAttributeTarget->input_device, mStreamAttributeTarget->input_source, mStreamAttributeTarget->sample_rate,
+ mStreamAttributeTarget->num_channels);
+
+ ASSERT(mCaptureDataClient == NULL);
+ mCaptureDataClient = new AudioALSACaptureDataClient(AudioALSACaptureDataProviderTDM::getInstance(), mStreamAttributeTarget);
+
+#if 1
+ pOutFile = fopen("/data/vendor/audiohal/RecTDM.pcm", "wb");
+ if (pOutFile == NULL) {
+ ALOGD("%s(), fopen fail", __FUNCTION__);
+ }
+#endif
+
+ mHardwareResourceManager->startInputDevice(mStreamAttributeTarget->input_device);
+
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerTDM::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ mHardwareResourceManager->stopInputDevice(mHardwareResourceManager->getInputDevice());
+
+ ASSERT(mCaptureDataClient != NULL);
+ delete mCaptureDataClient;
+
+#if 1
+ if (pOutFile != NULL) {
+ fclose(pOutFile);
+ }
+#endif
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerTDM::routing(const audio_devices_t input_device __unused) {
+ /*mHardwareResourceManager->changeInputDevice(input_device);*/
+ return NO_ERROR;
+}
+
+
+ssize_t AudioALSACaptureHandlerTDM::read(void *buffer, ssize_t bytes) {
+ ALOGV("%s()", __FUNCTION__);
+
+ mCaptureDataClient->read(buffer, bytes);
+#if 1 //remove dump here which might cause process too long due to SD performance
+ if (pOutFile != NULL) {
+ fwrite(buffer, sizeof(char), bytes, pOutFile);
+ }
+#endif
+ return bytes;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerVOW.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerVOW.cpp
new file mode 100644
index 0000000..71c7cc7
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerVOW.cpp
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureHandlerVOW.h"
+
+#include "AudioALSACaptureDataClient.h"
+#include "AudioALSACaptureDataProviderVOW.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+
+#define LOG_TAG "AudioALSACaptureHandlerVOW"
+
+namespace android {
+
+AudioALSACaptureHandlerVOW::AudioALSACaptureHandlerVOW(stream_attribute_t *stream_attribute_target) :
+ AudioALSACaptureHandlerBase(stream_attribute_target) {
+ ALOGD("%s()", __FUNCTION__);
+
+ init();
+}
+
+
+AudioALSACaptureHandlerVOW::~AudioALSACaptureHandlerVOW() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureHandlerVOW::init() {
+ ALOGD("%s()", __FUNCTION__);
+
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerVOW::open() {
+ ALOGD("+%s(), input_device = 0x%x, input_source = 0x%x",
+ __FUNCTION__, mStreamAttributeTarget->input_device, mStreamAttributeTarget->input_source);
+
+ //ASSERT(mCaptureDataClient == NULL);
+ mCaptureDataClient = new AudioALSACaptureDataClient(AudioALSACaptureDataProviderVOW::getInstance(), mStreamAttributeTarget);
+ //mVOWCaptureDataProvider = AudioALSACaptureDataProviderVOW::getInstance();
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerVOW::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ ASSERT(mCaptureDataClient != NULL);
+ delete mCaptureDataClient;
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerVOW::routing(const audio_devices_t input_device __unused) {
+ WARNING("Not support!!");
+ return INVALID_OPERATION;
+}
+
+
+ssize_t AudioALSACaptureHandlerVOW::read(void *buffer, ssize_t bytes) {
+ ALOGV("%s()", __FUNCTION__);
+
+ return mCaptureDataClient->read(buffer, bytes);
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerVoice.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerVoice.cpp
new file mode 100644
index 0000000..0d71cda
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACaptureHandlerVoice.cpp
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACaptureHandlerVoice.h"
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+#include "AudioALSACaptureDataClientAurisysNormal.h"
+#else
+#include "AudioALSACaptureDataClient.h"
+#endif
+#include "AudioALSACaptureDataProviderVoice.h"
+#include "AudioALSACaptureDataProviderVoiceDL.h"
+#include "AudioALSACaptureDataProviderVoiceUL.h"
+#include "AudioALSACaptureDataProviderVoiceMix.h"
+#include "AudioType.h"
+#include "audio_custom_exp.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioALSACaptureHandlerVoice"
+
+namespace android {
+
+AudioALSACaptureHandlerVoice::AudioALSACaptureHandlerVoice(stream_attribute_t *stream_attribute_target) :
+ AudioALSACaptureHandlerBase(stream_attribute_target) {
+ ALOGD("%s()", __FUNCTION__);
+ //Need to set false because HandlerVoice should close before speechoff
+ mSupportConcurrencyInCall = false;
+ init();
+}
+
+
+AudioALSACaptureHandlerVoice::~AudioALSACaptureHandlerVoice() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACaptureHandlerVoice::init() {
+ ALOGD("%s()", __FUNCTION__);
+ mCaptureHandlerType = CAPTURE_HANDLER_VOICE;
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerVoice::open() {
+ ALOGD("+%s(), input_device = 0x%x, input_source = 0x%x",
+ __FUNCTION__, mStreamAttributeTarget->input_device, mStreamAttributeTarget->input_source);
+
+ ASSERT(mCaptureDataClient == NULL);
+
+ AudioALSACaptureDataProviderBase *provider = NULL;
+
+#ifndef LEGACY_VOICE_RECORD
+ switch (mStreamAttributeTarget->input_source) {
+#ifdef INCALL_DL_RECORD_DISABLED
+ default: {
+ provider = AudioALSACaptureDataProviderVoiceUL::getInstance();
+ break;
+ }
+#else
+ case AUDIO_SOURCE_VOICE_DOWNLINK: {
+ provider = AudioALSACaptureDataProviderVoiceDL::getInstance();
+ break;
+ }
+ case AUDIO_SOURCE_VOICE_UPLINK: {
+ provider = AudioALSACaptureDataProviderVoiceUL::getInstance();
+ break;
+ }
+ case AUDIO_SOURCE_VOICE_CALL: {
+ provider = AudioALSACaptureDataProviderVoiceMix::getInstance();
+ break;
+ }
+ default: {
+ provider = AudioALSACaptureDataProviderVoiceUL::getInstance();
+ break;
+ }
+#endif
+ }
+#else
+ // legacy voice record
+ provider = AudioALSACaptureDataProviderVoice::getInstance();
+#endif
+
+
+#if defined(MTK_AURISYS_FRAMEWORK_SUPPORT)
+ mCaptureDataClient = new AudioALSACaptureDataClientAurisysNormal(provider, mStreamAttributeTarget, NULL);
+#else
+ mCaptureDataClient = new AudioALSACaptureDataClient(provider, mStreamAttributeTarget);
+#endif
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerVoice::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ ASSERT(mCaptureDataClient != NULL);
+ delete mCaptureDataClient;
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACaptureHandlerVoice::routing(const audio_devices_t input_device __unused) {
+ WARNING("Not support!!"); // TODO(Harvey): check it
+ return INVALID_OPERATION;
+}
+
+
+ssize_t AudioALSACaptureHandlerVoice::read(void *buffer, ssize_t bytes) {
+ ALOGV("%s()", __FUNCTION__);
+
+ return mCaptureDataClient->read(buffer, bytes);
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceBase.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceBase.cpp
new file mode 100644
index 0000000..d592eef
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceBase.cpp
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACodecDeviceBase.h"
+
+#include <AudioLock.h>
+
+#include "AudioALSADriverUtility.h"
+
+#include "AudioALSACodecDeviceOutEarphonePMIC.h"
+#include "AudioALSACodecDeviceOutReceiverPMIC.h"
+#include "AudioALSACodecDeviceOutSpeakerPMIC.h"
+#include "AudioALSACodecDeviceOutSpeakerEarphonePMIC.h"
+#include "AudioALSADeviceConfigManager.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACodecDeviceBase"
+
+namespace android {
+struct mixer *AudioALSACodecDeviceBase::mMixer = NULL;
+
+AudioALSACodecDeviceBase *AudioALSACodecDeviceBase::createCodecOutputDevices() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ return AudioALSACodecDeviceOutSpeakerPMIC::getInstance();
+}
+
+AudioALSACodecDeviceBase::AudioALSACodecDeviceBase() :
+ mClientCount(0) {
+ ALOGD("%s()", __FUNCTION__);
+
+ if (mMixer == NULL) {
+ mMixer = AudioALSADriverUtility::getInstance()->getMixer();
+ ASSERT(mMixer != NULL);
+ }
+}
+
+AudioALSACodecDeviceBase::~AudioALSACodecDeviceBase() {
+ ALOGD("%s()", __FUNCTION__);
+
+ if (mMixer != NULL) {
+ mixer_close(mMixer);
+ mMixer = NULL;
+ }
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutEarphonePMIC.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutEarphonePMIC.cpp
new file mode 100644
index 0000000..1fb0dda
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutEarphonePMIC.cpp
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACodecDeviceOutEarphonePMIC.h"
+
+#include <AudioLock.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACodecDeviceOutEarphonePMIC"
+
+namespace android {
+
+AudioALSACodecDeviceOutEarphonePMIC *AudioALSACodecDeviceOutEarphonePMIC::mAudioALSACodecDeviceOutEarphonePMIC = NULL;
+AudioALSACodecDeviceOutEarphonePMIC *AudioALSACodecDeviceOutEarphonePMIC::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACodecDeviceOutEarphonePMIC == NULL) {
+ mAudioALSACodecDeviceOutEarphonePMIC = new AudioALSACodecDeviceOutEarphonePMIC();
+ }
+ ASSERT(mAudioALSACodecDeviceOutEarphonePMIC != NULL);
+ return mAudioALSACodecDeviceOutEarphonePMIC;
+}
+
+status_t AudioALSACodecDeviceOutEarphonePMIC::DeviceDoDcCalibrate() {
+ int hplOffset = 0, hprOffset = 0;
+ int hplTrimCode = 0, hprTrimCode = 0;
+ int retval = 0;
+
+#ifdef NEW_PMIC_DCTRIM_FLOW
+#define DC_TRIM_CONTROL_SWITCH_NAME "Dctrim_Control_Switch"
+#define DC_TRIM_OFFSET_NAME "DcTrim_DC_Offset"
+#define DC_TRIM_CODE_NAME "DcTrim_Hp_Trimcode"
+
+#define DC_TRIM_CALIBRATED_STRING "Calibrated"
+#define DC_TRIM_CALIBRATING_STRING "Calibrating"
+
+ int dcTrimState = mixer_ctl_get_value(mixer_get_ctl_by_name(mMixer, DC_TRIM_CONTROL_SWITCH_NAME), 0);
+
+ ALOGD("%s(), ctl %s = %d", __FUNCTION__, DC_TRIM_CONTROL_SWITCH_NAME, dcTrimState);
+
+ // check if calibrated
+ if (strcmp(mixer_ctl_get_enum_string(mixer_get_ctl_by_name(mMixer, DC_TRIM_CONTROL_SWITCH_NAME), dcTrimState), DC_TRIM_CALIBRATED_STRING) == 0) {
+ ALOGD("%s(), dc trimmed", __FUNCTION__);
+ return 0;
+ }
+
+ // do dc calibrate
+ retval = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, DC_TRIM_CONTROL_SWITCH_NAME), DC_TRIM_CALIBRATING_STRING);
+ hplOffset = mixer_ctl_get_value(mixer_get_ctl_by_name(mMixer, DC_TRIM_OFFSET_NAME), 0);
+ hprOffset = mixer_ctl_get_value(mixer_get_ctl_by_name(mMixer, DC_TRIM_OFFSET_NAME), 1);
+ hplTrimCode = mixer_ctl_get_value(mixer_get_ctl_by_name(mMixer, DC_TRIM_CODE_NAME), 0);
+ hprTrimCode = mixer_ctl_get_value(mixer_get_ctl_by_name(mMixer, DC_TRIM_CODE_NAME), 1);
+#else
+ hplOffset = mixer_ctl_get_value(mixer_get_ctl_by_name(mMixer, "Audio HPL Offset"), 0);
+ hprOffset = mixer_ctl_get_value(mixer_get_ctl_by_name(mMixer, "Audio HPR Offset"), 0);
+#endif
+
+ ALOGD("-%s(), hp_dc_offset = [%d, %d], hp_trim_code = [%d, %d]", __FUNCTION__, hplOffset, hprOffset, hplTrimCode, hprTrimCode);
+
+ return NO_ERROR;
+}
+
+AudioALSACodecDeviceOutEarphonePMIC::AudioALSACodecDeviceOutEarphonePMIC() {
+ ALOGD("%s()", __FUNCTION__);
+#if !defined(MTK_AUDIO_KS)
+ DeviceDoDcCalibrate();
+#endif
+}
+
+
+AudioALSACodecDeviceOutEarphonePMIC::~AudioALSACodecDeviceOutEarphonePMIC() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACodecDeviceOutEarphonePMIC::open() {
+ ALOGD("+%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+
+ if (mClientCount == 0) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Amp_R_Switch"), "On")) {
+ ALOGE("Error: Audio_Amp_R_Switch invalid value");
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Amp_L_Switch"), "On")) {
+ ALOGE("Error: Audio_Amp_L_Switch invalid value");
+ }
+ }
+
+ mClientCount++;
+
+ ALOGD("-%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACodecDeviceOutEarphonePMIC::close() {
+ ALOGD("+%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+
+ mClientCount--;
+
+ if (mClientCount == 0) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Amp_R_Switch"), "Off")) {
+ ALOGE("Error: Audio_Amp_R_Switch invalid value");
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Amp_L_Switch"), "Off")) {
+ ALOGE("Error: Audio_Amp_L_Switch invalid value");
+ }
+ }
+
+ ALOGD("-%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+ return NO_ERROR;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutExtSpeakerAmp.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutExtSpeakerAmp.cpp
new file mode 100644
index 0000000..d63558b
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutExtSpeakerAmp.cpp
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACodecDeviceOutExtSpeakerAmp.h"
+
+#include <AudioLock.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACodecDeviceOutExtSpeakerAmp"
+
+namespace android {
+
+AudioALSACodecDeviceOutExtSpeakerAmp *AudioALSACodecDeviceOutExtSpeakerAmp::mAudioALSACodecDeviceOutExtSpeakerAmp = NULL;
+AudioALSACodecDeviceOutExtSpeakerAmp *AudioALSACodecDeviceOutExtSpeakerAmp::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACodecDeviceOutExtSpeakerAmp == NULL) {
+ mAudioALSACodecDeviceOutExtSpeakerAmp = new AudioALSACodecDeviceOutExtSpeakerAmp();
+ }
+ ASSERT(mAudioALSACodecDeviceOutExtSpeakerAmp != NULL);
+ return mAudioALSACodecDeviceOutExtSpeakerAmp;
+}
+
+
+AudioALSACodecDeviceOutExtSpeakerAmp::AudioALSACodecDeviceOutExtSpeakerAmp() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+AudioALSACodecDeviceOutExtSpeakerAmp::~AudioALSACodecDeviceOutExtSpeakerAmp() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACodecDeviceOutExtSpeakerAmp::open() {
+ ALOGD("+%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+
+ if (mClientCount == 0) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Ext_Speaker_Amp_Switch"), "On")) {
+ ALOGE("Error: Ext_Speaker_Amp_Switch invalid value");
+ }
+ }
+
+ mClientCount++;
+
+ ALOGD("-%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACodecDeviceOutExtSpeakerAmp::close() {
+ ALOGD("+%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+
+ mClientCount--;
+
+ if (mClientCount == 0) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Ext_Speaker_Amp_Switch"), "Off")) {
+ ALOGE("Error: Ext_Speaker_Amp_Switch invalid value");
+ }
+ }
+
+ ALOGD("-%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+ return NO_ERROR;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutHeadphone.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutHeadphone.cpp
new file mode 100644
index 0000000..152b978
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutHeadphone.cpp
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACodecDeviceOutHeadphone.h"
+
+#include <AudioLock.h>
+
+
+#define LOG_TAG "AudioALSACodecDeviceOutHeadphone"
+
+namespace android {
+
+AudioALSACodecDeviceOutHeadphone *AudioALSACodecDeviceOutHeadphone::mAudioALSACodecDeviceOutHeadphone = NULL;
+AudioALSACodecDeviceOutHeadphone *AudioALSACodecDeviceOutHeadphone::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACodecDeviceOutHeadphone == NULL) {
+ mAudioALSACodecDeviceOutHeadphone = new AudioALSACodecDeviceOutHeadphone();
+ }
+ ASSERT(mAudioALSACodecDeviceOutHeadphone != NULL);
+ return mAudioALSACodecDeviceOutHeadphone;
+}
+
+AudioALSACodecDeviceOutHeadphone::AudioALSACodecDeviceOutHeadphone() :
+ hifi_enable(1),
+ mCount(0),
+ mHpPcmOut(NULL) {
+ memset(&mHpPcmConfig, 0, sizeof(mHpPcmConfig));
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+AudioALSACodecDeviceOutHeadphone::~AudioALSACodecDeviceOutHeadphone() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+status_t AudioALSACodecDeviceOutHeadphone::open() {
+ open(48000);
+
+ return NO_ERROR;
+}
+
+status_t AudioALSACodecDeviceOutHeadphone::open(int SampleRate) {
+ ALOGD("+%s(), mCount = %d, hifi_enable %d", __FUNCTION__, mCount, hifi_enable);
+
+ if (mCount == 0) {
+ if (hifi_enable) {
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmExtHpMedia);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmExtHpMedia);
+
+ memset(&mHpPcmConfig, 0, sizeof(mHpPcmConfig));
+ mHpPcmConfig.channels = 2;
+ mHpPcmConfig.rate = SampleRate;
+ mHpPcmConfig.period_size = 1024;
+ mHpPcmConfig.period_count = 2;
+ mHpPcmConfig.format = PCM_FORMAT_S32_LE;
+ mHpPcmConfig.stop_threshold = ~(0UL); // TODO: KC: check if needed
+
+ ASSERT(mHpPcmOut == NULL);
+ mHpPcmOut = pcm_open(cardindex, pcmindex, PCM_OUT | PCM_MONOTONIC, &mHpPcmConfig);
+
+ if (pcm_is_ready(mHpPcmOut) == false) {
+ ALOGE("%s(), pcm_is_ready(%p) == false due to %s, close pcm.", __FUNCTION__, mHpPcmOut, pcm_get_error(mHpPcmOut));
+ pcm_close(mHpPcmOut);
+ mHpPcmOut = NULL;
+ } else {
+ if (pcm_start(mHpPcmOut) != 0) {
+ ALOGE("%s(), pcm_start(%p) fail due to %s", __FUNCTION__, mHpPcmOut, pcm_get_error(mHpPcmOut));
+ }
+ }
+ ASSERT(mHpPcmOut != NULL);
+ ALOGD("%s(), mHpPcmOut = %p", __FUNCTION__, mHpPcmOut);
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Master Playback Volume"), 0, 255)) {
+ ALOGE("Error: Master Playback Volume left channel invalid value");
+ }
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Master Playback Volume"), 1, 255)) {
+ ALOGE("Error: Master Playback Volume right channel invalid value");
+ }
+ } else {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Amp_R_Switch"), "On")) {
+ ALOGE("Error: Audio_Amp_R_Switch invalid value");
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Amp_L_Switch"), "On")) {
+ ALOGE("Error: Audio_Amp_L_Switch invalid value");
+ }
+ }
+ }
+
+ mCount++;
+
+ ALOGD("-%s(), mCount = %d", __FUNCTION__, mCount);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACodecDeviceOutHeadphone::close() {
+ ALOGD("+%s(), mCount = %d", __FUNCTION__, mCount);
+
+ mCount--;
+
+ if (mCount == 0) {
+ if (hifi_enable) {
+ pcm_stop(mHpPcmOut);
+ pcm_close(mHpPcmOut);
+ mHpPcmOut = NULL;
+ } else {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Amp_R_Switch"), "Off")) {
+ ALOGE("Error: Audio_Amp_R_Switch invalid value");
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Amp_L_Switch"), "Off")) {
+ ALOGE("Error: Audio_Amp_L_Switch invalid value");
+ }
+ }
+ }
+
+ ALOGD("-%s(), mCount = %d", __FUNCTION__, mCount);
+ return NO_ERROR;
+}
+
+status_t AudioALSACodecDeviceOutHeadphone::setHeadphoneState(int enable) {
+ hifi_enable = enable;
+
+ return NO_ERROR;
+}
+
+status_t AudioALSACodecDeviceOutHeadphone::getHeadphoneState() {
+ return hifi_enable;
+
+ return NO_ERROR;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutReceiverPMIC.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutReceiverPMIC.cpp
new file mode 100644
index 0000000..f8154c7
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutReceiverPMIC.cpp
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACodecDeviceOutReceiverPMIC.h"
+
+#include <AudioLock.h>
+
+#include "AudioUtility.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACodecDeviceOutReceiverPMIC"
+
+namespace android {
+
+AudioALSACodecDeviceOutReceiverPMIC *AudioALSACodecDeviceOutReceiverPMIC::mAudioALSACodecDeviceOutReceiverPMIC = NULL;
+AudioALSACodecDeviceOutReceiverPMIC *AudioALSACodecDeviceOutReceiverPMIC::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACodecDeviceOutReceiverPMIC == NULL) {
+ mAudioALSACodecDeviceOutReceiverPMIC = new AudioALSACodecDeviceOutReceiverPMIC();
+ }
+ ASSERT(mAudioALSACodecDeviceOutReceiverPMIC != NULL);
+ return mAudioALSACodecDeviceOutReceiverPMIC;
+}
+
+
+AudioALSACodecDeviceOutReceiverPMIC::AudioALSACodecDeviceOutReceiverPMIC() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+AudioALSACodecDeviceOutReceiverPMIC::~AudioALSACodecDeviceOutReceiverPMIC() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACodecDeviceOutReceiverPMIC::open() {
+ ALOGD("+%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+
+ if (mClientCount == 0) {
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_2IN1_SPEAKER)) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Speaker_class_Switch"), "RECEIVER")) {
+ ALOGE("Error: Audio_Speaker_class_Switch invalid value");
+ }
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Speaker_Amp_Switch"), "On")) {
+ ALOGE("Error: Speaker_Amp_Switch invalid value");
+ }
+ } else {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Voice_Amp_Switch"), "On")) {
+ ALOGE("Error: Voice_Amp_Switch invalid value");
+ }
+ }
+
+ }
+
+ mClientCount++;
+
+ ALOGD("-%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACodecDeviceOutReceiverPMIC::close() {
+ ALOGD("+%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+
+ mClientCount--;
+
+ if (mClientCount == 0) {
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_2IN1_SPEAKER)) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Speaker_Amp_Switch"), "Off")) {
+ ALOGE("Error: Speaker_Amp_Switch invalid value");
+ }
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Speaker_class_Switch"), "CLASSAB")) {
+ ALOGE("Error: Audio_Speaker_class_Switch invalid value");
+ }
+ } else {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Voice_Amp_Switch"), "Off")) {
+ ALOGE("Error: Voice_Amp_Switch invalid value");
+ }
+ }
+ }
+
+ ALOGD("-%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+ return NO_ERROR;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutReceiverSpeakerSwitch.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutReceiverSpeakerSwitch.cpp
new file mode 100644
index 0000000..0590dde
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutReceiverSpeakerSwitch.cpp
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACodecDeviceOutReceiverSpeakerSwitch.h"
+
+#include <AudioLock.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACodecDeviceOutReceiverSpeakerSwitch"
+
+namespace android {
+
+AudioALSACodecDeviceOutReceiverSpeakerSwitch *AudioALSACodecDeviceOutReceiverSpeakerSwitch::mAudioALSACodecDeviceOutReceiverSpeakerSwitch = NULL;
+AudioALSACodecDeviceOutReceiverSpeakerSwitch *AudioALSACodecDeviceOutReceiverSpeakerSwitch::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACodecDeviceOutReceiverSpeakerSwitch == NULL) {
+ mAudioALSACodecDeviceOutReceiverSpeakerSwitch = new AudioALSACodecDeviceOutReceiverSpeakerSwitch();
+ }
+ ASSERT(mAudioALSACodecDeviceOutReceiverSpeakerSwitch != NULL);
+ return mAudioALSACodecDeviceOutReceiverSpeakerSwitch;
+}
+
+
+AudioALSACodecDeviceOutReceiverSpeakerSwitch::AudioALSACodecDeviceOutReceiverSpeakerSwitch() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+AudioALSACodecDeviceOutReceiverSpeakerSwitch::~AudioALSACodecDeviceOutReceiverSpeakerSwitch() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACodecDeviceOutReceiverSpeakerSwitch::open() {
+ ALOGD("+%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+
+ if (mClientCount == 0) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Receiver_Speaker_Switch"), "On")) {
+ ALOGE("Error: Ext_Speaker_Amp_Switch invalid value");
+ }
+ }
+
+ mClientCount++;
+
+ ALOGD("-%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACodecDeviceOutReceiverSpeakerSwitch::close() {
+ ALOGD("+%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+
+ mClientCount--;
+
+ if (mClientCount == 0) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Receiver_Speaker_Switch"), "Off")) {
+ ALOGE("Error: Ext_Speaker_Amp_Switch invalid value");
+ }
+ }
+
+ ALOGD("-%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+ return NO_ERROR;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutSpeakerEarphonePMIC.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutSpeakerEarphonePMIC.cpp
new file mode 100644
index 0000000..367964e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutSpeakerEarphonePMIC.cpp
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACodecDeviceOutSpeakerEarphonePMIC.h"
+
+#include <AudioLock.h>
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACodecDeviceOutSpeakerEarphonePMIC"
+
+namespace android {
+
+AudioALSACodecDeviceOutSpeakerEarphonePMIC *AudioALSACodecDeviceOutSpeakerEarphonePMIC::mAudioALSACodecDeviceOutSpeakerEarphonePMIC = NULL;
+AudioALSACodecDeviceOutSpeakerEarphonePMIC *AudioALSACodecDeviceOutSpeakerEarphonePMIC::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACodecDeviceOutSpeakerEarphonePMIC == NULL) {
+ mAudioALSACodecDeviceOutSpeakerEarphonePMIC = new AudioALSACodecDeviceOutSpeakerEarphonePMIC();
+ }
+ ASSERT(mAudioALSACodecDeviceOutSpeakerEarphonePMIC != NULL);
+ return mAudioALSACodecDeviceOutSpeakerEarphonePMIC;
+}
+
+status_t AudioALSACodecDeviceOutSpeakerEarphonePMIC::DeviceDoDcCalibrate() {
+#define MAX_HP_GAIN_LEVEL (19)
+#define DC_TRIM_OFFSET_HPL_SPK_NAME "Audio HPL_SPK Offset"
+#define DC_TRIM_OFFSET_HPR_SPK_NAME "Audio HPR_SPK Offset"
+
+
+ int HplOffset[MAX_HP_GAIN_LEVEL * 2], HprOffset, i, num_values;
+ struct mixer_ctl *ctl;
+
+ ALOGD("%s()", __FUNCTION__);
+
+ // do dc calibrate
+ ctl = mixer_get_ctl_by_name(mMixer, DC_TRIM_OFFSET_HPL_SPK_NAME);
+ if (ctl) {
+ mixer_ctl_get_array(ctl, HplOffset, MAX_HP_GAIN_LEVEL);
+ for (i = 0; i < MAX_HP_GAIN_LEVEL; i++) {
+ ALOGV("%s(), HplOffset[%d] = 0x%x ", __FUNCTION__, i,
+ HplOffset[i]);
+ }
+ } else {
+ ALOGD("%s(), can't get mixer control(%s)", __FUNCTION__,
+ DC_TRIM_OFFSET_HPL_SPK_NAME);
+ }
+
+ ctl = mixer_get_ctl_by_name(mMixer, DC_TRIM_OFFSET_HPR_SPK_NAME);
+ if (ctl) {
+ HprOffset = mixer_ctl_get_value(ctl, 0);
+ ALOGD("%s(), HprOffset = 0x%x ", __FUNCTION__, HprOffset);
+ } else {
+ ALOGD("%s(), can't get mixer control(%s)", __FUNCTION__,
+ DC_TRIM_OFFSET_HPR_SPK_NAME);
+ }
+
+ return NO_ERROR;
+}
+
+AudioALSACodecDeviceOutSpeakerEarphonePMIC::AudioALSACodecDeviceOutSpeakerEarphonePMIC() {
+ ALOGD("%s()", __FUNCTION__);
+#if !defined(MTK_AUDIO_KS)
+ DeviceDoDcCalibrate();
+#endif
+}
+
+
+AudioALSACodecDeviceOutSpeakerEarphonePMIC::~AudioALSACodecDeviceOutSpeakerEarphonePMIC() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACodecDeviceOutSpeakerEarphonePMIC::open() {
+ ALOGD("+%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+
+ if (mClientCount == 0) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Headset_Speaker_Amp_Switch"), "On")) {
+ ALOGE("Error: Headset_Speaker_Amp_Switch invalid value");
+ }
+ }
+
+ mClientCount++;
+
+ ALOGD("-%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACodecDeviceOutSpeakerEarphonePMIC::close() {
+ ALOGD("+%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+
+ mClientCount--;
+
+ if (mClientCount == 0) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Headset_Speaker_Amp_Switch"), "Off")) {
+ ALOGE("Error: Headset_Speaker_Amp_Switch invalid value");
+ }
+ }
+
+ ALOGD("-%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+ return NO_ERROR;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutSpeakerNXP.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutSpeakerNXP.cpp
new file mode 100644
index 0000000..82496f5
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutSpeakerNXP.cpp
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACodecDeviceOutSpeakerNXP.h"
+#include "AudioALSAStreamManager.h"
+
+#include <AudioLock.h>
+#include "audio_custom_exp.h"
+
+#include <mtk_tfa98xx_interface.h>
+
+#define APLL_ON //Low jitter Mode Set
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACodecDeviceOutSpeakerNXP"
+
+namespace android {
+
+AudioALSACodecDeviceOutSpeakerNXP *AudioALSACodecDeviceOutSpeakerNXP::mAudioALSACodecDeviceOutSpeakerNXP = NULL;
+AudioALSACodecDeviceOutSpeakerNXP *AudioALSACodecDeviceOutSpeakerNXP::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACodecDeviceOutSpeakerNXP == NULL) {
+ mAudioALSACodecDeviceOutSpeakerNXP = new AudioALSACodecDeviceOutSpeakerNXP();
+ }
+ ASSERT(mAudioALSACodecDeviceOutSpeakerNXP != NULL);
+ return mAudioALSACodecDeviceOutSpeakerNXP;
+}
+
+
+AudioALSACodecDeviceOutSpeakerNXP::AudioALSACodecDeviceOutSpeakerNXP() {
+ ALOGD("%s()", __FUNCTION__);
+ // use default samplerate to load setting.
+#ifndef MTK_APLL_DEFAULT_OFF
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_always_hd_Switch"), "On")) {
+ ALOGE("Error: Audio_always_hd_Switch invalid value");
+ }
+#endif
+
+ open();
+ close();
+}
+
+
+AudioALSACodecDeviceOutSpeakerNXP::~AudioALSACodecDeviceOutSpeakerNXP() {
+ ALOGD("%s()", __FUNCTION__);
+
+ MTK_Tfa98xx_Deinit();
+}
+
+
+status_t AudioALSACodecDeviceOutSpeakerNXP::open() {
+#ifndef EXTCODEC_ECHO_REFERENCE_SUPPORT
+ MTK_Tfa98xx_SetBypassDspIncall(1);
+#endif
+
+ return open(44100);
+}
+
+status_t AudioALSACodecDeviceOutSpeakerNXP::open(const uint32_t SampleRate) {
+ ALOGD("+%s(), mClientCount = %d, SampleRate = %d", __FUNCTION__, mClientCount, SampleRate);
+ modem_index_t modem_index = SpeechDriverFactory::GetInstance()->GetActiveModemIndex();
+ int ret;
+
+ if (mClientCount == 0) {
+#ifdef APLL_ON
+ ALOGD("+%s(), Audio_i2s0_hd_Switch on", __FUNCTION__);
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_hd_Switch"), "On")) {
+ ALOGE("Error: Audio_i2s0_hd_Switch invalid value");
+ }
+#endif
+ /* Config echo reference */
+ if (AudioALSAStreamManager::getInstance()->isModeInPhoneCall()) {
+ if (modem_index == MODEM_1) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_ExtCodec_EchoRef_Switch"), "MD1")) {
+ ALOGE("Error: Audio_ExtCodec_EchoRef_Switch MD1 invalid value");
+ }
+ } else {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_ExtCodec_EchoRef_Switch"), "MD3")) {
+ ALOGE("Error: Audio_ExtCodec_EchoRef_Switch MD3 invalid value");
+ }
+ }
+ }
+
+ /* Enable SmartPa i2s */
+ switch (SampleRate) {
+ case 8000:
+ ret = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "On8000");
+ break;
+ case 16000:
+ ret = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "On16000");
+ break;
+ case 32000:
+ ret = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "On32000");
+ break;
+ case 44100:
+ ret = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "On44100");
+ break;
+ case 48000:
+ ret = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "On48000");
+ break;
+ case 96000:
+ ret = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "On96000");
+ break;
+ case 192000:
+ ret = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "On192000");
+ break;
+ }
+
+ if (ret > 0) {
+ ALOGE("%s(), ERROR: Audio_i2s0_SideGen_Switch, ret = %d, samplerate = %d\n", __FUNCTION__, ret, sampleRate);
+ }
+
+ MTK_Tfa98xx_SetSampleRate(SampleRate);
+ MTK_Tfa98xx_SpeakerOn();
+#ifdef EXTCODEC_ECHO_REFERENCE_SUPPORT
+ //Echo Reference configure will be set on all sample rate
+ MTK_Tfa98xx_EchoReferenceConfigure(1);
+#endif
+ }
+
+ mClientCount++;
+
+ ALOGD("-%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACodecDeviceOutSpeakerNXP::close() {
+ ALOGD("+%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+
+ mClientCount--;
+
+ if (mClientCount == 0) {
+ MTK_Tfa98xx_SpeakerOff();
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "Off")) {
+ ALOGE("Error: Audio_i2s0_SideGen_Switch invalid value");
+ }
+#ifdef EXTCODEC_ECHO_REFERENCE_SUPPORT
+ ALOGD("%s(), Audio_ExtCodec_EchoRef_Switch off", __FUNCTION__);
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_ExtCodec_EchoRef_Switch"), "Off")) {
+ ALOGE("Error: Audio_ExtCodec_EchoRef_Switch invalid value");
+ }
+#endif
+#ifdef APLL_ON
+ ALOGD("+%s(), Audio_i2s0_hd_Switch off", __FUNCTION__);
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_hd_Switch"), "Off")) {
+ ALOGE("Error: Audio_i2s0_hd_Switch invalid value");
+ }
+#endif
+ }
+
+ ALOGD("-%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+ return NO_ERROR;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutSpeakerPMIC.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutSpeakerPMIC.cpp
new file mode 100644
index 0000000..714eca8
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSACodecDeviceOutSpeakerPMIC.cpp
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSACodecDeviceOutSpeakerPMIC.h"
+
+#include <AudioLock.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSACodecDeviceOutSpeakerPMIC"
+
+namespace android {
+
+AudioALSACodecDeviceOutSpeakerPMIC *AudioALSACodecDeviceOutSpeakerPMIC::mAudioALSACodecDeviceOutSpeakerPMIC = NULL;
+AudioALSACodecDeviceOutSpeakerPMIC *AudioALSACodecDeviceOutSpeakerPMIC::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSACodecDeviceOutSpeakerPMIC == NULL) {
+ mAudioALSACodecDeviceOutSpeakerPMIC = new AudioALSACodecDeviceOutSpeakerPMIC();
+ }
+ ASSERT(mAudioALSACodecDeviceOutSpeakerPMIC != NULL);
+ return mAudioALSACodecDeviceOutSpeakerPMIC;
+}
+
+
+AudioALSACodecDeviceOutSpeakerPMIC::AudioALSACodecDeviceOutSpeakerPMIC() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+AudioALSACodecDeviceOutSpeakerPMIC::~AudioALSACodecDeviceOutSpeakerPMIC() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSACodecDeviceOutSpeakerPMIC::open() {
+ ALOGD("+%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+
+ if (mClientCount == 0) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Speaker_Amp_Switch"), "On")) {
+ ALOGE("Error: Speaker_Amp_Switch invalid value");
+ }
+ }
+
+ mClientCount++;
+
+ ALOGD("-%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSACodecDeviceOutSpeakerPMIC::close() {
+ ALOGD("+%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+
+ mClientCount--;
+
+ if (mClientCount == 0) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Speaker_Amp_Switch"), "Off")) {
+ ALOGE("Error: Speaker_Amp_Switch invalid value");
+ }
+ }
+
+ ALOGD("-%s(), mClientCount = %d", __FUNCTION__, mClientCount);
+ return NO_ERROR;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSADataProcessor.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSADataProcessor.cpp
new file mode 100644
index 0000000..50b2ffd
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSADataProcessor.cpp
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSADataProcessor.h"
+
+#include <utils/threads.h>
+
+#include <AudioLock.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSADataProcessor"
+
+namespace android {
+
+AudioALSADataProcessor *AudioALSADataProcessor::mAudioALSADataProcessor = NULL;
+AudioALSADataProcessor *AudioALSADataProcessor::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSADataProcessor == NULL) {
+ mAudioALSADataProcessor = new AudioALSADataProcessor();
+ }
+ ASSERT(mAudioALSADataProcessor != NULL);
+ return mAudioALSADataProcessor;
+}
+
+AudioALSADataProcessor::AudioALSADataProcessor() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+AudioALSADataProcessor::~AudioALSADataProcessor() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+} // end of namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSADeviceConfigManager.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSADeviceConfigManager.cpp
new file mode 100644
index 0000000..4a927e1
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSADeviceConfigManager.cpp
@@ -0,0 +1,512 @@
+// SPDX-License-Identifier: MediaTekProprietary
+
+#include <tinyalsa/asoundlib.h>
+#include "AudioALSADeviceConfigManager.h"
+#include "AudioALSADriverUtility.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSADeviceConfigManager"
+
+#define AUDIO_DEVICE_EXT_CONFIG_FILE "/vendor/etc/audio_device.xml"
+
+namespace android {
+
+DeviceCtlDescriptor::DeviceCtlDescriptor() {
+ DeviceStatusCounter = 0;
+}
+
+
+AudioALSADeviceConfigManager *AudioALSADeviceConfigManager::UniqueAlsaDeviceConfigParserInstance = NULL;
+
+AudioALSADeviceConfigManager *AudioALSADeviceConfigManager::getInstance() {
+ if (UniqueAlsaDeviceConfigParserInstance == 0) {
+ UniqueAlsaDeviceConfigParserInstance = new AudioALSADeviceConfigManager();
+ }
+ return UniqueAlsaDeviceConfigParserInstance;
+}
+
+AudioALSADeviceConfigManager::AudioALSADeviceConfigManager():
+ mConfigsupport(false),
+ mInit(false),
+ mMixer(NULL)
+
+{
+ ALOGV("%s()", __FUNCTION__);
+
+#ifdef CONFIG_MT_ENG_BUILD
+ mLogEnable = 1;
+#else
+ mLogEnable = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);
+#endif
+
+ int ret = LoadAudioConfig(AUDIO_DEVICE_EXT_CONFIG_FILE);
+ if (ret != NO_ERROR) {
+ mConfigsupport = false;
+ } else {
+ mConfigsupport = true;
+ }
+
+ if (mMixer == NULL) {
+ mMixer = AudioALSADriverUtility::getInstance()->getMixer();
+ ASSERT(mMixer != NULL);
+ }
+
+ mInit = true;
+}
+
+status_t AudioALSADeviceConfigManager::GetVersion(TiXmlElement *root) {
+ const char *VersionNumber = root->Attribute("value"); // get action
+ VersionControl = String8(VersionNumber);
+ ALOGD("GetVersion = %s", VersionNumber);
+ return NO_ERROR;
+}
+
+bool AudioALSADeviceConfigManager::CheckDeviceExist(const char *devicename) {
+ for (size_t i = 0; i < mDeviceVector.size(); i++) {
+ DeviceCtlDescriptor *DeviceScriptor = mDeviceVector.itemAt(i);
+ if (strcmp(devicename, DeviceScriptor->mDevicename.string()) == 0) {
+ ALOGV("%s() exist devicename = %s", __FUNCTION__, devicename);
+ return true;
+ }
+ }
+ ALOGV("%s() not exist devicename = %s", __FUNCTION__, devicename);
+ return false;
+}
+
+DeviceCtlDescriptor *AudioALSADeviceConfigManager::GetDeviceDescriptorbyname(const char *devicename) {
+ ALOGV("%s", __FUNCTION__);
+ for (size_t i = 0; i < mDeviceVector.size(); i++) {
+ DeviceCtlDescriptor *DeviceScriptor = mDeviceVector.itemAt(i);
+ if (strcmp(devicename, DeviceScriptor->mDevicename.string()) == 0) {
+ ALOGV("%s() exist devicename = %s", __FUNCTION__, devicename);
+ return mDeviceVector.itemAt(i);
+ }
+ }
+ return NULL;
+}
+
+status_t AudioALSADeviceConfigManager::ParseDeviceSequence(TiXmlElement *root) {
+ DeviceCtlDescriptor *TempDeviceDescriptor = NULL;
+ if (root != NULL) {
+ const char *devicename = root->Attribute("name"); // get path name
+ const char *action = root->Attribute("value"); // get action
+ ALOGV("%s() devicename = %s action = %s", __FUNCTION__, devicename, action);
+ if (CheckDeviceExist(devicename) == false) { // this device has not exist , new object
+ TempDeviceDescriptor = new DeviceCtlDescriptor();
+ TempDeviceDescriptor->mDevicename = String8(devicename);
+ mDeviceVector.add(TempDeviceDescriptor);
+ } else {
+ TempDeviceDescriptor = GetDeviceDescriptorbyname(devicename); // get instance in vector
+ }
+
+ if (TempDeviceDescriptor == NULL) {
+ ALOGE("%s() is NULL pointer , return", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ if (strcmp(action, AUDIO_DEVICE_TURNON) == 0) {
+ ALOGV("add turn on sequnce");
+ TiXmlElement *child = root->FirstChildElement("kctl");
+ while (child != NULL) {
+ const char *valname = child->Attribute("name");
+ const char *valvalue = child->Attribute("value");
+ ALOGV("valname = %s valvalue = %s ", valname, valvalue);
+ TempDeviceDescriptor->mDeviceCltonVector.add(String8(valname));
+ TempDeviceDescriptor->mDeviceCltonVector.add(String8(valvalue));
+ child = child->NextSiblingElement("kctl");
+ }
+ } else if (strcmp(action, AUDIO_DEVICE_TURNOFF) == 0) {
+ ALOGV("add turn off sequnce");
+ TiXmlElement *child = root->FirstChildElement("kctl");
+ while (child != NULL) {
+ const char *valname = child->Attribute("name");
+ const char *valvalue = child->Attribute("value");
+ ALOGV("valname = %s valvalue = %s ", valname, valvalue);
+ TempDeviceDescriptor->mDeviceCltoffVector.add(String8(valname));
+ TempDeviceDescriptor->mDeviceCltoffVector.add(String8(valvalue));
+ child = child->NextSiblingElement("kctl");
+ }
+ } else if (strcmp(action, AUDIO_DEVICE_SETTING) == 0) {
+ ALOGV("add AUDIO_DEVICE_SETTING");
+ TiXmlElement *child = root->FirstChildElement("kctl");
+ while (child != NULL) {
+ const char *valname = child->Attribute("name");
+ const char *valvalue = child->Attribute("value");
+ ALOGV("valname = %s valvalue = %s ", valname, valvalue);
+ TempDeviceDescriptor->mDeviceCltsettingVector.add(String8(valname));
+ TempDeviceDescriptor->mDeviceCltsettingVector.add(String8(valvalue));
+ child = child->NextSiblingElement("kctl");
+ }
+ } else {
+ ALOGD("device sequnce either not turn on and turn off");
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t AudioALSADeviceConfigManager::ParseInitSequence(TiXmlElement *root) {
+ ALOGD("+%s()", __FUNCTION__);
+ TiXmlElement *child = root->FirstChildElement("kctl");
+ while (child != NULL) {
+ const char *valname = child->Attribute("name");
+ const char *valvalue = child->Attribute("value");
+ ALOGD("valname = %s valvalue = %s ", valname, valvalue);
+ mDeviceCtlSeq.mDeviceCltNameVector.add(String8(valname));
+ mDeviceCtlSeq.mDeviceCltValueVector.add(String8(valvalue));
+ child = child->NextSiblingElement("kctl");
+ }
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+bool AudioALSADeviceConfigManager::SupportConfigFile() {
+ return mConfigsupport;
+}
+
+status_t AudioALSADeviceConfigManager::LoadAudioConfig(const char *path) {
+ if (mInit == true) {
+ return ALREADY_EXISTS;
+ }
+
+ ALOGV("%s()", __FUNCTION__);
+ TiXmlDocument doc(path);
+ bool loadOkay = doc.LoadFile();
+ if (loadOkay) {
+ // document is loaded
+ ALOGV("LoadAudioConfig success ");
+
+ // here handle for xml version and other inforamtion
+ TiXmlDeclaration *declaration = doc.FirstChild()->ToDeclaration();
+ ALOGD("TiXmlDeclaration version = %s, Encoding = %s, Standalone = %s",
+ declaration->Version(), declaration->Encoding(), declaration->Standalone());
+
+ TiXmlElement *root = doc.FirstChildElement("root");
+
+ if (root == NULL) { // no root element in this xml
+ root = doc.FirstChildElement("mixercontrol");
+ } else {
+ root = root->FirstChildElement("mixercontrol");
+ }
+
+ if (root != NULL) {
+ TiXmlElement *Version = root->FirstChildElement("versioncontrol"); // find with version contol
+ if (Version != NULL) {
+ GetVersion(Version);
+ }
+ }
+
+ if (root) {
+ ALOGV("FirstChildElement can find mixer");
+ ParseInitSequence(root);
+ TiXmlElement *child = root->FirstChildElement("path");
+ while (child) {
+ ParseDeviceSequence(child);
+ child = child->NextSiblingElement("path");
+ }
+ }
+ } else {
+ // load failed
+ ALOGE("LoadAudioConfig fail ");
+ return INVALID_OPERATION;
+ }
+ return NO_ERROR;
+}
+
+int AudioALSADeviceConfigManager::setMixerByteCtl(struct mixer_ctl *ctl, char **values, unsigned int numValues) {
+ int ret = 0;
+ char *buf;
+ char *end;
+ unsigned int i;
+ long n;
+
+ buf = (char *)malloc(numValues);
+
+ if (buf == NULL) {
+ ALOGD("%s(), Failed to alloc mem for bytes %d\n", __FUNCTION__, numValues);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < numValues; i++) {
+ errno = 0;
+ n = strtol(values[i], &end, 0);
+ if (*end) {
+ ALOGW("%s not an integer\n", values[i]);
+ ret = -EINVAL;
+ break;
+ }
+ if (errno) {
+ ALOGW("strtol: %s: %s\n", values[i], strerror(errno));
+ ret = -EINVAL;
+ break;
+ }
+ if (n < 0 || n > 0xff) {
+ ALOGW("%s should be between [0, 0xff]\n", values[i]);
+ ret = -EINVAL;
+ break;
+ }
+ buf[i] = n;
+ }
+
+ if (ret == 0) {
+ ret = mixer_ctl_set_array(ctl, buf, numValues);
+ if (ret < 0) {
+ ALOGW("Failed to set binary control\n");
+ }
+ }
+
+ free(buf);
+ return ret;
+}
+
+int AudioALSADeviceConfigManager::setMixerCtlValue(String8 cltName, String8 cltValue) {
+ struct mixer_ctl *ctl;
+ enum mixer_ctl_type type;
+ struct mixer *mixer = mMixer;
+
+ unsigned int num_ctl_values;
+ unsigned int num_values = 0;
+ unsigned int str_len = cltValue.size();
+
+ unsigned int i, j;
+
+ int ret = 0;
+
+ const char *charCtlValue = cltValue.string();
+ const char *charCltName = cltName.string();
+
+ ALOGV("%s(), charCltName = %s, charCtlValue = %s\n", __FUNCTION__, charCltName, charCtlValue);
+
+ if (isdigit(charCltName[0])) {
+ ctl = mixer_get_ctl(mixer, atoi(charCltName));
+ } else {
+ ctl = mixer_get_ctl_by_name(mixer, charCltName);
+ }
+
+ if (!ctl) {
+ ALOGD("Invalid mixer control\n");
+ return -EINVAL;
+ }
+
+ type = mixer_ctl_get_type(ctl);
+ num_ctl_values = mixer_ctl_get_num_values(ctl);
+
+ char values[num_ctl_values][str_len + 1];
+ for (i = 0; i < num_ctl_values; i++) {
+ memset(values[i], 0, str_len + 1);
+ }
+
+ /* To get num of values*/
+ if (num_ctl_values > 1) {
+ for (i = 0; i <= str_len && num_values < num_ctl_values; i++) {
+ bool find_value = false;
+ if (*(charCtlValue) == 0) {
+ break;
+ }
+
+ for (j = 0; j < str_len; j++) {
+ if ((*(charCtlValue) >= '0') && (*(charCtlValue) <= '9')) {
+ values[num_values][j] = *charCtlValue++;
+ if (find_value == false) {
+ find_value = true;
+ }
+ } else {
+ if (*(charCtlValue) != 0) {
+ charCtlValue++;
+ }
+ break;
+ }
+ }
+
+ if (find_value) {
+ num_values++;
+ }
+ }
+
+ ALOGD("num_values is %u, And the value is as bellow\n", num_values);
+ for (i = 0; i < num_values; i++) {
+ ALOGD("String values[%d]:%s\n", i, values[i]);
+ }
+ } else {
+ num_values = 1;
+ memcpy(values[0], cltValue.string(), cltValue.size());
+ }
+
+ if (type == MIXER_CTL_TYPE_BYTE) {
+ return setMixerByteCtl(ctl, (char **)values, num_values);
+ }
+
+ if (isdigit(values[0][0])) {
+ if (num_values == 1) {
+ /* Set all values the same */
+ int value = atoi(values[0]);
+
+ for (i = 0; i < num_ctl_values; i++) {
+ ret = mixer_ctl_set_value(ctl, i, value);
+ if (ret) {
+ ALOGD("Error: invalid value\n");
+ return ret;
+ }
+ }
+ } else {
+ /* Set multiple values */
+ if (num_values > num_ctl_values) {
+ ALOGD("Error: %u values given, but control only takes %d\n",
+ num_values, num_ctl_values);
+ return -EINVAL;
+ }
+ for (i = 0; i < num_values; i++) {
+ ret = mixer_ctl_set_value(ctl, i, atoi(values[i]));
+ if (ret) {
+ ALOGD("Error: invalid value for index %d\n", i);
+ return ret;
+ }
+ }
+ }
+ } else {
+ ALOGD("%s(), Enum_values Num %u\n", __FUNCTION__, num_values);
+ if (type == MIXER_CTL_TYPE_ENUM) {
+ if (num_values != 1) {
+ ALOGD("Enclose strings in quotes and try again\n");
+ return -EINVAL;
+ }
+ ret = mixer_ctl_set_enum_by_string(ctl, cltValue.string());
+ if (ret)
+ ALOGD("Error: invalid enum value\n");
+ } else {
+ ALOGD("Error: only enum types can be set with strings\n");
+ }
+ }
+
+ return ret;
+}
+
+int AudioALSADeviceConfigManager::setMixerCtl(String8 cltName, String8 cltValue) {
+ int ret = 0;
+ struct mixer_ctl *ctl = mixer_get_ctl_by_name(mMixer, cltName.string());
+ enum mixer_ctl_type type = mixer_ctl_get_type(ctl);
+ ALOGV("%s(), cltName = %s, cltValue = %s, cltType = %d", __FUNCTION__, cltName.string(), cltValue.string(), type);
+
+ switch (type) {
+ case MIXER_CTL_TYPE_ENUM:
+ ret = mixer_ctl_set_enum_by_string(ctl, cltValue.string());
+ break;
+ case MIXER_CTL_TYPE_BOOL:
+ case MIXER_CTL_TYPE_INT:
+ case MIXER_CTL_TYPE_BYTE:
+ ret = setMixerCtlValue(cltName, cltValue);
+ break;
+ default:
+ ALOGE("%s(), Error: Unsupport mixer ctl type %d, cltName = %s, cltValue = %s",
+ __FUNCTION__, type, cltName.string(), cltValue.string());
+ ASSERT(0);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+status_t AudioALSADeviceConfigManager::ApplyDeviceTurnonSequenceByName(const char *DeviceName) {
+ DeviceCtlDescriptor *descriptor = GetDeviceDescriptorbyname(DeviceName);
+ if (descriptor == NULL) {
+ ALOGE("%s DeviceName = %s descriptor == NULL", __FUNCTION__, DeviceName);
+ return INVALID_OPERATION;
+ }
+ ALOGD("%s() DeviceName = %s descriptor->DeviceStatusCounte = %d", __FUNCTION__, DeviceName, descriptor->DeviceStatusCounter);
+ if (descriptor->DeviceStatusCounter == 0) {
+ for (size_t count = 0; count < descriptor->mDeviceCltonVector.size(); count += 2) {
+ String8 cltname = descriptor->mDeviceCltonVector.itemAt(count);
+ String8 cltvalue = descriptor->mDeviceCltonVector.itemAt(count + 1);
+ ALOGV("cltname = %s cltvalue = %s", cltname.string(), cltvalue.string());
+ if (setMixerCtl(cltname, cltvalue)) {
+ ALOGE("Error: %s cltname.string () = %s cltvalue.string () = %s", __FUNCTION__, cltname.string(), cltvalue.string());
+ ASSERT(false);
+ }
+ }
+ }
+ descriptor->DeviceStatusCounter++;
+ return NO_ERROR;
+}
+
+status_t AudioALSADeviceConfigManager::ApplyDeviceTurnoffSequenceByName(const char *DeviceName) {
+ DeviceCtlDescriptor *descriptor = GetDeviceDescriptorbyname(DeviceName);
+ if (descriptor == NULL) {
+ ALOGE("%s(), DeviceName = %s descriptor == NULL", __FUNCTION__, DeviceName);
+ return INVALID_OPERATION;
+ }
+ ALOGD("%s(), DeviceName = %s descriptor->DeviceStatusCounter = %d", __FUNCTION__, DeviceName, descriptor->DeviceStatusCounter);
+
+ descriptor->DeviceStatusCounter--;
+ if (descriptor->DeviceStatusCounter == 0) {
+ for (size_t count = 0; count < descriptor->mDeviceCltoffVector.size(); count += 2) {
+ String8 cltname = descriptor->mDeviceCltoffVector.itemAt(count);
+ String8 cltvalue = descriptor->mDeviceCltoffVector.itemAt(count + 1);
+ ALOGV("%s(), cltname = %s cltvalue = %s", __FUNCTION__, cltname.string(), cltvalue.string());
+ if (setMixerCtl(cltname, cltvalue)) {
+ ALOGE("%s(), Error: ApplyDeviceTurnoffSequenceByName devicename = %s", __FUNCTION__, descriptor->mDevicename.string());
+ ASSERT(false);
+ }
+ }
+ } else if (descriptor->DeviceStatusCounter < 0) {
+ ALOGW("%s(), DeviceName = %s DeviceStatusCounter < 0", __FUNCTION__, DeviceName);
+ descriptor->DeviceStatusCounter = 0;
+ }
+ return NO_ERROR;
+}
+
+
+status_t AudioALSADeviceConfigManager::ApplyDeviceSettingByName(const char *DeviceName) {
+ DeviceCtlDescriptor *descriptor = GetDeviceDescriptorbyname(DeviceName);
+ if (descriptor == NULL) {
+ ALOGE("%s DeviceName = %s descriptor == NULL", __FUNCTION__, DeviceName);
+ return INVALID_OPERATION;
+ }
+ ALOGD_IF(mLogEnable, "%s() DeviceName = %s descriptor->DeviceStatusCounter = %d", __FUNCTION__, DeviceName, descriptor->DeviceStatusCounter);
+
+ for (size_t count = 0; count < descriptor->mDeviceCltsettingVector.size(); count += 2) {
+ String8 cltname = descriptor->mDeviceCltsettingVector.itemAt(count);
+ String8 cltvalue = descriptor->mDeviceCltsettingVector.itemAt(count + 1);
+ ALOGD_IF(mLogEnable, "cltname = %s cltvalue = %s", cltname.string(), cltvalue.string());
+ if (setMixerCtl(cltname, cltvalue)) {
+ ALOGE("Error: %s() devicename = %s", __FUNCTION__, descriptor->mDevicename.string());
+ ASSERT(false);
+ }
+ }
+ return NO_ERROR;
+}
+
+void AudioALSADeviceConfigManager::dump() {
+ DeviceCtlDescriptor *descriptor = NULL;
+
+ ALOGD("AudioALSADeviceConfigManager dump init sequence");
+ for (size_t count = 0; count < mDeviceCtlSeq.mDeviceCltNameVector.size() ; count++) {
+ String8 temp = mDeviceCtlSeq.mDeviceCltNameVector.itemAt(count);
+ String8 temp1 = mDeviceCtlSeq.mDeviceCltValueVector.itemAt(count);
+ ALOGD("init sequnce kclt = %s value = %s", temp.string(), temp1.string());
+ }
+
+ for (size_t count = 0; count < mDeviceVector.size() ; count++) {
+ descriptor = mDeviceVector.itemAt(count);
+ ALOGD("mDescritor->name = %s", descriptor->mDevicename.string());
+ for (size_t sequence = 0; sequence < descriptor->mDeviceCltonVector.size() ; sequence += 2) {
+ String8 temp = descriptor->mDeviceCltonVector.itemAt(sequence);
+ String8 temp1 = descriptor->mDeviceCltonVector.itemAt(sequence + 1);
+ ALOGD("turn on name = %s value = %s ", temp.string(), temp1.string());
+ }
+ for (size_t sequence = 0; sequence < descriptor->mDeviceCltoffVector.size() ; sequence += 2) {
+ String8 temp = descriptor->mDeviceCltoffVector.itemAt(sequence);
+ String8 temp1 = descriptor->mDeviceCltoffVector.itemAt(sequence + 1);
+ ALOGD("turn off name = %s value = %s ", temp.string(), temp1.string());
+ }
+ for (size_t sequence = 0; sequence < descriptor->mDeviceCltsettingVector.size() ; sequence += 2) {
+ String8 temp = descriptor->mDeviceCltsettingVector.itemAt(sequence);
+ String8 temp1 = descriptor->mDeviceCltsettingVector.itemAt(sequence + 1);
+ ALOGD("mDeviceCltsettingVector name = %s value = %s ", temp.string(), temp1.string());
+ }
+ }
+}
+
+
+}
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSADeviceParser.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSADeviceParser.cpp
new file mode 100644
index 0000000..d710034
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSADeviceParser.cpp
@@ -0,0 +1,429 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSADeviceParser.h"
+#include <stdint.h>
+#include <dirent.h>
+#include <sys/types.h>
+#if defined(MTK_AUDIO_KS)
+#include <tinyxml.h>
+#endif
+
+#include "audio_custom_exp.h"
+#include "AudioUtility.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSADeviceParser"
+
+#define ALSASOUND_CARD_LOCATION "proc/asound/cards"
+#define ALSASOUND_DEVICE_LOCATION "/proc/asound/devices/"
+#define ALSASOUND_ASOUND_LOCATION "/proc/asound"
+#define ALSASOUND_PCM_LOCATION "/proc/asound/pcm"
+#define PROC_READ_BUFFER_SIZE (256)
+
+#define AUDIO_DEVICE_EXT_CONFIG_FILE "/vendor/etc/audio_device.xml"
+
+namespace android {
+
+static String8 keypcmPlayback = String8("playback");
+static String8 keypcmCapture = String8("capture");
+
+AudioALSADeviceParser *AudioALSADeviceParser::UniqueAlsaDeviceInstance = NULL;
+
+AudioALSADeviceParser *AudioALSADeviceParser::getInstance() {
+ if (UniqueAlsaDeviceInstance == 0) {
+ UniqueAlsaDeviceInstance = new AudioALSADeviceParser();
+ }
+ return UniqueAlsaDeviceInstance;
+}
+
+AudioALSADeviceParser::AudioALSADeviceParser() {
+ ALOGV("%s()", __FUNCTION__);
+
+#ifdef CONFIG_MT_ENG_BUILD
+ mLogEnable = 1;
+#else
+ mLogEnable = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);
+#endif
+
+ getCardName();
+ ParseCardIndex();
+ GetAllPcmAttribute();
+#if defined(MTK_AUDIODSP_SUPPORT) || defined(MTK_AUDIO_TUNNELING_SUPPORT)
+ GetAllCompressAttribute();
+#endif
+ QueryPcmDriverCapability();
+ dump();
+}
+
+void AudioALSADeviceParser::getCardName() {
+ bool cardNameSuccess = false;
+
+#if defined(MTK_AUDIO_KS)
+ TiXmlDocument doc(AUDIO_DEVICE_EXT_CONFIG_FILE);
+
+ if (doc.LoadFile()) {
+ TiXmlElement *root = doc.FirstChildElement("root");
+
+ if (root) {
+ TiXmlElement *card = root->FirstChildElement("card");
+
+ if (card) {
+ const char *cardName = card->Attribute("name");
+
+ if (cardName) {
+ mCardName = cardName;
+ cardNameSuccess = true;
+ } else {
+ ALOGE("%s(), get card name attribute fail", __FUNCTION__);
+ }
+ } else {
+ ALOGE("%s(), no card element", __FUNCTION__);
+ }
+ } else {
+ ALOGE("%s(), no root element", __FUNCTION__);
+ }
+ } else {
+ ALOGE("%s(), LoadFile fail, %s", __FUNCTION__, AUDIO_DEVICE_EXT_CONFIG_FILE);
+ }
+
+#else
+#if defined(MT_SOUND_CARD_CUSTOM_NAME) //defined in audio_custom_exp.h
+ mCardName = MT_SOUND_CARD_CUSTOM_NAME;
+#else
+ mCardName = keyCardName;
+#endif
+ cardNameSuccess = true;
+#endif
+
+ if (!cardNameSuccess) {
+ ALOGE("%s(), get card name fail", __FUNCTION__);
+ ASSERT(0);
+ } else {
+ ALOGD("%s(), card name %s", __FUNCTION__, mCardName.string());
+ }
+}
+
+void AudioALSADeviceParser::ParseCardIndex() {
+ /*
+ * $adb shell cat proc/asound/cards
+ * 0 [mtsndcard ]: mt-snd-card - mt-snd-card
+ * mt-snd-card
+ * mCardIndex = 0;
+ */
+ ALOGV("%s()", __FUNCTION__);
+ FILE *mCardFile = NULL;
+ char tempbuffer[PROC_READ_BUFFER_SIZE];
+ mCardFile = fopen(ALSASOUND_CARD_LOCATION, "r");
+ bool isCardIndexFound = false;
+ if (mCardFile) {
+ ALOGD("card open success");
+ while (!feof(mCardFile)) {
+ fgets(tempbuffer, PROC_READ_BUFFER_SIZE, mCardFile);
+
+ if (strchr(tempbuffer, '[')) { // this line contain '[' character
+ char *Rch = strtok(tempbuffer, "[");
+ mCardIndex = atoi(Rch);
+ ALOGD("\tcurrent CardIndex = %d, Rch = %s", mCardIndex, Rch);
+ Rch = strtok(NULL, " ]");
+ ALOGD("\tcurrent sound card name = %s", Rch);
+ if (strcmp(Rch, mCardName.string()) == 0) {
+ ALOGD("\tmCardIndex found = %d", mCardIndex);
+ isCardIndexFound = true;
+ break;
+ }
+ }
+
+ memset((void *)tempbuffer, 0, PROC_READ_BUFFER_SIZE);
+ }
+ } else {
+ ALOGE("Pcm open fail");
+ }
+
+ if (mCardFile) {
+ fclose(mCardFile);
+ }
+
+ ASSERT(isCardIndexFound);
+}
+
+void AudioALSADeviceParser::dump() {
+ size_t i = 0;
+ ALOGV("dump size = %zu", mAudioDeviceVector.size());
+ for (i = 0 ; i < mAudioDeviceVector.size(); i++) {
+ AudioDeviceDescriptor *temp = mAudioDeviceVector.itemAt(i);
+ ALOGV("name = %s, card index = %d, pcm index = %d, playback = %d, capture = %d",
+ temp->mStreamName.string(), temp->mCardindex, temp->mPcmindex,
+ temp->mplayback, temp->mRecord);
+ }
+}
+
+unsigned int AudioALSADeviceParser::GetPcmBufferSize(unsigned int pcmindex, unsigned int direction) {
+ size_t i = 0;
+ unsigned int buffersize = 0;
+ for (i = 0 ; i < mAudioDeviceVector.size(); i++) {
+ AudioDeviceDescriptor *temp = mAudioDeviceVector.itemAt(i);
+ if (temp->mPcmindex == pcmindex) {
+ if (direction == PCM_OUT) {
+ buffersize = temp->mPlayparam.mBufferBytes;
+ } else if (direction == PCM_IN) {
+ buffersize = temp->mRecordparam.mBufferBytes;
+ }
+ break;
+ }
+ }
+ ALOGD("%s buffersize = %d", __FUNCTION__, buffersize);
+ return buffersize;
+}
+
+
+unsigned int AudioALSADeviceParser::GetPcmIndexByString(String8 stringpair) {
+ ALOGV("%s() stringpair = %s ", __FUNCTION__, stringpair.string());
+ int pcmindex = -1;
+ size_t i = 0;
+ for (i = 0 ; i < mAudioDeviceVector.size(); i++) {
+ AudioDeviceDescriptor *temp = mAudioDeviceVector.itemAt(i);
+ if (temp->mStreamName.compare(stringpair) == 0) {
+ pcmindex = temp->mPcmindex;
+ ALOGD("compare pcm success = %d, stringpair = %s", pcmindex, stringpair.string());
+ break;
+ }
+ }
+
+ if (pcmindex < 0) {
+ for (i = 0 ; i < mAudioComprDevVector.size(); i++) {
+ AudioDeviceDescriptor *temp = mAudioComprDevVector.itemAt(i);
+ if (temp->mStreamName.compare(stringpair) == 0) {
+ pcmindex = temp->mPcmindex;
+ ALOGD("Compare compress success id = %d", pcmindex);
+ break;
+ }
+ }
+ }
+ return pcmindex;
+}
+
+unsigned int AudioALSADeviceParser::GetCardIndexByString(String8 stringpair) {
+ ALOGV("%s() stringpair = %s ", __FUNCTION__, stringpair.string());
+ int Cardindex = -1;
+ size_t i = 0;
+ for (i = 0 ; i < mAudioDeviceVector.size(); i++) {
+ AudioDeviceDescriptor *temp = mAudioDeviceVector.itemAt(i);
+ if (temp->mStreamName.compare(stringpair) == 0) {
+ Cardindex = temp->mCardindex;
+ ALOGV(" compare success Cardindex = %d", Cardindex);
+ break;
+ }
+ }
+
+ if (Cardindex < 0) {
+ for (i = 0 ; i < mAudioComprDevVector.size(); i++) {
+ AudioDeviceDescriptor *temp = mAudioComprDevVector.itemAt(i);
+ if (temp->mStreamName.compare(stringpair) == 0) {
+ Cardindex = temp->mCardindex;
+ ALOGD("compare compress Cardindex success = %d", Cardindex);
+ break;
+ }
+ }
+ }
+ return Cardindex;
+}
+
+
+void AudioALSADeviceParser::SetPcmCapability(AudioDeviceDescriptor *Descriptor, char *Buffer) {
+ if (Buffer == NULL) {
+ return;
+ }
+ String8 CompareString = String8(Buffer);
+ //ALOGD("SetPcmCapability CompareString = %s",CompareString.string ());
+ if ((CompareString.compare(keypcmPlayback)) == 0) {
+ //ALOGD("SetPcmCapability playback support");
+ Descriptor->mplayback = 1;
+ }
+ if ((CompareString.compare(keypcmCapture)) == 0) {
+ //ALOGD("SetPcmCapability capture support");
+ Descriptor->mRecord = 1;
+ }
+}
+
+void AudioALSADeviceParser::AddPcmString(char *InputBuffer) {
+ ALOGD_IF(mLogEnable, "AddPcmString InputBuffer = %s", InputBuffer);
+ char *Rch;
+ char *rest_of_str = NULL;
+ AudioDeviceDescriptor *mAudiioDeviceDescriptor = NULL;
+ Rch = strtok_r(InputBuffer, "-", &rest_of_str);
+ // parse for stream name
+ if (Rch != NULL) {
+ mAudiioDeviceDescriptor = new AudioDeviceDescriptor();
+ mAudiioDeviceDescriptor->mCardindex = atoi(Rch);
+ Rch = strtok_r(NULL, ":", &rest_of_str);
+ mAudiioDeviceDescriptor->mPcmindex = atoi(Rch);
+ Rch = strtok_r(NULL, ": ", &rest_of_str);
+ mAudiioDeviceDescriptor->mStreamName = String8(Rch);
+ Rch = strtok_r(NULL, ": ", &rest_of_str);
+ mAudioDeviceVector.push(mAudiioDeviceDescriptor);
+ }
+ // parse for playback or record support
+ while (Rch != NULL) {
+ Rch = strtok_r(NULL, ": ", &rest_of_str);
+ if (mAudiioDeviceDescriptor != NULL) {
+ SetPcmCapability(mAudiioDeviceDescriptor, Rch);
+ }
+ }
+}
+
+void AudioALSADeviceParser::GetAllPcmAttribute(void) {
+ ALOGV("%s()", __FUNCTION__);
+ FILE *mPcmFile = NULL;
+ char tempbuffer[PROC_READ_BUFFER_SIZE];
+ int result;
+ mPcmFile = fopen(ALSASOUND_PCM_LOCATION, "r");
+ if (mPcmFile) {
+ ALOGD("%s(), Pcm open success", __FUNCTION__);
+ while (!feof(mPcmFile)) {
+ fgets(tempbuffer, PROC_READ_BUFFER_SIZE, mPcmFile);
+ AddPcmString(tempbuffer);
+ memset((void *)tempbuffer, 0, PROC_READ_BUFFER_SIZE);
+ }
+ } else {
+ ALOGD("%s(), Pcm open fail", __FUNCTION__);
+ }
+
+ if (mPcmFile) {
+ fclose(mPcmFile);
+ }
+}
+
+void AudioALSADeviceParser::GetAllCompressAttribute(void) {
+ ALOGV("%s()", __FUNCTION__);
+ FILE *compress_file = NULL;
+ char tempbuffer[PROC_READ_BUFFER_SIZE];
+ char compress_info_path[PROC_READ_BUFFER_SIZE];
+ int result;
+ struct dirent *de;
+ snprintf(compress_info_path, sizeof(compress_info_path),
+ "%s/card%d/", ALSASOUND_ASOUND_LOCATION, mCardIndex);
+
+ DIR *d = opendir(compress_info_path);
+ if (d == 0) {
+ ALOGD("%s(), Soundcard path open fail", __FUNCTION__);
+ return;
+ }
+
+ while ((de = readdir(d)) != NULL) {
+ if (strncmp(de->d_name, "compr", 5) == 0) {
+ strncat(compress_info_path, de->d_name, strlen(de->d_name));
+ strncat(compress_info_path, "/info", 5);
+ compress_file = fopen(compress_info_path, "r");
+ if (compress_file) {
+ ALOGD("%s(), Compress info open success", __FUNCTION__);
+ char *Rch;
+ char *rest_of_str = NULL;
+ AudioDeviceDescriptor *mAudiioDeviceDescriptor = NULL;
+ mAudiioDeviceDescriptor = new AudioDeviceDescriptor();
+ while (!feof(compress_file)) {
+ fgets(tempbuffer, PROC_READ_BUFFER_SIZE, compress_file);
+ Rch = strtok_r(tempbuffer, ": ", &rest_of_str);
+ if (Rch != NULL) {
+ if (strncmp(Rch, "card", 4) == 0) {
+ mAudiioDeviceDescriptor->mCardindex = atoi(rest_of_str);
+ } else if (strncmp(Rch, "device", 6) == 0) {
+ mAudiioDeviceDescriptor->mPcmindex = atoi(rest_of_str);
+ } else if (strncmp(Rch, "stream", 6) == 0) {
+ Rch = strtok_r(NULL, ": ", &rest_of_str);
+ if ((strncmp(Rch, "PLAYBACK", 8)) == 0) {
+ mAudiioDeviceDescriptor->mplayback = 1;
+ } else if ((strncmp(Rch, "CAPTURE", 7)) == 0) {
+ mAudiioDeviceDescriptor->mRecord = 1;
+ }
+ } else if ((strncmp(Rch, "id", 2)) == 0) {
+ Rch = strtok_r(NULL, " ", &rest_of_str);
+ mAudiioDeviceDescriptor->mStreamName = String8(Rch);
+ }
+ }
+ memset((void *)tempbuffer, 0, PROC_READ_BUFFER_SIZE);
+ }
+ mAudioComprDevVector.push(mAudiioDeviceDescriptor);
+ } else {
+ ALOGD("%s(), Compress file open fail", __FUNCTION__);
+ }
+ }
+ }
+ if (compress_file) {
+ fclose(compress_file);
+ closedir(d);
+ }
+
+}
+
+status_t AudioALSADeviceParser::GetPcmDriverparameters(AudioPcmDeviceparam *PcmDeviceparam, struct pcm_params *params) {
+ PcmDeviceparam->mRateMin = pcm_params_get_min(params, PCM_PARAM_RATE);
+ PcmDeviceparam->mRateMax = pcm_params_get_max(params, PCM_PARAM_RATE);
+ ALOGD_IF(mLogEnable, "Rate:\tmin=%uHz\tmax=%uHz\n", PcmDeviceparam->mRateMin, PcmDeviceparam->mRateMax);
+
+ PcmDeviceparam->mChannelMin = pcm_params_get_min(params, PCM_PARAM_CHANNELS);
+ PcmDeviceparam->mChannelMax = pcm_params_get_max(params, PCM_PARAM_CHANNELS);
+ ALOGD_IF(mLogEnable, "Channels:\tmin=%u\t\tmax=%u\n", PcmDeviceparam->mChannelMin, PcmDeviceparam->mChannelMax);
+
+ PcmDeviceparam->mSampleBitMin = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS);
+ PcmDeviceparam->mSampleBitMax = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS);
+ ALOGD_IF(mLogEnable, "Sample bits:\tmin=%u\t\tmax=%u\n", PcmDeviceparam->mSampleBitMin, PcmDeviceparam->mSampleBitMax);
+
+ PcmDeviceparam->mPreriodSizeMin = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE);
+ PcmDeviceparam->mPreriodSizeMax = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE);
+ ALOGD_IF(mLogEnable, "Period size:\tmin=%u\t\tmax=%u\n", PcmDeviceparam->mPreriodSizeMin, PcmDeviceparam->mPreriodSizeMax);
+
+ PcmDeviceparam->mPreriodCountMin = pcm_params_get_min(params, PCM_PARAM_PERIODS);
+ PcmDeviceparam->mPreriodCountMax = pcm_params_get_max(params, PCM_PARAM_PERIODS);
+ ALOGD_IF(mLogEnable, "Period count:\tmin=%u\t\tmax=%u\n", PcmDeviceparam->mPreriodCountMin, PcmDeviceparam->mPreriodCountMax);
+
+ PcmDeviceparam->mBufferBytes = pcm_params_get_max(params, PCM_PARAM_BUFFER_BYTES);
+ ALOGD_IF(mLogEnable, "PCM_PARAM_BUFFER_BYTES :\t max=%u\t\n", PcmDeviceparam->mBufferBytes);
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSADeviceParser::QueryPcmDriverCapability() {
+ struct pcm_params *params = NULL;
+ AudioDeviceDescriptor *temp = NULL;;
+ int Direction = 0;
+ for (size_t i = 0; i < mAudioDeviceVector.size(); i++) {
+ temp = mAudioDeviceVector.itemAt(i);
+ ALOGD_IF(mLogEnable, "pcm %d %s %s, pcm mCardindex %d mPcmindex %d", temp->mPcmindex, temp->mStreamName.string(),
+ temp->mCodecName.string(), temp->mCardindex, temp->mPcmindex);
+ if (temp->mplayback == 1) {
+ params = pcm_params_get(temp->mCardindex, temp->mPcmindex, PCM_OUT);
+ if (params == NULL) {
+ ALOGD("Device %zu does not exist playback", i);
+ } else {
+ if (temp->mplayback == 1) {
+ GetPcmDriverparameters(&temp->mPlayparam, params);
+ }
+ }
+ if (params != NULL) {
+ pcm_params_free(params);
+ params = NULL;
+ }
+ }
+
+ if (temp->mRecord == 1) {
+ params = pcm_params_get(temp->mCardindex, temp->mPcmindex, PCM_IN);
+ if (params == NULL) {
+ ALOGD("Device %zu does not exist capture", i);
+ } else {
+ if (temp->mRecord == 1) {
+ GetPcmDriverparameters(&temp->mRecordparam, params);
+ }
+ }
+ if (params != NULL) {
+ pcm_params_free(params);
+ params = NULL;
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
+
+}
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSADriverUtility.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSADriverUtility.cpp
new file mode 100644
index 0000000..9e980e7
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSADriverUtility.cpp
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSADriverUtility.h"
+#include <cutils/properties.h>
+#include <AudioLock.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <AudioALSADeviceParser.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSADriverUtility"
+
+namespace android {
+
+AudioALSADriverUtility *AudioALSADriverUtility::mAudioALSADriverUtility = NULL;
+AudioALSADriverUtility *AudioALSADriverUtility::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSADriverUtility == NULL) {
+ mAudioALSADriverUtility = new AudioALSADriverUtility();
+ }
+ ASSERT(mAudioALSADriverUtility != NULL);
+ return mAudioALSADriverUtility;
+}
+
+int AudioALSADriverUtility::GetPropertyValue(const char *ProPerty_Key) {
+ int result;
+ char value[PROPERTY_VALUE_MAX];
+ property_get(ProPerty_Key, value, "0");
+ result = atoi(value);
+ return result;
+}
+
+int AudioALSADriverUtility::setPropertyValue(const char *ProPerty_Key, int value) {
+ int result;
+ char valuestring[PROPERTY_VALUE_MAX];
+
+ sprintf(valuestring, "%d", value);
+ property_set(ProPerty_Key, valuestring);
+ return 0;
+}
+
+AudioALSADriverUtility::AudioALSADriverUtility() :
+ mMixer(NULL) {
+ ALOGD("%s()", __FUNCTION__);
+
+ mMixer = mixer_open(AudioALSADeviceParser::getInstance()->GetCardIndex());
+ ALOGD("mMixer = %p", mMixer);
+ ASSERT(mMixer != NULL);
+}
+
+struct mixer_ctl *AudioALSADriverUtility::getMixerCtrlByName(struct mixer *mixer, const char *name) {
+ return mixer_get_ctl_by_name(mixer, name);
+}
+
+int AudioALSADriverUtility::mixerCtrlGetValue(struct mixer_ctl *ctl, unsigned int id) {
+ return mixer_ctl_get_value(ctl, id);
+}
+
+int AudioALSADriverUtility::mixerCtrlSetValue(struct mixer_ctl *ctl, unsigned int id, int value) {
+ return mixer_ctl_set_value(ctl, id, value);
+}
+
+AudioALSADriverUtility::~AudioALSADriverUtility() {
+ ALOGD("%s()", __FUNCTION__);
+
+ mixer_close(mMixer);
+ mMixer = NULL;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAFMController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAFMController.cpp
new file mode 100644
index 0000000..e99e4db
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAFMController.cpp
@@ -0,0 +1,528 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#define LOG_TAG "AudioALSAFMController"
+
+#include "AudioALSAFMController.h"
+
+#include <sys/ioctl.h>
+#include <cutils/properties.h>
+
+#include "WCNChipController.h"
+
+#include <AudioLock.h>
+#include "AudioALSADriverUtility.h"
+#include "AudioALSAHardwareResourceManager.h"
+//#include "AudioALSAVolumeController.h"
+//#include "AudioVolumeInterface.h"
+
+#include "AudioVolumeFactory.h"
+#include "AudioALSAStreamManager.h"
+
+#include "AudioALSASampleRateController.h"
+
+#include "AudioALSADeviceParser.h"
+
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+#include "AudioALSANLEController.h"
+#endif
+
+#if defined(MTK_AUDIO_KS)
+#include "AudioALSADeviceConfigManager.h"
+#include "AudioSmartPaController.h"
+#endif
+
+namespace android {
+
+/*==============================================================================
+ * Property keys
+ *============================================================================*/
+
+const char PROPERTY_KEY_FM_FORCE_DIRECT_MODE_TYPE[PROPERTY_KEY_MAX] = "af.fm.force_direct_mode_type";
+
+/*==============================================================================
+ * Const Value
+ *============================================================================*/
+
+/*==============================================================================
+ * Enumerator
+ *============================================================================*/
+
+enum fm_force_direct_mode_t {
+ FM_FORCE_NONE = 0x0,
+ FM_FORCE_DIRECT_MODE = 0x1,
+ FM_FORCE_INDIRECT_MODE = 0x2,
+};
+
+/*==============================================================================
+ * Singleton Pattern
+ *============================================================================*/
+
+AudioALSAFMController *AudioALSAFMController::mAudioALSAFMController = NULL;
+
+AudioALSAFMController *AudioALSAFMController::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSAFMController == NULL) {
+ mAudioALSAFMController = new AudioALSAFMController();
+ }
+ ASSERT(mAudioALSAFMController != NULL);
+ return mAudioALSAFMController;
+}
+
+/*==============================================================================
+ * Constructor / Destructor / Init / Deinit
+ *============================================================================*/
+
+AudioALSAFMController::AudioALSAFMController() :
+ mFmDeviceCallback(NULL),
+ mHardwareResourceManager(AudioALSAHardwareResourceManager::getInstance()),
+ mAudioALSAVolumeController(AudioVolumeFactory::CreateAudioVolumeController()),
+ mFmEnable(false),
+ mIsFmDirectConnectionMode(true),
+ mUseFmDirectConnectionMode(true),
+#if defined(SUPPORT_FM_AUDIO_BY_PROPRIETARY_PARAMETER_CONTROL)
+ mFmVolume(0.5), // for Demo if fmw never changes the volume
+#else
+ mFmVolume(0.0), // valid volume value: 0.0 ~ 1.0
+#endif
+ mPcm(NULL),
+ mPcmUL(NULL),
+ mOuput_device(AUDIO_DEVICE_NONE),
+ mHyBridNLERegister(false) {
+ ALOGD("%s()", __FUNCTION__);
+
+#ifdef CONFIG_MT_ENG_BUILD
+ mLogEnable = 1;
+#else
+ mLogEnable = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);
+#endif
+ memset(&mConfig, 0, sizeof(mConfig));
+}
+
+AudioALSAFMController::~AudioALSAFMController() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+/*==============================================================================
+ * FM Control
+ *============================================================================*/
+
+bool AudioALSAFMController::checkFmNeedUseDirectConnectionMode() {
+ return mUseFmDirectConnectionMode;
+}
+
+
+bool AudioALSAFMController::getFmEnable() {
+ AL_AUTOLOCK(mLock);
+ ALOGV("%s(), mFmEnable = %d", __FUNCTION__, mFmEnable);
+ return mFmEnable;
+}
+
+status_t AudioALSAFMController::setFmEnable(const bool enable, const audio_devices_t output_device, bool bForceControl, bool bForce2DirectConn, bool bNeedSyncVolume __unused) { // TODO(Harvey)
+ // Lock to Protect HW Registers & AudioMode
+ // TODO(Harvey): get stream manager lock here?
+
+ AL_AUTOLOCK(mLock);
+
+ ALOGD("+%s(), mFmEnable = %d => enable = %d, output_device = 0x%x, bForceControl = %d, bForce2DirectConn = %d",
+ __FUNCTION__, mFmEnable, enable, output_device, bForceControl, bForce2DirectConn);
+
+
+ if (WCNChipController::GetInstance()->IsSupportFM() == false) {
+ ALOGW("-%s(), Don't support FM in the platform", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ // Check Current Status
+ if (enable == mFmEnable) {
+ ALOGW("-%s(), enable == mFmEnable, return.", __FUNCTION__);
+ return NO_ERROR;
+ }
+
+ // Update Enable Status
+ mFmEnable = enable;
+ // update output device
+ mOuput_device = output_device;
+
+#if defined(MTK_AUDIO_SW_DRE) && defined(MTK_NEW_VOL_CONTROL)
+ AudioMTKGainController::getInstance()->setFmEnable(enable);
+#endif
+
+ AudioALSASampleRateController *pAudioALSASampleRateController = AudioALSASampleRateController::getInstance();
+
+ if (mFmEnable == true) { // Open
+#if 0 // local print only
+ ALOGD("IsFMMergeInterfaceSupported = %d", WCNChipController::GetInstance()->IsFMMergeInterfaceSupported());
+ ALOGD("IsFmChipPadSelConnSys = %d", WCNChipController::GetInstance()->IsFmChipPadSelConnSys());
+ ALOGD("IsFmChipUseSlaveMode = %d", WCNChipController::GetInstance()->IsFmChipUseSlaveMode());
+ ALOGD("GetFmChipSamplingRate = %d", WCNChipController::GetInstance()->GetFmChipSamplingRate());
+
+ ALOGD("IsBTMergeInterfaceSupported = %d", WCNChipController::GetInstance()->IsBTMergeInterfaceSupported());
+ ALOGD("BTChipHWInterface = %d", WCNChipController::GetInstance()->BTChipHWInterface());
+ ALOGD("BTUseCVSDRemoval = %d", WCNChipController::GetInstance()->BTUseCVSDRemoval());
+ ALOGD("BTChipSamplingRate = %d", WCNChipController::GetInstance()->BTChipSamplingRate());
+ ALOGD("BTChipSamplingRateNumber = %d", WCNChipController::GetInstance()->BTChipSamplingRateNumber());
+ ALOGD("BTChipSyncFormat = %d", WCNChipController::GetInstance()->BTChipSyncFormat());
+ ALOGD("BTChipSyncLength = %d", WCNChipController::GetInstance()->BTChipSyncLength());
+ ALOGD("BTChipSecurityHiLo = %d", WCNChipController::GetInstance()->BTChipSecurityHiLo());
+
+ ALOGD("GetBTCurrentSamplingRateNumber = %d", WCNChipController::GetInstance()->GetBTCurrentSamplingRateNumber());
+#endif
+
+#if defined(MTK_BASIC_PACKAGE)||defined(MTK_BSP_PACKAGE)
+ if (!isPreferredSampleRate(getFmDownlinkSamplingRate()))
+#endif
+ {
+ if (checkFmNeedUseDirectConnectionMode() == true) {
+ pAudioALSASampleRateController->setPrimaryStreamOutSampleRate(48000);
+ }
+ }
+
+ if (true != bForceControl || false != bForce2DirectConn) { //If indirect mode, normal handler will set PLAYBACK_SCENARIO_STREAM_OUT
+ pAudioALSASampleRateController->setScenarioStatus(PLAYBACK_SCENARIO_FM);
+ }
+
+ if (WCNChipController::GetInstance()->IsFMMergeInterfaceSupported() == true) {
+ //I2S fixed at 32K Hz
+ WCNChipController::GetInstance()->SetFmChipSampleRate(getFmDownlinkSamplingRate());
+ }
+
+
+ // Set Audio Digital/Analog HW Register
+ // if (checkFmNeedUseDirectConnectionMode(output_device) == true)
+ // {
+ if (true == bForceControl && false == bForce2DirectConn) {
+ mIsFmDirectConnectionMode = false;
+ } else {
+ // acquire pmic clk
+ mHardwareResourceManager->EnableAudBufClk(true);
+
+ setFmDirectConnection_l(true, true, output_device);
+ mHardwareResourceManager->startOutputDevice(output_device, getFmDownlinkSamplingRate());
+
+ mAudioALSAVolumeController->setMasterVolume(mAudioALSAVolumeController->getMasterVolume(),
+ AudioALSAStreamManager::getInstance()->getModeForGain(),
+ output_device);
+ }
+ // }
+ // else
+ // {
+ // mIsFmDirectConnectionMode = false;
+ // }
+
+ // Set Direct/Indirect Mode to FMAudioPlayer
+ // doDeviceChangeCallback();
+ } else { // Close
+ // Disable Audio Digital/Analog HW Register
+ if (mIsFmDirectConnectionMode == true) {
+ mHardwareResourceManager->stopOutputDevice();
+
+ //release pmic clk
+ mHardwareResourceManager->EnableAudBufClk(false);
+ }
+ setFmDirectConnection_l(false, true, output_device);
+
+ // reset FM playback status
+ pAudioALSASampleRateController->resetScenarioStatus(PLAYBACK_SCENARIO_FM);
+ }
+
+ ALOGD_IF(mLogEnable, "-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSAFMController::routing(const audio_devices_t pre_device, const audio_devices_t new_device) {
+ AL_AUTOLOCK(mLock);
+
+ ASSERT(mFmEnable == true);
+
+ ALOGD("+%s(), pre_device = 0x%x, new_device = 0x%x", __FUNCTION__, pre_device, new_device);
+
+#if defined(SUPPORT_FM_AUDIO_BY_PROPRIETARY_PARAMETER_CONTROL)
+ if (mIsFmDirectConnectionMode) {
+ if (new_device & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+ mHardwareResourceManager->stopOutputDevice();
+ mHardwareResourceManager->startOutputDevice(new_device, getFmDownlinkSamplingRate());
+ }
+ }
+ mOuput_device = new_device;
+#else
+ if (WCNChipController::GetInstance()->IsSupportFM() == false) {
+ ALOGW("-%s(), Don't support FM in the platform", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ // Close
+ if (mIsFmDirectConnectionMode == true) { // Direct mode, close it directly
+ // wait until HW Gain stable
+ setFmVolume_l(0.0);// make sure
+ usleep(430000); // -74.5/0.25 * 64 / 44100 = 430 ms
+ mHardwareResourceManager->stopOutputDevice();
+ }
+
+ mOuput_device = new_device;
+
+ // Open
+ setFmDirectConnection_l(checkFmNeedUseDirectConnectionMode(), false, new_device);
+
+ // Set Direct/Indirect Mode for FM Chip
+ // doDeviceChangeCallback();
+
+ // Enable PMIC Analog Part
+ if (mIsFmDirectConnectionMode == true) { // Direct mode, open it directly
+ mHardwareResourceManager->startOutputDevice(new_device, getFmDownlinkSamplingRate());
+ setFmVolume_l(mFmVolume);
+ }
+#endif
+ ALOGD_IF(mLogEnable, "-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+void AudioALSAFMController::setFmDeviceCallback(const AUDIO_DEVICE_CHANGE_CALLBACK_STRUCT *callback_data) {
+ if (callback_data == NULL) {
+ mFmDeviceCallback = NULL;
+ } else {
+ mFmDeviceCallback = callback_data->callback;
+ ASSERT(mFmDeviceCallback != NULL);
+ }
+}
+
+status_t AudioALSAFMController::doDeviceChangeCallback() {
+ ALOGD("+%s(), mIsFmDirectConnectionMode = %d, callback = %p", __FUNCTION__, mIsFmDirectConnectionMode, mFmDeviceCallback);
+
+ ASSERT(mFmEnable == true);
+
+ if (mFmDeviceCallback == NULL) { // factory mode might not set mFmDeviceCallback
+ ALOGE("-%s(), mFmDeviceCallback == NULL", __FUNCTION__);
+ return NO_INIT;
+ }
+
+
+ if (mIsFmDirectConnectionMode == true) {
+ mFmDeviceCallback((void *)false); // Direct Mode, No need to create in/out stream
+ ALOGD_IF(mLogEnable, "-%s(), mFmDeviceCallback(false)", __FUNCTION__);
+ } else {
+ mFmDeviceCallback((void *)true); // Indirect Mode, Need to create in/out stream
+ ALOGD_IF(mLogEnable, "-%s(), mFmDeviceCallback(true)", __FUNCTION__);
+ }
+
+ return NO_ERROR;
+}
+
+bool AudioALSAFMController::isPreferredSampleRate(uint32_t rate) const {
+ switch (rate) {
+ case 44100:
+ case 48000:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*==============================================================================
+ * Audio HW Control
+ *============================================================================*/
+
+uint32_t AudioALSAFMController::getFmUplinkSamplingRate() const {
+ uint32_t Rate = AudioALSASampleRateController::getInstance()->getPrimaryStreamOutSampleRate();
+
+ if (Rate != 48000 && Rate != 44100) {
+ return 44100;
+ } else {
+ return Rate;
+ }
+}
+
+uint32_t AudioALSAFMController::getFmDownlinkSamplingRate() const {
+#if defined(MTK_HIFIAUDIO_SUPPORT)
+ if (mHardwareResourceManager->getHiFiStatus()) {
+ ALOGD("-%s()FM HIFI sample raet 48000 fix", __FUNCTION__);
+ return 48000;
+ } else {
+ return AudioALSASampleRateController::getInstance()->getPrimaryStreamOutSampleRate();
+ }
+#else
+ return AudioALSASampleRateController::getInstance()->getPrimaryStreamOutSampleRate();
+#endif
+}
+
+status_t AudioALSAFMController::setFmDirectConnection_l(const bool enable, const bool bforce, audio_devices_t output_device) {
+ ALOGD("+%s(), enable = %d, bforce = %d, output_device = %d", __FUNCTION__, enable, bforce, output_device);
+
+ // Check Current Status
+ if (mIsFmDirectConnectionMode == enable && bforce == false) {
+ ALOGW("-%s(), enable = %d, bforce = %d", __FUNCTION__, enable, bforce);
+ return INVALID_OPERATION;
+ }
+
+
+ // Apply
+ if (enable == true) {
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = 2;
+ mConfig.rate = getFmDownlinkSamplingRate();
+ mConfig.period_size = 3072;
+ mConfig.period_count = 2;
+ mConfig.format = PCM_FORMAT_S16_LE;
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+
+ // Get pcm open Info
+ int card_index = -1;
+ int pcm_index = -1;
+
+ if (mPcm == NULL) {
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+#if defined(MTK_AUDIO_KS)
+ mConfig.stop_threshold = ~(0U);
+ if ((output_device & AUDIO_DEVICE_OUT_SPEAKER) &&
+ AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(WCNChipController::GetInstance()->IsFMMergeInterfaceSupported() ?
+ AUDIO_CTL_MRG_TO_I2S : AUDIO_CTL_CONNSYS_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+
+ if (popcount(output_device) > 1) {
+ mApTurnOnSequence2 = WCNChipController::GetInstance()->IsFMMergeInterfaceSupported() ?
+ AUDIO_CTL_MRG_TO_ADDA_DL : AUDIO_CTL_CONNSYS_TO_ADDA_DL;
+ }
+ } else {
+ mApTurnOnSequence = WCNChipController::GetInstance()->IsFMMergeInterfaceSupported() ?
+ AUDIO_CTL_MRG_TO_ADDA_DL : AUDIO_CTL_CONNSYS_TO_ADDA_DL;
+ }
+
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence2);
+ }
+
+ card_index = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmHostlessFm);
+ pcm_index = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessFm);
+
+ mPcm = pcm_open(card_index, pcm_index, PCM_OUT, &mConfig);
+ mPcmUL = pcm_open(card_index, pcm_index, PCM_IN, &mConfig);
+#else
+ if (WCNChipController::GetInstance()->IsFMMergeInterfaceSupported() == true) {
+ card_index = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmMRGrxPlayback);
+ pcm_index = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmMRGrxPlayback);
+ } else {
+ card_index = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmFMI2SPlayback);
+ pcm_index = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmFMI2SPlayback);
+ }
+
+ ALOGD_IF(mLogEnable, "%s(), card_index = %d, pcm_index = %d", __FUNCTION__, card_index, pcm_index);
+ mPcm = pcm_open(card_index, pcm_index, PCM_OUT, &mConfig);
+ ALOGD_IF(mLogEnable, "%s(), pcm_open mPcm = %p", __FUNCTION__, mPcm);
+#endif
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+ if (mPcm != NULL) {
+ if (mHyBridNLERegister == false && AudioALSAHyBridNLEManager::getInstance()->addHwPathStream(AUDIO_STREAM_HW_FM) == NO_ERROR) {
+ mHyBridNLERegister = true;
+ } else {
+ ALOGE("%s, Err mHyBridNLERegister %d", __FUNCTION__, mHyBridNLERegister);
+ }
+ }
+#endif
+ }
+ if (mPcm == NULL || pcm_is_ready(mPcm) == false) {
+ ALOGE("%s(), Unable to open mPcm device %u (%s)", __FUNCTION__, pcm_index, pcm_get_error(mPcm));
+ }
+#if defined(MTK_AUDIO_KS)
+ if (pcm_start(mPcmUL)) {
+ ALOGE("%s(), pcm_start UL %p fail due to %s", __FUNCTION__, mPcmUL, pcm_get_error(mPcmUL));
+ }
+
+ if (pcm_start(mPcm)) {
+ ALOGE("%s(), pcm_start DL(%p) fail due to %s", __FUNCTION__, mPcm, pcm_get_error(mPcm));
+ }
+#else
+ pcm_start(mPcm);
+#endif
+ } else {
+ if (mPcm != NULL) {
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ pcm_stop(mPcm);
+ pcm_close(mPcm);
+ mPcm = NULL;
+
+#if defined(MTK_AUDIO_KS)
+ pcm_stop(mPcmUL);
+ pcm_close(mPcmUL);
+ mPcmUL = NULL;
+
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence2);
+ mApTurnOnSequence2.clear();
+ }
+#endif
+
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+ if (mHyBridNLERegister) {
+ if (AudioALSAHyBridNLEManager::getInstance()->removeHwPathStream(AUDIO_STREAM_HW_FM) == NO_ERROR) {
+ mHyBridNLERegister = false;
+ } else {
+ ALOGE("%s, Err removeHwPathStream Fail", __FUNCTION__);
+ }
+ }
+#endif
+ }
+ }
+
+
+ // Update Direct Mode Status
+ mIsFmDirectConnectionMode = enable;
+
+ // Update (HW_GAIN2) Volume for Direct Mode Only
+ if (mIsFmDirectConnectionMode == true) {
+ setFmVolume_l(mFmVolume);
+ }
+
+
+ ALOGD_IF(mLogEnable, "-%s(), enable = %d, bforce = %d", __FUNCTION__, enable, bforce);
+ return NO_ERROR;
+}
+
+status_t AudioALSAFMController::setFmVolume(const float fm_volume) {
+ AL_AUTOLOCK(mLock);
+ return setFmVolume_l(fm_volume);
+}
+
+status_t AudioALSAFMController::setFmVolume_l(const float fm_volume) {
+ ALOGD("%s(), mFmVolume = %f => fm_volume = %f", __FUNCTION__, mFmVolume, fm_volume);
+
+ const float kMaxFmVolume = 1.0;
+ ASSERT(0 <= fm_volume && fm_volume <= kMaxFmVolume); // valid volume value: 0.0 ~ 1.0
+
+ mFmVolume = fm_volume;
+
+ if (WCNChipController::GetInstance()->IsSupportFM() == false) {
+ ALOGW("-%s(), Don't support FM in the platform", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ // Set HW Gain for Direct Mode // TODO(Harvey): FM Volume
+ if (mFmEnable == true && mIsFmDirectConnectionMode == true) {
+ mAudioALSAVolumeController->setFmVolume(mFmVolume);
+ } else {
+ ALOGD("%s(), Do nothing. mFMEnable = %d, mIsFmDirectConnectionMode = %d", __FUNCTION__, mFmEnable, mIsFmDirectConnectionMode);
+ }
+
+ return NO_ERROR;
+}
+
+float AudioALSAFMController::getFmVolume() {
+ AL_AUTOLOCK(mLock);
+ return mFmVolume;
+}
+
+/*==============================================================================
+ * WCN FM Chip Control
+ *============================================================================*/
+
+bool AudioALSAFMController::getFmChipPowerInfo() {
+ return WCNChipController::GetInstance()->GetFmChipPowerInfo();
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAGainController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAGainController.cpp
new file mode 100644
index 0000000..8280b62
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAGainController.cpp
@@ -0,0 +1,2242 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <math.h>
+#include <SpeechDriverFactory.h>
+
+#include "AudioALSAGainController.h"
+#include <AudioALSASpeechPhoneCallController.h>
+#include "SpeechEnhancementController.h"
+//#include "AudioAMPControlInterface.h"
+#include "AudioALSADeviceConfigManager.h"
+#include "AudioALSADeviceParser.h"
+#include "AudioALSADriverUtility.h"
+#include "AudioALSAStreamManager.h"
+#include "AudioALSAHardwareResourceManager.h"
+#ifdef MTK_USB_PHONECALL
+#include "AudioUSBPhoneCallController.h"
+#endif
+#ifdef MTK_AUDIO_SPH_LPBK_PARAM
+#include "LoopbackManager.h"
+#endif
+
+#include "AudioTypeExt.h"
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+#include "AudioALSANLEController.h"
+#endif
+#include <SpeechConfig.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioMTKGainController"
+
+#ifdef ALOGG
+#undef ALOGG
+#endif
+#ifdef CONFIG_MT_ENG_BUILD
+#define ALOGG(...) ALOGD(__VA_ARGS__)
+#else
+#define ALOGG(...)
+#endif
+
+#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))
+
+namespace android {
+AudioMTKGainController *AudioMTKGainController::UniqueVolumeInstance = NULL;
+
+// here can change to match audiosystem
+
+// total 64 dB
+static const float keydBPerStep = 0.25f;
+static const float keyvolumeStep = 255.0f;
+
+
+// shouldn't need to touch these
+static const float keydBConvert = -keydBPerStep * 2.302585093f / 20.0f;
+static const float keydBConvertInverse = 1.0f / keydBConvert;
+
+//static const char *PGA_Gain_String[] = {"0Db", "6Db", "12Db" , "18Db" , "24Db" , "30Db"};
+
+//hw spec db
+//const int keyAudioBufferStep = 19;
+//const int KeyAudioBufferGain[] = { -5, -3, -1, 1, 3, 5, 7, 9};
+//const int KeyAudioBufferGain[] = { 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -40}; // move to xml
+/*static const char *DL_PGA_Headset_GAIN[] = {"8Db", "7Db", "6Db", "5Db", "4Db", "3Db", "2Db", "1Db", "0Db", "-1Db", "-2Db", "-3Db",
+ "-4Db", "-5Db", "-6Db", "-7Db", "-8Db", "-9Db", "-10Db" , "-40Db"
+ };*/
+
+//const int keyVoiceBufferStep = 19;
+//const int KeyVoiceBufferGain[] = { -21, -19, -17, -15, -13, -11, -9, -7, -5, -3, -1, 1, 3, 5, 7, 9};
+//const int KeyVoiceBufferGain[] = { 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -40}; move to xml
+/*static const char *DL_PGA_Handset_GAIN[] = {"8Db", "7Db", "6Db", "5Db", "4Db", "3Db", "2Db", "1Db", "0Db", "-1Db", "-2Db", "-3Db",
+ "-4Db", "-5Db", "-6Db", "-7Db", "-8Db", "-9Db", "-10Db" , "-40Db"
+ };*/
+
+
+//const int keyULStep = 5;
+//const int KeyULGain[] = { -6, 0, 6, 12, 18, 24};
+//const int keyULGainOffset = 2;
+
+//const int keySPKStep = 15;
+//const int KeySPKgain[] = { -60, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
+/*static const char *DL_PGA_SPEAKER_GAIN[] = {"MUTE", "0Db", "4Db", "5Db", "6Db", "7Db", "8Db", "9Db", "10Db", // move to xml
+ "11Db", "12Db", "13Db", "14Db", "15Db", "16Db", "17Db"
+ };*/
+
+
+
+//const int keyDLDigitalDegradeMax = 63;
+
+//const int keyULDigitalIncreaseMax = 32;
+
+// static const int keySidetoneSize = 47; // move to xml
+
+/*static const uint16_t SwAgc_Gain_Map[AUDIO_SYSTEM_UL_GAIN_MAX + 1] = // move to xml
+{
+ 25, 24, 23, 22, 21, 20, 19, 18, 17,
+ 16, 15, 14, 13, 12 , 11,
+ 16, 15, 14, 13, 12 , 11,
+ 16, 15, 14, 13, 12 , 11,
+ 16, 15, 14, 13, 12 , 11,
+ 16, 15, 14, 13, 12 , 11,
+ 10, 9, 8, 7, 6, 5, 4
+};
+
+static const uint16_t PGA_Gain_Map[AUDIO_SYSTEM_UL_GAIN_MAX + 1] =
+{
+ 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6,
+ 12, 12, 12, 12, 12, 12,
+ 18, 18, 18, 18, 18, 18,
+ 24, 24, 24, 24, 24, 24,
+ 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30
+};*/
+
+//static const uint16_t keySideTone[] = // move to xml
+//{
+// 32767, 29204, 26027, 23196, 20674, 18426, 16422, 14636, 13044, 11625, /*1dB per step*/
+// 10361, 9234, 8230, 7335, 6537, 5826, 5193, 4628, 4125, 3676,
+// 3276, 2919, 2602, 2319, 2066, 1841, 1641, 1463, 1304, 1162,
+// 1035, 923, 822, 733, 653, 582, 519, 462, 412, 367,
+// 327, 291, 260, 231, 206, 183, 163, 145
+//};
+
+// HW Gain mappring
+static const uint32_t kHWGainMap[] = {
+ 0x00000, // 0, -64.0 dB (mute)
+ 0x0015E, // 1, -63.5 dB
+ 0x00173, // 2, -63.0 dB
+ 0x00189, // 3, -62.5 dB
+ 0x001A0, // 4, -62.0 dB
+ 0x001B9, // 5, -61.5 dB
+ 0x001D3, // 6, -61.0 dB
+ 0x001EE, // 7, -60.5 dB
+ 0x0020C, // 8, -60.0 dB
+ 0x0022B, // 9, -59.5 dB
+ 0x0024C, // 10, -59.0 dB
+ 0x0026F, // 11, -58.5 dB
+ 0x00294, // 12, -58.0 dB
+ 0x002BB, // 13, -57.5 dB
+ 0x002E4, // 14, -57.0 dB
+ 0x00310, // 15, -56.5 dB
+ 0x0033E, // 16, -56.0 dB
+ 0x00370, // 17, -55.5 dB
+ 0x003A4, // 18, -55.0 dB
+ 0x003DB, // 19, -54.5 dB
+ 0x00416, // 20, -54.0 dB
+ 0x00454, // 21, -53.5 dB
+ 0x00495, // 22, -53.0 dB
+ 0x004DB, // 23, -52.5 dB
+ 0x00524, // 24, -52.0 dB
+ 0x00572, // 25, -51.5 dB
+ 0x005C5, // 26, -51.0 dB
+ 0x0061D, // 27, -50.5 dB
+ 0x00679, // 28, -50.0 dB
+ 0x006DC, // 29, -49.5 dB
+ 0x00744, // 30, -49.0 dB
+ 0x007B2, // 31, -48.5 dB
+ 0x00827, // 32, -48.0 dB
+ 0x008A2, // 33, -47.5 dB
+ 0x00925, // 34, -47.0 dB
+ 0x009B0, // 35, -46.5 dB
+ 0x00A43, // 36, -46.0 dB
+ 0x00ADF, // 37, -45.5 dB
+ 0x00B84, // 38, -45.0 dB
+ 0x00C32, // 39, -44.5 dB
+ 0x00CEC, // 40, -44.0 dB
+ 0x00DB0, // 41, -43.5 dB
+ 0x00E7F, // 42, -43.0 dB
+ 0x00F5B, // 43, -42.5 dB
+ 0x01044, // 44, -42.0 dB
+ 0x0113B, // 45, -41.5 dB
+ 0x01240, // 46, -41.0 dB
+ 0x01355, // 47, -40.5 dB
+ 0x0147A, // 48, -40.0 dB
+ 0x015B1, // 49, -39.5 dB
+ 0x016FA, // 50, -39.0 dB
+ 0x01857, // 51, -38.5 dB
+ 0x019C8, // 52, -38.0 dB
+ 0x01B4F, // 53, -37.5 dB
+ 0x01CED, // 54, -37.0 dB
+ 0x01EA4, // 55, -36.5 dB
+ 0x02075, // 56, -36.0 dB
+ 0x02261, // 57, -35.5 dB
+ 0x0246B, // 58, -35.0 dB
+ 0x02693, // 59, -34.5 dB
+ 0x028DC, // 60, -34.0 dB
+ 0x02B48, // 61, -33.5 dB
+ 0x02DD9, // 62, -33.0 dB
+ 0x03090, // 63, -32.5 dB
+ 0x03371, // 64, -32.0 dB
+ 0x0367D, // 65, -31.5 dB
+ 0x039B8, // 66, -31.0 dB
+ 0x03D24, // 67, -30.5 dB
+ 0x040C3, // 68, -30.0 dB
+ 0x04499, // 69, -29.5 dB
+ 0x048AA, // 70, -29.0 dB
+ 0x04CF8, // 71, -28.5 dB
+ 0x05188, // 72, -28.0 dB
+ 0x0565D, // 73, -27.5 dB
+ 0x05B7B, // 74, -27.0 dB
+ 0x060E6, // 75, -26.5 dB
+ 0x066A4, // 76, -26.0 dB
+ 0x06CB9, // 77, -25.5 dB
+ 0x0732A, // 78, -25.0 dB
+ 0x079FD, // 79, -24.5 dB
+ 0x08138, // 80, -24.0 dB
+ 0x088E0, // 81, -23.5 dB
+ 0x090FC, // 82, -23.0 dB
+ 0x09994, // 83, -22.5 dB
+ 0x0A2AD, // 84, -22.0 dB
+ 0x0AC51, // 85, -21.5 dB
+ 0x0B687, // 86, -21.0 dB
+ 0x0C157, // 87, -20.5 dB
+ 0x0CCCC, // 88, -20.0 dB
+ 0x0D8EF, // 89, -19.5 dB
+ 0x0E5CA, // 90, -19.0 dB
+ 0x0F367, // 91, -18.5 dB
+ 0x101D3, // 92, -18.0 dB
+ 0x1111A, // 93, -17.5 dB
+ 0x12149, // 94, -17.0 dB
+ 0x1326D, // 95, -16.5 dB
+ 0x14496, // 96, -16.0 dB
+ 0x157D1, // 97, -15.5 dB
+ 0x16C31, // 98, -15.0 dB
+ 0x181C5, // 99, -14.5 dB
+ 0x198A1, // 100, -14.0 dB
+ 0x1B0D7, // 101, -13.5 dB
+ 0x1CA7D, // 102, -13.0 dB
+ 0x1E5A8, // 103, -12.5 dB
+ 0x2026F, // 104, -12.0 dB
+ 0x220EA, // 105, -11.5 dB
+ 0x24134, // 106, -11.0 dB
+ 0x26368, // 107, -10.5 dB
+ 0x287A2, // 108, -10.0 dB
+ 0x2AE02, // 109, -9.5 dB
+ 0x2D6A8, // 110, -9.0 dB
+ 0x301B7, // 111, -8.5 dB
+ 0x32F52, // 112, -8.0 dB
+ 0x35FA2, // 113, -7.5 dB
+ 0x392CE, // 114, -7.0 dB
+ 0x3C903, // 115, -6.5 dB
+ 0x4026E, // 116, -6.0 dB
+ 0x43F40, // 117, -5.5 dB
+ 0x47FAC, // 118, -5.0 dB
+ 0x4C3EA, // 119, -4.5 dB
+ 0x50C33, // 120, -4.0 dB
+ 0x558C4, // 121, -3.5 dB
+ 0x5A9DF, // 122, -3.0 dB
+ 0x5FFC8, // 123, -2.5 dB
+ 0x65AC8, // 124, -2.0 dB
+ 0x6BB2D, // 125, -1.5 dB
+ 0x72148, // 126, -1.0 dB
+ 0x78D6F, // 127, -0.5 dB
+ 0x80000, // 128, 0.0 dB
+};
+
+// callback function
+void xmlChangedCallback(AppHandle *_appHandle, const char *_audioTypeName) {
+ // reload XML file
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return;
+ }
+
+ if (appOps->appHandleReloadAudioType(_appHandle, _audioTypeName) == APP_ERROR) {
+ ALOGE("%s(), Reload xml fail!(audioType = %s)", __FUNCTION__, _audioTypeName);
+ } else {
+ AudioMTKGainController::getInstance()->updateXmlParam(_audioTypeName);
+ }
+}
+
+float AudioMTKGainController::linearToLog(int volume) {
+ //ALOGD("linearToLog(%d)=%f", volume, v);
+ return volume ? exp(float(keyvolumeStep - volume) * keydBConvert) : 0;
+}
+
+int AudioMTKGainController::logToLinear(float volume) {
+ //ALOGD("logTolinear(%d)=%f", v, volume);
+ return volume ? keyvolumeStep - int(keydBConvertInverse * log(volume) + 0.5) : 0;
+}
+
+AudioMTKGainController *AudioMTKGainController::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (UniqueVolumeInstance == 0) {
+ ALOGV("+UniqueVolumeInstance\n");
+ UniqueVolumeInstance = new AudioMTKGainController();
+ ALOGV("-UniqueVolumeInstance\n");
+ }
+
+ return UniqueVolumeInstance;
+}
+
+AudioMTKGainController::AudioMTKGainController() {
+ ALOGD("AudioMTKGainController contructor");
+ // mAmpControl = AudioDeviceManger::createInstance();
+ mAudioSpeechEnhanceInfoInstance = AudioSpeechEnhanceInfo::getInstance();
+ mHardwareResourceManager = AudioALSAHardwareResourceManager::getInstance();
+ mVoiceVolume = 1.0f;
+ mMasterVolume = 1.0f;
+ //mFmVolume = 0xFF;
+ //mFmChipVolume = 0xFFFFFFFF;
+ mBand = GAIN_SPEECH_NB;
+ mNetwork = GAIN_SPEECH_NETWORK_GSM;
+ mSupportBtVol = false;
+ mSceneIndex = GAIN_SCENE_INDEX_DEFAULT;
+ memset(&mHwVolume, 0xFF, sizeof(mHwVolume));
+ memset(&mHwStream, 0xFF, sizeof(mHwStream));
+ memset(&mHwCaptureInfo, 0, sizeof(mHwCaptureInfo));
+ GainTableParamParser::getInstance()->getSceneList(&mSceneList);
+ allocateGainTable();
+ initVolumeController();
+ mULTotalGain = 184;
+ mHpImpedanceIdx = mSpec->hpImpDefaultIdx;
+#ifdef MTK_AUDIO_SW_DRE
+ mSWDREMute = false;
+ mMutedHandlerVector.clear();
+ mHasMuteHandler = false;
+ mNumHandler = 0;
+ mFmEnable = false;
+#endif
+ mANCEnable = false;
+ mInitDone = true;
+ mMixer = NULL;
+ mMixer = AudioALSADriverUtility::getInstance()->getMixer();
+ ALOGD("mMixer = %p", mMixer);
+ ASSERT(mMixer != NULL);
+
+ /* XML changed callback process */
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return;
+ }
+
+ appOps->appHandleRegXmlChangedCb(appOps->appHandleGetInstance(), xmlChangedCallback);
+}
+
+status_t AudioMTKGainController::allocateGainTable() {
+ ALOGD("%s()", __FUNCTION__);
+ mGainTable.sceneGain = (GainTableForScene *)malloc(mSceneList.size() * sizeof(GainTableForScene));
+ if (mGainTable.sceneGain == NULL) {
+ ALOGE("%s(), Allocate scene gain table fail", __FUNCTION__);
+ ASSERT(0);
+ return NO_MEMORY;
+ }
+ return NO_ERROR;
+}
+
+status_t AudioMTKGainController::freeGainTable() {
+ ALOGD("%s()", __FUNCTION__);
+ free(mGainTable.sceneGain);
+ return NO_ERROR;
+}
+
+AudioMTKGainController::~AudioMTKGainController() {
+ freeGainTable();
+}
+
+status_t AudioMTKGainController::initVolumeController() {
+ GainTableParamParser::getInstance()->getGainTableParam(&mGainTable, &mSceneList);
+ GainTableParamParser::getInstance()->getGainTableSpec(&mSpec);
+ return NO_ERROR;
+}
+
+status_t AudioMTKGainController::getSceneGainTableParameter(GainTableForScene *_gainTableForScene) {
+ ALOGV("%s()", __FUNCTION__);
+ memcpy((void *)_gainTableForScene, (void *)mGainTable.sceneGain, sizeof(GainTableForScene) * mSceneList.size());
+ return NO_ERROR;
+}
+
+status_t AudioMTKGainController::getNonSceneGainTableParameter(GainTableForNonScene *_gainTableForNonScene) {
+ ALOGV("%s()", __FUNCTION__);
+ memcpy((void *)_gainTableForNonScene, (void *)&mGainTable.nonSceneGain, sizeof(GainTableForNonScene));
+ return NO_ERROR;
+}
+
+int AudioMTKGainController::getSceneCount() {
+ return (int)(mSceneList.size());
+}
+
+int AudioMTKGainController::getSceneIndex(const char *scene) {
+ std::string inputScene = scene;
+ for (int i = 0; i < getSceneCount(); i++) {
+ if (mSceneList[i] == inputScene) {
+ ALOGD("%s(), %s index found = %d", __FUNCTION__, scene, i);
+ return i;
+ }
+ }
+ ALOGD("%s(), %s index nout found, use GAIN_SCENE_INDEX_DEFAULT", __FUNCTION__, scene);
+ return GAIN_SCENE_INDEX_DEFAULT;
+}
+
+int AudioMTKGainController::getCurrentSceneIndex() {
+ ALOGD("%s(), mSceneIndex = %d", __FUNCTION__, mSceneIndex);
+ return mSceneIndex;
+}
+
+void AudioMTKGainController::setScene(const char *scene) {
+ ALOGD("%s(), scene = %s", __FUNCTION__, scene);
+ mSceneIndex = getSceneIndex(scene);
+}
+
+status_t AudioMTKGainController::initCheck() {
+ return mInitDone;
+}
+
+void AudioMTKGainController::updateXmlParam(const char *_audioTypeName) {
+ ALOGD("%s(), audioType = %s", __FUNCTION__, _audioTypeName);
+
+ bool needResetDlGain = false;
+ bool isMicGainChanged = false;
+
+ if (strcmp(_audioTypeName, PLAY_DIGI_AUDIOTYPE_NAME) == 0) {
+ GainTableParamParser::getInstance()->updatePlaybackDigitalGain(&mGainTable, &mSceneList);
+ } else if (strcmp(_audioTypeName, PLAY_ANA_AUDIOTYPE_NAME) == 0) {
+ GainTableParamParser::getInstance()->updatePlaybackAnalogGain(&mGainTable, &mSceneList);
+ needResetDlGain = true;
+ } else if (strcmp(_audioTypeName, SPEECH_VOL_AUDIOTYPE_NAME) == 0) {
+ GainTableParamParser::getInstance()->updateSpeechVol(&mGainTable);
+ isMicGainChanged = true;
+ needResetDlGain = true;
+ } else if (strcmp(_audioTypeName, REC_VOL_AUDIOTYPE_NAME) == 0) {
+ GainTableParamParser::getInstance()->updateRecordVol(&mGainTable, &mSceneList);
+ isMicGainChanged = true;
+ } else if (strcmp(_audioTypeName, VOIP_VOL_AUDIOTYPE_NAME) == 0) {
+ GainTableParamParser::getInstance()->updateVoIPVol(&mGainTable, &mSceneList);
+ isMicGainChanged = true;
+ needResetDlGain = true;
+ } else if (strcmp(_audioTypeName, RINGBACK_VOL_AUDIOTYPE_NAME) == 0) {
+ GainTableParamParser::getInstance()->updateRingbackVol(&mGainTable);
+ // No need to set DL analog gain
+ } else if (strcmp(_audioTypeName, VOLUME_AUDIOTYPE_NAME) == 0) {
+ GainTableParamParser::getInstance()->loadGainTableSpec();
+ GainTableParamParser::getInstance()->getGainTableParam(&mGainTable, &mSceneList);
+ GainTableParamParser::getInstance()->getGainTableSpec(&mSpec);
+ isMicGainChanged = true;
+ needResetDlGain = true;
+ } else if (strcmp(_audioTypeName, GAIN_MAP_AUDIOTYPE_NAME) == 0) {
+ GainTableParamParser::getInstance()->loadGainTableMapDl();
+ GainTableParamParser::getInstance()->getGainTableParam(&mGainTable, &mSceneList);
+ isMicGainChanged = true;
+ needResetDlGain = true;
+ } else if (strcmp(_audioTypeName, GAIN_MAP_UL_AUDIOTYPE_NAME) == 0) {
+ GainTableParamParser::getInstance()->loadGainTableMapUl();
+ GainTableParamParser::getInstance()->getGainTableParam(&mGainTable, &mSceneList);
+ isMicGainChanged = true;
+ } else if (strcmp(_audioTypeName, HP_IMPEDANCE_AUDIOTYPE_NAME) == 0) {
+ GainTableParamParser::getInstance()->loadGainTableHpImpedance();
+ GainTableParamParser::getInstance()->getGainTableSpec(&mSpec);
+ needResetDlGain = true;
+ }
+
+ // reset mic gain immediately
+ if (isMicGainChanged) {
+ if (!isInVoiceCall(mHwStream.mode)) {
+ SetCaptureGain(mHwCaptureInfo.mode, mHwCaptureInfo.source, mHwCaptureInfo.input_device, mHwCaptureInfo.output_devices);
+ }
+ }
+
+ if (needResetDlGain)
+ setAnalogVolume_l(mHwStream.stream,
+ mHwStream.devices,
+ mHwStream.index,
+ mHwStream.mode);
+}
+
+status_t AudioMTKGainController::SetCaptureGain(audio_mode_t mode, audio_source_t source, audio_devices_t input_device, audio_devices_t output_devices) {
+ ALOGD("+%s(), mode=%d, source=%d, input device=0x%x, output device=0x%x", __FUNCTION__, mode, source, input_device, output_devices);
+
+ if (source == AUDIO_SOURCE_HOTWORD) {
+ return NO_ERROR;
+ }
+ if (mode == AUDIO_MODE_CURRENT) {
+ mode = mHwCaptureInfo.mode;
+ }
+ mHwCaptureInfo.mode = mode;
+ mHwCaptureInfo.source = source;
+ mHwCaptureInfo.input_device = input_device;
+ mHwCaptureInfo.output_devices = output_devices;
+
+ switch (mode) {
+ case AUDIO_MODE_NORMAL:
+ case AUDIO_MODE_RINGTONE: {
+ switch (source) {
+ case AUDIO_SOURCE_CAMCORDER:
+ case AUDIO_SOURCE_VOICE_RECOGNITION:
+ case AUDIO_SOURCE_VOICE_UNLOCK:
+ case AUDIO_SOURCE_CUSTOMIZATION1:
+ case AUDIO_SOURCE_CUSTOMIZATION2:
+ case AUDIO_SOURCE_CUSTOMIZATION3:
+ case AUDIO_SOURCE_UNPROCESSED:
+ ApplyMicGain(getGainMicMode(source, mode),
+ getGainDevice(input_device),
+ mode);
+ break;
+ default:
+ //for audio tuning tool tuning case.
+ if (mAudioSpeechEnhanceInfoInstance->IsAPDMNRTuningEnable()) { //for DMNR tuning
+ if (mAudioSpeechEnhanceInfoInstance->GetAPTuningMode() == HANDSFREE_MODE_DMNR) {
+ ApplyMicGain(GAIN_MIC_VOICE_CALL, GAIN_DEVICE_SPEAKER, mode);
+ } else if (mAudioSpeechEnhanceInfoInstance->GetAPTuningMode() == NORMAL_MODE_DMNR) {
+ ApplyMicGain(GAIN_MIC_VOICE_CALL, GAIN_DEVICE_EARPIECE, mode);
+ } else {
+ ApplyMicGain(GAIN_MIC_NORMAL, GAIN_DEVICE_EARPIECE, mode);
+ }
+ } else {
+ ApplyMicGain(GAIN_MIC_NORMAL, getGainDevice(input_device), mode);
+ }
+ break;
+ }
+ break;
+ }
+ case AUDIO_MODE_IN_CALL: {
+ if (AudioALSASpeechPhoneCallController::getInstance()->checkTtyNeedOn() == false) {
+ if (!audio_is_bluetooth_sco_device(output_devices)) {
+ ApplyMicGain(getGainMicMode(source, mode),
+ getGainDevice(output_devices),
+ mode);
+ }
+ }
+ break;
+ }
+ case AUDIO_MODE_IN_COMMUNICATION: {
+ ApplyMicGain(getGainMicMode(source, mode),
+ getGainDevice(output_devices),
+ mode);
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ return NO_ERROR;
+}
+
+
+status_t AudioMTKGainController::speechNetworkChange(unsigned int info) {
+ bool isNetworkSupport = (info & (0x1 << 15)) != 0;
+ GAIN_SPEECH_BAND band;
+ char *netName = NULL;
+ GAIN_SPEECH_NETWORK net;
+
+ if (isNetworkSupport) {
+ band = (GAIN_SPEECH_BAND)((info >> 4) & 0x3); //info[4:5]
+ netName = SpeechConfig::getInstance()->getNameForEachSpeechNetwork(info & 0xf);
+ net = GainTableParamParser::getInstance()->getGainSpeechNetwork(netName);
+ } else {
+ band = (GAIN_SPEECH_BAND)((info >> 3) & 0x7); //info[3:5]
+ net = (GAIN_SPEECH_NETWORK)0;
+ }
+ ALOGD("%s(), info 0x%x, band %d, net %d, netName %s", __FUNCTION__, info, band, net, netName);
+
+ AutoMutex lock(mLock);
+ if (mBand != band || mNetwork != net) {
+ mBand = band;
+ mNetwork = net;
+ if (isInVoiceCall(mHwStream.mode)) {
+ setAnalogVolume_l(mHwStream.stream, mHwStream.devices, mHwStream.index, AUDIO_MODE_IN_CALL);
+ }
+ }
+ return NO_ERROR;
+}
+
+bool AudioMTKGainController::isNbSpeechBand(void) {
+ AutoMutex lock(mLock);
+ return mBand == GAIN_SPEECH_NB;
+}
+
+status_t AudioMTKGainController::setBtVolumeCapability(bool support) {
+ AutoMutex lock(mLock);
+ mSupportBtVol = !support; // if bt device do not support volume , we should
+ return NO_ERROR;
+}
+
+status_t AudioMTKGainController::setAnalogVolume_l(int stream, int devices, int index, audio_mode_t mode) {
+ ALOGG("setAnalogVolume(), stream %d, devices 0x%x, index %d, mode %d", stream, devices, index, mode);
+ mHwStream.stream = stream;
+ mHwStream.devices = devices;
+ mHwStream.index = index;
+ mHwStream.mode = mode;
+
+ if (isInVoiceCall(mode)) {
+ setVoiceVolume(index, devices, mode);
+ AudioALSASpeechPhoneCallController::getInstance()->updateVolume();
+ } else {
+ setNormalVolume(stream, index, devices, mode);
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioMTKGainController::setAnalogVolume(int stream, int devices, int index, audio_mode_t mode) {
+ AutoMutex lock(mLock);
+ return setAnalogVolume_l(stream, devices, index, mode);
+}
+
+status_t AudioMTKGainController::setNormalVolume(int stream, int index, int devices, audio_mode_t mode) {
+ // Avoid pop noise when switch between headset and spk+headset mode
+ if (((audio_devices_t)devices != mHardwareResourceManager->getOutputDevice()) &&
+ (mHardwareResourceManager->getOutputDevice() != 0x0)) {
+ ALOGW("%s(), devices(0x%x) != mOutputDevices(0x%x), skip set device gain",
+ __FUNCTION__, devices, mHardwareResourceManager->getOutputDevice());
+ return NO_ERROR;
+ }
+
+ if (audio_is_bluetooth_sco_device(devices)) {
+ ALOGD("%s(), devices(0x%x) is BTSCO, skip set device gain", __FUNCTION__, devices);
+ return NO_ERROR;
+ }
+
+ ALOGD("%s(), mSceneIndex = %d, stream %d, devices 0x%x, index %d, mode 0x%x",
+ __FUNCTION__, mSceneIndex, stream, devices, index, mode);
+
+ // get gain device
+ GAIN_DEVICE gainDevice = getGainDevice(devices);
+
+ // check stream/index range
+ if (!isValidStreamType((audio_stream_type_t)stream)) {
+ ALOGW("error, stream %d is invalid, use %d instead", stream, AUDIO_STREAM_MUSIC);
+ stream = AUDIO_STREAM_MUSIC;
+ }
+ if (!isValidVolIdx(index, mode)) {
+ ALOGW("error, index %d is invalid, use max %d instead", index, GAIN_MAX_VOL_INDEX);
+ index = GAIN_MAX_VOL_INDEX;
+ }
+
+#ifdef MTK_HAC_SUPPORT
+ // change gain device if HAC On
+ if (gainDevice == GAIN_DEVICE_EARPIECE &&
+ SpeechEnhancementController::GetInstance()->GetHACOn()) {
+ ALOGD("%s(): HAC ON gain device change from EarPiece to HAC", __FUNCTION__);
+ gainDevice = GAIN_DEVICE_HAC;
+ }
+#endif
+
+ if (isSpeakerCategory(gainDevice)) {
+ if (mSpec->spkAnaType >= 0 && mSpec->spkAnaType < NUM_GAIN_ANA_TYPE) {
+ unsigned char gain = mGainTable.sceneGain[mSceneIndex].streamGain[stream][gainDevice][index].analog[mSpec->spkAnaType];
+ setSpeakerGain(gain);
+ }
+ }
+
+ if (isHeadsetCategory(gainDevice)) {
+ unsigned char gain = mGainTable.sceneGain[mSceneIndex].streamGain[stream][gainDevice][index].analog[GAIN_ANA_HEADPHONE];
+ ApplyAudioGain(gain, mode, gainDevice);
+ // setAMPGain(streamGain->stream[gainDevice].amp, AMP_CONTROL_POINT, devices);
+ }
+
+ if (isEarpieceCategory(gainDevice)) {
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_2IN1_SPEAKER) ||
+ IsAudioSupportFeature(AUDIO_SUPPORT_VIBRATION_SPEAKER)) {
+ if (mSpec->spkAnaType >= 0 && mSpec->spkAnaType < NUM_GAIN_ANA_TYPE) {
+ unsigned char gain = mGainTable.sceneGain[mSceneIndex].streamGain[stream][gainDevice][index].analog[mSpec->spkAnaType];
+ setSpeakerGain(gain);
+ }
+ } else {
+ unsigned char gain = mGainTable.sceneGain[mSceneIndex].streamGain[stream][gainDevice][index].analog[GAIN_ANA_HANDSET];
+ ApplyAudioGain(gain, mode, gainDevice);
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioMTKGainController::setVoiceVolume(int index, int devices, audio_mode_t mode) {
+ ALOGD("%s(), index = %d, devices = 0x%x, mode = %d, mBand = %d, mNetwork = %d, mVoiceVolume = %f",
+ __FUNCTION__, index, devices, mode, mBand, mNetwork, mVoiceVolume);
+
+
+ if (audio_is_bluetooth_sco_device(devices)) {
+ // check stream/index range
+ if (!isValidVolIdx(index, AUDIO_MODE_NORMAL)) {
+ ALOGW("error, index %d is invalid, use max %d instead", index, GAIN_MAX_VOL_INDEX);
+ index = GAIN_MAX_VOL_INDEX;
+ }
+
+ ALOGD("audio_is_bluetooth_sco_device = %d, mSupportBtVol is %d", true, mSupportBtVol);
+ uint8_t digitalDegradeDb = 0;
+
+ // help tune gain if bt device doesn't support volume ctrl, otherwise pass 0dB
+ if (mSupportBtVol) {
+ digitalDegradeDb = mGainTable.sceneGain[mSceneIndex].streamGain[AUDIO_STREAM_BLUETOOTH_SCO][GAIN_DEVICE_HEADSET][index].digital;
+ }
+
+ ApplyMdDlGain(index == 0 ? 255 : digitalDegradeDb); // modem dl gain
+ ApplyMdUlGain(0);
+
+ return NO_ERROR;
+ } else {
+ // check stream/index range
+ if (!isValidVolIdx(index, mode)) {
+ ALOGW("error, index %d is invalid, use max %d instead", index, GAIN_MAX_SPEECH_VOL_INDEX);
+ index = GAIN_MAX_SPEECH_VOL_INDEX;
+ }
+
+ // get gain device
+ GAIN_DEVICE gainDevice = GAIN_DEVICE_NONE;
+ if (AudioALSASpeechPhoneCallController::getInstance()->checkTtyNeedOn() == true) {
+ gainDevice = getGainDeviceForTty();
+ } else {
+ gainDevice = getGainDevice(devices);
+ }
+
+ if (gainDevice == GAIN_DEVICE_HSSPK) {
+ ALOGW("%s(), phone call mode can't choose HSSPK", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+#ifdef MTK_HAC_SUPPORT
+ // change gain device if HAC On
+ if (gainDevice == GAIN_DEVICE_EARPIECE) {
+ bool mHACon = SpeechEnhancementController::GetInstance()->GetHACOn();
+ if (mHACon) {
+ ALOGD("%s(): HAC ON = %d, gain device change from EarPiece to HAC", __FUNCTION__, mHACon);
+ gainDevice = GAIN_DEVICE_HAC;
+ }
+ }
+#endif
+
+ // set analog gain
+ if (isSpeakerCategory(gainDevice)) {
+ if (mSpec->spkAnaType >= 0 && mSpec->spkAnaType < NUM_GAIN_ANA_TYPE) {
+ unsigned char gain = mGainTable.nonSceneGain.speechGain[mBand][mNetwork][gainDevice][index].analog[mSpec->spkAnaType];
+ setSpeakerGain(gain);
+ }
+ }
+
+ if (isHeadsetCategory(gainDevice)) {
+ unsigned char gain = mGainTable.nonSceneGain.speechGain[mBand][mNetwork][gainDevice][index].analog[GAIN_ANA_HEADPHONE];
+ ApplyAudioGain(gain, mode, gainDevice);
+ }
+
+ if (isEarpieceCategory(gainDevice)) {
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_2IN1_SPEAKER) ||
+ IsAudioSupportFeature(AUDIO_SUPPORT_VIBRATION_SPEAKER)) {
+ if (mSpec->spkAnaType >= 0 && mSpec->spkAnaType < NUM_GAIN_ANA_TYPE) {
+ unsigned char gain = mGainTable.nonSceneGain.speechGain[mBand][mNetwork][gainDevice][index].analog[mSpec->spkAnaType];
+ setSpeakerGain(gain);
+ }
+ } else {
+ unsigned char gain = mGainTable.nonSceneGain.speechGain[mBand][mNetwork][gainDevice][index].analog[GAIN_ANA_HANDSET];
+ ApplyAudioGain(gain, mode, gainDevice);
+ }
+ }
+
+ // set digital gain
+ //setAMPGain(ampgain, AMP_CONTROL_POINT, device);
+ uint8_t digitalDegradeDb = mGainTable.nonSceneGain.speechGain[mBand][mNetwork][gainDevice][index].digital;
+ ApplyMdDlGain(digitalDegradeDb); // modem dl gain
+
+ // mic gain & modem UL gain
+ if (index == 0) { // don't set ul/stf gain when force mute dl
+ return 0;
+ }
+
+ if (AudioALSASpeechPhoneCallController::getInstance()->checkTtyNeedOn() == true) {
+ ApplyMicGainForTty(mode);
+ } else {
+ ApplyMicGainByDevice(devices, mode);
+ }
+
+ ApplySideTone(gainDevice);
+ }
+
+ return NO_ERROR;
+}
+
+void AudioMTKGainController::ApplyMicGainByDevice(uint32_t device, audio_mode_t mode) {
+ if (device & AUDIO_DEVICE_OUT_EARPIECE ||
+ device & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+ device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+ device & AUDIO_DEVICE_OUT_SPEAKER ||
+ device & AUDIO_DEVICE_OUT_BUS ||
+ device & AUDIO_DEVICE_OUT_USB_DEVICE ||
+ device & AUDIO_DEVICE_OUT_USB_HEADSET) {
+
+ GAIN_MIC_MODE micMode = getGainMicMode(AUDIO_SOURCE_DEFAULT, mode);
+ GAIN_DEVICE gainDevice = getGainDevice(device);
+
+#ifdef MTK_USB_PHONECALL
+ if (gainDevice == GAIN_DEVICE_USB &&
+ AudioUSBPhoneCallController::getInstance()->isUsingUSBIn() == false) {
+ // usb call using usb output only, input gain use HP gain
+ gainDevice = GAIN_DEVICE_HEADPHONE;
+ }
+#endif
+
+ ApplyMicGain(micMode, gainDevice, mode);
+ } else if (audio_is_bluetooth_sco_device(device)) {
+ //when use BT_SCO , apply digital to 0db.
+ ApplyMdUlGain(0);
+ }
+}
+
+void AudioMTKGainController::ApplyMicGainForTty(audio_mode_t mode) {
+
+ audio_devices_t outDevice = AudioALSASpeechPhoneCallController::getInstance()->getOutputDevice();
+ TtyModeType ttyMode = AudioALSASpeechPhoneCallController::getInstance()->getTtyMode();
+ GAIN_MIC_MODE micMode = getGainMicMode(AUDIO_SOURCE_DEFAULT, mode);
+
+ if (outDevice == 0) {
+ ALOGE("%s(), outDevice=0!!! do nothing", __FUNCTION__);
+ } else if (outDevice & AUDIO_DEVICE_OUT_SPEAKER) {
+ if (ttyMode == AUD_TTY_VCO) {
+ ALOGD("%s(), speaker, TTY_VCO", __FUNCTION__);
+ ApplyMicGain(micMode, GAIN_DEVICE_SPEAKER, mode);
+ } else if (ttyMode == AUD_TTY_HCO) {
+ ALOGD("%s(), speaker, TTY_HCO", __FUNCTION__);
+ ApplyMicGain(micMode, GAIN_DEVICE_TTY, mode);
+ } else if (ttyMode == AUD_TTY_FULL) {
+ ALOGD("%s(), speaker, TTY_FULL", __FUNCTION__);
+ ApplyMicGain(micMode, GAIN_DEVICE_TTY, mode);
+ }
+ } else if ((outDevice == AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+ (outDevice == AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+ if (ttyMode == AUD_TTY_VCO) {
+ ALOGD("%s(), headset, TTY_VCO", __FUNCTION__);
+ ApplyMicGain(micMode, GAIN_DEVICE_EARPIECE, mode);
+ } else if (ttyMode == AUD_TTY_HCO) {
+ ALOGD("%s(), headset, TTY_HCO", __FUNCTION__);
+ ApplyMicGain(micMode, GAIN_DEVICE_TTY, mode);
+ } else if (ttyMode == AUD_TTY_FULL) {
+ ApplyMicGain(micMode, GAIN_DEVICE_TTY, mode);
+ }
+ } else if (outDevice == AUDIO_DEVICE_OUT_EARPIECE) {
+ // tty device is removed. TtyCtm already off in CloseMD.
+ ALOGD("%s(), receiver", __FUNCTION__);
+ } else {
+ ALOGD("%s(), routing = 0x%x", __FUNCTION__, outDevice);
+ }
+}
+
+GAIN_DEVICE AudioMTKGainController::getGainDevice(audio_devices_t devices) {
+ GAIN_DEVICE gainDevice = GAIN_DEVICE_NONE;
+ bool IsSuperVolumeMode = AudioALSASpeechPhoneCallController::getInstance()->getSpeechFeatureStatus(SPEECH_FEATURE_SUPERVOLUME);
+
+ if (devices & AUDIO_DEVICE_BIT_IN) {
+ /* input device */
+ if (devices == AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ if (mHardwareResourceManager->getNumOfHeadsetPole() == 5) {
+ if (mANCEnable) {
+ gainDevice = GAIN_DEVICE_HEADSET_5POLE_ANC;
+ } else {
+ gainDevice = GAIN_DEVICE_HEADSET_5POLE;
+ }
+ } else {
+ gainDevice = GAIN_DEVICE_HEADSET;
+ }
+ } else if (devices == AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ gainDevice = GAIN_DEVICE_SPEAKER;
+ } else if (devices == AUDIO_DEVICE_IN_USB_DEVICE || devices == AUDIO_DEVICE_IN_USB_HEADSET || devices == AUDIO_DEVICE_IN_BUS) {
+ gainDevice = GAIN_DEVICE_USB;
+ } else {
+ ALOGE("%s(), error, devices (0x%x) not support, return GAIN_DEVICE_SPEAKER", __FUNCTION__, devices);
+ gainDevice = GAIN_DEVICE_SPEAKER;
+ }
+ } else {
+ /* output device */
+ if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
+#ifdef MTK_AUDIO_SPH_LPBK_PARAM
+ if (LoopbackManager::GetInstance()->CheckIsModemLoopback(LoopbackManager::GetInstance()->GetLoopbackType())) {
+ gainDevice = GAIN_DEVICE_LPBK_SPK;
+ } else
+#endif
+ {
+ if (IsSuperVolumeMode == true) {
+ gainDevice = GAIN_DEVICE_SPK_EV;
+ } else {
+ gainDevice = GAIN_DEVICE_SPEAKER;
+ }
+ }
+
+ if ((devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+ (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+ gainDevice = GAIN_DEVICE_HSSPK;
+ }
+ } else if (devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+#ifdef MTK_AUDIO_SPH_LPBK_PARAM
+ if (LoopbackManager::GetInstance()->CheckIsModemLoopback(LoopbackManager::GetInstance()->GetLoopbackType())) {
+ gainDevice = GAIN_DEVICE_LPBK_HP;
+ } else
+#endif
+ {
+ if (mHardwareResourceManager->getNumOfHeadsetPole() == 5) {
+ if (mANCEnable) {
+ gainDevice = GAIN_DEVICE_HEADSET_5POLE_ANC;
+ } else {
+ gainDevice = GAIN_DEVICE_HEADSET_5POLE;
+ }
+ } else {
+ gainDevice = GAIN_DEVICE_HEADSET;
+ }
+ }
+ } else if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+#ifdef MTK_AUDIO_SPH_LPBK_PARAM
+ if (LoopbackManager::GetInstance()->CheckIsModemLoopback(LoopbackManager::GetInstance()->GetLoopbackType())) {
+ gainDevice = GAIN_DEVICE_LPBK_HP;
+ } else
+#endif
+ gainDevice = GAIN_DEVICE_HEADPHONE;
+ } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
+#ifdef MTK_AUDIO_SPH_LPBK_PARAM
+ if (LoopbackManager::GetInstance()->CheckIsModemLoopback(LoopbackManager::GetInstance()->GetLoopbackType())) {
+ gainDevice = GAIN_DEVICE_LPBK_RCV;
+ } else
+#endif
+ {
+ if (IsSuperVolumeMode == true) {
+ gainDevice = GAIN_DEVICE_RCV_EV;
+ } else {
+ gainDevice = GAIN_DEVICE_EARPIECE;
+ }
+ }
+ } else if (devices & AUDIO_DEVICE_OUT_USB_DEVICE || devices & AUDIO_DEVICE_OUT_USB_HEADSET || devices & AUDIO_DEVICE_OUT_BUS) {
+ gainDevice = GAIN_DEVICE_USB;
+ } else {
+ ALOGE("%s(), error, devices (%d) not support, return GAIN_DEVICE_SPEAKER", __FUNCTION__, devices);
+ gainDevice = GAIN_DEVICE_SPEAKER;
+ }
+ }
+
+ ALOGG("%s(), input devices = 0x%x, return gainDevice = %d", __FUNCTION__, devices, gainDevice);
+ return gainDevice;
+}
+
+GAIN_DEVICE AudioMTKGainController::getGainDeviceForTty(void) {
+ GAIN_DEVICE gainDeviceForTty = GAIN_DEVICE_NONE;
+ audio_devices_t outDevice = AudioALSASpeechPhoneCallController::getInstance()->getOutputDevice();
+ TtyModeType ttyMode = AudioALSASpeechPhoneCallController::getInstance()->getTtyMode();
+
+ if (outDevice & AUDIO_DEVICE_OUT_SPEAKER) {
+ if (ttyMode == AUD_TTY_VCO) {
+ ALOGD("%s(), speaker, TTY_VCO", __FUNCTION__);
+ gainDeviceForTty = GAIN_DEVICE_HEADSET;
+ } else if (ttyMode == AUD_TTY_HCO) {
+ ALOGD("%s(), speaker, TTY_HCO", __FUNCTION__);
+ gainDeviceForTty = GAIN_DEVICE_SPEAKER;
+ } else if (ttyMode == AUD_TTY_FULL) {
+ ALOGD("%s(), speaker, TTY_FULL", __FUNCTION__);
+ gainDeviceForTty = GAIN_DEVICE_HEADSET;
+ }
+ } else if ((outDevice == AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+ (outDevice == AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+ if (ttyMode == AUD_TTY_VCO) {
+ ALOGD("%s(), headset, TTY_VCO", __FUNCTION__);
+ gainDeviceForTty = GAIN_DEVICE_HEADSET;
+ } else if (ttyMode == AUD_TTY_HCO) {
+ ALOGD("%s(), headset, TTY_HCO", __FUNCTION__);
+ gainDeviceForTty = GAIN_DEVICE_EARPIECE;
+ } else if (ttyMode == AUD_TTY_FULL) {
+ ALOGD("%s(), headset, TTY_FULL", __FUNCTION__);
+ gainDeviceForTty = GAIN_DEVICE_HEADSET;
+ }
+ }
+
+ if (gainDeviceForTty < 0 || gainDeviceForTty >= NUM_GAIN_DEVICE) {
+ ALOGE("%s(), error, use GAIN_DEVICE_EARPIECE", __FUNCTION__);
+ gainDeviceForTty = GAIN_DEVICE_EARPIECE;
+ }
+
+ ALOGD("%s(), outDevice = 0x%x, ttyMode = %d return gainDeviceForTty = %d",
+ __FUNCTION__, outDevice, ttyMode, gainDeviceForTty);
+ return gainDeviceForTty;
+}
+
+GAIN_MIC_MODE AudioMTKGainController::getGainMicMode(audio_source_t _source, audio_mode_t _mode) {
+ GAIN_MIC_MODE micMode = GAIN_MIC_NORMAL;
+
+ switch (_mode) {
+ case AUDIO_MODE_NORMAL:
+ case AUDIO_MODE_RINGTONE:
+ switch (_source) {
+ case AUDIO_SOURCE_MIC:
+ micMode = GAIN_MIC_NORMAL;
+ break;
+ case AUDIO_SOURCE_VOICE_UPLINK:
+ case AUDIO_SOURCE_VOICE_DOWNLINK:
+ case AUDIO_SOURCE_VOICE_CALL:
+ micMode = GAIN_MIC_VOICE_CALL;
+ break;
+ case AUDIO_SOURCE_CAMCORDER:
+ micMode = GAIN_MIC_CAMCORDER;
+ break;
+ case AUDIO_SOURCE_VOICE_RECOGNITION:
+ micMode = GAIN_MIC_VOICE_RECOGNITION;
+ break;
+ case AUDIO_SOURCE_VOICE_COMMUNICATION:
+ micMode = GAIN_MIC_VOICE_COMMUNICATION;
+ break;
+ case AUDIO_SOURCE_VOICE_UNLOCK:
+ micMode = GAIN_MIC_VOICE_UNLOCK;
+ break;
+ case AUDIO_SOURCE_CUSTOMIZATION1:
+ micMode = GAIN_MIC_CUSTOMIZATION1;
+ break;
+ case AUDIO_SOURCE_CUSTOMIZATION2:
+ micMode = GAIN_MIC_CUSTOMIZATION2;
+ break;
+ case AUDIO_SOURCE_CUSTOMIZATION3:
+ micMode = GAIN_MIC_CUSTOMIZATION3;
+ break;
+ case AUDIO_SOURCE_UNPROCESSED:
+ micMode = GAIN_MIC_UNPROCESSED;
+ break;
+ default:
+ micMode = GAIN_MIC_NORMAL;
+ break;
+ }
+ break;
+ case AUDIO_MODE_IN_CALL:
+ micMode = GAIN_MIC_VOICE_CALL;
+ break;
+ case AUDIO_MODE_IN_COMMUNICATION:
+ micMode = GAIN_MIC_VOICE_COMMUNICATION;
+ break;
+ default:
+ ALOGE("%s(), not handled mode %d", __FUNCTION__, _mode);
+ micMode = GAIN_MIC_NORMAL;
+ break;
+ }
+ return micMode;
+}
+
+void AudioMTKGainController::ApplyMdDlGain(int32_t degradeDb) {
+ // set degarde db to mode side, DL part, here use degrade dbg
+ ALOGG("ApplyMdDlGain degradeDb = %d", degradeDb);
+#if 0
+ if (degradeDb >= keyDLDigitalDegradeMax) {
+ degradeDb = keyDLDigitalDegradeMax;
+ }
+
+ SpeechDriverFactory::GetInstance()->GetSpeechDriver()->SetDownlinkGain((-1 * degradeDb) << 2); // degrade db * 4
+#endif
+ SpeechDriverFactory::GetInstance()->GetSpeechDriver()->SetDownlinkGain((-1 * degradeDb));
+}
+
+void AudioMTKGainController::ApplyMdDlEhn1Gain(int32_t Gain) {
+ // set degarde db to mode side, DL part, here use degrade dbg
+ ALOGD("ApplyMdDlEhn1Gain degradeDb = %d", Gain);
+ //SpeechDriverFactory::GetInstance()->GetSpeechDriver()->SetEnh1DownlinkGain(-1 * (Gain) << 2); // degrade db * 4
+ SpeechDriverFactory::GetInstance()->GetSpeechDriver()->SetEnh1DownlinkGain(-1 * (Gain));
+}
+
+void AudioMTKGainController::ApplyMdUlGain(int32_t IncreaseDb) {
+ // set degarde db to mode side, UL part, here use positive gain becasue SW_agc always positive
+ ALOGG("ApplyMdUlGain degradeDb = %d", IncreaseDb);
+
+ //if (mHwVolume.swAgc != IncreaseDb)
+ {
+ mHwVolume.swAgc = IncreaseDb;
+ SpeechDriverFactory::GetInstance()->GetSpeechDriver()->SetUplinkGain(IncreaseDb << 2); // degrade db * 4
+ }
+}
+
+void AudioMTKGainController::ApplyAudioGain(int gain, audio_mode_t mode, GAIN_DEVICE gainDevice) {
+ ALOGG("ApplyAudioGain(), gain = %d, mode = %d, gainDevice = %d", gain, mode, gainDevice);
+ int bufferGain = gain;
+
+ unsigned int bufferGainStringSize;
+ if (isHeadsetCategory(gainDevice)) {
+ bufferGainStringSize = mSpec->audioBufferGainString.size();
+ } else { // if (isEarpieceCategory(gainDevice))
+ bufferGainStringSize = mSpec->voiceBufferGainString.size();
+ }
+
+ if (bufferGain >= (int)bufferGainStringSize) {
+ bufferGain = bufferGainStringSize - 1;
+ }
+
+ // adjust gain according to master volume
+ bufferGain = tuneGainForMasterVolume(bufferGain, mode, gainDevice);
+
+ // adjust gain according to hp impedance when using HP
+ bufferGain = tuneGainForHpImpedance(bufferGain, gainDevice);
+
+ if (isEarpieceCategory(gainDevice)) {
+ setVoiceBufferGain(bufferGain);
+ } else if (isHeadsetCategory(gainDevice)) {
+ setAudioBufferGain(bufferGain);
+ }
+}
+
+int AudioMTKGainController::GetReceiverGain(void) {
+ struct mixer_ctl *ctl;
+ unsigned int num_values, i ;
+ int index = 0;
+
+ ctl = mixer_get_ctl_by_name(mMixer, mSpec->voiceBufMixerName.c_str());
+ num_values = mixer_ctl_get_num_values(ctl);
+ for (i = 0; i < num_values; i++) {
+ index = mixer_ctl_get_value(ctl, i);
+ ALOGD("GetReceiverGain i = %d index = %d ", i, index);
+ }
+ return index;
+}
+
+int AudioMTKGainController::GetHeadphoneRGain(void) {
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+ size_t nle_gain_idx;
+ if (AudioALSAHyBridNLEManager::getInstance()->getNleHwConfigByIndex(&nle_gain_idx) != NO_ERROR) {
+ ALOGE("%s getNleHwConfigByIndex Error", __FUNCTION__);
+ nle_gain_idx = 0;
+ }
+ return ((int)nle_gain_idx);
+#else
+ struct mixer_ctl *ctl;
+ unsigned int num_values, i ;
+ int index = 0;
+
+ ctl = mixer_get_ctl_by_name(mMixer, mSpec->audioBufRMixerName.c_str());
+ num_values = mixer_ctl_get_num_values(ctl);
+ for (i = 0; i < num_values; i++) {
+ index = mixer_ctl_get_value(ctl, i);
+ ALOGD("GetHeadphoneRGain i = %d index = %d ", i, index);
+ }
+ return index;
+#endif
+}
+
+
+int AudioMTKGainController::GetHeadphoneLGain(void) {
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+ size_t nle_gain_idx;
+ if (AudioALSAHyBridNLEManager::getInstance()->getNleHwConfigByIndex(&nle_gain_idx) != NO_ERROR) {
+ ALOGE("%s getNleHwConfigByIndex Error", __FUNCTION__);
+ nle_gain_idx = 0;
+ }
+ return ((int)nle_gain_idx);
+#else
+ struct mixer_ctl *ctl;
+ unsigned int num_values, i ;
+ int index = 0;
+ ALOGD("GetHeadphoneLGain");
+ ctl = mixer_get_ctl_by_name(mMixer, mSpec->audioBufLMixerName.c_str());
+ num_values = mixer_ctl_get_num_values(ctl);
+ for (i = 0; i < num_values; i++) {
+ index = mixer_ctl_get_value(ctl, i);
+ ALOGD("GetHeadphoneLGain i = %d index = %d ", i, index);
+ }
+ return index;
+#endif
+}
+
+void AudioMTKGainController::SetReceiverGain(int index) {
+ ALOGG("SetReceiverGain = %d", index);
+ struct mixer_ctl *ctl;
+
+ if (index < 0) {
+ index = 0;
+ }
+
+ if ((uint32_t)index >= mSpec->voiceBufferGainString.size()) {
+ index = mSpec->voiceBufferGainString.size() - 1;
+ }
+
+ ctl = mixer_get_ctl_by_name(mMixer, mSpec->voiceBufMixerName.c_str());
+
+ if (ctl) {
+ if (mixer_ctl_set_enum_by_string(ctl, mSpec->voiceBufferGainString[index].c_str())) {
+ ALOGE("Error: %s invalid value", mSpec->voiceBufMixerName.c_str());
+ }
+ } else {
+ ALOGE("Error: get mixer ctl fail, %s", mSpec->voiceBufMixerName.c_str());
+ }
+}
+
+void AudioMTKGainController::SetHeadPhoneLGain(int index) {
+ ALOGG("SetHeadPhoneLGain = %d", index);
+ struct mixer_ctl *ctl;
+
+ if (index < 0) {
+ index = 0;
+ }
+
+ if ((uint32_t)index >= mSpec->audioBufferGainString.size()) {
+ index = mSpec->audioBufferGainString.size() - 1;
+ }
+
+ ctl = mixer_get_ctl_by_name(mMixer, mSpec->audioBufLMixerName.c_str());
+
+ if (ctl) {
+ if (mixer_ctl_set_enum_by_string(ctl, mSpec->audioBufferGainString[index].c_str())) {
+ ALOGE("Error: %s invalid value", mSpec->audioBufLMixerName.c_str());
+ }
+ } else {
+ ALOGE("Error: get mixer ctl fail, %s", mSpec->audioBufLMixerName.c_str());
+ }
+}
+
+void AudioMTKGainController::SetHeadPhoneRGain(int index) {
+ ALOGG("SetHeadPhoneRGain = %d", index);
+ struct mixer_ctl *ctl;
+
+ if (index < 0) {
+ index = 0;
+ }
+
+ if ((uint32_t)index >= mSpec->audioBufferGainString.size()) {
+ index = mSpec->audioBufferGainString.size() - 1;
+ }
+
+ ctl = mixer_get_ctl_by_name(mMixer, mSpec->audioBufRMixerName.c_str());
+
+ if (ctl) {
+ if (mixer_ctl_set_enum_by_string(ctl, mSpec->audioBufferGainString[index].c_str())) {
+ ALOGE("Error: %s invalid value", mSpec->audioBufRMixerName.c_str());
+ }
+ } else {
+ ALOGE("Error: get mixer ctl fail, %s", mSpec->audioBufRMixerName.c_str());
+ }
+}
+
+void AudioMTKGainController::setAudioBufferGain(int gain) {
+#ifdef MTK_AUDIO_SW_DRE
+ if (mSWDREMute) {
+ ALOGD("%s(), bypass when SWDRE mute", __FUNCTION__);
+ return;
+ }
+#endif
+
+ if (gain >= (int)mSpec->audioBufferGainString.size()) {
+ gain = mSpec->audioBufferGainString.size() - 1;
+ }
+
+ ALOGG("setAudioBufferGain, gain %d, mHwVolume.audioBuffer %d", gain, mHwVolume.audioBuffer);
+
+ mHwVolume.audioBuffer = gain;
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+ if (AudioALSAHyBridNLEManager::getInstance()->setNleHwConfigByIndex(gain) == FAILED_TRANSACTION) { // the parameter using Index of HP Gain Reg
+ SetHeadPhoneLGain(gain);
+ SetHeadPhoneRGain(gain);
+ }
+#else
+ SetHeadPhoneLGain(gain);
+ SetHeadPhoneRGain(gain);
+#endif
+}
+
+void AudioMTKGainController::setVoiceBufferGain(int gain) {
+ if (gain >= (int)mSpec->voiceBufferGainString.size()) {
+ gain = mSpec->voiceBufferGainString.size() - 1;
+ }
+
+ ALOGG("setVoiceBufferGain, gain %d, mHwVolume.voiceBuffer %d", gain, mHwVolume.voiceBuffer);
+
+ mHwVolume.voiceBuffer = gain;
+ SetReceiverGain(gain);
+}
+
+int AudioMTKGainController::GetSPKGain(void) {
+ struct mixer_ctl *ctl;
+ enum mixer_ctl_type type;
+ unsigned int num_values, i ;
+ int index = 0;
+ ALOGD("GetSPKGain");
+ ctl = mixer_get_ctl_by_name(mMixer, mSpec->spkLMixerName.c_str());
+ type = mixer_ctl_get_type(ctl);
+ num_values = mixer_ctl_get_num_values(ctl);
+ for (i = 0; i < num_values; i++) {
+ index = mixer_ctl_get_value(ctl, i);
+ ALOGD("GetSPKGain i = %d index = %d ", i, index);
+ }
+
+ return index;
+}
+
+void AudioMTKGainController::SetSpeakerGain(int index) {
+ ALOGG("SetSpeakerGain,index=%d \n", index);
+
+ std::vector<std::string> *enumString;
+ switch (mSpec->spkAnaType) {
+ case GAIN_ANA_HEADPHONE:
+ enumString = &mSpec->audioBufferGainString;
+
+ if (index < 0) {
+ index = 0;
+ }
+
+ break;
+ case GAIN_ANA_LINEOUT:
+ enumString = &mSpec->lineoutBufferGainString;
+
+ if (index < 0) {
+ index = 0;
+ }
+
+ break;
+ case GAIN_ANA_SPEAKER:
+ default:
+ enumString = &mSpec->spkGainString;
+
+ if (index < 0) {
+ index = 1;
+ }
+
+ break;
+ }
+
+ if ((uint32_t)index >= enumString->size()) {
+ index = enumString->size() - 1;
+ }
+
+ struct mixer_ctl *ctl;
+ // left chanel
+ ctl = mixer_get_ctl_by_name(mMixer, mSpec->spkLMixerName.c_str());
+ if (!ctl) {
+ ALOGE("Error: get mixer ctl fail, %s", mSpec->spkLMixerName.c_str());
+ } else {
+ if (mixer_ctl_set_enum_by_string(ctl, enumString->at(index).c_str())) {
+ ALOGE("Error: set %s with %s failed", mSpec->spkLMixerName.c_str(), enumString->at(index).c_str());
+ }
+ }
+
+ // right channel
+ ctl = mixer_get_ctl_by_name(mMixer, mSpec->spkRMixerName.c_str());
+ if (!ctl) {
+ ALOGE("Error: get mixer ctl fail, %s", mSpec->spkRMixerName.c_str());
+ } else {
+ if (mixer_ctl_set_enum_by_string(ctl, enumString->at(index).c_str())) {
+ ALOGE("Error: set %s with %s failed", mSpec->spkRMixerName.c_str(), enumString->at(index).c_str());
+ }
+ }
+
+}
+
+void AudioMTKGainController::setSpeakerGain(int gain) {
+ ALOGD("%s(), gain = %d, spkAnaType = %d, spkLMixerName = %s, spkRMixerName = %s",
+ __FUNCTION__,
+ gain,
+ mSpec->spkAnaType,
+ mSpec->spkLMixerName.c_str(),
+ mSpec->spkRMixerName.c_str());
+
+ // adjust gain according to master volume
+ if (mSpec->spkAnaType == GAIN_ANA_SPEAKER) {
+ if (!isInVoiceCall(mHwStream.mode)) { // mMasterVolume don't affect voice call
+ int degradedB = (keyvolumeStep - logToLinear(mMasterVolume)) * keydBPerStep;
+ ALOGD("%s(), degraded gain of mMasterVolume = %d dB", __FUNCTION__, degradedB);
+ gain -= degradedB;
+ if (gain <= 0) { //avoid mute
+ gain = 1;
+ }
+ }
+ } else {
+ gain = tuneGainForMasterVolume(gain, mHwStream.mode, GAIN_DEVICE_SPEAKER);
+ }
+
+ ALOGG("%s(), gain %d, mHwVolume.speaker %d", __FUNCTION__, gain, mHwVolume.speaker);
+
+ mHwVolume.speaker = gain;
+ SetSpeakerGain(gain);
+}
+
+void AudioMTKGainController::setAMPGain(void *points __unused, int num __unused, int device __unused) {
+ ALOGD("setAMPGain, device %d", device);
+#ifdef USING_EXTAMP_TC1
+ // if (mAmpControl && points)
+ // {
+ // mAmpControl->setVolume(points, num, device);
+ // }
+#endif
+}
+
+void AudioMTKGainController::SetAdcPga1(int gain) {
+ struct mixer_ctl *ctl;
+ int num_values = 0;
+
+ ctl = mixer_get_ctl_by_name(mMixer, mSpec->ulPgaLMixerName.c_str());
+ num_values = mixer_ctl_get_num_values(ctl);
+
+ if (ctl) {
+ if (mixer_ctl_set_enum_by_string(ctl, mSpec->ulPgaGainString[gain].c_str())) {
+ ALOGE("Error: %s invalid value", mSpec->ulPgaLMixerName.c_str());
+ }
+ } else {
+ ALOGE("Error: get mixer ctl fail, %s", mSpec->ulPgaLMixerName.c_str());
+ }
+}
+void AudioMTKGainController::SetAdcPga2(int gain) {
+ struct mixer_ctl *ctl;
+ int num_values = 0;
+
+ ctl = mixer_get_ctl_by_name(mMixer, mSpec->ulPgaRMixerName.c_str());
+ num_values = mixer_ctl_get_num_values(ctl);
+
+ if (ctl) {
+ if (mixer_ctl_set_enum_by_string(ctl, mSpec->ulPgaGainString[gain].c_str())) {
+ ALOGE("Error: %s invalid value", mSpec->ulPgaRMixerName.c_str());
+ }
+ } else {
+ ALOGE("Error: get mixer ctl fail, %s", mSpec->ulPgaRMixerName.c_str());
+ }
+}
+
+status_t AudioMTKGainController::ApplyMicGain(uint32_t MicType, int mode) {
+ /* deprecated !!! DO NOT USE !!! */
+ /* The following will be removed */
+ GAIN_MIC_MODE micMode = GAIN_MIC_NORMAL;
+ GAIN_DEVICE gainDevice = GAIN_DEVICE_EARPIECE;
+
+ if (MicType == Normal_Mic) {
+ micMode = GAIN_MIC_VOICE_CALL;
+ gainDevice = GAIN_DEVICE_EARPIECE;
+ } else if (MicType == Handfree_Mic) {
+ micMode = GAIN_MIC_VOICE_CALL;
+ gainDevice = GAIN_DEVICE_SPEAKER;
+ } else if (MicType == Headset_Mic) {
+ micMode = GAIN_MIC_VOICE_CALL;
+ gainDevice = getGainDevice(AUDIO_DEVICE_IN_WIRED_HEADSET);
+ } else if (MicType == TTY_CTM_Mic) {
+ micMode = GAIN_MIC_VOICE_CALL;
+ gainDevice = GAIN_DEVICE_TTY;
+ } else {
+ ALOGE("%s(), MicType not supported", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ return ApplyMicGain(micMode, gainDevice, (audio_mode_t)mode);
+}
+
+status_t AudioMTKGainController::ApplyMicGain(GAIN_MIC_MODE _micMode, GAIN_DEVICE _gainDevice, audio_mode_t _mode) {
+ uint8_t analogidx;
+ uint8_t gain = _micMode == GAIN_MIC_VOICE_CALL ?
+ mGainTable.nonSceneGain.speechMicGain[mBand][mNetwork][_gainDevice].gain :
+ mGainTable.sceneGain[mSceneIndex].micGain[_micMode][_gainDevice].gain;
+
+ if (gain > mSpec->micIdxMax[_gainDevice]) {
+ gain = mSpec->micIdxMax[_gainDevice];
+ }
+ if (gain < mSpec->micIdxMin[_gainDevice]) {
+ gain = mSpec->micIdxMin[_gainDevice];
+ }
+
+ uint8_t degradedb = mSpec->micIdxMax[_gainDevice] - gain;
+ short analogdegrade = mSpec->ulPgaGainMap[_gainDevice][degradedb];
+ short swagcmap = isDmicDevice(_gainDevice) ?
+ mSpec->swagcGainMapDmic[_gainDevice][degradedb] : mSpec->swagcGainMap[_gainDevice][degradedb];
+
+ mULTotalGain = UPLINK_GAIN_MAX - ((mSpec->micIdxMax[_gainDevice] - gain) * UPLINK_ONEDB_STEP);
+
+ ALOGD("ApplyMicGain(), mSceneIndex = %d, _mic_mode = %d, _gain_device = %d, mode = %d, micgain = %d, mULTotalGain = %d, mBand %d, mNetwork %d",
+ mSceneIndex, _micMode, _gainDevice, _mode, gain, mULTotalGain, mBand, mNetwork);
+
+ ASSERT(mSpec->ulHwPgaIdxMax != 0);
+
+ if (mSpec->ulHwPgaIdxMax == 0) {
+ ALOGE("%s(), ulHwPgaIdxMax == 0", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ if (_gainDevice != GAIN_DEVICE_USB && _gainDevice != GAIN_DEVICE_BT) {
+ mHwVolume.micGain = gain;
+ analogidx = (mSpec->ulPgaGainMapMax - analogdegrade) / mSpec->ulHwPgaIdxMax;
+ ALOGD("%s(), SetAdcPga1 = %d, SetAdcPga2 = %d", __FUNCTION__, analogidx, analogidx);
+ SetAdcPga1(analogidx);
+ SetAdcPga2(analogidx);
+ }
+
+ mHwVolume.swAgc = swagcmap;
+ if (isInVoiceCall(_mode)) {
+ ApplyMdUlGain(swagcmap);
+ }
+
+ return NO_ERROR;
+}
+
+short AudioMTKGainController::GetSWMICGain() {
+ return mHwVolume.swAgc ;
+}
+
+status_t AudioMTKGainController::ApplySideTone(uint32_t Mode) {
+ if (Mode >= NUM_GAIN_DEVICE) {
+ ALOGW("error, invalid gainDevice = %d, do nothing", Mode);
+ return BAD_VALUE;
+ }
+
+ // here apply side tone gain, need base on UL and DL analog gainQuant
+#if defined(MTK_HAC_SUPPORT)
+ // change gain device if HAC On
+ if (Mode == GAIN_DEVICE_EARPIECE) {
+ bool mHACon = SpeechEnhancementController::GetInstance()->GetHACOn();
+ if (mHACon) {
+ ALOGD("%s(): HAC ON = %d, gain device change from EarPiece to HAC", __FUNCTION__, mHACon);
+ Mode = GAIN_DEVICE_HAC;
+ }
+ }
+#endif
+
+ uint8_t sidetone = mGainTable.nonSceneGain.sidetoneGain[mBand][mNetwork][Mode].gain;
+ if (sidetone > mSpec->sidetoneIdxMax) {
+ sidetone = mSpec->sidetoneIdxMax;
+ }
+
+ uint16_t updated_sidetone = 0;
+
+ if (isEarpieceCategory((enum GAIN_DEVICE)Mode)) {
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_2IN1_SPEAKER) ||
+ IsAudioSupportFeature(AUDIO_SUPPORT_VIBRATION_SPEAKER)) {
+ if (mSpec->spkAnaType >= 0 && mSpec->spkAnaType < NUM_GAIN_ANA_TYPE) {
+ updated_sidetone = updateSidetone(mSpec->spkGainDb[GetSPKGain()], sidetone, mHwVolume.swAgc);
+ } else {
+ updated_sidetone = updateSidetone(0, sidetone, mHwVolume.swAgc);
+ }
+ } else {
+ updated_sidetone = updateSidetone(mSpec->voiceBufferGainDb[GetReceiverGain()], sidetone, mHwVolume.swAgc);
+ }
+ } else if (isHeadsetCategory((enum GAIN_DEVICE)Mode)) {
+ updated_sidetone = updateSidetone(mSpec->audioBufferGainDb[GetHeadphoneRGain()], sidetone, mHwVolume.swAgc);
+ } else if (Mode == GAIN_DEVICE_SPEAKER) {
+ //value = updateSidetone(KeyVoiceBufferGain[GetReceiverGain()], sidetone, mHwVolume.swAgc);
+ // mute sidetone gain when speaker mode.
+ updated_sidetone = 0;
+ }
+
+ ALOGD("ApplySideTone gainDevice %d, sidetone %u, updated_sidetone %u", Mode, sidetone, updated_sidetone);
+#if !defined(SPH_AP_SET_SIDETONE)
+ SpeechDriverFactory::GetInstance()->GetSpeechDriver()->SetSidetoneGain(updated_sidetone);
+#endif
+ return NO_ERROR;
+}
+
+uint16_t AudioMTKGainController::updateSidetone(int dlPGAGain, int sidetone, uint8_t ulGain) {
+
+ int vol = 0;
+ uint16_t DSP_ST_GAIN = 0;
+ int positive_gain_db = 0;
+ int oldDlPGAGain = dlPGAGain;
+ int oldSidetone = sidetone;
+ int oldUlGain = ulGain;
+
+ if (sidetone == 0) {
+ DSP_ST_GAIN = 0;
+ } else {
+ vol = sidetone + ulGain; //1dB/step
+#if !defined(SPH_AP_SET_SIDETONE)
+ vol = dlPGAGain - vol + 67 - mSpec->ulGainOffset;
+#else
+ vol = dlPGAGain - vol + 49 - mSpec->ulGainOffset;
+
+#if defined(SPH_POSITIVE_SIDETONE_GAIN)
+ if (vol < 0) {
+ vol = vol + 6;
+ positive_gain_db += 6;
+ }
+#endif
+#endif
+
+ if (vol < 0) {
+ vol = 0;
+ }
+ if (vol > mSpec->sidetoneIdxMax) {
+ vol = mSpec->sidetoneIdxMax;
+ }
+ DSP_ST_GAIN = mSpec->stfGainMap[vol];
+ }
+ ALOGD("%s(), DSP_ST_GAIN = %d, positive_gain_db = %d, dlPGAGain %d, sidetone %d, ulGain %u",
+ __FUNCTION__, DSP_ST_GAIN, positive_gain_db,
+ oldDlPGAGain, oldSidetone, oldUlGain);
+
+#if defined(SPH_AP_SET_SIDETONE)
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Sidetone_Gain"), 0, DSP_ST_GAIN)) {
+ ALOGW("%s(), set Sidetone_Gain fail", __FUNCTION__);
+ }
+#if defined(SPH_POSITIVE_SIDETONE_GAIN)
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Sidetone_Positive_Gain_dB"), 0, positive_gain_db)) {
+ ALOGW("%s(), set Sidetone_Positive_Gain_dB fail", __FUNCTION__);
+ }
+#endif
+#endif
+
+ return DSP_ST_GAIN;
+}
+
+bool AudioMTKGainController::isInVoiceCall(audio_mode_t mode) {
+ return (mode == AUDIO_MODE_IN_CALL);
+}
+
+bool AudioMTKGainController::isInVoipCall(audio_mode_t mode) {
+ return mode == AUDIO_MODE_IN_COMMUNICATION;
+}
+
+bool AudioMTKGainController::isInCall(audio_mode_t mode) {
+ return (isInVoiceCall(mode) || isInVoipCall(mode));
+}
+
+
+//static functin to get FM power state
+#define BUF_LEN 1
+static char rbuf[BUF_LEN] = {'\0'};
+static char wbuf[BUF_LEN] = {'1'};
+static const char *FM_POWER_STAUTS_PATH = "/proc/fm";
+static const char *FM_DEVICE_PATH = "dev/fm";
+
+status_t AudioMTKGainController::setFmVolume(const float fm_volume) {
+ ALOGV("%s(), fm_volume = %f", __FUNCTION__, fm_volume);
+
+ // Calculate HW Gain Value
+ uint32_t volume_index = logToLinear(fm_volume); // 0 ~ 256
+ uint32_t hw_gain = kHWGainMap[volume_index >> 1]; // 0 ~ 0x80000
+
+ // Set HW Gain
+ return mHardwareResourceManager->setHWGain2DigitalGain(hw_gain);
+}
+
+/*
+status_t AudioMTKGainController::SetDigitalHwGain(int _digitalLinearGain, enum GAINTABLE_HWGAIN_TYPE _hwGainType)
+{
+ ALOGD("%s(), _digitalLinearGain = %d, _hwGainType = %d", __FUNCTION__, _digitalLinearGain, _hwGainType);
+
+ uint32_t hw_gain = kHWGainMap[_digitalLinearGain >> 1]; // 0 ~ 0x80000
+
+ switch (_hwGainType)
+ {
+ case GAINTABLE_HWGAIN1:
+ return mHardwareResourceManager->setHWGain2DigitalGain(hw_gain);
+ case GAINTABLE_HWGAIN2:
+ ALOGW("%s(), error, HW Gain2 not supported", __FUNCTION__);
+ return BAD_VALUE;
+ default:
+ ALOGW("%s(), error, undefined _HwGainType = %d", __FUNCTION__, _hwGainType);
+ break;
+ }
+ return BAD_VALUE;
+}
+
+enum GAINTABLE_HWGAIN_TYPE AudioMTKGainController::GetHWGainTypeForFM()
+{
+ return GAINTABLE_HWGAIN1;
+}
+*/
+int AudioMTKGainController::GetDigitalLinearGain(int _volIdx, audio_devices_t _device, audio_stream_type_t _streamType) {
+ ALOGD("%s(), _volIdx = %d, _device = %d, _streamType = %d", __FUNCTION__, _volIdx, _device, _streamType);
+
+ GAIN_DEVICE gainDevice = getGainDevice(_device);
+
+ // convert _volIdx to linear(0~255)
+ if (!isValidStreamType(_streamType)) {
+ ALOGE("error, Invalid stream type = %d", _streamType);
+ _streamType = AUDIO_STREAM_MUSIC;
+ }
+ int linearGain = mGainTable.sceneGain[mSceneIndex].streamGain[_streamType][gainDevice][_volIdx].digital;
+ return keyvolumeStep - linearGain;
+}
+
+float AudioMTKGainController::GetDigitalLogGain(int _volIdx, audio_devices_t _device, audio_stream_type_t _streamType) {
+ return linearToLog(GetDigitalLinearGain(_volIdx, _device, _streamType));
+}
+
+bool AudioMTKGainController::isValidStreamType(audio_stream_type_t _streamType) {
+ return (_streamType >= GAIN_MIN_STREAM_TYPE && _streamType <= GAIN_MAX_STREAM_TYPE);
+}
+
+bool AudioMTKGainController::isValidVolIdx(int _idx, audio_mode_t _mode) {
+ if (isInVoiceCall(_mode)) {
+ return (_idx >= 0 && _idx <= GAIN_MAX_SPEECH_VOL_INDEX);
+ } else {
+ return (_idx >= 0 && _idx <= GAIN_MAX_VOL_INDEX);
+ }
+}
+
+bool AudioMTKGainController::isHeadsetCategory(enum GAIN_DEVICE _gainDevice) {
+ return _gainDevice == GAIN_DEVICE_HEADPHONE ||
+ _gainDevice == GAIN_DEVICE_HEADSET ||
+ _gainDevice == GAIN_DEVICE_HSSPK ||
+ _gainDevice == GAIN_DEVICE_HEADSET_5POLE ||
+ _gainDevice == GAIN_DEVICE_HEADSET_5POLE_ANC ||
+ _gainDevice == GAIN_DEVICE_LPBK_HP;
+}
+
+bool AudioMTKGainController::isEarpieceCategory(enum GAIN_DEVICE _gainDevice) {
+ return _gainDevice == GAIN_DEVICE_EARPIECE ||
+ _gainDevice == GAIN_DEVICE_HAC ||
+ _gainDevice == GAIN_DEVICE_LPBK_RCV ||
+ _gainDevice == GAIN_DEVICE_RCV_EV ;
+}
+
+bool AudioMTKGainController::isSpeakerCategory(enum GAIN_DEVICE _gainDevice) {
+ return _gainDevice == GAIN_DEVICE_SPEAKER ||
+ (_gainDevice == GAIN_DEVICE_HSSPK && mSpec->spkAnaType != GAIN_ANA_HEADPHONE) ||
+ _gainDevice == GAIN_DEVICE_LPBK_SPK ||
+ _gainDevice == GAIN_DEVICE_SPK_EV;
+}
+
+bool AudioMTKGainController::isDmicDevice(enum GAIN_DEVICE _gainDevice) {
+ return IsAudioSupportFeature(AUDIO_SUPPORT_DMIC) && // use DMIC & is built in mic
+ (_gainDevice == GAIN_DEVICE_EARPIECE ||
+ _gainDevice == GAIN_DEVICE_SPEAKER ||
+ _gainDevice == GAIN_DEVICE_HEADPHONE ||
+ _gainDevice == GAIN_DEVICE_LPBK_RCV ||
+ _gainDevice == GAIN_DEVICE_LPBK_SPK ||
+ _gainDevice == GAIN_DEVICE_RCV_EV ||
+ _gainDevice == GAIN_DEVICE_SPK_EV);
+}
+
+uint32_t AudioMTKGainController::getHpImpedanceIdx(int32_t impedance) {
+ for (unsigned int i = 0; i < mSpec->hpImpThresholdList.size(); i++) {
+ if (impedance <= mSpec->hpImpThresholdList[i]) {
+ return i;
+ }
+ }
+
+ return mSpec->hpImpThresholdList.size();
+}
+
+int AudioMTKGainController::getHpImpedanceCompesateValue(void) {
+ ASSERT(mHpImpedanceIdx <= mSpec->hpImpThresholdList.size());
+
+ ALOGG("%s(), mHpImpedanceIdx = %d, compensate value = %d",
+ __FUNCTION__,
+ mHpImpedanceIdx,
+ mSpec->hpImpCompensateList[mHpImpedanceIdx]);
+
+ return mSpec->hpImpCompensateList[mHpImpedanceIdx];
+}
+
+int AudioMTKGainController::tuneGainForMasterVolume(int gain, audio_mode_t mode, GAIN_DEVICE gainDevice) {
+ int bufferGainPreferMaxIdx = 0;
+ if (isHeadsetCategory(gainDevice)) {
+ bufferGainPreferMaxIdx = mSpec->audioBufferGainPreferMaxIdx;
+ } else if (isSpeakerCategory(gainDevice)) {
+ switch (mSpec->spkAnaType) {
+ case GAIN_ANA_HEADPHONE:
+ bufferGainPreferMaxIdx = mSpec->audioBufferGainPreferMaxIdx;
+ break;
+ case GAIN_ANA_LINEOUT:
+ bufferGainPreferMaxIdx = mSpec->lineoutBufferGainPreferMaxIdx;
+ break;
+ case GAIN_ANA_SPEAKER:
+ default:
+ ALOGE("%s(), error, this should not happen", __FUNCTION__);
+ ASSERT(false);
+ break;
+ }
+ } else { // if (isEarpieceCategory(gainDevice))
+ bufferGainPreferMaxIdx = mSpec->voiceBufferGainPreferMaxIdx;
+ }
+
+ // adjust gain according to master volume
+ if (!isInVoiceCall(mode) && // mMasterVolume don't affect voice call
+ gain <= bufferGainPreferMaxIdx) { // don't change gain if already mute(-40dB)
+ int degradedB = (keyvolumeStep - logToLinear(mMasterVolume)) * keydBPerStep;
+ ALOGG("%s(), degraded gain of mMasterVolume = %d dB", __FUNCTION__, degradedB);
+ if (gain + degradedB <= bufferGainPreferMaxIdx) {
+ gain += degradedB;
+ } else {
+ gain = bufferGainPreferMaxIdx;
+ }
+ }
+
+ return gain;
+}
+
+int AudioMTKGainController::tuneGainForHpImpedance(int gain, GAIN_DEVICE gainDevice) {
+ if (isHeadsetCategory(gainDevice) &&
+ mSpec->hpImpEnable &&
+ gain <= mSpec->audioBufferGainPreferMaxIdx && // don't change gain if already mute(-40dB)
+ !mANCEnable) {
+ ALOGG("%s(), before compesate HP impedance, bufferGain = %d", __FUNCTION__, gain);
+ gain += getHpImpedanceCompesateValue();
+ // prevent set to mute(-40dB) when change gain for HP impedance
+ if (gain > mSpec->audioBufferGainPreferMaxIdx) {
+ gain = mSpec->audioBufferGainPreferMaxIdx;
+ } else if (gain < 0) {
+ gain = 0;
+ }
+
+ ALOGD("%s(), after compesate HP impedance idx (%d), bufferGain = %d",
+ __FUNCTION__,
+ mHpImpedanceIdx,
+ gain);
+ }
+
+ return gain;
+}
+
+/********************************************************************************
+*
+*
+*
+* UnUsed API
+*
+*
+*
+***********************************************************************************/
+
+uint16_t AudioMTKGainController::MappingToDigitalGain(unsigned char Gain __unused) {
+ return 0;
+}
+
+uint16_t AudioMTKGainController::MappingToPGAGain(unsigned char Gain __unused) {
+ return 0;
+}
+
+status_t AudioMTKGainController::setMasterVolume(float v, audio_mode_t mode, uint32_t devices) {
+ ALOGG("%s(), mMasterVolume = %f, mode = %d, devices = 0x%x", __FUNCTION__, v, mode, devices);
+ mMasterVolume = v;
+
+ if (mode == AUDIO_MODE_CURRENT) {
+ mode = mHwStream.mode;
+ }
+ mHwStream.mode = mode;
+ mHwStream.devices = devices;
+ if (!isInVoiceCall(mode)) {
+ setNormalVolume(mHwStream.stream, mHwStream.index, devices, mode);
+ }
+ return NO_ERROR;
+}
+
+float AudioMTKGainController::getMasterVolume() {
+ ALOGV("AudioMTKGainController getMasterVolume");
+ return mMasterVolume;
+}
+
+
+status_t AudioMTKGainController::setVoiceVolume(float v, audio_mode_t mode, uint32_t device) {
+ mVoiceVolume = v;
+ mHwStream.mode = mode;
+ mHwStream.devices = device;
+ setVoiceVolume(mHwStream.index, device, mode);
+ return NO_ERROR;
+}
+
+float AudioMTKGainController::getVoiceVolume(void) {
+ return mVoiceVolume;
+}
+
+status_t AudioMTKGainController::setVoiceVolume(int MapVolume __unused, uint32_t device __unused) {
+ return INVALID_OPERATION;
+}
+status_t AudioMTKGainController::ApplyVoiceGain(int degradeDb __unused, audio_mode_t mode __unused, uint32_t device __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioMTKGainController::setStreamVolume(int stream __unused, float v __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioMTKGainController::setStreamMute(int stream __unused, bool mute __unused) {
+ return INVALID_OPERATION;
+}
+
+float AudioMTKGainController::getStreamVolume(int stream __unused) {
+ return 1.0;
+}
+
+// should depend on different usage , FM ,MATV and output device to setline in gain
+status_t AudioMTKGainController::SetLineInPlaybackGain(int type __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioMTKGainController::SetLineInRecordingGain(int type __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioMTKGainController::SetSideTone(uint32_t Mode __unused, uint32_t Gain __unused) {
+
+ return INVALID_OPERATION;
+}
+
+uint32_t AudioMTKGainController::GetSideToneGain(uint32_t device __unused) {
+
+ return INVALID_OPERATION;
+}
+
+
+status_t AudioMTKGainController::SetMicGain(uint32_t Mode __unused, uint32_t Gain __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioMTKGainController::SetULTotalGain(uint32_t Mode __unused, unsigned char Gain __unused) {
+ /* deprecated */
+ return NO_ERROR;
+}
+
+status_t AudioMTKGainController::SetDigitalHwGain(uint32_t Mode __unused, uint32_t Gain __unused, uint32_t routes __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioMTKGainController::SetMicGainTuning(uint32_t Mode __unused, uint32_t Gain __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioMTKGainController::SetMicGainTuning(GAIN_MIC_MODE micMode, GAIN_DEVICE gainDevice, uint32_t gainDecimal) {
+ unsigned char micGain;
+
+ // handle deprecated GAIN_MIC_MODE
+ if (micMode >= NUM_GAIN_MIC_MODE) {
+ if (micMode == Normal_Mic) {
+ micMode = GAIN_MIC_VOICE_CALL;
+ gainDevice = GAIN_DEVICE_EARPIECE;
+ } else if (micMode == Handfree_Mic) {
+ micMode = GAIN_MIC_VOICE_CALL;
+ gainDevice = GAIN_DEVICE_SPEAKER;
+ } else if (micMode == Headset_Mic) {
+ micMode = GAIN_MIC_VOICE_CALL;
+ gainDevice = getGainDevice(AUDIO_DEVICE_IN_WIRED_HEADSET);
+ } else {
+ ALOGE("%s(), micMode %d not supported", __FUNCTION__, micMode);
+ return BAD_VALUE;
+ }
+ }
+
+ // decimal to micIdx
+ micGain = mSpec->micIdxMax[gainDevice] - (mSpec->decRecMax - gainDecimal) / mSpec->decRecStepPerDb;
+
+ if (micGain > mSpec->micIdxMax[gainDevice]) {
+ micGain = mSpec->micIdxMax[gainDevice];
+ }
+ if (micGain < mSpec->micIdxMin[gainDevice]) {
+ micGain = mSpec->micIdxMin[gainDevice];
+ }
+
+ if (micMode == GAIN_MIC_VOICE_CALL) {
+ mGainTable.nonSceneGain.speechMicGain[mBand][mNetwork][gainDevice].gain = micGain;
+ } else {
+ mGainTable.sceneGain[mSceneIndex].micGain[micMode][gainDevice].gain = micGain;
+ }
+
+ ALOGD("%s(), micMode %d, gainDevice %d, gainDecimal %u, set micGain %hhu", __FUNCTION__, micMode, gainDevice, gainDecimal, micGain);
+
+ return NO_ERROR;
+}
+
+unsigned short AudioMTKGainController::getMicGainDecimal(GAIN_MIC_MODE micMode, GAIN_DEVICE gainDevice) {
+ uint8_t micGain;
+
+ // handle deprecated GAIN_MIC_MODE
+ if (micMode >= NUM_GAIN_MIC_MODE) {
+ if (micMode == Normal_Mic) {
+ micMode = GAIN_MIC_VOICE_CALL;
+ gainDevice = GAIN_DEVICE_EARPIECE;
+ } else if (micMode == Handfree_Mic) {
+ micMode = GAIN_MIC_VOICE_CALL;
+ gainDevice = GAIN_DEVICE_SPEAKER;
+ } else if (micMode == Headset_Mic) {
+ micMode = GAIN_MIC_VOICE_CALL;
+ gainDevice = getGainDevice(AUDIO_DEVICE_IN_WIRED_HEADSET);
+ } else {
+ ALOGE("%s(), MicType %d not supported", __FUNCTION__, micMode);
+ micMode = GAIN_MIC_VOICE_CALL;
+ gainDevice = GAIN_DEVICE_EARPIECE;
+ }
+ }
+
+ micGain = micMode == GAIN_MIC_VOICE_CALL ?
+ mGainTable.nonSceneGain.speechMicGain[mBand][mNetwork][gainDevice].gain :
+ mGainTable.sceneGain[mSceneIndex].micGain[micMode][gainDevice].gain;
+
+ if (micGain > mSpec->micIdxMax[gainDevice]) {
+ micGain = mSpec->micIdxMax[gainDevice];
+ }
+ if (micGain < mSpec->micIdxMin[gainDevice]) {
+ micGain = mSpec->micIdxMin[gainDevice];
+ }
+
+ // calculate decimal, micIdxMax <--> mSpec->decRecMax
+ unsigned short micGainDecimal = mSpec->decRecMax - (mSpec->micIdxMax[gainDevice] - micGain) * mSpec->decRecStepPerDb;
+ ALOGD("%s(), micMode %d, gainDevice %d, micGainDecimal %hu",
+ __FUNCTION__, micMode, gainDevice, micGainDecimal);
+
+ return micGainDecimal;
+}
+
+bool AudioMTKGainController::GetHeadPhoneImpedance(void) {
+ ALOGG("%s(), mSpec->hpImpEnable = %d OnBoardResistor = %d mHpImpedanceIdx= %d",
+ __FUNCTION__, mSpec->hpImpEnable, mSpec->hpImpOnBoardResistor, mHpImpedanceIdx);
+
+ if (mSpec->hpImpEnable) {
+#if defined(MTK_AUDIO_KS)
+ // enable impedance detection path
+ struct pcm_config config;
+ String8 apTurnOnSequence = String8(AUDIO_CTL_HP_IMPEDANCE);
+
+ memset(&config, 0, sizeof(config));
+ config.channels = 2;
+ config.rate = 48000;
+ config.period_size = 1024;
+ config.period_count = 2;
+ config.format = PCM_FORMAT_S16_LE;
+ config.stop_threshold = ~(0U);
+
+ int cardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmHostlessADDADLI2SOut);
+ int pcmIndex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessADDADLI2SOut);
+
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(apTurnOnSequence);
+
+ struct pcm *pcm = pcm_open(cardIndex, pcmIndex, PCM_OUT, &config);
+ if (pcm == NULL || pcm_is_ready(pcm) == false) {
+ ALOGE("%s(), Unable to open pcm device %u (%s)", __FUNCTION__, pcmIndex, pcm_get_error(pcm));
+ } else {
+ if (pcm_start(pcm)) {
+ ALOGE("%s(), pcm_start %p fail due to %s", __FUNCTION__, pcm, pcm_get_error(pcm));
+ }
+ }
+
+#endif
+ uint32_t newHPImpedance = 0;
+ int32_t HPImpedanceValue = 0;
+
+ struct mixer_ctl *ctl;
+ unsigned int num_values, i;
+ ctl = mixer_get_ctl_by_name(mMixer, "Audio HP ImpeDance Setting");
+
+ num_values = mixer_ctl_get_num_values(ctl);
+ for (i = 0; i < num_values; i++) {
+ newHPImpedance = mixer_ctl_get_value(ctl, i);
+ HPImpedanceValue = newHPImpedance - mSpec->hpImpOnBoardResistor;
+ }
+
+#if defined(MTK_AUDIO_KS)
+ if (pcm) {
+ pcm_stop(pcm);
+ pcm_close(pcm);
+ pcm = NULL;
+ }
+
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(apTurnOnSequence);
+#endif
+
+ uint32_t newHpImpedanceIdx = getHpImpedanceIdx(HPImpedanceValue);
+ ALOGD("%s(), newHpImpedanceIdx = %d, Detected value = %d, Headphone Impedance = %d, OnBoardResistor = %d",
+ __FUNCTION__, newHpImpedanceIdx, newHPImpedance, HPImpedanceValue, mSpec->hpImpOnBoardResistor);
+
+ // update volume setting
+ if (mHpImpedanceIdx != newHpImpedanceIdx) {
+ mHpImpedanceIdx = newHpImpedanceIdx;
+ setAnalogVolume_l(mHwStream.stream, mHwStream.devices, mHwStream.index, mHwStream.mode);
+ }
+ }
+
+ return true;
+}
+
+int AudioMTKGainController::ApplyAudioGainTuning(int Gain __unused, uint32_t mode __unused, uint32_t device __unused) {
+ return 0;
+}
+
+void AudioMTKGainController::SetLinoutRGain(int DegradedBGain __unused) {
+
+}
+
+void AudioMTKGainController::SetLinoutLGain(int DegradedBGain __unused) {
+
+}
+
+uint32_t AudioMTKGainController::GetOffloadGain(float vol_f __unused) {
+ return 0;
+}
+
+void AudioMTKGainController::setANCEnable(bool _enable) {
+#ifdef MTK_AUDIO_SW_DRE
+ AL_AUTOLOCK(mSWDRELock);
+#endif
+ mANCEnable = _enable;
+#ifdef MTK_AUDIO_SW_DRE
+ if (mANCEnable) {
+ if (mSWDREMute) {
+ SWDRERampToNormal();
+ mSWDREMute = false;
+ }
+ } else {
+ updateSWDREState(false, false);
+ }
+#endif
+}
+
+#ifdef MTK_AUDIO_SW_DRE
+void AudioMTKGainController::registerPlaybackHandler(uint32_t _identity) {
+ if (mMutedHandlerVector.indexOfKey(_identity) >= 0) {
+ ALOGW("%s(), warn, playback handler already exist, _identity = %d", __FUNCTION__, _identity);
+ } else {
+ AL_AUTOLOCK(mSWDRELock);
+ mMutedHandlerVector.add(_identity, false);
+ updateSWDREState(true, false);
+ }
+}
+
+void AudioMTKGainController::removePlaybackHandler(uint32_t _identity) {
+ if (mMutedHandlerVector.indexOfKey(_identity) < 0) {
+ ALOGW("%s(), warn, playback handler not found, _identity = %d", __FUNCTION__, _identity);
+ } else {
+ AL_AUTOLOCK(mSWDRELock);
+ mMutedHandlerVector.removeItem(_identity);
+ updateSWDREState(true, false);
+ }
+}
+
+void AudioMTKGainController::requestMute(uint32_t _identity, bool _mute) {
+ if (mMutedHandlerVector.indexOfKey(_identity) < 0) {
+ ALOGW("%s(), warn, playback handler not found, _identity = %d", __FUNCTION__, _identity);
+ } else {
+ if (mMutedHandlerVector.valueFor(_identity) != _mute) {
+ AL_AUTOLOCK(mSWDRELock);
+ mMutedHandlerVector.replaceValueFor(_identity, _mute);
+ updateSWDREState(false, true);
+ }
+ }
+}
+
+void AudioMTKGainController::setFmEnable(bool _enable) {
+ AL_AUTOLOCK(mSWDRELock);
+ if (_enable) {
+ mFmEnable = true;
+ if (mSWDREMute) {
+ SWDRERampToNormal();
+ mSWDREMute = false;
+ }
+ } else {
+ mFmEnable = false;
+ updateSWDREState(false, false);
+ }
+}
+
+bool AudioMTKGainController::isOtherModuleWorking() {
+ return mFmEnable || mANCEnable;
+}
+
+void AudioMTKGainController::updateSWDREState(bool _numChanged, bool _muteChanged) {
+ bool curHasMuteHandler = false;
+ size_t curNumHandler;
+
+ if (_numChanged == false && _muteChanged == true) {
+ for (size_t i = 0; i < mMutedHandlerVector.size(); i++) {
+ if (mMutedHandlerVector.valueAt(i) == true) {
+ curHasMuteHandler = true;
+ break;
+ }
+ }
+
+ if (mNumHandler == 1 && !isOtherModuleWorking()) {
+ if (mHasMuteHandler == false && curHasMuteHandler == true) {
+ ALOGD("%s(), num = 1, hasMuteHandler false -> true", __FUNCTION__);
+ mSWDREMute = true;
+ // call ramp to mute
+ SWDRERampToMute();
+ } else if (mHasMuteHandler == true && curHasMuteHandler == false) {
+ ALOGD("%s(), num = 1, hasMuteHandler true -> false", __FUNCTION__);
+ // call ramp to normal
+ SWDRERampToNormal();
+ mSWDREMute = false;
+ }
+ }
+
+ mHasMuteHandler = curHasMuteHandler;
+ } else if (_numChanged == true && _muteChanged == false) {
+ curNumHandler = mMutedHandlerVector.size();
+
+ if (mHasMuteHandler) {
+ if (mNumHandler > 1 && curNumHandler == 1 && !isOtherModuleWorking()) {
+ ALOGD("%s(), hasMuteHandler, numHandler >1 -> 1", __FUNCTION__);
+ mSWDREMute = true;
+ // call ramp to mute
+ SWDRERampToMute();
+ } else if (mNumHandler == 1 && curNumHandler > 1 && !isOtherModuleWorking()) {
+ ALOGD("%s(), hasMuteHandler, numHandler 1 -> >1", __FUNCTION__);
+ // call ramp to normal
+ SWDRERampToNormal();
+ mSWDREMute = false;
+ } else if (curNumHandler == 0) {
+ ALOGD("%s(), hasMuteHandler, numHandler 1 -> 0", __FUNCTION__);
+ mHasMuteHandler = false;
+ // call ramp to normal
+ SWDRERampToNormal();
+ mSWDREMute = false;
+ }
+ }
+
+ mNumHandler = curNumHandler;
+ } else {
+ if (mNumHandler == 1 && mHasMuteHandler && !isOtherModuleWorking()) {
+ ALOGD("%s(), num = 1, has mute", __FUNCTION__);
+ mSWDREMute = true;
+ // call ramp to mute
+ SWDRERampToMute();
+ }
+ return;
+ }
+}
+
+void AudioMTKGainController::SWDRERampToMute() {
+ int cur_idx = GetHeadphoneLGain();
+ int target_idx = (int)(mSpec->audioBufferGainString.size() - 1);
+
+ ALOGD("%s(), cur_idx = %d, target_idx = %d", __FUNCTION__, cur_idx, target_idx);
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+ if (AudioALSAHyBridNLEManager::getInstance()->setNleHwConfigByIndex(target_idx) == FAILED_TRANSACTION) { // the parameter using Index of HP Gain Reg
+ SetHeadPhoneLGain(target_idx);
+ SetHeadPhoneRGain(target_idx);
+ }
+#else
+ SetHeadPhoneLGain(target_idx);
+ SetHeadPhoneRGain(target_idx);
+#endif
+}
+
+void AudioMTKGainController::SWDRERampToNormal() {
+ int cur_idx = GetHeadphoneLGain();
+ if (cur_idx != (int)mSpec->audioBufferGainString.size() - 1) {
+ ALOGW("%s(), cur_idx %d != mute", __FUNCTION__, cur_idx);
+ }
+
+ GAIN_DEVICE gainDevice = getGainDevice(mHwStream.devices);
+
+ /* routing will change the mHwStream.devices, error handle */
+ if (gainDevice != GAIN_DEVICE_HEADSET && gainDevice != GAIN_DEVICE_HEADPHONE &&
+ gainDevice != GAIN_DEVICE_HEADSET_5POLE && gainDevice != GAIN_DEVICE_HEADSET_5POLE_ANC) {
+ gainDevice = GAIN_DEVICE_HEADSET;
+ }
+
+ unsigned char bufferGain = mGainTable.sceneGain[mSceneIndex].streamGain[mHwStream.stream][gainDevice][mHwStream.index].analog[GAIN_ANA_HEADPHONE];
+
+ if (bufferGain >= mSpec->audioBufferGainString.size()) {
+ bufferGain = mSpec->audioBufferGainString.size() - 1;
+ }
+
+ // adjust gain according to master volume
+ bufferGain = tuneGainForMasterVolume(bufferGain, mHwStream.mode, gainDevice);
+
+ // adjust gain according to hp impedance when using HP
+ bufferGain = tuneGainForHpImpedance(bufferGain, gainDevice);
+
+ int target_idx = bufferGain;
+
+ ALOGD("%s(), cur_idx = %d, target_idx = %d, cur_devices = 0x%x", __FUNCTION__, cur_idx, target_idx, mHwStream.devices);
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+ if (AudioALSAHyBridNLEManager::getInstance()->setNleHwConfigByIndex(target_idx) == FAILED_TRANSACTION) { // the parameter using Index of HP Gain Reg
+ SetHeadPhoneLGain(target_idx);
+ SetHeadPhoneRGain(target_idx);
+ }
+#else
+ SetHeadPhoneLGain(target_idx);
+ SetHeadPhoneRGain(target_idx);
+#endif
+}
+
+#endif
+}
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAHardwareResourceManager.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAHardwareResourceManager.cpp
new file mode 100644
index 0000000..67ffb52
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAHardwareResourceManager.cpp
@@ -0,0 +1,1694 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAHardwareResourceManager.h"
+
+#include <utils/threads.h>
+
+#include "AudioType.h"
+#include <AudioLock.h>
+#include "AudioAssert.h"
+
+#include "AudioALSADriverUtility.h"
+#include "audio_custom_exp.h"
+
+// TMP
+#include "AudioALSACodecDeviceOutEarphonePMIC.h"
+#include "AudioALSACodecDeviceOutReceiverPMIC.h"
+#include "AudioALSACodecDeviceOutSpeakerPMIC.h"
+#include "AudioALSACodecDeviceOutSpeakerEarphonePMIC.h"
+#include "AudioALSADeviceConfigManager.h"
+#include "AudioALSAHardware.h"
+#include "AudioALSASampleRateController.h"
+#include "AudioALSADeviceParser.h"
+#include "AudioVolumeFactory.h"
+#include "LoopbackManager.h"
+#include "AudioDeviceInt.h"
+#include "AudioCustParamClient.h"
+
+#ifdef MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT
+#include "AudioParamParser.h"
+#endif
+
+#include "AudioSmartPaController.h"
+
+#ifdef MTK_USB_PHONECALL
+#include "AudioUSBPhoneCallController.h"
+#endif
+
+#ifdef USING_EXTAMP_HP
+#include "AudioALSACodecDeviceOutExtSpeakerAmp.h"
+#endif
+
+#ifdef HAVING_RCV_SPK_SWITCH
+#include "AudioALSACodecDeviceOutReceiverSpeakerSwitch.h"
+#endif
+
+#include "WCNChipController.h"
+
+#ifdef MTK_ANC_SUPPORT
+#include "AudioALSAANCController.h"
+#endif
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+#include "AudioALSANLEController.h"
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSAHardwareResourceManager"
+
+static const char *PROPERTY_KEY_EXTDAC = "vendor.audiohal.resource.extdac.support";
+
+#define A2DP_DEFAULT_LANTENCY (100)
+
+namespace android {
+
+static const char *SIDEGEN[] = {
+ "I0I1", "I2", "I3I4", "I5I6",
+ "I7I8", "I9", "I10I11", "I12I13",
+ "I14", "I15I16", "I17I18", "I19I20",
+ "I21I22", "O0O1", "O2", "O3O4",
+ "O5O6", "O7O8", "O9O10", "O11",
+ "O12", "O13O14", "O15O16", "O17O18",
+ "O19O20", "O21O22", "O23O24", "OFF",
+ "O3", "O4", "I25I26", "O25",
+ "O28O29", "I23I24", "O32O33", "I34I35"
+};
+
+static const char *SIDEGEN_SAMEPLRATE[] = {
+ "8K", "11K", "12K", "16K",
+ "22K", "24K", "32K", "44K",
+ "48K", "88k", "96k", "176k",
+ "192k"
+};
+
+static AudioLock mGetInstanceLock;
+AudioALSAHardwareResourceManager *AudioALSAHardwareResourceManager::mAudioALSAHardwareResourceManager = NULL;
+AudioALSAHardwareResourceManager *AudioALSAHardwareResourceManager::getInstance() {
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSAHardwareResourceManager == NULL) {
+ mAudioALSAHardwareResourceManager = new AudioALSAHardwareResourceManager();
+ }
+ ASSERT(mAudioALSAHardwareResourceManager != NULL);
+ return mAudioALSAHardwareResourceManager;
+}
+
+status_t AudioALSAHardwareResourceManager::ResetDevice(void) {
+#if defined(MTK_AUDIO_KS)
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIO_CTL_RESET_DEVICE);
+#else
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Amp_R_Switch"), "Off")) {
+ ALOGE("Error: Audio_Amp_R_Switch invalid value");
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Amp_L_Switch"), "Off")) {
+ ALOGE("Error: Audio_Amp_L_Switch invalid value");
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Voice_Amp_Switch"), "Off")) {
+ ALOGE("Error: Voice_Amp_Switch invalid value");
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Speaker_Amp_Switch"), "Off")) {
+ ALOGE("Error: Speaker_Amp_Switch invalid value");
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Headset_Speaker_Amp_Switch"), "Off")) {
+ ALOGE("Error: Headset_Speaker_Amp_Switch invalid value");
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Ext_Speaker_Amp_Switch"), "Off")) {
+ ALOGE("Error: Ext_Speaker_Amp_Switch invalid value");
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Receiver_Speaker_Switch"), "Off")) {
+ ALOGE("Error: Receiver_Speaker_Switch invalid value");
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_ADC_1_Switch"), "Off")) {
+ ALOGE("Error: Headset_Speaker_Amp_Switch invalid value");
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_ADC_2_Switch"), "Off")) {
+ ALOGE("Error: Headset_Speaker_Amp_Switch invalid value");
+ }
+#endif
+ return NO_ERROR;
+}
+
+AudioALSAHardwareResourceManager::AudioALSAHardwareResourceManager() :
+ mMixer(AudioALSADriverUtility::getInstance()->getMixer()),
+ mPcmDL(NULL),
+ mDeviceConfigManager(AudioALSADeviceConfigManager::getInstance()),
+ mOutputDevices(AUDIO_DEVICE_NONE),
+ mInputDevice(AUDIO_DEVICE_NONE),
+ mOutputDeviceSampleRate(44100),
+ mInputDeviceSampleRate(48000),
+ mIsChangingInputDevice(false),
+ mStartOutputDevicesCount(0),
+ mStartInputDeviceCount(0),
+ mSpeakerStatusChangeCb(NULL),
+#if defined(MTK_AUDIO_MIC_INVERSE) || defined(DEN_PHONE_MIC_INVERSE)
+ mMicInverse(true), // if defined MTK_AUDIO_MIC_INVERSE, default invert main & ref mic
+#else
+ mMicInverse(false),
+#endif
+ mBuiltInMicSpecificType(BUILTIN_MIC_DEFAULT),
+#ifdef MTK_HIFIAUDIO_SUPPORT
+ mHiFiState(false),
+ mHiFiDACStatusCount(0),
+#endif
+ mNumHSPole(4),
+ mHeadchange(false),
+ mSmartPaController(AudioSmartPaController::getInstance()),
+ mSpkPcmOut(NULL),
+ mA2dpDeviceLatency(A2DP_DEFAULT_LANTENCY),
+ mA2dpFwLatency(0) {
+ ALOGD("%s()", __FUNCTION__);
+
+#ifdef CONFIG_MT_ENG_BUILD
+ mLogEnable = 1;
+#else
+ mLogEnable = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);
+#endif
+ ResetDevice();
+ AudioALSACodecDeviceOutEarphonePMIC::getInstance();
+ AudioALSACodecDeviceOutSpeakerEarphonePMIC::getInstance();
+
+ memset((void *)&mSpkPcmConfig, 0, sizeof(mSpkPcmConfig));
+ mStartInputDeviceSeqeunce.clear();
+
+ mNumPhoneMicSupport = AudioCustParamClient::GetInstance()->getNumMicSupport();
+
+#ifdef MTK_HIFIAUDIO_SUPPORT
+ mHiFiState = false;
+#endif
+ setMicType();
+
+ if (!mSmartPaController->isSmartPAUsed() &&
+ mSmartPaController->isSmartPADynamicDetectSupport()) {
+ setNonSmartPAType();
+ }
+}
+
+
+AudioALSAHardwareResourceManager::~AudioALSAHardwareResourceManager() {
+ ALOGD("%s()", __FUNCTION__);
+ AL_AUTOLOCK(mGetInstanceLock);
+ mAudioALSAHardwareResourceManager = NULL;
+}
+
+/**
+ * output devices
+ */
+status_t AudioALSAHardwareResourceManager::setOutputDevice(const audio_devices_t new_devices, const uint32_t sample_rate) {
+ ALOGD_IF(mLogEnable,"+%s(), new_devices = 0x%x, mStartOutputDevicesCount = %d", __FUNCTION__, new_devices, mStartOutputDevicesCount);
+
+ ASSERT(mStartOutputDevicesCount == 0);
+
+ mOutputDevices = new_devices;
+ mOutputDeviceSampleRate = sample_rate;
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::startOutputDevice(const audio_devices_t new_devices, const uint32_t SampleRate) {
+ ALOGD("+%s(), new_devices = 0x%x, mOutputDevices = 0x%x, mStartOutputDevicesCount = %d SampleRate = %d",
+ __FUNCTION__, new_devices, mOutputDevices, mStartOutputDevicesCount, SampleRate);
+
+ AL_AUTOLOCK(mLock);
+
+ if (new_devices == mOutputDevices) {
+ // don't need to do anything
+ } else if (AUDIO_DEVICE_NONE != mOutputDevices) {
+ changeOutputDevice_l(new_devices, SampleRate);
+ } else {
+ startOutputDevice_l(new_devices, SampleRate);
+ }
+
+ mStartOutputDevicesCount++;
+
+ ALOGD_IF(mLogEnable, "-%s(), mOutputDevices = 0x%x, mStartOutputDevicesCount = %d", __FUNCTION__, mOutputDevices, mStartOutputDevicesCount);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::stopOutputDevice() {
+ ALOGD("+%s(), mOutputDevices = 0x%x, mStartOutputDevicesCount = %d", __FUNCTION__, mOutputDevices, mStartOutputDevicesCount);
+
+ AL_AUTOLOCK(mLock);
+
+ if (mStartOutputDevicesCount > 1) {
+ // don't need to do anything
+ } else {
+ if (mStartOutputDevicesCount == 1 && mOutputDevices != AUDIO_DEVICE_NONE) {
+ stopOutputDevice_l();
+ } else {
+ ASSERT(0);
+ if (mStartOutputDevicesCount < 0) {
+ mStartOutputDevicesCount = 0;
+ }
+ }
+ }
+
+ if (mStartOutputDevicesCount > 0) {
+ mStartOutputDevicesCount--;
+ }
+
+ if (mHeadchange == true && mStartOutputDevicesCount == 0) {
+#ifdef MTK_NEW_VOL_CONTROL
+ AudioMTKGainController::getInstance()->GetHeadPhoneImpedance();
+#else
+ AudioALSAVolumeController::getInstance()->GetHeadPhoneImpedance();
+#endif
+ mHeadchange = false;
+ }
+
+ ALOGD_IF(mLogEnable,"-%s(), mOutputDevices = 0x%x, mStartOutputDevicesCount = %d", __FUNCTION__, mOutputDevices, mStartOutputDevicesCount);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::changeOutputDevice(const audio_devices_t new_devices) {
+ ALOGD("+%s(), mOutputDevices: 0x%x => 0x%x", __FUNCTION__, mOutputDevices, new_devices);
+
+ AL_AUTOLOCK(mLock);
+ changeOutputDevice_l(new_devices, mOutputDeviceSampleRate);
+
+ ALOGD_IF(mLogEnable, "-%s(), mOutputDevices: 0x%x", __FUNCTION__, mOutputDevices);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::startOutputDevice_l(const audio_devices_t new_devices, const uint32_t SampleRate) {
+ mOutputDevices = new_devices;
+ mOutputDeviceSampleRate = SampleRate;
+
+#if !defined(MTK_AUDIO_KS)
+ if (mSmartPaController->isSmartPAUsed() &&
+ (new_devices & AUDIO_DEVICE_OUT_SPEAKER && mSmartPaController->isAlsaCodec())) {
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmExtSpkMeida);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmExtSpkMeida);
+
+ memset(&mSpkPcmConfig, 0, sizeof(mSpkPcmConfig));
+ mSpkPcmConfig.channels = 2;
+ mSpkPcmConfig.rate = SampleRate;
+ mSpkPcmConfig.period_size = 1024;
+ mSpkPcmConfig.period_count = 2;
+ mSpkPcmConfig.format = PCM_FORMAT_S32_LE;
+ mSpkPcmConfig.stop_threshold = ~(0U); // TODO: KC: check if needed
+
+ ASSERT(mSpkPcmOut == NULL);
+
+ if (mSmartPaController->getI2sSetStage() & SPK_I2S_BEFORE_PCM_OPEN) {
+ mSmartPaController->dspOnBoardSpeakerOn(SampleRate);
+ }
+
+ mSpkPcmOut = pcm_open(cardindex, pcmindex, PCM_OUT | PCM_MONOTONIC, &mSpkPcmConfig);
+
+ if (pcm_is_ready(mSpkPcmOut) == false) {
+ ALOGE("%s(), pcm_is_ready(%p) == false due to %s, close pcm.", __FUNCTION__, mSpkPcmOut, pcm_get_error(mSpkPcmOut));
+ pcm_close(mSpkPcmOut);
+ mSpkPcmOut = NULL;
+ } else {
+ if (pcm_start(mSpkPcmOut) != 0) {
+ ALOGE("%s(), pcm_start(%p) fail due to %s", __FUNCTION__, mSpkPcmOut, pcm_get_error(mSpkPcmOut));
+ }
+ }
+ ASSERT(mSpkPcmOut != NULL);
+ ALOGV("%s(), mSpkPcmOut = %p", __FUNCTION__, mSpkPcmOut);
+ }
+#endif
+
+ if (new_devices == (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+ new_devices == (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+#ifdef MTK_ANC_SUPPORT
+ AudioALSAANCController::getInstance()->setHeadphoneSpeakerEnabled(true);
+#endif
+ OpenHeadphoneSpeakerPath(SampleRate);
+ } else if (new_devices == AUDIO_DEVICE_OUT_EARPIECE) {
+#ifdef MTK_ANC_SUPPORT
+ AudioALSAANCController::getInstance()->setReceiverEnabled(true);
+#endif
+ OpenReceiverPath(SampleRate);
+ } else if (new_devices == AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+ new_devices == AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+ OpenHeadphonePath(SampleRate);
+ } else if (new_devices & AUDIO_DEVICE_OUT_SPEAKER) {
+#ifdef MTK_ANC_SUPPORT
+ AudioALSAANCController::getInstance()->setSpeakerEnabled(true);
+#endif
+ OpenSpeakerPath(SampleRate);
+ }
+
+ notifyOutputDeviceStatusChange(mOutputDevices, DEVICE_STATUS_ON);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::stopOutputDevice_l() {
+ if (mOutputDevices == (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+ mOutputDevices == (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+ CloseHeadphoneSpeakerPath();
+#ifdef MTK_ANC_SUPPORT
+ AudioALSAANCController::getInstance()->setHeadphoneSpeakerEnabled(false);
+#endif
+ } else if (mOutputDevices == AUDIO_DEVICE_OUT_EARPIECE) {
+ CloseReceiverPath();
+#ifdef MTK_ANC_SUPPORT
+ AudioALSAANCController::getInstance()->setReceiverEnabled(false);
+#endif
+ } else if (mOutputDevices == AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+ mOutputDevices == AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+ CloseHeadphonePath();
+ } else if (mOutputDevices & AUDIO_DEVICE_OUT_SPEAKER) {
+ CloseSpeakerPath();
+#ifdef MTK_ANC_SUPPORT
+ AudioALSAANCController::getInstance()->setSpeakerEnabled(false);
+#endif
+ }
+
+#if !defined(MTK_AUDIO_KS)
+ if (mSmartPaController->isSmartPAUsed() &&
+ (mOutputDevices & AUDIO_DEVICE_OUT_SPEAKER) &&
+ mSmartPaController->isAlsaCodec()) {
+ if (mSpkPcmOut != NULL) {
+ pcm_stop(mSpkPcmOut);
+ pcm_close(mSpkPcmOut);
+ mSpkPcmOut = NULL;
+ }
+
+ if (mSmartPaController->getI2sSetStage() & SPK_I2S_BEFORE_PCM_OPEN) {
+ mSmartPaController->dspOnBoardSpeakerOff();
+ }
+ }
+#endif
+ notifyOutputDeviceStatusChange(mOutputDevices, DEVICE_STATUS_OFF);
+
+ mOutputDevices = AUDIO_DEVICE_NONE;
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::changeOutputDevice_l(const audio_devices_t new_devices, const uint32_t SampleRate) {
+ stopOutputDevice_l();
+ startOutputDevice_l(new_devices, SampleRate);
+
+ return NO_ERROR;
+}
+
+bool AudioALSAHardwareResourceManager::isSharedOutDevice(audio_devices_t device) {
+ // these devices cannot exist at the same time
+ audio_devices_t sharedDevice = AUDIO_DEVICE_OUT_EARPIECE |
+ AUDIO_DEVICE_OUT_SPEAKER |
+ AUDIO_DEVICE_OUT_WIRED_HEADSET |
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO |
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+
+ if (isBtSpkDevice(device)) {
+ return true;
+ }
+
+ if ((device & ~sharedDevice) != 0) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * input devices
+ */
+status_t AudioALSAHardwareResourceManager::setInputDevice(const audio_devices_t new_devices) {
+ ALOGD_IF(mLogEnable,"+%s(), new_devices = 0x%x, mStartInputDeviceCount = %d", __FUNCTION__, new_devices, mStartInputDeviceCount);
+
+ return NO_ERROR;
+}
+
+void AudioALSAHardwareResourceManager::setMIC1Mode(bool isHeadsetMic) {
+ uint32_t micmode = isHeadsetMic ? mHeadsetMicMode : mPhoneMicMode;
+
+ ALOGD_IF(mLogEnable, "%s(), isHeadsetMic %d, micmode %d", __FUNCTION__, isHeadsetMic, micmode);
+
+ if (micmode == AUDIO_MIC_MODE_ACC) {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC1_TYPE_ACCMODE);
+ } else if (micmode == AUDIO_MIC_MODE_DCC) {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC1_TYPE_DCCMODE);
+ } else if ((micmode == AUDIO_MIC_MODE_DMIC) || (micmode == AUDIO_MIC_MODE_DMIC_LP) || (micmode == AUDIO_MIC_MODE_DMIC_VENDOR01)) {
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_DMIC)) {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC1_TYPE_DMICMODE);
+ } else {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC1_TYPE_ACCMODE);
+ }
+ } else if (micmode == AUDIO_MIC_MODE_DCCECMDIFF) {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC1_TYPE_DCCECMDIFFMODE);
+ } else if (micmode == AUDIO_MIC_MODE_DCCECMSINGLE) {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC1_TYPE_DCCECMSINGLEMODE);
+ }
+}
+
+void AudioALSAHardwareResourceManager::setMIC2Mode(bool isHeadsetMic) {
+ uint32_t micmode = isHeadsetMic ? mHeadsetMicMode : mPhoneMicMode;
+
+ ALOGD_IF(mLogEnable, "%s(), isHeadsetMic %d, micmode %d", __FUNCTION__, isHeadsetMic, micmode);
+
+ if (micmode == AUDIO_MIC_MODE_ACC) {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC2_TYPE_ACCMODE);
+ } else if (micmode == AUDIO_MIC_MODE_DCC) {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC2_TYPE_DCCMODE);
+ } else if ((micmode == AUDIO_MIC_MODE_DMIC) || (micmode == AUDIO_MIC_MODE_DMIC_LP) || (micmode == AUDIO_MIC_MODE_DMIC_VENDOR01)) {
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_DMIC)) {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC2_TYPE_DMICMODE);
+ } else {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC2_TYPE_ACCMODE);
+ }
+ } else if (micmode == AUDIO_MIC_MODE_DCCECMDIFF) {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC2_TYPE_DCCECMDIFFMODE);
+ } else if (micmode == AUDIO_MIC_MODE_DCCECMSINGLE) {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC2_TYPE_DCCECMSINGLEMODE);
+ }
+}
+
+void AudioALSAHardwareResourceManager::setMIC3Mode(bool isHeadsetMic) {
+ uint32_t micmode = isHeadsetMic ? mHeadsetMicMode : mPhoneMicMode;
+
+ ALOGD_IF(mLogEnable, "%s(), isHeadsetMic %d, micmode %d", __FUNCTION__, isHeadsetMic, micmode);
+
+ if (micmode == AUDIO_MIC_MODE_ACC) {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC3_TYPE_ACCMODE);
+ } else if (micmode == AUDIO_MIC_MODE_DCC) {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC3_TYPE_DCCMODE);
+ } else if ((micmode == AUDIO_MIC_MODE_DMIC) || (micmode == AUDIO_MIC_MODE_DMIC_LP) || (micmode == AUDIO_MIC_MODE_DMIC_VENDOR01)) {
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_DMIC)) {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC3_TYPE_DMICMODE);
+ } else {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC3_TYPE_ACCMODE);
+ }
+ } else if (micmode == AUDIO_MIC_MODE_DCCECMDIFF) {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC3_TYPE_DCCECMDIFFMODE);
+ } else if (micmode == AUDIO_MIC_MODE_DCCECMSINGLE) {
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC3_TYPE_DCCECMSINGLEMODE);
+ }
+}
+
+static void setSingleDmicLoopbackType(builtin_mic_specific_type mBuiltInMicSpecificType,
+ bool mMicInverse, bool enable) {
+ bool use_single_input = IsAudioSupportFeature(AUDIO_SUPPORT_DMIC) &
+ LoopbackManager::GetInstance()->GetLoopbackType();
+ AudioALSADeviceConfigManager *mDeviceConfigManager = AudioALSADeviceConfigManager::getInstance();
+
+ ALOGD("%s(), start input = %d, use_single_input = %d, mBuiltInMicSpecificType = %d",
+ __FUNCTION__, enable, use_single_input, mBuiltInMicSpecificType);
+
+ if (use_single_input) {
+ if (enable) {
+ switch (mBuiltInMicSpecificType) {
+ case BUILTIN_MIC_MIC1_ONLY:
+ if (mMicInverse) {
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_LOOPBACK_USE_SINGLE_MIC_R_CH);
+ } else {
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_LOOPBACK_USE_SINGLE_MIC_L_CH);
+ }
+
+ break;
+ case BUILTIN_MIC_MIC2_ONLY:
+ if (mMicInverse) {
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_LOOPBACK_USE_SINGLE_MIC_L_CH);
+ } else {
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_LOOPBACK_USE_SINGLE_MIC_R_CH);
+ }
+
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (mBuiltInMicSpecificType) {
+ case BUILTIN_MIC_MIC1_ONLY:
+ if (mMicInverse) {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_LOOPBACK_USE_SINGLE_MIC_R_CH);
+ } else {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_LOOPBACK_USE_SINGLE_MIC_L_CH);
+ }
+
+ break;
+ case BUILTIN_MIC_MIC2_ONLY:
+ if (mMicInverse) {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_LOOPBACK_USE_SINGLE_MIC_L_CH);
+ } else {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_LOOPBACK_USE_SINGLE_MIC_R_CH);
+ }
+
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+}
+
+status_t AudioALSAHardwareResourceManager::startInputDevice(const audio_devices_t new_device) {
+ ALOGD("+%s(), new_device = 0x%x, mInputDevice = 0x%x, mStartInputDeviceCount = %d, mMicInverse = %d, mNumPhoneMicSupport = %d",
+ __FUNCTION__, new_device, mInputDevice, mStartInputDeviceCount, mMicInverse, mNumPhoneMicSupport);
+
+ AL_AUTOLOCK(mLockin);
+ bool needTurnonSequence = (new_device & ~AUDIO_DEVICE_BIT_IN) & (AUDIO_DEVICE_IN_BUILTIN_MIC | AUDIO_DEVICE_IN_BACK_MIC | AUDIO_DEVICE_IN_WIRED_HEADSET);
+
+ if (needTurnonSequence == false) {
+ ALOGD("%s(), no need to config analog part", __FUNCTION__);
+ return NO_ERROR;
+ }
+
+#ifdef FORCE_ROUTING_REF_MIC
+ mBuiltInMicSpecificType = BUILTIN_MIC_MIC2_ONLY; /* For bring up */
+#endif
+
+ if (((mInputDevice & new_device) & ~AUDIO_DEVICE_BIT_IN) != 0) {
+ ALOGW("%s(), input device already opened", __FUNCTION__);
+ mStartInputDeviceCount++;
+ ALOGD("-%s(), mInputDevice = 0x%x, mStartInputDeviceCount = %d", __FUNCTION__, mInputDevice, mStartInputDeviceCount);
+ return NO_ERROR;
+ }
+
+ if (mStartInputDeviceCount > 0 &&
+ ((mInputDevice & new_device) & ~AUDIO_DEVICE_BIT_IN) == 0) {
+ ALOGE("%s(), shouldn't switch input device directly", __FUNCTION__);
+ ASSERT(0);
+ }
+
+ int retval = 0;
+
+#if defined(MTK_AUDIO_KS)
+ if (!mStartInputDeviceSeqeunce.isEmpty()) {
+ ALOGE("%s(), close before open different input device", __FUNCTION__);
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(mStartInputDeviceSeqeunce.string());
+ mStartInputDeviceSeqeunce.clear();
+ ASSERT(0);
+ }
+
+ String8 deviceName, specificMic, inverse;
+ switch (new_device) {
+ case AUDIO_DEVICE_IN_BUILTIN_MIC:
+ deviceName = AUDIO_CTL_BUILT_IN_MIC;
+
+ switch (mBuiltInMicSpecificType) {
+ case BUILTIN_MIC_MIC1_ONLY:
+ specificMic = AUDIO_CTL_MIC1;
+ break;
+ case BUILTIN_MIC_MIC2_ONLY:
+ specificMic = AUDIO_CTL_MIC2;
+ break;
+ case BUILTIN_MIC_MIC3_ONLY:
+ specificMic = AUDIO_CTL_MIC3;
+ break;
+ case BUILTIN_MIC_DEFAULT:
+ default:
+ if (mNumPhoneMicSupport == 2) {
+ specificMic = AUDIO_CTL_DUAL_MIC;
+ } else if (mNumPhoneMicSupport > 2) {
+ specificMic = AUDIO_CTL_THREE_MIC;
+ } else {
+ specificMic = AUDIO_CTL_SINGLE_MIC;
+ }
+ break;
+ }
+ setMIC1Mode(false);
+ setMIC3Mode(false);
+ break;
+ case AUDIO_DEVICE_IN_BACK_MIC:
+ deviceName = AUDIO_CTL_BUILT_IN_MIC;
+ if (mNumPhoneMicSupport > 2) {
+ specificMic = AUDIO_CTL_BACK_MIC_3;
+ } else {
+ specificMic = AUDIO_CTL_BACK_MIC;
+ }
+ setMIC1Mode(false);
+ setMIC3Mode(false);
+ break;
+ case AUDIO_DEVICE_IN_WIRED_HEADSET:
+ deviceName = AUDIO_CTL_HEADSET_MIC;
+ setMIC2Mode(true);
+ break;
+ default:
+ ALOGE("%s(), not supported device", __FUNCTION__);
+ ASSERT(0);
+ deviceName = AUDIO_CTL_BUILT_IN_MIC;
+ break;
+ }
+
+ if (mNumPhoneMicSupport >= 2) {
+ if (mMicInverse && new_device != AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ ALOGD("%s(), need mic inverse", __FUNCTION__);
+ inverse = AUDIO_CTL_MIC_INVERSE;
+ }
+ }
+
+ mStartInputDeviceSeqeunce = deviceName;
+ if (!specificMic.isEmpty()) {
+ mStartInputDeviceSeqeunce += String8("_") + specificMic;
+ }
+
+ if (!inverse.isEmpty()) {
+ mStartInputDeviceSeqeunce += String8("_") + inverse;
+ }
+
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(mStartInputDeviceSeqeunce.string());
+#if defined(MTK_AUDIO_KS_DEPRECATED)
+ setMIC1Mode(new_device == AUDIO_DEVICE_IN_WIRED_HEADSET);
+#endif
+#else
+ if (new_device == AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ setMIC1Mode(false);
+ setMIC2Mode(false);
+ setSingleDmicLoopbackType(mBuiltInMicSpecificType, mMicInverse, true);
+
+ if (mBuiltInMicSpecificType == BUILTIN_MIC_MIC1_ONLY) {
+ if (mMicInverse == true) {
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_MIC1_INVERSE);
+ } else {
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_MIC1);
+ }
+ } else if (mBuiltInMicSpecificType == BUILTIN_MIC_MIC2_ONLY) {
+ if (mMicInverse == true) {
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_MIC2_INVERSE);
+ } else {
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_MIC2);
+ }
+ } else if (mBuiltInMicSpecificType == BUILTIN_MIC_MIC3_ONLY) {
+ // ADC3 using DCC mode with 3rd mic input
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC3_TYPE_DCCMODE);
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_MIC3);
+ } else if (mBuiltInMicSpecificType == BUILTIN_MIC_MIC4_ONLY) {
+ // ADC3 using DCC mode with 4th mic input
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC3_TYPE_DCCMODE);
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_MIC4);
+ } else if (mBuiltInMicSpecificType == BUILTIN_MIC_MIC5_ONLY) {
+ // ADC3 using DCC mode with 5th mic input
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIOMIC3_TYPE_DCCMODE);
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_MIC5);
+ } else if (mBuiltInMicSpecificType == BUILTIN_MIC_DEFAULT) {
+ switch (mNumPhoneMicSupport) {
+ case 3:
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_BUILTIN_TRIPLE_MIC);
+ break;
+ case 2:
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_BUILTIN_DUAL_MIC);
+ break;
+ case 1:
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_BUILTIN_SINGLE_MIC);
+ break;
+ default:
+ break;
+ }
+
+ if (mMicInverse == true && mNumPhoneMicSupport > 1) {
+ ALOGD("%s(), need MicInverse", __FUNCTION__);
+ mDeviceConfigManager->ApplyDeviceSettingByName(AUDIO_MIC_INVERSE);
+ }
+ }
+ } else if (new_device == AUDIO_DEVICE_IN_BACK_MIC) {
+ if (mNumPhoneMicSupport >= 2) {
+ setMIC1Mode(false);
+ setMIC2Mode(false);
+
+ if (mMicInverse == true) {
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_BUILTIN_BACK_MIC_INVERSE);
+ } else {
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_BUILTIN_BACK_MIC);
+ }
+ } else {
+ ALOGW("%s(), mic < 2, not support", __FUNCTION__);
+ }
+ } else if (new_device == AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ setMIC1Mode(true);
+ setMIC2Mode(true);
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_HEADSET_MIC);
+
+ if (mNumHSPole == 5) {
+ retval = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_UL_LR_Swap"), "On");
+ }
+ ASSERT(retval == 0);
+ }
+#endif
+
+ mInputDevice |= new_device;
+ mStartInputDeviceCount++;
+
+
+ ALOGD("-%s(), mInputDevice = 0x%x, mStartInputDeviceCount = %d", __FUNCTION__, mInputDevice, mStartInputDeviceCount);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::stopInputDevice(const audio_devices_t stop_device) {
+ ALOGD("+%s(), mInputDevice = 0x%x, stop_device = 0x%x, mStartInputDeviceCount = %d, mMicInverse = %d, mNumPhoneMicSupport = %d",
+ __FUNCTION__, mInputDevice, stop_device, mStartInputDeviceCount, mMicInverse, mNumPhoneMicSupport);
+
+ AL_AUTOLOCK(mLockin);
+
+ bool needTurnoffSequence = (stop_device & ~AUDIO_DEVICE_BIT_IN) & (AUDIO_DEVICE_IN_BUILTIN_MIC | AUDIO_DEVICE_IN_BACK_MIC | AUDIO_DEVICE_IN_WIRED_HEADSET);
+
+ if (needTurnoffSequence == false) {
+ ALOGD("%s(), no need to config analog part", __FUNCTION__);
+ return NO_ERROR;
+ }
+
+ if (((mInputDevice & stop_device) & ~AUDIO_DEVICE_BIT_IN) == 0) {
+ ALOGW("%s(), input device not opened yet, do nothing", __FUNCTION__);
+ ASSERT(0);
+ return NO_ERROR;
+ }
+
+ if (mStartInputDeviceCount > 0) {
+ mStartInputDeviceCount--;
+ }
+
+ if (mStartInputDeviceCount < 0) {
+ ALOGE("%s(), mStartInputDeviceCount negative %d, reset to 0!", __FUNCTION__, mStartInputDeviceCount);
+ mStartInputDeviceCount = 0;
+ ASSERT(0);
+ }
+
+ if (mStartInputDeviceCount > 0) {
+ ALOGD("-%s(), mInputDevice = 0x%x, mStartInputDeviceCount = %d,return", __FUNCTION__, mInputDevice, mStartInputDeviceCount);
+ return NO_ERROR;
+ }
+
+ int retval = 0;
+#if defined(MTK_AUDIO_KS)
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(mStartInputDeviceSeqeunce.string());
+ mStartInputDeviceSeqeunce.clear();
+#else
+ if (stop_device == AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ setSingleDmicLoopbackType(mBuiltInMicSpecificType, mMicInverse, false);
+
+ if (mBuiltInMicSpecificType == BUILTIN_MIC_MIC1_ONLY) {
+ if (mMicInverse == true) {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_MIC1_INVERSE);
+ } else {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_MIC1);
+ }
+ } else if (mBuiltInMicSpecificType == BUILTIN_MIC_MIC2_ONLY) {
+ if (mMicInverse == true) {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_MIC2_INVERSE);
+ } else {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_MIC2);
+ }
+ } else if (mBuiltInMicSpecificType == BUILTIN_MIC_MIC3_ONLY) {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_MIC3);
+ } else if (mBuiltInMicSpecificType == BUILTIN_MIC_MIC4_ONLY) {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_MIC4);
+ } else if (mBuiltInMicSpecificType == BUILTIN_MIC_MIC5_ONLY) {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_MIC5);
+ } else if (mBuiltInMicSpecificType == BUILTIN_MIC_DEFAULT) {
+ setMIC1Mode(false);
+ setMIC2Mode(false);
+
+ switch (mNumPhoneMicSupport) {
+ case 3:
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_BUILTIN_TRIPLE_MIC);
+ break;
+ case 2:
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_BUILTIN_DUAL_MIC);
+ break;
+ case 1:
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_BUILTIN_SINGLE_MIC);
+ break;
+ default:
+ break;
+ }
+ }
+ } else if (stop_device == AUDIO_DEVICE_IN_BACK_MIC) {
+ if (mNumPhoneMicSupport >= 2) {
+ setMIC1Mode(false);
+ setMIC2Mode(false);
+ if (mMicInverse == true) {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_BUILTIN_BACK_MIC_INVERSE);
+ } else {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_BUILTIN_BACK_MIC);
+ }
+ } else {
+ ALOGW("%s(), mic < 2, not support", __FUNCTION__);
+ }
+ } else if (stop_device == AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ setMIC1Mode(true);
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_HEADSET_MIC);
+
+ if (mNumHSPole == 5) {
+ retval = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_UL_LR_Swap"), "Off");
+ }
+ ASSERT(retval == 0);
+ }
+#endif
+
+ mInputDevice &= ((~stop_device) | AUDIO_DEVICE_BIT_IN);
+ if (mInputDevice == AUDIO_DEVICE_BIT_IN) { mInputDevice = AUDIO_DEVICE_NONE; }
+
+ ALOGD_IF(mLogEnable, "-%s(), mInputDevice = 0x%x, mStartInputDeviceCount = %d", __FUNCTION__, mInputDevice, mStartInputDeviceCount);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::changeInputDevice(const audio_devices_t new_device) {
+ ALOGD("+%s(), mInputDevice: 0x%x => 0x%x", __FUNCTION__, mInputDevice, new_device);
+
+ stopInputDevice(getInputDevice());
+ startInputDevice(new_device);
+
+ ALOGD_IF(mLogEnable, "-%s(), mInputDevice: 0x%x", __FUNCTION__, mInputDevice);
+ return NO_ERROR;
+}
+
+
+
+status_t AudioALSAHardwareResourceManager::setHWGain2DigitalGain(const uint32_t gain) {
+ ALOGD("%s(), gain = 0x%x", __FUNCTION__, gain);
+
+ const uint32_t kMaxAudioHWGainValue = 0x80000;
+
+ if (gain > kMaxAudioHWGainValue) {
+ ALOGE("%s(), gain(0x%x) > kMaxAudioHWGainValue(0x%x)!! return!!", __FUNCTION__, gain, kMaxAudioHWGainValue);
+ return BAD_VALUE;
+ }
+
+ int retval = 0;
+#if defined(MTK_AUDIO_KS)
+ retval = mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "HW Gain 1"), 0, gain);
+#else
+ if (WCNChipController::GetInstance()->IsFMMergeInterfaceSupported() == true) {
+ retval = mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Audio Mrgrx Volume"), 0, gain);
+ } else {
+ retval = mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Audio FM I2S Volume"), 0, gain);
+ }
+#endif
+
+ if (retval != 0) {
+ ALOGE("%s(), retval = %d", __FUNCTION__, retval);
+ ASSERT(retval == 0);
+ }
+
+ return NO_ERROR;
+}
+
+
+
+status_t AudioALSAHardwareResourceManager::setInterruptRate(const audio_output_flags_t flag,
+ const uint32_t rate) {
+ if (rate <= 0 || rate >= 65535) {
+ ALOGE("%s, rate is not in range", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ int retval;
+ if (isIsolatedDeepBuffer(flag)) {
+ retval = mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "deep_buffer_irq_cnt"), 0, rate);
+ } else {
+ retval = mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Audio IRQ1 CNT"), 0, rate);
+ }
+
+ if (retval != 0) {
+ ALOGE("%s(), retval = %d", __FUNCTION__, retval);
+ ASSERT(retval == 0);
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::setInterruptRate2(const uint32_t rate) {
+ if (rate <= 0 || rate >= 65535) {
+ ALOGE("%s, rate is not in range", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ //int retval = mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Audio IRQ2 CNT"), 0, rate);
+ //ASSERT(retval == 0);
+
+ //return (retval == 0) ? NO_ERROR : UNKNOWN_ERROR;
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::setULInterruptRate(const uint32_t rate) {
+ if (rate <= 0 || rate >= 65535) {
+ ALOGE("%s, rate is not in range", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ int retval = mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Audio IRQ2 CNT"), 0, rate);
+
+ if (retval != 0) {
+ ALOGE("%s(), retval = %d", __FUNCTION__, retval);
+ //ASSERT(retval == 0);
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::openAddaOutput(const uint32_t sample_rate) {
+ ALOGD("+%s(), sample_rate = 0x%x", __FUNCTION__, sample_rate);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+ struct pcm_config mConfig;
+
+ // DL setting
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = 2;
+ mConfig.rate = sample_rate;
+ mConfig.period_size = 1024;
+ mConfig.period_count = 2;
+ mConfig.format = PCM_FORMAT_S16_LE;
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+
+#if defined(MTK_AUDIO_KS)
+ mConfig.stop_threshold = ~(0U);
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessADDADLI2SOut);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmHostlessADDADLI2SOut);
+#else
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmI2S0Dl1Playback);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmI2S0Dl1Playback);
+#endif
+
+ ASSERT(mPcmDL == NULL);
+ mPcmDL = pcm_open(cardIdx, pcmIdx, PCM_OUT, &mConfig);
+ ASSERT(mPcmDL != NULL);
+ ALOGV("%s(), mPcmDL = %p", __FUNCTION__, mPcmDL);
+
+ pcm_start(mPcmDL);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::closeAddaOutput() {
+ ALOGD("+%s()", __FUNCTION__);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+ pcm_stop(mPcmDL);
+ pcm_close(mPcmDL);
+ mPcmDL = NULL;
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::setSgenMode(const sgen_mode_t sgen_mode) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_SineGen_Switch"), SIDEGEN[sgen_mode])) {
+ ALOGE("Error: Audio_SineGen_Switch invalid value");
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::setSgenSampleRate(const sgen_mode_samplerate_t sample_rate) {
+ ALOGD("setSgenSampleRate = %d", sample_rate);
+ if (sample_rate < 0 || sample_rate >= 9) {
+ ALOGE("%s, sgen_rate is not in range", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_SineGen_SampleRate"), SIDEGEN_SAMEPLRATE[sample_rate])) {
+ ALOGE("Error: Audio_SineGen_SampleRate invalid value");
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::setSgenMute(int channel, bool mute) {
+ ALOGD("%s(), channel %d, mute %d", __FUNCTION__, channel, mute);
+
+ struct mixer_ctl *ctl = (channel == 0) ?
+ mixer_get_ctl_by_name(mMixer, "Audio_SineGen_Mute_Ch1") :
+ mixer_get_ctl_by_name(mMixer, "Audio_SineGen_Mute_Ch2");
+
+ if (mixer_ctl_set_enum_by_string(ctl, mute ? "On" : "Off")) {
+ ALOGE("Error: Audio_SineGen_Mute_Ch1/2 invalid value, ctl %p", ctl);
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::setSgenFreqDiv(int channel, int freqDiv) {
+ ALOGD("%s(), channel %d, freqDiv %d", __FUNCTION__, channel, freqDiv);
+
+ struct mixer_ctl *ctl = (channel == 0) ?
+ mixer_get_ctl_by_name(mMixer, "Audio_SineGen_Freq_Div_Ch1") :
+ mixer_get_ctl_by_name(mMixer, "Audio_SineGen_Freq_Div_Ch2");
+
+ if (mixer_ctl_set_value(ctl, 0, freqDiv)) {
+ ALOGE("Error: Audio_SineGen_Freq_Div_Ch1/2 invalid value, ctl %p", ctl);
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::EnableSideToneFilter(const bool enable) {
+#ifdef ENABLE_SW_SIDETONE
+ ALOGD("%s(), SW Sidetone Applied, skip setting HW Sidetone", __FUNCTION__);
+
+#else
+ ALOGV("EnableSideToneFilter enable = %d", enable);
+ if (enable) {
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_SIDETONE);
+ } else {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_SIDETONE);
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+bool AudioALSAHardwareResourceManager::GetExtDacPropertyEnable() {
+ return AudioALSADriverUtility::getInstance()->GetPropertyValue(PROPERTY_KEY_EXTDAC);
+}
+
+status_t AudioALSAHardwareResourceManager::SetExtDacGpioEnable(bool bEnable) {
+ int retval = 0;
+ // check for property first
+ if (GetExtDacPropertyEnable() == true) {
+ ALOGD("%s GetExtDacPropertyEnable bEnable = %d", __FUNCTION__, bEnable);
+ if (bEnable == true) {
+ retval = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_I2S1_Setting"), "On");
+ ASSERT(retval == 0);
+ } else {
+ retval = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_I2S1_Setting"), "Off");
+ ASSERT(retval == 0);
+ }
+ return NO_ERROR;
+ }
+
+ // if supprot for extdac
+#ifdef EXT_DAC_SUPPORT
+ if (bEnable == true) {
+ retval = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_I2S1_Setting"), "On");
+ ASSERT(retval == 0);
+ } else {
+ retval = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_I2S1_Setting"), "Off");
+ ASSERT(retval == 0);
+ }
+#endif
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::setMicType(void) {
+ char value[PROPERTY_VALUE_MAX];
+ int ret, bflag;
+
+ mPhoneMicMode = GetMicDeviceMode(0);
+ mHeadsetMicMode = GetMicDeviceMode(1);
+
+#ifdef UPDATE_PHONE_MIC_MODE_BY_PCB
+ if (mPhoneMicMode == AUDIO_MIC_MODE_ACC || mPhoneMicMode == AUDIO_MIC_MODE_DCC) {
+ mPhoneMicMode = updatePhoneMicMode();
+ mHeadsetMicMode = mPhoneMicMode;
+ }
+#endif
+
+#if !defined(MTK_AUDIO_KS)
+ // init using phone mic mode
+ setMIC1Mode(false);
+ setMIC2Mode(false);
+
+ if (mNumPhoneMicSupport >= 3) {
+ setMIC3Mode(false);
+ }
+
+#endif
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::setSPKCurrentSensor(bool bSwitch) {
+ struct mixer_ctl *ctl;
+ struct mixer_ctl *ctl2;
+
+ enum mixer_ctl_type type;
+ unsigned int num_values;
+ static AUDIO_SPEAKER_MODE eSpeakerMode;
+ ALOGD("%s(), bSwitch = %d", __FUNCTION__, bSwitch);
+ ctl = mixer_get_ctl_by_name(mMixer, "Audio_Speaker_CurrentSensing");
+
+ if (ctl == NULL) {
+ ALOGE("Kernel unsupport Audio_Speaker_CurrentSensing");
+ return UNKNOWN_ERROR;
+ }
+
+ if (mixer_ctl_set_enum_by_string(ctl, bSwitch ? "On" : "Off")) {
+ ALOGE("Error: Audio_Speaker_CurrentSensing invalid value : On");
+ }
+
+
+ ctl2 = mixer_get_ctl_by_name(mMixer, "Audio_Speaker_class_Switch");
+
+ if (true == bSwitch) {
+ //Save Speaker Mode
+ ALOGD("Enable+ value [%d] [%s]", mixer_ctl_get_value(ctl2, 0), mixer_ctl_get_enum_string(ctl2, mixer_ctl_get_value(ctl2, 0)));
+
+ if (strcmp(mixer_ctl_get_enum_string(ctl2, mixer_ctl_get_value(ctl2, 0)), "CLASSAB")) {
+ eSpeakerMode = AUDIO_SPEAKER_MODE_D;
+ } else {
+ eSpeakerMode = AUDIO_SPEAKER_MODE_AB;
+ }
+
+ ALOGD("Current Mode [%d]", eSpeakerMode);
+
+ if (mixer_ctl_set_enum_by_string(ctl2, "CLASSAB")) {
+ ALOGE("Error: Audio_Speaker_CurrentPeakDetector invalid value");
+ }
+
+ ALOGD("Enable- [%s]", mixer_ctl_get_enum_string(ctl2, mixer_ctl_get_value(ctl2, 0)));
+
+ } else {
+ //restore Speaker Mode
+
+ if (mixer_ctl_set_enum_by_string(ctl2, eSpeakerMode ? "CLASSAB" : "CALSSD")) {
+ ALOGE("Error: Audio_Speaker_CurrentPeakDetector invalid value");
+ }
+
+ ALOGD("RollBack to [%s]", mixer_ctl_get_enum_string(ctl2, 0));
+ }
+
+
+ ALOGD("Audio_Speaker_CurrentSensing Get value [%d] [%s]", mixer_ctl_get_value(ctl, 0), mixer_ctl_get_enum_string(ctl, mixer_ctl_get_value(ctl, 0)));
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::setSPKCurrentSensorPeakDetectorReset(bool bSwitch) {
+ struct mixer_ctl *ctl;
+ enum mixer_ctl_type type;
+ unsigned int num_values;
+ ALOGD("%s(), bSwitch = %d", __FUNCTION__, bSwitch);
+ ctl = mixer_get_ctl_by_name(mMixer, "Audio_Speaker_CurrentPeakDetector");
+
+ if (ctl == NULL) {
+ ALOGE("Kernel unsupport Audio_Speaker_CurrentPeakDetector");
+ return UNKNOWN_ERROR;
+ }
+
+ type = mixer_ctl_get_type(ctl);
+ num_values = mixer_ctl_get_num_values(ctl);
+ if (mixer_ctl_set_enum_by_string(ctl, bSwitch ? "On" : "Off")) {
+ ALOGE("Error: Audio_Speaker_CurrentPeakDetector invalid value");
+ }
+
+ return NO_ERROR;
+}
+
+uint32_t AudioALSAHardwareResourceManager::updatePhoneMicMode() {
+ struct mixer_ctl *ctl;
+ uint32_t mic_mode = mPhoneMicMode;
+ unsigned int ctl_value = 0;
+ ALOGD("%s()", __FUNCTION__);
+ ctl = mixer_get_ctl_by_name(mMixer, "Audio_MIC_Mode");
+
+ if (ctl == NULL) {
+ ALOGD("Kernel unsupport Audio_MIC_Mode");
+ return mic_mode;
+ }
+
+ ctl_value = mixer_ctl_get_value(ctl, 0);
+
+ ALOGD("%s(), new mic mode = %d, old mic_mode = %d", __FUNCTION__, ctl_value, mic_mode);
+
+ return ctl_value;
+}
+
+bool AudioALSAHardwareResourceManager::setSpeakerStatusChangeCb(SpeakerStatusChangeCb cb) {
+ mSpeakerStatusChangeCb = cb;
+ return true;
+}
+
+bool AudioALSAHardwareResourceManager::notifyOutputDeviceStatusChange(const audio_devices_t device, const DeviceStatus status) {
+ bool ret = true;
+ if (device & AUDIO_DEVICE_OUT_SPEAKER) {
+ if (mSpeakerStatusChangeCb != NULL) {
+ ret = mSpeakerStatusChangeCb(status);
+ }
+ }
+ return ret;
+}
+
+audio_devices_t AudioALSAHardwareResourceManager::getOutputDevice() {
+ return mOutputDevices;
+}
+
+audio_devices_t AudioALSAHardwareResourceManager::getInputDevice() {
+ return mInputDevice;
+}
+
+
+status_t AudioALSAHardwareResourceManager::setMicInverse(bool bMicInverse) {
+ ALOGD_IF(mLogEnable, "%s(), bMicInverse = %d", __FUNCTION__, bMicInverse);
+ if (getNumPhoneMicSupport() >= 2) {
+#if defined(MTK_AUDIO_MIC_INVERSE) || defined(DEN_PHONE_MIC_INVERSE)
+ mMicInverse = !bMicInverse;
+#else
+ mMicInverse = bMicInverse;
+#endif
+ } else {
+ ALOGD_IF(mLogEnable, "%s(), not support", __FUNCTION__);
+ }
+ return NO_ERROR;
+}
+
+void AudioALSAHardwareResourceManager::EnableAudBufClk(bool bEanble) {
+ ALOGV("%s(), bEanble = %d, mStartOutputDevicesCount %d", __FUNCTION__, bEanble, mStartOutputDevicesCount);
+
+#if !defined(MTK_AUDIO_KS)
+ if (mStartOutputDevicesCount > 0) {
+ return;
+ }
+
+ enum mixer_ctl_type type;
+ struct mixer_ctl *ctl;
+ int retval = 0;
+ ctl = mixer_get_ctl_by_name(mMixer, "AUD_CLK_BUF_Switch");
+
+ if (ctl == NULL) {
+ ALOGE("EnableAudBufClk not support");
+ return ;
+ }
+
+ if (bEanble == true) {
+ retval = mixer_ctl_set_enum_by_string(ctl, "On");
+ ASSERT(retval == 0);
+ } else {
+ retval = mixer_ctl_set_enum_by_string(ctl, "Off");
+ ASSERT(retval == 0);
+ }
+#endif
+}
+
+
+bool AudioALSAHardwareResourceManager::getMicInverse(void) {
+#if defined(MTK_AUDIO_MIC_INVERSE) || defined(DEN_PHONE_MIC_INVERSE)
+ ALOGD("%s(), mMicInverse = %d", __FUNCTION__, !mMicInverse);
+ return !mMicInverse;
+#else
+ ALOGD("%s(), mMicInverse = %d", __FUNCTION__, mMicInverse);
+ return mMicInverse;
+#endif
+}
+
+
+void AudioALSAHardwareResourceManager::setAudioDebug(const bool enable) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Debug_Setting"), enable ? "On" : "Off")) {
+ ALOGE("Error: Audio_Debug_Setting invalid value");
+ }
+#if defined(MTK_AUDIO_KS)
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Codec_Debug_Setting"), enable ? "On" : "Off")) {
+ ALOGE("Error: Audio_Codec_Debug_Setting invalid value");
+ }
+#endif
+}
+
+int AudioALSAHardwareResourceManager::setNonSmartPAType() {
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ return -ENOENT;
+ }
+ AppHandle *appHandle = appOps->appHandleGetInstance();
+ const char *spkType = appOps->appHandleGetFeatureOptionValue(appHandle, "MTK_AUDIO_SPEAKER_PATH");
+
+ if (strstr(spkType, "int_spk_amp")) {
+ nonSmartPAType = AUDIO_SPK_INTAMP;
+ } else if (strstr(spkType, "int_lo_buf")) {
+ nonSmartPAType = AUDIO_SPK_EXTAMP_LO;
+ } else if (strstr(spkType, "int_hp_buf")) {
+ nonSmartPAType = AUDIO_SPK_EXTAMP_HP;
+ } else if (strstr(spkType, "2_in_1_spk")) {
+ nonSmartPAType = AUDIO_SPK_2_IN_1;
+ } else if (strstr(spkType, "3_in_1_spk")) {
+ nonSmartPAType = AUDIO_SPK_3_IN_1;
+ } else {
+ ALOGW("%s(), invalid spkType:%s", __FUNCTION__, spkType);
+ nonSmartPAType = AUDIO_SPK_INVALID;
+ }
+ ALOGD("%s(), nonSmartPAType: %d", __FUNCTION__, nonSmartPAType);
+
+ return 0;
+}
+
+int AudioALSAHardwareResourceManager::getNonSmartPAType() {
+ if (mSmartPaController->isSmartPADynamicDetectSupport()) {
+ return nonSmartPAType;
+ } else {
+#if defined(USING_EXTAMP_HP)
+ return AUDIO_SPK_EXTAMP_HP;
+#elif defined(USING_EXTAMP_LO)
+ return AUDIO_SPK_EXTAMP_LO;
+#else
+ return AUDIO_SPK_INTAMP;
+#endif
+ }
+}
+
+status_t AudioALSAHardwareResourceManager::OpenReceiverPath(const uint32_t SampleRate __unused) {
+ //AudioALSACodecDeviceOutReceiverPMIC::getInstance()->open();
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_2IN1_SPEAKER)) {
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_2IN1_SPEAKER);
+ } else {
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_RECEIVER);
+ }
+#ifdef HAVING_RCV_SPK_SWITCH
+ AudioALSACodecDeviceOutReceiverSpeakerSwitch::getInstance()->open();
+#endif
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::CloseReceiverPath() {
+ //AudioALSACodecDeviceOutReceiverPMIC::getInstance()->close();
+
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_2IN1_SPEAKER)) {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_2IN1_SPEAKER);
+ } else {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_RECEIVER);
+ }
+#ifdef HAVING_RCV_SPK_SWITCH
+ AudioALSACodecDeviceOutReceiverSpeakerSwitch::getInstance()->close();
+#endif
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::OpenHeadphonePath(const uint32_t SampleRate __unused) {
+#if defined(MTK_DPD_SUPPORT)
+ setDPDModule(true);
+#endif
+ SetExtDacGpioEnable(true);
+#if defined(MTK_HIFIAUDIO_SUPPORT)
+ if (mHiFiState) {
+ ALOGD_IF(mLogEnable, "%s(), use ext hifi dac to play", __FUNCTION__);
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_HIFI_DAC);
+ mHiFiDACStatusCount++;
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_HEADPHONE);
+ } else {
+ ALOGD_IF(mLogEnable, "%s(), use pmic dac to play", __FUNCTION__);
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_HEADPHONE);
+ }
+#else
+ ALOGD_IF(mLogEnable, "%s(), use pmic dac to play", __FUNCTION__);
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_HEADPHONE);
+#endif
+
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+ AudioALSAHyBridNLEManager::getInstance()->setEnableNLE(true);
+#endif
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::CloseHeadphonePath() {
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+ AudioALSAHyBridNLEManager::getInstance()->setEnableNLE(false);
+#endif
+#if defined(MTK_HIFIAUDIO_SUPPORT)
+ if (mHiFiDACStatusCount > 0) {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_HIFI_DAC);
+ mHiFiDACStatusCount--;
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_HEADPHONE);
+ } else {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_HEADPHONE);
+ }
+#else
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_HEADPHONE);
+#endif
+#if defined(MTK_DPD_SUPPORT)
+ setDPDModule(false);
+#endif
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHardwareResourceManager::OpenSpeakerPath(const uint32_t SampleRate) {
+ SetExtDacGpioEnable(true);
+
+ if (mSmartPaController->isSmartPAUsed()) {
+ mSmartPaController->speakerOn(SampleRate, mOutputDevices);
+ } else {
+ int spkType = getNonSmartPAType();
+ switch (spkType) {
+ case AUDIO_SPK_INTAMP:
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_SPEAKER);
+ break;
+ case AUDIO_SPK_EXTAMP_LO:
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_SPEAKER);
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_EXT_SPEAKER);
+ break;
+ case AUDIO_SPK_EXTAMP_HP:
+#if defined(USING_EXTAMP_HP_FLAG)
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Ext_Speaker_Use"), "On")) {
+ ALOGE("%s(), Ext_Speaker_Used invalid value\n", __FUNCTION__);
+ }
+#endif
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_HEADPHONE);
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_EXT_SPEAKER);
+ break;
+ default:
+ ALOGE("%s(), invalid spk type, use EXTAMP_LO as default.\n", __FUNCTION__);
+ ASSERT(0);
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_SPEAKER);
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_EXT_SPEAKER);
+ break;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::CloseSpeakerPath() {
+ if (mSmartPaController->isSmartPAUsed()) {
+ mSmartPaController->speakerOff();
+ } else {
+ int spkType = getNonSmartPAType();
+ switch (spkType) {
+ case AUDIO_SPK_INTAMP:
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_SPEAKER);
+ break;
+ case AUDIO_SPK_EXTAMP_LO:
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_EXT_SPEAKER);
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_SPEAKER);
+ break;
+ case AUDIO_SPK_EXTAMP_HP:
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_EXT_SPEAKER);
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_HEADPHONE);
+#if defined(USING_EXTAMP_HP_FLAG)
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Ext_Speaker_Use"), "Off")) {
+ ALOGE("Error: Ext_Speaker_Used invalid value");
+ }
+#endif
+ break;
+ default:
+ ALOGE("%s(), invalid spk type, use EXTAMP_LO as default.\n", __FUNCTION__);
+ ASSERT(0);
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_EXT_SPEAKER);
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_SPEAKER);
+ break;
+ }
+ }
+
+ SetExtDacGpioEnable(false);
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::OpenHeadphoneSpeakerPath(const uint32_t SampleRate) {
+ SetExtDacGpioEnable(true);
+
+ if (mSmartPaController->isSmartPAUsed()) {
+ mSmartPaController->speakerOn(SampleRate, mOutputDevices);
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_HEADPHONE);
+ } else {
+ int spkType = getNonSmartPAType();
+ switch (spkType) {
+ case AUDIO_SPK_INTAMP:
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_EARPHONE_SPEAKER);
+ break;
+ case AUDIO_SPK_EXTAMP_LO:
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_EARPHONE_SPEAKER);
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_EXT_SPEAKER);
+ break;
+ case AUDIO_SPK_EXTAMP_HP:
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_HEADPHONE);
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_EXT_SPEAKER);
+ break;
+ default:
+ ALOGE("%s(), invalid spk type, use EXTAMP_LO as default.\n", __FUNCTION__);
+ ASSERT(0);
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_EARPHONE_SPEAKER);
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_EXT_SPEAKER);
+ break;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::CloseHeadphoneSpeakerPath() {
+ if (mSmartPaController->isSmartPAUsed()) {
+ mSmartPaController->speakerOff();
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_HEADPHONE);
+ } else {
+ int spkType = getNonSmartPAType();
+ switch (spkType) {
+ case AUDIO_SPK_INTAMP:
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_EARPHONE_SPEAKER);
+ break;
+ case AUDIO_SPK_EXTAMP_LO:
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_EXT_SPEAKER);
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_EARPHONE_SPEAKER);
+ break;
+ case AUDIO_SPK_EXTAMP_HP:
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_EXT_SPEAKER);
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_HEADPHONE);
+ break;
+ default:
+ ALOGE("%s(), invalid spk type, use EXTAMP_LO as default.\n", __FUNCTION__);
+ ASSERT(0);
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_EXT_SPEAKER);
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_EARPHONE_SPEAKER);
+ break;
+ }
+ }
+
+ SetExtDacGpioEnable(false);
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::OpenBuiltInMicPath() {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::CloseBuiltInMicPath() {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::OpenBackMicPath() {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::CloseBackMicPath() {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::OpenWiredHeadsetMicPath() {
+ return NO_ERROR;
+}
+
+status_t AudioALSAHardwareResourceManager::CloseWiredHeadsetMicPath() {
+ return NO_ERROR;
+}
+
+void AudioALSAHardwareResourceManager::HpImpeDanceDetect(void) {
+ ALOGD("+HpImpeDanceDetect");
+#if defined(MTK_AUDIO_GAIN_TABLE) == defined(MTK_NEW_VOL_CONTROL)
+
+ AL_AUTOLOCK(mLock);
+
+ /* notify codec hp just plugged in, call get_accdet_auxadc() during accdet on */
+ struct mixer_ctl *ctl = mixer_get_ctl_by_name(mMixer, "Headphone Plugged In");
+ if (ctl) {
+ int ret = 0;
+ ret = mixer_ctl_set_enum_by_string(ctl, "On");
+ if (ret) {
+ ALOGE("%s(), ret %d, set Headphone Plugged In failed", __FUNCTION__, ret);
+ }
+ } else {
+ ALOGW("%s(), Headphone Plugged In not support", __FUNCTION__);
+ }
+
+ if (mStartOutputDevicesCount != 0) {
+ ALOGD("-HpImpeDanceDetect : output device Busy");
+ mHeadchange = true;
+ return;
+ }
+
+#ifdef MTK_NEW_VOL_CONTROL
+ AudioMTKGainController::getInstance()->GetHeadPhoneImpedance();
+#else
+ AudioALSAVolumeController::getInstance()->GetHeadPhoneImpedance();
+#endif
+
+ mHeadchange = false;
+#endif
+ ALOGD("-HpImpeDanceDetect");
+}
+
+void AudioALSAHardwareResourceManager::setDPDModule(bool enable) {
+ ALOGD("%s() enable = %d", __FUNCTION__, enable);
+
+ enum mixer_ctl_type type;
+ struct mixer_ctl *ctl;
+ int retval = 0;
+
+ ctl = mixer_get_ctl_by_name(mMixer, "Audio_DPD_Switch");
+
+ if (ctl == NULL) {
+ ALOGE("Audio_DPD_Switch not support");
+ return;
+ }
+
+ if (enable) {
+ retval = mixer_ctl_set_enum_by_string(ctl, "On");
+ ASSERT(retval == 0);
+ } else {
+ retval = mixer_ctl_set_enum_by_string(ctl, "Off");
+ ASSERT(retval == 0);
+ }
+ return;
+}
+
+void AudioALSAHardwareResourceManager::setHeadphoneLowPowerMode(bool enable) {
+ ALOGD("%s() enable = %d", __FUNCTION__, enable);
+
+ enum mixer_ctl_type type;
+ struct mixer_ctl *ctl;
+ int retval = 0;
+
+ ctl = mixer_get_ctl_by_name(mMixer, "Audio_Power_Mode");
+
+ if (ctl == NULL) {
+ ALOGE("Audio_Power_Mode not support");
+ return;
+ }
+
+ if (enable) {
+ retval = mixer_ctl_set_enum_by_string(ctl, "Low_Power");
+ ASSERT(retval == 0);
+ } else {
+ retval = mixer_ctl_set_enum_by_string(ctl, "Hifi");
+ ASSERT(retval == 0);
+ }
+ return;
+}
+
+void AudioALSAHardwareResourceManager::setCodecSampleRate(const uint32_t sample_rate) {
+ ALOGD("+%s(), sample_rate = %d", __FUNCTION__, sample_rate);
+
+ int retval = mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Codec_ADC_SampleRate"), 0, sample_rate);
+ if (retval != 0) {
+ ALOGE("%s(), Set mixer Codec_ADC_SampleRate error(), ret = %d!!!", __FUNCTION__, retval);
+ }
+
+ retval = mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Codec_DAC_SampleRate"), 0, sample_rate);
+ if (retval != 0) {
+ ALOGE("%s(), Set mixer Codec_DAC_SampleRate error(), ret = %d!!!", __FUNCTION__, retval);
+ }
+
+ retval = mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Codec_ADC2_SampleRate"), 0, sample_rate);
+ if (retval != 0) {
+ ALOGE("%s(), Set mixer Codec_ADC2_SampleRate error(), ret = %d!!!", __FUNCTION__, retval);
+ }
+
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+void AudioALSAHardwareResourceManager::resetA2dpDeviceLatency(void) {
+ mA2dpDeviceLatency = A2DP_DEFAULT_LANTENCY;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSALoopbackController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSALoopbackController.cpp
new file mode 100644
index 0000000..f02b64d
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSALoopbackController.cpp
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSALoopbackController.h"
+#include "AudioBTCVSDControl.h"
+#include "AudioALSADriverUtility.h"
+#include "AudioALSADeviceParser.h"
+#include "AudioALSAStreamManager.h"
+#include "AudioALSAHardwareResourceManager.h"
+#include "WCNChipController.h"
+#include "AudioALSAPlaybackHandlerBTCVSD.h"
+#include "AudioALSAStreamOut.h"
+
+#if defined(MTK_AUDIO_KS)
+#include "AudioALSADeviceConfigManager.h"
+#include "AudioSmartPaController.h"
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSALoopbackController"
+
+static char const *const kBTCVSDDeviceName = "/dev/ebc";
+#define AUD_DRV_IOC_MAGIC 'C'
+#define ALLOCATE_FREE_BTCVSD_BUF _IOWR(AUD_DRV_IOC_MAGIC, 0xE0, unsigned int)
+#define SET_BTCVSD_STATE _IOWR(AUD_DRV_IOC_MAGIC, 0xE1, unsigned int)
+#define GET_BTCVSD_STATE _IOWR(AUD_DRV_IOC_MAGIC, 0xE2, unsigned int)
+
+namespace android {
+//static AudioMTKStreamOutInterface *streamOutput;
+AudioMTKStreamOutInterface *streamOutput = NULL;
+static struct mixer *mMixerForBtLoopback;
+
+AudioALSALoopbackController *AudioALSALoopbackController::mAudioALSALoopbackController = NULL;
+AudioALSALoopbackController *AudioALSALoopbackController::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSALoopbackController == NULL) {
+ mAudioALSALoopbackController = new AudioALSALoopbackController();
+ }
+ ASSERT(mAudioALSALoopbackController != NULL);
+ return mAudioALSALoopbackController;
+}
+
+
+AudioALSALoopbackController::AudioALSALoopbackController() :
+ mHardwareResourceManager(AudioALSAHardwareResourceManager::getInstance()),
+ mPcmDL(NULL),
+ mPcmUL(NULL),
+ mMixer(AudioALSADriverUtility::getInstance()->getMixer()),
+ mFd2(0),
+ mBtLoopbackWithCodec(false),
+ mBtLoopbackWithoutCodec(false),
+ mUseBtCodec(false) {
+ mMixerForBtLoopback = AudioALSADriverUtility::getInstance()->getMixer();
+
+ memset((void *)&mConfig, 0, sizeof(mConfig));
+}
+
+
+AudioALSALoopbackController::~AudioALSALoopbackController() {
+
+}
+
+
+status_t AudioALSALoopbackController::open(const audio_devices_t output_devices, const audio_devices_t input_device) {
+ ALOGD("+%s(), output_devices = 0x%x, input_device = 0x%x", __FUNCTION__, output_devices, input_device);
+ AL_AUTOLOCK(mLock);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ // DL loopback setting
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = 2;
+ mConfig.rate = 48000;
+ mConfig.period_size = 1024;
+ mConfig.period_count = 2;
+ mConfig.format = PCM_FORMAT_S16_LE;
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+ ALOGD("+%s(), mConfig.rate=%d", __FUNCTION__, mConfig.rate);
+
+#if defined(MTK_AUDIO_KS)
+ mConfig.stop_threshold = ~(0U);
+ if ((output_devices & AUDIO_DEVICE_OUT_SPEAKER) &&
+ AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(AUDIO_CTL_ADDA_UL_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+
+ if (popcount(output_devices) > 1) {
+ mApTurnOnSequence2 = AUDIO_CTL_ADDA_UL_TO_ADDA_DL;
+ }
+ } else {
+ mApTurnOnSequence = AUDIO_CTL_ADDA_UL_TO_ADDA_DL;
+ }
+
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence2);
+ }
+
+ int cardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmHostlessLpbk);
+ int pcmInIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessLpbk);
+ int pcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessLpbk);
+
+ mHardwareResourceManager->startInputDevice(input_device);
+#else
+ int pcmInIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmUlDlLoopback);
+ int pcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmUlDlLoopback);
+ int cardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmUlDlLoopback);
+#endif
+
+ ASSERT(mPcmUL == NULL && mPcmDL == NULL);
+ mPcmUL = pcm_open(cardIndex, pcmInIdx, PCM_IN, &mConfig);
+ mPcmDL = pcm_open(cardIndex, pcmOutIdx, PCM_OUT, &mConfig);
+ ASSERT(mPcmUL != NULL && mPcmDL != NULL);
+ ALOGV("%s(), mPcmUL = %p, mPcmDL = %p", __FUNCTION__, mPcmUL, mPcmDL);
+
+ if (input_device == AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ if (mHardwareResourceManager->getNumOfHeadsetPole() == 5) {
+ setLoopbackUseLCh(false);
+ } else {
+ setLoopbackUseLCh(true);
+ }
+ }
+
+ pcm_start(mPcmUL);
+ pcm_start(mPcmDL);
+
+#if !defined(MTK_AUDIO_KS)
+ mHardwareResourceManager->startInputDevice(input_device);
+#endif
+ mHardwareResourceManager->startOutputDevice(output_devices, mConfig.rate);
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSALoopbackController::close() {
+ ALOGD("+%s()", __FUNCTION__);
+ AL_AUTOLOCK(mLock);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ mHardwareResourceManager->stopOutputDevice();
+
+ pcm_stop(mPcmDL);
+ pcm_stop(mPcmUL);
+ pcm_close(mPcmDL);
+ pcm_close(mPcmUL);
+
+ mPcmDL = NULL;
+ mPcmUL = NULL;
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence2);
+ mApTurnOnSequence2.clear();
+ }
+#endif
+
+ if (mHardwareResourceManager->getInputDevice() == AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ setLoopbackUseLCh(false);
+ }
+
+ mHardwareResourceManager->stopInputDevice(mHardwareResourceManager->getInputDevice());
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSALoopbackController::SetApBTCodec(bool enable_codec) {
+ ALOGD("+%s(), enable_codec = %d", __FUNCTION__, enable_codec);
+ mUseBtCodec = enable_codec;
+ return NO_ERROR;
+}
+
+bool AudioALSALoopbackController::IsAPBTLoopbackWithCodec(void) {
+ //ALOGD("+%s(), mBtLoopbackWithCodec = %d", __FUNCTION__, mBtLoopbackWithCodec);
+ return mBtLoopbackWithCodec;
+}
+
+status_t AudioALSALoopbackController::OpenAudioLoopbackControlFlow(const audio_devices_t input_device,
+ const audio_devices_t output_device) {
+ // check BT device
+ const bool bt_device_on = audio_is_bluetooth_sco_device(output_device);
+
+ ALOGD("+%s(), input_device = 0x%x, output_device = 0x%x, bt_device_on = %d, mUseBtCodec = %d,"
+ "mBtLoopbackWithoutCodec: %d, mBtLoopbackWithCodec: %d", __FUNCTION__,
+ input_device, output_device, bt_device_on, mUseBtCodec, mBtLoopbackWithoutCodec, mBtLoopbackWithCodec);
+ if (bt_device_on == true) {
+ // DAIBT
+ if (WCNChipController::GetInstance()->BTUseCVSDRemoval() == true) {
+ if (!mUseBtCodec) {
+ mBtLoopbackWithoutCodec = 1;
+ mFd2 = 0;
+#ifndef MTK_SUPPORT_BTCVSD_ALSA
+ mFd2 = ::open(kBTCVSDDeviceName, O_RDWR);
+ ALOGD("+%s(), CVSD AP loopback without codec, mFd2: %d, AP errno: %d", __FUNCTION__, mFd2, errno);
+ ::ioctl(mFd2, ALLOCATE_FREE_BTCVSD_BUF, 0); //allocate TX working buffers in kernel
+ ::ioctl(mFd2, ALLOCATE_FREE_BTCVSD_BUF, 2); //allocate TX working buffers in kernel
+ ::ioctl(mFd2, SET_BTCVSD_STATE, BT_SCO_TXSTATE_DIRECT_LOOPBACK); //set state to kernel
+#else
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixerForBtLoopback, "BT_DIRECT_LOOPBACK"), "On")) {
+ ALOGE("Error: BT_DIRECT_LOOPBACK invalid value");
+ } else {
+ ALOGD("+%s(), CVSD AP loopback without codec, BT_DIRECT_LOOPBACK==On", __FUNCTION__);
+ }
+#endif
+ } else {
+ int format = AUDIO_FORMAT_PCM_16_BIT;
+ uint32_t channels = AUDIO_CHANNEL_OUT_MONO;
+ uint32_t sampleRate = 8000;
+ status_t status = NO_ERROR;
+ mBtLoopbackWithCodec = 1;
+ streamOutput = AudioALSAStreamManager::getInstance()->openOutputStream(output_device, &format,
+ &channels, &sampleRate,
+ &status);
+ ALOGD("+%s(), CVSD AP loopback with codec, streamOutput: %p", __FUNCTION__, streamOutput);
+ mBTCVSDLoopbackThread = new AudioMTKLoopbackThread();
+ if (mBTCVSDLoopbackThread.get()) {
+ mBTCVSDLoopbackThread->run("mBTCVSDLoopbackThread");
+ }
+ }
+ }
+ }
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSALoopbackController::CloseAudioLoopbackControlFlow(void) {
+ AL_AUTOLOCK(mLock);
+ ALOGD("+%s()", __FUNCTION__);
+
+ //const bool bt_device_on = audio_is_bluetooth_sco_device(output_device);
+ bool bt_device_on = true;
+
+ ALOGD("%s(), bt_device_on = %d, mBtLoopbackWithoutCodec: %d, mBtLoopbackWithCodec: %d",
+ __FUNCTION__, bt_device_on, mBtLoopbackWithoutCodec, mBtLoopbackWithCodec);
+
+ if (bt_device_on) {
+ if (WCNChipController::GetInstance()->BTUseCVSDRemoval() == true) {
+ if (mBtLoopbackWithoutCodec) {
+#ifndef MTK_SUPPORT_BTCVSD_ALSA
+ ::ioctl(mFd2, ALLOCATE_FREE_BTCVSD_BUF, 1); //allocate TX working buffers in kernel
+ ::ioctl(mFd2, ALLOCATE_FREE_BTCVSD_BUF, 3); //allocate TX working buffers in kernel
+ ::ioctl(mFd2, SET_BTCVSD_STATE, BT_SCO_TXSTATE_IDLE); //set state to kernel
+#else
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixerForBtLoopback, "BT_DIRECT_LOOPBACK"), "Off")) {
+ ALOGE("Error: BT_DIRECT_LOOPBACK invalid value");
+ } else {
+ ALOGD("%s(), CVSD AP loopback without codec, BT_DIRECT_LOOPBACK==Off", __FUNCTION__);
+ }
+#endif
+ mBtLoopbackWithoutCodec = 0;
+ } else if (mBtLoopbackWithCodec) {
+ ((AudioALSAStreamOut *)streamOutput)->setSuspend(true);
+ streamOutput->standbyStreamOut();
+ if (mBTCVSDLoopbackThread.get()) {
+ int ret = 0;
+ ret = mBTCVSDLoopbackThread->requestExitAndWait();
+ if (ret == WOULD_BLOCK) {
+ mBTCVSDLoopbackThread->requestExit();
+ }
+ mBTCVSDLoopbackThread.clear();
+ }
+ AudioALSAStreamManager::getInstance()->closeOutputStream(streamOutput);
+ mBtLoopbackWithCodec = 0;
+ }
+ }
+ }
+
+ ALOGD("-%s()", __FUNCTION__);
+
+ return NO_ERROR;
+}
+
+
+void AudioALSALoopbackController::setLoopbackUseLCh(bool enable) {
+ enum mixer_ctl_type type;
+ struct mixer_ctl *ctl;
+ int retval = 0;
+
+ ctl = mixer_get_ctl_by_name(mMixer, "LPBK_IN_USE_LCH");
+
+ if (ctl == NULL) {
+ ALOGE("LPBK_IN_USE_LCH not support");
+ return;
+ }
+
+ if (enable == true) {
+ retval = mixer_ctl_set_enum_by_string(ctl, "On");
+ ASSERT(retval == 0);
+ } else {
+ retval = mixer_ctl_set_enum_by_string(ctl, "Off");
+ ASSERT(retval == 0);
+ }
+}
+
+
+#if 1 //0902
+
+extern void CVSDLoopbackResetBuffer();
+extern void CVSDLoopbackReadDataDone(uint32_t len);
+extern void CVSDLoopbackGetReadBuffer(uint8_t **buffer, uint32_t *buf_len);
+extern int32_t CVSDLoopbackGetDataCount();
+
+AudioALSALoopbackController::AudioMTKLoopbackThread::AudioMTKLoopbackThread() {
+ ALOGD("BT_SW_CVSD AP loopback AudioMTKLoopbackThread constructor");
+}
+
+AudioALSALoopbackController::AudioMTKLoopbackThread::~AudioMTKLoopbackThread() {
+ ALOGD("BT_SW_CVSD AP loopback ~AudioMTKLoopbackThread");
+}
+
+void AudioALSALoopbackController::AudioMTKLoopbackThread::onFirstRef() {
+ ALOGD("BT_SW_CVSD AP loopback AudioMTKLoopbackThread::onFirstRef");
+ run(mName, ANDROID_PRIORITY_URGENT_AUDIO);
+}
+
+status_t AudioALSALoopbackController::AudioMTKLoopbackThread::readyToRun() {
+ ALOGD("BT_SW_CVSD AP loopback AudioMTKLoopbackThread::readyToRun()");
+ return NO_ERROR;
+}
+
+bool AudioALSALoopbackController::AudioMTKLoopbackThread::threadLoop() {
+ uint8_t *pReadBuffer;
+ uint32_t uReadByte, uWriteDataToBT;
+ CVSDLoopbackResetBuffer();
+ while (!(exitPending() == true)) {
+ ALOGD("BT_SW_CVSD AP loopback threadLoop(+)");
+ uWriteDataToBT = 0;
+ CVSDLoopbackGetReadBuffer(&pReadBuffer, &uReadByte);
+ uReadByte &= 0xFFFFFFFE;
+
+ if (uReadByte > 480) {
+ uReadByte = 480;
+ }
+
+ if (uReadByte) {
+ uWriteDataToBT = streamOutput->write(pReadBuffer, uReadByte);
+ CVSDLoopbackReadDataDone(uWriteDataToBT);
+ } else {
+ usleep(5 * 1000); //5ms
+ }
+ ALOGD("BT_SW_CVSD AP loopback threadLoop(-), uReadByte: %d, uWriteDataToBT: %d", uReadByte, uWriteDataToBT);
+ }
+ ALOGD("BT_SW_CVSD AP loopback threadLoop exit");
+ return false;
+}
+
+#endif
+
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSANLEController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSANLEController.cpp
new file mode 100644
index 0000000..779b7c8
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSANLEController.cpp
@@ -0,0 +1,2041 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#define LOG_TAG "AudioALSANLEController"
+#ifdef CONFIG_MT_ENG_BUILD
+#define LOG_NDEBUG 0 //enable and then ALOGV will print
+#endif
+#include "AudioALSANLEController.h"
+#include <stdlib.h> //for math
+#include <math.h> //for log
+#include "AudioALSADriverUtility.h"
+#include <cutils/properties.h>
+
+// #define VERY_VERBOSE_LOGGING
+#define ENABLE_NLE_HW_CONTROL // off when soft verify only
+
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+// By user
+#define NLE_GAIN_HP_DB_USER (3)
+#define NLE_GAIN_HP_INDEX_USER (9)
+#define NLE_GAIN_EOP_DB (-40)
+
+// Spec of NLE
+#define NLE_GAIN_HP_DB_MAX (12)
+#define NLE_GAIN_HP_DB_MIN (-32)
+#define NLE_GAIN_NLE_DB_MAX (44)
+#define NLE_GAIN_NLE_DB_MIN (0)
+#define NLE_GAIN_NLE_VALUE_MAX (44)
+#define NLE_DELAY_ANA_OUTPUT_T (0x0D) // Reg is 0x0C
+
+#define NLE_SUPPORT_ANA_GAIN_MUTE_DB (-40)
+#define NLE_SUPPORT_ANA_GAIN_MUTE_VALUE (0x3F)
+#define NLE_GAIN_HP_VALUE_MIN (0x2C)
+
+#if 0
+//Digital 0~30 dB
+//Analog 8~-22 dB
+// By user
+#define NLE_GAIN_HP_DB_USER (3)
+#define NLE_GAIN_HP_INDEX_USER (5)
+#define NLE_GAIN_EOP_DB (-40)
+
+// Spec of NLE
+#define NLE_GAIN_HP_DB_MAX (8)
+#define NLE_GAIN_HP_DB_MIN (-22)
+#define NLE_GAIN_NLE_DB_MAX (30)
+#define NLE_GAIN_NLE_DB_MIN (0)
+#define NLE_GAIN_NLE_VALUE_MAX (30)
+#define NLE_DELAY_ANA_OUTPUT_T (0x0D) // Reg is 0x0C
+
+#define NLE_SUPPORT_ANA_GAIN_MUTE_DB (-40)
+#define NLE_SUPPORT_ANA_GAIN_MUTE_VALUE (0x3F)
+#define NLE_GAIN_HP_VALUE_MIN (0x1E)
+#endif
+
+namespace android {
+/*==============================================================================
+ * Singleton Pattern
+ *============================================================================*/
+
+AudioALSAHyBridNLEManager *AudioALSAHyBridNLEManager::mAudioALSAHyBridNREManager = NULL;
+uint32_t AudioALSAHyBridNLEManager::mSupportRunNLEHandlerBitwise = (1 << PLAYBACK_HANDLER_NORMAL); // | (1 << PLAYBACK_HANDLER_DEEP_BUFFER);
+
+uint32_t find_bit_pos(uint32_t val) {
+ uint32_t bit_pos, i;
+ for (i = 1, bit_pos = 1; i != 0 && i <= val; i <<= 1, bit_pos++) {
+ if (val & i) {
+ return bit_pos;
+ }
+ }
+ return 0;
+}
+
+AudioALSAHyBridNLEManager *AudioALSAHyBridNLEManager::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSAHyBridNREManager == NULL) {
+ mAudioALSAHyBridNREManager = new AudioALSAHyBridNLEManager();
+ }
+ ASSERT(mAudioALSAHyBridNREManager != NULL);
+ return mAudioALSAHyBridNREManager;
+}
+
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+AudioALSAHyBridNLEManager::AudioALSAHyBridNLEManager() {
+ int property_forceoff;
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get("persist.vendor.audio.nle.eop", property_value, "0");
+ int property_eop = atoi(property_value);
+ property_get("persist.vendor.audio.nle.forceoff", property_value, "0");
+ property_forceoff = atoi(property_value);
+ mHwSupport = false;
+ mMixer = NULL;
+ mMixer = AudioALSADriverUtility::getInstance()->getMixer();
+ ASSERT(mMixer != NULL);
+#ifdef ENABLE_NLE_HW_CONTROL
+ const unsigned int num_values = 20;
+ struct mixer_ctl *ctl;
+ signed char HwCapability[num_values];
+ ctl = mixer_get_ctl_by_name(mMixer, "Audio_HyBridNLE_HwCapability");
+ if (NULL == ctl) {
+ ALOGE("Err for get Audio_HyBridNLE_HwCapability");
+ }
+ memset((void *)HwCapability, 0, sizeof(signed char)*num_values);
+ if (mixer_ctl_get_array(ctl, (void *)HwCapability, num_values)) {
+ ALOGE("Error for HwCapability");
+ } else {
+ ALOGD("Hw Config from kernel");
+ mHwSupport = true;
+ mHwAnalogGainMaxDb = (HwCapability[0] == 0) ? (int8_t) HwCapability[1] : ((int8_t) HwCapability[1]) * (-1);
+ mHwAnalogGainMinDb = (HwCapability[2] == 0) ? (int8_t) HwCapability[3] : ((int8_t) HwCapability[3]) * (-1);
+ mHwAnalogGainMinValue = (HwCapability[4] == 0) ? (size_t) HwCapability[5] : ((size_t) HwCapability[5]) * (-1);
+ mHwAnalogGainMuteDb = (HwCapability[6] == 0) ? (int8_t) HwCapability[7] : ((int8_t) HwCapability[7]) * (-1);
+ mHwAnalogGainMuteValue = (HwCapability[8] == 0) ? (size_t) HwCapability[9] : ((size_t) HwCapability[9]) * (-1);
+ mHwDigitalGainMaxDb = (HwCapability[10] == 0) ? (int8_t) HwCapability[11] : ((int8_t) HwCapability[11]) * (-1);
+ mHwDigitalGainMaxValue = (HwCapability[12] == 0) ? (size_t) HwCapability[13] : ((size_t) HwCapability[13]) * (-1);
+ mHwDigitalgGainMinDb = (HwCapability[14] == 0) ? (size_t) HwCapability[15] : ((size_t) HwCapability[15]) * (-1);
+ mHwAnalogDelayTick = (uint8_t) HwCapability[17];
+ }
+#endif
+ if (mHwSupport == false) {
+ ALOGD("Hw Config from user");
+ mHwAnalogGainMaxDb = NLE_GAIN_HP_DB_MAX;
+ mHwAnalogGainMinDb = NLE_GAIN_HP_DB_MIN;
+ mHwAnalogGainMinValue = NLE_GAIN_HP_VALUE_MIN;
+ mHwAnalogGainMuteDb = NLE_SUPPORT_ANA_GAIN_MUTE_DB;
+ mHwAnalogGainMuteValue = NLE_SUPPORT_ANA_GAIN_MUTE_VALUE;
+ mHwDigitalGainMaxDb = NLE_GAIN_NLE_DB_MAX;
+ mHwDigitalGainMaxValue = NLE_GAIN_NLE_VALUE_MAX;
+ mHwDigitalgGainMinDb = NLE_GAIN_NLE_DB_MIN;
+ mHwAnalogDelayTick = NLE_DELAY_ANA_OUTPUT_T;
+ }
+ ALOGD("mHwAnalogGainMaxDb = %d", mHwAnalogGainMaxDb);
+ ALOGD("mHwAnalogGainMinDb = %d", mHwAnalogGainMinDb);
+ ALOGD("mHwAnalogGainMinValue = %zu", mHwAnalogGainMinValue);
+ ALOGD("mHwAnalogGainMuteDb = %d", mHwAnalogGainMuteDb);
+ ALOGD("mHwAnalogGainMuteValue = %zu", mHwAnalogGainMuteValue);
+ ALOGD("mHwDigitalGainMaxDb = %d", mHwDigitalGainMaxDb);
+ ALOGD("mHwDigitalGainMaxValue = %zu", mHwDigitalGainMaxValue);
+ ALOGD("mHwDigitalgGainMinDb = %d", mHwDigitalgGainMinDb);
+ ALOGD("mHwAnalogDelayTick = %d", mHwAnalogDelayTick);
+
+ mGainHP_Db_Max = NLE_GAIN_HP_DB_USER;
+ mGainHP_Db_Min = (int32_t) mHwAnalogGainMinDb;
+ mGainNLE_Db_Min = (int32_t) mHwDigitalgGainMinDb;
+ if (property_eop < 0) {
+ mGainEop_Db = property_eop;
+ mSetEopByProp = true;
+ } else {
+ mGainEop_Db = NLE_GAIN_EOP_DB;
+ mSetEopByProp = false;
+ }
+ mGainNLE_Db_Max = mGainHP_Db_Max - mGainHP_Db_Min;
+ mGainSop_Db = mGainEop_Db - mGainNLE_Db_Max;
+#if 0
+ mLNleHwInfo.stPrev.mGainNle = mRNleHwInfo.stPrev.mGainNle = NLE_GAIN_UNININIAL_VALUE;
+ mLNleHwInfo.stPrev.mGainHP = mRNleHwInfo.stPrev.mGainHP = NLE_GAIN_UNININIAL_VALUE;
+ mLNleHwInfo.stCur.mGainNle = mRNleHwInfo.stCur.mGainNle = mGainNLE_Db_Min;
+ mLNleHwInfo.stCur.mGainHP = mRNleHwInfo.stCur.mGainHP = mGainHP_Db_Max;
+ mLNleHwInfo.stPrev.mDbpPerStep = mLNleHwInfo.stCur.mDbpPerStep = mRNleHwInfo.stPrev.mDbpPerStep = mRNleHwInfo.stCur.mDbpPerStep = 0;
+ mLNleHwInfo.stPrev.mStepPerZC = mLNleHwInfo.stCur.mStepPerZC = mRNleHwInfo.stPrev.mStepPerZC = mRNleHwInfo.stCur.mStepPerZC = 0;
+#endif
+ mStatus = AUDIO_HYBRID_NLE_MNG_STATE_DISABLE;
+ mActivePBHandler = PLAYBACK_HANDLER_BASE;
+ mActivePBHandlerBitwise = 0;
+ mInitPBHandlerBitwise = 0;
+ mLNleHwInfo.mChannel = AUDIO_NLE_CHANNEL_L;
+ resetDefaultGain(&mLNleHwInfo);
+ mRNleHwInfo.mChannel = AUDIO_NLE_CHANNEL_R;
+ resetDefaultGain(&mRNleHwInfo);
+ mMode = AUDIO_MODE_NORMAL;
+ memset(&mNleCtrlOfPlaybackHandler[0], 0, sizeof(AudioALSANLECtrl *)*PLAYBACK_HANDLER_MAX);
+ mNleCtrlOfPlaybackHandlerCounter = 0;
+ mHwPathStreamCounter = 0;
+ mBypassNLE = false;
+ mNleSwitch = false;
+ if (property_forceoff > 0) {
+ mForceTurnOffNLE = true;
+ } else {
+ mForceTurnOffNLE = false;
+ }
+ // showRegInfo();
+ double mfloatValue = pow(10, (mGainEop_Db / 20.0));
+ mMax24BitValidValue = (uint32_t)(NLE_24BIT_POSITIVE_MAX * mfloatValue);
+ mMax16BitValidValue = (uint32_t)(NLE_16BIT_POSITIVE_MAX * mfloatValue);
+ ALOGD("mMax24BitValidValue %d, mMax16BitValidValue %d", mMax24BitValidValue, mMax16BitValidValue);
+ ALOGD("[Init] %s %d", __FUNCTION__, __LINE__);
+}
+
+status_t AudioALSAHyBridNLEManager::setNleHwConfigByDb(int hpMaxGainDb, int eopGainDb) {
+ status_t dRet = NO_ERROR;
+ int32_t mPrevGainEop_Db = mGainEop_Db;
+
+ if (hpMaxGainDb < mGainHP_Db_Min) {
+ ALOGE("[Err] mGainHP_Db_Min > hpMaxGainDb, [%d] > [%d]", mGainHP_Db_Min, hpMaxGainDb);
+ return BAD_VALUE;
+ }
+
+ if (hpMaxGainDb > mHwAnalogGainMaxDb || (hpMaxGainDb < mHwAnalogGainMinDb && hpMaxGainDb != mHwAnalogGainMuteDb)) {
+ ALOGE("[Err] hpMaxGainDb [%d] should be not > [%d] or < [%d]", hpMaxGainDb, mHwAnalogGainMaxDb, mHwAnalogGainMinDb);
+ return BAD_VALUE;
+ }
+
+ if (eopGainDb > 0 || eopGainDb < -96) {
+ ALOGE("[Err] eopGainDb > 0 || < -96, [%d]", eopGainDb);
+ return BAD_VALUE;
+ }
+
+ AL_AUTOLOCK(mLock);
+ mGainHP_Db_Max = hpMaxGainDb;
+ if (!mSetEopByProp) {
+ mGainEop_Db = eopGainDb;
+ }
+ if (mGainHP_Db_Max == mHwAnalogGainMuteDb) {
+ mGainNLE_Db_Max = 0;
+ } else {
+ mGainNLE_Db_Max = mGainHP_Db_Max - mGainHP_Db_Min;
+ }
+ mGainSop_Db = mGainEop_Db - mGainNLE_Db_Max;
+ if (mPrevGainEop_Db != mGainEop_Db) {
+ double mfloatValue = pow(10, (mGainEop_Db / 20.0));
+ mMax24BitValidValue = (uint32_t)(NLE_24BIT_POSITIVE_MAX * mfloatValue);
+ mMax16BitValidValue = (uint32_t)(NLE_16BIT_POSITIVE_MAX * mfloatValue);
+ ALOGD("mMax24BitValidValue %d, mMax16BitValidValue %d", mMax24BitValidValue, mMax16BitValidValue);
+ }
+
+ if (mStatus == AUDIO_HYBRID_NLE_MNG_STATE_RUNNING) {
+ if (mSupportRunNLEHandlerBitwise & mActivePBHandlerBitwise) {
+ AudioALSANLECtrl *pCurNLECtrl = mNleCtrlOfPlaybackHandler[mActivePBHandler];
+ dRet = doAdjustGainProcess(pCurNLECtrl, pCurNLECtrl->mCheckHwExtraFrameCnt, NLE_ADJUST_GAIN_NORMAL);
+ }
+ } else if (mStatus == AUDIO_HYBRID_NLE_MNG_STATE_BYBASS) {
+ dRet = ramp2DigitalGainZero();
+ } else {
+ dRet = FAILED_TRANSACTION;
+ }
+ return dRet;
+}
+
+status_t AudioALSAHyBridNLEManager::setNleHwConfigByIndex(size_t hpMaxGainIdx) {
+ status_t dRet = NO_ERROR;
+ int8_t bDb;
+ dRet = getDbFromAnalogIdx(hpMaxGainIdx, &bDb);
+ ALOGV("%s Idx %zu, dB %d, dRet %d", __FUNCTION__, hpMaxGainIdx, bDb, dRet);
+ if (dRet == NO_ERROR) {
+ int dDb = (int) bDb;
+ dRet = setNleHwConfigByDb(dDb, mGainEop_Db);
+ }
+ return dRet;
+}
+
+status_t AudioALSAHyBridNLEManager::getNleHwConfigByDb(int *hpMaxGainDb) {
+ ALOGV("%s", __FUNCTION__);
+ if (hpMaxGainDb == NULL) {
+ ALOGE("[Err] %s %d Bad Argu", __FUNCTION__, __LINE__);
+ return BAD_VALUE;
+ }
+ AL_AUTOLOCK(mLock);
+ *hpMaxGainDb = mGainHP_Db_Max;
+ return NO_ERROR;
+}
+
+status_t AudioALSAHyBridNLEManager::getNleHwConfigByIndex(size_t *hpMaxGainIdx) {
+ status_t dRet = NO_ERROR;
+ ALOGV("%s", __FUNCTION__);
+ if (hpMaxGainIdx == NULL) {
+ ALOGE("[Err] %s %d Bad Argu", __FUNCTION__, __LINE__);
+ return BAD_VALUE;
+ }
+ AL_AUTOLOCK(mLock);
+ int8_t bDb;
+ if (mGainHP_Db_Max < 0) {
+ bDb = (mGainHP_Db_Max * (-1)) & 0x00ff;
+ } else {
+ bDb = mGainHP_Db_Max & 0x00ff;
+ }
+ dRet = getAnalogIdx(bDb, hpMaxGainIdx);
+ if (dRet != NO_ERROR) {
+ ALOGE("[Err] %s %d mapping err", __FUNCTION__, __LINE__);
+ }
+ return dRet;
+}
+
+audio_hybridnlemng_status AudioALSAHyBridNLEManager::getStatus(void) {
+ audio_hybridnlemng_status CurrentStatus;
+ AL_AUTOLOCK(mLock);
+ CurrentStatus = mStatus;
+ ALOGV("Status: %d", CurrentStatus);
+ return CurrentStatus;
+}
+
+status_t AudioALSAHyBridNLEManager::initPlayBackHandler(playback_handler_t ePlaybackHandlerType, stream_attribute_t *pStreamAttribute, AudioALSAPlaybackHandlerBase *pPlaybackHandler) {
+ ALOGV("%s", __FUNCTION__);
+
+ status_t dRet;
+ audio_hybridnlemng_status mOldStatus, mCurStatus;
+ if (mForceTurnOffNLE) {
+ return INVALID_OPERATION;
+ }
+
+ if (ePlaybackHandlerType >= PLAYBACK_HANDLER_MAX) {
+ ALOGE("[Err] %s %d", __FUNCTION__, __LINE__);
+ return BAD_INDEX;
+ }
+
+ if (pPlaybackHandler == NULL) {
+ ALOGE("[Err] %s %d", __FUNCTION__, __LINE__);
+ return BAD_VALUE;
+ }
+
+ if (pStreamAttribute == NULL) {
+ ALOGE("[Err] %s %d", __FUNCTION__, __LINE__);
+ return BAD_VALUE;
+ }
+
+ {
+ AL_AUTOLOCK(mLock);
+ if (mNleCtrlOfPlaybackHandler[ePlaybackHandlerType] != NULL) {
+ ALOGE("[Err] %s %d", __FUNCTION__, __LINE__);
+ return ALREADY_EXISTS;
+ }
+
+ mNleCtrlOfPlaybackHandler[ePlaybackHandlerType] = new AudioALSANLECtrl(ePlaybackHandlerType, pStreamAttribute);
+
+ if (mNleCtrlOfPlaybackHandler[ePlaybackHandlerType] == NULL) {
+ ALOGE("[Err] %s %d", __FUNCTION__, __LINE__);
+ return NO_MEMORY;
+ }
+
+ dRet = mNleCtrlOfPlaybackHandler[ePlaybackHandlerType]->init(pPlaybackHandler);
+
+ if (dRet != NO_ERROR) {
+ ALOGW("[Warn] Unsupport handler %d %s %d", ePlaybackHandlerType, __FUNCTION__, __LINE__);
+ delete mNleCtrlOfPlaybackHandler[ePlaybackHandlerType];
+ mNleCtrlOfPlaybackHandler[ePlaybackHandlerType] = NULL;
+ return dRet;
+ }
+
+ mNleCtrlOfPlaybackHandlerCounter++;
+ mInitPBHandlerBitwise |= (1 << ePlaybackHandlerType);
+
+ mOldStatus = mStatus;
+ updateCurStatus();
+ mCurStatus = mStatus;
+ }
+
+ waitForBypass(mOldStatus, mCurStatus);
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHyBridNLEManager::deinitPlayBackHandler(playback_handler_t ePlaybackHandlerType) {
+ ALOGV("%s ePlaybackHandlerType %d", __FUNCTION__, ePlaybackHandlerType);
+
+ status_t dRet;
+ audio_hybridnlemng_status mOldStatus, mCurStatus;
+
+ if (ePlaybackHandlerType >= PLAYBACK_HANDLER_MAX) {
+ ALOGE("[Err] %s %d", __FUNCTION__, __LINE__);
+ return BAD_INDEX;
+ }
+
+ {
+ AL_AUTOLOCK(mLock);
+ if (mNleCtrlOfPlaybackHandler[ePlaybackHandlerType] == NULL) {
+ ALOGE("[Err] %s %d", __FUNCTION__, __LINE__);
+ return NO_INIT;
+ }
+
+ dRet = mNleCtrlOfPlaybackHandler[ePlaybackHandlerType]->deinit();
+
+ if (dRet != NO_ERROR) {
+ ALOGE("[Err] %s %d", __FUNCTION__, __LINE__);
+ return dRet;
+ }
+
+ delete mNleCtrlOfPlaybackHandler[ePlaybackHandlerType];
+ mNleCtrlOfPlaybackHandler[ePlaybackHandlerType] = NULL;
+
+ mNleCtrlOfPlaybackHandlerCounter--;
+ mInitPBHandlerBitwise &= ~(1 << ePlaybackHandlerType);
+
+ mOldStatus = mStatus;
+ updateCurStatus();
+ mCurStatus = mStatus;
+ }
+
+ waitForBypass(mOldStatus, mCurStatus);
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHyBridNLEManager::process(playback_handler_t ePlaybackHandlerType, void *buffer, size_t Byte) {
+ status_t dRet = NO_ERROR;
+#if 0
+ nsecs_t sysTimeBegin, sysTimeCur;
+ uint32_t sysDiff;
+ ALOGD("+");
+ sysTimeBegin = systemTime();
+#endif
+
+ if (ePlaybackHandlerType >= PLAYBACK_HANDLER_MAX) {
+ ALOGE("[Err] %s %d", __FUNCTION__, __LINE__);
+ return BAD_INDEX;
+ }
+
+ if (!((1 << ePlaybackHandlerType) & mSupportRunNLEHandlerBitwise)) {
+ ALOGE("[Err] %s %d", __FUNCTION__, __LINE__);
+ return INVALID_OPERATION;
+ }
+
+ AL_AUTOLOCK(mLock);
+ if (mNleCtrlOfPlaybackHandler[ePlaybackHandlerType] == NULL) {
+ // ALOGV("[Warn] %s %d", __FUNCTION__, __LINE__);
+ return NO_INIT;
+ }
+
+ if (Byte != mNleCtrlOfPlaybackHandler[ePlaybackHandlerType]->process(buffer, Byte)) {
+ ALOGV("[Err] %s %d", __FUNCTION__, __LINE__);
+ return INVALID_OPERATION;
+ }
+
+ if (mStatus == AUDIO_HYBRID_NLE_MNG_STATE_RUNNING) {
+ if (ePlaybackHandlerType == mActivePBHandler) {
+ AudioALSANLECtrl *pCurNLECtrl = mNleCtrlOfPlaybackHandler[ePlaybackHandlerType];
+ dRet = doAdjustGainProcess(pCurNLECtrl, pCurNLECtrl->mCheckHwExtraFrameCnt, NLE_ADJUST_GAIN_NORMAL);
+ }
+ }
+#if 0
+ sysTimeCur = systemTime();
+ sysDiff = ns2ms(sysTimeCur - sysTimeBegin);
+ ALOGD("%d %u", sysDiff, Byte);
+#endif
+ return dRet;
+}
+
+status_t AudioALSAHyBridNLEManager::setBypassNLE(bool bBypass) {
+ ALOGV("%s", __FUNCTION__);
+ audio_hybridnlemng_status mOldStatus, mCurStatus;
+ {
+ AL_AUTOLOCK(mLock);
+
+ if (bBypass == mBypassNLE) {
+ ALOGE("[Err] %s %d", __FUNCTION__, __LINE__);
+ return INVALID_OPERATION;
+ }
+
+ mBypassNLE = bBypass;
+
+ mOldStatus = mStatus;
+ updateCurStatus();
+ mCurStatus = mStatus;
+ }
+
+ waitForBypass(mOldStatus, mCurStatus);
+
+ return NO_ERROR;
+}
+
+bool AudioALSAHyBridNLEManager::getBypassNLE(void) {
+ ALOGV("%s", __FUNCTION__);
+ return mBypassNLE;
+}
+
+status_t AudioALSAHyBridNLEManager::setEnableNLE(bool bEnable) {
+ ALOGV("%s %d", __FUNCTION__, bEnable);
+ audio_hybridnlemng_status mOldStatus, mCurStatus;
+
+ {
+ AL_AUTOLOCK(mLock);
+
+ if (bEnable == mNleSwitch) {
+ ALOGV("[Err] %s %d mNleSwitch %d", __FUNCTION__, __LINE__, mNleSwitch);
+ return INVALID_OPERATION;
+ }
+
+ mNleSwitch = bEnable;
+
+ mOldStatus = mStatus;
+ updateCurStatus();
+ mCurStatus = mStatus;
+ }
+
+ waitForBypass(mOldStatus, mCurStatus);
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHyBridNLEManager::dump(void) {
+ ALOGD("Dump...");
+ ALOGD("mGainHP_Db_Min %d", mGainHP_Db_Min);
+ ALOGD("mGainNLE_Db_Max %d", mGainNLE_Db_Max);
+ ALOGD("mGainNLE_Db_Min %d", mGainNLE_Db_Min);
+ ALOGD("mGainEop_Db %d", mGainEop_Db);
+ ALOGD("mGainSop_Db %d", mGainSop_Db);
+ ALOGD("mActivePBHandler %d", mActivePBHandler);
+ ALOGD("mActivePBHandlerBitwise 0x%x", mActivePBHandlerBitwise);
+ ALOGD("mInitPBHandlerBitwise 0x%x", mInitPBHandlerBitwise);
+ ALOGD("mMode %d", mMode);
+ ALOGD("mNleCtrlOfPlaybackHandlerCounter %d", mNleCtrlOfPlaybackHandlerCounter);
+ ALOGD("mHwPathStreamCounter %d", mHwPathStreamCounter);
+ ALOGD("mBypassNLE %d", mBypassNLE);
+ ALOGD("mNleSwitch %d", mNleSwitch);
+ ALOGD("mHwAnalogGainMaxDb = %d", mHwAnalogGainMaxDb);
+ ALOGD("mHwAnalogGainMinDb = %d", mHwAnalogGainMinDb);
+ ALOGD("mHwAnalogGainMinValue = %zu", mHwAnalogGainMinValue);
+ ALOGD("mHwAnalogGainMuteDb = %d", mHwAnalogGainMuteDb);
+ ALOGD("mHwAnalogGainMuteValue = %zu", mHwAnalogGainMuteValue);
+ ALOGD("mHwDigitalGainMaxDb = %d", mHwDigitalGainMaxDb);
+ ALOGD("mHwDigitalGainMaxValue = %zu", mHwDigitalGainMaxValue);
+ ALOGD("mHwDigitalgGainMinDb = %d", mHwDigitalgGainMinDb);
+ ALOGD("mHwAnalogDelayTick = %d", mHwAnalogDelayTick);
+ return NO_ERROR;
+}
+
+uint32_t AudioALSAHyBridNLEManager::getSupportRunNLEHandler(void) {
+ return mSupportRunNLEHandlerBitwise;
+}
+
+status_t AudioALSAHyBridNLEManager::setSupportRunNLEHandler(playback_handler_t eHandler) {
+ if ((eHandler != PLAYBACK_HANDLER_NORMAL) && (eHandler != PLAYBACK_HANDLER_DEEP_BUFFER)) {
+ ALOGD("Only Support PLAYBACK_HANDLER_NORMAL(%d) and PLAYBACK_HANDLER_DEEPBUF(%d), Not %d",
+ PLAYBACK_HANDLER_NORMAL, PLAYBACK_HANDLER_DEEP_BUFFER, eHandler);
+ return BAD_VALUE;
+ }
+ ALOGD("Support %d Handler", eHandler);
+ // We overwrite the supported handler, not add/remove so far
+ mSupportRunNLEHandlerBitwise = (1 << eHandler);
+ return NO_ERROR;
+}
+
+status_t AudioALSAHyBridNLEManager::setNleEopDb(int eopGainDb) {
+ return setNleHwConfigByDb(mGainHP_Db_Max, eopGainDb);
+}
+
+int AudioALSAHyBridNLEManager::getNleEopDb(void) {
+ return mGainEop_Db;
+}
+
+status_t AudioALSAHyBridNLEManager::setAudioMode(audio_mode_t eMode) {
+ ALOGV("%s", __FUNCTION__);
+ audio_hybridnlemng_status mOldStatus, mCurStatus;
+ {
+ AL_AUTOLOCK(mLock);
+
+ if (eMode == mMode) {
+ ALOGE("[Err] %s %d", __FUNCTION__, __LINE__);
+ return INVALID_OPERATION;
+ }
+
+ mMode = eMode;
+
+ mOldStatus = mStatus;
+ updateCurStatus();
+ mCurStatus = mStatus;
+ }
+
+ waitForBypass(mOldStatus, mCurStatus);
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHyBridNLEManager::addHwPathStream(audio_stream_hw_path eHwPath __unused) {
+ ALOGV("%s", __FUNCTION__);
+ audio_hybridnlemng_status mOldStatus, mCurStatus;
+
+ // eHwPath = eHwPath; //ToDo
+ {
+ AL_AUTOLOCK(mLock);
+
+ mHwPathStreamCounter++;
+
+ mOldStatus = mStatus;
+ updateCurStatus();
+ mCurStatus = mStatus;
+ }
+
+ waitForBypass(mOldStatus, mCurStatus);
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHyBridNLEManager::removeHwPathStream(audio_stream_hw_path eHwPath __unused) {
+ ALOGV("%s", __FUNCTION__);
+ audio_hybridnlemng_status mOldStatus, mCurStatus;
+
+ //eHwPath = eHwPath; //ToDo
+ {
+ AL_AUTOLOCK(mLock);
+
+ if (mHwPathStreamCounter <= 0) {
+ ALOGE("[Err] %s %d", __FUNCTION__, __LINE__);
+ return UNKNOWN_ERROR;
+ }
+
+ mHwPathStreamCounter--;
+
+ mOldStatus = mStatus;
+ updateCurStatus();
+ mCurStatus = mStatus;
+ }
+
+ waitForBypass(mOldStatus, mCurStatus);
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHyBridNLEManager::updateCurStatus(void) {
+ audio_hybridnlemng_status nowStatus = mStatus;
+ ALOGD("mNleSwitch %d mBypassNLE %d PBHCount %d mMode %d HwPathCnt %d PBH %d PBHBit 0x%x InitBit 0x%x", mNleSwitch, mBypassNLE, mNleCtrlOfPlaybackHandlerCounter, mMode, mHwPathStreamCounter, mActivePBHandler, mActivePBHandlerBitwise, mInitPBHandlerBitwise);
+ do {
+ if (mNleSwitch == false) {
+ if (mStatus == AUDIO_HYBRID_NLE_MNG_STATE_DISABLE) {
+ break;
+ } else if (mStatus == AUDIO_HYBRID_NLE_MNG_STATE_BYBASS) {
+ disableNleHw();
+ ALOGV("ts %d -> %d", mStatus, AUDIO_HYBRID_NLE_MNG_STATE_DISABLE);
+ mStatus = AUDIO_HYBRID_NLE_MNG_STATE_DISABLE;
+ } else if (mStatus == AUDIO_HYBRID_NLE_MNG_STATE_RUNNING) {
+ // Do ramp down to digital gain to Zero
+ ramp2DigitalGainZero();
+ ALOGV("ts %d -> %d", mStatus, AUDIO_HYBRID_NLE_MNG_STATE_BYBASS);
+ mStatus = AUDIO_HYBRID_NLE_MNG_STATE_BYBASS;
+ }
+ } else if (mBypassNLE == true || mNleCtrlOfPlaybackHandlerCounter > 1 || mMode != AUDIO_MODE_NORMAL || mHwPathStreamCounter != 0) {
+
+ if (mStatus == AUDIO_HYBRID_NLE_MNG_STATE_DISABLE) {
+ enableNleHw();
+ ALOGV("ts %d -> %d", mStatus, AUDIO_HYBRID_NLE_MNG_STATE_BYBASS);
+ mStatus = AUDIO_HYBRID_NLE_MNG_STATE_BYBASS;
+ } else if (mStatus == AUDIO_HYBRID_NLE_MNG_STATE_BYBASS) {
+ break;
+ } else if (mStatus == AUDIO_HYBRID_NLE_MNG_STATE_RUNNING) {
+ // Do ramp down to digital gain to Zero (Other change)
+ ramp2DigitalGainZero();
+ ALOGV("ts %d -> %d", mStatus, AUDIO_HYBRID_NLE_MNG_STATE_BYBASS);
+ mStatus = AUDIO_HYBRID_NLE_MNG_STATE_BYBASS;
+ }
+ } else {
+ if (mStatus == AUDIO_HYBRID_NLE_MNG_STATE_DISABLE) {
+ enableNleHw();
+ ALOGV("ts %d -> %d", mStatus, AUDIO_HYBRID_NLE_MNG_STATE_BYBASS);
+ mStatus = AUDIO_HYBRID_NLE_MNG_STATE_BYBASS;
+ } else if (mStatus == AUDIO_HYBRID_NLE_MNG_STATE_BYBASS) {
+ if (mNleCtrlOfPlaybackHandlerCounter == 1 && (mSupportRunNLEHandlerBitwise & mInitPBHandlerBitwise)) {
+ mActivePBHandlerBitwise = mInitPBHandlerBitwise;
+ mActivePBHandler = (playback_handler_t)(find_bit_pos(mActivePBHandlerBitwise) - 1);
+ ALOGV("ts %d -> %d with Handle %d", mStatus, AUDIO_HYBRID_NLE_MNG_STATE_RUNNING, mActivePBHandler);
+ mStatus = AUDIO_HYBRID_NLE_MNG_STATE_RUNNING;
+ } else {
+ break;
+ }
+ } else if (mStatus == AUDIO_HYBRID_NLE_MNG_STATE_RUNNING) {
+ if (mNleCtrlOfPlaybackHandlerCounter == 0 || !(mSupportRunNLEHandlerBitwise & mInitPBHandlerBitwise)) {
+ // Do ramp down to digital gain to Zero (Self change)
+ ramp2DigitalGainZero();
+ ALOGV("ts %d -> %d", mStatus, AUDIO_HYBRID_NLE_MNG_STATE_BYBASS);
+ mActivePBHandlerBitwise = 0;
+ mActivePBHandler = PLAYBACK_HANDLER_BASE;
+ mStatus = AUDIO_HYBRID_NLE_MNG_STATE_BYBASS;
+ } else {
+ break;
+ }
+ }
+ }
+ } while (1);
+
+ if (nowStatus != mStatus) {
+ ALOGD("%s status [%d] -> [%d]", __FUNCTION__, nowStatus, mStatus);
+ }
+ ALOGV("PHC %d mMode %d HwCount %d BypassNLE %d", mNleCtrlOfPlaybackHandlerCounter, mMode, mHwPathStreamCounter, mBypassNLE);
+ return NO_ERROR;
+}
+
+status_t AudioALSAHyBridNLEManager::enableNleHw(void) {
+ //Pass rg_nle_delay_ana into setting
+ //Pass initial Analog gain into setting
+ ALOGV("%s", __FUNCTION__);
+ unsigned char GainConfig[3];
+ GainConfig[0] = mHwAnalogDelayTick;
+ if (mGainHP_Db_Max < 0) {
+ GainConfig[1] = 1;
+ GainConfig[2] = (mGainHP_Db_Max * (-1)) & 0x00ff;
+ } else {
+ GainConfig[1] = 0;
+ GainConfig[2] = mGainHP_Db_Max & 0x00ff;
+ }
+#ifdef ENABLE_NLE_HW_CONTROL
+ if (mHwSupport) {
+ if (mixer_ctl_set_array(mixer_get_ctl_by_name(mMixer, "Audio_HyBridNLE_TurnOn"), (const void *)GainConfig, 3)) {
+ ALOGE("[Errrrrrrrrrrrrrrr] NLE %s %d", __FUNCTION__, __LINE__);
+ return INVALID_OPERATION;
+ }
+ } else {
+ ALOGD("%s Kernel unsupport", __FUNCTION__);
+ }
+#else
+ ALOGD("%s Audio_HyBridNLE_TurnOn", __FUNCTION__);
+#endif
+ return NO_ERROR;
+}
+
+status_t AudioALSAHyBridNLEManager::disableNleHw(void) {
+ //Pass rg_nle_delay_ana into setting
+ //Pass initial Analog gain into setting
+ ALOGV("%s", __FUNCTION__);
+ unsigned char GainConfig[3];
+ GainConfig[0] = mHwAnalogDelayTick;
+ if (mGainHP_Db_Max < 0) {
+ GainConfig[1] = 1;
+ GainConfig[2] = (mGainHP_Db_Max * (-1)) & 0x00ff;
+ } else {
+ GainConfig[1] = 0;
+ GainConfig[2] = mGainHP_Db_Max & 0x00ff;
+ }
+#ifdef ENABLE_NLE_HW_CONTROL
+ if (mHwSupport) {
+ if (mixer_ctl_set_array(mixer_get_ctl_by_name(mMixer, "Audio_HyBridNLE_TurnOff"), (const void *)GainConfig, 3)) {
+ ALOGE("[Errrrrrrrrrrrrrrr] NLE %s %d", __FUNCTION__, __LINE__);
+ return INVALID_OPERATION;
+ }
+ } else {
+ ALOGD("%s Kernel unsupport", __FUNCTION__);
+ }
+#else
+ ALOGD("%s Audio_HyBridNLE_TurnOff", __FUNCTION__);
+#endif
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHyBridNLEManager::ramp2DigitalGainZero(void) {
+ ALOGV("%s", __FUNCTION__);
+ if (mSupportRunNLEHandlerBitwise & mActivePBHandlerBitwise) {
+ AudioALSANLECtrl *pCurNLECtrl = mNleCtrlOfPlaybackHandler[mActivePBHandler];
+ if (pCurNLECtrl != NULL) {
+ return doAdjustGainProcess(pCurNLECtrl, pCurNLECtrl->mRamp2ZeroFrameCnt, NLE_ADJUST_GAIN_RAMP_TO_BYPASS);
+ } else {
+ // Do rampdown to 0 with NoZCE
+ resetDefaultGain(&mLNleHwInfo);
+ resetDefaultGain(&mRNleHwInfo);
+ applyGain2Hw(&mLNleHwInfo);
+ applyGain2Hw(&mRNleHwInfo);
+ return NO_ERROR;
+ }
+ } else {
+ // Do rampdown to 0 with NoZCE
+ resetDefaultGain(&mLNleHwInfo);
+ resetDefaultGain(&mRNleHwInfo);
+ applyGain2Hw(&mLNleHwInfo);
+ applyGain2Hw(&mRNleHwInfo);
+ return NO_ERROR;
+ }
+}
+
+bool AudioALSAHyBridNLEManager::checkIfGainTargeted(void) {
+ // Query Kernel driver to check if target for both LR
+#ifdef ENABLE_NLE_HW_CONTROL
+ ALOGVV("%s", __FUNCTION__);
+ struct mixer_ctl *ctl;
+ int dValue = 0;
+ if (mHwSupport) {
+ ctl = mixer_get_ctl_by_name(mMixer, "Audio_HyBridNLE_Targeted");
+ if (NULL == ctl) {
+ ALOGE("[%s] [%d]", __FUNCTION__, __LINE__);
+ return false;
+ }
+ dValue = mixer_ctl_get_value(ctl, 0);
+ } else {
+ ALOGD("%s Kernel unsupport", __FUNCTION__);
+ }
+ if (dValue == 1) {
+ return true;
+ } else {
+ return false;
+ }
+#else
+ return false;
+#endif
+}
+
+void AudioALSAHyBridNLEManager::showRegInfo(void) {
+#ifdef ENABLE_NLE_HW_CONTROL
+ if (mHwSupport) {
+ const unsigned int num_values = 32;
+ struct mixer_ctl *ctl;
+ unsigned char GainConfig[num_values];
+ ctl = mixer_get_ctl_by_name(mMixer, "Audio_HyBridNLE_Info");
+ if (NULL == ctl) {
+ ALOGE("Err for get Audio_HyBridNLE_Info");
+ }
+ memset((void *)GainConfig, 0, sizeof(unsigned char)*num_values);
+ if (mixer_ctl_get_array(ctl, (void *)GainConfig, num_values)) {
+ ALOGE("Error for GainConfig");
+ }
+ ALOGD("NLEREG: AFE_DL_NLE_R_CFG0 = 0x%x", GainConfig[1] << 8 | GainConfig[0]);
+ ALOGD("NLEREG: AFE_DL_NLE_R_CFG1 = 0x%x", GainConfig[3] << 8 | GainConfig[2]);
+ ALOGD("NLEREG: AFE_DL_NLE_R_CFG2 = 0x%x", GainConfig[5] << 8 | GainConfig[4]);
+ ALOGD("NLEREG: AFE_DL_NLE_R_CFG3 = 0x%x", GainConfig[7] << 8 | GainConfig[6]);
+
+ ALOGD("NLEREG: AFE_DL_NLE_L_CFG0 = 0x%x", GainConfig[9] << 8 | GainConfig[8]);
+ ALOGD("NLEREG: AFE_DL_NLE_L_CFG0 = 0x%x", GainConfig[11] << 8 | GainConfig[10]);
+ ALOGD("NLEREG: AFE_DL_NLE_L_CFG0 = 0x%x", GainConfig[13] << 8 | GainConfig[12]);
+ ALOGD("NLEREG: AFE_DL_NLE_L_CFG0 = 0x%x", GainConfig[15] << 8 | GainConfig[14]);
+
+ ALOGD("NLEREG: AFE_RGS_NLE_R_CFG0 = 0x%x", GainConfig[17] << 8 | GainConfig[16]);
+ ALOGD("NLEREG: AFE_RGS_NLE_R_CFG1 = 0x%x", GainConfig[19] << 8 | GainConfig[18]);
+ ALOGD("NLEREG: AFE_RGS_NLE_R_CFG2 = 0x%x", GainConfig[21] << 8 | GainConfig[20]);
+ ALOGD("NLEREG: AFE_RGS_NLE_R_CFG3 = 0x%x", GainConfig[23] << 8 | GainConfig[22]);
+
+ ALOGD("NLEREG: AFE_RGS_NLE_L_CFG0 = 0x%x", GainConfig[25] << 8 | GainConfig[24]);
+ ALOGD("NLEREG: AFE_RGS_NLE_L_CFG1 = 0x%x", GainConfig[27] << 8 | GainConfig[26]);
+ ALOGD("NLEREG: AFE_RGS_NLE_L_CFG2 = 0x%x", GainConfig[29] << 8 | GainConfig[28]);
+ ALOGD("NLEREG: AFE_RGS_NLE_L_CFG3 = 0x%x", GainConfig[31] << 8 | GainConfig[30]);
+ } else {
+ ALOGD("%s Kernel unsupport", __FUNCTION__);
+ }
+#else
+ ALOGD("%s Audio_HyBridNLE_Info", __FUNCTION__);
+#endif
+}
+status_t AudioALSAHyBridNLEManager::waitForBypass(audio_hybridnlemng_status ePrevStatus, audio_hybridnlemng_status eCurStatus) {
+ if ((eCurStatus == AUDIO_HYBRID_NLE_MNG_STATE_BYBASS && ePrevStatus == AUDIO_HYBRID_NLE_MNG_STATE_RUNNING)
+ || (eCurStatus == AUDIO_HYBRID_NLE_MNG_STATE_DISABLE && ePrevStatus == AUDIO_HYBRID_NLE_MNG_STATE_BYBASS)) {
+ ALOGV("waitForBypass Need wait %d -> %d", ePrevStatus, eCurStatus);
+ nsecs_t sysTimeBegin, sysTimeCur;
+ uint32_t sysDiff;
+ sysTimeBegin = systemTime();
+ do {
+ if (checkIfGainTargeted() == true) {
+ break;
+ } else {
+ sysTimeCur = systemTime();
+ sysDiff = ns2ms(sysTimeCur - sysTimeBegin);
+ if (sysDiff >= NLE_WAIT_NLE_BYPASS_MAX_MS) {
+ ALOGW("[Warn] waitForBypass TimeOut %d MS", sysDiff);
+ break;
+ }
+ usleep(1000);
+ }
+ } while (1);
+ ALOGV("waitForBypass Exit wait");
+ } else {
+ ALOGV("Do nothing for %d -> %d", ePrevStatus, eCurStatus);
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHyBridNLEManager::doAdjustGainProcess(AudioALSANLECtrl *pCurNLECtrl, size_t zuCheckOffsetFrameCnt, audio_hybrid_adjust_mode eAdjustMode) {
+ status_t dRet;
+ time_info_struct_t stHWBuffer_Time_Info;
+ size_t UsedFrameCount;
+ size_t zuCheckExtraFrameCnt;
+ size_t zuOffsetForTail;
+ if (pCurNLECtrl == NULL || eAdjustMode >= NLE_ADJUST_GAIN_MAX) {
+ ALOGE("[Err] doAdjustGainProcess pCurNLECtrl %p eAdjustMode %d", pCurNLECtrl, eAdjustMode);
+ return BAD_VALUE;
+ } else if (eAdjustMode == NLE_ADJUST_GAIN_RAMP_TO_BYPASS) {
+ //Insert MAX value into offset
+ zuCheckExtraFrameCnt = 0;
+ } else {
+ zuCheckExtraFrameCnt = zuCheckOffsetFrameCnt;
+ }
+
+ if (pCurNLECtrl->mAudioALSAPlaybackHandlerBase->getHardwareBufferInfo(&stHWBuffer_Time_Info) == NO_ERROR) {
+ UsedFrameCount = stHWBuffer_Time_Info.buffer_per_time - stHWBuffer_Time_Info.frameInfo_get;
+ if (eAdjustMode == NLE_ADJUST_GAIN_RAMP_TO_BYPASS) {
+ if (zuCheckOffsetFrameCnt > UsedFrameCount) {
+ zuOffsetForTail = 0;
+ } else {
+ zuOffsetForTail = UsedFrameCount - zuCheckOffsetFrameCnt;
+ }
+ pCurNLECtrl->setMaxSPLintoSpecificPos(zuOffsetForTail);
+ }
+ // ALOGD("UsedFrameCount L %d", UsedFrameCount); - For Debug
+ UsedFrameCount = UsedFrameCount + zuCheckExtraFrameCnt;
+ dRet = checkAndSetGain(UsedFrameCount, pCurNLECtrl, &(mLNleHwInfo), &(pCurNLECtrl->mLBuf));
+ if (dRet == NO_ERROR) {
+#if 0
+ if (pCurNLECtrl->mAudioALSAPlaybackHandlerBase->getHardwareBufferInfo(&stHWBuffer_Time_Info) == NO_ERROR) {
+ UsedFrameCount = stHWBuffer_Time_Info.buffer_per_time - stHWBuffer_Time_Info.frameInfo_get;
+ // ALOGD("UsedFrameCount R %d", UsedFrameCount); - For Debug
+ UsedFrameCount = UsedFrameCount + pCurNLECtrl->mCheckHwExtraFrameCnt;
+ dRet = checkAndSetGain(UsedFrameCount, pCurNLECtrl, &(mRNleHwInfo), &(pCurNLECtrl->mRBuf));
+ if (dRet == NO_ERROR) {
+ ;
+ } else if (dRet == INVALID_OPERATION) {
+ ;
+ } else {
+ ALOGE("[Err] %s %d dRet = %d", __FUNCTION__, __LINE__, dRet);
+ }
+ } else {
+ ALOGVV("2nd getHardwareBufferInfo Null");
+ dRet = INVALID_OPERATION;
+ }
+#else
+ dRet = checkAndSetGain(UsedFrameCount, pCurNLECtrl, &(mRNleHwInfo), &(pCurNLECtrl->mRBuf));
+#endif
+ } else if (dRet == INVALID_OPERATION) {
+ ;
+ } else {
+ ALOGE("[Err] %s %d dRet = %d", __FUNCTION__, __LINE__, dRet);
+ }
+ } else {
+ ALOGVV("1st getHardwareBufferInfo Null");
+ dRet = INVALID_OPERATION;
+ }
+ return dRet;
+}
+
+status_t AudioALSAHyBridNLEManager::getDbFromAnalogIdx(size_t AnalogIdx, int8_t *pDb) {
+ int8_t mDb;
+
+ if (pDb == NULL) {
+ ALOGE("[Err] %s LINE %d", __FUNCTION__, __LINE__);
+ return BAD_VALUE;
+ }
+
+ if ((AnalogIdx > mHwAnalogGainMinValue && AnalogIdx < mHwAnalogGainMuteValue) || AnalogIdx > mHwAnalogGainMuteValue) {
+ ALOGE("[Err] %s LINE %d AnalogIdx %zu Reserved", __FUNCTION__, __LINE__, AnalogIdx);
+ return BAD_VALUE;
+ }
+
+ if (AnalogIdx == mHwAnalogGainMuteValue) {
+ mDb = mHwAnalogGainMuteDb;
+ } else {
+ mDb = mHwAnalogGainMaxDb - (int8_t) AnalogIdx;
+ }
+
+ *pDb = mDb;
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHyBridNLEManager::getAnalogIdx(int8_t Db, size_t *pAnalogIdx) {
+ size_t mAnalogIdx;
+
+ if (pAnalogIdx == NULL) {
+ ALOGE("[Err] %s LINE %d", __FUNCTION__, __LINE__);
+ return BAD_VALUE;
+ }
+
+ if (Db > mHwAnalogGainMaxDb || (Db < mHwAnalogGainMinDb && Db != mHwAnalogGainMuteDb)) {
+ ALOGE("[Err] %s LINE %d Db %d Reserved", __FUNCTION__, __LINE__, Db);
+ return BAD_VALUE;
+ }
+
+ if (Db == mHwAnalogGainMuteDb) {
+ mAnalogIdx = mHwAnalogGainMuteValue;
+ } else {
+ mAnalogIdx = (size_t)(mHwAnalogGainMaxDb - Db);
+ }
+
+ *pAnalogIdx = mAnalogIdx;
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHyBridNLEManager::getDbFromDigitalIdx(size_t DigitalIdx, int8_t *pDb) {
+ int8_t mDb;
+
+ if (pDb == NULL) {
+ ALOGE("[Err] %s LINE %d", __FUNCTION__, __LINE__);
+ return BAD_VALUE;
+ }
+
+ if (DigitalIdx > mHwDigitalGainMaxValue) {
+ ALOGE("[Err] %s LINE %d DigitalIdx %zu Reserved", __FUNCTION__, __LINE__, DigitalIdx);
+ return BAD_VALUE;
+ }
+
+ mDb = DigitalIdx;
+
+ *pDb = mDb;
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHyBridNLEManager::getDigitalIdx(int8_t Db, size_t *pDigitalIdx) {
+ size_t mDigitalIdx;
+
+ if (pDigitalIdx == NULL) {
+ ALOGE("[Err] %s LINE %d", __FUNCTION__, __LINE__);
+ return BAD_VALUE;
+ }
+
+ if (Db < 0 || Db > 0x2C) {
+ ALOGE("[Err] %s LINE %d Db %d Reserved", __FUNCTION__, __LINE__, Db);
+ return BAD_VALUE;
+ }
+
+ mDigitalIdx = Db;
+
+ *pDigitalIdx = mDigitalIdx;
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHyBridNLEManager::gainAllocatePlan(float Spl, size_t ZeroCnt, size_t Zuframecount, NleHwInfo_t *pNleHwInfo) {
+ int32_t Gain_Spl;
+ int32_t mGainNle;
+ int32_t mGainHP;
+ if (Spl > 0.0f || pNleHwInfo == NULL) {
+ ALOGE("[Err] NLE gainAllocatePlan unreasonable %f (should < 0.0f) nleHwInfo = %p", Spl, pNleHwInfo);
+ return BAD_VALUE;
+ }
+ Gain_Spl = (int) Spl;
+ if (Gain_Spl > mGainEop_Db || mGainHP_Db_Max == NLE_SUPPORT_ANA_GAIN_MUTE_DB) {
+ mGainNle = mGainNLE_Db_Min;
+ mGainHP = mGainHP_Db_Max;
+ } else {
+ if ((mGainSop_Db <= Gain_Spl) && (Gain_Spl <= mGainEop_Db)) {
+ mGainNle = mGainEop_Db - Gain_Spl;
+ mGainHP = mGainHP_Db_Max - mGainNle;
+ } else {
+ mGainNle = mGainNLE_Db_Max;
+ mGainHP = mGainHP_Db_Min;
+ }
+ }
+
+ pNleHwInfo->stPrev.mGainNle = pNleHwInfo->stCur.mGainNle;
+ pNleHwInfo->stPrev.mGainHP = pNleHwInfo->stCur.mGainHP;
+ pNleHwInfo->stPrev.mDbpPerStep = pNleHwInfo->stCur.mDbpPerStep;
+ pNleHwInfo->stPrev.mStepPerZC = pNleHwInfo->stCur.mStepPerZC;
+
+ pNleHwInfo->stCur.mGainNle = mGainNle;
+ pNleHwInfo->stCur.mGainHP = mGainHP;
+#if 0
+ if (pNleHwInfo->mChannel == AUDIO_NLE_CHANNEL_L) {
+ ALOGVV("%d->%d", pNleHwInfo->mMaxSPL_Db, Gain_Spl);
+ }
+#endif
+ pNleHwInfo->mMaxSPL_Db = Gain_Spl;
+ pNleHwInfo->mZeroEventCount = ZeroCnt;
+ pNleHwInfo->mLookUpFrameCount = Zuframecount;
+ // mNleHwInfo.stCur.mDbpPerStep ToDo
+ // mNleHwInfo.stCur.mStepPerZC ToDo
+ return NO_ERROR;
+}
+
+status_t AudioALSAHyBridNLEManager::applyGain2Hw(NleHwInfo_t *pNleHwInfo) {
+ status_t dRet = NO_ERROR;
+ if (pNleHwInfo == NULL) {
+ ALOGE("[Err] NLE applyGain2Hw NleHwInfo %p", pNleHwInfo);
+ return BAD_VALUE;
+ }
+
+ if (pNleHwInfo->stCur.mGainNle != pNleHwInfo->stPrev.mGainNle ||
+ pNleHwInfo->stCur.mGainHP != pNleHwInfo->stPrev.mGainHP) {
+
+ if (pNleHwInfo->mChannel == AUDIO_NLE_CHANNEL_L) {
+ ALOGVV("Gain_Spl %d, GainNle %d, GainHP %d ZeroCnt %zu lookup %zu", pNleHwInfo->mMaxSPL_Db, pNleHwInfo->stCur.mGainNle, pNleHwInfo->stCur.mGainHP, pNleHwInfo->mZeroEventCount, pNleHwInfo->mLookUpFrameCount);
+ }
+
+ unsigned char GainConfig[9];
+ GainConfig[0] = pNleHwInfo->mChannel;
+ GainConfig[1] = pNleHwInfo->mZeroEventCount & 0x00ff;
+ GainConfig[2] = (pNleHwInfo->mZeroEventCount >> 8) & 0x00ff;
+ GainConfig[3] = (pNleHwInfo->mZeroEventCount >> 16) & 0x00ff;
+ GainConfig[4] = (pNleHwInfo->mZeroEventCount >> 24) & 0x00ff;
+ GainConfig[5] = (NLE_GAIN_STEP_MAX_DB & 0x00ff);
+ GainConfig[6] = pNleHwInfo->stCur.mGainNle;
+ if (pNleHwInfo->stCur.mGainHP < 0) {
+ GainConfig[7] = 1;
+ GainConfig[8] = (pNleHwInfo->stCur.mGainHP * (-1)) & 0x00ff;
+ } else {
+ GainConfig[7] = 0;
+ GainConfig[8] = pNleHwInfo->stCur.mGainHP & 0x00ff;
+ }
+#ifdef ENABLE_NLE_HW_CONTROL
+ if (mHwSupport) {
+ if (mixer_ctl_set_array(mixer_get_ctl_by_name(mMixer, "Audio_HyBridNLE_SetGain"), (const void *)GainConfig, 9)) {
+ ALOGE("[Errrrrrrrrrrrrrrr] NLE %s %d", __FUNCTION__, __LINE__);
+ return INVALID_OPERATION;
+ }
+ } else {
+ ALOGD("%s Kernel unsupport", __FUNCTION__);
+ }
+#else
+#endif
+ }
+ return dRet;
+}
+
+status_t AudioALSAHyBridNLEManager::resetDefaultGain(NleHwInfo_t *pNleHwInfo) {
+ if (pNleHwInfo == NULL) {
+ ALOGE("[Err] NLE resetDefaultGain NleHwInfo %p", pNleHwInfo);
+ return BAD_VALUE;
+ }
+ audio_nle_channel Channel = pNleHwInfo->mChannel;
+ // ALOGD("%s %p", __FUNCTION__, pNleHwInfo);
+ memset(pNleHwInfo, 0x00, sizeof(NleHwInfo_t));
+ pNleHwInfo->mChannel = Channel;
+ pNleHwInfo->stPrev.mGainNle = NLE_GAIN_UNININIAL_VALUE;
+ pNleHwInfo->stPrev.mGainHP = NLE_GAIN_UNININIAL_VALUE;
+ pNleHwInfo->stCur.mGainNle = mGainNLE_Db_Min;
+ pNleHwInfo->stCur.mGainHP = mGainHP_Db_Max;
+ pNleHwInfo->mMaxValue = NLE_24BIT_NAGATIVE_MAX;
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAHyBridNLEManager::getGstepAndGnum(int32_t SPL_diff, size_t ZeroCnt, int32_t *pdGstep, int32_t *pdGnum) {
+ int32_t dGstep, dGnum;
+ int32_t dTempdGstep, dTempdGnum;
+ size_t absSPL_diff = abs(SPL_diff);
+ if (pdGstep == NULL || pdGnum == NULL || ZeroCnt == 0 || SPL_diff == 0) {
+ ALOGE("[Err] NLE getGstepAndGnum pdGstep %p pdGnum %p ZeroCnt %zu SPL_diff %d", pdGstep, pdGnum, ZeroCnt, SPL_diff);
+ return BAD_VALUE;
+ }
+
+ if (ZeroCnt >= absSPL_diff) {
+ dGstep = 1; // 1dB
+ dGnum = 1; // 1 times
+ } else {
+ dTempdGstep = (absSPL_diff + ZeroCnt) / ZeroCnt;
+ if (dTempdGstep <= NLE_GAIN_STEP_MAX_DB) {
+ dGstep = dTempdGstep;
+ dGnum = 1;
+ } else {
+ dTempdGnum = (dTempdGstep + NLE_GAIN_STEP_MAX_DB) / NLE_GAIN_STEP_MAX_DB;
+ dGstep = NLE_GAIN_STEP_MAX_DB;
+ dGnum = dTempdGnum;
+ }
+ }
+
+ *pdGstep = dGstep - 1;// For Reg mapping
+ *pdGnum = dGnum;
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAHyBridNLEManager::checkAndSetGain(size_t zuframecount, AudioALSANLECtrl *pNleCtrl, NleHwInfo_t *pNleHwInfo, RingBuf *pRingBuf) {
+ status_t dRet;
+ float SPL_Db = 0.0f;
+ size_t Zero_Cnt = 0;
+ if (zuframecount == 0 || pNleCtrl == NULL || pNleHwInfo == NULL || pRingBuf == NULL) {
+ ALOGW("[Warn] zuframecount = %zu, pNleCtrl = %p, pNleHwInfo = %p, pRingBuf = %p %s Line%d ", zuframecount, pNleCtrl, pNleHwInfo, pRingBuf, __FUNCTION__, __LINE__);
+ return INVALID_OPERATION;
+ } else if (pNleCtrl->mMinPreviewFrameCount > zuframecount) {
+ ALOGW("[Warn] zuframecount = %zu, min = %zu, %s Line%d ", zuframecount, pNleCtrl->mMinPreviewFrameCount, __FUNCTION__, __LINE__);
+ //return INVALID_OPERATION; We continue to apply NLE even it has risk that ZCE isn't enough
+ }
+ if (pNleCtrl->mBytePerSample == (sizeof(int32_t))) {
+ dRet = pNleCtrl->getMaxSPLandZeroCnt(pNleHwInfo, pRingBuf, zuframecount, &SPL_Db, &Zero_Cnt, mMax24BitValidValue);
+ } else {
+ dRet = pNleCtrl->getMaxSPLandZeroCnt(pNleHwInfo, pRingBuf, zuframecount, &SPL_Db, &Zero_Cnt, mMax16BitValidValue);
+ }
+
+ if (dRet != NO_ERROR) {
+ ALOGE("[Err] dRet = %d, %s %d ", dRet, __FUNCTION__, __LINE__);
+ return dRet;
+ }
+
+ dRet = gainAllocatePlan(SPL_Db, Zero_Cnt, zuframecount, pNleHwInfo);
+
+ if (dRet != NO_ERROR) {
+ ALOGE("[Err] dRet = %d, %s %d ", dRet, __FUNCTION__, __LINE__);
+ return dRet;
+ }
+
+ dRet = applyGain2Hw(pNleHwInfo);
+
+ if (dRet != NO_ERROR) {
+ ALOGE("[Err] dRet = %d, %s %d ", dRet, __FUNCTION__, __LINE__);
+ return dRet;
+ }
+ return dRet;
+}
+
+AudioALSANLECtrl::AudioALSANLECtrl(playback_handler_t ePlaybackHandlerType, const stream_attribute_t *pStream_Attribute_Source) {
+ if (pStream_Attribute_Source != NULL) {
+ memcpy(&mStreamAttribute, pStream_Attribute_Source, sizeof(mStreamAttribute));
+ mBytePerSample = audio_bytes_per_sample(mStreamAttribute.audio_format);
+ mMinPreviewByte = (mBytePerSample * mStreamAttribute.num_channels * mStreamAttribute.sample_rate * (NLE_SUPPORT_PREVIEW_MS_MIN + NLE_HW_QUEUE_SKIP_ZCE_FRAMECOUNT_MS - NLE_HW_QUEUE_EXTRA_FRAMECOUNT_MS)) / 1000;
+ mHwBufTotalFrame = mStreamAttribute.buffer_size / (mBytePerSample * mStreamAttribute.num_channels);
+ mCheckHwExtraFrameCnt = (mStreamAttribute.sample_rate * NLE_HW_QUEUE_EXTRA_FRAMECOUNT_MS) / 1000;
+ mSkipHwZCEFrameCnt = (mStreamAttribute.sample_rate * NLE_HW_QUEUE_SKIP_ZCE_FRAMECOUNT_MS) / 1000;
+ mMinPreviewFrameCount = ((mStreamAttribute.sample_rate * NLE_SUPPORT_PREVIEW_MS_MIN + 1000) / 1000) + mCheckHwExtraFrameCnt;
+ mPlaybackedFrameCnt = (mStreamAttribute.sample_rate * NLE_HW_QUEUE_EXTRA_FRAMECOUNT_MS) / 1000 - NLE_HW_QUEUE_BUFFER_BEFORE_DAC_FRAMECOUNT;
+ mRamp2ZeroFrameCnt = (mStreamAttribute.sample_rate * NLE_WAIT_NLE_BYPASS_MAX_MS) / 1000;
+ if ((ePlaybackHandlerType >= PLAYBACK_HANDLER_NORMAL) && (1 << ePlaybackHandlerType) & AudioALSAHyBridNLEManager::getSupportRunNLEHandler()) {
+ ALOGD("F 0x%x Dev 0x%x CM 0x%x CN %d SR %d BS %d", mStreamAttribute.audio_format, mStreamAttribute.output_devices, mStreamAttribute.audio_channel_mask, mStreamAttribute.num_channels,
+ mStreamAttribute.sample_rate, mStreamAttribute.buffer_size);
+ ALOGD("MB %zu TB %zu CEF %zu SKZ %zu MPB %zu PBDF %zu Ramp2ZeroFC %zu", mMinPreviewByte, mHwBufTotalFrame, mCheckHwExtraFrameCnt, mSkipHwZCEFrameCnt, mMinPreviewFrameCount, mPlaybackedFrameCnt, mRamp2ZeroFrameCnt);
+ }
+#if 0
+ ALOGD("audio_format 0x%x", mStreamAttribute.audio_format);
+ ALOGD("output_devices 0x%x", mStreamAttribute.output_devices);
+ ALOGD("audio_channel_mask 0x%x", mStreamAttribute.audio_channel_mask);
+ ALOGD("num_channels %d", mStreamAttribute.num_channels);
+ ALOGD("sample_rate %d", mStreamAttribute.sample_rate);
+ ALOGD("byte_per_sample %zu", mBytePerSample);
+ ALOGD("buffer_byte %d", mStreamAttribute.buffer_size);
+ ALOGD("min_preview_byte %zu", mMinPreviewByte);
+ ALOGD("mHwBufTotalFrame %zu", mHwBufTotalFrame);
+ ALOGD("mCheckHwExtraFrameCnt %zu", mCheckHwExtraFrameCnt);
+ ALOGD("mSkipHwZCEFrameCnt %zu", mSkipHwZCEFrameCnt);
+ ALOGD("mMinPreviewFrameCount %zu", mMinPreviewFrameCount);
+ ALOGD("mPlaybackedFrameCnt %zu", mPlaybackedFrameCnt);
+ ALOGD("mRamp2ZeroFrameCnt %zu", mRamp2ZeroFrameCnt);
+#endif
+ } else {
+ memset(&mStreamAttribute, 0, sizeof(mStreamAttribute));
+ mBytePerSample = 0;
+ mMinPreviewByte = 0;
+ mHwBufTotalFrame = 0;
+ mMinPreviewFrameCount = 0;
+ mCheckHwExtraFrameCnt = 0;
+ mSkipHwZCEFrameCnt = 0;
+ mPlaybackedFrameCnt = 0;
+ mRamp2ZeroFrameCnt = 0;
+ }
+ ALOGD("AudioALSANLECtrl ePlaybackHandlerType %d", ePlaybackHandlerType);
+ mAattachPlaybackHandlerType = ePlaybackHandlerType;
+ mAudioALSAPlaybackHandlerBase = NULL;
+ mState = AUDIO_NLE_STATE_NONE;
+ memset(&mLBuf, 0, sizeof(mLBuf));
+ memset(&mRBuf, 0, sizeof(mRBuf));
+}
+
+AudioALSANLECtrl::~AudioALSANLECtrl() {
+ freeResource();
+ ALOGD("~AudioALSANLECtrl ePlaybackHandlerType %d", mAattachPlaybackHandlerType);
+}
+
+status_t AudioALSANLECtrl::checkValidForInit(playback_handler_t ePlaybackHandlerType) {
+ if (mState != AUDIO_NLE_STATE_NONE) {
+ ALOGW("[Warn] NLE init invalid mState [%d]", mState);
+ return INVALID_OPERATION;
+ } else if (!((mStreamAttribute.output_devices == AUDIO_DEVICE_OUT_WIRED_HEADSET) || (mStreamAttribute.output_devices == AUDIO_DEVICE_OUT_WIRED_HEADPHONE))) {
+ ALOGW("[Warn] NLE init fail device 0x%x", mStreamAttribute.output_devices);
+ return BAD_VALUE;
+ } else if ((ePlaybackHandlerType != PLAYBACK_HANDLER_NORMAL) && (ePlaybackHandlerType != PLAYBACK_HANDLER_OFFLOAD) && (ePlaybackHandlerType != PLAYBACK_HANDLER_FAST)
+ && (ePlaybackHandlerType != PLAYBACK_HANDLER_DEEP_BUFFER)) {
+ ALOGW("[Warn] NLE init fail ePlaybackHandlerType %d", ePlaybackHandlerType);
+ return BAD_VALUE;
+ } else if (mStreamAttribute.audio_format != AUDIO_FORMAT_PCM_16_BIT && mStreamAttribute.audio_format != AUDIO_FORMAT_PCM_8_24_BIT) {
+ ALOGW("[Warn] NLE init fail audio_format 0x%x", mStreamAttribute.audio_format);
+ return BAD_VALUE;
+ } else if (mStreamAttribute.audio_channel_mask != AUDIO_CHANNEL_IN_STEREO) {
+ ALOGW("[Warn] NLE init fail audio_channel_mask 0x%x", mStreamAttribute.audio_channel_mask);
+ return BAD_VALUE;
+ } else if (mStreamAttribute.num_channels > NLE_SUPPORT_CH_NUMBER_MAX) {
+ ALOGW("[Warn] NLE init fail num_channels %d", mStreamAttribute.num_channels);
+ return BAD_VALUE;
+ } else if (mStreamAttribute.sample_rate > NLE_SUPPORT_SAMPLING_RATE_MAX) {
+ ALOGW("[Warn] NLE init fail sample_rate %d", mStreamAttribute.sample_rate);
+ return BAD_VALUE;
+ } else if ((mStreamAttribute.buffer_size < mMinPreviewByte) && ((1 << ePlaybackHandlerType) & AudioALSAHyBridNLEManager::getSupportRunNLEHandler())) {
+ ALOGE("[Err] NLE init fail buffer_size %d (Need large than %zu)", mStreamAttribute.buffer_size, mMinPreviewByte);
+ return BAD_VALUE;
+ } else {
+ return NO_ERROR;
+ }
+}
+
+status_t AudioALSANLECtrl::freeResource(void) {
+ if (mLBuf.pBufBase != NULL) {
+ delete [] mLBuf.pBufBase;
+ memset(&mLBuf, 0, sizeof(mLBuf));
+ }
+
+ if (mRBuf.pBufBase != NULL) {
+ delete [] mRBuf.pBufBase;
+ memset(&mRBuf, 0, sizeof(mRBuf));
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSANLECtrl::allocateResource(void) {
+ size_t bufSize = (mStreamAttribute.buffer_size >> 1) + mCheckHwExtraFrameCnt * mBytePerSample;
+ mLBuf.pBufBase = new char[bufSize];
+ if (mLBuf.pBufBase == NULL) {
+ ALOGE("[Err] %s Line %d allocate fail", __FUNCTION__, __LINE__);
+ goto resource_lack;
+ } else {
+ mLBuf.bufLen = bufSize;
+ mLBuf.pRead = mLBuf.pWrite = mLBuf.pBufBase;
+ memset(mLBuf.pBufBase, 0, mLBuf.bufLen);
+ }
+
+ mRBuf.pBufBase = new char[bufSize];
+ if (mRBuf.pBufBase == NULL) {
+ ALOGE("[Err] %s Line %d allocate fail", __FUNCTION__, __LINE__);
+ goto resource_lack;
+ } else {
+ mRBuf.bufLen = bufSize;
+ mRBuf.pRead = mRBuf.pWrite = mRBuf.pBufBase;
+ memset(mRBuf.pBufBase, 0, mRBuf.bufLen);
+ }
+
+ return NO_ERROR;
+resource_lack:
+ freeResource();
+
+ return NO_MEMORY;
+}
+
+size_t AudioALSANLECtrl::writeToEachChannel(void *buffer, size_t Byte) {
+ size_t frame_count = 0;
+ size_t frame_1ch_count = 0;
+ size_t RemainByte = Byte;
+ size_t oneframe_byte = mBytePerSample * mStreamAttribute.num_channels;
+
+ if (mBytePerSample == sizeof(int32_t)) { // 4 Byte
+ int32_t *p32BufSrc = (int32_t *) buffer;
+ int32_t *p32BufDstLwptr = (int32_t *) mLBuf.pWrite;
+ int32_t *p32BufDstRwptr = (int32_t *) mRBuf.pWrite;
+ size_t TailFreeByte = (size_t) mLBuf.bufLen - (size_t)(mLBuf.pWrite - mLBuf.pBufBase);//One Channnel
+ size_t HeadFreeByte = (Byte / mStreamAttribute.num_channels) - TailFreeByte; //One Channnel
+ frame_1ch_count = 0;
+ while (TailFreeByte && RemainByte) {
+ p32BufDstLwptr[frame_1ch_count] = p32BufSrc[(frame_count << 1)];
+ p32BufDstRwptr[frame_1ch_count] = p32BufSrc[(frame_count << 1) + 1];
+ frame_1ch_count++;
+ frame_count++;
+ TailFreeByte = TailFreeByte - mBytePerSample;
+ RemainByte = RemainByte - oneframe_byte;
+ }
+ if (RemainByte) {
+ p32BufDstLwptr = (int32_t *) mLBuf.pBufBase;
+ p32BufDstRwptr = (int32_t *) mRBuf.pBufBase;
+ frame_1ch_count = 0;
+ while (HeadFreeByte) {
+ p32BufDstLwptr[frame_1ch_count] = p32BufSrc[(frame_count << 1)];
+ p32BufDstRwptr[frame_1ch_count] = p32BufSrc[(frame_count << 1) + 1];
+ frame_1ch_count++;
+ frame_count++;
+ HeadFreeByte = HeadFreeByte - mBytePerSample;
+ }
+ }
+ mLBuf.pWrite = ((char *)p32BufDstLwptr) + frame_1ch_count * mBytePerSample;
+ mRBuf.pWrite = ((char *)p32BufDstRwptr) + frame_1ch_count * mBytePerSample;
+
+ } else {
+ int16_t *p16BufSrc = (int16_t *) buffer;
+ int16_t *p16BufDstLwptr = (int16_t *) mLBuf.pWrite;
+ int16_t *p16BufDstRwptr = (int16_t *) mRBuf.pWrite;
+ size_t TailFreeByte = (size_t) mLBuf.bufLen - (size_t)(mLBuf.pWrite - mLBuf.pBufBase);
+ size_t HeadFreeByte = (Byte / mStreamAttribute.num_channels) - TailFreeByte;
+ frame_1ch_count = 0;
+ while (TailFreeByte && RemainByte) {
+ p16BufDstLwptr[frame_1ch_count] = p16BufSrc[(frame_count << 1)];
+ p16BufDstRwptr[frame_1ch_count] = p16BufSrc[(frame_count << 1) + 1];
+ frame_1ch_count++;
+ frame_count++;
+ TailFreeByte = TailFreeByte - mBytePerSample;
+ RemainByte = RemainByte - oneframe_byte;
+ }
+ if (RemainByte) {
+ p16BufDstLwptr = (int16_t *) mLBuf.pBufBase;
+ p16BufDstRwptr = (int16_t *) mRBuf.pBufBase;
+ frame_1ch_count = 0;
+ while (HeadFreeByte) {
+ p16BufDstLwptr[frame_1ch_count] = p16BufSrc[(frame_count << 1)];
+ p16BufDstRwptr[frame_1ch_count] = p16BufSrc[(frame_count << 1) + 1];
+ frame_1ch_count++;
+ frame_count++;
+ HeadFreeByte = HeadFreeByte - mBytePerSample;
+ }
+ }
+ mLBuf.pWrite = ((char *)p16BufDstLwptr) + frame_1ch_count * mBytePerSample;
+ mRBuf.pWrite = ((char *)p16BufDstRwptr) + frame_1ch_count * mBytePerSample;
+ }
+
+ return Byte;
+}
+
+status_t AudioALSANLECtrl::getMaxSPLandZeroCnt(NleHwInfo_t *pNleHwInfo, RingBuf *pRingBuf, size_t zuframecount, float *pSPL_Db, size_t *pZeroCnt, uint32_t maxValidValue) {
+ if (pRingBuf == NULL || zuframecount == 0 || pSPL_Db == NULL || pZeroCnt == NULL || pNleHwInfo == NULL) {
+ ALOGE("[Err] dRet = %d, %s %d ", INVALID_OPERATION, __FUNCTION__, __LINE__);
+ return INVALID_OPERATION;
+ }
+ bool bPrevSignBit = false;
+ size_t zuZeroCount = 0;
+ size_t zuTempZeroCount = 0;
+ size_t zuIndexOfMaxSPL = 0;
+ if (mBytePerSample == sizeof(int32_t)) {
+ uint32_t dMaxSPL = 1;
+ uint32_t dTempSPL = 0;
+ if ((pRingBuf->pBufBase + zuframecount * mBytePerSample) > pRingBuf->pWrite) { //Ring
+ int32_t *p32BufSrc = (int32_t *)(pRingBuf->pWrite + pRingBuf->bufLen - zuframecount * mBytePerSample);
+ size_t cnt1 = (size_t)((pRingBuf->pBufBase + pRingBuf->bufLen) - ((char *)p32BufSrc));
+ cnt1 = cnt1 / mBytePerSample;
+ size_t cnt2 = zuframecount - cnt1;
+ if (cnt1) {
+ if (cnt1 > mSkipHwZCEFrameCnt) {
+ bPrevSignBit = p32BufSrc[0 + mSkipHwZCEFrameCnt] & (1 << 23);
+ }
+ } else {
+ p32BufSrc = (int32_t *) pRingBuf->pBufBase;
+ if (cnt2 > mSkipHwZCEFrameCnt) {
+ bPrevSignBit = p32BufSrc[0 + mSkipHwZCEFrameCnt] & (1 << 23);
+ }
+ }
+ //ALOGD("Base %x, Write %x Len %x Src %x cnt1 %d cnt2 %d t %d", pRingBuf->pBufBase, pRingBuf->pWrite, pRingBuf->bufLen, p32BufSrc, cnt1, cnt2, zuframecount);
+ for (size_t i = 0; i < cnt1; i++) {
+ if (p32BufSrc[i] < 0) {
+ if (i > mSkipHwZCEFrameCnt && bPrevSignBit == false) {
+ bPrevSignBit = true;
+ zuTempZeroCount++;
+ }
+ dTempSPL = abs(p32BufSrc[i]);
+ if (dMaxSPL < dTempSPL) {
+ dMaxSPL = dTempSPL;
+ zuIndexOfMaxSPL = i;
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ if (dMaxSPL >= maxValidValue) {
+ break;
+ }
+ }
+ } else {
+ if (i > mSkipHwZCEFrameCnt && bPrevSignBit == true) {
+ bPrevSignBit = false;
+ zuTempZeroCount++;
+ }
+ dTempSPL = (uint32_t) p32BufSrc[i];
+ if (dMaxSPL < dTempSPL) {
+ dMaxSPL = dTempSPL;
+ zuIndexOfMaxSPL = i;
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ if (dMaxSPL >= maxValidValue) {
+ break;
+ }
+ }
+ }
+ }
+ if (dMaxSPL < maxValidValue) {
+ p32BufSrc = (int32_t *) pRingBuf->pBufBase;
+ for (size_t i = 0; i < cnt2; i++) {
+ if (p32BufSrc[i] < 0) {
+ if (((i + cnt1) > mSkipHwZCEFrameCnt) && bPrevSignBit == false) {
+ bPrevSignBit = true;
+ zuTempZeroCount++;
+ }
+ dTempSPL = abs(p32BufSrc[i]);
+ if (dMaxSPL < dTempSPL) {
+ dMaxSPL = dTempSPL;
+ zuIndexOfMaxSPL = i + cnt1;
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ if (dMaxSPL >= maxValidValue) {
+ break;
+ }
+ }
+ } else {
+ if (((i + cnt1) > mSkipHwZCEFrameCnt) && bPrevSignBit == true) {
+ bPrevSignBit = false;
+ zuTempZeroCount++;
+ }
+ dTempSPL = (uint32_t) p32BufSrc[i];
+ if (dMaxSPL < dTempSPL) {
+ dMaxSPL = dTempSPL;
+ zuIndexOfMaxSPL = i + cnt1;
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ if (dMaxSPL >= maxValidValue) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (zuIndexOfMaxSPL < mPlaybackedFrameCnt) {
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ }
+ if (pNleHwInfo->mMaxValue > dMaxSPL) {
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ }
+ } else {
+ int32_t *p32BufSrc = (int32_t *)(pRingBuf->pWrite - zuframecount * mBytePerSample);
+ if (zuframecount > mSkipHwZCEFrameCnt) {
+ bPrevSignBit = p32BufSrc[0 + mSkipHwZCEFrameCnt] & (1 << 23);
+ }
+ for (size_t i = 0; i < zuframecount; i++) {
+ if (p32BufSrc[i] < 0) {
+ if (i > mSkipHwZCEFrameCnt && bPrevSignBit == false) {
+ bPrevSignBit = true;
+ zuTempZeroCount++;
+ }
+ dTempSPL = abs(p32BufSrc[i]);
+ if (dMaxSPL < dTempSPL) {
+ dMaxSPL = dTempSPL;
+ zuIndexOfMaxSPL = i;
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ if (dMaxSPL >= maxValidValue) {
+ break;
+ }
+ }
+ } else {
+ if (i > mSkipHwZCEFrameCnt && bPrevSignBit == true) {
+ bPrevSignBit = false;
+ zuTempZeroCount++;
+ }
+ dTempSPL = (uint32_t) p32BufSrc[i];
+ if (dMaxSPL < dTempSPL) {
+ dMaxSPL = dTempSPL;
+ zuIndexOfMaxSPL = i;
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ if (dMaxSPL >= maxValidValue) {
+ break;
+ }
+ }
+ }
+ }
+ if (zuIndexOfMaxSPL < mPlaybackedFrameCnt) {
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ }
+ if (pNleHwInfo->mMaxValue > dMaxSPL) {
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ }
+ }
+ if (dMaxSPL >= maxValidValue) {
+ *pSPL_Db = 0; // Don't need to calc log dMaxSPL
+ } else {
+ if (NLE_24BIT_NAGATIVE_MAX == dMaxSPL) {
+ dMaxSPL = NLE_24BIT_POSITIVE_MAX;
+ }
+ pNleHwInfo->mMaxValue = dMaxSPL;
+ float fMaxSPL = ((float) dMaxSPL) / 8388607.0;
+ *pSPL_Db = 20.0 * log10(fMaxSPL); // 8388607 = 2^23 -1;
+ }
+ //ALOGD("dMaxSPL %d %f *SPL_Db %f", dMaxSPL, fMaxSPL, *SPL_Db);
+ } else {
+ uint32_t dMaxSPL = 0;
+ uint16_t dTempSPL = 0;
+ if ((pRingBuf->pBufBase + zuframecount * mBytePerSample) > pRingBuf->pWrite) { //Ring
+ int16_t *p16BufSrc = (int16_t *)(pRingBuf->pWrite + pRingBuf->bufLen - zuframecount * mBytePerSample);
+ size_t cnt1 = (size_t)((pRingBuf->pBufBase + pRingBuf->bufLen) - ((char *)p16BufSrc));
+ cnt1 = cnt1 / mBytePerSample;
+ size_t cnt2 = zuframecount - cnt1;
+ if (cnt1) {
+ if (cnt1 > mSkipHwZCEFrameCnt) {
+ bPrevSignBit = p16BufSrc[0 + mSkipHwZCEFrameCnt] & (1 << 15);
+ }
+ } else {
+ p16BufSrc = (int16_t *) pRingBuf->pBufBase;
+ if (cnt2 > mSkipHwZCEFrameCnt) {
+ bPrevSignBit = p16BufSrc[0 + mSkipHwZCEFrameCnt] & (1 << 15);
+ }
+ }
+ //ALOGD("Base %x, Write %x Len %x Src %x cnt1 %d cnt2 %d t %d", pRingBuf->pBufBase, pRingBuf->pWrite, pRingBuf->bufLen, p32BufSrc, cnt1, cnt2, zuframecount);
+ for (size_t i = 0; i < cnt1; i++) {
+ if (p16BufSrc[i] < 0) {
+ if (i > mSkipHwZCEFrameCnt && bPrevSignBit == false) {
+ bPrevSignBit = true;
+ zuTempZeroCount++;
+ }
+ dTempSPL = abs(p16BufSrc[i]);
+ if (dMaxSPL < dTempSPL) {
+ dMaxSPL = dTempSPL;
+ zuIndexOfMaxSPL = i;
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ if (dMaxSPL >= maxValidValue) {
+ break;
+ }
+ }
+ } else {
+ if (i > mSkipHwZCEFrameCnt && bPrevSignBit == true) {
+ bPrevSignBit = false;
+ zuTempZeroCount++;
+ }
+ dTempSPL = (uint16_t) p16BufSrc[i];
+ if (dMaxSPL < dTempSPL) {
+ dMaxSPL = dTempSPL;
+ zuIndexOfMaxSPL = i;
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ if (dMaxSPL >= maxValidValue) {
+ break;
+ }
+ }
+ }
+ }
+ if (dMaxSPL < maxValidValue) {
+ p16BufSrc = (int16_t *) pRingBuf->pBufBase;
+ for (size_t i = 0; i < cnt2; i++) {
+ if (p16BufSrc[i] < 0) {
+ if (((i + cnt1) > mSkipHwZCEFrameCnt) && bPrevSignBit == false) {
+ bPrevSignBit = true;
+ zuTempZeroCount++;
+ }
+ dTempSPL = abs(p16BufSrc[i]);
+ if (dMaxSPL < dTempSPL) {
+ dMaxSPL = dTempSPL;
+ zuIndexOfMaxSPL = i + cnt1;
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ if (dMaxSPL >= maxValidValue) {
+ break;
+ }
+ }
+ } else {
+ if (((i + cnt1) > mSkipHwZCEFrameCnt) && bPrevSignBit == true) {
+ bPrevSignBit = false;
+ zuTempZeroCount++;
+ }
+ dTempSPL = (uint16_t) p16BufSrc[i];
+ if (dMaxSPL < dTempSPL) {
+ dMaxSPL = dTempSPL;
+ zuIndexOfMaxSPL = i + cnt1;
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ if (dMaxSPL >= maxValidValue) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (zuIndexOfMaxSPL < mPlaybackedFrameCnt) {
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ }
+ if (pNleHwInfo->mMaxValue > dMaxSPL) {
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ }
+ } else {
+ int16_t *p16BufSrc = (int16_t *)(pRingBuf->pWrite - zuframecount * mBytePerSample);
+ if (zuframecount > mSkipHwZCEFrameCnt) {
+ bPrevSignBit = p16BufSrc[0 + mSkipHwZCEFrameCnt] & (1 << 15);
+ }
+ for (size_t i = 0; i < zuframecount; i++) {
+ if (p16BufSrc[i] < 0) {
+ dTempSPL = abs(p16BufSrc[i]);
+ if (i > mSkipHwZCEFrameCnt && bPrevSignBit == false) {
+ bPrevSignBit = true;
+ zuTempZeroCount++;
+ }
+ if (dMaxSPL < dTempSPL) {
+ dMaxSPL = dTempSPL;
+ zuIndexOfMaxSPL = i;
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ if (dMaxSPL >= maxValidValue) {
+ break;
+ }
+ }
+ } else {
+ if (i > mSkipHwZCEFrameCnt && bPrevSignBit == true) {
+ bPrevSignBit = false;
+ zuTempZeroCount++;
+ }
+ dTempSPL = (uint16_t) p16BufSrc[i];
+ if (dMaxSPL < dTempSPL) {
+ dMaxSPL = dTempSPL;
+ zuIndexOfMaxSPL = i;
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ if (dMaxSPL >= maxValidValue) {
+ break;
+ }
+ }
+ }
+ }
+ if (zuIndexOfMaxSPL < mPlaybackedFrameCnt) {
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ }
+ if (pNleHwInfo->mMaxValue > dMaxSPL) {
+ zuZeroCount = zuZeroCount + zuTempZeroCount;
+ zuTempZeroCount = 0;
+ }
+ }
+ if (dMaxSPL >= maxValidValue) {
+ *pSPL_Db = 0; // Don't need to calc log dMaxSPL
+ } else {
+ if (NLE_16BIT_NAGATIVE_MAX == dMaxSPL) {
+ dMaxSPL = NLE_16BIT_POSITIVE_MAX;
+ }
+ pNleHwInfo->mMaxValue = dMaxSPL;
+ *pSPL_Db = 20.0 * log10(dMaxSPL / 32767); // 32767 = 2^15 -1;
+ }
+ }
+ //zuZeroCount = zuZeroCount + zuTempZeroCount; Debug only
+ *pZeroCnt = zuZeroCount;
+ return NO_ERROR;
+}
+
+status_t AudioALSANLECtrl::setMaxSPLintoSpecificPos(size_t zuOffsetForTail) {
+ size_t mIndexOfChangeValue = 0;
+ if (zuOffsetForTail >= mHwBufTotalFrame + mCheckHwExtraFrameCnt) {
+ ALOGE("[Err] %s %zu > %zu + %zu", __FUNCTION__, zuOffsetForTail, mHwBufTotalFrame, mCheckHwExtraFrameCnt);
+ return BAD_VALUE;
+ }
+
+ if ((mLBuf.pBufBase + zuOffsetForTail * mBytePerSample) > mLBuf.pWrite) { //Ring
+ mIndexOfChangeValue = (mLBuf.pWrite - mLBuf.pBufBase + mLBuf.bufLen - zuOffsetForTail * mBytePerSample) / mBytePerSample;
+ } else {
+ mIndexOfChangeValue = (mLBuf.pWrite - mLBuf.pBufBase - zuOffsetForTail * mBytePerSample) / mBytePerSample;
+ }
+
+ if (mIndexOfChangeValue == 0) {
+ mIndexOfChangeValue = mHwBufTotalFrame + mCheckHwExtraFrameCnt - 1;
+ } else {
+ mIndexOfChangeValue = mIndexOfChangeValue - 1;
+ }
+ ALOGVV("mIndexOfChangeValue %zu Of %zu (Write %zu)", mIndexOfChangeValue, mHwBufTotalFrame + mCheckHwExtraFrameCnt, (mLBuf.pWrite - mLBuf.pBufBase) / mBytePerSample);
+
+ if (mStreamAttribute.audio_format == AUDIO_FORMAT_PCM_16_BIT) {
+ int16_t *p16BufSrc = (int16_t *)(mLBuf.pBufBase);
+ p16BufSrc[mIndexOfChangeValue] = NLE_16BIT_POSITIVE_MAX;
+ p16BufSrc = (int16_t *)(mRBuf.pBufBase);
+ p16BufSrc[mIndexOfChangeValue] = NLE_16BIT_POSITIVE_MAX;
+ } else {
+ int32_t *p32BufSrc = (int32_t *)(mLBuf.pBufBase);
+ p32BufSrc[mIndexOfChangeValue] = NLE_24BIT_POSITIVE_MAX;
+ p32BufSrc = (int32_t *)(mRBuf.pBufBase);
+ p32BufSrc[mIndexOfChangeValue] = NLE_24BIT_POSITIVE_MAX;
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSANLECtrl::init(AudioALSAPlaybackHandlerBase *pPlaybackHandler) {
+ status_t eRet;
+
+ AL_AUTOLOCK(mLock);
+
+ eRet = checkValidForInit(mAattachPlaybackHandlerType);
+ if (eRet != NO_ERROR) {
+ return eRet;
+ }
+
+ eRet = allocateResource();
+ if (eRet != NO_ERROR) {
+ return eRet;
+ }
+
+ if (mStreamAttribute.audio_format == AUDIO_FORMAT_PCM_16_BIT) {
+ int16_t *p16BufSrc = (int16_t *)(mLBuf.pBufBase);
+ p16BufSrc[mHwBufTotalFrame + mCheckHwExtraFrameCnt - 1] = NLE_16BIT_POSITIVE_MAX;
+ p16BufSrc = (int16_t *)(mRBuf.pBufBase);
+ p16BufSrc[mHwBufTotalFrame + mCheckHwExtraFrameCnt - 1] = NLE_16BIT_POSITIVE_MAX;
+ } else {
+ int32_t *p32BufSrc = (int32_t *)(mLBuf.pBufBase);
+ p32BufSrc[mHwBufTotalFrame + mCheckHwExtraFrameCnt - 1] = NLE_24BIT_POSITIVE_MAX;
+ p32BufSrc = (int32_t *)(mRBuf.pBufBase);
+ p32BufSrc[mHwBufTotalFrame + mCheckHwExtraFrameCnt - 1] = NLE_24BIT_POSITIVE_MAX;
+ }
+
+ mAudioALSAPlaybackHandlerBase = pPlaybackHandler;
+
+ mState = AUDIO_NLE_STATE_INITIALIZED;
+
+ return NO_ERROR;
+}
+
+status_t AudioALSANLECtrl::deinit(void) {
+ AL_AUTOLOCK(mLock);
+
+ if (mState == AUDIO_NLE_STATE_NONE) {
+ //ALOGE("[Err] NLE deinit invalid mState [%d]", mState);
+ return INVALID_OPERATION;
+ }
+
+ freeResource();
+
+ mState = AUDIO_NLE_STATE_NONE;
+
+ return NO_ERROR;
+}
+
+size_t AudioALSANLECtrl::process(void *buffer, size_t Byte) {
+ size_t dWriteByte = 0;
+ status_t eRet;
+
+ AL_AUTOLOCK(mLock);
+
+ if (mState == AUDIO_NLE_STATE_NONE) {
+ //ALOGE("[Err] NLE process invalid mState [%d]", mState);
+ return 0;
+ }
+
+ if (buffer == NULL || Byte > mStreamAttribute.buffer_size) {
+ ALOGE("[Err] NLE process buffer [0x%p] size [%zu] (should be less than [%d])", buffer, Byte, mStreamAttribute.buffer_size);
+ return 0;
+ }
+
+ if (mState == AUDIO_NLE_STATE_INITIALIZED) {
+ mState = AUDIO_NLE_STATE_FIRST_WRITE;
+ } else if (mState == AUDIO_NLE_STATE_FIRST_WRITE) {
+ mState = AUDIO_NLE_STATE_RUNNING;
+ }
+
+ return writeToEachChannel(buffer, Byte);
+}
+
+#else
+AudioALSAHyBridNLEManager::AudioALSAHyBridNLEManager() {
+ mGainHP_Db_Max = NLE_GAIN_HP_DB_USER;
+ mGainHP_Db_Min = NLE_GAIN_HP_DB_MIN;
+ mGainNLE_Db_Min = NLE_GAIN_NLE_DB_MIN;
+ mGainEop_Db = NLE_GAIN_EOP_DB;
+ mGainNLE_Db_Max = mGainHP_Db_Max - mGainHP_Db_Min;
+ mGainSop_Db = mGainEop_Db - mGainNLE_Db_Max;
+ mStatus = AUDIO_HYBRID_NLE_MNG_STATE_DISABLE;
+ mActivePBHandler = PLAYBACK_HANDLER_BASE;
+ mActivePBHandlerBitwise = 0;
+ mInitPBHandlerBitwise = 0;
+ memset(&mLNleHwInfo, 0, sizeof(mLNleHwInfo));
+ memset(&mRNleHwInfo, 0, sizeof(mRNleHwInfo));
+ mMode = AUDIO_MODE_NORMAL;
+ memset(&mNleCtrlOfPlaybackHandler[0], 0, sizeof(AudioALSANLECtrl *)*PLAYBACK_HANDLER_MAX);
+ mNleCtrlOfPlaybackHandlerCounter = 0;
+ mHwPathStreamCounter = 0;
+ mBypassNLE = false;
+ mNleSwitch = false;
+ mMixer = NULL;
+ mHwAnalogGainMaxDb = NLE_GAIN_HP_DB_MAX;
+ mHwAnalogGainMinDb = NLE_GAIN_HP_DB_MIN;
+ mHwAnalogGainMinValue = NLE_GAIN_HP_VALUE_MIN;
+ mHwAnalogGainMuteDb = NLE_SUPPORT_ANA_GAIN_MUTE_DB;
+ mHwAnalogGainMuteValue = NLE_SUPPORT_ANA_GAIN_MUTE_VALUE;
+ mHwDigitalGainMaxDb = NLE_GAIN_NLE_DB_MAX;
+ mHwDigitalGainMaxValue = NLE_GAIN_NLE_VALUE_MAX;
+ mHwDigitalgGainMinDb = NLE_GAIN_NLE_DB_MIN;
+ mHwAnalogDelayTick = NLE_DELAY_ANA_OUTPUT_T;
+ mHwSupport = false;
+ mSetEopByProp = false;
+ mForceTurnOffNLE = false;
+ mMax24BitValidValue = NLE_24BIT_POSITIVE_MAX;
+ mMax16BitValidValue = NLE_16BIT_POSITIVE_MAX;
+}
+
+
+status_t AudioALSAHyBridNLEManager::setNleHwConfigByDb(int hpMaxGainDb __unused, int eopGainDb __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::setNleHwConfigByIndex(size_t hpMaxGainIdx __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::getNleHwConfigByDb(int *hpMaxGainDb __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::getNleHwConfigByIndex(size_t *hpMaxGainIdx __unused) {
+ return INVALID_OPERATION;
+}
+
+audio_hybridnlemng_status AudioALSAHyBridNLEManager::getStatus(void) {
+ return AUDIO_HYBRID_NLE_MNG_STATE_DISABLE;
+}
+
+status_t AudioALSAHyBridNLEManager::initPlayBackHandler(playback_handler_t ePlaybackHandlerType __unused, stream_attribute_t *pStreamAttribute __unused, AudioALSAPlaybackHandlerBase *pPlaybackHandler __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::deinitPlayBackHandler(playback_handler_t ePlaybackHandlerType __unused) {
+ return INVALID_OPERATION;
+}
+status_t AudioALSAHyBridNLEManager::process(playback_handler_t ePlaybackHandlerType __unused, void *buffer __unused, size_t Byte __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::setBypassNLE(bool bBypass __unused) {
+ return INVALID_OPERATION;
+}
+
+bool AudioALSAHyBridNLEManager::getBypassNLE(void) {
+ return true;
+}
+
+status_t AudioALSAHyBridNLEManager::setEnableNLE(bool bEnable __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::dump(void) {
+ return INVALID_OPERATION;
+}
+
+uint32_t AudioALSAHyBridNLEManager::getSupportRunNLEHandler(void) {
+ return mSupportRunNLEHandlerBitwise;
+}
+
+status_t AudioALSAHyBridNLEManager::setSupportRunNLEHandler(playback_handler_t eHandler __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::setNleEopDb(int eopGainDb __unused) {
+ return INVALID_OPERATION;
+}
+
+int AudioALSAHyBridNLEManager::getNleEopDb(void) {
+ return -96;
+}
+
+status_t AudioALSAHyBridNLEManager::setAudioMode(audio_mode_t eMode __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::addHwPathStream(audio_stream_hw_path eHwPath __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::removeHwPathStream(audio_stream_hw_path eHwPath __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::updateCurStatus(void) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::enableNleHw(void) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::disableNleHw(void) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::ramp2DigitalGainZero(void) {
+ return INVALID_OPERATION;
+}
+
+bool AudioALSAHyBridNLEManager::checkIfGainTargeted(void) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::waitForBypass(audio_hybridnlemng_status ePrevStatus __unused, audio_hybridnlemng_status eCurStatus __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::doAdjustGainProcess(AudioALSANLECtrl *pCurNLECtrl __unused, size_t zuCheckOffsetFrameCnt __unused, audio_hybrid_adjust_mode eAdjustMode __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::getDbFromAnalogIdx(size_t AnalogIdx __unused, int8_t *pDb __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::getAnalogIdx(int8_t Db __unused, size_t *pAnalogIdx __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::getDbFromDigitalIdx(size_t DigitalIdx __unused, int8_t *pDb __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::getDigitalIdx(int8_t Db __unused, size_t *pDigitalIdx __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::gainAllocatePlan(float Spl __unused, size_t ZeroCnt __unused, size_t Zuframecount __unused, NleHwInfo_t *pNleHwInfo __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::applyGain2Hw(NleHwInfo_t *pNleHwInfo __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::resetDefaultGain(NleHwInfo_t *pNleHwInfo __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::getGstepAndGnum(int32_t SPL_diff __unused, size_t ZeroCnt __unused, int32_t *pdGstep __unused, int32_t *pdGnum __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAHyBridNLEManager::checkAndSetGain(size_t zuframecount __unused, AudioALSANLECtrl *pNleCtrl __unused, NleHwInfo_t *pNleHwInfo __unused, RingBuf *pRingBuf __unused) {
+ return INVALID_OPERATION;
+}
+
+AudioALSANLECtrl::AudioALSANLECtrl(playback_handler_t ePlaybackHandlerType __unused, const stream_attribute_t *pStream_Attribute_Source __unused) {
+ memset(&mStreamAttribute, 0, sizeof(mStreamAttribute));
+ mBytePerSample = 0;
+ mMinPreviewByte = 0;
+ mHwBufTotalFrame = 0;
+ mMinPreviewFrameCount = 0;
+ mCheckHwExtraFrameCnt = 0;
+ mSkipHwZCEFrameCnt = 0;
+ mPlaybackedFrameCnt = 0;
+ mRamp2ZeroFrameCnt = 0;
+ mAattachPlaybackHandlerType = PLAYBACK_HANDLER_BASE;
+ mAudioALSAPlaybackHandlerBase = NULL;
+ mState = AUDIO_NLE_STATE_NONE;
+ memset(&mLBuf, 0, sizeof(mLBuf));
+ memset(&mRBuf, 0, sizeof(mRBuf));
+}
+
+AudioALSANLECtrl::~AudioALSANLECtrl() {
+}
+
+status_t AudioALSANLECtrl::checkValidForInit(playback_handler_t ePlaybackHandlerType __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSANLECtrl::freeResource(void) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSANLECtrl::allocateResource(void) {
+ return INVALID_OPERATION;
+}
+
+size_t AudioALSANLECtrl::writeToEachChannel(void *buffer __unused, size_t Byte __unused) {
+ return 0;
+}
+
+status_t AudioALSANLECtrl::getMaxSPLandZeroCnt(NleHwInfo_t *pNleHwInfo __unused, RingBuf *pRingBuf __unused, size_t zuframecount __unused, float *pSPL_Db __unused, size_t *pZeroCnt __unused, uint32_t maxValidValue __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSANLECtrl::setMaxSPLintoSpecificPos(size_t zuOffsetForTail __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSANLECtrl::init(AudioALSAPlaybackHandlerBase *pPlaybackHandler __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSANLECtrl::deinit(void) {
+ return INVALID_OPERATION;
+}
+
+size_t AudioALSANLECtrl::process(void *buffer, size_t Byte) {
+ return writeToEachChannel(buffer, Byte);
+}
+#endif
+
+}
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAParamTuner.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAParamTuner.cpp
new file mode 100644
index 0000000..bd434d5
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAParamTuner.cpp
@@ -0,0 +1,1930 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*******************************************************************************
+ *
+ * Filename:
+ * ---------
+ * AudioALSAParamTuner.cpp
+ *
+ * Project:
+ * --------
+ * Android
+ *
+ * Description:
+ * ------------
+ * This file implements the method for handling param tuning.
+ *
+ * Author:
+ * -------
+ * Donglei Ji (mtk80823)
+ *******************************************************************************/
+
+#define MTK_LOG_ENABLE 1
+#include <unistd.h>
+#include <sched.h>
+#include <sys/prctl.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <log/log.h>
+#include <system/audio.h>
+
+#include "AudioALSAParamTuner.h"
+#include "AudioCustParamClient.h"
+
+#include "AudioVolumeFactory.h"
+//#include "AudioAnalogControlFactory.h"
+//#include "AudioDigitalControlFactory.h"
+#include "SpeechEnhancementController.h"
+#include "SpeechDriverInterface.h"
+#if defined(MTK_AUDIO_GAIN_TABLE) && !defined(MTK_NEW_VOL_CONTROL)
+#include "AudioMTKVolumeCapability.h"
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+//#define PLAYBUF_SIZE 6400l
+#define PLAYBUF_SIZE 16384
+#define A2M_SHARED_BUFFER_OFFSET (1408)
+#define WAV_HEADER_SIZE 44
+
+// define in AudioMtkVolumeControler.cpp
+#define AUDIO_BUFFER_HW_GAIN_STEP (13)
+
+#undef WRITE_RECORDDATA_ON_APSIDEDMNR
+
+#define LOG_TAG "AudioALSAParamTuner"
+namespace android {
+//digital gain map
+static const float Volume_Mapping_Step = 256.0f;
+uint32_t MapVoiceVolumetoCustom(uint32_t gain) {
+ uint32_t mappingGain = 0;
+ if (gain > VOICE_VOLUME_MAX) {
+ gain = VOICE_VOLUME_MAX;
+ }
+
+ float degradeDb = ((float)(VOICE_VOLUME_MAX - gain)) / (float)(VOICE_ONEDB_STEP);
+ mappingGain = (uint32)(Volume_Mapping_Step - ((uint32)(degradeDb * 4.0)));
+ ALOGD("%s(), gain:%d, mappingGain:%d", __FUNCTION__, gain, mappingGain);
+
+ return mappingGain;
+}
+
+const uint16_t digitOnly_quater_dB_tableForSpeech[264] = {
+ 4096, 3980, 3867, 3757, /* 0 ~ -0.75 dB*/
+ 3645, 3547, 3446, 3349, /* -1 ~ -1.75 dB*/ // downlink begin (-1db == 3645 == E3D)
+ 3254, 3161, 3072, 2984, /* -2 ~ -2.75 dB*/
+ 2900, 2817, 2738, 2660, /* -3 ~ -3.75 dB*/
+ 2584, 2511, 2440, 2371, /* -4 ~ -4.75 dB*/
+ 2303, 2238, 2175, 2113, /* -5 ~ -5.75 dB*/
+ 2053, 1995, 1938, 1883, /* -6 ~ -6.75 dB*/
+ 1830, 1778, 1727, 1678, /* -7 ~ -7.75 dB*/
+ 1631, 1584, 1539, 1496, /* -8 ~ -8.75 dB*/
+ 1453, 1412, 1372, 1333, /* -9 ~ -9.75 dB*/
+ 1295, 1259, 1223, 1188, /* -10 ~ -10.75 dB*/
+ 1154, 1122, 1090, 1059, /* -11 ~ -11.75 dB*/
+ 1029, 1000, 971, 944, /* -12 ~ -12.75 dB*/
+ 917, 891, 866, 841, /* -13 ~ -13.75 dB*/
+ 817, 794, 772, 750, /* -14 ~ -14.75 dB*/
+ 728, 708, 688, 668, /* -15 ~ -15.75 dB*/
+ 649, 631, 613, 595, /* -16 ~ -16.75 dB*/
+ 579, 562, 546, 531, /* -17 ~ -17.75 dB*/
+ 516, 501, 487, 473, /* -18 ~ -18.75 dB*/
+ 460, 447, 434, 422, /* -19 ~ -19.75 dB*/
+ 410, 398, 387, 376, /* -20 ~ -20.75 dB*/
+ 365, 355, 345, 335, /* -21 ~ -21.75 dB*/
+ 325, 316, 307, 298, /* -22 ~ -22.75 dB*/
+ 290, 282, 274, 266, /* -23 ~ -23.75 dB*/
+ 258, 251, 244, 237, /* -24 ~ -24.75 dB*/
+ 230, 224, 217, 211, /* -25 ~ -25.75 dB*/
+ 205, 199, 194, 188, /* -26 ~ -26.75 dB*/
+ 183, 178, 173, 168, /* -27 ~ -27.75 dB*/
+ 163, 158, 154, 150, /* -28 ~ -28.75 dB*/
+ 145, 141, 137, 133, /* -29 ~ -29.75 dB*/
+ 130, 126, 122, 119, /* -30 ~ -30.75 dB*/
+ 115, 112, 109, 106, /* -31 ~ -31.75 dB*/
+ 103, 100, 97, 94, /* -32 ~ -32.75 dB*/
+ 92, 89, 87, 84, /* -33 ~ -33.75 dB*/
+ 82, 79, 77, 75, /* -34 ~ -34.75 dB*/
+ 73, 71, 69, 67, /* -35 ~ -35.75 dB*/
+ 65, 63, 61, 60, /* -36 ~ -36.75 dB*/
+ 58, 56, 55, 53, /* -37 ~ -37.75 dB*/
+ 52, 50, 49, 47, /* -38 ~ -38.75 dB*/
+ 46, 45, 43, 42, /* -39 ~ -39.75 dB*/
+ 41, 40, 39, 38, /* -40 ~ -40.75 dB*/
+ 37, 35, 34, 33, /* -41 ~ -41.75 dB*/
+ 33, 32, 31, 30, /* -42 ~ -42.75 dB*/
+ 29, 28, 27, 27, /* -43 ~ -43.75 dB*/
+ 26, 25, 24, 24, /* -44 ~ -44.75 dB*/
+ 23, 22, 22, 21, /* -45 ~ -45.75 dB*/
+ 21, 20, 19, 19, /* -46 ~ -46.75 dB*/
+ 18, 18, 17, 17, /* -47 ~ -47.75 dB*/
+ 16, 16, 15, 15, /* -48 ~ -48.75 dB*/
+ 15, 14, 14, 13, /* -49 ~ -49.75 dB*/
+ 13, 13, 12, 12, /* -50 ~ -50.75 dB*/
+ 12, 11, 11, 11, /* -51 ~ -51.75 dB*/
+ 10, 10, 10, 9, /* -52 ~ -52.75 dB*/
+ 9, 9, 9, 8, /* -53 ~ -53.75 dB*/
+ 8, 8, 8, 7, /* -54 ~ -54.75 dB*/
+ 7, 7, 7, 7, /* -55 ~ -55.75 dB*/
+ 6, 6, 6, 6, /* -56 ~ -56.75 dB*/
+ 6, 6, 5, 5, /* -57 ~ -57.75 dB*/
+ 5, 5, 5, 5, /* -58 ~ -58.75 dB*/
+ 5, 4, 4, 4, /* -59 ~ -59.75 dB*/
+ 4, 4, 4, 4, /* -60 ~ -60.75 dB*/
+ 4, 4, 3, 3, /* -61 ~ -61.75 dB*/
+ 3, 3, 3, 3, /* -62 ~ -62.75 dB*/
+ 3, 3, 3, 3, /* -63 ~ -63.75 dB*/
+ 3, 3, 2, 2, /* -64 ~ -64.75 dB*/
+ 2, 2, 2, 2, /* -65 ~ -65.75 dB*/
+};
+
+static void *Play_PCM_With_SpeechEnhance_Routine(void *arg) {
+
+ ALOGD("%s(), Play_PCM_With_SpeechEnhance_Routine in +", __FUNCTION__);
+ AudioALSAParamTuner *pAUDParamTuning = (AudioALSAParamTuner *)arg;
+
+ if (pAUDParamTuning == NULL) {
+ ALOGE("%s(), Play_PCM_With_SpeechEnhance_Routine pAUDParamTuning = NULL", __FUNCTION__);
+ return 0;
+ }
+
+ char *tmp = new char[PLAYBUF_SIZE];
+
+ if (tmp == NULL) {
+ ALOGE("%s(), Allocate tmp size = %d Fail", __FUNCTION__, PLAYBUF_SIZE);
+ ASSERT(0);
+ return 0;
+ }
+#if defined(SPH_SR32K)||defined(SPH_SR48K)
+ uint32_t PCM_BUF_SIZE = 1280;
+#else
+ uint32_t PCM_BUF_SIZE = pAUDParamTuning->m_bWBMode ? 640 : 320;
+#endif
+ unsigned long sleepTime = ((PLAYBUF_SIZE / PCM_BUF_SIZE) * 20 * 1000) >> 1;
+
+ // open AudioRecord
+ pthread_mutex_lock(&pAUDParamTuning->mPPSMutex);
+
+ // Adjust thread priority
+ prctl(PR_SET_NAME, (unsigned long)"PlaybackWithSphEnRoutine", 0, 0, 0);
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+ //Prepare file pointer
+ FILE *pFd = pAUDParamTuning->m_pInputFile; //file for input
+
+ // ----start the loop --------
+ pAUDParamTuning->m_bPPSThreadExit = false;
+
+ int numOfBytesPlayed = 0;
+ int playBufFreeCnt = 0;
+ int cntR = 0;
+
+ if (pFd != NULL) {
+ cntR = fread(tmp, sizeof(char), WAV_HEADER_SIZE, pFd);
+ if (cntR != WAV_HEADER_SIZE) {
+ ALOGE("%s(), read WAV Fail!!! bytes Read(%d) < Header Size(%d)", __FUNCTION__, cntR, WAV_HEADER_SIZE);
+ }
+ memset(tmp, 0, PLAYBUF_SIZE);
+ }
+ ALOGD("%s(), pthread_cond_signal(&pAUDParamTuning->mPPSExit_Cond), buffer size=%d, sleepTime=%lu us", __FUNCTION__, PCM_BUF_SIZE, sleepTime);
+ pthread_cond_signal(&pAUDParamTuning->mPPSExit_Cond); // wake all thread
+ pthread_mutex_unlock(&pAUDParamTuning->mPPSMutex);
+
+ while ((!pAUDParamTuning->m_bPPSThreadExit) && pFd) {
+ pthread_mutex_lock(&pAUDParamTuning->mPlayBufMutex);
+ playBufFreeCnt = pAUDParamTuning->mPlay2WayInstance->GetFreeBufferCount();
+ cntR = fread(tmp, sizeof(char), playBufFreeCnt, pFd);
+ pAUDParamTuning->mPlay2WayInstance->Write(tmp, cntR);
+ numOfBytesPlayed += cntR;
+ ALOGD("%s(), Playback buffer, free:%d, read from :%d, total play:%d", __FUNCTION__, playBufFreeCnt, cntR, numOfBytesPlayed);
+ pthread_mutex_unlock(&pAUDParamTuning->mPlayBufMutex);
+
+ if (cntR < playBufFreeCnt) {
+ ALOGD("%s(), File reach the end", __FUNCTION__);
+ usleep(sleepTime); ////wait to all data is played
+ break;
+ }
+ usleep(sleepTime);
+ }
+ if (tmp != NULL) {
+ // free buffer
+ delete[] tmp;
+ tmp = NULL;
+ }
+ if (!pAUDParamTuning->m_bPPSThreadExit) {
+ pAUDParamTuning->m_bPPSThreadExit = true;
+ pAUDParamTuning->enableModemPlaybackVIASPHPROC(false);
+ AudioTasteTuningStruct sRecoveryParam;
+ sRecoveryParam.slected_fir_index = 0;
+ sRecoveryParam.cmd_type = (unsigned short)AUD_TASTE_STOP;
+ sRecoveryParam.wb_mode = pAUDParamTuning->m_bWBMode;
+ sRecoveryParam.phone_mode = pAUDParamTuning->mMode;//current mode, not support switch mode during audio taste
+
+ pAUDParamTuning->updataOutputFIRCoffes(&sRecoveryParam);
+ }
+
+ //exit thread
+ ALOGD("%s(), pthread_mutex_lock", __FUNCTION__);
+ pthread_mutex_lock(&pAUDParamTuning->mPPSMutex);
+ ALOGD("%s(), pthread_cond_signal(&pAUDParamTuning->mPPSExit_Cond)", __FUNCTION__);
+ pthread_cond_signal(&pAUDParamTuning->mPPSExit_Cond); // wake all thread
+ pthread_mutex_unlock(&pAUDParamTuning->mPPSMutex);
+ return 0;
+}
+
+
+#ifdef DMNR_TUNNING_AT_MODEMSIDE
+static void *DMNR_Play_Rec_Routine(void *arg) {
+ ALOGD("+%s()", __FUNCTION__);
+ AudioALSAParamTuner *pDMNRTuning = (AudioALSAParamTuner *)arg;
+ if (pDMNRTuning == NULL) {
+ ALOGE("%s(), pDMNRTuning = NULL arg = %x", __FUNCTION__, arg);
+ return 0;
+ }
+#if defined(SPH_SR32K)||defined(SPH_SR48K)
+ uint32_t PCM_BUF_SIZE = 1280;
+#else
+ uint32_t PCM_BUF_SIZE = pDMNRTuning->m_bWBMode ? 640 : 320;
+#endif
+ unsigned long sleepTime = ((PLAYBUF_SIZE / PCM_BUF_SIZE) * 20 * 1000) >> 1;
+
+ pthread_mutex_lock(&pDMNRTuning->mRecPlayMutex);
+
+ // Adjust thread priority
+ prctl(PR_SET_NAME, (unsigned long)"DualMicCalibrationRoutine", 0, 0, 0);
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+
+ //Prepare file pointer
+ FILE *pInFp = pDMNRTuning->m_pInputFile; //file for input
+ FILE *pOutFp = pDMNRTuning->m_pOutputFile; //file for input
+
+ // ----start the loop --------
+ char *tmp = new char[PLAYBUF_SIZE];
+ pDMNRTuning->m_bRecPlayThreadExit = false;
+ int cntR = 0;
+ int cntW = 0;
+ int numOfBytesPlay = 0;
+ int numOfBytesRec = 0;
+
+ int playBufFreeCnt = 0;
+ int recBufDataCnt = 0;
+
+ ALOGD("%s(), pthread_cond_signal(&pDMNRTuning->mRecPlayExit_Cond)", __FUNCTION__);
+ pthread_cond_signal(&pDMNRTuning->mRecPlayExit_Cond); // wake all thread
+ pthread_mutex_unlock(&pDMNRTuning->mRecPlayMutex);
+
+ while ((!pDMNRTuning->m_bRecPlayThreadExit) && pOutFp) {
+ //handling playback buffer
+ pthread_mutex_lock(&pDMNRTuning->mPlayBufMutex);
+ if (pInFp) {
+ playBufFreeCnt = pDMNRTuning->mPlay2WayInstance->GetFreeBufferCount() - 8;
+ cntR = fread(tmp, sizeof(char), playBufFreeCnt, pInFp);
+ pDMNRTuning->mPlay2WayInstance->Write(tmp, cntR);
+ numOfBytesPlay += cntR;
+ ALOGD("%s(), Playback buffer, free:%d, read from :%d, total play:%d, sleepTime=%lld us", __FUNCTION__, playBufFreeCnt, cntR, numOfBytesPlay, sleepTime);
+ }
+ pthread_mutex_unlock(&pDMNRTuning->mPlayBufMutex);
+
+ // handling record buffer
+ pthread_mutex_lock(&pDMNRTuning->mRecBufMutex);
+ recBufDataCnt = pDMNRTuning->mRec2WayInstance->GetBufferDataCount();
+ pDMNRTuning->mRec2WayInstance->Read(tmp, recBufDataCnt);
+ cntW = fwrite((void *)tmp, sizeof(char), recBufDataCnt, pOutFp);
+ numOfBytesRec += cntW;
+ ALOGV("%s(), Record buffer, available:%d, write to file:%d, total rec:%d", __FUNCTION__, recBufDataCnt, cntW, numOfBytesRec);
+ pthread_mutex_unlock(&pDMNRTuning->mRecBufMutex);
+
+ usleep(sleepTime);
+ }
+
+ // free buffer
+ delete[] tmp;
+ tmp = NULL;
+
+ //exit thread
+ ALOGD("%s(), pthread_mutex_lock", __FUNCTION__);
+ pthread_mutex_lock(&pDMNRTuning->mRecPlayMutex);
+ ALOGD("%s(), pthread_cond_signal(&mRecPlayExit_Cond)", __FUNCTION__);
+ pthread_cond_signal(&pDMNRTuning->mRecPlayExit_Cond); // wake all thread
+ pthread_mutex_unlock(&pDMNRTuning->mRecPlayMutex);
+
+ return 0;
+}
+#else
+static int PCM_decode_data(WAVEHDR *wavHdr, char *in_buf, int block_size, char *out_buf, int *out_size) {
+ int i = 0, j = 0;
+ uint16_t *ptr_d;
+ uint8_t *ptr_s;
+ int readlen = 0;
+ int writelen = 0;
+
+ uint16_t channels = wavHdr->NumChannels;
+ uint16_t bits_per_sample = wavHdr->BitsPerSample;
+
+ ptr_s = (uint8_t *)in_buf;
+ ptr_d = (uint16_t *)out_buf;
+ readlen = block_size;
+ *out_size = 0;
+
+ switch (bits_per_sample) {
+ case 8:
+ if (channels == 2) {
+ for (i = 0; i < readlen; i++) {
+ *(ptr_d + j) = (uint16_t)(*(ptr_s + i) - 128) << 8;
+ j++;
+ }
+ } else {
+ for (i = 0; i < readlen; i++) {
+ *(ptr_d + j) = (uint16_t)(*(ptr_s + i) - 128) << 8;
+ *(ptr_d + j + 1) = *(ptr_d + j);
+ j += 2;
+ }
+ }
+ writelen = (j << 1);
+ break;
+ case 16:
+ if (channels == 2) {
+ for (i = 0; i < readlen; i += 2) {
+ *(ptr_d + j) = *(ptr_s + i) + ((uint16_t)(*(ptr_s + i + 1)) << 8);
+ j++;
+ }
+ } else {
+ for (i = 0; i < readlen; i += 2) {
+ *(ptr_d + j) = *(ptr_s + i) + ((uint16_t)(*(ptr_s + i + 1)) << 8);
+ *(ptr_d + j + 1) = *(ptr_d + j);
+ j += 2;
+ }
+ }
+ writelen = (j << 1);
+ break;
+ default:
+ ptr_d = (uint16_t *)(out_buf);
+ break;
+ }
+ *out_size = writelen;
+ return true;
+}
+static void PCM_Apply_DigitalDb(char *out_buf, int out_size, int table_index) {
+ short *pcmValue = (short *)out_buf;
+ for (int i = 0; i < out_size / 2; i++) {
+ *pcmValue = *pcmValue * (digitOnly_quater_dB_tableForSpeech[4 * table_index] / 4096.0);
+ pcmValue ++;
+ }
+}
+static void *DMNR_Play_Rec_ApSide_Routine(void *arg) {
+ ALOGD("+%s()", __FUNCTION__);
+ AudioALSAParamTuner *pDMNRTuning = (AudioALSAParamTuner *)arg;
+ if (pDMNRTuning == NULL) {
+ ALOGE("%s(), pDMNRTuning = NULL", __FUNCTION__);
+ return 0;
+ }
+
+ pthread_mutex_lock(&pDMNRTuning->mRecPlayMutex);
+
+ // Adjust thread priority
+ prctl(PR_SET_NAME, (unsigned long)"DualMicCalibrationAtApSideRoutine", 0, 0, 0);
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+
+ //Prepare file pointer
+ FILE *pInFp = pDMNRTuning->m_pInputFile; //file for input(use audiomtkstreamout to play)
+ FILE *pOutFp = pDMNRTuning->m_pOutputFile; //file for output(use audiomtkstreamin to record)
+
+ // ----start the loop --------
+ pDMNRTuning->m_bRecPlayThreadExit = false;
+
+ ALOGD("%s(), pthread_cond_signal(&pDMNRTuning->mRecPlayExit_Cond)", __FUNCTION__);
+ pthread_cond_signal(&pDMNRTuning->mRecPlayExit_Cond); // wake all thread
+ pthread_mutex_unlock(&pDMNRTuning->mRecPlayMutex);
+
+ AudioMTKStreamOutInterface *streamOutput = NULL;
+ AudioMTKStreamInInterface *streamInput = NULL;
+
+ WAVEHDR waveHeader;
+ memset(&waveHeader, 0, sizeof(WAVEHDR));
+
+ char *inBuffer = NULL; //for playback
+ char *outBuffer = NULL;
+ uint32_t readBlockLen = 0;
+ uint32_t hwBufferSize = 0;
+ int playbackDb_index = 0;
+
+ char readBuffer[1024] = {0};//for record
+
+ if (pInFp) { //open output stream for playback
+ //config output format channel= 2 , bits_per_sample=16
+ FILE_FORMAT fileType = pDMNRTuning->playbackFileFormat();
+
+ if (fileType == WAVE_FORMAT) {
+ fseek(pInFp, 0, SEEK_END);
+ size_t fileSize = ftell(pInFp);
+
+ if (fileSize < WAVE_FORMAT) {
+ ALOGW("%s(), play file(size = %zu) is broken.", __FUNCTION__, fileSize);
+ return 0;
+ }
+
+ /* TODO(JH): sometimes, the play file is correct, but cannot read all header data successfully! Retry 5 times */
+ size_t readSize = 0;
+ int retryCount = 5;
+ for (int i = 0; i < retryCount; i++) {
+ rewind(pInFp);
+ readSize = fread(&waveHeader, 1, WAV_HEADER_SIZE, pInFp);
+ if (readSize == WAV_HEADER_SIZE) {
+ break;
+ }
+ }
+
+ if (WAV_HEADER_SIZE != readSize) {
+ ALOGW("%s(), [Dual-Mic] cannot read wave header successfully! (WAV_HEADER_SIZE = %d, read size = %zu, fileSize = %zu, retryCont = %d)", __FUNCTION__, WAV_HEADER_SIZE, readSize, fileSize, retryCount);
+ return 0;
+ }
+ } else if (fileType == UNSUPPORT_FORMAT) {
+ ALOGW("%s(), [Dual-Mic] playback file format is not support", __FUNCTION__);
+ return 0;
+ }
+ uint32_t sampleRate = waveHeader.SampleRate;
+ uint32_t channels = AUDIO_CHANNEL_OUT_STEREO;
+ int format, status;
+#if 0
+ if (waveHeader.BitsPerSample == 8 || waveHeader.BitsPerSample == 16) {
+ format = AUDIO_FORMAT_PCM_16_BIT;
+ } else {
+ format = AUDIO_FORMAT_PCM_16_BIT;
+ }
+#else
+ format = AUDIO_FORMAT_PCM_16_BIT;
+ status = NO_ERROR;
+#endif
+
+ //create output stream
+ streamOutput = pDMNRTuning->getStreamManager()->openOutputStream(pDMNRTuning->mDMNROutputDevice, &format, &channels, &sampleRate, &status);
+
+ hwBufferSize = streamOutput->bufferSize(); //16k bytes
+
+ if (waveHeader.NumChannels == 1) {
+ switch (waveHeader.BitsPerSample) {
+ case 8:
+ readBlockLen = hwBufferSize >> 2;
+ break;
+ case 16:
+ readBlockLen = hwBufferSize >> 1;
+ break;
+ default:
+ readBlockLen = 0;
+ break;
+ }
+ } else {
+ switch (waveHeader.BitsPerSample) {
+ case 8:
+ readBlockLen = hwBufferSize >> 1;
+ break;
+ case 16:
+ readBlockLen = hwBufferSize;
+ break;
+ default:
+ readBlockLen = 0;
+ break;
+ }
+ }
+ inBuffer = new char[readBlockLen];
+ outBuffer = new char[hwBufferSize];
+ playbackDb_index = pDMNRTuning->getPlaybackDb();
+ ALOGD("%s(), readBlockLen = %d, hwBufferSize = %d,playbackDb_index = %d \n", __FUNCTION__, readBlockLen, hwBufferSize, playbackDb_index);
+ }
+
+ if (pOutFp) { //open input stream for record
+#ifdef MTK_AUDIO_HD_REC_SUPPORT
+ AUDIO_HD_RECORD_SCENE_TABLE_STRUCT hdRecordSceneTable;
+ AudioCustParamClient::GetInstance()->GetHdRecordSceneTableFromNV(&hdRecordSceneTable);
+ if (hdRecordSceneTable.num_voice_rec_scenes > 0) { //value=0;
+ int32_t BesRecScene = 1;//1:cts verifier offset
+ pDMNRTuning->getSpeechEnhanceInfoInst()->SetBesRecScene(BesRecScene);
+ }
+#endif
+ uint32_t device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ int format = AUDIO_FORMAT_PCM_16_BIT;
+ uint32_t channel = AUDIO_CHANNEL_IN_STEREO;
+ uint32_t sampleRate = 16000;
+ status_t status = 0;
+ streamInput = pDMNRTuning->getStreamManager()->openInputStream(device, &format, &channel, &sampleRate, &status, (audio_in_acoustics_t)0);
+ android::AudioParameter paramInputSource = android::AudioParameter();
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ paramInputSource.addInt(android::String8(android::AudioParameter::keyInputSource), AUDIO_SOURCE_CUSTOMIZATION3); // For aurisys, we defined new input source CUS3 for DMNR cal. (CUS1 is ASR)
+#else
+ paramInputSource.addInt(android::String8(android::AudioParameter::keyInputSource), AUDIO_SOURCE_CUSTOMIZATION1); // Legacy arch, we using CUSTOMIZATION1 for DMNR cal.
+#endif
+ streamInput->setParameters(paramInputSource.toString());
+
+ android::AudioParameter paramDeviceIn = android::AudioParameter();
+ paramDeviceIn.addInt(android::String8(android::AudioParameter::keyRouting), AUDIO_DEVICE_IN_BUILTIN_MIC);
+ streamInput->setParameters(paramDeviceIn.toString());
+ }
+
+ while (!pDMNRTuning->m_bRecPlayThreadExit) {
+ //handling playback buffer
+ pthread_mutex_lock(&pDMNRTuning->mPlayBufMutex);
+ if (pInFp && !feof(pInFp)) {
+ int readdata = 0, writedata = 0, out_size = 0;
+ memset(inBuffer, 0, readBlockLen);
+ memset(outBuffer, 0, hwBufferSize);
+ if (readBlockLen > 0) {
+ readdata = fread(inBuffer, readBlockLen, 1, pInFp);
+ }
+ PCM_decode_data(&waveHeader, inBuffer, readBlockLen, outBuffer, &out_size);
+ PCM_Apply_DigitalDb(outBuffer, out_size, playbackDb_index);
+ writedata = streamOutput->write(outBuffer, out_size);
+#if 0
+ char filename[] = "/data/vendor/audiohal/xxx.pcm";
+ FILE *fp = fopen(filename, "ab+");
+ fwrite(outBuffer, writedata, 1, fp);
+ fclose(fp);
+#endif
+ }
+ pthread_mutex_unlock(&pDMNRTuning->mPlayBufMutex);
+
+ // handling record buffer
+ pthread_mutex_lock(&pDMNRTuning->mRecBufMutex);
+ if (pOutFp) {
+ memset(readBuffer, 0, sizeof(readBuffer));
+ int nRead = streamInput->read(readBuffer, 1024);
+#ifdef WRITE_RECORDDATA_ON_APSIDEDMNR
+ fwrite(readBuffer, 1, nRead, pOutFp);
+#endif
+ }
+ pthread_mutex_unlock(&pDMNRTuning->mRecBufMutex);
+ }
+
+ if (pInFp) {
+ streamOutput->standbyStreamOut();
+ pDMNRTuning->getStreamManager()->closeOutputStream(streamOutput);
+ if (inBuffer) {
+ delete[] inBuffer;
+ inBuffer = NULL;
+ }
+ if (outBuffer) {
+ delete[] outBuffer;
+ outBuffer = NULL;
+ }
+ }
+
+ if (pOutFp) {
+ streamInput->standby(); //this will close input device
+ pDMNRTuning->getStreamManager()->closeInputStream(streamInput);
+ }
+
+ //exit thread
+ pthread_mutex_lock(&pDMNRTuning->mRecPlayMutex);
+ ALOGD("%s(), pthread_cond_signal(&mRecPlayExit_Cond)", __FUNCTION__);
+ pthread_cond_signal(&pDMNRTuning->mRecPlayExit_Cond); // wake all thread
+ pthread_mutex_unlock(&pDMNRTuning->mRecPlayMutex);
+
+ return 0;
+}
+
+static void *FIR_Rec_ApSide_Routine(void *arg)
+{
+ ALOGD("+%s()", __FUNCTION__);
+ AudioALSAParamTuner *pFIRRecording = (AudioALSAParamTuner *)arg;
+ if (pFIRRecording == NULL)
+ {
+ ALOGE("%s(), pFIRRecording = NULL", __FUNCTION__);
+ return 0;
+ }
+
+ pthread_mutex_lock(&pFIRRecording->mRecPlayMutex);
+
+ //Adjust thread priority
+ prctl(PR_SET_NAME, (unsigned long)"FIRRecordAtApSideRoutine", 0, 0, 0);
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+
+ //Prepare file pointer
+ FILE *pOutFp = pFIRRecording->m_pOutputFile; //file for output(use audiomtkstreamin to record)
+
+ // ----start the loop --------
+ pFIRRecording->m_bRecPlayThreadExit = false;
+
+ ALOGD("%s(), pthread_cond_signal(&pFIRRecording->mRecPlayExit_Cond)", __FUNCTION__);
+ pthread_cond_signal(&pFIRRecording->mRecPlayExit_Cond); // wake all thread
+ pthread_mutex_unlock(&pFIRRecording->mRecPlayMutex);
+
+ AudioMTKStreamInInterface *streamInput = NULL;
+
+ WAVEHDR waveHeader;
+ memset(&waveHeader, 0, sizeof(WAVEHDR));
+
+ char readBuffer[1024] = {0}; //for record
+
+ //open input stream for record
+ if (pOutFp)
+ {
+#ifdef MTK_AUDIO_HD_REC_SUPPORT
+ AUDIO_HD_RECORD_SCENE_TABLE_STRUCT hdRecordSceneTable;
+ AudioCustParamClient::GetInstance()->GetHdRecordSceneTableFromNV(&hdRecordSceneTable);
+ if (hdRecordSceneTable.num_voice_rec_scenes > 0) //value=0;
+ {
+ int32_t BesRecScene = 1;//1:cts verifier offset
+ pFIRRecording->getSpeechEnhanceInfoInst()->SetBesRecScene(BesRecScene);
+ }
+#endif
+ uint32_t device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ int format = AUDIO_FORMAT_PCM_16_BIT;
+ uint32_t channel = AUDIO_CHANNEL_IN_STEREO;
+ uint32_t sampleRate = 48000;
+ status_t status = 0;
+ streamInput = pFIRRecording->getStreamManager()->openInputStream(device, &format, &channel, &sampleRate, &status, (audio_in_acoustics_t)0);
+
+ android::AudioParameter paramInputSource = android::AudioParameter();
+ paramInputSource.addInt(android::String8(android::AudioParameter::keyInputSource), AUDIO_SOURCE_MIC);
+ streamInput->setParameters(paramInputSource.toString());
+
+ //get device connection state
+ android::AudioParameter paramDeviceIn = android::AudioParameter();
+ if (pFIRRecording->getStreamManager()->getDeviceConnectionState(AUDIO_DEVICE_OUT_WIRED_HEADSET) == true)
+ {
+ paramDeviceIn.addInt(android::String8(android::AudioParameter::keyRouting), AUDIO_DEVICE_IN_WIRED_HEADSET);
+ streamInput->setParameters(paramDeviceIn.toString());
+ }
+ else
+ {
+ paramDeviceIn.addInt(android::String8(android::AudioParameter::keyRouting), AUDIO_DEVICE_IN_BUILTIN_MIC);
+ streamInput->setParameters(paramDeviceIn.toString());
+ }
+
+ }
+
+ while (!pFIRRecording->m_bRecPlayThreadExit)
+ {
+ // handling record buffer
+ pthread_mutex_lock(&pFIRRecording->mRecBufMutex);
+ if (pOutFp)
+ {
+ memset(readBuffer, 0, sizeof(readBuffer));
+ int nRead = streamInput->read(readBuffer, 1024);
+#ifdef WRITE_RECORDDATA_ON_APSIDEDMNR
+ fwrite(readBuffer, 1, nRead, pOutFp);
+#endif
+ }
+ pthread_mutex_unlock(&pFIRRecording->mRecBufMutex);
+ }
+
+ if (pOutFp)
+ {
+ streamInput->standby(); //this will close input device
+ pFIRRecording->getStreamManager()->closeInputStream(streamInput);
+ }
+
+ //exit thread
+ pthread_mutex_lock(&pFIRRecording->mRecPlayMutex);
+ ALOGD("%s(), pthread_cond_signal(&mRecPlayExit_Cond)", __FUNCTION__);
+ pthread_cond_signal(&pFIRRecording->mRecPlayExit_Cond); // wake all thread
+ pthread_mutex_unlock(&pFIRRecording->mRecPlayMutex);
+
+ return 0;
+}
+
+#endif
+
+AudioALSAParamTuner *AudioALSAParamTuner::UniqueTuningInstance = 0;
+
+AudioALSAParamTuner *AudioALSAParamTuner::getInstance() {
+ if (UniqueTuningInstance == 0) {
+ ALOGD("%s(), create AudioALSAParamTuner instance --", __FUNCTION__);
+ UniqueTuningInstance = new AudioALSAParamTuner();
+ ALOGD("%s(), create AudioALSAParamTuner instance ++", __FUNCTION__);
+ }
+
+ return UniqueTuningInstance;
+}
+
+AudioALSAParamTuner::AudioALSAParamTuner() :
+ mMode(0),
+ m_bPPSThreadExit(false),
+ m_bWBMode(false),
+ m_pInputFile(NULL),
+ mSideTone(0xFFFFFF40),
+ m_bPlaying(false),
+ mStartRec(false),
+ mTasteThreadID(0),
+ mRecPlayThreadID(0) {
+ ALOGD("+%s()", __FUNCTION__);
+ // create volume instance
+ mAudioALSAVolumeController = AudioVolumeFactory::CreateAudioVolumeController();
+ mAudioALSAVolumeController->initCheck();
+
+ // create audio resource manager instance
+ mAudioResourceManager = AudioALSAHardwareResourceManager::getInstance();
+
+ // create speech driver instance
+ mSpeechDriverFactory = SpeechDriverFactory::GetInstance();
+
+ mSphPhonecallCtrl = AudioALSASpeechPhoneCallController::getInstance();
+
+ memset(mOutputVolume, 0, MODE_NUM * sizeof(uint32));
+ memset(m_strInputFileName, 0, FILE_NAME_LEN_MAX * sizeof(char));
+
+ int ret = pthread_mutex_init(&mP2WMutex, NULL);
+ if (ret != 0) {
+ ALOGE("%s(), Failed to initialize pthread mP2WMutex!", __FUNCTION__);
+ }
+
+ ret = pthread_mutex_init(&mPPSMutex, NULL);
+ if (ret != 0) {
+ ALOGE("%s(), Failed to initialize mPPSMutex!", __FUNCTION__);
+ }
+
+ ret = pthread_mutex_init(&mPlayBufMutex, NULL);
+ if (ret != 0) {
+ ALOGE("%s(), Failed to initialize mPlayBufMutex!", __FUNCTION__);
+ }
+
+ ret = pthread_cond_init(&mPPSExit_Cond, NULL);
+ if (ret != 0) {
+ ALOGE("%s(), Failed to initialize mPPSExit_Cond!", __FUNCTION__);
+ }
+
+#if !defined(MTK_AUDIO_HD_REC_SUPPORT)
+ if (mAudioResourceManager->getNumPhoneMicSupport() >= 2)
+#endif
+ {
+ m_bDMNRPlaying = false;
+ m_bRecPlayThreadExit = false;
+ m_pOutputFile = NULL;
+
+ mPlay2WayInstance = 0;
+ mRec2WayInstance = 0;
+
+ memset(m_strOutFileName, 0, FILE_NAME_LEN_MAX * sizeof(char));
+
+ AUDIO_VER1_CUSTOM_VOLUME_STRUCT VolumeCustomParam;//volume custom data
+ AudioCustParamClient::GetInstance()->GetVolumeVer1ParamFromNV(&VolumeCustomParam);
+
+#ifdef MTK_NEW_VOL_CONTROL
+ mDualMicTool_micGain[0] = AudioMTKGainController::getInstance()->getMicGainDecimal(Normal_Mic, GAIN_DEVICE_EARPIECE);
+#else
+ mDualMicTool_micGain[0] = VolumeCustomParam.audiovolume_mic[VOLUME_NORMAL_MODE][3];
+#endif
+ if (mDualMicTool_micGain[0] > UPLINK_GAIN_MAX) {
+ mDualMicTool_micGain[0] = UPLINK_GAIN_MAX;
+ }
+
+#ifdef MTK_NEW_VOL_CONTROL
+ mDualMicTool_micGain[1] = AudioMTKGainController::getInstance()->getMicGainDecimal(Handfree_Mic, GAIN_DEVICE_SPEAKER);
+#else
+ mDualMicTool_micGain[1] = VolumeCustomParam.audiovolume_mic[VOLUME_SPEAKER_MODE][3];
+#endif
+ if (mDualMicTool_micGain[1] > UPLINK_GAIN_MAX) {
+ mDualMicTool_micGain[1] = UPLINK_GAIN_MAX;
+ }
+
+ mDualMicTool_receiverGain = VolumeCustomParam.audiovolume_sph[VOLUME_NORMAL_MODE][CUSTOM_VOLUME_STEP - 1];
+ if (mDualMicTool_receiverGain > MAX_VOICE_VOLUME) {
+ mDualMicTool_receiverGain = MAX_VOICE_VOLUME;
+ }
+
+ mDualMicTool_headsetGain = VolumeCustomParam.audiovolume_sph[VOLUME_HEADSET_MODE][3];
+ if (mDualMicTool_headsetGain > MAX_VOICE_VOLUME) {
+ mDualMicTool_headsetGain = MAX_VOICE_VOLUME;
+ }
+#ifndef DMNR_TUNNING_AT_MODEMSIDE
+ mAudioStreamManager = AudioALSAStreamManager::getInstance();
+ mAudioSpeechEnhanceInfoInstance = AudioSpeechEnhanceInfo::getInstance();
+ mPlaybackDb_index = 0;
+#endif
+ mDMNROutputDevice = 0;
+
+ ret = pthread_mutex_init(&mRecPlayMutex, NULL);
+ if (ret != 0) {
+ ALOGE("%s(), Failed to initialize mRecPlayMutex!", __FUNCTION__);
+ }
+
+ ret = pthread_mutex_init(&mRecBufMutex, NULL);
+ if (ret != 0) {
+ ALOGE("%s(), Failed to initialize mRecBufMutex!", __FUNCTION__);
+ }
+
+ ret = pthread_cond_init(&mRecPlayExit_Cond, NULL);
+ if (ret != 0) {
+ ALOGE("%s(), Failed to initialize mRecPlayExit_Cond!", __FUNCTION__);
+ }
+
+ ALOGD("%s(), AudioALSAParamTuner: default mic gain-mormal:%d;handsfree:%d, receiver gain:%d, headset Gain:%d", __FUNCTION__, mDualMicTool_micGain[0], mDualMicTool_micGain[1], mDualMicTool_receiverGain,
+ mDualMicTool_headsetGain);
+ }
+}
+
+AudioALSAParamTuner::~AudioALSAParamTuner() {
+ ALOGD("~AudioALSAParamTuner");
+}
+
+//for taste tool
+bool AudioALSAParamTuner::isPlaying() {
+ ALOGV("%s(), playing:%d", __FUNCTION__, m_bPlaying);
+ bool ret = false;
+ pthread_mutex_lock(&mP2WMutex);
+
+#if defined(MTK_AUDIO_HD_REC_SUPPORT)
+ ALOGV("%s(), DMNR playing:%d", __FUNCTION__, m_bDMNRPlaying);
+ ret = (m_bPlaying | m_bDMNRPlaying) ? true : false;
+#else
+ if (mAudioResourceManager->getNumPhoneMicSupport() >= 2) {
+ ALOGV("%s(), DMNR playing:%d", __FUNCTION__, m_bDMNRPlaying);
+ ret = (m_bPlaying | m_bDMNRPlaying) ? true : false;
+ } else {
+ ret = m_bPlaying;
+ }
+#endif
+
+ pthread_mutex_unlock(&mP2WMutex);
+ return ret;
+}
+
+uint32_t AudioALSAParamTuner::getMode() {
+ ALOGD("%s(), mode:%d", __FUNCTION__, mMode);
+ pthread_mutex_lock(&mP2WMutex);
+ uint32_t ret = mMode;
+ pthread_mutex_unlock(&mP2WMutex);
+ return ret;
+}
+
+status_t AudioALSAParamTuner::setMode(uint32_t mode) {
+ ALOGD("%s(), mode:%d", __FUNCTION__, mode);
+ pthread_mutex_lock(&mP2WMutex);
+ mMode = mode;
+ pthread_mutex_unlock(&mP2WMutex);
+ return NO_ERROR;
+}
+
+status_t AudioALSAParamTuner::setPlaybackFileName(const char *fileName) {
+ ALOGD("+%s()", __FUNCTION__);
+ pthread_mutex_lock(&mP2WMutex);
+ if (fileName != NULL && strlen(fileName) < FILE_NAME_LEN_MAX - 1) {
+ ALOGD("%s(), input file name:%s", __FUNCTION__, fileName);
+ memset(m_strInputFileName, 0, FILE_NAME_LEN_MAX);
+ audio_strncpy(m_strInputFileName, fileName, FILE_NAME_LEN_MAX);
+ } else {
+ ALOGE("%s(), input file name NULL or too long", __FUNCTION__);
+ pthread_mutex_unlock(&mP2WMutex);
+ return BAD_VALUE;
+ }
+ pthread_mutex_unlock(&mP2WMutex);
+ return NO_ERROR;
+}
+
+status_t AudioALSAParamTuner::setDLPGA(uint32_t gain) {
+ uint32_t outputDev = 0;
+
+ if (gain > MAX_VOICE_VOLUME) {
+ ALOGE("%s(), gain error gain=%x", __FUNCTION__, gain);
+ return BAD_VALUE;
+ }
+
+ pthread_mutex_lock(&mP2WMutex);
+ mOutputVolume[mMode] = gain;
+ ALOGD("+%s(), mode=%d, gain=%d, lad volume=0x%x", __FUNCTION__, mMode, gain, mOutputVolume[mMode]);
+
+ if (m_bPlaying) {
+ ALOGD("%s(), lad_Volume=%x", __FUNCTION__, mOutputVolume[mMode]);
+
+#ifdef MTK_NEW_VOL_CONTROL
+ //MTK_AUDIO_GAIN_TABLE set tuner gain directly to HW
+ mAudioALSAVolumeController->ApplySideTone(GAIN_DEVICE_EARPIECE); // in 0.5dB
+ setSphVolume(mMode, mOutputVolume[mMode]);
+#else
+
+ switch (mMode) {
+ case SPEECH_MODE_NORMAL: {
+ outputDev = AUDIO_DEVICE_OUT_EARPIECE;
+ break;
+ }
+ case SPEECH_MODE_EARPHONE: {
+ outputDev = AUDIO_DEVICE_OUT_WIRED_HEADSET ;
+ break;
+ }
+ case SPEECH_MODE_LOUD_SPEAKER:
+ outputDev = AUDIO_DEVICE_OUT_SPEAKER;
+ break;
+ default:
+ outputDev = AUDIO_DEVICE_OUT_EARPIECE;
+ break;
+ }
+
+ mAudioALSAVolumeController->setVoiceVolume(mOutputVolume[mMode], outputDev);
+
+#endif
+ }
+
+ pthread_mutex_unlock(&mP2WMutex);
+ return NO_ERROR;
+}
+
+void AudioALSAParamTuner::updataOutputFIRCoffes(AudioTasteTuningStruct *pCustParam) {
+ SpeechDriverInterface *pSpeechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ ALOGD("+%s(), mMode:%d, m_bPlaying:%d,", __FUNCTION__, mMode, m_bPlaying);
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ unsigned short IdxVolume = pCustParam->slected_fir_index;
+ ALOGD("%s(), MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT update volume index(%d) for Audio Taste", __FUNCTION__, IdxVolume);
+ //AUDIO_STREAM_VOICE_CALL 0
+ pSpeechDriver->setMDVolumeIndex(0, 0, IdxVolume);
+
+#else
+ int ret = 0;
+ unsigned short mode = pCustParam->phone_mode;
+ unsigned short cmdType = pCustParam->cmd_type;
+ uint32_t sampleRate = 16000;
+
+ ALOGD("%s(), mode:%d, mMode:%d, m_bPlaying:%d,", __FUNCTION__, mode, mMode, m_bPlaying);
+
+ pthread_mutex_lock(&mP2WMutex);
+
+ if (m_bPlaying && mode == mMode) {
+ pSpeechDriver->PCM2WayOff(); // trun off PCM2Way
+ mAudioResourceManager->stopInputDevice(mAudioResourceManager->getInputDevice());
+ mAudioResourceManager->stopOutputDevice();
+ pthread_mutex_unlock(&mP2WMutex);
+ usleep(10 * 1000); //wait to make sure all message is processed
+ pthread_mutex_lock(&mP2WMutex);
+ }
+ AudioCustParamClient *pAudioCustParamClient = AudioCustParamClient::GetInstance();
+ if (pCustParam->wb_mode) {
+#if defined(MTK_WB_SPEECH_SUPPORT)
+ AUDIO_CUSTOM_WB_PARAM_STRUCT sCustWbParam;
+ pAudioCustParamClient->GetWBSpeechParamFromNVRam(&sCustWbParam);
+ if (cmdType && sCustWbParam.speech_mode_wb_para[mode][7] != pCustParam->dlDigitalGain) {
+ ALOGD("%s(), mode=%d, ori dlDG gain=%d, new dlDG gain=%d", __FUNCTION__, mode, sCustWbParam.speech_mode_wb_para[mode][7], pCustParam->dlDigitalGain);
+ sCustWbParam.speech_mode_wb_para[mode][7] = pCustParam->dlDigitalGain;
+ }
+ ret = pSpeechDriver->SetWBSpeechParameters(&sCustWbParam);
+#endif
+ } else {
+ AUDIO_CUSTOM_PARAM_STRUCT sCustParam;
+ AUDIO_PARAM_MED_STRUCT sCustMedParam;
+ unsigned short index = pCustParam->slected_fir_index;
+ unsigned short dlGain = pCustParam->dlDigitalGain;
+ pAudioCustParamClient->GetNBSpeechParamFromNVRam(&sCustParam);
+ pAudioCustParamClient->GetMedParamFromNV(&sCustMedParam);
+
+ if ((cmdType == (unsigned short)AUD_TASTE_START || cmdType == (unsigned short)AUD_TASTE_INDEX_SETTING) && sCustMedParam.select_FIR_output_index[mode] != index) {
+ ALOGD("%s(), mode=%d, old index=%d, new index=%d", __FUNCTION__, mode, sCustMedParam.select_FIR_output_index[mode], index);
+ //save index to MED with different mode.
+ sCustMedParam.select_FIR_output_index[mode] = index;
+
+ ALOGD("%s(), ori sph_out_fir[%d][0]=%d, ori sph_out_fir[%d][44]=%d", __FUNCTION__, mode, sCustParam.sph_out_fir[mode][0], mode, sCustParam.sph_out_fir[mode][44]);
+ //copy med data into audio_custom param
+ memcpy((void *)sCustParam.sph_out_fir[mode], (void *)sCustMedParam.speech_output_FIR_coeffs[mode][index], sizeof(sCustParam.sph_out_fir[index]));
+ ALOGD("%s(), new sph_out_fir[%d][0]=%d, new sph_out_fir[%d][44]=%d", __FUNCTION__, mode, sCustParam.sph_out_fir[mode][0], mode, sCustParam.sph_out_fir[mode][44]);
+ pAudioCustParamClient->SetNBSpeechParamToNVRam(&sCustParam);
+ pAudioCustParamClient->SetMedParamToNV(&sCustMedParam);
+ }
+
+ if ((cmdType == (unsigned short)AUD_TASTE_START || cmdType == (unsigned short)AUD_TASTE_DLDG_SETTING) && sCustParam.speech_mode_para[mode][7] != dlGain) {
+ ALOGD("%s(), mode=%d, old dlDGGain=%d, new dlDGGain=%d", __FUNCTION__, mode, sCustParam.speech_mode_para[mode][7], dlGain);
+ sCustParam.speech_mode_para[mode][7] = dlGain;
+ }
+ ALOGD("%s(), sph_out_fir[%d][0]=%d, sph_out_fir[%d][44]=%d", __FUNCTION__, mode, sCustParam.sph_out_fir[mode][0], mode, sCustParam.sph_out_fir[mode][44]);
+ ret = pSpeechDriver->SetNBSpeechParameters(&sCustParam);
+ }
+
+ if (m_bPlaying && mode == mMode) {
+ mAudioResourceManager->startInputDevice(AUDIO_DEVICE_IN_BUILTIN_MIC);
+
+//V1 platform only support AFE 16KHz
+ sampleRate = m_bWBMode ? 16000 : 8000;
+
+ switch (mMode) {
+ case SPEECH_MODE_NORMAL: {
+ mAudioResourceManager->startOutputDevice(AUDIO_DEVICE_OUT_EARPIECE, sampleRate);
+#ifdef MTK_NEW_VOL_CONTROL
+ mAudioALSAVolumeController->ApplySideTone(GAIN_DEVICE_EARPIECE); // in 0.5dB
+#else
+ mAudioALSAVolumeController->ApplySideTone(EarPiece_SideTone_Gain); // in 0.5dB
+#endif
+ pSpeechDriver->SetSpeechMode(AUDIO_DEVICE_IN_BUILTIN_MIC, AUDIO_DEVICE_OUT_EARPIECE);
+ break;
+ }
+ case SPEECH_MODE_EARPHONE: {
+ mAudioResourceManager->startOutputDevice(AUDIO_DEVICE_OUT_WIRED_HEADSET, sampleRate);
+#ifdef MTK_NEW_VOL_CONTROL
+ mAudioALSAVolumeController->ApplySideTone(GAIN_DEVICE_HEADSET);
+#else
+ mAudioALSAVolumeController->ApplySideTone(Headset_SideTone_Gain);
+#endif
+ pSpeechDriver->SetSpeechMode(AUDIO_DEVICE_IN_BUILTIN_MIC, AUDIO_DEVICE_OUT_WIRED_HEADSET);
+ break;
+ }
+ case SPEECH_MODE_LOUD_SPEAKER:
+ mAudioResourceManager->startOutputDevice(AUDIO_DEVICE_OUT_SPEAKER, sampleRate);
+#ifdef MTK_NEW_VOL_CONTROL
+ mAudioALSAVolumeController->ApplySideTone(GAIN_DEVICE_SPEAKER);
+#else
+ mAudioALSAVolumeController->ApplySideTone(LoudSpk_SideTone_Gain);
+#endif
+ pSpeechDriver->SetSpeechMode(AUDIO_DEVICE_IN_BUILTIN_MIC, AUDIO_DEVICE_OUT_SPEAKER);
+ break;
+ default:
+ break;
+ }
+ setSphVolume(mMode, mOutputVolume[mMode]);
+
+ sph_enh_mask_struct_t sphMask;
+ sphMask = SpeechEnhancementController::GetInstance()->GetSpeechEnhancementMask(); // copy DMNR mask
+ sphMask.dynamic_func = SPH_ENH_DYNAMIC_MASK_VCE;
+ pSpeechDriver->SetSpeechEnhancementMask(sphMask);
+ pSpeechDriver->PCM2WayOn(m_bWBMode); // start PCM 2 way
+ pSpeechDriver->SetSpeechEnhancement(true);
+ }
+ pthread_mutex_unlock(&mP2WMutex);
+
+#endif
+}
+
+status_t AudioALSAParamTuner::enableModemPlaybackVIASPHPROC(bool bEnable, bool bWB) { //need record path?
+
+ ALOGD("%s(), bEnable:%d, bWBMode:%d", __FUNCTION__, bEnable, bWB);
+ int ret = 0;
+
+ // 3 sec for creat thread timeout
+ struct timeval now;
+ struct timespec timeout;
+ gettimeofday(&now, NULL);
+ timeout.tv_sec = now.tv_sec + 3;
+ timeout.tv_nsec = now.tv_usec * 1000;
+
+ if (mRec2WayInstance == 0) {
+ mRec2WayInstance = Record2Way::GetInstance();
+ }
+ if (mPlay2WayInstance == 0) {
+ mPlay2WayInstance = Play2Way::GetInstance();
+ }
+
+ if (bEnable && (isPlaying() == false)) {
+ ALOGD("%s(), open Enable:%d, isPlaying():%d", __FUNCTION__, bEnable, isPlaying());
+ pthread_mutex_lock(&mP2WMutex);
+ m_pInputFile = fopen(m_strInputFileName, "rb");
+ if (m_pInputFile == NULL) {
+ m_pInputFile = fopen("/mnt/sdcard2/test.wav", "rb");
+ if (m_pInputFile == NULL) {
+ ALOGD("%s(), open input file fail!!", __FUNCTION__);
+ pthread_mutex_unlock(&mP2WMutex);
+ return BAD_VALUE;
+ }
+ }
+ m_bWBMode = bWB;
+ ALOGD("%s(), ApplySideTone mode=%d", __FUNCTION__, mMode);
+ //Audio Taste: use MODEM_1
+ mSphPhonecallCtrl->setParam(String8("AudioTaste=1;"));
+ switch (mMode) {
+ case SPEECH_MODE_NORMAL: {
+#ifdef MTK_NEW_VOL_CONTROL
+ mAudioALSAVolumeController->ApplySideTone(GAIN_DEVICE_EARPIECE);// in 0.5dB
+#else
+ mAudioALSAVolumeController->ApplySideTone(EarPiece_SideTone_Gain);// in 0.5dB
+#endif
+ mSphPhonecallCtrl->open(AUDIO_MODE_IN_CALL, AUDIO_DEVICE_OUT_EARPIECE, AUDIO_DEVICE_IN_BUILTIN_MIC);
+ break;
+ }
+ case SPEECH_MODE_EARPHONE: {
+#ifdef MTK_NEW_VOL_CONTROL
+ mAudioALSAVolumeController->ApplySideTone(GAIN_DEVICE_HEADSET);
+#else
+ mAudioALSAVolumeController->ApplySideTone(Headset_SideTone_Gain);
+#endif
+ mSphPhonecallCtrl->open(AUDIO_MODE_IN_CALL, AUDIO_DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_IN_WIRED_HEADSET);
+ break;
+ }
+ case SPEECH_MODE_LOUD_SPEAKER:
+#ifdef MTK_NEW_VOL_CONTROL
+ mAudioALSAVolumeController->ApplySideTone(GAIN_DEVICE_SPEAKER);
+#else
+ mAudioALSAVolumeController->ApplySideTone(LoudSpk_SideTone_Gain);
+#endif
+ mSphPhonecallCtrl->open(AUDIO_MODE_IN_CALL, AUDIO_DEVICE_OUT_SPEAKER, AUDIO_DEVICE_IN_BUILTIN_MIC);
+ break;
+ default:
+ break;
+ }
+
+ setSphVolume(mMode, mOutputVolume[mMode]);
+ // start pcm2way
+ mRec2WayInstance->Start();
+ mPlay2WayInstance->Start();
+
+ ALOGD("%s(), open taste_threadloop thread~", __FUNCTION__);
+ pthread_mutex_lock(&mPPSMutex);
+ ret = pthread_create(&mTasteThreadID, NULL, Play_PCM_With_SpeechEnhance_Routine, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s(), Play_PCM_With_SpeechEnhance_Routine thread pthread_create error!!", __FUNCTION__);
+ pthread_mutex_unlock(&mPPSMutex);
+ pthread_mutex_unlock(&mP2WMutex);
+ return UNKNOWN_ERROR;
+ }
+
+ ALOGD("%s(), +mPPSExit_Cond wait", __FUNCTION__);
+ ret = pthread_cond_timedwait(&mPPSExit_Cond, &mPPSMutex, &timeout);
+ ALOGD("%s(), -mPPSExit_Cond receive ret=%d", __FUNCTION__, ret);
+ pthread_mutex_unlock(&mPPSMutex);
+
+ pthread_mutex_unlock(&mP2WMutex);
+ usleep(100 * 1000);
+ pthread_mutex_lock(&mP2WMutex);
+
+ m_bPlaying = true;
+ sph_enh_mask_struct_t sphMask;
+ sphMask = SpeechEnhancementController::GetInstance()->GetSpeechEnhancementMask(); // copy DMNR mask
+ sphMask.dynamic_func = SPH_ENH_DYNAMIC_MASK_VCE;
+ mSpeechDriverFactory->GetSpeechDriver()->SetSpeechEnhancementMask(sphMask);
+ mSpeechDriverFactory->GetSpeechDriver()->PCM2WayOn(m_bWBMode); // start PCM 2 way
+ mSpeechDriverFactory->GetSpeechDriver()->SetSpeechEnhancement(true);
+ pthread_mutex_unlock(&mP2WMutex);
+ } else if ((!bEnable) && m_bPlaying) {
+ ALOGD("%s(), close Enable:%d, isPlaying():%d", __FUNCTION__, bEnable, isPlaying());
+ pthread_mutex_lock(&mP2WMutex);
+ pthread_mutex_lock(&mPPSMutex);
+ if (!m_bPPSThreadExit) {
+ m_bPPSThreadExit = true;
+ ALOGD("%s(), +mPPSExit_Cond wait", __FUNCTION__);
+ ret = pthread_cond_timedwait(&mPPSExit_Cond, &mPPSMutex, &timeout);
+ ALOGD("%s(), -mPPSExit_Cond receive ret=%d", __FUNCTION__, ret);
+ }
+ pthread_mutex_unlock(&mPPSMutex);
+
+ mSpeechDriverFactory->GetSpeechDriver()->PCM2WayOff();
+ mSphPhonecallCtrl->close();
+
+ mRec2WayInstance->Stop();
+ mPlay2WayInstance->Stop();
+ mSphPhonecallCtrl->setParam(String8("AudioTaste=0;"));
+ m_bPlaying = false;
+ if (m_pInputFile) { fclose(m_pInputFile); }
+ m_pInputFile = NULL;
+ pthread_mutex_unlock(&mP2WMutex);
+ usleep(200 * 1000); //wait to make sure all message is processed
+ } else {
+ ALOGD("%s(), The Audio Taste Tool State is error, bEnable=%d, playing=%d", __FUNCTION__, bEnable, m_bPlaying);
+ return BAD_VALUE;
+ }
+
+ return NO_ERROR;
+}
+
+FILE_FORMAT AudioALSAParamTuner::playbackFileFormat() {
+ ALOGD("%s(), playback file name:%s", __FUNCTION__, m_strInputFileName);
+ FILE_FORMAT ret = UNSUPPORT_FORMAT;
+ char *pFileSuffix = m_strInputFileName;
+
+ strsep(&pFileSuffix, ".");
+ if (pFileSuffix != NULL) {
+ if (strcmp(pFileSuffix, "pcm") == 0 || strcmp(pFileSuffix, "PCM") == 0) {
+ ALOGD("%s(), playback file format is pcm", __FUNCTION__);
+ ret = PCM_FORMAT;
+ } else if (strcmp(pFileSuffix, "wav") == 0 || strcmp(pFileSuffix, "WAV") == 0) {
+ ALOGD("%s(), playback file format is wav", __FUNCTION__);
+ ret = WAVE_FORMAT;
+ } else {
+ ALOGD("%s(), playback file format is unsupport", __FUNCTION__);
+ ret = UNSUPPORT_FORMAT;
+ }
+ }
+
+ return ret;
+}
+
+// For DMNR Tuning
+status_t AudioALSAParamTuner::setRecordFileName(const char *fileName) {
+#if !defined(MTK_AUDIO_HD_REC_SUPPORT)
+ if (mAudioResourceManager->getNumPhoneMicSupport() < 2) {
+ ALOGE("%s(), unsupport", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+#endif
+ ALOGD("+%s()", __FUNCTION__);
+ pthread_mutex_lock(&mP2WMutex);
+ if (fileName != NULL && strlen(fileName) < FILE_NAME_LEN_MAX - 1) {
+ ALOGD("%s(), input file name:%s", __FUNCTION__, fileName);
+ memset(m_strOutFileName, 0, FILE_NAME_LEN_MAX);
+ audio_strncpy(m_strOutFileName, fileName, FILE_NAME_LEN_MAX);
+ } else {
+ ALOGE("%s(), input file name NULL or too long!", __FUNCTION__);
+ pthread_mutex_unlock(&mP2WMutex);
+ return BAD_VALUE;
+ }
+
+ pthread_mutex_unlock(&mP2WMutex);
+ return NO_ERROR;
+}
+
+status_t AudioALSAParamTuner::setDMNRGain(unsigned short type, unsigned short value) {
+#if !defined(MTK_AUDIO_HD_REC_SUPPORT)
+ if (mAudioResourceManager->getNumPhoneMicSupport() < 2) {
+ ALOGE("%s(), unsupport", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+#endif
+
+ ALOGD("%s(), type=%d, gain=%d", __FUNCTION__, type, value);
+ status_t ret = NO_ERROR;
+
+ if (value < 0) {
+ return BAD_VALUE;
+ }
+
+ pthread_mutex_lock(&mP2WMutex);
+ switch (type) {
+ case AUD_MIC_GAIN:
+ mDualMicTool_micGain[0] = (value > UPLINK_GAIN_MAX) ? UPLINK_GAIN_MAX : value;
+ break;
+ case AUD_RECEIVER_GAIN:
+ mDualMicTool_receiverGain = (value > MAX_VOICE_VOLUME) ? MAX_VOICE_VOLUME : value;
+ break;
+ case AUD_HS_GAIN:
+ mDualMicTool_headsetGain = (value > MAX_VOICE_VOLUME) ? MAX_VOICE_VOLUME : value;
+ break;
+ case AUD_MIC_GAIN_HF:
+ mDualMicTool_micGain[1] = (value > UPLINK_GAIN_MAX) ? UPLINK_GAIN_MAX : value;
+ break;
+ default:
+ ALOGW("%s(), unknown type", __FUNCTION__);
+ ret = BAD_VALUE;
+ break;
+ }
+ pthread_mutex_unlock(&mP2WMutex);
+ return ret;
+}
+
+status_t AudioALSAParamTuner::getDMNRGain(unsigned short type, unsigned short *value) {
+#if !defined(MTK_AUDIO_HD_REC_SUPPORT)
+ if (mAudioResourceManager->getNumPhoneMicSupport() < 2) {
+ ALOGE("%s(), unsupport", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+#endif
+
+ ALOGD("%s(), type=%d", __FUNCTION__, type);
+ status_t ret = NO_ERROR;
+
+ pthread_mutex_lock(&mP2WMutex);
+ switch (type) {
+ case AUD_MIC_GAIN:
+ *value = mDualMicTool_micGain[0]; // normal mic
+ break;
+ case AUD_RECEIVER_GAIN:
+ *value = mDualMicTool_receiverGain;
+ break;
+ case AUD_HS_GAIN:
+ *value = mDualMicTool_headsetGain;
+ break;
+ case AUD_MIC_GAIN_HF:
+ *value = mDualMicTool_micGain[1]; //handsfree mic
+ break;
+ default:
+ ALOGW("%s(), unknown type", __FUNCTION__);
+ ret = BAD_VALUE;
+ break;
+ }
+ pthread_mutex_unlock(&mP2WMutex);
+ return ret;
+}
+
+status_t AudioALSAParamTuner::setPlaybackVolume(uint32_t mode, uint32_t gain, uint32_t device) {
+#if !defined(MTK_AUDIO_HD_REC_SUPPORT)
+ if (mAudioResourceManager->getNumPhoneMicSupport() < 2) {
+ ALOGE("%s(), unsupport", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+#endif
+
+ ALOGD("+%s(), gain:%u,mode:%u, device=%u", __FUNCTION__, gain, mode, device);
+
+ switch (mode) {
+ case VOLUME_NORMAL_MODE:
+
+ mPlaybackDb_index = mAudioALSAVolumeController->ApplyAudioGainTuning(gain, mode, Audio_Earpiece);
+ break;
+ case VOLUME_HEADSET_MODE:
+
+ mPlaybackDb_index = mAudioALSAVolumeController->ApplyAudioGainTuning(gain, mode, Audio_Headset);
+ break;
+ case VOLUME_SPEAKER_MODE:
+ case VOLUME_HEADSET_SPEAKER_MODE:
+ // nothing to do
+ ALOGD("%s(), invalid mode!!", __FUNCTION__);
+ break;
+ default:
+ break;
+ }
+
+ ALOGV("-%s(), mPlaybackDb_index=%d", __FUNCTION__, mPlaybackDb_index);
+ return NO_ERROR;
+}
+
+status_t AudioALSAParamTuner::enableDMNRAtApSide(bool bEnable, bool bWBMode, unsigned short outputDevice, unsigned short workMode) {
+#if !defined(MTK_AUDIO_HD_REC_SUPPORT)
+ if (mAudioResourceManager->getNumPhoneMicSupport() < 2) {
+ ALOGE("%s(), unsupport", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+#endif
+
+ ALOGD("%s(), bEnable:%d, wb mode:%d, outputDevice:%d,work mode:%d", __FUNCTION__, bEnable, bWBMode, outputDevice, workMode);
+
+ // 3 sec for timeout
+ struct timeval now;
+ struct timespec timeout;
+ gettimeofday(&now, NULL);
+ timeout.tv_sec = now.tv_sec + 3;
+ timeout.tv_nsec = now.tv_usec * 1000;
+ int ret;
+
+ if (bEnable && (isPlaying() == false)) {
+ pthread_mutex_lock(&mP2WMutex);
+ // open input file for playback
+ if ((workMode == RECPLAY_MODE) || (workMode == RECPLAY_HF_MODE)) {
+ m_pInputFile = fopen(m_strInputFileName, "rb");
+ ALOGD("%s(), [Dual-Mic] open input file filename:%s", __FUNCTION__, m_strInputFileName);
+ if (m_pInputFile == NULL) {
+ ALOGW("%s(), [Dual-Mic] open input file fail!!", __FUNCTION__);
+ pthread_mutex_unlock(&mP2WMutex);
+ return BAD_VALUE;
+ }
+ }
+
+ m_pOutputFile = fopen(m_strOutFileName, "wb");
+ ALOGD("%s(), [Dual-Mic] open output file filename:%s", __FUNCTION__, m_strOutFileName);
+ if (m_pOutputFile == NULL) {
+ ALOGW("%s(), [Dual-Mic] open output file fail!!", __FUNCTION__);
+ fclose(m_pInputFile);
+ pthread_mutex_unlock(&mP2WMutex);
+ return BAD_VALUE;
+ }
+
+ m_bWBMode = bWBMode;
+
+ //set MIC gain
+#ifdef MTK_NEW_VOL_CONTROL
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ GAIN_MIC_MODE mode = GAIN_MIC_CUSTOMIZATION3;
+#else
+ GAIN_MIC_MODE mode = GAIN_MIC_CUSTOMIZATION1;
+#endif
+#endif
+
+ if (workMode > RECONLY_MODE) {
+ mAudioSpeechEnhanceInfoInstance-> SetAPTuningMode(HANDSFREE_MODE_DMNR);
+#ifdef MTK_NEW_VOL_CONTROL
+ AudioMTKGainController::getInstance()->SetMicGainTuning(mode, GAIN_DEVICE_SPEAKER, mDualMicTool_micGain[1]);
+ AudioMTKGainController::getInstance()->SetMicGainTuning(mode, GAIN_DEVICE_EARPIECE, mDualMicTool_micGain[1]);
+#else
+ mAudioALSAVolumeController->SetMicGainTuning(Handfree_Mic, mDualMicTool_micGain[1]);
+#endif
+ } else {
+ mAudioSpeechEnhanceInfoInstance-> SetAPTuningMode(NORMAL_MODE_DMNR);
+#ifdef MTK_NEW_VOL_CONTROL
+ AudioMTKGainController::getInstance()->SetMicGainTuning(mode, GAIN_DEVICE_SPEAKER, mDualMicTool_micGain[0]);
+ AudioMTKGainController::getInstance()->SetMicGainTuning(mode, GAIN_DEVICE_EARPIECE, mDualMicTool_micGain[0]);
+#else
+ mAudioALSAVolumeController->SetMicGainTuning(Normal_Mic, mDualMicTool_micGain[0]);
+#endif
+ }
+
+ //set output and output gain in dB
+ if ((workMode == RECPLAY_MODE) || (workMode == RECPLAY_HF_MODE)) {
+ uint32_t dev = outputDevice == OUTPUT_DEVICE_RECEIVER ? AUDIO_DEVICE_OUT_EARPIECE : AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ mDMNROutputDevice = dev;
+ uint32_t volume = outputDevice == OUTPUT_DEVICE_RECEIVER ? mDualMicTool_receiverGain : mDualMicTool_headsetGain;
+ uint32_t mode = outputDevice == OUTPUT_DEVICE_RECEIVER ? VOLUME_NORMAL_MODE : VOLUME_HEADSET_MODE;
+ ALOGD("%s(), changeOutputDevice,dev=%d, mDMNROutputDevice=0x%x ", __FUNCTION__, dev, mDMNROutputDevice);
+ //mAudioResourceManager->changeOutputDevice(dev); //set downlink path, modify to move it to openstreamout device
+ setPlaybackVolume(mode, volume, dev);
+ ALOGD("%s(), Play+Rec set dual mic at ap side, dev:0x%x, mode:%d, gain:%d", __FUNCTION__, dev, mode, volume);
+ }
+
+ // open buffer thread
+ ALOGD("%s(), threadloop thread~", __FUNCTION__);
+ pthread_mutex_lock(&mRecPlayMutex);
+ ret = pthread_create(&mRecPlayThreadID, NULL, DMNR_Play_Rec_ApSide_Routine, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s(), pthread_create error!!", __FUNCTION__);
+ }
+
+ ALOGD("%s(), +mRecPlayExit_Cond wait", __FUNCTION__);
+ ret = pthread_cond_timedwait(&mRecPlayExit_Cond, &mRecPlayMutex, &timeout);
+ ALOGD("%s(), -mRecPlayExit_Cond receive ret=%d", __FUNCTION__, ret);
+ pthread_mutex_unlock(&mRecPlayMutex);
+
+ m_bDMNRPlaying = true;
+ pthread_mutex_unlock(&mP2WMutex);
+
+ usleep(10 * 1000);
+ } else if (!bEnable && m_bDMNRPlaying) {
+ //stop buffer thread
+ ALOGD("%s(), close", __FUNCTION__);
+ pthread_mutex_lock(&mRecPlayMutex);
+ if (!m_bRecPlayThreadExit) {
+ m_bRecPlayThreadExit = true;
+ ALOGD("%s(), +mRecPlayExit_Cond wait", __FUNCTION__);
+ ret = pthread_cond_timedwait(&mRecPlayExit_Cond, &mRecPlayMutex, &timeout);
+ ALOGD("%s(), -mRecPlayExit_Cond receive ret=%d", __FUNCTION__, ret);
+ }
+ pthread_mutex_unlock(&mRecPlayMutex);
+
+ //wait to make sure all message is processed
+ usleep(200 * 1000);
+
+ //set back MIC gain
+ AUDIO_VER1_CUSTOM_VOLUME_STRUCT VolumeCustomParam;//volume custom data
+ AudioCustParamClient::GetInstance()->GetVolumeVer1ParamFromNV(&VolumeCustomParam);
+
+#ifdef MTK_NEW_VOL_CONTROL
+ // reset volume from xml
+ AudioMTKGainController::getInstance()->updateXmlParam(REC_VOL_AUDIOTYPE_NAME);
+#else
+ uint32_t voldB = VolumeCustomParam.audiovolume_mic[VOLUME_NORMAL_MODE][3];
+ voldB = voldB > UPLINK_GAIN_MAX ? UPLINK_GAIN_MAX : voldB;
+ mAudioALSAVolumeController->SetMicGainTuning(Normal_Mic, voldB);
+
+ voldB = VolumeCustomParam.audiovolume_mic[VOLUME_SPEAKER_MODE][3];
+ voldB = voldB > UPLINK_GAIN_MAX ? UPLINK_GAIN_MAX : voldB;
+ mAudioALSAVolumeController->SetMicGainTuning(Handfree_Mic, voldB);
+#endif
+ mAudioSpeechEnhanceInfoInstance-> SetAPTuningMode(TUNING_MODE_NONE);
+
+ m_bDMNRPlaying = false;
+
+ pthread_mutex_lock(&mP2WMutex);
+ if (m_pInputFile) { fclose(m_pInputFile); }
+ m_pInputFile = NULL;
+ pthread_mutex_unlock(&mP2WMutex);
+
+ if (m_pOutputFile) { fclose(m_pOutputFile); }
+ m_pOutputFile = NULL;
+ } else {
+ ALOGD("%s(), The DMNR Tuning State is error, bEnable=%d, playing=%d", __FUNCTION__, bEnable, m_bPlaying);
+ return BAD_VALUE;
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAParamTuner::enableFIRRecord(bool bEnable)
+{
+ ALOGD("%s(), bEnable:%d", __FUNCTION__, bEnable);
+
+ // 3 sec for timeout
+ struct timeval now;
+ struct timespec timeout;
+ gettimeofday(&now, NULL);
+ timeout.tv_sec = now.tv_sec + 3;
+ timeout.tv_nsec = now.tv_usec * 1000;
+ int ret;
+
+ if (bEnable && !mStartRec)
+ {
+ // open output file for record
+ m_pOutputFile = fopen(m_strOutFileName, "wb");
+ ALOGD("%s(), open output file filename:%s", __FUNCTION__, m_strOutFileName);
+ if (m_pOutputFile == NULL)
+ {
+ ALOGW("%s(), open output file fail!!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ // open buffer thread
+ ALOGD("%s(), threadloop thread~", __FUNCTION__);
+ pthread_mutex_lock(&mRecPlayMutex);
+ ret = pthread_create(&mRecPlayThreadID, NULL, FIR_Rec_ApSide_Routine, (void *)this);
+ if (ret != 0)
+ {
+ ALOGE("%s(), pthread_create error!!", __FUNCTION__);
+ }
+
+ ALOGD("%s(), +mRecPlayExit_Cond wait", __FUNCTION__);
+ ret = pthread_cond_timedwait(&mRecPlayExit_Cond, &mRecPlayMutex, &timeout);
+ ALOGD("%s(), -mRecPlayExit_Cond receive ret=%d", __FUNCTION__, ret);
+ pthread_mutex_unlock(&mRecPlayMutex);
+
+ mStartRec = true;
+ }
+ else if (!bEnable && mStartRec)
+ {
+ //stop buffer thread
+ ALOGD("%s(), close", __FUNCTION__);
+ pthread_mutex_lock(&mRecPlayMutex);
+ if (!m_bRecPlayThreadExit)
+ {
+ m_bRecPlayThreadExit = true;
+ ALOGD("%s(), +mRecPlayExit_Cond wait", __FUNCTION__);
+ ret = pthread_cond_timedwait(&mRecPlayExit_Cond, &mRecPlayMutex, &timeout);
+ ALOGD("%s(), -mRecPlayExit_Cond receive ret=%d", __FUNCTION__, ret);
+ }
+ pthread_mutex_unlock(&mRecPlayMutex);
+
+ //wait to make sure all message is processed or tuning tool may crash
+ usleep(200 * 1000);
+
+ mStartRec = false;
+
+ if (m_pOutputFile) { fclose(m_pOutputFile); }
+ m_pOutputFile = NULL;
+ }
+ else
+ {
+ ALOGD("%s(), The FIR Record State is error, bEnable=%d", __FUNCTION__, bEnable);
+ return BAD_VALUE;
+ }
+
+ return NO_ERROR;
+}
+
+#if defined(MTK_AUDIO_GAIN_TABLE) && !defined(MTK_NEW_VOL_CONTROL)
+status_t AudioALSAParamTuner::getGainInfoForDisp(void *pParam) {
+ //for UI Disp
+ PCDispTotolStru *ptr = (PCDispTotolStru *)pParam;
+
+ //ptr->itemNum = 0xFFFF;
+ ptr->itemNum = 0xF3FF;
+ getPCDispItem(pParam);
+ getPCDispMic(pParam);
+
+ ptr->gainRangeNum = 0x3FF;
+ memcpy(ptr->gainRange, gainRangeCopy, sizeof(gainRangeCopy));
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAParamTuner::getPCDispItem(void *pParam) {
+ ALOGD("+%s()", __FUNCTION__);
+ PCDispTotolStru *ptr = (PCDispTotolStru *)pParam;
+ mAudioHWVolumeCapabilityInstance = AudioHWVolumeCapability::getInstance();
+
+ //for DispItem[0]
+ memcpy(ptr->DispItem[0].strType, "VOIP", sizeof("VOIP"));
+ ptr->DispItem[0].level = mAudioHWVolumeCapabilityInstance->getStreamLevel((int(AUDIO_STREAM_VOICE_CALL)));
+ ptr->DispItem[0].subItemNum = 0x7;
+ getPCDispSubItem(pParam, int(AUDIO_STREAM_VOICE_CALL));
+
+ //for DispItem[1]
+ memcpy(ptr->DispItem[1].strType, "System", sizeof("System"));
+ ptr->DispItem[1].level = mAudioHWVolumeCapabilityInstance->getStreamLevel((int(AUDIO_STREAM_SYSTEM)));
+ ptr->DispItem[1].subItemNum = 0x6;
+ getPCDispSubItem(pParam, int(AUDIO_STREAM_SYSTEM));
+
+ //for DispItem[2]
+ memcpy(ptr->DispItem[2].strType, "Ring", sizeof("Ring"));
+ ptr->DispItem[2].level = mAudioHWVolumeCapabilityInstance->getStreamLevel((int(AUDIO_STREAM_RING)));
+ ptr->DispItem[2].subItemNum = 0x6;
+ getPCDispSubItem(pParam, int(AUDIO_STREAM_RING));
+
+ //for DispItem[3]
+ memcpy(ptr->DispItem[3].strType, "Music", sizeof("Music"));
+ ptr->DispItem[3].level = mAudioHWVolumeCapabilityInstance->getStreamLevel((int(AUDIO_STREAM_MUSIC)));
+ ptr->DispItem[3].subItemNum = 0x6;
+ getPCDispSubItem(pParam, int(AUDIO_STREAM_MUSIC));
+
+ //for DispItem[4]
+ memcpy(ptr->DispItem[4].strType, "Alarm", sizeof("Alarm"));
+ ptr->DispItem[4].level = mAudioHWVolumeCapabilityInstance->getStreamLevel((int(AUDIO_STREAM_ALARM)));
+ ptr->DispItem[4].subItemNum = 0x6;
+ getPCDispSubItem(pParam, int(AUDIO_STREAM_ALARM));
+
+ //for DispItem[5]
+ memcpy(ptr->DispItem[5].strType, "Notification", sizeof("Notification"));
+ ptr->DispItem[5].level = mAudioHWVolumeCapabilityInstance->getStreamLevel((int(AUDIO_STREAM_NOTIFICATION)));
+ ptr->DispItem[5].subItemNum = 0x6;
+ getPCDispSubItem(pParam, int(AUDIO_STREAM_NOTIFICATION));
+
+ //for DispItem[6]
+ memcpy(ptr->DispItem[6].strType, "Bluetooth_sco", sizeof("Bluetooth_sco"));
+ ptr->DispItem[6].level = mAudioHWVolumeCapabilityInstance->getStreamLevel((int(AUDIO_STREAM_BLUETOOTH_SCO)));
+ ptr->DispItem[6].subItemNum = 0x2;
+ getPCDispSubItem(pParam, int(AUDIO_STREAM_BLUETOOTH_SCO));
+
+ //for DispItem[7]
+ memcpy(ptr->DispItem[7].strType, "Enforce Audbile", sizeof("Enforce Audbile"));
+ ptr->DispItem[7].level = mAudioHWVolumeCapabilityInstance->getStreamLevel((int(AUDIO_STREAM_ENFORCED_AUDIBLE)));
+ ptr->DispItem[7].subItemNum = 0x6;
+ getPCDispSubItem(pParam, int(AUDIO_STREAM_ENFORCED_AUDIBLE));
+
+ //for DispItem[8]
+ memcpy(ptr->DispItem[8].strType, "DTMF", sizeof("DTMF"));
+ ptr->DispItem[8].level = mAudioHWVolumeCapabilityInstance->getStreamLevel((int(AUDIO_STREAM_DTMF)));
+ ptr->DispItem[8].subItemNum = 0x6;
+ getPCDispSubItem(pParam, int(AUDIO_STREAM_DTMF));
+
+ //for DispItem[9]
+ memcpy(ptr->DispItem[9].strType, "TTS", sizeof("TTS"));
+ ptr->DispItem[9].level = mAudioHWVolumeCapabilityInstance->getStreamLevel((int(AUDIO_STREAM_TTS)));
+ ptr->DispItem[9].subItemNum = 0x6;
+ getPCDispSubItem(pParam, int(AUDIO_STREAM_TTS));
+
+ //for DispItem[10]
+
+ //for DispItem[11]
+
+ //for DispItem[12]
+ memcpy(ptr->DispItem[12].strType, "SidetoneNB", sizeof("SidetoneNB"));
+ ptr->DispItem[12].level = 0x0100;
+ ptr->DispItem[12].subItemNum = 0x7;
+ getPCDispSubItem(pParam, int(AUDIO_STREAM_VOICE_CALL), 3);
+
+ //for DispItem[13]
+ memcpy(ptr->DispItem[13].strType, "SidetoneWB", sizeof("SidetoneWB"));
+ ptr->DispItem[13].level = 0x0100;
+ ptr->DispItem[13].subItemNum = 0x7;
+ getPCDispSubItem(pParam, int(AUDIO_STREAM_VOICE_CALL), 4);
+
+ //for DispItem[14]
+ memcpy(ptr->DispItem[14].strType, "SpeechNB", sizeof("SpeechNB"));
+ ptr->DispItem[14].level = mAudioHWVolumeCapabilityInstance->getStreamLevel((int(AUDIO_STREAM_VOICE_CALL)));
+ ptr->DispItem[14].level = (ptr->DispItem[14].level & 0xFF00) | ((ptr->DispItem[14].level & 0xFF00) >> 8);
+ ptr->DispItem[14].subItemNum = 0x7;
+ getPCDispSubItem(pParam, int(AUDIO_STREAM_VOICE_CALL), 1);
+
+ //for DispItem[15]
+ memcpy(ptr->DispItem[15].strType, "SpeechWB", sizeof("SpeechWB"));
+ ptr->DispItem[15].level = mAudioHWVolumeCapabilityInstance->getStreamLevel((int(AUDIO_STREAM_VOICE_CALL)));
+ ptr->DispItem[15].level = (ptr->DispItem[15].level & 0xFF00) | ((ptr->DispItem[15].level & 0xFF00) >> 8);
+ ptr->DispItem[15].subItemNum = 0x7;
+ getPCDispSubItem(pParam, int(AUDIO_STREAM_VOICE_CALL), 2);
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+status_t AudioALSAParamTuner::getPCDispSubItem(void *pParam, int streamType, int speech) {
+ ALOGD("+%s()", __FUNCTION__);
+ PCDispTotolStru *ptr = (PCDispTotolStru *)pParam;
+ mAudioHWVolumeCapabilityInstance = AudioHWVolumeCapability::getInstance();
+
+ switch ((audio_stream_type_t)streamType) {
+ case AUDIO_STREAM_VOICE_CALL: {
+ ALOGD("%s(), speech is %d", __FUNCTION__, speech);
+ if (speech != 1 && speech != 2 && speech != 3 && speech != 4) { //for VOIP
+ memcpy(ptr->DispItem[0].subItem[0].outputDevice, "Receiver", sizeof("Receiver"));
+ ptr->DispItem[0].subItem[0].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_RECEIVER);
+
+ memcpy(ptr->DispItem[0].subItem[1].outputDevice, "Headset", sizeof("Headset"));
+ ptr->DispItem[0].subItem[1].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_HEADPHONE);
+
+ memcpy(ptr->DispItem[0].subItem[2].outputDevice, "Speaker", sizeof("Speaker"));
+#ifdef USING_EXTAMP_HP
+ ptr->DispItem[0].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, false);
+#else
+ ptr->DispItem[0].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, true);
+#endif
+ } else if (speech == 1) { // for speech NB
+ memcpy(ptr->DispItem[14].subItem[0].outputDevice, "Incall Receiver", sizeof("Incall Receiver"));
+ ptr->DispItem[14].subItem[0].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(PHONE_CALL_MODE, CAPABILITY_DEVICE_RECEIVER);
+
+ memcpy(ptr->DispItem[14].subItem[1].outputDevice, "Incall Headset", sizeof("Incall Headset"));
+ ptr->DispItem[14].subItem[1].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(PHONE_CALL_MODE, CAPABILITY_DEVICE_HEADPHONE);
+
+ memcpy(ptr->DispItem[14].subItem[2].outputDevice, "Incall Speaker", sizeof("Incall Speaker"));
+#ifdef USING_EXTAMP_HP
+ ptr->DispItem[14].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(PHONE_CALL_MODE, CAPABILITY_DEVICE_SPEAKER, false);
+#else
+ ptr->DispItem[14].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(PHONE_CALL_MODE, CAPABILITY_DEVICE_SPEAKER, true);
+#endif
+ } else if (speech == 2) { //for speech WB
+ memcpy(ptr->DispItem[15].subItem[0].outputDevice, "Incall Receiver", sizeof("Incall Receiver"));
+ ptr->DispItem[15].subItem[0].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(PHONE_CALL_MODE, CAPABILITY_DEVICE_RECEIVER);
+
+ memcpy(ptr->DispItem[15].subItem[1].outputDevice, "Incall Headset", sizeof("Incall Headset"));
+ ptr->DispItem[15].subItem[1].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(PHONE_CALL_MODE, CAPABILITY_DEVICE_HEADPHONE);
+
+ memcpy(ptr->DispItem[15].subItem[2].outputDevice, "Incall Speaker", sizeof("Incall Speaker"));
+#ifdef USING_EXTAMP_HP
+ ptr->DispItem[15].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(PHONE_CALL_MODE, CAPABILITY_DEVICE_SPEAKER, false);
+#else
+ ptr->DispItem[15].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(PHONE_CALL_MODE, CAPABILITY_DEVICE_SPEAKER, true);
+#endif
+ } else if (speech == 3) { // for sidetone NB
+ memcpy(ptr->DispItem[12].subItem[0].outputDevice, "Incall Receiver", sizeof("Incall Receiver"));
+ ptr->DispItem[12].subItem[0].AnalogPoint = 0x0;
+
+ memcpy(ptr->DispItem[12].subItem[1].outputDevice, "Incall Headset", sizeof("Incall Headset"));
+ ptr->DispItem[12].subItem[1].AnalogPoint = 0x0;
+
+ memcpy(ptr->DispItem[12].subItem[2].outputDevice, "Incall Speaker", sizeof("Incall Speaker"));
+ // ptr->DispItem[12].subItem[2].AnalogPoint = 0x0;
+#ifdef USING_EXTAMP_HP
+ ptr->DispItem[12].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(-1, -1, false);
+#else
+ ptr->DispItem[12].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(-1, -1, true);
+#endif
+ } else if (speech == 4) { //for sidetone WB
+ memcpy(ptr->DispItem[13].subItem[0].outputDevice, "Incall Receiver", sizeof("Incall Receiver"));
+ ptr->DispItem[13].subItem[0].AnalogPoint = 0x0;
+
+ memcpy(ptr->DispItem[13].subItem[1].outputDevice, "Incall Headset", sizeof("Incall Headset"));
+ ptr->DispItem[13].subItem[1].AnalogPoint = 0x0;
+
+ memcpy(ptr->DispItem[13].subItem[2].outputDevice, "Incall Speaker", sizeof("Incall Speaker"));
+ // ptr->DispItem[13].subItem[2].AnalogPoint = 0x0;
+#ifdef USING_EXTAMP_HP
+ ptr->DispItem[13].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(-1, -1, false);
+#else
+ ptr->DispItem[13].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(-1, -1, true);
+#endif
+ }
+ }
+ break;
+ case AUDIO_STREAM_SYSTEM: {
+ memcpy(ptr->DispItem[1].subItem[1].outputDevice, "Headset", sizeof("Headset"));
+ ptr->DispItem[1].subItem[1].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_HEADPHONE);
+
+ memcpy(ptr->DispItem[1].subItem[2].outputDevice, "Speaker", sizeof("Speaker"));
+#ifdef USING_EXTAMP_HP
+ ptr->DispItem[1].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, false);
+#else
+ ptr->DispItem[1].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, true);
+#endif
+ }
+ break;
+ case AUDIO_STREAM_RING: {
+ memcpy(ptr->DispItem[2].subItem[1].outputDevice, "Headset", sizeof("Headset"));
+ ptr->DispItem[2].subItem[1].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_HEADPHONE);
+
+ memcpy(ptr->DispItem[2].subItem[2].outputDevice, "Speaker", sizeof("Speaker"));
+#ifdef USING_EXTAMP_HP
+ ptr->DispItem[2].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, false);
+#else
+ ptr->DispItem[2].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, true);
+#endif
+ }
+ break;
+ case AUDIO_STREAM_MUSIC: {
+ memcpy(ptr->DispItem[3].subItem[1].outputDevice, "Headset", sizeof("Headset"));
+ ptr->DispItem[3].subItem[1].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_HEADPHONE);
+
+ memcpy(ptr->DispItem[3].subItem[2].outputDevice, "Speaker", sizeof("Speaker"));
+#ifdef USING_EXTAMP_HP
+ ptr->DispItem[3].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, false);
+#else
+ ptr->DispItem[3].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, true);
+#endif
+ }
+ break;
+ case AUDIO_STREAM_ALARM: {
+ memcpy(ptr->DispItem[4].subItem[1].outputDevice, "Headset", sizeof("Headset"));
+ ptr->DispItem[4].subItem[1].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_HEADPHONE);
+
+ memcpy(ptr->DispItem[4].subItem[2].outputDevice, "Speaker", sizeof("Speaker"));
+#ifdef USING_EXTAMP_HP
+ ptr->DispItem[4].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, false);
+#else
+ ptr->DispItem[4].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, true);
+#endif
+ }
+ break;
+ case AUDIO_STREAM_NOTIFICATION: {
+ memcpy(ptr->DispItem[5].subItem[1].outputDevice, "Headset", sizeof("Headset"));
+ ptr->DispItem[5].subItem[1].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_HEADPHONE);
+
+ memcpy(ptr->DispItem[5].subItem[2].outputDevice, "Speaker", sizeof("Speaker"));
+#ifdef USING_EXTAMP_HP
+ ptr->DispItem[5].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, false);
+#else
+ ptr->DispItem[5].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, true);
+#endif
+ }
+ break;
+ case AUDIO_STREAM_BLUETOOTH_SCO: {
+ memcpy(ptr->DispItem[6].subItem[1].outputDevice, "Headset", sizeof("Headset"));
+ ptr->DispItem[6].subItem[1].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_NONE);
+ }
+ break;
+ case AUDIO_STREAM_ENFORCED_AUDIBLE: {
+ memcpy(ptr->DispItem[7].subItem[1].outputDevice, "Headset", sizeof("Headset"));
+ ptr->DispItem[7].subItem[1].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_HEADPHONE);
+
+ memcpy(ptr->DispItem[7].subItem[2].outputDevice, "Speaker", sizeof("Speaker"));
+#ifdef USING_EXTAMP_HP
+ ptr->DispItem[7].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, false);
+#else
+ ptr->DispItem[7].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, true);
+#endif
+ }
+ break;
+ case AUDIO_STREAM_DTMF: {
+ memcpy(ptr->DispItem[8].subItem[1].outputDevice, "Headset", sizeof("Headset"));
+ ptr->DispItem[8].subItem[1].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_HEADPHONE);
+
+ memcpy(ptr->DispItem[8].subItem[2].outputDevice, "Speaker", sizeof("Speaker"));
+#ifdef USING_EXTAMP_HP
+ ptr->DispItem[8].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, false);
+#else
+ ptr->DispItem[8].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, true);
+#endif
+ }
+ break;
+ case AUDIO_STREAM_TTS: {
+ memcpy(ptr->DispItem[9].subItem[1].outputDevice, "Headset", sizeof("Headset"));
+ ptr->DispItem[9].subItem[1].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_HEADPHONE);
+
+ memcpy(ptr->DispItem[9].subItem[2].outputDevice, "Speaker", sizeof("Speaker"));
+#ifdef USING_EXTAMP_HP
+ ptr->DispItem[9].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, false);
+#else
+ ptr->DispItem[9].subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, true);
+#endif
+ }
+ break;
+ default:
+ break;
+ }
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSAParamTuner::getPCDispMic(void *pParam) {
+ PCDispTotolStru *ptr = (PCDispTotolStru *)pParam;
+
+ memcpy(ptr->DispMic.strType, "Mic", sizeof("Mic"));
+ ptr->DispMic.subItemNum = 0xF0FFFF;
+ memcpy(ptr->DispMic.subItem, subItemMic, sizeof(ptr->DispMic.subItem));
+
+ return NO_ERROR;
+}
+#ifdef MTK_AUDIO_GAIN_TABLE_BT
+status_t AudioALSAParamTuner::getBtNrecInfoForDisp(void *pParam) {
+ PCDispItem *ptr = (PCDispItem *)pParam;
+
+ //for DispItem BT NREC
+ memcpy(ptr->strType, "Bluetooth_nrec", sizeof("Bluetooth_nrec"));
+ ptr->level = mAudioHWVolumeCapabilityInstance->getStreamLevel((int(AUDIO_STREAM_BLUETOOTH_SCO)));
+ ptr->subItemNum = 0x6;
+
+ memcpy(ptr->subItem[1].outputDevice, "Headset", sizeof("Headset"));
+ ptr->subItem[1].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_HEADPHONE);
+
+ memcpy(ptr->subItem[2].outputDevice, "Speaker", sizeof("Speaker"));
+#ifdef USING_EXTAMP_HP
+ ptr->subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, false);
+#else
+ ptr->subItem[2].AnalogPoint = mAudioHWVolumeCapabilityInstance->getDevicePath(NORMAL_MODE, CAPABILITY_DEVICE_SPEAKER, true);
+#endif
+
+ return NO_ERROR;
+}
+#endif
+#endif
+
+status_t AudioALSAParamTuner::setSphVolume(uint32_t mode, uint32_t gain) {
+ ALOGV("+%s(), speech mode=0x%x, gain=0x%x", __FUNCTION__, mode, gain);
+ int32_t degradeDb = (DEVICE_VOLUME_STEP - MapVoiceVolumetoCustom(gain)) / VOICE_ONEDB_STEP;
+ int voiceAnalogRange = DEVICE_MAX_VOLUME - DEVICE_MIN_VOLUME;
+
+ switch (mode) {
+ case SPEECH_MODE_NORMAL:
+ if (degradeDb <= AUDIO_BUFFER_HW_GAIN_STEP) {
+ mAudioALSAVolumeController->SetReceiverGain(degradeDb);
+ mAudioALSAVolumeController->ApplyMdDlGain(0);
+ } else {
+ mAudioALSAVolumeController->SetReceiverGain(voiceAnalogRange);
+ degradeDb -= voiceAnalogRange;
+ mAudioALSAVolumeController->ApplyMdDlGain(degradeDb);
+ }
+ mAudioALSAVolumeController->ApplyMicGain(Normal_Mic, AUDIO_MODE_IN_CALL);
+ break;
+ case SPEECH_MODE_EARPHONE:
+ if (degradeDb <= AUDIO_BUFFER_HW_GAIN_STEP) {
+ mAudioALSAVolumeController->SetHeadPhoneRGain(degradeDb);
+ mAudioALSAVolumeController->SetHeadPhoneLGain(degradeDb);
+ mAudioALSAVolumeController->ApplyMdDlGain(0);
+ } else {
+ mAudioALSAVolumeController->SetHeadPhoneRGain(voiceAnalogRange);
+ mAudioALSAVolumeController->SetHeadPhoneLGain(voiceAnalogRange);
+ degradeDb -= voiceAnalogRange;
+ mAudioALSAVolumeController->ApplyMdDlGain(degradeDb);
+ }
+ mAudioALSAVolumeController->ApplyMicGain(Headset_Mic, AUDIO_MODE_IN_CALL);
+ break;
+ case SPEECH_MODE_LOUD_SPEAKER:
+ if (degradeDb <= AUDIO_BUFFER_HW_GAIN_STEP) {
+#ifdef USING_EXTAMP_HP
+ mAudioALSAVolumeController->SetHeadPhoneRGain(degradeDb);
+ mAudioALSAVolumeController->SetHeadPhoneLGain(degradeDb);
+#else
+ mAudioALSAVolumeController->SetSpeakerGain(degradeDb);
+
+#endif
+ mAudioALSAVolumeController->ApplyMdDlGain(0);
+ } else {
+ voiceAnalogRange = DEVICE_AMP_MAX_VOLUME - DEVICE_AMP_MIN_VOLUME;
+#ifdef USING_EXTAMP_HP
+ mAudioALSAVolumeController->SetHeadPhoneRGain(voiceAnalogRange);
+ mAudioALSAVolumeController->SetHeadPhoneLGain(voiceAnalogRange);
+#else
+ mAudioALSAVolumeController->SetSpeakerGain(voiceAnalogRange);
+#endif
+ degradeDb -= voiceAnalogRange;
+ mAudioALSAVolumeController->ApplyMdDlGain(degradeDb);
+ }
+ mAudioALSAVolumeController->ApplyMicGain(Handfree_Mic, AUDIO_MODE_IN_CALL);
+ break;
+ default:
+ break;
+ }
+ return NO_ERROR;
+}
+};
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPcmDataCaptureIn.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPcmDataCaptureIn.cpp
new file mode 100644
index 0000000..eb1e778
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPcmDataCaptureIn.cpp
@@ -0,0 +1,469 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAPcmDataCaptureIn.h"
+#include "AudioUtility.h"
+#include "AudioType.h"
+#include <AudioLock.h>
+#include "AudioALSADeviceParser.h"
+#include <pthread.h>
+#include <sys/prctl.h>
+#include <sys/prctl.h>
+#include "AudioALSADriverUtility.h"
+#include <cutils/sched_policy.h>
+
+#define LOG_TAG "AudioALSAPcmDataCaptureIn"
+#define IV_RETRY_TIMES 10
+
+namespace android {
+
+
+AudioALSAPcmDataCaptureIn *AudioALSAPcmDataCaptureIn::mAudioALSAPcmDataCaptureIn = NULL;
+
+AudioALSAPcmDataCaptureIn *AudioALSAPcmDataCaptureIn::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSAPcmDataCaptureIn == NULL) {
+ mAudioALSAPcmDataCaptureIn = new AudioALSAPcmDataCaptureIn();
+ }
+ ASSERT(mAudioALSAPcmDataCaptureIn != NULL);
+ return mAudioALSAPcmDataCaptureIn;
+}
+
+
+AudioALSAPcmDataCaptureIn::AudioALSAPcmDataCaptureIn() {
+ ALOGD("%s()", __FUNCTION__);
+ mAudioPcmInputThread = new AudioPCMInputThread(this);
+ ALOGD("%s new mAudioPcmInputThread", __func__);
+
+ if (mAudioPcmInputThread.get() != NULL) {
+ ALOGD("mAudioPcmInputThread->run();");
+ mAudioPcmInputThread->run("AudioALSAPcmDataCaptureIn");
+ } else {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ }
+ memset((void *)&mStreamAttributeSource, 0, sizeof(stream_attribute_t));
+
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+AudioALSAPcmDataCaptureIn::~AudioALSAPcmDataCaptureIn() {
+ ALOGD("%s()", __FUNCTION__);
+
+ int ret = 0;
+ ret = mAudioPcmInputThread->requestExitAndWait();
+ if (ret == WOULD_BLOCK) {
+ mAudioPcmInputThread->requestExit();
+ }
+ mAudioPcmInputThread.clear();
+ mAudioPcmInputThread = NULL;
+
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+ssize_t AudioALSAPcmDataCaptureIn::read(void *buffer, ssize_t bytes) {
+ int retcode = 0;
+ retcode = mAudioPcmInputThread->readIVData(buffer, bytes);
+ return retcode;
+}
+
+status_t AudioALSAPcmDataCaptureIn::SetThreadEnable() {
+ mAudioPcmInputThread->SetThreadEnable();
+ return NO_ERROR;
+}
+
+status_t AudioALSAPcmDataCaptureIn::SetThreadDisable() {
+ mAudioPcmInputThread->SetThreadDisable();
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPcmDataCaptureIn::Standby() {
+ ALOGD("%s", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPcmDataCaptureIn::GetPcmConfig(pcm_config *mPcmInputConfig) {
+ mAudioPcmInputThread->GetPcmConfig(mPcmInputConfig);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPcmDataCaptureIn::SetPcmConfig(pcm_config mPcmInputConfig) {
+ mAudioPcmInputThread->SetPcmConfig(mPcmInputConfig);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPcmDataCaptureIn::AudioPCMInputThread::SetPcmConfig(pcm_config I2SInputConfig) {
+ ALOGD("%s", __FUNCTION__);
+ memcpy((void *)&mPcmInputConfig, (void *)&I2SInputConfig, sizeof(pcm_config));
+ return NO_ERROR;
+}
+
+status_t AudioALSAPcmDataCaptureIn::AudioPCMInputThread::GetPcmConfig(pcm_config *pI2SInputConfig) {
+ ALOGD("%s", __FUNCTION__);
+ memcpy((void *)pI2SInputConfig, (void *)&mPcmInputConfig, sizeof(pcm_config));
+ return NO_ERROR;
+}
+
+void AudioALSAPcmDataCaptureIn::AudioPCMInputThread::onFirstRef() {
+ ALOGD("%s", __func__);
+ mReadBufferSize = 0;
+ mReadBuffer = NULL;
+ mbRunning = false;
+ mbStatusChange = false;
+ mReadBuffer = NULL;
+ mReadBufferSize = 0;
+ memset((void *)&mPcmInputConfig, 0, sizeof(pcm_config));
+ AllocateResource();
+}
+
+void AudioALSAPcmDataCaptureIn::AudioPCMInputThread::OpenPCMDump(const char *class_name) {
+ char mDumpFileName[128];
+ sprintf(mDumpFileName, "%s.%d.%s.pcm", streaminIVIn, DumpIVFileNum, class_name);
+
+ mPCMIVDumpFile = NULL;
+ mPCMIVDumpFile = AudioOpendumpPCMFile(mDumpFileName, streamout_propty);
+
+ if (mPCMIVDumpFile != NULL) {
+ ALOGD("%s DumpFileName = %s", __FUNCTION__, mDumpFileName);
+ DumpIVFileNum++;
+ DumpIVFileNum %= MAX_DUMP_NUM;
+ }
+}
+
+void AudioALSAPcmDataCaptureIn::AudioPCMInputThread::ClosePCMDump() {
+ if (mPCMIVDumpFile) {
+ AudioCloseDumpPCMFile(mPCMIVDumpFile);
+ ALOGD("%s(), close it", __FUNCTION__);
+ }
+}
+
+status_t AudioALSAPcmDataCaptureIn::AudioPCMInputThread:: SetThreadEnable() {
+ uint32_t tryCount = 0;
+
+ ALOGD("%s", __FUNCTION__);
+ Mutex::Autolock _l(mPcmLock);
+ OpenPCMDump(LOG_TAG);
+ mbStatusChange = mbRunning ^ 1;
+ ALOGD("%s mbStatusChange = %d mbRunning = %d", __FUNCTION__, mbStatusChange, mbRunning);
+ mbRunning = true;
+ if (mbStatusChange == true) {
+ mWaitWorkCV.signal();
+ }
+ ALOGD("+%s", __FUNCTION__);
+ status_t retval = mPcmWaitWorkCV.waitRelative(mPcmLock, milliseconds(50));
+ while (retval != NO_ERROR && tryCount < IV_RETRY_TIMES) {
+ tryCount++;
+ ALOGD("%s try mPcmWaitWorkCV tryCount = %d retval = %d", __FUNCTION__, tryCount, retval);
+ mWaitWorkCV.signal();
+ retval = mPcmWaitWorkCV.waitRelative(mPcmLock, milliseconds(50));
+
+ }
+ ALOGD("-%s retval = %d", __FUNCTION__, retval);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPcmDataCaptureIn::AudioPCMInputThread:: SetThreadDisable() {
+ ALOGD("+%s", __FUNCTION__);
+ Mutex::Autolock _l(mPcmLock);
+ ClosePCMDump();
+ mbStatusChange = mbRunning ^ 0;
+ mbRunning = false;
+ ALOGD("++%s", __FUNCTION__);
+ mPcmWaitWorkCV.wait(mPcmLock);
+ ALOGD("-%s", __FUNCTION__);
+ return NO_ERROR;
+}
+
+/*
+* Read from Ringbuffer
+* @ param buffer : buffer to be filled
+* @ param bytes : how many bytes to be read
+*/
+int AudioALSAPcmDataCaptureIn::AudioPCMInputThread::readIVData(void *buffer, ssize_t bytes) {
+ Mutex::Autolock _l(mRingLock);
+ int datacount = RingBuf_getDataCount(&mRawDataBuf);
+ //ALOGD("+%s bytes = %d datacount = %d", __FUNCTION__, bytes,datacount);
+ if (datacount < bytes) {
+ ALOGD("%s datacount < bytes datacount = %d bytes = %d", __FUNCTION__, datacount, bytes);
+ memset(buffer,0,bytes);
+ return bytes;
+ }
+ RingBuf_copyToLinear((char *)buffer, &mRawDataBuf, bytes);
+ //ALOGD("-%s bytes = %d", __func__, bytes);
+ return bytes;
+}
+
+
+status_t AudioALSAPcmDataCaptureIn::AudioPCMInputThread::OpenPcm() {
+ // open pcm driver
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmI2S2ADCCapture);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmI2S2ADCCapture);
+ ALOGD("%s channels = %d format = %d period_count = %d period_size= %d", __FUNCTION__,
+ mPcmInputConfig.channels, mPcmInputConfig.format, mPcmInputConfig.period_count, mPcmInputConfig.period_size);
+ mInputPcm = pcm_open(cardindex, pcmindex, PCM_IN, &mPcmInputConfig);
+ if (mInputPcm == NULL) {
+ ALOGE("%s(), mPcm == NULL!!", __FUNCTION__);
+ }
+ ALOGD("-%s(), mPcm = %p", __FUNCTION__, mInputPcm);
+ ASSERT(mInputPcm != NULL);
+ StartPcm();
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAPcmDataCaptureIn::AudioPCMInputThread::ClosePcm() {
+ ALOGD("%s", __FUNCTION__);
+ if (mInputPcm != NULL) {
+ pcm_stop(mInputPcm);
+ pcm_close(mInputPcm);
+ mInputPcm = NULL;
+ }
+ return NO_ERROR;
+}
+
+status_t AudioALSAPcmDataCaptureIn::AudioPCMInputThread::StartPcm() {
+ ALOGD("%s(), mPcm = %p", __FUNCTION__, mInputPcm);
+ int ret = pcm_start(mInputPcm);
+ if (ret) {
+ ALOGE("%s(), pcm_start(%p) fail due to %s", __FUNCTION__, mInputPcm, pcm_get_error(mInputPcm));
+ ASSERT(0);
+ }
+ return ret;
+}
+
+unsigned int AudioALSAPcmDataCaptureIn::AudioPCMInputThread::FormatTransfer(
+ int SourceFormat, int TargetFormat, void *Buffer, unsigned int mReadBufferSize) {
+ unsigned mReformatSize = 0;
+ int *srcbuffer = (int *)Buffer;
+ short *dstbuffer = (short *)Buffer;
+ if (SourceFormat == PCM_FORMAT_S32_LE && TargetFormat == PCM_FORMAT_S16_LE) {
+ short temp = 0;
+ while (mReadBufferSize) {
+ temp = (short)((*srcbuffer) >> 8);
+ *dstbuffer = temp;
+ srcbuffer++;
+ dstbuffer++;
+ mReadBufferSize -= sizeof(int);
+ mReformatSize += sizeof(short);
+ }
+ } else {
+ mReformatSize = mReadBufferSize;
+ }
+ return mReformatSize;
+}
+
+
+int AudioALSAPcmDataCaptureIn::AudioPCMInputThread::GetPcmData() {
+ //ALOGD("+%s", __FUNCTION__);
+ int ReadSize = 0;
+ unsigned int RingFreeSpace = 0;
+ unsigned int ReformatSize = mReadBufferSize;
+ if (mbRunning == true) {
+ if (mInputPcm != NULL) {
+ memset((void *)mReadBuffer, 0, mReadBufferSize);
+ ReadSize = pcm_read(mInputPcm, (void *)mReadBuffer, mReadBufferSize);
+ if (ReadSize != 0) {
+ ALOGD("+%s mReadBufferSize = %d ReadSize = %d", __FUNCTION__, mReadBuffer, mReadBufferSize);
+ return -EPIPE;
+ }
+
+ ReformatSize = FormatTransfer(mPcmInputConfig.format, PCM_FORMAT_S16_LE, (void *)mReadBuffer, mReadBufferSize);
+ if (mPCMIVDumpFile != NULL) { // dump data if needed
+ AudioDumpPCMData((void *)mReadBuffer, ReformatSize, mPCMIVDumpFile);
+ }
+ }
+
+ /*
+ * copy read data to ring buffer
+ */
+ mRingLock.lock();
+ RingFreeSpace = RingBuf_getFreeSpace(&mRawDataBuf);
+ if (RingFreeSpace >= mReadBufferSize) {
+ RingBuf_copyFromLinear(&mRawDataBuf, mReadBuffer, ReformatSize);
+ } else {
+ ALOGE("RingFreeSpace = %d mReadBufferSize = %d", RingFreeSpace, ReformatSize);
+ }
+ mRingWaitWorkCV.signal();
+ mRingLock.unlock();
+
+ } else {
+ ALOGD("mbRunning = %d no need read", mbRunning);
+ return 0;
+ }
+ //ALOGD("+%s", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPcmDataCaptureIn::AudioPCMInputThread::AssignReadSize() {
+ mReadBufferSize = mPcmInputConfig.period_size;
+ mReadBufferSize *= mPcmInputConfig.channels;
+ if (mPcmInputConfig.format == PCM_FORMAT_S16_LE) {
+ mReadBufferSize *= 2;
+ } else if (mPcmInputConfig.format != PCM_FORMAT_S8) {
+ mReadBufferSize *= 4;
+ }
+ ALOGD("%s mReadBufferSize = %u", __FUNCTION__, mReadBufferSize);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPcmDataCaptureIn::AudioPCMInputThread::AllocateResource() {
+ AssignReadSize();
+
+ ALOGD("%s mReadBufferSize = %u mReadBufferAllocateSize = %d", __FUNCTION__, mReadBufferSize, mReadBufferAllocateSize);
+
+ if (mReadBuffer == NULL) {
+ mReadBuffer = new char[mReadBufferAllocateSize];
+ memset((void *)mReadBuffer, 0, mReadBufferAllocateSize);
+ ALOGD("%s mReadBufferAllocateSize = %d", __FUNCTION__, mReadBufferAllocateSize);
+ }
+
+ if (mRawDataBuf.pBufBase == NULL) {
+ mRawDataBuf.bufLen = mReadBufferAllocateSize * 4;
+ mRawDataBuf.pBufBase = new char[mRawDataBuf.bufLen];
+ memset((void *)mRawDataBuf.pBufBase, 0, mRawDataBuf.bufLen);
+ mRawDataBuf.pWrite = mRawDataBuf.pBufBase;
+ mRawDataBuf.pRead = mRawDataBuf.pBufBase;
+ }
+
+ ASSERT(mRawDataBuf.pBufBase != NULL);
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAPcmDataCaptureIn::AudioPCMInputThread::ResetResource() {
+ ALOGD("+ %s", __FUNCTION__);
+
+ if (mRawDataBuf.pBufBase != NULL) {
+ mRawDataBuf.pWrite = mRawDataBuf.pBufBase;
+ mRawDataBuf.pRead = mRawDataBuf.pBufBase;
+ }
+
+ ALOGD("- %s", __FUNCTION__);
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPcmDataCaptureIn::AudioPCMInputThread::ReleaseResource() {
+ ALOGD("+ %s", __FUNCTION__);
+ if (mReadBuffer != NULL) {
+ delete []mReadBuffer ;
+ mReadBuffer = NULL;
+ }
+
+ if (mRawDataBuf.pBufBase != NULL) {
+ mRawDataBuf.bufLen = 0;
+ delete[] mRawDataBuf.pBufBase;
+ mRawDataBuf.pBufBase = NULL;
+ mRawDataBuf.pWrite = NULL;
+ mRawDataBuf.pRead = NULL;
+ }
+
+ ALOGD("- %s", __FUNCTION__);
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPcmDataCaptureIn::AudioPCMInputThread::ProcessStateChange() {
+ if (mbStatusChange == false) {
+ return NO_ERROR;
+ } else { // state has change
+ Mutex::Autolock _l(mPcmLock);
+ if (mbRunning == true) { // thread start
+ OpenPcm();
+ AssignReadSize();
+ mPcmWaitWorkCV.signal();
+ } else { // threadstop
+ ClosePcm();
+ ResetResource();
+ mPcmWaitWorkCV.signal();
+ mRingWaitWorkCV.signal();
+ }
+ mbStatusChange = false;
+ }
+ return NO_ERROR;
+}
+
+bool AudioALSAPcmDataCaptureIn::AudioPCMInputThread::threadLoop() {
+ // do threadloop thing
+ unsigned long long diffns, diffus = 0;
+ int ReadSize = 0;
+ struct timespec tstemp1, tstemp2;
+ while (!(exitPending() == true)) {
+ mLock.lock();
+ if (mbRunning == false && mbStatusChange == false) {
+ ALOGD("%s going to sleep", __FUNCTION__);
+ mWaitWorkCV.wait(mLock);
+ ALOGD("%s waking up", __FUNCTION__);
+ }
+ /*
+ * threadloop
+ */
+ tstemp1 = GetSystemTime(false);
+ ProcessStateChange();
+ ReadSize = GetPcmData();
+ mLock.unlock();
+
+ if(ReadSize < 0)
+ usleep(20 * 1000);
+
+ tstemp2 = GetSystemTime(false);
+ diffns = TimeDifference(tstemp1, tstemp2);
+ diffus = diffns / 1000;
+ //ALOGD("%s TimeDifference = %llu in ns %llu in us mbStatusChange = %d mbRunning = %d", __FUNCTION__, diffns, diffus,mbStatusChange,mbRunning);
+ return true;
+ }
+
+ ALOGD("threadLoop exit");
+ return false;
+}
+
+AudioALSAPcmDataCaptureIn::AudioPCMInputThread::AudioPCMInputThread(AudioALSAPcmDataCaptureIn *PcmDataCaptureIn) {
+ ALOGD("%s constructor", __func__);
+ mAudioALSAPcmDataCaptureIn = PcmDataCaptureIn;
+ mReadBuffer = NULL;
+ mReadBufferSize = 0;
+ memset((void *)&mRawDataBuf, 0, sizeof(RingBuf));
+ mbRunning = false;
+ mPCMIVDumpFile = NULL;
+ DumpIVFileNum = 0;
+ memset((void *)&mPcmInputConfig, 0, sizeof(pcm_config));
+ mInputPcm = NULL;
+ mbStatusChange = false;
+}
+
+AudioALSAPcmDataCaptureIn::AudioPCMInputThread::~AudioPCMInputThread() {
+ ALOGD("%s destructor", __func__);
+ ReleaseResource();
+}
+
+// Good place to do one-time initializations
+status_t AudioALSAPcmDataCaptureIn::AudioPCMInputThread::readyToRun() {
+ ALOGD("%s readyToRun()", __func__);
+
+#ifdef MTK_AUDIO_ADJUST_PRIORITY
+ // force to set priority
+ struct sched_param sched_p;
+ sched_getparam(0, &sched_p);
+ sched_p.sched_priority = RTPM_PRIO_AUDIO_PLAYBACK;
+ if (0 != sched_setscheduler(0, SCHED_RR, &sched_p)) {
+ ALOGE("[%s] failed, errno: %d", __FUNCTION__, errno);
+ } else {
+ sched_p.sched_priority = RTPM_PRIO_AUDIO_CCCI_THREAD;
+ sched_getparam(0, &sched_p);
+ ALOGD("sched_setscheduler ok, priority: %d", sched_p.sched_priority);
+ }
+#endif
+ prctl(PR_SET_NAME, (unsigned long)"AudioIVDataCaptureIn", 0, 0, 0);
+
+ return NO_ERROR;
+}
+
+
+} // end of namespace android
+
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackDataDispatcher.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackDataDispatcher.cpp
new file mode 100644
index 0000000..6de9766
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackDataDispatcher.cpp
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAPlaybackDataDispatcher.h"
+
+#include <utils/threads.h>
+
+#include "AudioType.h"
+#include <AudioLock.h>
+
+#define LOG_TAG "AudioALSAPlaybackDataDispatcher"
+
+namespace android {
+
+AudioALSAPlaybackDataDispatcher *AudioALSAPlaybackDataDispatcher::mAudioALSAPlaybackDataDispatcher = NULL;
+AudioALSAPlaybackDataDispatcher *AudioALSAPlaybackDataDispatcher::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSAPlaybackDataDispatcher == NULL) {
+ mAudioALSAPlaybackDataDispatcher = new AudioALSAPlaybackDataDispatcher();
+ }
+ ASSERT(mAudioALSAPlaybackDataDispatcher != NULL);
+ return mAudioALSAPlaybackDataDispatcher;
+}
+
+AudioALSAPlaybackDataDispatcher::AudioALSAPlaybackDataDispatcher() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+AudioALSAPlaybackDataDispatcher::~AudioALSAPlaybackDataDispatcher() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+} // end of namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerAAudio.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerAAudio.cpp
new file mode 100644
index 0000000..aceaf97
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerAAudio.cpp
@@ -0,0 +1,365 @@
+// SPDX-License-Identifier: MediaTekProprietary
+
+#include "AudioALSAPlaybackHandlerAAudio.h"
+#include "AudioALSAHardwareResourceManager.h"
+
+#if defined(MTK_AUDIO_KS)
+#include "AudioALSADeviceConfigManager.h"
+#endif
+
+#include "AudioSmartPaController.h"
+#include <audio_utils/clock.h>
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSAPlaybackHandlerAAudio"
+
+
+
+namespace android {
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+
+
+/*==============================================================================
+ * Utility
+ *============================================================================*/
+
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioALSAPlaybackHandlerAAudio::AudioALSAPlaybackHandlerAAudio(const stream_attribute_t *stream_attribute_source) :
+ AudioALSAPlaybackHandlerBase(stream_attribute_source),
+ mTime_nanoseconds(0),
+ mPosition_frames(0),
+ mMin_size_frames(0) {
+ ALOGV("%s()", __FUNCTION__);
+
+ mPlaybackHandlerType = PLAYBACK_HANDLER_FAST;
+}
+
+
+AudioALSAPlaybackHandlerAAudio::~AudioALSAPlaybackHandlerAAudio() {
+}
+
+
+status_t AudioALSAPlaybackHandlerAAudio::open() {
+ ALOGD("+%s(), flag = %d, source output_devices = 0x%x, audio_format = %x, buffer_size = %d, sample_rate = %d",
+ __FUNCTION__,
+ mStreamAttributeSource->mAudioOutputFlags,
+ mStreamAttributeSource->output_devices,
+ mStreamAttributeSource->audio_format,
+ mStreamAttributeSource->buffer_size,
+ mStreamAttributeSource->sample_rate);
+
+
+ AL_LOCK_MS(AudioALSADriverUtility::getInstance()->getStreamSramDramLock(), 3000);
+
+ // acquire pmic clk
+ mHardwareResourceManager->EnableAudBufClk(true);
+
+ int pcmindex = 0;
+ int cardindex = 0;
+
+#if defined(MTK_AUDIO_KS)
+ pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmPlayback5);
+ cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmPlayback5);
+
+ if ((mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER) &&
+ AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(AUDIO_CTL_PLAYBACK5_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+
+ if (popcount(mStreamAttributeSource->output_devices) > 1) {
+ mApTurnOnSequence2 = AUDIO_CTL_PLAYBACK5_TO_ADDA_DL;
+ }
+ } else {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK5_TO_ADDA_DL;
+ }
+
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence2);
+ }
+#else
+ ALOGE("%s(), MMAP only support KS!", __FUNCTION__);
+ ASSERT(0);
+#endif
+
+ mStreamAttributeTarget.audio_format = (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_32_BIT) ?
+ AUDIO_FORMAT_PCM_8_24_BIT : AUDIO_FORMAT_PCM_16_BIT;
+ mStreamAttributeTarget.audio_channel_mask = mStreamAttributeSource->audio_channel_mask;
+ mStreamAttributeTarget.num_channels = popcount(mStreamAttributeTarget.audio_channel_mask);
+ mStreamAttributeTarget.sample_rate = mStreamAttributeSource->sample_rate;
+
+
+ // HW pcm config
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = mStreamAttributeTarget.num_channels;
+ mConfig.rate = mStreamAttributeTarget.sample_rate;
+
+ int bytesPerSample = (mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4;
+
+
+ // period_size & period_count
+ int max_framecount = MAX_MMAP_HW_BUFFER_SIZE / mConfig.channels / bytesPerSample;
+ int min_framecount = MMAP_DL_PERIOD_SIZE * MIN_MMAP_PERIOD_COUNT;
+
+ if (mMin_size_frames < min_framecount) {
+ mMin_size_frames = min_framecount;
+ }
+ else if (mMin_size_frames > MAX_MMAP_FRAME_COUNT) {
+ mMin_size_frames = MAX_MMAP_FRAME_COUNT;
+ }
+
+ mConfig.period_count = 2;
+ mConfig.period_size = (mMin_size_frames - 1) / mConfig.period_count + 1;
+ mMin_size_frames = mConfig.period_count * mConfig.period_size;
+
+ int scenario = (mMin_size_frames <= max_framecount) ? 1 : 0;
+ ALOGD("%s(), set mmap_play_scenario %d", __FUNCTION__, scenario);
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "mmap_play_scenario"), 0, scenario)) {
+ ALOGW("%s(), mmap_play_scenario enable fail", __FUNCTION__);
+ }
+
+
+ mConfig.format = transferAudioFormatToPcmFormat(mStreamAttributeTarget.audio_format);
+
+ mConfig.start_threshold = mConfig.period_size * mConfig.period_count;;
+ mConfig.stop_threshold = INT32_MAX;
+ mConfig.silence_threshold = 0;
+ mConfig.avail_min = 0;//mStreamAttributeSource->buffer_size / ((mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4) / mStreamAttributeSource->num_channels;
+ ALOGD("%s(), mConfig: channels = %d, rate = %d, period_size = %d, period_count = %d, format = %d, avail_min = %d, start_threshold = %d",
+ __FUNCTION__,
+ mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mConfig.format,
+ mConfig.avail_min, mConfig.start_threshold);
+
+
+ mStreamAttributeTarget.buffer_size = mConfig.period_size * mConfig.period_count * mConfig.channels *
+ bytesPerSample;
+
+ unsigned int flag = PCM_MMAP | PCM_NOIRQ | PCM_OUT | PCM_MONOTONIC;
+ openPcmDriverWithFlag(pcmindex, flag);
+
+
+ AL_UNLOCK(AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+
+#if defined(MTK_HYBRID_NLE_SUPPORT) // must be after pcm open
+ mStreamAttributeTarget.output_devices = mStreamAttributeSource->output_devices;
+ initNLEProcessing();
+#endif
+
+ // open codec driver
+ mHardwareResourceManager->startOutputDevice(mStreamAttributeSource->output_devices, mStreamAttributeTarget.sample_rate);
+
+
+
+
+ mTimeStampValid = false;
+ mBytesWriteKernel = 0;
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerAAudio::close() {
+ ALOGD("+%s(), mDevice = 0x%x", __FUNCTION__, mStreamAttributeSource->output_devices);
+
+
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+ // Must do this before close analog path
+ deinitNLEProcessing();
+#endif
+
+ // close codec driver
+ mHardwareResourceManager->stopOutputDevice();
+
+ // close pcm driver
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+ closePcmDriver();
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence2);
+ mApTurnOnSequence2.clear();
+ }
+
+ ALOGD("%s(), set mmap_play_scenario 0", __FUNCTION__);
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "mmap_play_scenario"), 0, 0)) {
+ ALOGW("%s(), mmap_play_scenario disable fail", __FUNCTION__);
+ }
+#endif
+
+
+ //release pmic clk
+ mHardwareResourceManager->EnableAudBufClk(false);
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerAAudio::routing(const audio_devices_t output_devices) {
+ mHardwareResourceManager->changeOutputDevice(output_devices);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerAAudio::setScreenState(bool mode __unused, size_t buffer_size __unused, size_t reduceInterruptSize __unused, bool bforce __unused) {
+ ALOGE("MMAP call %s!!", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+ssize_t AudioALSAPlaybackHandlerAAudio::write(const void *buffer __unused, size_t bytes) {
+ ALOGE("MMAP call %s!!", __FUNCTION__);
+ return bytes;
+}
+
+
+status_t AudioALSAPlaybackHandlerAAudio::setFilterMng(AudioMTKFilterManager *pFilterMng __unused) {
+ ALOGE("MMAP call %s!!", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerAAudio::start() {
+ int ret = INVALID_OPERATION;
+ ALOGD("+%s", __FUNCTION__);
+
+ if (mPcm == NULL) {
+ ALOGW("%s, mPcm == NULL !", __FUNCTION__);
+ return ret;
+ }
+
+ ret = pcm_start(mPcm);
+ if (ret < 0) {
+ ALOGE("%s: pcm_start fail %d, %s", __FUNCTION__, ret, pcm_get_error(mPcm));
+ }
+
+ ALOGD("-%s", __FUNCTION__);
+ return ret;
+}
+
+
+status_t AudioALSAPlaybackHandlerAAudio::stop() {
+ int ret = INVALID_OPERATION;
+ ALOGD("+%s", __FUNCTION__);
+
+ if (mPcm == NULL) {
+ ALOGW("%s, mPcm == NULL !", __FUNCTION__);
+ return ret;
+ }
+
+ ret = pcm_stop(mPcm);
+ if (ret < 0) {
+ ALOGE("%s: pcm_stop fail %d", __FUNCTION__, ret);
+ }
+
+ ALOGD("-%s", __FUNCTION__);
+ return ret;
+}
+
+
+status_t AudioALSAPlaybackHandlerAAudio::createMmapBuffer(int32_t min_size_frames,
+ struct audio_mmap_buffer_info *info) {
+ unsigned int offset = 0;
+ unsigned int frames = 0;
+ uint32_t buffer_size = 0;
+ int ret = INVALID_OPERATION;
+ ALOGD("+%s, min_size_frames %d", __FUNCTION__, min_size_frames);
+
+ mMin_size_frames = min_size_frames;
+
+ // open pcm
+ open();
+
+ if (mPcm == NULL) {
+ ALOGW("%s, mPcm == NULL !", __FUNCTION__);
+ return ret;
+ }
+
+ ret = pcm_mmap_begin(mPcm, &info->shared_memory_address, &offset, &frames);
+ if (ret < 0) {
+ goto exit;
+ }
+
+ info->buffer_size_frames = pcm_get_buffer_size(mPcm);
+ info->burst_size_frames = MMAP_DL_PERIOD_SIZE;
+ buffer_size = pcm_frames_to_bytes(mPcm, info->buffer_size_frames);
+
+ info->shared_memory_fd = mixer_ctl_get_value(mixer_get_ctl_by_name(mMixer, "aaudio_dl_mmap_fd"), 0);
+ if (info->shared_memory_fd == 0) {
+ // share mode
+ info->shared_memory_fd = pcm_get_poll_fd(mPcm);
+ ALOGD("%s, shared fd %d", __FUNCTION__, info->shared_memory_fd);
+ } else {
+ info->buffer_size_frames *= -1;
+ }
+
+ memset(info->shared_memory_address, 0, buffer_size);
+
+ ALOGD("%s: fd %d, buffer address %p, buffer_size_frames %d %d, burst_size_frames %d", __FUNCTION__,
+ info->shared_memory_fd, info->shared_memory_address, info->buffer_size_frames,
+ buffer_size, info->burst_size_frames);
+
+exit:
+ if (ret != 0) {
+ if (mPcm != NULL) {
+ pcm_close(mPcm);
+ mPcm = NULL;
+ }
+ }
+
+ ALOGD("-%s", __FUNCTION__);
+ return ret;
+}
+
+
+status_t AudioALSAPlaybackHandlerAAudio::getMmapPosition(struct audio_mmap_position *position) {
+ int ret = INVALID_OPERATION;
+
+ if (mPcm == NULL) {
+ ALOGW("%s, mPcm == NULL !", __FUNCTION__);
+ return ret;
+ }
+
+ struct timespec ts = { 0, 0 };
+ ret = pcm_mmap_get_hw_ptr(mPcm, (unsigned int *)&position->position_frames, &ts);
+ if (ret < 0) {
+ ALOGE("%s: %s", __FUNCTION__, pcm_get_error(mPcm));
+ return ret;
+ }
+ position->time_nanoseconds = audio_utils_ns_from_timespec(&ts);
+
+#if 0
+ // correction
+ if (mTime_nanoseconds == 0) {
+ mTime_nanoseconds = position->time_nanoseconds;
+ mPosition_frames = position->position_frames;
+ } else {
+ position->position_frames = (position->time_nanoseconds - mTime_nanoseconds) * 48 / 1000000 + mPosition_frames;
+ }
+#endif
+
+ if (position->position_frames < 0) {
+ ALOGD("%s, time_nanoseconds %lld, mPosition_frames %d", __FUNCTION__,
+ (long long)position->time_nanoseconds, position->position_frames);
+ }
+
+ return ret;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerBTCVSD.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerBTCVSD.cpp
new file mode 100644
index 0000000..2ca28ef
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerBTCVSD.cpp
@@ -0,0 +1,578 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAPlaybackHandlerBTCVSD.h"
+
+#include <inttypes.h>
+#include <time.h>
+
+#include "AudioUtility.h"
+
+#include "WCNChipController.h"
+#include "AudioALSACaptureDataProviderEchoRefBTCVSD.h"
+#include "AudioALSACaptureDataProviderBTCVSD.h"
+#include "AudioALSAStreamManager.h"
+#include "AudioBTCVSDControl.h"
+#include "AudioALSADriverUtility.h"
+
+#if (defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT) && (MTK_AUDIO_TUNING_TOOL_V2_PHASE >= 2))
+#include "AudioParamParser.h"
+#endif
+
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+#include <audio_ringbuf.h>
+#include <audio_pool_buf_handler.h>
+
+#include <aurisys_controller.h>
+#include <aurisys_lib_manager.h>
+#endif
+
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSAPlaybackHandlerBTCVSD"
+
+//#define DEBUG_TIMESTAMP
+
+#ifdef DEBUG_TIMESTAMP
+#define SHOW_TIMESTAMP(format, args...) ALOGD(format, ##args)
+#else
+#define SHOW_TIMESTAMP(format, args...)
+#endif
+
+#define BUFFER_SIZE_PER_ACCESSS_32BIT (8192)
+#define BUFFER_SIZE_PER_ACCESSS_16BIT (4096)
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+
+#define BT_IRQ_PERIOD_US 22500
+
+namespace android {
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+static bool mBTMode_Open;
+
+AudioALSAPlaybackHandlerBTCVSD::AudioALSAPlaybackHandlerBTCVSD(const stream_attribute_t *stream_attribute_source) :
+ AudioALSAPlaybackHandlerBase(stream_attribute_source),
+ mTotalEchoRefBufSize(0),
+ mDataProviderEchoRefBTCVSD(AudioALSACaptureDataProviderEchoRefBTCVSD::getInstance()),
+ mWCNChipController(WCNChipController::GetInstance()),
+ mAudioBTCVSDControl(AudioBTCVSDControl::getInstance()),
+ mMixer(AudioALSADriverUtility::getInstance()->getMixer()),
+ mInitWrite(true),
+ mWrittenFrame(0)
+#ifndef MTK_SUPPORT_BTCVSD_ALSA
+ , mFd2(mAudioBTCVSDControl->getFd())
+#else
+ , mFd2(-1)
+#endif
+{
+ ALOGD("%s()", __FUNCTION__);
+ mPlaybackHandlerType = PLAYBACK_HANDLER_BT_CVSD;
+
+ /* Init EchoRef Resource */
+ memset(&mEchoRefStartTime, 0, sizeof(mEchoRefStartTime));
+
+ /* Init EchoRef Resource */
+ memset(&mStreamAttributeTargetEchoRef, 0, sizeof(mStreamAttributeTargetEchoRef));
+
+ /* Init timestamp*/
+ memset(&mNewtime, 0, sizeof(mNewtime));
+ memset(&mOldtime, 0, sizeof(mOldtime));
+}
+
+
+AudioALSAPlaybackHandlerBTCVSD::~AudioALSAPlaybackHandlerBTCVSD() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSAPlaybackHandlerBTCVSD::open() {
+ ALOGD("+%s(), mDevice = 0x%x, sample_rate = %d, num_channels = %d, buffer_size = %d, audio_format = %d",
+ __FUNCTION__, mStreamAttributeSource->output_devices,
+ mStreamAttributeSource->sample_rate, mStreamAttributeSource->num_channels,
+ mStreamAttributeSource->buffer_size, mStreamAttributeSource->audio_format);
+
+ // debug pcm dump
+ OpenPCMDump(LOG_TAG);
+
+ // HW attribute config // TODO(Harvey): query this
+ mStreamAttributeTarget.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ mStreamAttributeTarget.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ mStreamAttributeTarget.num_channels = popcount(mStreamAttributeTarget.audio_channel_mask);
+ mStreamAttributeTarget.sample_rate = mWCNChipController->GetBTCurrentSamplingRateNumber();
+
+ // Setup echoref stream attribute
+ mStreamAttributeTargetEchoRef.audio_format = mStreamAttributeTarget.audio_format;
+ mStreamAttributeTargetEchoRef.audio_channel_mask = mStreamAttributeTarget.audio_channel_mask;
+ mStreamAttributeTargetEchoRef.num_channels = mStreamAttributeTarget.num_channels;
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ mStreamAttributeTargetEchoRef.sample_rate = mStreamAttributeTarget.sample_rate;
+#else
+ mStreamAttributeTargetEchoRef.sample_rate = mStreamAttributeSource->sample_rate; // No src applied, using source's sample rate
+#endif
+
+#ifdef MTK_SUPPORT_BTCVSD_ALSA
+ //////copy from Capture
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = mStreamAttributeTarget.num_channels;
+ mConfig.rate = mStreamAttributeTarget.sample_rate;
+ // total buffer size must be multiple of SCO_TX_ENCODE_SIZE
+ mConfig.period_size = 45; // 1 bt interrupt = 22.5ms, = 180 bytes, 180 / 2ch / 2 byte (16bit) = 45
+ mConfig.period_count = 6; // 6 bt interrupt
+ mConfig.format = PCM_FORMAT_S16_LE;
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+
+ ASSERT(mPcm == NULL);
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmBTCVSDPlayback);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmBTCVSDPlayback);
+ mPcm = pcm_open(cardIdx, pcmIdx, PCM_OUT, &mConfig);
+ ASSERT(mPcm != NULL && pcm_is_ready(mPcm) == true);
+
+ if (pcm_prepare(mPcm) != 0) {
+ ALOGE("%s(), pcm_prepare(%p) == false due to %s, close pcm.", __FUNCTION__, mPcm, pcm_get_error(mPcm));
+ pcm_close(mPcm);
+ mPcm = NULL;
+ }
+#endif
+ mBTMode_Open = mAudioBTCVSDControl->BT_SCO_isWideBand();
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "btcvsd_band"), mBTMode_Open ? "WB" : "NB")) {
+ ALOGE("Error: btcvsd_band invalid value");
+ }
+
+ uint32_t bufferSizePerAccess = mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_16_BIT ?
+ BUFFER_SIZE_PER_ACCESSS_16BIT : BUFFER_SIZE_PER_ACCESSS_32BIT;
+
+ ALOGD("%s(), data align to %d", __FUNCTION__, bufferSizePerAccess);
+ mDataAlignedSize = bufferSizePerAccess;
+ mDataPendingForceUse = true;
+
+ initDataPending();
+
+ // init DC Removal
+ initDcRemoval();
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ if (get_aurisys_on()) {
+ // open mAudioBTCVSDControl
+ mAudioBTCVSDControl->BTCVSD_Init(mFd2, mStreamAttributeTarget.sample_rate, mStreamAttributeTarget.num_channels);
+
+ CreateAurisysLibManager();
+ } else
+#endif
+ {
+ // open mAudioBTCVSDControl
+ mAudioBTCVSDControl->BTCVSD_Init(mFd2, mStreamAttributeSource->sample_rate, mStreamAttributeSource->num_channels);
+
+ // bit conversion
+ initBitConverter();
+ }
+
+ /* Reset software timestamp information */
+ mTotalEchoRefBufSize = 0;
+ memset((void *)&mEchoRefStartTime, 0, sizeof(mEchoRefStartTime));
+
+ ALOGD("-%s(), mStreamAttributeTarget, ch=%d, sr=%d, mStreamAttributeTargetEchoRef, ch=%d, sr=%d",
+ __FUNCTION__,
+ mStreamAttributeTarget.num_channels,
+ mStreamAttributeTarget.sample_rate,
+ mStreamAttributeTargetEchoRef.num_channels,
+ mStreamAttributeTargetEchoRef.sample_rate);
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerBTCVSD::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+#ifndef MTK_SUPPORT_BTCVSD_ALSA // clean bt buffer before closing, alsa version will clean in kernel close
+ const uint32_t mute_buf_len = mDataAlignedSize;
+ char mute_buf[mute_buf_len];
+ memset(mute_buf, 0, mute_buf_len);
+
+ this->write(mute_buf, mute_buf_len);
+ this->write(mute_buf, mute_buf_len);
+ this->write(mute_buf, mute_buf_len);
+ this->write(mute_buf, mute_buf_len);
+#endif
+
+#ifdef MTK_SUPPORT_BTCVSD_ALSA
+ // close pcm driver
+ closePcmDriver();
+#endif
+
+ // close mAudioBTCVSDControl
+ mAudioBTCVSDControl->BTCVSD_StandbyProcess(mFd2);
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ if (get_aurisys_on()) {
+ DestroyAurisysLibManager();
+ } else
+#endif
+ {
+ // bit conversion
+ deinitBitConverter();
+ }
+ //DC removal
+ deinitDcRemoval();
+
+ DeinitDataPending();
+
+ // debug pcm dump
+ ClosePCMDump();
+
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerBTCVSD::routing(const audio_devices_t output_devices __unused) {
+ return INVALID_OPERATION;
+}
+
+int AudioALSAPlaybackHandlerBTCVSD::getLatency() {
+ int latency;
+
+ // buffer size bytes in kernel
+ latency = mConfig.period_size *
+ mConfig.period_count *
+ getSizePerFrame(audio_format_from_pcm_format(mConfig.format), mConfig.channels);
+
+ // buffer size (encoded data) to latency ms
+ latency = ((latency / SCO_TX_ENCODE_SIZE / 3) * BT_IRQ_PERIOD_US) / 1000;
+
+ return latency;
+}
+
+ssize_t AudioALSAPlaybackHandlerBTCVSD::write(const void *buffer, size_t bytes) {
+#ifdef MTK_SUPPORT_BTCVSD_ALSA
+ if (mPcm == NULL) {
+ ALOGE("%s(), mPcm == NULL, return", __FUNCTION__);
+ return bytes;
+ }
+#endif
+ ALOGV("%s(), buffer = %p, bytes = %zu", __FUNCTION__, buffer, bytes);
+
+ if (mPCMDumpFile) {
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[0] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+ }
+
+ // const -> to non const
+ void *pBuffer = const_cast<void *>(buffer);
+ ASSERT(pBuffer != NULL);
+
+ void *pBufferAfterDataPending = NULL;
+ uint32_t bytesAfterDataPending = 0;
+ if (mDataPendingForceUse) {
+ dodataPending(pBuffer, bytes, &pBufferAfterDataPending, &bytesAfterDataPending);
+
+ if (bytesAfterDataPending < mDataAlignedSize) {
+ ALOGV("%s(), bytesAfterDataPending %u, return", __FUNCTION__, bytesAfterDataPending);
+ return bytes;
+ }
+ } else {
+ pBufferAfterDataPending = pBuffer;
+ bytesAfterDataPending = bytes;
+ }
+
+ void *pBufferAfterDcRemoval = NULL;
+ uint32_t bytesAfterDcRemoval = 0;
+ // DC removal before DRC
+ doDcRemoval(pBufferAfterDataPending, bytesAfterDataPending, &pBufferAfterDcRemoval, &bytesAfterDcRemoval);
+
+ // bit conversion
+ void *pBufferAfterBitConvertion = NULL;
+ uint32_t bytesAfterBitConvertion = 0;
+
+ uint32_t buf_sample_rate = 0;
+ uint32_t buf_num_channels = 0;
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ if (get_aurisys_on()) {
+ buf_sample_rate = mStreamAttributeTarget.sample_rate;
+ buf_num_channels = mStreamAttributeTarget.num_channels;
+
+ // expect library output amount smoothly
+ mTransferredBufferSize = GetTransferredBufferSize(
+ bytesAfterDcRemoval,
+ mStreamAttributeSource,
+ &mStreamAttributeTarget);
+
+ audio_pool_buf_copy_from_linear(
+ mAudioPoolBufDlIn,
+ pBufferAfterDcRemoval,
+ bytesAfterDcRemoval);
+
+ // post processing + SRC + Bit conversion
+ aurisys_process_dl_only(mAurisysLibManager, mAudioPoolBufDlIn, mAudioPoolBufDlOut);
+
+ uint32_t data_size = audio_ringbuf_count(&mAudioPoolBufDlOut->ringbuf);
+ if (data_size > mTransferredBufferSize) {
+ data_size = mTransferredBufferSize;
+ }
+ audio_pool_buf_copy_to_linear(
+ &mLinearOut->p_buffer,
+ &mLinearOut->memory_size,
+ mAudioPoolBufDlOut,
+ data_size);
+ //ALOGD("aurisys process data_size: %u", data_size);
+
+ // wrap to original playback handler
+ pBufferAfterBitConvertion = (void *)mLinearOut->p_buffer;
+ bytesAfterBitConvertion = data_size;
+ } else
+#endif
+ {
+ buf_sample_rate = mStreamAttributeSource->sample_rate;
+ buf_num_channels = mStreamAttributeSource->num_channels;
+
+ doBitConversion(pBufferAfterDcRemoval, bytesAfterDcRemoval, &pBufferAfterBitConvertion, &bytesAfterBitConvertion);
+ }
+
+ // EchoRef
+ uint32_t echoRefDataSize = bytesAfterBitConvertion;
+ const char *pEchoRefBuffer = (const char *)pBufferAfterBitConvertion;
+
+ // write data to bt cvsd driver
+ uint8_t *outbuffer, *inbuf, *workbuf;
+ uint32_t insize, outsize, workbufsize, total_outsize, src_fs_s;
+
+ inbuf = (uint8_t *)pBufferAfterBitConvertion;
+
+ if (mPCMDumpFile) {
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[1] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+ }
+
+ do {
+ outbuffer = mAudioBTCVSDControl->BT_SCO_TX_GetCVSDOutBuf();
+ outsize = SCO_TX_ENCODE_SIZE;
+ insize = bytesAfterBitConvertion;
+ workbuf = mAudioBTCVSDControl->BT_SCO_TX_GetCVSDWorkBuf();
+ workbufsize = SCO_TX_PCM64K_BUF_SIZE;
+ total_outsize = 0;
+ do {
+ if (mBTMode_Open != mAudioBTCVSDControl->BT_SCO_isWideBand()) {
+ ALOGD("BTSCO change mode after TX_Begin!!!");
+ mAudioBTCVSDControl->BT_SCO_TX_End(mFd2);
+ mAudioBTCVSDControl->BT_SCO_TX_Begin(mFd2, buf_sample_rate, buf_num_channels);
+ mBTMode_Open = mAudioBTCVSDControl->BT_SCO_isWideBand();
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "btcvsd_band"), mBTMode_Open ? "WB" : "NB")) {
+ ALOGE("Error: btcvsd_band invalid value");
+ }
+ return bytes;
+ }
+
+ if (mAudioBTCVSDControl->BT_SCO_isWideBand()) {
+ mAudioBTCVSDControl->btsco_process_TX_MSBC(inbuf, &insize, outbuffer, &outsize, workbuf); // return insize is consumed size
+ ALOGV("WriteDataToBTSCOHW, do mSBC encode outsize=%d, consumed size=%d, bytesAfterBitConvertion=%d", outsize, insize, bytesAfterBitConvertion);
+ } else {
+ mAudioBTCVSDControl->btsco_process_TX_CVSD(inbuf, &insize, outbuffer, &outsize, workbuf, workbufsize); // return insize is consumed size
+ ALOGV("WriteDataToBTSCOHW, do CVSD encode outsize=%d, consumed size=%d, bytesAfterBitConvertion=%d", outsize, insize, bytesAfterBitConvertion);
+ }
+ outbuffer += outsize;
+ inbuf += insize;
+
+ ASSERT(bytesAfterBitConvertion >= insize); // bytesAfterBitConvertion - insize >= 0
+ bytesAfterBitConvertion -= insize;
+
+ insize = bytesAfterBitConvertion;
+ total_outsize += outsize;
+ } while (total_outsize < BTSCO_CVSD_TX_OUTBUF_SIZE && outsize != 0);
+
+ ALOGV("WriteDataToBTSCOHW write to kernel(+) total_outsize = %d", total_outsize);
+ if (total_outsize > 0) {
+ WritePcmDumpData((void *)(mAudioBTCVSDControl->BT_SCO_TX_GetCVSDOutBuf()), total_outsize);
+#ifdef MTK_SUPPORT_BTCVSD_ALSA
+ // prevent stuck in alsa due to bt stop before audio start
+ bool skipWrite = false;
+ int maxTimeoutTrial = 2;
+ unsigned int avail = 0;
+ unsigned int totalOutFrame = (total_outsize / (mConfig.channels * pcm_format_to_bits(mConfig.format) / 8));
+
+ while (maxTimeoutTrial >= 0) {
+ bool needSkipWrite = false;
+ struct timespec timeStamp;
+
+ if (pcm_get_htimestamp(mPcm, &avail, &timeStamp) != 0) {
+ ALOGW("%s(), pcm_get_htimestamp fail %s, mWrittenFrame %u, totalOutFrame %u\n", __FUNCTION__, pcm_get_error(mPcm), mWrittenFrame, totalOutFrame);
+ if (mInitWrite && mWrittenFrame + totalOutFrame > mConfig.period_size * mConfig.period_count) {
+ needSkipWrite = true;
+ }
+ } else {
+ mInitWrite = false;
+ if (totalOutFrame > avail) {
+ needSkipWrite = true;
+ }
+ }
+
+ if (needSkipWrite) {
+ skipWrite = true;
+ usleep(BT_IRQ_PERIOD_US);
+ maxTimeoutTrial--;
+ } else {
+ skipWrite = false;
+ break;
+ }
+ }
+
+ if (!skipWrite) {
+ int retval = pcm_write(mPcm, mAudioBTCVSDControl->BT_SCO_TX_GetCVSDOutBuf(), total_outsize);
+ if (retval != 0) {
+ ALOGE("%s(), pcm_write() error, retval = %d", __FUNCTION__, retval);
+ } else {
+ mWrittenFrame += totalOutFrame;
+ }
+ } else {
+ ALOGW("%s(), skip write, total_out_size %u, avail %u, mWrittenFrame %u", __FUNCTION__, total_outsize, avail, mWrittenFrame);
+ }
+#else
+ ssize_t WrittenBytes = ::write(mFd2, mAudioBTCVSDControl->BT_SCO_TX_GetCVSDOutBuf(), total_outsize);
+#endif
+ updateStartTimeStamp();
+
+ }
+
+ ALOGV("WriteDataToBTSCOHW write to kernel(-) remaining bytes = %d", bytesAfterBitConvertion);
+ } while (bytesAfterBitConvertion > 0);
+
+ if (mPCMDumpFile) {
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[2] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+ }
+
+ /* Write echo ref data to data provider if needed */
+ writeEchoRefDataToDataProvider(mDataProviderEchoRefBTCVSD, pEchoRefBuffer, echoRefDataSize);
+
+ if (mPCMDumpFile) {
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[3] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+
+ if (latencyTime[3] > 0.022) {
+ ALOGD("latency_in_s,%1.3lf,%1.3lf,%1.3lf,%1.3lf, interrupt,%1.3lf", latencyTime[0], latencyTime[1], latencyTime[2], latencyTime[3], mStreamAttributeTarget.mInterrupt);
+ }
+ }
+
+ return bytes;
+}
+
+
+status_t AudioALSAPlaybackHandlerBTCVSD::updateStartTimeStamp() {
+ if (mEchoRefStartTime.tv_sec == 0 && mEchoRefStartTime.tv_nsec == 0) {
+ TimeBufferInfo *pTimeInfoBuffer = NULL;
+
+ /* Get tx timestamp */
+#ifdef MTK_SUPPORT_BTCVSD_ALSA
+ struct mixer_ctl *ctl;
+ unsigned int num_values, i;
+ int index = 0;
+ TimeBufferInfo timeBufferInfo;
+
+ /* get timestamp from driver*/
+ ctl = mixer_get_ctl_by_name(mMixer, "btcvsd_tx_timestamp");
+ int ret_val = mixer_ctl_get_array(ctl, &timeBufferInfo, sizeof(timeBufferInfo));
+ if (ret_val < 0) {
+ ALOGE("%s() mixer_ctl_get_array() failed (error %d)", __FUNCTION__, ret_val);
+ pTimeInfoBuffer = NULL;
+ return INVALID_OPERATION;
+ } else {
+ pTimeInfoBuffer = &timeBufferInfo;
+ }
+#else
+ pTimeInfoBuffer = (TimeBufferInfo *)(mAudioBTCVSDControl->BT_SCO_TX_GetTimeBufferInfo());
+#endif
+ ASSERT(pTimeInfoBuffer != NULL);
+
+ /* Convert TimeBufferInfo to timespec */
+ unsigned long long timeStamp = pTimeInfoBuffer->timestampUS + pTimeInfoBuffer->dataCountEquiTime;
+ mEchoRefStartTime.tv_sec = timeStamp / 1000000000;
+ mEchoRefStartTime.tv_nsec = timeStamp % 1000000000;
+
+ int delayMs = 0;
+ const char *btDeviceName = AudioALSAStreamManager::getInstance()->GetBtHeadsetName();
+
+#if (defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT) && (MTK_AUDIO_TUNING_TOOL_V2_PHASE >= 2))
+ /* Get the BT device delay parameter */
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return INVALID_OPERATION;
+ }
+
+ AppHandle *pAppHandle = appOps->appHandleGetInstance();
+ AudioType *audioType = appOps->appHandleGetAudioTypeByName(pAppHandle, "BtInfo");
+ if (audioType) {
+ String8 categoryPath("BT headset,");
+ categoryPath += (btDeviceName ? btDeviceName : "");
+
+ ParamUnit *paramUnit = appOps->audioTypeGetParamUnit(audioType, categoryPath.string());
+ ASSERT(paramUnit);
+
+ // isVoIP : true(VoIP) or false(3GVT)
+ Param *param = appOps->paramUnitGetParamByName(paramUnit, "voip_ap_delay_ms");
+ ASSERT(param);
+
+ delayMs = *(int *)param->data;
+ } else {
+ ALOGW("%s(), No BtInfo audio type found!", __FUNCTION__);
+ }
+#endif
+
+ struct timespec origStartTime = mEchoRefStartTime;
+ adjustTimeStamp(&mEchoRefStartTime, delayMs);
+
+ ALOGD("%s(), Set start timestamp (%ld.%09ld->%ld.%09ld), mTotalEchoRefBufSize = %d, BT headset = %s, delayMs = %d (audio_mode = %d), dataCountEquiTime=%" PRIu64 ", timestampUS=%" PRIu64 "",
+ __FUNCTION__,
+ origStartTime.tv_sec,
+ origStartTime.tv_nsec,
+ mEchoRefStartTime.tv_sec,
+ mEchoRefStartTime.tv_nsec,
+ mTotalEchoRefBufSize,
+ btDeviceName,
+ delayMs,
+ mStreamAttributeSource->audio_mode,
+ pTimeInfoBuffer->dataCountEquiTime,
+ pTimeInfoBuffer->timestampUS);
+ } else {
+ ALOGV("%s(), start timestamp (%ld.%09ld), mTotalEchoRefBufSize = %d", __FUNCTION__, mEchoRefStartTime.tv_sec, mEchoRefStartTime.tv_nsec, mTotalEchoRefBufSize);
+ }
+
+ return NO_ERROR;
+}
+
+bool AudioALSAPlaybackHandlerBTCVSD::writeEchoRefDataToDataProvider(AudioALSACaptureDataProviderEchoRefBTCVSD *dataProvider, const char *echoRefData, uint32_t dataSize) {
+ if (dataProvider->isEnable()) {
+ /* Calculate buffer's time stamp */
+ struct timespec newTimeStamp;
+ calculateTimeStampByBytes(mEchoRefStartTime, mTotalEchoRefBufSize, mStreamAttributeTargetEchoRef, &newTimeStamp);
+
+ SHOW_TIMESTAMP("%s(), mTotalEchoRefBufSize = %d, write size = %d, newTimeStamp = %ld.%09ld -> %ld.%09ld",
+ __FUNCTION__, mTotalEchoRefBufSize, dataSize, mEchoRefStartTime.tv_sec, mEchoRefStartTime.tv_nsec,
+ newTimeStamp.tv_sec, newTimeStamp.tv_nsec);
+
+ // TODO(JH): Consider the close case, need to free EchoRef data from provider
+ dataProvider->writeData(echoRefData, dataSize, &newTimeStamp);
+
+ //WritePcmDumpData(echoRefData, dataSize);
+ } else {
+ SHOW_TIMESTAMP("%s(), data provider is not enabled, Do not write echo ref data to provider", __FUNCTION__);
+ }
+ mTotalEchoRefBufSize += dataSize;
+
+ return true;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerBTSCO.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerBTSCO.cpp
new file mode 100644
index 0000000..96b0d0e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerBTSCO.cpp
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAPlaybackHandlerBTSCO.h"
+
+#include "AudioALSADriverUtility.h"
+#include "AudioALSAHardwareResourceManager.h"
+#include <AudioLock.h>
+
+#include "WCNChipController.h"
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+#include <audio_ringbuf.h>
+#include <audio_pool_buf_handler.h>
+
+#include <aurisys_controller.h>
+#include <aurisys_lib_manager.h>
+#endif
+
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSAPlaybackHandlerBTSCO"
+
+
+#if defined(CONFIG_MT_ENG_BUILD)
+#define DEBUG_LATENCY
+#endif
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+
+namespace android {
+
+AudioALSAPlaybackHandlerBTSCO::AudioALSAPlaybackHandlerBTSCO(const stream_attribute_t *stream_attribute_source) :
+ AudioALSAPlaybackHandlerBase(stream_attribute_source),
+ mWCNChipController(WCNChipController::GetInstance()) {
+ ALOGD("%s()", __FUNCTION__);
+ mPlaybackHandlerType = PLAYBACK_HANDLER_BT_SCO;
+ memset(&mNewtime, 0, sizeof(mNewtime));
+ memset(&mOldtime, 0, sizeof(mOldtime));
+}
+
+
+AudioALSAPlaybackHandlerBTSCO::~AudioALSAPlaybackHandlerBTSCO() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSAPlaybackHandlerBTSCO::open() {
+ ALOGD("+%s(), mDevice = 0x%x", __FUNCTION__, mStreamAttributeSource->output_devices);
+
+ if (mStreamAttributeSource->isMixerOut) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "dl1bt_memif_select"), "dl2")) {
+ ALOGE("Error: dl1bt_memif_select invalid value");
+ }
+ } else {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "dl1bt_memif_select"), "dl1")) {
+ ALOGE("Error: dl1bt_memif_select invalid value");
+ }
+ }
+
+ // debug pcm dump
+ OpenPCMDump(LOG_TAG);
+
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVOIPCallBTPlayback);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVOIPCallBTPlayback);
+
+ struct pcm_params *params;
+ params = pcm_params_get(cardindex, pcmindex, PCM_OUT);
+ if (params == NULL) {
+ ALOGD("Device does not exist.\n");
+ }
+#ifdef PLAYBACK_USE_24BITS_ONLY
+ const uint32_t bt_max_buffer_size = 8192; // 8k
+#else
+ const uint32_t bt_max_buffer_size = 4096; // 4k
+#endif
+ const uint32_t kernel_max_buffer_size = pcm_params_get_max(params, PCM_PARAM_BUFFER_BYTES);
+ mStreamAttributeTarget.buffer_size = (kernel_max_buffer_size < bt_max_buffer_size) ? kernel_max_buffer_size : bt_max_buffer_size;
+ ALOGD("buffersizemax = %d", mStreamAttributeTarget.buffer_size);
+ pcm_params_free(params);
+
+ // HW attribute config // TODO(Harvey): query this
+#ifdef PLAYBACK_USE_24BITS_ONLY
+ mStreamAttributeTarget.audio_format = AUDIO_FORMAT_PCM_8_24_BIT;
+#else
+ mStreamAttributeTarget.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+#endif
+ mStreamAttributeTarget.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ mStreamAttributeTarget.num_channels = popcount(mStreamAttributeTarget.audio_channel_mask);
+ mStreamAttributeTarget.sample_rate = mWCNChipController->GetBTCurrentSamplingRateNumber();
+
+
+ // HW pcm config
+ mConfig.channels = mStreamAttributeTarget.num_channels;
+ mConfig.rate = mStreamAttributeTarget.sample_rate;
+
+ mConfig.period_count = 2;
+ mConfig.period_size = (mStreamAttributeTarget.buffer_size / (mConfig.channels * mConfig.period_count)) / ((mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4);
+
+ mConfig.format = transferAudioFormatToPcmFormat(mStreamAttributeTarget.audio_format);
+
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+ ALOGD("%s(), mConfig: channels = %d, rate = %d, period_size = %d, period_count = %d, format = %d",
+ __FUNCTION__, mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mConfig.format);
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ if (get_aurisys_on()) {
+ CreateAurisysLibManager();
+ } else
+#endif
+ {
+ // SRC
+ initBliSrc();
+
+ // bit conversion
+ initBitConverter();
+
+ initDataPending();
+ }
+
+ // init DC Removal
+ initDcRemoval();
+
+ // open pcm driver
+ openPcmDriver(pcmindex);
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerBTSCO::close() {
+ ALOGD("+%s()", __FUNCTION__);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ const uint32_t mute_buf_len = 8192;
+ char mute_buf[mute_buf_len];
+ memset(mute_buf, 0, mute_buf_len);
+
+ this->write(mute_buf, mute_buf_len);
+ this->write(mute_buf, mute_buf_len);
+ this->write(mute_buf, mute_buf_len);
+ this->write(mute_buf, mute_buf_len);
+ this->write(mute_buf, mute_buf_len);
+ this->write(mute_buf, mute_buf_len);
+ this->write(mute_buf, mute_buf_len);
+ this->write(mute_buf, mute_buf_len);
+
+ // close pcm driver
+ closePcmDriver();
+
+ //DC removal
+ deinitDcRemoval();
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ if (get_aurisys_on()) {
+ DestroyAurisysLibManager();
+ } else
+#endif
+ {
+ DeinitDataPending();
+
+
+ // bit conversion
+ deinitBitConverter();
+
+ // SRC
+ deinitBliSrc();
+ }
+
+ // debug pcm dump
+ ClosePCMDump();
+
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerBTSCO::routing(const audio_devices_t output_devices __unused) {
+ return INVALID_OPERATION;
+}
+
+ssize_t AudioALSAPlaybackHandlerBTSCO::write(const void *buffer, size_t bytes) {
+ ALOGV("%s(), buffer = %p, bytes = %zu", __FUNCTION__, buffer, bytes);
+
+ if (mPcm == NULL) {
+ ALOGE("%s(), mPcm == NULL, return", __FUNCTION__);
+ return bytes;
+ }
+
+ // const -> to non const
+ void *pBuffer = const_cast<void *>(buffer);
+ ASSERT(pBuffer != NULL);
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[0] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+
+ void *pBufferAfterDcRemoval = NULL;
+ uint32_t bytesAfterDcRemoval = 0;
+ // DC removal before DRC
+ doDcRemoval(pBuffer, bytes, &pBufferAfterDcRemoval, &bytesAfterDcRemoval);
+ pBuffer = pBufferAfterDcRemoval;
+ bytes = bytesAfterDcRemoval;
+
+ void *pBufferAfterPending = NULL;
+ uint32_t bytesAfterpending = 0;
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ if (get_aurisys_on()) {
+ // expect library output amount smoothly
+ mTransferredBufferSize = GetTransferredBufferSize(
+ bytes,
+ mStreamAttributeSource,
+ &mStreamAttributeTarget);
+
+ audio_pool_buf_copy_from_linear(
+ mAudioPoolBufDlIn,
+ pBuffer,
+ bytes);
+
+ // post processing + SRC + Bit conversion
+ aurisys_process_dl_only(mAurisysLibManager, mAudioPoolBufDlIn, mAudioPoolBufDlOut);
+
+ // data pending: sram is device memory, need word size align 64 byte for 64 bit platform
+ uint32_t data_size = audio_ringbuf_count(&mAudioPoolBufDlOut->ringbuf);
+ if (data_size > mTransferredBufferSize) {
+ data_size = mTransferredBufferSize;
+ }
+ data_size &= 0xFFFFFFC0;
+ audio_pool_buf_copy_to_linear(
+ &mLinearOut->p_buffer,
+ &mLinearOut->memory_size,
+ mAudioPoolBufDlOut,
+ data_size);
+
+ //ALOGD("aurisys process data_size: %u", data_size);
+
+ // wrap to original playback handler
+ pBufferAfterPending = (void *)mLinearOut->p_buffer;
+ bytesAfterpending = data_size;
+ } else
+#endif
+ {
+ // SRC
+ void *pBufferAfterBliSrc = NULL;
+ uint32_t bytesAfterBliSrc = 0;
+ doBliSrc(pBuffer, bytes, &pBufferAfterBliSrc, &bytesAfterBliSrc);
+
+
+ // bit conversion
+ void *pBufferAfterBitConvertion = NULL;
+ uint32_t bytesAfterBitConvertion = 0;
+ doBitConversion(pBufferAfterBliSrc, bytesAfterBliSrc, &pBufferAfterBitConvertion, &bytesAfterBitConvertion);
+
+
+ // data pending
+ pBufferAfterPending = NULL;
+ bytesAfterpending = 0;
+ dodataPending(pBufferAfterBitConvertion, bytesAfterBitConvertion, &pBufferAfterPending, &bytesAfterpending);
+ }
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[1] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+
+ // write data to pcm driver
+ WritePcmDumpData(pBufferAfterPending, bytesAfterpending);
+ int retval = pcm_write(mPcm, pBufferAfterPending, bytesAfterpending);
+
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[2] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+
+
+ if (retval != 0) {
+ ALOGE("%s(), pcm_write() error, retval = %d", __FUNCTION__, retval);
+ }
+
+#ifdef DEBUG_LATENCY
+ ALOGD("AudioALSAPlaybackHandlerNormal::write (-) latency_in_us,%1.6lf,%1.6lf,%1.6lf", latencyTime[0], latencyTime[1], latencyTime[2]);
+#endif
+
+
+ return bytes;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerBase.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerBase.cpp
new file mode 100644
index 0000000..a371565
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerBase.cpp
@@ -0,0 +1,1450 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAPlaybackHandlerBase.h"
+
+#include "AudioALSADataProcessor.h"
+
+#include "AudioALSADriverUtility.h"
+#include "AudioALSAHardwareResourceManager.h"
+#include "AudioUtility.h"
+
+#include "AudioMTKFilter.h"
+
+#if (defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT) && (MTK_AUDIO_TUNING_TOOL_V2_PHASE >= 2))
+#include "AudioParamParser.h"
+#endif
+
+#include <SpeechEnhancementController.h>
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+#include <utils/String8.h>
+
+#include <audio_memory_control.h>
+#include <audio_lock.h>
+#include <audio_ringbuf.h>
+
+
+#include <audio_task.h>
+#include <aurisys_scenario.h>
+
+#include <arsi_type.h>
+#include <aurisys_config.h>
+
+#include <audio_pool_buf_handler.h>
+
+#include <aurisys_utility.h>
+#include <aurisys_controller.h>
+#include <aurisys_lib_manager.h>
+#endif
+
+#ifdef MTK_AUDIO_SCP_SUPPORT
+#include <AudioMessengerIPI.h>
+#endif
+
+#ifdef MTK_AUDIODSP_SUPPORT
+#include "AudioDspStreamManager.h"
+#include <audio_task.h>
+#include <AudioDspType.h>
+#endif
+
+#include "AudioSmartPaController.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSAPlaybackHandlerBase"
+
+namespace android {
+
+static const uint32_t kMaxPcmDriverBufferSize = 0x20000; // 128k
+static const uint32_t kBliSrcOutputBufferSize = 0x10000; // 64k
+static const uint32_t kPcmDriverBufferSize = 0x20000; // 128k
+
+
+uint32_t AudioALSAPlaybackHandlerBase::mDumpFileNum = 0;
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+static AudioLock mAurisysLibManagerLock;
+#endif
+#ifdef MTK_AUDIODSP_SUPPORT
+static FILE *pcmdump_array[TASK_SCENE_SIZE][DEBUG_PCMDUMP_NUM];
+uint32_t AudioALSAPlaybackHandlerBase::mDumpFileNumDSP = 0;
+#endif
+
+AudioALSAPlaybackHandlerBase::AudioALSAPlaybackHandlerBase(const stream_attribute_t *stream_attribute_source) :
+#ifdef MTK_AUDIO_SCP_SUPPORT
+ mAudioMessengerIPI(AudioMessengerIPI::getInstance()),
+#else
+ mAudioMessengerIPI(NULL),
+#endif
+ mPlaybackHandlerType(PLAYBACK_HANDLER_BASE),
+ mHardwareResourceManager(AudioALSAHardwareResourceManager::getInstance()),
+ mStreamAttributeSource(stream_attribute_source),
+ mPcm(NULL),
+ mComprStream(NULL),
+ mStreamCbk(NULL),
+ mCbkCookie(NULL),
+ mAudioFilterManagerHandler(NULL),
+ mPostProcessingOutputBuffer(NULL),
+ mPostProcessingOutputBufferSize(0),
+ mFirstDataWrite(true),
+ mDcRemove(NULL),
+ mDcRemoveWorkBuffer(NULL),
+ mDcRemoveBufferSize(0),
+ mBliSrc(NULL),
+ mBliSrcOutputBuffer(NULL),
+ mBitConverter(NULL),
+ mBitConverterOutputBuffer(NULL),
+ mdataPendingOutputBuffer(NULL),
+ mdataPendingTempBuffer(NULL),
+ mdataPendingOutputBufferSize(0),
+ mdataPendingRemindBufferSize(0),
+ mDataAlignedSize(64),
+ mDataPendingForceUse(false),
+ mNLEMnger(NULL),
+ mPCMDumpFile(NULL),
+#ifdef MTK_AUDIODSP_SUPPORT
+ mPCMDumpFileDSP(NULL),
+#endif
+ mMixer(AudioALSADriverUtility::getInstance()->getMixer()),
+ mBytesWriteKernel(0),
+ mTimeStampValid(true),
+ mHalQueuedFrame(0),
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ mAurisysLibManager(NULL),
+ mManagerConfig(NULL),
+ mAurisysScenario(AURISYS_SCENARIO_INVALID),
+ mAudioPoolBufUlIn(NULL),
+ mAudioPoolBufUlOut(NULL),
+ mAudioPoolBufDlIn(NULL),
+ mAudioPoolBufDlOut(NULL),
+ mTransferredBufferSize(0xFFFFFFFF),
+ mLinearOut(NULL),
+#endif
+ mIsNeedUpdateLib(false),
+ mSmoother(NULL),
+ mDataProcessor(AudioALSADataProcessor::getInstance()),
+ mIdentity(0xFFFFFFFF),
+ mPcmflag(0),
+ audio_pcm_write_wrapper_fp(NULL) {
+ ALOGV("%s()", __FUNCTION__);
+
+ memset(&mConfig, 0, sizeof(mConfig));
+ memset(&mStreamAttributeTarget, 0, sizeof(mStreamAttributeTarget));
+ memset(&mComprConfig, 0, sizeof(mComprConfig));
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ AUDIO_ALLOC_STRUCT(struct data_buf_t, mLinearOut);
+#endif
+}
+
+
+AudioALSAPlaybackHandlerBase::~AudioALSAPlaybackHandlerBase() {
+ ALOGV("%s()", __FUNCTION__);
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ AUDIO_FREE_POINTER(mLinearOut);
+#endif
+}
+
+
+status_t AudioALSAPlaybackHandlerBase::ListPcmDriver(const unsigned int card, const unsigned int device) {
+ struct pcm_params *params;
+ unsigned int min, max ;
+ params = pcm_params_get(card, device, PCM_OUT);
+ if (params == NULL) {
+ ALOGD("Device does not exist.\n");
+ }
+ min = pcm_params_get_min(params, PCM_PARAM_RATE);
+ max = pcm_params_get_max(params, PCM_PARAM_RATE);
+ ALOGD(" Rate:\tmin=%uHz\tmax=%uHz\n", min, max);
+ min = pcm_params_get_min(params, PCM_PARAM_CHANNELS);
+ max = pcm_params_get_max(params, PCM_PARAM_CHANNELS);
+ ALOGD(" Channels:\tmin=%u\t\tmax=%u\n", min, max);
+ min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS);
+ max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS);
+ ALOGD(" Sample bits:\tmin=%u\t\tmax=%u\n", min, max);
+ min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE);
+ max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE);
+ ALOGD(" Period size:\tmin=%u\t\tmax=%u\n", min, max);
+ min = pcm_params_get_min(params, PCM_PARAM_PERIODS);
+ max = pcm_params_get_max(params, PCM_PARAM_PERIODS);
+ ALOGD("Period count:\tmin=%u\t\tmax=%u\n", min, max);
+ max = pcm_params_get_max(params, PCM_PARAM_BUFFER_SIZE);
+ ALOGD("PCM_PARAM_BUFFER_SIZE :\t max=%u\t\n", max);
+ max = pcm_params_get_max(params, PCM_PARAM_BUFFER_BYTES);
+ ALOGD("PCM_PARAM_BUFFER_BYTES :\t max=%u\t\n", max);
+ pcm_params_free(params);
+
+ return NO_ERROR;
+}
+status_t AudioALSAPlaybackHandlerBase::openPcmDriverWithFlag(const unsigned int device, unsigned int flag) {
+ ALOGV("+%s(), pcm device = %d flag = 0x%x", __FUNCTION__, device, flag);
+
+ ASSERT(mPcm == NULL);
+
+ mPcmflag = flag;
+ mPcm = pcm_open(AudioALSADeviceParser::getInstance()->GetCardIndex(),
+ device, flag, &mConfig);
+ if (mPcm == NULL) {
+ ALOGE("%s(), mPcm == NULL!!", __FUNCTION__);
+ } else if (pcm_is_ready(mPcm) == false) {
+ ALOGE("%s(), pcm_is_ready(%p) == false due to %s, close pcm.", __FUNCTION__, mPcm, pcm_get_error(mPcm));
+ pcm_close(mPcm);
+ mPcm = NULL;
+ } else if (pcm_prepare(mPcm) != 0) {
+ ALOGE("%s(), pcm_prepare(%p) == false due to %s, close pcm.", __FUNCTION__, mPcm, pcm_get_error(mPcm));
+ pcm_close(mPcm);
+ mPcm = NULL;
+ }
+
+ if (mPcmflag & PCM_MMAP) {
+ audio_pcm_write_wrapper_fp = pcm_mmap_write;
+ } else {
+ audio_pcm_write_wrapper_fp = pcm_write;
+ }
+
+ ALOGD("%s(), pcm device = %d flag = 0x%x mPcm = %p", __FUNCTION__, device, flag, mPcm);
+ ASSERT(mPcm != NULL);
+ return NO_ERROR;
+
+}
+
+status_t AudioALSAPlaybackHandlerBase::pcmWrite(struct pcm *pcm, const void *data, unsigned int count) {
+ return audio_pcm_write_wrapper_fp(pcm, data, count);
+}
+
+status_t AudioALSAPlaybackHandlerBase::openPcmDriver(const unsigned int device) {
+ return openPcmDriverWithFlag(device, PCM_OUT | PCM_MONOTONIC);
+}
+
+status_t AudioALSAPlaybackHandlerBase::closePcmDriver() {
+ ALOGV("+%s(), mPcm = %p", __FUNCTION__, mPcm);
+
+ if (mPcm != NULL) {
+ pcm_stop(mPcm);
+ pcm_close(mPcm);
+ mPcm = NULL;
+ }
+
+ ALOGD("-%s(), mPcm = %p", __FUNCTION__, mPcm);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerBase::openComprDriver(const unsigned int device) {
+ ALOGD("+%s(), compr device = %d", __FUNCTION__, device);
+ ASSERT(mComprStream == NULL);
+ mComprStream = compress_open(AudioALSADeviceParser::getInstance()->GetCardIndex(),
+ device, COMPRESS_IN, &mComprConfig);
+ if (mComprStream == NULL) {
+ ALOGE("%s(), mComprStream == NULL!!", __FUNCTION__);
+ return INVALID_OPERATION;
+ } else if (is_compress_ready(mComprStream) == false) {
+ ALOGE("%s(), compress device open fail:%s", __FUNCTION__, compress_get_error(mComprStream));
+ compress_close(mComprStream);
+ mComprStream = NULL;
+ return INVALID_OPERATION;
+ }
+ ALOGD("-%s(), mComprStream = %p", __FUNCTION__, mComprStream);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerBase::closeComprDriver() {
+ ALOGD("+%s(), mComprStream = %p", __FUNCTION__, mComprStream);
+
+ if (mComprStream != NULL) {
+ //close compress driver
+ compress_stop(mComprStream);
+ compress_close(mComprStream);
+ mComprStream = NULL;
+ }
+
+ ALOGD("-%s(), mComprStream = %p", __FUNCTION__, mComprStream);
+ return NO_ERROR;
+
+}
+
+status_t AudioALSAPlaybackHandlerBase::setComprCallback(stream_callback_t StreamCbk, void *CbkCookie) {
+ mStreamCbk = StreamCbk;
+ mCbkCookie = CbkCookie;
+ return NO_ERROR;
+}
+
+int AudioALSAPlaybackHandlerBase::updateAudioMode(audio_mode_t mode) {
+ ALOGV("%s(), mode %d", __FUNCTION__, mode);
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ if (mAurisysLibManager && get_aurisys_on()) {
+ if ((mAurisysScenario == AURISYS_SCENARIO_PLAYBACK_NORMAL || mAurisysScenario == AURISYS_SCENARIO_PLAYBACK_LOW_LATENCY) &&
+ IsVoIPEnable()) {
+ // change from normal to voip need delay
+ mIsNeedUpdateLib = true;
+ } else if (mAurisysScenario != AURISYS_SCENARIO_PLAYBACK_LOW_LATENCY) {
+ mIsNeedUpdateLib = false;
+ DestroyAurisysLibManager();
+ CreateAurisysLibManager();
+ }
+ }
+#endif
+ return 0;
+}
+
+int AudioALSAPlaybackHandlerBase::preWriteOperation(const void *buffer, size_t bytes) {
+ ALOGV("%s(), buffer %p, bytes %zu, mIsNeedUpdateLib %d", __FUNCTION__, buffer, bytes, mIsNeedUpdateLib);
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ // reopen aurisys when one hal buffer is in low level, below -60dB
+ if (!mIsNeedUpdateLib) {
+ return 0;
+ }
+
+ bool canUpdateLib = true;
+
+ size_t tmp_bytes = bytes;
+
+ if (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_16_BIT) {
+ int16_t *sample = (int16_t *)buffer;
+ int16_t threshold = 32; // below -60dB, ((2^16) >> 10) / 2 = 32
+
+ while (tmp_bytes > 0) {
+ if (((*sample) > threshold) || ((*sample) < (-1 * threshold))) {
+ canUpdateLib = false;
+ break;
+ }
+ tmp_bytes -= audio_bytes_per_sample(mStreamAttributeSource->audio_format);
+ sample++;
+ }
+ } else { // assume AUDIO_FORMAT_PCM_32_BIT
+ int32_t *sample = (int32_t *)buffer;
+ int32_t threshold = 2097152; // below -60dB, ((2^32) >> 10) / 2 = 2097152
+
+ while (tmp_bytes > 0) {
+ if (((*sample) > threshold) || ((*sample) < (-1 * threshold))) {
+ canUpdateLib = false;
+ break;
+ }
+ tmp_bytes -= audio_bytes_per_sample(mStreamAttributeSource->audio_format);
+ sample++;
+ }
+ }
+
+ if (canUpdateLib) {
+ mIsNeedUpdateLib = false;
+ DestroyAurisysLibManager();
+ CreateAurisysLibManager();
+ }
+
+#endif
+ return 0;
+}
+
+status_t AudioALSAPlaybackHandlerBase::doStereoToMonoConversionIfNeed(void *buffer, size_t bytes) {
+#ifndef ENABLE_STEREO_SPEAKER
+ if (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER) {
+ if (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_32_BIT) {
+ int32_t *Sample = (int32_t *)buffer;
+ while (bytes > 0) {
+ int32_t averageValue = ((*Sample) >> 1) + ((*(Sample + 1)) >> 1);
+ *Sample++ = averageValue;
+ *Sample++ = averageValue;
+ bytes -= 8;
+ }
+ } else if (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_16_BIT) {
+ int16_t *Sample = (int16_t *)buffer;
+ while (bytes > 0) {
+ int16_t averageValue = ((*Sample) >> 1) + ((*(Sample + 1)) >> 1);
+ *Sample++ = averageValue;
+ *Sample++ = averageValue;
+ bytes -= 4;
+ }
+ }
+ }
+#endif
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerBase::setScreenState(bool mode __unused,
+ size_t buffer_size __unused,
+ size_t reduceInterruptSize __unused,
+ bool bforce __unused) {
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerBase::getHardwareBufferInfo(time_info_struct_t *HWBuffer_Time_Info) {
+#if defined(CONFIG_MT_ENG_BUILD)
+ ALOGV("+%s()", __FUNCTION__);
+#endif
+
+ if (mComprStream == NULL) {
+ ASSERT(mPcm != NULL);
+ } else {
+ ALOGD("%s(), no pcm handler, return directly", __FUNCTION__);
+ return NO_ERROR;
+ }
+
+ if (mTimeStampValid == false) {
+ ALOGV("getHardwareBufferInfo: It doesn't start to fetch data on PCM buffer");
+ return UNKNOWN_ERROR;
+ }
+
+ ASSERT(mPcm != NULL);
+ int ret = pcm_get_htimestamp(mPcm, &HWBuffer_Time_Info->frameInfo_get, &HWBuffer_Time_Info->timestamp_get);
+ if (ret != 0) {
+ ALOGE("-%s(), pcm_get_htimestamp fail, ret = %d, pcm_get_error = %s", __FUNCTION__, ret, pcm_get_error(mPcm));
+ return UNKNOWN_ERROR;
+ } else {
+ // kernel total buffer size to frame
+ HWBuffer_Time_Info->buffer_per_time = pcm_bytes_to_frames(mPcm, mStreamAttributeTarget.buffer_size);
+
+ HWBuffer_Time_Info->halQueuedFrame = mHalQueuedFrame;
+ }
+ ALOGV("-%s, frameInfo_get = %u, mStreamAttributeTarget.buffer_size = %d, buffer_per_time = %u, halQueuedFrame = %d",
+ __FUNCTION__, HWBuffer_Time_Info->frameInfo_get, mStreamAttributeTarget.buffer_size, HWBuffer_Time_Info->buffer_per_time, HWBuffer_Time_Info->halQueuedFrame);
+ return NO_ERROR;
+}
+status_t AudioALSAPlaybackHandlerBase::get_timeStamp(unsigned long *frames, unsigned int *samplerate) {
+ if (mComprStream == NULL) {
+ ALOGE("%s(), mComprStream NULL", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ if (compress_get_tstamp(mComprStream, frames, samplerate) == 0) {
+ ALOGV("%s(), frames:%lu, samplerate:%u", __FUNCTION__, *frames, *samplerate);
+ return NO_ERROR;
+ } else {
+ ALOGE("%s get_tstamp fail %s\n", __FUNCTION__, compress_get_error(mComprStream));
+ return UNKNOWN_ERROR;
+ }
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerBase::updateHardwareBufferInfo(size_t sourceWrittenBytes, uint32_t targetWrittenBytes) {
+ // calculated hal queued buffer
+ size_t sourceSizePerFrame = getSizePerFrame(mStreamAttributeSource->audio_format,
+ mStreamAttributeSource->num_channels);
+ size_t targetSizePerFrame = getSizePerFrame(mStreamAttributeTarget.audio_format,
+ mStreamAttributeTarget.num_channels);
+
+ size_t inBytesInHandler = ((uint64_t)sourceWrittenBytes * mStreamAttributeTarget.sample_rate * targetSizePerFrame) /
+ (sourceSizePerFrame * mStreamAttributeSource->sample_rate);
+
+ if (inBytesInHandler >= targetWrittenBytes) {
+ if (mPcm) {
+ mHalQueuedFrame += pcm_bytes_to_frames(mPcm, inBytesInHandler - targetWrittenBytes);
+ } else {
+ mHalQueuedFrame += (inBytesInHandler - targetWrittenBytes) / targetSizePerFrame;
+ }
+ } else {
+ if (mPcm) {
+ mHalQueuedFrame -= pcm_bytes_to_frames(mPcm, targetWrittenBytes - inBytesInHandler);
+ } else {
+ mHalQueuedFrame -= (targetWrittenBytes - inBytesInHandler) / targetSizePerFrame;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+playback_handler_t AudioALSAPlaybackHandlerBase::getPlaybackHandlerType() {
+ return mPlaybackHandlerType;
+}
+
+status_t AudioALSAPlaybackHandlerBase::setFilterMng(AudioMTKFilterManager *pFilterMng __unused) {
+ ALOGW("%s(), do nothing", __FUNCTION__);
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAPlaybackHandlerBase::initPostProcessing() {
+ // init post processing
+ mPostProcessingOutputBufferSize = kMaxPcmDriverBufferSize;
+ mPostProcessingOutputBuffer = new char[mPostProcessingOutputBufferSize];
+ ASSERT(mPostProcessingOutputBuffer != NULL);
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerBase::deinitPostProcessing() {
+ // deinit post processing
+ if (mPostProcessingOutputBuffer) {
+ delete []mPostProcessingOutputBuffer;
+ mPostProcessingOutputBuffer = NULL;
+ mPostProcessingOutputBufferSize = 0;
+ }
+#if !defined(MTK_AURISYS_FRAMEWORK_SUPPORT)
+ if (mAudioFilterManagerHandler) {
+ mAudioFilterManagerHandler->stop();
+ mAudioFilterManagerHandler = NULL;
+ }
+#endif
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerBase::doPostProcessing(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes) {
+ // bypass downlink filter while DMNR tuning // TO DO Verification, HoChi
+#if !defined(MTK_AURISYS_FRAMEWORK_SUPPORT)
+ if (mAudioFilterManagerHandler && mStreamAttributeSource->BesRecord_Info.besrecord_dmnr_tuningEnable == false && mStreamAttributeSource->bBypassPostProcessDL == false)
+ {
+ if (inBytes > mPostProcessingOutputBufferSize) {
+ ALOGW("%s(), inBytes %d > mPostProcessingOutputBufferSize %d", __FUNCTION__, inBytes, mPostProcessingOutputBufferSize);
+ ASSERT(0);
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ } else {
+ mAudioFilterManagerHandler->start(mFirstDataWrite); // TODO(Harvey, Hochi), why start everytime in write() ??
+ uint32_t outputSize = mAudioFilterManagerHandler->process(pInBuffer, inBytes, mPostProcessingOutputBuffer, mPostProcessingOutputBufferSize);
+ if (outputSize == 0) {
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ } else {
+ *ppOutBuffer = mPostProcessingOutputBuffer;
+ *pOutBytes = outputSize;
+ }
+ }
+ } else
+#endif
+ { // bypass
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ }
+
+ ASSERT(*ppOutBuffer != NULL && *pOutBytes != 0);
+ return NO_ERROR;
+}
+
+int32 AudioALSAPlaybackHandlerBase::initDcRemoval() {
+ DCR_BITDEPTH depth = DCREMOVE_BIT24;
+ mDcRemove = newMtkDcRemove();
+ ASSERT(mDcRemove != NULL);
+ if (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_16_BIT) {
+ depth = DCREMOVE_BIT16;
+ }
+ mDcRemove->init(mStreamAttributeSource->num_channels, mStreamAttributeSource->sample_rate,
+ DCR_MODE_3, depth);
+ mDcRemoveBufferSize = kMaxPcmDriverBufferSize;
+ mDcRemoveWorkBuffer = new char[mDcRemoveBufferSize];
+ memset(mDcRemoveWorkBuffer, 0, mDcRemoveBufferSize);
+ ASSERT(mDcRemoveWorkBuffer != NULL);
+ return NO_ERROR;
+
+}
+
+int32 AudioALSAPlaybackHandlerBase::deinitDcRemoval() {
+ if (mDcRemove) {
+ mDcRemove->close();
+ deleteMtkDcRemove(mDcRemove);
+ mDcRemove = NULL;
+ }
+ if (mDcRemoveWorkBuffer) {
+ delete [] mDcRemoveWorkBuffer;
+ mDcRemoveWorkBuffer = NULL;
+ }
+ return NO_ERROR;
+}
+
+int32 AudioALSAPlaybackHandlerBase::doDcRemoval(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes) {
+ uint32_t num_process_data = mDcRemoveBufferSize;
+
+ if (mDcRemove == NULL) {
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ } else if (inBytes > mDcRemoveBufferSize) {
+ ALOGW("%s(), inBytes %d > mDcRemoveBufferSize %d", __FUNCTION__, inBytes, mDcRemoveBufferSize);
+ ASSERT(0);
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ } else {
+ mDcRemove->process(pInBuffer, &inBytes, mDcRemoveWorkBuffer, &num_process_data);
+ *ppOutBuffer = mDcRemoveWorkBuffer;
+ *pOutBytes = num_process_data;
+ }
+ ALOGV("%s(), inBytes: %d, pOutBytes: %d ppOutBuffer = %p", __FUNCTION__, inBytes, *pOutBytes, *ppOutBuffer);
+ ASSERT(*ppOutBuffer != NULL && *pOutBytes != 0);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerBase::initBliSrc() {
+ // init BLI SRC if need
+ if (mStreamAttributeSource->sample_rate != mStreamAttributeTarget.sample_rate ||
+ mStreamAttributeSource->num_channels != mStreamAttributeTarget.num_channels) {
+ ALOGD("%s(), sample_rate: %d => %d, num_channels: %d => %d, mStreamAttributeSource->audio_format: 0x%x", __FUNCTION__,
+ mStreamAttributeSource->sample_rate, mStreamAttributeTarget.sample_rate,
+ mStreamAttributeSource->num_channels, mStreamAttributeTarget.num_channels,
+ mStreamAttributeSource->audio_format);
+
+ SRC_PCM_FORMAT src_pcm_format = SRC_IN_Q1P15_OUT_Q1P15;
+ if (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_32_BIT) {
+ src_pcm_format = SRC_IN_Q1P31_OUT_Q1P31;
+ } else if (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_16_BIT) {
+ src_pcm_format = SRC_IN_Q1P15_OUT_Q1P15;
+ } else {
+ ALOGE("%s(), not support mStreamAttributeSource->audio_format(0x%x) SRC!!", __FUNCTION__, mStreamAttributeSource->audio_format);
+ }
+
+ mBliSrc = newMtkAudioSrc(
+ mStreamAttributeSource->sample_rate, mStreamAttributeSource->num_channels,
+ mStreamAttributeTarget.sample_rate, mStreamAttributeTarget.num_channels,
+ src_pcm_format);
+ ASSERT(mBliSrc != NULL);
+ mBliSrc->open();
+
+ mBliSrcOutputBuffer = new char[kBliSrcOutputBufferSize];
+ ASSERT(mBliSrcOutputBuffer != NULL);
+ }
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerBase::deinitBliSrc() {
+ // deinit BLI SRC if need
+ if (mBliSrc != NULL) {
+ mBliSrc->close();
+ deleteMtkAudioSrc(mBliSrc);
+ mBliSrc = NULL;
+ }
+
+ if (mBliSrcOutputBuffer != NULL) {
+ delete[] mBliSrcOutputBuffer;
+ mBliSrcOutputBuffer = NULL;
+ }
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerBase::doBliSrc(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes) {
+ if (mBliSrc == NULL) { // No need SRC
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ } else {
+ char *p_read = (char *)pInBuffer;
+ uint32_t num_raw_data_left = inBytes;
+ uint32_t num_converted_data = kBliSrcOutputBufferSize; // max convert num_free_space
+
+ uint32_t consumed = num_raw_data_left;
+ mBliSrc->process((int16_t *)p_read, &num_raw_data_left,
+ (int16_t *)mBliSrcOutputBuffer, &num_converted_data);
+ consumed -= num_raw_data_left;
+ p_read += consumed;
+
+ ALOGV("%s(), num_raw_data_left = %u, num_converted_data = %u",
+ __FUNCTION__, num_raw_data_left, num_converted_data);
+
+ if (num_raw_data_left > 0) {
+ ALOGW("%s(), num_raw_data_left(%u) > 0", __FUNCTION__, num_raw_data_left);
+ ASSERT(num_raw_data_left == 0);
+ }
+
+ *ppOutBuffer = mBliSrcOutputBuffer;
+ *pOutBytes = num_converted_data;
+ }
+
+ ASSERT(*ppOutBuffer != NULL && *pOutBytes != 0);
+ return NO_ERROR;
+}
+
+
+pcm_format AudioALSAPlaybackHandlerBase::transferAudioFormatToPcmFormat(const audio_format_t audio_format) const {
+ pcm_format retval = PCM_FORMAT_S16_LE;
+
+ switch (audio_format) {
+ case AUDIO_FORMAT_PCM_8_BIT: {
+ retval = PCM_FORMAT_S8;
+ break;
+ }
+ case AUDIO_FORMAT_PCM_16_BIT: {
+ retval = PCM_FORMAT_S16_LE;
+ break;
+ }
+ case AUDIO_FORMAT_PCM_8_24_BIT: {
+#if defined(MTK_AUDIO_KS)
+ retval = PCM_FORMAT_S24_LE;
+#else
+ retval = PCM_FORMAT_S32_LE;
+#endif
+ break;
+ }
+ case AUDIO_FORMAT_PCM_32_BIT: {
+ retval = PCM_FORMAT_S32_LE;
+ break;
+ }
+ default: {
+ ALOGE("No such audio format(0x%x)!! Use AUDIO_FORMAT_PCM_16_BIT(0x%x) instead", audio_format, PCM_FORMAT_S16_LE);
+ retval = PCM_FORMAT_S16_LE;
+ break;
+ }
+ }
+
+ ALOGD("%s(), audio_format(0x%x) => pcm_format(0x%x)", __FUNCTION__, audio_format, retval);
+ return retval;
+}
+
+
+status_t AudioALSAPlaybackHandlerBase::initBitConverter() {
+ // init bit converter if need
+ if (mStreamAttributeSource->audio_format != mStreamAttributeTarget.audio_format) {
+ BCV_PCM_FORMAT bcv_pcm_format;
+ bool isInputValid = true;
+ if ((mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_32_BIT) || (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_8_24_BIT)) {
+ if (mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_16_BIT) {
+ bcv_pcm_format = BCV_IN_Q1P31_OUT_Q1P15;
+ } else if (mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_8_24_BIT) {
+ bcv_pcm_format = BCV_IN_Q1P31_OUT_Q9P23;
+ } else {
+ isInputValid = false;
+ }
+ } else if (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_16_BIT) {
+ if (mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_32_BIT) {
+ bcv_pcm_format = BCV_IN_Q1P15_OUT_Q1P31;
+ } else if (mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_8_24_BIT) {
+ bcv_pcm_format = BCV_IN_Q1P15_OUT_Q9P23;
+ } else {
+ isInputValid = false;
+ }
+ } else if (mStreamAttributeSource->audio_format == AUDIO_FORMAT_MP3) { //doug for tunneling
+ if (mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_16_BIT) {
+ return NO_ERROR;
+ } else if (mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_8_24_BIT) {
+ bcv_pcm_format = BCV_IN_Q1P15_OUT_Q9P23;
+ } else {
+ isInputValid = false;
+ }
+ }
+
+ if (!isInputValid) {
+ ASSERT(0);
+ ALOGD("%s(), invalid, audio_format: 0x%x => 0x%x",
+ __FUNCTION__, mStreamAttributeSource->audio_format, mStreamAttributeTarget.audio_format);
+ return INVALID_OPERATION;
+ }
+
+ ALOGD("%s(), audio_format: 0x%x => 0x%x, bcv_pcm_format = 0x%x",
+ __FUNCTION__, mStreamAttributeSource->audio_format, mStreamAttributeTarget.audio_format, bcv_pcm_format);
+
+ if (mStreamAttributeSource->num_channels > 2) {
+ mBitConverter = newMtkAudioBitConverter(
+ mStreamAttributeSource->sample_rate,
+ 2,
+ bcv_pcm_format);
+ } else {
+ mBitConverter = newMtkAudioBitConverter(
+ mStreamAttributeSource->sample_rate,
+ mStreamAttributeSource->num_channels,
+ bcv_pcm_format);
+ }
+
+ ASSERT(mBitConverter != NULL);
+ mBitConverter->open();
+ mBitConverter->resetBuffer();
+
+ mBitConverterOutputBuffer = new char[kMaxPcmDriverBufferSize];
+ ASSERT(mBitConverterOutputBuffer != NULL);
+ ASSERT(mBitConverterOutputBuffer != NULL);
+ }
+
+ ALOGV("%s(), mBitConverter = %p, mBitConverterOutputBuffer = %p", __FUNCTION__, mBitConverter, mBitConverterOutputBuffer);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerBase::deinitBitConverter() {
+ // deinit bit converter if need
+ if (mBitConverter != NULL) {
+ mBitConverter->close();
+ deleteMtkAudioBitConverter(mBitConverter);
+ mBitConverter = NULL;
+ }
+
+ if (mBitConverterOutputBuffer != NULL) {
+ delete[] mBitConverterOutputBuffer;
+ mBitConverterOutputBuffer = NULL;
+ }
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerBase::doBitConversion(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes) {
+ if (mBitConverter != NULL) {
+ *pOutBytes = kPcmDriverBufferSize;
+ mBitConverter->process(pInBuffer, &inBytes, (void *)mBitConverterOutputBuffer, pOutBytes);
+ *ppOutBuffer = mBitConverterOutputBuffer;
+ } else {
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ }
+
+ ASSERT(*ppOutBuffer != NULL && *pOutBytes != 0);
+ return NO_ERROR;
+}
+
+// we assue that buufer should write as 64 bytes align , so only src handler is create,
+// will cause output buffer is not 64 bytes align
+status_t AudioALSAPlaybackHandlerBase::initDataPending() {
+ ALOGV("mBliSrc = %p", mBliSrc);
+ if (mBliSrc != NULL || mDataPendingForceUse) {
+ mdataPendingOutputBufferSize = (1024 * 128) + mDataAlignedSize; // here nned to cover max write buffer size
+ mdataPendingOutputBuffer = new char[mdataPendingOutputBufferSize];
+ mdataPendingTempBuffer = new char[mDataAlignedSize];
+ ASSERT(mdataPendingOutputBuffer != NULL);
+ }
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerBase::DeinitDataPending() {
+ ALOGD("DeinitDataPending");
+ if (mdataPendingOutputBuffer != NULL) {
+ delete[] mdataPendingOutputBuffer;
+ mdataPendingOutputBuffer = NULL;
+ }
+ if (mdataPendingTempBuffer != NULL) {
+ delete[] mdataPendingTempBuffer ;
+ mdataPendingTempBuffer = NULL;
+ }
+ mdataPendingOutputBufferSize = 0;
+ mdataPendingRemindBufferSize = 0;
+ return NO_ERROR;
+}
+
+// we assue that buufer should write as 64 bytes align , so only src handler is create,
+// will cause output buffer is not 64 bytes align
+status_t AudioALSAPlaybackHandlerBase::dodataPending(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes) {
+ char *DataPointer = (char *)mdataPendingOutputBuffer;
+ char *DatainputPointer = (char *)pInBuffer;
+ uint32 TotalBufferSize = inBytes + mdataPendingRemindBufferSize;
+ uint32 tempRemind = TotalBufferSize % mDataAlignedSize;
+ uint32 TotalOutputSize = TotalBufferSize - tempRemind;
+ uint32 TotalOutputCount = TotalOutputSize;
+ if (mBliSrc != NULL || mDataPendingForceUse) { // do data pending
+ //ALOGD("inBytes = %d mdataPendingRemindBufferSize = %d TotalOutputSize = %d",inBytes,mdataPendingRemindBufferSize,TotalOutputSize);
+
+ if (TotalOutputSize != 0) {
+ if (mdataPendingRemindBufferSize != 0) { // deal previous remaind buffer
+ memcpy((void *)DataPointer, (void *)mdataPendingTempBuffer, mdataPendingRemindBufferSize);
+ DataPointer += mdataPendingRemindBufferSize;
+ TotalOutputCount -= mdataPendingRemindBufferSize;
+ }
+
+ //deal with input buffer
+ memcpy((void *)DataPointer, pInBuffer, TotalOutputCount);
+ DataPointer += TotalOutputCount;
+ DatainputPointer += TotalOutputCount;
+ TotalOutputCount = 0;
+
+ //ALOGD("tempRemind = %d pOutBytes = %d",tempRemind,*pOutBytes);
+
+ // deal with remind buffer
+ memcpy((void *)mdataPendingTempBuffer, (void *)DatainputPointer, tempRemind);
+ mdataPendingRemindBufferSize = tempRemind;
+ } else {
+ // deal with remind buffer
+ memcpy((void *)(mdataPendingTempBuffer + mdataPendingRemindBufferSize), (void *)DatainputPointer, inBytes);
+ mdataPendingRemindBufferSize += inBytes;
+ }
+
+ // update pointer and data count
+ *ppOutBuffer = mdataPendingOutputBuffer;
+ *pOutBytes = TotalOutputSize;
+ } else {
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ }
+
+ ASSERT(*ppOutBuffer != NULL);
+ if (!mDataPendingForceUse) {
+ ASSERT(*pOutBytes != 0);
+ }
+ return NO_ERROR;
+}
+
+
+
+
+void AudioALSAPlaybackHandlerBase::OpenPCMDump(const char *className) {
+ ALOGV("%s()", __FUNCTION__);
+ char mDumpFileName[128];
+ sprintf(mDumpFileName, "%s.%d.%s.pid%d.tid%d.pcm", streamout, mDumpFileNum, className, getpid(), gettid());
+
+ mPCMDumpFile = NULL;
+ mPCMDumpFile = AudioOpendumpPCMFile(mDumpFileName, streamout_propty);
+
+ if (mPCMDumpFile != NULL) {
+ ALOGD("%s DumpFileName = %s", __FUNCTION__, mDumpFileName);
+
+ mDumpFileNum++;
+ mDumpFileNum %= MAX_DUMP_NUM;
+ }
+}
+
+void AudioALSAPlaybackHandlerBase::ClosePCMDump() {
+ ALOGV("%s()", __FUNCTION__);
+ if (mPCMDumpFile) {
+ AudioCloseDumpPCMFile(mPCMDumpFile);
+ ALOGD("%s(), close it", __FUNCTION__);
+ }
+}
+
+void AudioALSAPlaybackHandlerBase::WritePcmDumpData(const void *buffer, ssize_t bytes) {
+ if (mPCMDumpFile) {
+ //ALOGD("%s()", __FUNCTION__);
+ AudioDumpPCMData((void *)buffer, bytes, mPCMDumpFile);
+ }
+}
+
+#ifdef MTK_AUDIODSP_SUPPORT
+int AudioALSAPlaybackHandlerBase::setDspDumpWakelock(bool condition) {
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "audio_dsp_wakelock"), 0, condition)) {
+ ALOGW("%s(), enable fail", __FUNCTION__);
+ return -1;
+ }
+ return 0;
+}
+
+void AudioALSAPlaybackHandlerBase::OpenPCMDumpDSP(const char *className) {
+#define MAX_TASKNAME_LEN (128)
+
+ const char *audio_dump = "/data/vendor/audiohal/audio_dump";
+
+ char mDumpFileName[128];
+ char task_name[MAX_TASKNAME_LEN];
+ char value[PROPERTY_VALUE_MAX];
+ uint8_t pcmdump_task_id = TASK_SCENE_PRIMARY;
+ int i, dsp_taskdump_property = 0;
+ struct ipi_msg_t ipi_msg;
+ FILE *pcm_dump = NULL;
+
+ ALOGD("%s() mAudioOutputFlags=0x%x", __FUNCTION__, mStreamAttributeSource->mAudioOutputFlags);
+
+ if (mStreamAttributeSource->mAudioOutputFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
+ strncpy(task_name, "TaskDeepBuf", MAX_TASKNAME_LEN);
+ pcmdump_task_id = TASK_SCENE_DEEPBUFFER;
+ } else if (mStreamAttributeSource->mAudioOutputFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+ strncpy(task_name, "TaskPrimary", MAX_TASKNAME_LEN);
+ pcmdump_task_id = TASK_SCENE_PRIMARY;
+ } else if (mStreamAttributeSource->mAudioOutputFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ strncpy(task_name, "TaskOffload", MAX_TASKNAME_LEN);
+ pcmdump_task_id = TASK_SCENE_PLAYBACK_MP3;
+ } else if (mStreamAttributeSource->mAudioOutputFlags & AUDIO_OUTPUT_FLAG_VOIP_RX) {
+ strncpy(task_name, "TaskVoip", MAX_TASKNAME_LEN);
+ pcmdump_task_id = TASK_SCENE_VOIP;
+ } else {
+ strncpy(task_name, "TaskPrimary", MAX_TASKNAME_LEN);
+ pcmdump_task_id = TASK_SCENE_PRIMARY;
+ }
+
+ property_get(streamoutdsp_propty, value, "0");
+ dsp_taskdump_property = atoi(value);
+ ALOGD("dsp_taskdump_property = %d", dsp_taskdump_property);
+ if (dsp_taskdump_property) {
+ setDspDumpWakelock(true);
+ for (i = 0; i < DEBUG_PCMDUMP_NUM; i++) {
+ sprintf(mDumpFileName, "%s/%s.%d.%d.%d.%s_point%d.pcm",
+ audio_dump, className, mDumpFileNumDSP, getpid(), gettid(), task_name, i);
+ mPCMDumpFileDSP = AudioOpendumpPCMFile(mDumpFileName, streamoutdsp_propty);
+ if (mPCMDumpFileDSP != NULL) {
+ ALOGD("%s DumpFileName = %s", __FUNCTION__, mDumpFileName);
+ }
+ set_task_pcmdump_info(pcmdump_task_id, i, (void *)mPCMDumpFileDSP);
+ }
+
+ // send PCM_DUMP_ENABLE ipi to DSP
+ mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ pcmdump_task_id, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_BYPASS_ACK,
+ AUDIO_DSP_TASK_PCMDUMP_ON, dsp_taskdump_property, 0,
+ NULL);
+
+ // check taskplayabck dump
+ if (AudioDspStreamManager::getInstance()->getDspTaskPlaybackStatus() == true) {
+ strncpy(task_name, "TaskPlayback", MAX_TASKNAME_LEN);
+
+ for (i = 0; i < DEBUG_PCMDUMP_NUM; i++) {
+ get_task_pcmdump_info(TASK_SCENE_AUDPLAYBACK, i, (void **)&pcm_dump);
+ if (pcm_dump == NULL) {
+ sprintf(mDumpFileName, "%s/%s.%d.%d.%d.%s_point%d.pcm",
+ audio_dump, className, mDumpFileNumDSP, getpid(), gettid(), task_name, i);
+ mPCMDumpFileDSP = AudioOpendumpPCMFile(mDumpFileName, streamoutdsp_propty);
+ if (mPCMDumpFileDSP != NULL) {
+ ALOGD("%s DumpFileName = %s", __FUNCTION__, mDumpFileName);
+ }
+ set_task_pcmdump_info(TASK_SCENE_AUDPLAYBACK, i, (void *)mPCMDumpFileDSP);
+ }
+ }
+
+ mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_AUDPLAYBACK, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_BYPASS_ACK,
+ AUDIO_DSP_TASK_PCMDUMP_ON, dsp_taskdump_property, 0,
+ NULL);
+ }
+ mDumpFileNumDSP++;
+ mDumpFileNumDSP %= MAX_DUMP_NUM;
+ } else {
+ mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ pcmdump_task_id, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_BYPASS_ACK,
+ AUDIO_DSP_TASK_PCMDUMP_ON, dsp_taskdump_property, 0,
+ NULL);
+ mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_AUDPLAYBACK, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_BYPASS_ACK,
+ AUDIO_DSP_TASK_PCMDUMP_ON, dsp_taskdump_property, 0,
+ NULL);
+ }
+}
+
+void AudioALSAPlaybackHandlerBase::ClosePCMDumpDSP(void) {
+
+ char value[PROPERTY_VALUE_MAX];
+ uint8_t pcmdump_task_id = TASK_SCENE_PRIMARY;
+ int dsp_taskdump_property;
+ FILE *pcm_dump = NULL;
+ int i;
+
+ ALOGD("%s() mAudioOutputFlags=0x%x", __FUNCTION__, mStreamAttributeSource->mAudioOutputFlags);
+
+ if (mStreamAttributeSource->mAudioOutputFlags == AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
+ pcmdump_task_id = TASK_SCENE_DEEPBUFFER;
+ } else if (mStreamAttributeSource->mAudioOutputFlags == AUDIO_OUTPUT_FLAG_PRIMARY) {
+ pcmdump_task_id = TASK_SCENE_PRIMARY;
+ } else if (mStreamAttributeSource->mAudioOutputFlags == AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ pcmdump_task_id = TASK_SCENE_PLAYBACK_MP3;
+ } else {
+ pcmdump_task_id = TASK_SCENE_PRIMARY;
+ }
+
+ /* do this to prevent property is close when playback. */
+ setDspDumpWakelock(false);
+
+ for (i = 0; i < DEBUG_PCMDUMP_NUM; i++) {
+ get_task_pcmdump_info(pcmdump_task_id, i, (void **)&pcm_dump);
+ if (pcm_dump != NULL) {
+ AudioCloseDumpPCMFile(pcm_dump);
+ set_task_pcmdump_info(pcmdump_task_id, i, NULL);
+ }
+ }
+
+ if (AudioDspStreamManager::getInstance()->getDspTaskPlaybackStatus() == false) {
+ for (i = 0; i < DEBUG_PCMDUMP_NUM; i++) {
+ get_task_pcmdump_info(TASK_SCENE_AUDPLAYBACK, i, (void **)&pcm_dump);
+ if (pcm_dump != NULL) {
+ AudioCloseDumpPCMFile(pcm_dump);
+ set_task_pcmdump_info(TASK_SCENE_AUDPLAYBACK, i, NULL);
+ }
+ }
+ }
+}
+#endif
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+status_t AudioALSAPlaybackHandlerBase::initNLEProcessing() {
+ status_t dRet;
+
+ if (mNLEMnger != NULL) {
+ return ALREADY_EXISTS;
+ }
+
+ mNLEMnger = AudioALSAHyBridNLEManager::getInstance();
+
+ if (mNLEMnger == NULL) {
+ ALOGE("[Err] NLE %s New Fail Line#%d", __FUNCTION__, __LINE__);
+ return NO_MEMORY;
+ }
+
+ dRet = mNLEMnger->initPlayBackHandler(mPlaybackHandlerType, &mStreamAttributeTarget, this);
+
+ if (dRet != NO_ERROR) {
+ mNLEMnger = NULL;
+ ALOGV("Unsupport the Handler NLE %s init Fail Line#%d", __FUNCTION__, __LINE__);
+ }
+ return dRet;
+}
+
+
+status_t AudioALSAPlaybackHandlerBase::deinitNLEProcessing() {
+ status_t dRet;
+
+ if (mNLEMnger != NULL) {
+ dRet = mNLEMnger->deinitPlayBackHandler(mPlaybackHandlerType);
+ if (dRet != NO_ERROR) {
+ ALOGW("[Warn] NLE %s deinit Fail Line#%d", __FUNCTION__, __LINE__);
+ }
+ mNLEMnger = NULL;
+ return dRet;
+ } else {
+ ALOGV("Unsupport the Handler NLE %s ObjNull Fail Line#%d", __FUNCTION__, __LINE__);
+ return NO_INIT;
+ }
+}
+
+
+status_t AudioALSAPlaybackHandlerBase::doNLEProcessing(void *pInBuffer, size_t inBytes) {
+ size_t dWriteByte = 0;
+ status_t dRet;
+
+ if (mNLEMnger != NULL) {
+ dRet = mNLEMnger->process(mPlaybackHandlerType, pInBuffer, inBytes);
+ if (dRet != NO_ERROR) {
+ ALOGV("[Warn] NLE %s Line#%d dRet %d", __FUNCTION__, __LINE__, dRet);
+ }
+ return dRet;
+ } else {
+ ALOGV("[Warn] NLE %s ObjNull Fail Line#%d", __FUNCTION__, __LINE__);
+ return NO_INIT;
+ }
+}
+#else
+status_t AudioALSAPlaybackHandlerBase::initNLEProcessing() {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAPlaybackHandlerBase::deinitNLEProcessing() {
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAPlaybackHandlerBase::doNLEProcessing(void *pInBuffer __unused, size_t inBytes __unused) {
+ return INVALID_OPERATION;
+}
+#endif
+
+
+
+/*
+ * =============================================================================
+ * Aurisys Framework 2.0
+ * =============================================================================
+ */
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+void AudioALSAPlaybackHandlerBase::CreateAurisysLibManager() {
+ uint32_t sample_rate = 0 ;
+ const char* libKey = NULL;
+
+ /* scenario & sample rate */
+ if (IsVoIPEnable()) {
+ mAurisysScenario = AURISYS_SCENARIO_VOIP; /* VoIP DL */
+ sample_rate = 16000;
+ libKey = "MTKSE";
+ } else if (mStreamAttributeSource->mAudioOutputFlags & AUDIO_OUTPUT_FLAG_FAST) {
+ mAurisysScenario = AURISYS_SCENARIO_PLAYBACK_LOW_LATENCY;
+ sample_rate = mStreamAttributeSource->sample_rate;
+ libKey = "MTKBESSOUND";
+ } else {
+ mAurisysScenario = AURISYS_SCENARIO_PLAYBACK_NORMAL;
+ sample_rate = mStreamAttributeSource->sample_rate;
+ libKey = "MTKBESSOUND";
+ }
+
+ ALOGD("%s, voip: %d, mAurisysScenario: %u", __FUNCTION__, IsVoIPEnable(), mAurisysScenario);
+
+ /* manager config */
+ AUDIO_ALLOC_STRUCT(struct aurisys_lib_manager_config_t, mManagerConfig);
+
+ mManagerConfig->aurisys_scenario = mAurisysScenario;
+ mManagerConfig->arsi_process_type = ARSI_PROCESS_TYPE_DL_ONLY;
+ mManagerConfig->audio_format = mStreamAttributeSource->audio_format;
+ mManagerConfig->sample_rate = mStreamAttributeSource->sample_rate;
+ mManagerConfig->frame_size_ms = 20; /* TODO */
+ mManagerConfig->num_channels_ul = 2;
+ mManagerConfig->num_channels_dl = mStreamAttributeSource->num_channels;
+ mManagerConfig->core_type = AURISYS_CORE_HAL;
+
+ /* task config */
+ InitArsiTaskConfig(mManagerConfig);
+
+ /* create manager */
+ AL_AUTOLOCK(mAurisysLibManagerLock);
+
+ mAurisysLibManager = create_aurisys_lib_manager(mManagerConfig);
+ InitBufferConfig(mAurisysLibManager);
+
+ aurisys_parsing_param_file(mAurisysLibManager);
+ aurisys_create_arsi_handlers(mAurisysLibManager); /* should init task/buf configs first */
+ aurisys_pool_buf_formatter_init(mAurisysLibManager); /* should init task/buf configs first */
+
+#if (defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT) && (MTK_AUDIO_TUNING_TOOL_V2_PHASE >= 2))
+ // Set custom scene information to all DL lib
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps && appOps->appHandleIsFeatureOptionEnabled(appOps->appHandleGetInstance(), "VIR_SCENE_CUSTOMIZATION_SUPPORT"))
+ {
+ /* Apply parameter for scene */
+ const char* scenarioStr = get_string_by_enum_aurisys_scenario(AURISYS_CORE_HAL, mAurisysScenario);
+ String8 key_value_pair = String8::format("HAL,%s,%s,KEY_VALUE,SetAudioCustomScene,%s=SET",
+ scenarioStr,
+ libKey,
+ mStreamAttributeSource->mCustScene);
+ aurisys_set_parameter(key_value_pair.string());
+
+ key_value_pair = String8::format("HAL,%s,%s,APPLY_PARAM,0=SET", scenarioStr, libKey);
+ aurisys_set_parameter(key_value_pair.string());
+ }
+#endif
+
+ //aurisys_set_dl_digital_gain(mAurisysLibManager, 0, 0);
+}
+
+
+/* TODO: move to aurisys framework?? add a new struct to keep hal arributes */
+void AudioALSAPlaybackHandlerBase::InitArsiTaskConfig(
+ struct aurisys_lib_manager_config_t *pManagerConfig) {
+ struct arsi_task_config_t *pTaskConfig = &pManagerConfig->task_config;
+
+ /* input device */ /* TODO: get voip ul attribute */
+ pTaskConfig->input_device_info.devices = mStreamAttributeSource->input_device; /* TODO */
+ pTaskConfig->input_device_info.audio_format = mStreamAttributeSource->audio_format;
+ pTaskConfig->input_device_info.sample_rate = mStreamAttributeSource->sample_rate; /* TODO */
+ pTaskConfig->input_device_info.channel_mask = mStreamAttributeSource->audio_channel_mask;
+ pTaskConfig->input_device_info.num_channels = mStreamAttributeSource->num_channels;
+ if (mStreamAttributeSource->output_devices == AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+ switch (AudioALSAHardwareResourceManager::getInstance()->getNumOfHeadsetPole()) {
+ case 4:
+ pTaskConfig->input_device_info.num_channels = 1;
+ break;
+ case 5:
+ pTaskConfig->input_device_info.num_channels = 2;
+ break;
+ default:
+ pTaskConfig->input_device_info.num_channels = 1;
+ ALOGE("%s(), can't found matched pole number, use 1 ch", __FUNCTION__);
+ break;
+ }
+ }
+ pTaskConfig->input_device_info.hw_info_mask = 0; /* TODO */
+
+ /* output device */
+ audio_devices_t output_devices = mStreamAttributeSource->output_devices;
+ if (isBtSpkDevice(output_devices)) {
+ // use SPK setting for BTSCO + SPK
+ output_devices = (audio_devices_t)(output_devices & (~AUDIO_DEVICE_OUT_ALL_SCO));
+ }
+
+ pTaskConfig->output_device_info.devices = mStreamAttributeSource->output_devices;
+ pTaskConfig->output_device_info.audio_format = mStreamAttributeSource->audio_format;
+ pTaskConfig->output_device_info.sample_rate = mStreamAttributeSource->sample_rate;
+ pTaskConfig->output_device_info.channel_mask = mStreamAttributeSource->audio_channel_mask;
+ pTaskConfig->output_device_info.num_channels = mStreamAttributeSource->num_channels;
+ if (AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ pTaskConfig->output_device_info.hw_info_mask = OUTPUT_DEVICE_HW_INFO_SMARTPA_SPEAKER; /* SMARTPA */
+ } else {
+ pTaskConfig->output_device_info.hw_info_mask = 0;
+ }
+
+ /* task scene */
+ pTaskConfig->task_scene = map_aurisys_scenario_to_task_scene(
+ pManagerConfig->core_type,
+ pManagerConfig->aurisys_scenario);
+
+ /* audio mode */
+ pTaskConfig->audio_mode = mStreamAttributeSource->audio_mode;
+
+ /* max device capability for allocating memory */
+ pTaskConfig->max_input_device_sample_rate = 48000; /* TODO */
+ pTaskConfig->max_output_device_sample_rate = 48000; /* TODO */
+
+ pTaskConfig->max_input_device_num_channels =
+ AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport();
+ pTaskConfig->max_output_device_num_channels = 2; /* TODO */
+
+ /* flag & source */
+ pTaskConfig->output_flags = mStreamAttributeSource->mAudioOutputFlags;
+ pTaskConfig->input_source = mStreamAttributeSource->input_source;
+ pTaskConfig->input_flags = 0;
+
+ /* Enhancement feature */
+ if (pTaskConfig->output_device_info.devices == AUDIO_DEVICE_OUT_EARPIECE &&
+ SpeechEnhancementController::GetInstance()->GetHACOn()) {
+ pTaskConfig->enhancement_feature_mask |= ENHANCEMENT_FEATURE_EARPIECE_HAC;
+ }
+
+ if ((pTaskConfig->input_device_info.devices & AUDIO_DEVICE_IN_ALL_SCO)
+ && (pTaskConfig->output_device_info.devices & AUDIO_DEVICE_OUT_ALL_SCO)
+ && SpeechEnhancementController::GetInstance()->GetBtHeadsetNrecOn()) {
+ pTaskConfig->enhancement_feature_mask |= ENHANCEMENT_FEATURE_BT_NREC;
+ }
+
+
+ dump_task_config(pTaskConfig);
+}
+
+
+void AudioALSAPlaybackHandlerBase::InitBufferConfig(struct aurisys_lib_manager_t *manager) {
+ /* DL in */
+ mAudioPoolBufDlIn = create_audio_pool_buf(manager, DATA_BUF_DOWNLINK_IN, 0);
+
+ mAudioPoolBufDlIn->buf->b_interleave = 1; /* LRLRLRLR*/
+ mAudioPoolBufDlIn->buf->frame_size_ms = 0;
+ mAudioPoolBufDlIn->buf->num_channels = mStreamAttributeSource->num_channels;
+ mAudioPoolBufDlIn->buf->sample_rate_buffer = mStreamAttributeSource->sample_rate;
+ mAudioPoolBufDlIn->buf->sample_rate_content = mStreamAttributeSource->sample_rate;
+ mAudioPoolBufDlIn->buf->audio_format = mStreamAttributeSource->audio_format;
+
+
+ /* DL out */
+ mAudioPoolBufDlOut = create_audio_pool_buf(manager, DATA_BUF_DOWNLINK_OUT, 0);
+
+ mAudioPoolBufDlOut->buf->b_interleave = 1; /* LRLRLRLR*/
+ mAudioPoolBufDlOut->buf->frame_size_ms = 0;
+ mAudioPoolBufDlOut->buf->num_channels = mStreamAttributeTarget.num_channels;
+ mAudioPoolBufDlOut->buf->sample_rate_buffer = mStreamAttributeTarget.sample_rate;
+ mAudioPoolBufDlOut->buf->sample_rate_content = mStreamAttributeTarget.sample_rate;
+ mAudioPoolBufDlOut->buf->audio_format = mStreamAttributeTarget.audio_format;
+}
+
+
+void AudioALSAPlaybackHandlerBase::DestroyAurisysLibManager() {
+ ALOGD("%s()", __FUNCTION__);
+
+ AL_AUTOLOCK(mAurisysLibManagerLock);
+
+ aurisys_destroy_arsi_handlers(mAurisysLibManager);
+ aurisys_pool_buf_formatter_deinit(mAurisysLibManager);
+ destroy_aurisys_lib_manager(mAurisysLibManager);
+ mAurisysLibManager = NULL;
+
+ /* NOTE: auto destroy audio_pool_buf when destroy_aurisys_lib_manager() */
+ mAudioPoolBufUlIn = NULL;
+ mAudioPoolBufUlOut = NULL;
+ mAudioPoolBufDlIn = NULL;
+ mAudioPoolBufDlOut = NULL;
+
+ mIsNeedUpdateLib = false;
+
+ AUDIO_FREE_POINTER(mLinearOut->p_buffer);
+ memset(mLinearOut, 0, sizeof(data_buf_t));
+
+ AUDIO_FREE_POINTER(mManagerConfig);
+}
+
+
+uint32_t AudioALSAPlaybackHandlerBase::GetTransferredBufferSize(uint32_t sourceBytes,
+ const stream_attribute_t *source,
+ const stream_attribute_t *target) {
+
+ uint32_t bytesPerSampleSource = (uint32_t)audio_bytes_per_sample(source->audio_format);
+ uint32_t bytesPerSampleTarget = (uint32_t)audio_bytes_per_sample(target->audio_format);
+
+ uint32_t bytesPerSecondSource = source->sample_rate * source->num_channels * bytesPerSampleSource;
+ uint32_t bytesPerSecondTarget = target->sample_rate * target->num_channels * bytesPerSampleTarget;
+
+ uint32_t unitTargetBytes = bytesPerSampleTarget * target->num_channels;
+ uint32_t targetBytes = 0;
+
+ if (bytesPerSecondSource == 0 || bytesPerSecondTarget == 0 || unitTargetBytes == 0) {
+ ALOGW("%s(), audio_format: 0x%x, 0x%x error!!", __FUNCTION__,
+ source->audio_format, target->audio_format);
+ return sourceBytes;
+ }
+
+ targetBytes = (uint32_t)((double)sourceBytes *
+ ((double)bytesPerSecondTarget /
+ (double)bytesPerSecondSource));
+ if ((targetBytes % unitTargetBytes) != 0) {
+ targetBytes = ((targetBytes / unitTargetBytes) + 1) * unitTargetBytes; // cell()
+ }
+
+ return targetBytes;
+}
+
+int AudioALSAPlaybackHandlerBase::getLatency() {
+
+#ifdef MTK_AUDIODSP_SUPPORT
+ int latency = 0;
+ const uint8_t size_per_channel = (mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_8_BIT ? 1 :
+ (mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_16_BIT ? 2 :
+ (mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_32_BIT ? 4 :
+ (mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_8_24_BIT ? 4 :
+ 2))));
+ const uint8_t size_per_frame = mStreamAttributeTarget.num_channels * size_per_channel;
+ latency = (mStreamAttributeTarget.buffer_size * 1000) / (mStreamAttributeTarget.sample_rate * size_per_frame);
+
+ if(mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+ mStreamAttributeTarget.dspLatency = AudioDspStreamManager::getInstance()->getA2dpPcmLatency() +
+ AudioALSAHardwareResourceManager::getInstance()->getA2dpLatency();
+ } else {
+ mStreamAttributeTarget.dspLatency = AudioDspStreamManager::getInstance()->getDlLatency();
+ }
+ latency += mStreamAttributeTarget.dspLatency;
+ return latency;
+#else
+ return -ENOSYS;
+#endif
+}
+
+
+#endif /* end if MTK_AURISYS_FRAMEWORK_SUPPORT */
+
+#ifdef MTK_AUDIODSP_SUPPORT
+void AudioALSAPlaybackHandlerBase::get_task_pcmdump_info(int task_id, int param, void **pcm_dump) {
+ *pcm_dump = pcmdump_array[task_id][param];
+
+ ALOGV("%s() %p %d %d\n", __FUNCTION__, *((FILE **)pcm_dump), task_id, param);
+}
+
+void AudioALSAPlaybackHandlerBase::set_task_pcmdump_info(int task_id, int param, void *pcm_dump) {
+ pcmdump_array[task_id][param] = (FILE *)pcm_dump;
+ ALOGV("%s() %p %d %d\n", __FUNCTION__, pcmdump_array[task_id][param], task_id, param);
+}
+
+void AudioALSAPlaybackHandlerBase::processDmaMsg(
+ struct ipi_msg_t *msg,
+ void *buf,
+ uint32_t size) {
+ FILE *pcm_dump = NULL;
+
+ ALOGV("%s() msg_id=0x%x, task_scene=%d, param2=0x%x, size=%d\n",
+ __FUNCTION__, msg->msg_id, msg->task_scene, msg->param2, size);
+
+ switch (msg->msg_id) {
+ case AUDIO_DSP_TASK_PCMDUMP_DATA:
+ get_task_pcmdump_info(msg->task_scene, msg->param2, (void **)&pcm_dump);
+ if (pcm_dump != NULL) {
+ AudioDumpPCMData(buf, size, pcm_dump);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void AudioALSAPlaybackHandlerBase::processDmaMsgWrapper(
+ struct ipi_msg_t *msg,
+ void *buf,
+ uint32_t size,
+ void *arg) {
+
+ AudioALSAPlaybackHandlerBase *pAudioALSAPlaybackHandlerBase =
+ static_cast<AudioALSAPlaybackHandlerBase *>(arg);
+
+ if (pAudioALSAPlaybackHandlerBase != NULL) {
+ pAudioALSAPlaybackHandlerBase->processDmaMsg(msg, buf, size);
+ }
+}
+#endif
+
+void AudioALSAPlaybackHandlerBase::updateSmootherTime(const uint64_t bufferTimeUs) {
+ if (mSmoother != NULL) {
+ updateWriteSmootherTime(mSmoother, bufferTimeUs);
+ }
+}
+
+status_t AudioALSAPlaybackHandlerBase::start() {
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerBase::stop() {
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerBase::createMmapBuffer(int32_t min_size_frames __unused,
+ struct audio_mmap_buffer_info *info __unused) {
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerBase::getMmapPosition(struct audio_mmap_position *position __unused) {
+ return NO_ERROR;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerDsp.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerDsp.cpp
new file mode 100644
index 0000000..382a763
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerDsp.cpp
@@ -0,0 +1,794 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAPlaybackHandlerDsp.h"
+#include "AudioALSAHardwareResourceManager.h"
+#include "AudioALSASampleRateController.h"
+#if defined(MTK_AUDIO_KS)
+#include "AudioALSADeviceConfigManager.h"
+#endif
+
+#include "AudioMTKFilter.h"
+#include "AudioVUnlockDL.h"
+#include "AudioALSADeviceParser.h"
+#include "AudioALSADriverUtility.h"
+#include "AudioALSAStreamManager.h"
+
+#include "AudioSmartPaController.h"
+
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+#include <aurisys_scenario_dsp.h>
+#include <arsi_type.h>
+#include <aurisys_config.h>
+#endif
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+#include "AudioDetectPulse.h"
+#endif
+
+#ifdef MTK_AUDIODSP_SUPPORT
+#include "AudioDspStreamManager.h"
+#include <audio_task.h>
+#endif
+
+#ifdef MTK_AUDIO_SCP_SUPPORT
+#include <AudioMessengerIPI.h>
+#endif
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSAPlaybackHandlerDsp"
+
+// Latency Detect
+//#define DEBUG_LATENCY
+#ifdef DEBUG_LATENCY
+#define THRESHOLD_FRAMEWORK 0.010
+#define THRESHOLD_HAL 0.010
+#define THRESHOLD_KERNEL 0.010
+#endif
+
+#ifndef KERNEL_BUFFER_SIZE_DL1_DATA2_NORMAL
+#define KERNEL_BUFFER_SIZE_DL1_DATA2_NORMAL KERNEL_BUFFER_SIZE_DL1_NORMAL
+#endif
+
+#ifndef KERNEL_BUFFER_SIZE_DL1_DATA2_HIFI_96K
+#define KERNEL_BUFFER_SIZE_DL1_DATA2_HIFI_96K KERNEL_BUFFER_SIZE_DL1_HIFI_96K
+#endif
+
+#ifndef KERNEL_BUFFER_SIZE_DL1_DATA2_HIFI_192K
+#define KERNEL_BUFFER_SIZE_DL1_DATA2_HIFI_192K KERNEL_BUFFER_SIZE_DL1_HIFI_192K
+#endif
+
+#define AUDIO_DSP_HW_MS_PERIOD (20)
+#define AUDIO_DSP_HW_PERIOD_COUNT (2)
+
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+static const char* PROPERTY_KEY_EXTDAC = "vendor.audiohal.resource.extdac.support";
+static const uint32_t kPcmDriverBufferSize = 0x20000; // 128k
+
+namespace android {
+
+AudioALSAPlaybackHandlerDsp::AudioALSAPlaybackHandlerDsp(const stream_attribute_t *stream_attribute_source) :
+ AudioALSAPlaybackHandlerBase(stream_attribute_source),
+ mDspHwPcm(NULL),
+ mForceMute(false),
+ mCurMuteBytes(0),
+ mStartMuteBytes(0),
+ mSupportNLE(false),
+ mTaskScene(TASK_SCENE_INVALID),
+ mAurisysDspConfig(NULL) {
+ mPlaybackHandlerType = isIsolatedDeepBuffer(mStreamAttributeSource->mAudioOutputFlags) ?
+ PLAYBACK_HANDLER_DEEP_BUFFER : (mStreamAttributeSource->mAudioOutputFlags & AUDIO_OUTPUT_FLAG_VOIP_RX) ?
+ PLAYBACK_HANDLER_VOIP : PLAYBACK_HANDLER_NORMAL;
+
+ ALOGD("%s() mPlaybackHandlerType = %d", __FUNCTION__, mPlaybackHandlerType);
+
+ if (mStreamAttributeSource->mAudioOutputFlags & AUDIO_OUTPUT_FLAG_FAST) {
+ mPlaybackHandlerType = PLAYBACK_HANDLER_FAST;
+ }
+
+ memset((void *)&mNewtime, 0, sizeof(mNewtime));
+ memset((void *)&mOldtime, 0, sizeof(mOldtime));
+ memset(&mDsphwConfig, 0, sizeof(mDsphwConfig));
+
+ if (!(platformIsolatedDeepBuffer()) ||
+ (platformIsolatedDeepBuffer() &&
+ mStreamAttributeSource->mAudioOutputFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) {
+ mSupportNLE = true;
+ } else {
+ mSupportNLE = false;
+ }
+
+ mPCMDumpFileDSP = NULL;
+ mDspStreamManager = AudioDspStreamManager::getInstance();
+ ASSERT(mDspStreamManager != NULL);
+}
+
+AudioALSAPlaybackHandlerDsp::~AudioALSAPlaybackHandlerDsp() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+uint32_t AudioALSAPlaybackHandlerDsp::getLowJitterModeSampleRate() {
+ return 48000;
+}
+
+int AudioALSAPlaybackHandlerDsp::setAfeDspShareMem(unsigned int flag, bool condition) {
+ mDspStreamManager->setAfeOutDspShareMem(flag, condition);
+ return 0;
+}
+
+int AudioALSAPlaybackHandlerDsp::setStreamState(unsigned int flag, bool condition) {
+ mDspStreamManager->setStreamOutState(flag, condition);
+ return 0;
+}
+
+int AudioALSAPlaybackHandlerDsp::setDspRuntimeEn(bool condition) {
+ if (isIsolatedDeepBuffer(mStreamAttributeSource->mAudioOutputFlags)) {
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "dsp_deepbuf_runtime_en"), 0, condition)) {
+ ALOGW("%s(), enable fail", __FUNCTION__);
+ return -1;
+ }
+ } else if (mStreamAttributeSource->mAudioOutputFlags & AUDIO_OUTPUT_FLAG_VOIP_RX) {
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "dsp_voipdl_runtime_en"), 0, condition)) {
+ ALOGW("%s(), enable fail", __FUNCTION__);
+ return -1;
+ }
+ } else {
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "dsp_primary_runtime_en"), 0, condition)) {
+ ALOGW("%s(), enable fail", __FUNCTION__);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+bool AudioALSAPlaybackHandlerDsp::deviceSupportHifi(audio_devices_t outputdevice) {
+ // modify this to let output device support hifi audio
+ if (outputdevice == AUDIO_DEVICE_OUT_WIRED_HEADSET || outputdevice == AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+ return true;
+ } else if (outputdevice & AUDIO_DEVICE_OUT_SPEAKER) {
+ if (AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ return AudioSmartPaController::getInstance()->getMaxSupportedRate() > 48000;
+ } else {
+ return true;
+ }
+ }
+ return false;
+}
+
+uint32_t AudioALSAPlaybackHandlerDsp::chooseTargetSampleRate(uint32_t SampleRate, audio_devices_t outputdevice) {
+ ALOGV("chooseTargetSampleRate SampleRate = %d outputdevice = %d", SampleRate, outputdevice);
+ uint32_t TargetSampleRate = 48000;
+ if (SampleRate <= 192000 && SampleRate > 96000 && deviceSupportHifi(outputdevice)) {
+ TargetSampleRate = 192000;
+ } else if (SampleRate <= 96000 && SampleRate > 48000 && deviceSupportHifi(outputdevice)) {
+ TargetSampleRate = 96000;
+ } else if (SampleRate <= 48000 && SampleRate >= 32000) {
+ TargetSampleRate = SampleRate;
+ }
+ return TargetSampleRate;
+}
+
+status_t AudioALSAPlaybackHandlerDsp::openDspHwPcm() {
+ int pcmindex = -1, cardindex = 0, ret = 0;
+ unsigned int pcmmaxsize, pcmconfigsize;
+ struct pcm_params *params = NULL;
+
+ ALOGV("+%s(),", __FUNCTION__);
+
+#if defined(MTK_AUDIO_KS)
+ if (isIsolatedDeepBuffer(mStreamAttributeSource->mAudioOutputFlags)) {
+ pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmPlayback3);
+ if (pcmindex < 0) {
+ // use playback 2 if this platform does not have playback 3
+ pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmPlayback2);
+ cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmPlayback2);
+ if (AudioDspStreamManager::getInstance()->getDspPlaybackEnable() == true) {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK2_TO_CAPTURE6;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK2_TO_DSP;
+ if (popcount(mStreamAttributeSource->output_devices) > 1) {
+ mApTurnOnSequence2 = AUDIO_CTL_PLAYBACK2_TO_ADDA_DL;
+ }
+ } else {
+ if ((mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER) &&
+ AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(AUDIO_CTL_PLAYBACK2_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+ if (popcount(mStreamAttributeSource->output_devices) > 1) {
+ mApTurnOnSequence2 = AUDIO_CTL_PLAYBACK2_TO_ADDA_DL;
+ }
+ } else {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK2_TO_ADDA_DL;
+ }
+
+ if ((AudioDspStreamManager::getInstance()->getDspA2DPEnable() == true) &&
+ (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+ mApTurnOnSequence3 = AUDIO_CTL_PLAYBACK2_TO_CAPTURE6;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK2_TO_DSP;
+ }
+ }
+ } else {
+ cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmPlayback3);
+ if (AudioDspStreamManager::getInstance()->getDspPlaybackEnable() == true) {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK3_TO_CAPTURE6;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK3_TO_DSP;
+ if (popcount(mStreamAttributeSource->output_devices) > 1) {
+ mApTurnOnSequence2 = AUDIO_CTL_PLAYBACK3_TO_ADDA_DL;
+ }
+ } else {
+ if ((mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER) &&
+ AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(AUDIO_CTL_PLAYBACK3_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+ if (popcount(mStreamAttributeSource->output_devices) > 1) {
+ mApTurnOnSequence2 = AUDIO_CTL_PLAYBACK3_TO_ADDA_DL;
+ }
+ } else {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK3_TO_ADDA_DL;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK3_TO_DSP;
+ }
+
+ if ((AudioDspStreamManager::getInstance()->getDspA2DPEnable() == true) &&
+ (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+ mApTurnOnSequence3 = AUDIO_CTL_PLAYBACK3_TO_CAPTURE6;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK3_TO_DSP;
+ }
+ }
+ }
+
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "deep_buffer_scenario"), 0, 1)) {
+ ALOGW("%s(), deep_buffer_scenario enable fail", __FUNCTION__);
+ }
+ } else if (mStreamAttributeSource->mAudioOutputFlags & AUDIO_OUTPUT_FLAG_VOIP_RX) {
+ // voip dl using DL12 , if not support using DL3
+ pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmPlayback12);
+ if(pcmindex < 0) {
+ pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmPlayback3);
+ cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmPlayback3);
+ if (AudioSmartPaController::getInstance()->isSmartPAUsed() &&
+ (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER)) {
+ if(AudioDspStreamManager::getInstance()->getDspPlaybackEnable() == true) {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK3_TO_CAPTURE6;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK3_TO_DSP;
+ } else {
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(AUDIO_CTL_PLAYBACK3_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+ if (popcount(mStreamAttributeSource->output_devices) > 1) {
+ mApTurnOnSequence2 = AUDIO_CTL_PLAYBACK3_TO_ADDA_DL;
+ }
+ }
+ } else {
+ if(AudioDspStreamManager::getInstance()->getDspPlaybackEnable() == true &&
+ (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER)) {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK3_TO_CAPTURE6;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK3_TO_DSP;
+ } else {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK3_TO_ADDA_DL;
+ }
+ }
+ } else {
+ cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmPlayback12);
+ if (AudioSmartPaController::getInstance()->isSmartPAUsed() &&
+ (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER)) {
+ if(AudioDspStreamManager::getInstance()->getDspPlaybackEnable() == true) {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK12_TO_CAPTURE6;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK12_TO_DSP;
+ } else {
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(AUDIO_CTL_PLAYBACK12_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK12_TO_DSP;
+ if (popcount(mStreamAttributeSource->output_devices) > 1) {
+ mApTurnOnSequence2 = AUDIO_CTL_PLAYBACK12_TO_ADDA_DL;
+ }
+ }
+ } else {
+ if(AudioDspStreamManager::getInstance()->getDspPlaybackEnable() == true &&
+ (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER)) {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK12_TO_CAPTURE6;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK12_TO_DSP;
+ } else {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK12_TO_ADDA_DL;
+ }
+ }
+ }
+ } else {
+ pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmPlayback1);
+ cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmPlayback1);
+ if (AudioDspStreamManager::getInstance()->getDspPlaybackEnable() == true) {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK1_TO_CAPTURE6;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK1_TO_DSP;
+ if (popcount(mStreamAttributeSource->output_devices) > 1) {
+ mApTurnOnSequence2 = AUDIO_CTL_PLAYBACK1_TO_ADDA_DL;
+ }
+ } else {
+ if ((mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER) &&
+ AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(AUDIO_CTL_PLAYBACK1_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+ if (popcount(mStreamAttributeSource->output_devices) > 1) {
+ mApTurnOnSequence2 = AUDIO_CTL_PLAYBACK1_TO_ADDA_DL;
+ }
+ } else {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK1_TO_ADDA_DL;
+ }
+
+ if ((AudioDspStreamManager::getInstance()->getDspA2DPEnable() == true) &&
+ (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+ mApTurnOnSequence3 = AUDIO_CTL_PLAYBACK1_TO_CAPTURE6;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK1_TO_DSP;
+ }
+ }
+ }
+
+ if (!mApTurnOnSequence.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+ }
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence2);
+ }
+ if (!mApTurnOnSequenceDsp.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequenceDsp);
+ }
+ if (!mApTurnOnSequence3.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence3);
+ }
+#else
+ String8 pcmPath = isIsolatedDeepBuffer(mStreamAttributeSource->mAudioOutputFlags) ?
+ keypcmDL1DATA2PLayback : keypcmI2S0Dl1Playback;
+
+ pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(pcmPath);
+ cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(pcmPath);
+#endif
+
+ ALOGD("%s(), pcmindex = %d cardindex = %d ", __FUNCTION__, pcmindex, cardindex);
+
+ /* allocate the same with dsp platform drver */
+ mDsphwConfig.period_size = mConfig.period_size;
+ mDsphwConfig.period_count = mConfig.period_count;
+ mDsphwConfig.channels = mStreamAttributeTarget.num_channels;
+ mDsphwConfig.rate = mStreamAttributeTarget.sample_rate;
+ mDsphwConfig.format = transferAudioFormatToPcmFormat(mStreamAttributeTarget.audio_format);
+
+ pcmconfigsize = mDsphwConfig.period_count * mDsphwConfig.period_size * mDsphwConfig.channels * (pcm_format_to_bits(mDsphwConfig.format) / 8);
+
+ ALOGD("%s(), mDsphwConfig: channels = %d, rate = %d, period_size = %d, period_count = %d, format = %d",
+ __FUNCTION__, mDsphwConfig.channels, mDsphwConfig.rate, mDsphwConfig.period_size, mDsphwConfig.period_count, mDsphwConfig.format);
+
+ mDsphwConfig.start_threshold = (mDsphwConfig.period_count * mDsphwConfig.period_size);
+ if (mStreamAttributeSource->mAudioInputFlags & AUDIO_OUTPUT_FLAG_VOIP_RX) {
+ mDsphwConfig.start_threshold = ((mDsphwConfig.period_count - 1) * mDsphwConfig.period_size);
+ }
+ mDsphwConfig.stop_threshold = ~(0U);
+ mDsphwConfig.silence_threshold = 0;
+
+ opeDspPcmDriver(pcmindex);
+ if (pcm_start(mDspHwPcm) != 0) {
+ ALOGE("%s(), pcm_start(%p) == false due to %s", __FUNCTION__, mDspHwPcm, pcm_get_error(mDspHwPcm));
+ }
+ ALOGV("-%s(),", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerDsp::open() {
+ ALOGV("+%s(), flag %d, mDevice = 0x%x", __FUNCTION__, mStreamAttributeSource->mAudioOutputFlags,
+ mStreamAttributeSource->output_devices);
+
+ struct pcm_params *params = NULL;
+ int dspPcmIndex, dspCardIndex = 0;
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ uint32_t aurisys_scenario = 0xFFFFFFFF;
+ uint8_t arsi_process_type = ARSI_PROCESS_TYPE_DL_ONLY;
+#endif
+ unsigned int feature_id = getDspFeatureID(mStreamAttributeSource->mAudioOutputFlags);
+
+ setAfeDspShareMem(mStreamAttributeSource->mAudioOutputFlags, true);
+ setDspRuntimeEn(true);
+ mAudioMessengerIPI->registerAdspFeature(feature_id);
+ setStreamState(mStreamAttributeSource->mAudioOutputFlags, true);
+
+ if (isIsolatedDeepBuffer(mStreamAttributeSource->mAudioOutputFlags)) {
+ mTaskScene = TASK_SCENE_DEEPBUFFER;
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ aurisys_scenario = AURISYS_SCENARIO_DSP_DEEP_BUF;
+#endif
+ } else if (mStreamAttributeSource->mAudioOutputFlags & AUDIO_OUTPUT_FLAG_VOIP_RX) {
+ mTaskScene = TASK_SCENE_VOIP;
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ aurisys_scenario = AURISYS_SCENARIO_DSP_VOIP;
+ arsi_process_type = ARSI_PROCESS_TYPE_DL_ONLY; //ARSI_PROCESS_TYPE_UL_AND_DL;
+#endif
+ } else {
+ mTaskScene = TASK_SCENE_PRIMARY;
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ aurisys_scenario = AURISYS_SCENARIO_DSP_PRIMARY;
+#endif
+ }
+ mAudioMessengerIPI->registerDmaCbk(
+ mTaskScene,
+ 0x10000,
+ 0x48000,
+ processDmaMsgWrapper,
+ this);
+
+
+ // debug pcm dump
+ OpenPCMDump(LOG_TAG);
+
+ if (isIsolatedDeepBuffer(mStreamAttributeSource->mAudioOutputFlags)) {
+ dspPcmIndex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmPlaybackDspDeepbuf);
+ dspCardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmPlaybackDspDeepbuf);
+ ALOGD("%s(), dspPcmIndex = %d dspCardIndex = %d deep buffer",
+ __FUNCTION__, dspPcmIndex, dspCardIndex);
+ } else if (mStreamAttributeSource->mAudioOutputFlags & AUDIO_OUTPUT_FLAG_VOIP_RX) {
+ dspPcmIndex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmPlaybackDspVoip);
+ dspCardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmPlaybackDspVoip);
+ ALOGD("%s(), dspPcmIndex = %d dspCardIndex = %d voip dl",
+ __FUNCTION__, dspPcmIndex, dspCardIndex);
+
+ } else {
+ dspPcmIndex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmPlaybackDspprimary);
+ dspCardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmPlaybackDspprimary);
+ ALOGD("%s(), dspPcmIndex = %d dspCardIndex = %d",
+ __FUNCTION__, dspPcmIndex, dspCardIndex);
+ }
+
+ // HW attribute config
+#ifdef PLAYBACK_USE_24BITS_ONLY
+ mStreamAttributeTarget.audio_format = AUDIO_FORMAT_PCM_8_24_BIT;
+#else
+ mStreamAttributeTarget.audio_format = (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_32_BIT) ? AUDIO_FORMAT_PCM_8_24_BIT : AUDIO_FORMAT_PCM_16_BIT;
+#endif
+
+ mStreamAttributeTarget.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ mStreamAttributeTarget.num_channels = popcount(mStreamAttributeTarget.audio_channel_mask);
+
+ mStreamAttributeTarget.sample_rate = chooseTargetSampleRate(AudioALSASampleRateController::getInstance()->getPrimaryStreamOutSampleRate(),
+ mStreamAttributeSource->output_devices);
+
+ mStreamAttributeTarget.output_devices = mStreamAttributeSource->output_devices;
+ mStreamAttributeTarget.mAudioOutputFlags = mStreamAttributeSource->mAudioOutputFlags;
+
+#ifdef HIFI_DEEP_BUFFER
+ if (mStreamAttributeTarget.sample_rate <= 48000) {
+ mStreamAttributeTarget.buffer_size = isIsolatedDeepBuffer(mStreamAttributeSource->mAudioOutputFlags) ?
+ KERNEL_BUFFER_SIZE_DL1_DATA2_NORMAL :
+ KERNEL_BUFFER_SIZE_DL1_NORMAL;
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+#ifdef PLAYBACK_USE_24BITS_ONLY
+#define KERNEL_BUFFER_SIZE_WITH_DRE (40 * 1024) /* 40KB for 32bit hal */
+#else
+#define KERNEL_BUFFER_SIZE_WITH_DRE (20 * 1024) /* 20KB for 16bit hal */
+#endif
+ if (mSupportNLE && (mStreamAttributeTarget.buffer_size < KERNEL_BUFFER_SIZE_WITH_DRE)) {
+ mStreamAttributeTarget.buffer_size = KERNEL_BUFFER_SIZE_WITH_DRE;
+ }
+#endif
+ } else if (mStreamAttributeTarget.sample_rate > 48000 && mStreamAttributeTarget.sample_rate <= 96000) {
+ uint32_t hifi_buffer_size = isIsolatedDeepBuffer(mStreamAttributeSource->mAudioOutputFlags) ?
+ KERNEL_BUFFER_SIZE_DL1_DATA2_HIFI_96K :
+ KERNEL_BUFFER_SIZE_DL1_HIFI_96K;
+
+ if (mStreamAttributeTarget.buffer_size >= hifi_buffer_size) {
+ mStreamAttributeTarget.buffer_size = hifi_buffer_size;
+ }
+ } else {
+ uint32_t hifi_buffer_size = isIsolatedDeepBuffer(mStreamAttributeSource->mAudioOutputFlags) ?
+ KERNEL_BUFFER_SIZE_DL1_DATA2_HIFI_192K :
+ KERNEL_BUFFER_SIZE_DL1_HIFI_192K;
+
+ if (mStreamAttributeTarget.buffer_size >= hifi_buffer_size) {
+ mStreamAttributeTarget.buffer_size = hifi_buffer_size;
+ }
+ }
+#endif /* end of #ifdef HIFI_DEEP_BUFFER */
+
+ //Change hwbuffer size in Comminuication
+ if (!(platformIsolatedDeepBuffer()) &&
+ mStreamAttributeSource->audio_mode == AUDIO_MODE_IN_COMMUNICATION) {
+ mStreamAttributeTarget.buffer_size = 2 * mStreamAttributeSource->buffer_size /
+ ((mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4) *
+ ((mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4);
+ }
+
+ // HW pcm config
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = mStreamAttributeSource->num_channels;
+ mConfig.rate = mStreamAttributeSource->sample_rate;
+
+ if (isIsolatedDeepBuffer(mStreamAttributeSource->mAudioOutputFlags)) {
+ mConfig.period_count = 2;
+ mConfig.period_size = (mStreamAttributeTarget.buffer_size / (mConfig.channels * mConfig.period_count)) / ((mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4);
+ } else {
+ mConfig.period_count = 4;
+ mConfig.period_size = (mStreamAttributeTarget.buffer_size / (mConfig.channels * mConfig.period_count)) / ((mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4);
+ }
+ mConfig.format = transferAudioFormatToPcmFormat(mStreamAttributeSource->audio_format);
+
+ mConfig.start_threshold = (mConfig.period_count * mConfig.period_size);
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+ ALOGD("%s(), mConfig: channels = %d, rate = %d, period_size = %d, period_count = %d, format = %d avail_min = %d",
+ __FUNCTION__, mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mConfig.format, mConfig.avail_min);
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ mDspStreamManager->CreateAurisysLibManager(
+ &mAurisysLibManager,
+ &mAurisysDspConfig,
+ mTaskScene,
+ aurisys_scenario,
+ arsi_process_type,
+ mStreamAttributeSource->audio_mode,
+ mStreamAttributeSource,
+ &mStreamAttributeTarget,
+ NULL,
+ NULL);
+#endif
+
+ // open pcm driver
+ openPcmDriver(dspPcmIndex);
+
+ openDspHwPcm();
+
+#ifdef MTK_AUDIODSP_SUPPORT
+ mDspStreamManager->addPlaybackHandler(this);
+ OpenPCMDumpDSP(LOG_TAG);
+#endif
+
+#if defined(MTK_HYBRID_NLE_SUPPORT) // must be after pcm open
+ mStreamAttributeTarget.output_devices = mStreamAttributeSource->output_devices;
+ initNLEProcessing();
+#endif
+
+ // open codec driver
+ mHardwareResourceManager->startOutputDevice(mStreamAttributeSource->output_devices, mStreamAttributeTarget.sample_rate);
+
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ VUnlockhdl->SetInputStandBy(false);
+ VUnlockhdl-> GetSRCInputParameter(mStreamAttributeTarget.sample_rate, mStreamAttributeTarget.num_channels, mStreamAttributeTarget.audio_format);
+ VUnlockhdl->GetFirstDLTime();
+ }
+
+ //===========================================
+
+ mTimeStampValid = false;
+ mBytesWriteKernel = 0;
+ ALOGV("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerDsp::close() {
+ ALOGD("+%s(), flag %d, mDevice = 0x%x", __FUNCTION__, mStreamAttributeSource->mAudioOutputFlags,
+ mStreamAttributeSource->output_devices);
+ unsigned int feature_id = getDspFeatureID(mStreamAttributeSource->mAudioOutputFlags);
+
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ VUnlockhdl->SetInputStandBy(true);
+ }
+ //===========================================
+
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+ // Must do this before close analog path
+ deinitNLEProcessing();
+#endif
+
+ // close codec driver
+ mHardwareResourceManager->stopOutputDevice();
+
+#ifdef MTK_AUDIODSP_SUPPORT
+ mDspStreamManager->removePlaybackHandler(this);
+#endif
+
+ // close pcm driver
+ closeDspPcmDriver();
+ closePcmDriver();
+
+ setAfeDspShareMem(mStreamAttributeSource->mAudioOutputFlags, false);
+ setDspRuntimeEn(false);
+ setStreamState(mStreamAttributeSource->mAudioOutputFlags, false);
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ mDspStreamManager->DestroyAurisysLibManager(
+ &mAurisysLibManager, &mAurisysDspConfig, mTaskScene);
+#endif
+ mAudioMessengerIPI->deregisterDmaCbk(mTaskScene);
+ mAudioMessengerIPI->deregisterAdspFeature(feature_id);
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequenceDsp);
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence2);
+ mApTurnOnSequence2.clear();
+ }
+ if (!mApTurnOnSequence3.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence3);
+ mApTurnOnSequence3.clear();
+ }
+
+ if (isIsolatedDeepBuffer(mStreamAttributeSource->mAudioOutputFlags)) {
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "deep_buffer_scenario"), 0, 0)) {
+ ALOGW("%s(), deep_buffer_scenario disable fail", __FUNCTION__);
+ }
+ }
+#endif
+
+ // debug pcm dump
+ ClosePCMDump();
+#ifdef MTK_AUDIODSP_SUPPORT
+ ClosePCMDumpDSP();
+#endif
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerDsp::openDspPcmDriverWithFlag(const unsigned int device, unsigned int flag) {
+ ALOGD("+%s(), mDspHwPcm device = %d, flag = 0x%x", __FUNCTION__, device, flag);
+
+ ASSERT(mDspHwPcm == NULL);
+ mDspHwPcm = pcm_open(AudioALSADeviceParser::getInstance()->GetCardIndex(),
+ device, flag, &mDsphwConfig);
+ if (mDspHwPcm == NULL) {
+ ALOGE("%s(), mDspHwPcm == NULL!!", __FUNCTION__);
+ } else if (pcm_is_ready(mDspHwPcm) == false) {
+ ALOGE("%s(), pcm_is_ready(%p) == false due to %s, close pcm.", __FUNCTION__, mDspHwPcm, pcm_get_error(mDspHwPcm));
+ pcm_close(mDspHwPcm);
+ mDspHwPcm = NULL;
+ } else if (pcm_prepare(mDspHwPcm) != 0) {
+ ALOGE("%s(), pcm_prepare(%p) == false due to %s, close pcm.", __FUNCTION__, mDspHwPcm, pcm_get_error(mDspHwPcm));
+ pcm_close(mDspHwPcm);
+ mDspHwPcm = NULL;
+ }
+
+ ASSERT(mDspHwPcm != NULL);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerDsp::opeDspPcmDriver(const unsigned int device) {
+ return openDspPcmDriverWithFlag(device, PCM_OUT | PCM_MONOTONIC);
+}
+
+status_t AudioALSAPlaybackHandlerDsp::closeDspPcmDriver() {
+
+ if (mDspHwPcm != NULL) {
+ pcm_stop(mDspHwPcm);
+ pcm_close(mDspHwPcm);
+ mDspHwPcm = NULL;
+ }
+
+ ALOGV("-%s(), mDspHwPcm = %p", __FUNCTION__, mDspHwPcm);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerDsp::routing(const audio_devices_t output_devices) {
+ mHardwareResourceManager->changeOutputDevice(output_devices);
+#if !defined(MTK_AURISYS_FRAMEWORK_SUPPORT)
+ if (mAudioFilterManagerHandler) { mAudioFilterManagerHandler->setDevice(output_devices); }
+#endif
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerDsp::setScreenState(bool mode, size_t buffer_size, size_t reduceInterruptSize, bool bforce __unused) {
+ // don't increase irq period when play hifi
+ if (mode == 0 && mStreamAttributeSource->sample_rate > 48000) {
+ return NO_ERROR;
+ }
+
+ ALOGD("%s, flag %d, %f, mode = %d , buffer_size = %zu, channel %d, format%d reduceInterruptSize = %zu",
+ __FUNCTION__, mStreamAttributeSource->mAudioOutputFlags,
+ mStreamAttributeTarget.mInterrupt, mode, buffer_size, mConfig.channels,
+ mStreamAttributeTarget.audio_format, reduceInterruptSize);
+
+ return NO_ERROR;
+}
+
+ssize_t AudioALSAPlaybackHandlerDsp::write(const void *buffer, size_t bytes) {
+ ALOGV("%s(), buffer = %p, bytes = %zu", __FUNCTION__, buffer, bytes);
+
+ if (mPcm == NULL) {
+ ALOGE("%s(), mPcm == NULL, return", __FUNCTION__);
+ return bytes;
+ }
+
+
+ // const -> to non const
+ void *pBuffer = const_cast<void *>(buffer);
+ ASSERT(pBuffer != NULL);
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[0] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+ // stereo to mono for speaker
+ doStereoToMonoConversionIfNeed(pBuffer, bytes);
+
+ // pcm dump
+ WritePcmDumpData(pBuffer, bytes);
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[1] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+ AudioDetectPulse::doDetectPulse(TAG_PLAYERBACK_HANDLER, PULSE_LEVEL, 0, (void *)pBuffer,
+ bytes, mStreamAttributeTarget.audio_format,
+ mStreamAttributeTarget.num_channels, mStreamAttributeTarget.sample_rate);
+#endif
+
+ // write data to pcm driver
+ int retval = pcm_write(mPcm, pBuffer, bytes);
+
+ mBytesWriteKernel = mBytesWriteKernel + bytes;
+ if (mTimeStampValid == false) {
+ if (mBytesWriteKernel >= (mStreamAttributeTarget.buffer_size >> 1)) {
+ mTimeStampValid = true;
+ }
+ }
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+ if (mSupportNLE) {
+ doNLEProcessing(pBuffer, bytes);
+ }
+#endif
+
+ updateHardwareBufferInfo(bytes, bytes);
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[2] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+
+#if 1 // TODO(Harvey, Wendy), temporary disable Voice Unlock until 24bit ready
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ // get remain time
+ //VUnlockhdl->SetDownlinkStartTime(ret_ms);
+ VUnlockhdl->GetFirstDLTime();
+
+ //VUnlockhdl->SetInputStandBy(false);
+ if (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+ mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+ memset((void *)pBuffer, 0, bytes);
+ }
+ VUnlockhdl->WriteStreamOutToRing(pBuffer, bytes);
+ }
+ //===========================================
+#endif
+
+
+ if (retval != 0) {
+ ALOGE("%s(), pcm_write() error, retval = %d", __FUNCTION__, retval);
+ }
+
+#ifdef DEBUG_LATENCY
+ if (latencyTime[0] > THRESHOLD_FRAMEWORK || latencyTime[1] > THRESHOLD_HAL || latencyTime[2] > (mStreamAttributeTarget.mInterrupt - latencyTime[0] - latencyTime[1] + THRESHOLD_KERNEL)) {
+ ALOGD("latency_in_s,%1.3lf,%1.3lf,%1.3lf, interrupt,%1.3lf,byte:%u", latencyTime[0], latencyTime[1], latencyTime[2], mStreamAttributeTarget.mInterrupt, bytesAfterpending);
+ }
+#endif
+
+ return bytes;
+}
+
+status_t AudioALSAPlaybackHandlerDsp::setFilterMng(AudioMTKFilterManager *pFilterMng) {
+#if !defined(MTK_AURISYS_FRAMEWORK_SUPPORT)
+ ALOGD("+%s() mAudioFilterManagerHandler [%p]", __FUNCTION__, pFilterMng);
+ mAudioFilterManagerHandler = pFilterMng;
+#else
+ (void *)pFilterMng;
+#endif
+ return NO_ERROR;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerFMTransmitter.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerFMTransmitter.cpp
new file mode 100644
index 0000000..3ec51a0
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerFMTransmitter.cpp
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAPlaybackHandlerFMTransmitter.h"
+
+#include "WCNChipController.h"
+
+#include "AudioALSADeviceParser.h"
+#include "AudioALSADriverUtility.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSAPlaybackHandlerFMTransmitter"
+
+namespace android {
+
+AudioALSAPlaybackHandlerFMTransmitter::AudioALSAPlaybackHandlerFMTransmitter(const stream_attribute_t *stream_attribute_source) :
+ AudioALSAPlaybackHandlerBase(stream_attribute_source),
+ mWCNChipController(WCNChipController::GetInstance()) {
+ ALOGD("%s()", __FUNCTION__);
+ mPlaybackHandlerType = PLAYBACK_HANDLER_FM_TX;
+}
+
+
+AudioALSAPlaybackHandlerFMTransmitter::~AudioALSAPlaybackHandlerFMTransmitter() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSAPlaybackHandlerFMTransmitter::open() {
+ ALOGD("+%s(), mDevice = 0x%x", __FUNCTION__, mStreamAttributeSource->output_devices);
+
+ // debug pcm dump
+ OpenPCMDump(LOG_TAG);
+
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmMRGTxPlayback);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmMRGTxPlayback);
+ ALOGD("AudioALSAPlaybackHandlerFMTransmitter::open() pcmindex = %d", pcmindex);
+ ListPcmDriver(cardindex, pcmindex);
+
+ struct pcm_params *params;
+ params = pcm_params_get(cardindex, pcmindex, PCM_OUT);
+ if (params == NULL) {
+ ALOGD("AudioALSAPlaybackHandlerFMTransmitter Device does not exist.\n");
+ }
+ mStreamAttributeTarget.buffer_size = pcm_params_get_max(params, PCM_PARAM_BUFFER_BYTES);
+ ALOGD("AudioALSAPlaybackHandlerFMTransmitter buffersizemax = %d", mStreamAttributeTarget.buffer_size);
+ pcm_params_free(params);
+
+ // HW attribute config // TODO(Harvey): query this
+#ifdef PLAYBACK_USE_24BITS_ONLY
+ mStreamAttributeTarget.audio_format = AUDIO_FORMAT_PCM_8_24_BIT;
+#else
+ mStreamAttributeTarget.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+#endif
+ mStreamAttributeTarget.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ mStreamAttributeTarget.num_channels = popcount(mStreamAttributeTarget.audio_channel_mask);
+ mStreamAttributeTarget.sample_rate = 44100; // TODO(Harvey, Chipeng): query?
+
+
+ // HW pcm config
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = mStreamAttributeTarget.num_channels;
+ mConfig.rate = mStreamAttributeTarget.sample_rate;
+
+ // Buffer size
+ mConfig.period_count = 2;
+ mConfig.period_size = (mStreamAttributeTarget.buffer_size / (mConfig.channels * mConfig.period_count)) / ((mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4);
+
+ mConfig.format = transferAudioFormatToPcmFormat(mStreamAttributeTarget.audio_format);
+
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+ ALOGD("%s(), mConfig: channels = %d, rate = %d, period_size = %d, period_count = %d, format = %d",
+ __FUNCTION__, mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mConfig.format);
+
+
+ // SRC
+ initBliSrc();
+
+
+ // bit conversion
+ initBitConverter();
+
+
+ // Get pcm open Info
+
+ // open pcm driver
+ openPcmDriver(pcmindex);
+
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerFMTransmitter::close() {
+ ALOGD("+%s()", __FUNCTION__);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ // close pcm driver
+ closePcmDriver();
+
+
+ // bit conversion
+ deinitBitConverter();
+
+
+ // SRC
+ deinitBliSrc();
+
+
+ // debug pcm dump
+ ClosePCMDump();
+
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerFMTransmitter::routing(const audio_devices_t output_devices __unused) {
+ return INVALID_OPERATION;
+}
+
+ssize_t AudioALSAPlaybackHandlerFMTransmitter::write(const void *buffer, size_t bytes) {
+ ALOGV("%s(), buffer = %p, bytes = %zu", __FUNCTION__, buffer, bytes);
+
+ if (mPcm == NULL) {
+ ALOGE("%s(), mPcm == NULL, return", __FUNCTION__);
+ return bytes;
+ }
+
+ // const -> to non const
+ void *pBuffer = const_cast<void *>(buffer);
+ ASSERT(pBuffer != NULL);
+
+
+ // SRC
+ void *pBufferAfterBliSrc = NULL;
+ uint32_t bytesAfterBliSrc = 0;
+ doBliSrc(pBuffer, bytes, &pBufferAfterBliSrc, &bytesAfterBliSrc);
+
+
+ // bit conversion
+ void *pBufferAfterBitConvertion = NULL;
+ uint32_t bytesAfterBitConvertion = 0;
+ doBitConversion(pBufferAfterBliSrc, bytesAfterBliSrc, &pBufferAfterBitConvertion, &bytesAfterBitConvertion);
+
+
+ // write data to pcm driver
+ WritePcmDumpData(pBufferAfterBitConvertion, bytesAfterBitConvertion);
+ int retval = pcm_write(mPcm, pBufferAfterBitConvertion, bytesAfterBitConvertion);
+
+
+ if (retval != 0) {
+ ALOGE("%s(), pcm_write() error, retval = %d", __FUNCTION__, retval);
+ }
+
+ return bytes;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerFast.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerFast.cpp
new file mode 100644
index 0000000..69002fb
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerFast.cpp
@@ -0,0 +1,599 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAPlaybackHandlerFast.h"
+
+#include "AudioALSAHardwareResourceManager.h"
+//#include "AudioALSAVolumeController.h"
+//#include "AudioVolumeInterface.h"
+#include "AudioVolumeFactory.h"
+#include "AudioALSASampleRateController.h"
+#if defined(MTK_AUDIO_KS)
+#include "AudioALSADeviceConfigManager.h"
+#endif
+
+#include "AudioMTKFilter.h"
+#include "AudioVUnlockDL.h"
+#include "AudioALSADeviceParser.h"
+#include "AudioALSADriverUtility.h"
+#include "AudioSmartPaController.h"
+
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+#include <audio_ringbuf.h>
+#include <audio_pool_buf_handler.h>
+
+#include <aurisys_controller.h>
+#include <aurisys_lib_manager.h>
+#endif
+
+#if defined(MTK_AUDIODSP_SUPPORT)
+#include "AudioDspStreamManager.h"
+#endif
+
+#include "AudioSmartPaController.h"
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+#include "AudioDetectPulse.h"
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSAPlaybackHandlerFast"
+
+// Latency Detect
+//#define DEBUG_LATENCY
+#define THRESHOLD_FRAMEWORK 0.002
+#define THRESHOLD_HAL 0.002
+#define THRESHOLD_KERNEL 0.002
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+static const char* PROPERTY_KEY_EXTDAC = "vendor.audiohal.resource.extdac.support";
+
+namespace android {
+
+AudioALSAPlaybackHandlerFast::AudioALSAPlaybackHandlerFast(const stream_attribute_t *stream_attribute_source) :
+ AudioALSAPlaybackHandlerBase(stream_attribute_source) {
+ ALOGD("%s()", __FUNCTION__);
+ mPlaybackHandlerType = PLAYBACK_HANDLER_FAST;
+
+ memset(&mNewtime, 0, sizeof(mNewtime));
+ memset(&mOldtime, 0, sizeof(mOldtime));
+}
+
+
+AudioALSAPlaybackHandlerFast::~AudioALSAPlaybackHandlerFast() {
+}
+
+uint32_t AudioALSAPlaybackHandlerFast::GetLowJitterModeSampleRate() {
+ return 48000;
+}
+
+bool AudioALSAPlaybackHandlerFast::SetLowJitterMode(bool bEnable, uint32_t SampleRate) {
+ ALOGV("%s() bEanble = %d SampleRate = %u", __FUNCTION__, bEnable, SampleRate);
+#if !defined(MTK_AUDIO_KS)
+ enum mixer_ctl_type type;
+ struct mixer_ctl *ctl;
+ int retval = 0;
+
+ // check need open low jitter mode
+ if (SampleRate <= GetLowJitterModeSampleRate() && (AudioALSADriverUtility::getInstance()->GetPropertyValue(PROPERTY_KEY_EXTDAC)) == false) {
+ ALOGD("%s(), bypass low jitter mode, bEnable = %d, SampleRate = %u", __FUNCTION__, bEnable, SampleRate);
+ return false;
+ } else {
+ ALOGD("%s() bEanble = %d, SampleRate = %u", __FUNCTION__, bEnable, SampleRate);
+ }
+
+ ctl = mixer_get_ctl_by_name(mMixer, "fast_dl_hd_Switch");
+
+ if (ctl == NULL) {
+ ALOGE("fast_dl_hd_Switch not support");
+ return false;
+ } else {
+ ALOGD("%s() bEanble = %d SampleRate = %u, fast_dl_hd_Switch",
+ __FUNCTION__, bEnable, SampleRate);
+ }
+
+ if (bEnable == true) {
+ retval = mixer_ctl_set_enum_by_string(ctl, "On");
+ ASSERT(retval == 0);
+ } else {
+ retval = mixer_ctl_set_enum_by_string(ctl, "Off");
+ ASSERT(retval == 0);
+ }
+#endif
+ return true;
+}
+
+bool AudioALSAPlaybackHandlerFast::DeviceSupportHifi(audio_devices_t outputdevice) {
+ // modify this to let output device support hifi audio
+ if (outputdevice == AUDIO_DEVICE_OUT_WIRED_HEADSET || outputdevice == AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+ return true;
+ } else if (outputdevice & AUDIO_DEVICE_OUT_SPEAKER) {
+ if (AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ return AudioSmartPaController::getInstance()->getMaxSupportedRate() > 48000;
+ } else {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+uint32_t AudioALSAPlaybackHandlerFast::ChooseTargetSampleRate(uint32_t SampleRate, audio_devices_t outputdevice) {
+ ALOGV("ChooseTargetSampleRate SampleRate = %d outputdevice = %d", SampleRate, outputdevice);
+ uint32_t TargetSampleRate = 48000;
+ if (SampleRate <= 192000 && SampleRate > 96000 && DeviceSupportHifi(outputdevice)) {
+ TargetSampleRate = 192000;
+ } else if (SampleRate <= 96000 && SampleRate > 48000 && DeviceSupportHifi(outputdevice)) {
+ TargetSampleRate = 96000;
+ } else if (SampleRate <= 48000 && SampleRate >= 32000) {
+ TargetSampleRate = SampleRate;
+ }
+ return TargetSampleRate;
+}
+
+status_t AudioALSAPlaybackHandlerFast::open() {
+ ALOGD("+%s(), mDevice = 0x%x", __FUNCTION__, mStreamAttributeSource->output_devices);
+
+ // debug pcm dump
+ OpenPCMDump(LOG_TAG);
+
+ AL_LOCK_MS(AudioALSADriverUtility::getInstance()->getStreamSramDramLock(), 3000);
+
+ // acquire pmic clk
+ mHardwareResourceManager->EnableAudBufClk(true);
+
+#if defined(MTK_AUDIO_KS)
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmPlayback2);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmPlayback2);
+#if !defined(MTK_AUDIODSP_SUPPORT)
+ if ((mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER) &&
+ AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(AUDIO_CTL_PLAYBACK2_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+ if (popcount(mStreamAttributeSource->output_devices) > 1) {
+ mApTurnOnSequence2 = AUDIO_CTL_PLAYBACK2_TO_ADDA_DL;
+ }
+ } else {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK2_TO_ADDA_DL;
+ }
+
+#else
+ if ((mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER) &&
+ (AudioDspStreamManager::getInstance()->getDspPlaybackEnable() == true)) {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK2_TO_CAPTURE6;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK2_TO_DSP;
+ } else if (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER &&
+ AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(AUDIO_CTL_PLAYBACK2_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+ if (popcount(mStreamAttributeSource->output_devices) > 1) {
+ mApTurnOnSequence2 = AUDIO_CTL_PLAYBACK2_TO_ADDA_DL;
+ }
+ if ((AudioDspStreamManager::getInstance()->getDspA2DPEnable() == true) &&
+ (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+ mApTurnOnSequence3 = AUDIO_CTL_PLAYBACK2_TO_CAPTURE6;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK2_TO_DSP;
+ }
+ } else{
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK2_TO_ADDA_DL;
+ if ((AudioDspStreamManager::getInstance()->getDspA2DPEnable() == true) &&
+ (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+ mApTurnOnSequence3 = AUDIO_CTL_PLAYBACK2_TO_CAPTURE6;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK2_TO_DSP;
+ }
+ }
+
+ if (!mApTurnOnSequenceDsp.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequenceDsp);
+ }
+ if (!mApTurnOnSequence3.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence3);
+ }
+#endif // end of defined(MTK_AUDIODSP_SUPPORT)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence2);
+ }
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "fast_play_scenario"), 0, 1)) {
+ ALOGW("%s(), fast_play_scenario enable fail", __FUNCTION__);
+ }
+#else
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmDl2Meida);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmDl2Meida);
+#endif // defined(MTK_AUDIO_KS)
+
+ struct pcm_params *params;
+ params = pcm_params_get(cardindex, pcmindex, PCM_OUT);
+ if (params == NULL) {
+ ALOGD("Device does not exist.\n");
+ }
+
+ mStreamAttributeTarget.buffer_size = pcm_params_get_max(params, PCM_PARAM_BUFFER_BYTES);
+ pcm_params_free(params);
+
+ // HW attribute config // TODO(Harvey): query this
+#ifdef PLAYBACK_USE_24BITS_ONLY
+ mStreamAttributeTarget.audio_format = AUDIO_FORMAT_PCM_8_24_BIT;
+#else
+ mStreamAttributeTarget.audio_format = (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_32_BIT) ? AUDIO_FORMAT_PCM_8_24_BIT : AUDIO_FORMAT_PCM_16_BIT;
+#endif
+ mStreamAttributeTarget.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ mStreamAttributeTarget.num_channels = popcount(mStreamAttributeTarget.audio_channel_mask);
+
+ mStreamAttributeTarget.sample_rate = ChooseTargetSampleRate(AudioALSASampleRateController::getInstance()->getPrimaryStreamOutSampleRate(),
+ mStreamAttributeSource->output_devices);
+
+ // HW pcm config
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = mStreamAttributeTarget.num_channels;
+ mConfig.rate = mStreamAttributeTarget.sample_rate;
+
+ // Buffer size: 1536(period_size) * 2(ch) * 4(byte) * 2(period_count) = 24 kb
+ mConfig.period_count = 2;
+ // audio low latency param - playback - interrupt rate
+ mConfig.period_size = (mStreamAttributeSource->buffer_size / mConfig.channels / ((mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4));
+
+ // audio low latency param - playback - hw buffer size
+ mStreamAttributeTarget.buffer_size = mConfig.period_size * mConfig.period_count * mConfig.channels * ((mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4);
+
+ // ALPS02409284, change interrupt rate & hw buffer size depend target's sampling rate
+ if (mStreamAttributeSource->sample_rate != mStreamAttributeTarget.sample_rate) {
+ mConfig.period_size = mConfig.period_size * mStreamAttributeTarget.sample_rate / mStreamAttributeSource->sample_rate;
+ }
+
+ mConfig.format = transferAudioFormatToPcmFormat(mStreamAttributeTarget.audio_format);
+
+ mConfig.start_threshold = mConfig.period_size * mConfig.period_count;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+ ALOGD("%s(), mConfig: channels = %d, rate = %d, period_size = %d, period_count = %d, format = %d, buffer size %d %d",
+ __FUNCTION__, mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mConfig.format,
+ mStreamAttributeTarget.buffer_size, mStreamAttributeSource->buffer_size);
+
+ mStreamAttributeTarget.mInterrupt = (mConfig.period_size + 0.0) / mStreamAttributeTarget.sample_rate;
+ mStreamAttributeTarget.output_devices = mStreamAttributeSource->output_devices;
+ mStreamAttributeTarget.mAudioOutputFlags = mStreamAttributeSource->mAudioOutputFlags;
+
+#ifdef MTK_AUDIODSP_SUPPORT
+ if (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER) {
+ mStreamAttributeTarget.dspLatency = AudioDspStreamManager::getInstance()->getDlLatency();
+ }
+#endif
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ if (get_aurisys_on()) {
+ CreateAurisysLibManager();
+ } else
+#endif
+ {
+ // post processing
+ initPostProcessing();
+
+ // SRC
+ initBliSrc();
+
+ // bit conversion
+ initBitConverter();
+
+ initDataPending();
+ }
+
+ // disable lowjitter mode
+ SetLowJitterMode(true, mStreamAttributeTarget.sample_rate);
+
+ // open pcm driver
+#if defined(PLAYBACK_MMAP)
+ unsigned int flag = PCM_NOIRQ | PCM_MMAP | PCM_OUT | PCM_MONOTONIC;
+ openPcmDriverWithFlag(pcmindex, flag);
+#else
+ openPcmDriver(pcmindex);
+#endif
+
+
+#if defined(MTK_AUDIODSP_SUPPORT)
+ if ((mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER) ||
+ (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+ AudioDspStreamManager::getInstance()->addPlaybackHandler(this);
+ }
+#endif
+
+ AL_UNLOCK(AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+#if defined(MTK_HYBRID_NLE_SUPPORT) // must be after pcm open
+ initNLEProcessing();
+#endif
+
+ // open codec driver
+ mHardwareResourceManager->startOutputDevice(mStreamAttributeSource->output_devices, mStreamAttributeTarget.sample_rate);
+
+
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ VUnlockhdl->SetInputStandBy(false);
+ VUnlockhdl-> GetSRCInputParameter(mStreamAttributeTarget.sample_rate, mStreamAttributeTarget.num_channels, mStreamAttributeTarget.audio_format);
+ VUnlockhdl->GetFirstDLTime();
+ }
+ //===========================================
+
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerFast::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ VUnlockhdl->SetInputStandBy(true);
+ }
+ //===========================================
+
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+ // Must do this before close analog path
+ deinitNLEProcessing();
+#endif
+
+ // close codec driver
+ mHardwareResourceManager->stopOutputDevice();
+
+ // close pcm driver
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+ closePcmDriver();
+
+#if defined(MTK_AUDIODSP_SUPPORT)
+ if (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER ||
+ (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+ AudioDspStreamManager::getInstance()->removePlaybackHandler(this);
+ }
+#endif
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence2);
+ mApTurnOnSequence2.clear();
+ }
+#ifdef MTK_AUDIODSP_SUPPORT
+ if (!mApTurnOnSequenceDsp.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequenceDsp);
+ mApTurnOnSequenceDsp.clear();
+ }
+ if (!mApTurnOnSequence3.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence3);
+ mApTurnOnSequence3.clear();
+ }
+#endif
+
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "fast_play_scenario"), 0, 0)) {
+ ALOGW("%s(), fast_play_scenario disable fail", __FUNCTION__);
+ }
+#endif
+
+ // disable lowjitter mode
+ SetLowJitterMode(false, mStreamAttributeTarget.sample_rate);
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ if (get_aurisys_on()) {
+ DestroyAurisysLibManager();
+ } else
+#endif
+ {
+ DeinitDataPending();
+
+ // bit conversion
+ deinitBitConverter();
+
+ // SRC
+ deinitBliSrc();
+
+ // post processing
+ deinitPostProcessing();
+ }
+
+ // debug pcm dump
+ ClosePCMDump();
+
+ //release pmic clk
+ mHardwareResourceManager->EnableAudBufClk(false);
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerFast::routing(const audio_devices_t output_devices) {
+ mHardwareResourceManager->changeOutputDevice(output_devices);
+#if !defined(MTK_AURISYS_FRAMEWORK_SUPPORT)
+ if (mAudioFilterManagerHandler) { mAudioFilterManagerHandler->setDevice(output_devices); }
+#endif
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerFast::setScreenState(bool mode __unused,
+ size_t buffer_size __unused,
+ size_t reduceInterruptSize __unused,
+ bool bforce __unused) {
+ return NO_ERROR;
+}
+
+ssize_t AudioALSAPlaybackHandlerFast::write(const void *buffer, size_t bytes) {
+ ALOGV("%s(), buffer = %p, bytes = %zu", __FUNCTION__, buffer, bytes);
+
+ if (mPcm == NULL) {
+ ALOGE("%s(), mPcm == NULL, return", __FUNCTION__);
+ return bytes;
+ }
+
+ // const -> to non const
+ void *pBuffer = const_cast<void *>(buffer);
+ ASSERT(pBuffer != NULL);
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[0] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+
+ // stereo to mono for speaker
+ doStereoToMonoConversionIfNeed(pBuffer, bytes);
+
+ void *pBufferAfterPending = NULL;
+ uint32_t bytesAfterpending = 0;
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ if (get_aurisys_on()) {
+ // expect library output amount smoothly
+ mTransferredBufferSize = GetTransferredBufferSize(
+ bytes,
+ mStreamAttributeSource,
+ &mStreamAttributeTarget);
+
+ audio_pool_buf_copy_from_linear(
+ mAudioPoolBufDlIn,
+ pBuffer,
+ bytes);
+
+ // post processing + SRC + Bit conversion
+ aurisys_process_dl_only(mAurisysLibManager, mAudioPoolBufDlIn, mAudioPoolBufDlOut);
+
+ // data pending: sram is device memory, need word size align 64 byte for 64 bit platform
+ uint32_t data_size = audio_ringbuf_count(&mAudioPoolBufDlOut->ringbuf);
+ if (data_size > mTransferredBufferSize) {
+ data_size = mTransferredBufferSize;
+ }
+ data_size &= 0xFFFFFFC0;
+ audio_pool_buf_copy_to_linear(
+ &mLinearOut->p_buffer,
+ &mLinearOut->memory_size,
+ mAudioPoolBufDlOut,
+ data_size);
+ //ALOGD("aurisys process data_size: %u", data_size);
+
+ // wrap to original playback handler
+ pBufferAfterPending = (void *)mLinearOut->p_buffer;
+ bytesAfterpending = data_size;
+ } else
+#endif
+ {
+ // post processing (can handle both Q1P16 and Q1P31 by audio_format_t)
+ void *pBufferAfterPostProcessing = NULL;
+ uint32_t bytesAfterPostProcessing = 0;
+
+ if (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+ pBufferAfterPostProcessing = pBuffer;
+ bytesAfterPostProcessing = bytes;
+ } else {
+ doPostProcessing(pBuffer, bytes, &pBufferAfterPostProcessing, &bytesAfterPostProcessing);
+ }
+
+ // SRC
+ void *pBufferAfterBliSrc = NULL;
+ uint32_t bytesAfterBliSrc = 0;
+ doBliSrc(pBufferAfterPostProcessing, bytesAfterPostProcessing, &pBufferAfterBliSrc, &bytesAfterBliSrc);
+
+
+ // bit conversion
+ void *pBufferAfterBitConvertion = NULL;
+ uint32_t bytesAfterBitConvertion = 0;
+ doBitConversion(pBufferAfterBliSrc, bytesAfterBliSrc, &pBufferAfterBitConvertion, &bytesAfterBitConvertion);
+
+ // data pending
+ pBufferAfterPending = NULL;
+ bytesAfterpending = 0;
+ dodataPending(pBufferAfterBitConvertion, bytesAfterBitConvertion, &pBufferAfterPending, &bytesAfterpending);
+ }
+
+ // pcm dump
+ WritePcmDumpData(pBufferAfterPending, bytesAfterpending);
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[1] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+
+#ifdef MTK_LATENCY_DETECT_PULSE
+ AudioDetectPulse::doDetectPulse(TAG_PLAYERBACK_HANDLER, PULSE_LEVEL, 0, (void *)pBufferAfterPending,
+ bytesAfterpending, mStreamAttributeTarget.audio_format,
+ mStreamAttributeTarget.num_channels, mStreamAttributeTarget.sample_rate);
+#endif
+
+ dataTransferBeforeWrite(pBufferAfterPending, bytesAfterpending);
+
+ // write data to pcm driver
+ int retval = pcmWrite(mPcm, pBufferAfterPending, bytesAfterpending);
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[2] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+
+#ifndef DOWNLINK_LOW_LATENCY
+ // TODO(Harvey, Wendy), temporary disable Voice Unlock until 24bit ready
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ // get remain time
+ //VUnlockhdl->SetDownlinkStartTime(ret_ms);
+ VUnlockhdl->GetFirstDLTime();
+
+ //VUnlockhdl->SetInputStandBy(false);
+ if (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+ mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+ memset((void *)pBufferAfterPending, 0, bytesAfterpending);
+ }
+ VUnlockhdl->WriteStreamOutToRing(pBufferAfterPending, bytesAfterpending);
+ }
+ //===========================================
+#endif
+
+
+ if (retval != 0) {
+ ALOGE("%s(), pcm_write() error, retval = %d", __FUNCTION__, retval);
+ }
+
+#ifdef DEBUG_LATENCY
+ if (latencyTime[0] > THRESHOLD_FRAMEWORK || latencyTime[1] > THRESHOLD_HAL || latencyTime[2] > (mStreamAttributeTarget.mInterrupt - latencyTime[0] - latencyTime[1] + THRESHOLD_KERNEL)) {
+ ALOGD("latency_in_s,%1.3lf,%1.3lf,%1.3lf, interrupt,%1.3lf", latencyTime[0], latencyTime[1], latencyTime[2], mStreamAttributeTarget.mInterrupt);
+ }
+#endif
+
+ return bytes;
+}
+
+status_t AudioALSAPlaybackHandlerFast::setFilterMng(AudioMTKFilterManager *pFilterMng) {
+#if !defined(MTK_AURISYS_FRAMEWORK_SUPPORT)
+ ALOGD("+%s() mAudioFilterManagerHandler [%p]", __FUNCTION__, pFilterMng);
+ mAudioFilterManagerHandler = pFilterMng;
+#else
+ (void *)pFilterMng;
+#endif
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerFast::dataTransferBeforeWrite(void *addr, uint32_t size) {
+ static bool bSupport = true;
+
+ //ALOGD("+%s() addr 0x%x", __FUNCTION__, (long long) addr);
+
+ if (bSupport) {
+ struct mixer_ctl *ctl = mixer_get_ctl_by_name(mMixer, "Audio_DL2_DataTransfer");
+ if (ctl == NULL) {
+ bSupport = false;
+ return NO_ERROR;
+ }
+
+ int array[2] = {(int)((long long) addr), (int)size};
+ int retval = mixer_ctl_set_array(ctl, array, 2);
+ ASSERT(retval == 0);
+ }
+ return NO_ERROR;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerMixer.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerMixer.cpp
new file mode 100644
index 0000000..8823e1f
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerMixer.cpp
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAPlaybackHandlerMixer.h"
+
+#include "AudioMixerOut.h"
+#include "AudioSmartPaController.h"
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+#include <audio_ringbuf.h>
+#include <audio_pool_buf_handler.h>
+
+#include <aurisys_controller.h>
+#include <aurisys_lib_manager.h>
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSAPlaybackHandlerMixer"
+
+#ifdef DEBUG_LATENCY
+// Latency Detect
+//#define DEBUG_LATENCY
+#define THRESHOLD_FRAMEWORK 0.010
+#define THRESHOLD_HAL 0.010
+#define THRESHOLD_KERNEL 0.010
+#endif
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+
+namespace android {
+
+AudioALSAPlaybackHandlerMixer::AudioALSAPlaybackHandlerMixer(const stream_attribute_t *stream_attribute_source) :
+ AudioALSAPlaybackHandlerBase(stream_attribute_source),
+ mMixerOut(NULL) {
+ ALOGD("%s()", __FUNCTION__);
+ mPlaybackHandlerType = PLAYBACK_HANDLER_MIXER;
+
+ memset((void *)&mNewtime, 0, sizeof(mNewtime));
+ memset((void *)&mOldtime, 0, sizeof(mOldtime));
+}
+
+AudioALSAPlaybackHandlerMixer::~AudioALSAPlaybackHandlerMixer() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+status_t AudioALSAPlaybackHandlerMixer::open() {
+ ALOGD("+%s(), flag %d, mDevice = 0x%x", __FUNCTION__, mStreamAttributeSource->mAudioOutputFlags,
+ mStreamAttributeSource->output_devices);
+
+ // debug pcm dump
+ OpenPCMDump(LOG_TAG);
+
+ mStreamAttributeTarget = *mStreamAttributeSource;
+
+ // get mixer out
+ enum MIXER_USAGE usage;
+ if (audio_is_bluetooth_sco_device(mStreamAttributeSource->output_devices) ||
+ isBtSpkDevice(mStreamAttributeSource->output_devices)) {
+ usage = MIXER_USAGE_BT;
+ } else if (AudioSmartPaController::getInstance()->isSwDspSpkProtect(mStreamAttributeSource->output_devices)) {
+ usage = MIXER_USAGE_SMARTPA;
+ } else if ((mStreamAttributeSource->mAudioOutputFlags & AUDIO_OUTPUT_FLAG_FAST) ||
+ (mStreamAttributeSource->mAudioOutputFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) {
+ // temp, rough condition
+ ASSERT(0);
+ usage = MIXER_USAGE_DEEP_FAST;
+ } else {
+ ASSERT(0);
+ usage = MIXER_USAGE_UNKNOWN;
+ }
+ mMixerOut = AudioMixerOut::getInstance(usage);
+
+ mMixerOut->attach(this, &mStreamAttributeTarget);
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ if (mStreamAttributeSource->mAudioOutputFlags == AUDIO_OUTPUT_FLAG_VOIP_RX) {
+ if (get_aurisys_on()) {
+ CreateAurisysLibManager();
+ }
+ // TODO: no voip effect in playback Handler After Mixer Out
+ } else {
+ // no effect for non voip stream out
+ }
+#endif
+
+ mSmoother = createWriteSmoother();
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerMixer::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ destroyWriteSmoother(&mSmoother);
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ if (mAurisysLibManager && get_aurisys_on()) {
+ DestroyAurisysLibManager();
+ }
+#endif
+
+ mMixerOut->detach(this);
+
+ // debug pcm dump
+ ClosePCMDump();
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+ssize_t AudioALSAPlaybackHandlerMixer::write(const void *buffer, size_t bytes) {
+ ALOGV("%s(), buffer = %p, bytes = %zu", __FUNCTION__, buffer, bytes);
+
+ // const -> to non const
+ void *pBuffer = const_cast<void *>(buffer);
+ ASSERT(pBuffer != NULL);
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[0] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+
+ void *finalBuffer = pBuffer;
+ uint32_t finalBufferBytes = bytes;
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ if (mAurisysLibManager && get_aurisys_on()) {
+ // expect library output amount smoothly
+ mTransferredBufferSize = GetTransferredBufferSize(
+ bytes,
+ mStreamAttributeSource,
+ &mStreamAttributeTarget);
+
+ audio_pool_buf_copy_from_linear(
+ mAudioPoolBufDlIn,
+ pBuffer,
+ bytes);
+
+ // post processing + SRC + Bit conversion
+ aurisys_process_dl_only(mAurisysLibManager, mAudioPoolBufDlIn, mAudioPoolBufDlOut);
+
+ // data pending: sram is device memory, need word size align 64 byte for 64 bit platform
+ uint32_t data_size = audio_ringbuf_count(&mAudioPoolBufDlOut->ringbuf);
+ if (data_size > mTransferredBufferSize) {
+ data_size = mTransferredBufferSize;
+ }
+ data_size &= 0xFFFFFFC0;
+ audio_pool_buf_copy_to_linear(
+ &mLinearOut->p_buffer,
+ &mLinearOut->memory_size,
+ mAudioPoolBufDlOut,
+ data_size);
+
+ // wrap to original playback handler
+ finalBuffer = (void *)mLinearOut->p_buffer;
+ finalBufferBytes = data_size;
+ }
+#endif
+
+ // pcm dump
+ WritePcmDumpData(finalBuffer, finalBufferBytes);
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[1] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+
+ // write data to Mixer
+ mMixerOut->write(this, finalBuffer, finalBufferBytes);
+
+ // sleep buffer latency
+ doWriteSmoother(
+ mSmoother,
+ getBufferLatencyUs(mStreamAttributeSource, bytes),
+ 2); // only sleep when left buffer time > 2 frames
+
+ updateHardwareBufferInfo(bytes, finalBufferBytes);
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[2] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+
+#ifdef DEBUG_LATENCY
+ if (latencyTime[0] > THRESHOLD_FRAMEWORK || latencyTime[1] > THRESHOLD_HAL || latencyTime[2] > (mStreamAttributeTarget.mInterrupt - latencyTime[0] - latencyTime[1] + THRESHOLD_KERNEL)) {
+ ALOGD("latency_in_s,%1.3lf,%1.3lf,%1.3lf, interrupt,%1.3lf,byte:%u", latencyTime[0], latencyTime[1], latencyTime[2], mStreamAttributeTarget.mInterrupt, bytesAfterpending);
+ }
+#endif
+
+ return bytes;
+}
+
+status_t AudioALSAPlaybackHandlerMixer::getHardwareBufferInfo(time_info_struct_t *HWBuffer_Time_Info) {
+ if (mMixerOut->getHardwareBufferInfo(this, HWBuffer_Time_Info) != NO_ERROR) {
+ return UNKNOWN_ERROR;
+ } else {
+ HWBuffer_Time_Info->halQueuedFrame += mHalQueuedFrame;
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerMixer::setScreenState(bool mode,
+ size_t buffer_size,
+ size_t reduceInterruptSize,
+ bool bforce) {
+ return mMixerOut->setScreenState(this, mode, buffer_size, reduceInterruptSize, bforce);
+}
+
+int AudioALSAPlaybackHandlerMixer::setSuspend(bool suspend) {
+ mMixerOut->setSuspend(this, suspend);
+ return 0;
+}
+
+status_t AudioALSAPlaybackHandlerMixer::routing(const audio_devices_t output_devices __unused) {
+ return NO_ERROR;
+}
+
+int AudioALSAPlaybackHandlerMixer::getLatency() {
+ return mMixerOut->getLatency();
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerOffload.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerOffload.cpp
new file mode 100644
index 0000000..affebc5
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerOffload.cpp
@@ -0,0 +1,930 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAPlaybackHandlerOffload.h"
+#include "AudioALSAHardwareResourceManager.h"
+#include "AudioVolumeFactory.h"
+#include "AudioALSASampleRateController.h"
+#include "AudioVUnlockDL.h"
+#include "AudioALSADeviceParser.h"
+#include "AudioALSADriverUtility.h"
+#include "AudioMTKFilter.h"
+#include "AudioALSADeviceConfigManager.h"
+#include "AudioSmartPaController.h"
+#ifdef MTK_AUDIODSP_SUPPORT
+#include "AudioDspStreamManager.h"
+#include "AudioALSAStreamManager.h"
+#endif
+
+#include <tinycompress/tinycompress.h>
+
+#include <pthread.h>
+#include <sys/prctl.h>
+
+#ifdef MTK_AUDIO_SCP_SUPPORT
+#include <audio_task.h>
+#include <AudioMessengerIPI.h>
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSAPlaybackHandlerOffload"
+
+namespace android {
+static void *writeThreadOffload(void *arg);
+static bool threadExit = true;
+static const char* PROPERTY_KEY_EXTDAC = "vendor.audiohal.resource.extdac.support";
+static bool offloadRouting = false;
+
+struct offload_stream_property offload_stream;
+struct offload_thread_property offload_thread;
+struct offload_write_info offload_write;
+
+static void *offload_threadloop(void *arg) {
+ // force to set priority
+ int command, ret = 0;
+ int write_ret = 0;
+ struct offload_cmd *cmd;
+ bool callback, exit, drain;
+ stream_callback_event_t event = STREAM_CBK_EVENT_ERROR;
+ struct listnode *item;
+ struct sched_param sched_p;
+
+ pthread_mutex_lock(&offload_thread.offload_mutex);
+ AudioALSAPlaybackHandlerOffload *pOffloadHandler = (AudioALSAPlaybackHandlerOffload *)arg;
+#ifdef MTK_AUDIO_ADJUST_PRIORITY
+#define RTPM_PRIO_AUDIO_PLAYBACK (95)
+ sched_getparam(0, &sched_p);
+ sched_p.sched_priority = RTPM_PRIO_AUDIO_PLAYBACK;
+ if (0 != sched_setscheduler(0, SCHED_RR, &sched_p)) {
+ ALOGE("%s() failed, errno: %d", __FUNCTION__, errno);
+ } else {
+ sched_getparam(0, &sched_p);
+ ALOGD("sched_setscheduler ok, priority: %d", sched_p.sched_priority);
+ }
+#endif
+ ALOGD("%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+
+ offload_stream.offload_state = OFFLOAD_STATE_IDLE;
+ offload_stream.remain_write = 0;
+ exit = false;
+ drain = false;
+
+ for (;;) {
+ cmd = NULL;
+ command = -1;
+ callback = false;
+ if (list_empty(&offload_thread.offload_cmd_list)) {
+ ALOGV("%s(),list_empty, state:%x, remain:%x", __FUNCTION__, offload_stream.offload_state, offload_stream.remain_write);
+ if (drain && offload_stream.offload_state == OFFLOAD_STATE_EARLY_DRAIN) {
+ command = OFFLOAD_CMD_DRAIN;
+ } else if (offload_stream.remain_write && offload_stream.offload_state == OFFLOAD_STATE_PLAYING) {
+ command = OFFLOAD_CMD_WRITE;
+ }
+ } else {
+ ALOGV("%s(),list not empty", __FUNCTION__);
+ item = list_head(&offload_thread.offload_cmd_list);
+ cmd = node_to_item(item, struct offload_cmd, node);
+ command = cmd->cmd;
+ list_remove(item);
+ free(cmd);
+ }
+
+ if (command == -1) {
+ pthread_cond_wait(&offload_thread.offload_cond, &offload_thread.offload_mutex);
+ ALOGV("%s(),waitevent-", __FUNCTION__);
+ continue;
+ }
+
+ pthread_mutex_unlock(&offload_thread.offload_mutex);
+ ALOGV("%s()command:%x", __FUNCTION__, command);
+
+ switch (command) {
+ case OFFLOAD_CMD_WRITE:
+ write_ret = pOffloadHandler->process_write();
+ if (pOffloadHandler->isformatnotsupport() == 1) {
+ ALOGD("%s() format not support, write ERROR callback notify", __FUNCTION__);
+ write_ret = OFFLOAD_WRITE_ERROR;
+ }
+ if (write_ret == OFFLOAD_WRITE_REMAIN) {
+ offload_stream.remain_write = 1;
+ pOffloadHandler->process_writewait();
+ } else if (write_ret == OFFLOAD_WRITE_EMPTY) {
+ offload_stream.remain_write = 0;
+ event = STREAM_CBK_EVENT_WRITE_READY;
+ callback = true;
+ drain = false;
+ ALOGV("%s() write callback notify", __FUNCTION__);
+ } else if (write_ret == OFFLOAD_WRITE_ERROR) {
+ event = STREAM_CBK_EVENT_ERROR;
+ callback = true;
+ drain = false;
+ ALOGV("%s() write ERROR callback notify", __FUNCTION__);
+ }
+ break;
+ case OFFLOAD_CMD_DRAIN:
+
+ ret = pOffloadHandler->process_drain();
+
+ if (offload_stream.offload_state == OFFLOAD_STATE_EARLY_DRAIN && (list_empty(&offload_thread.offload_cmd_list))) {
+ drain = true;
+ pOffloadHandler->process_writewait();
+ }
+
+ if (list_empty(&offload_thread.offload_cmd_list)) {
+ if (pOffloadHandler->isformatnotsupport() != 1){
+ event = STREAM_CBK_EVENT_DRAIN_READY;
+ callback = true;
+ drain = false;
+ ALOGD("%s() drain callback notify", __FUNCTION__);
+ pOffloadHandler->offload_initialize();
+ offload_stream.remain_write = 0;
+ offload_stream.offload_state = OFFLOAD_STATE_DRAINED;
+ } else {
+ event = STREAM_CBK_EVENT_ERROR;
+ callback = true;
+ ALOGD("%s() OFFLOAD_CMD_DRAIN: format error", __FUNCTION__);
+ }
+ }
+ break;
+ case OFFLOAD_CMD_PAUSE:
+ if (offload_stream.offload_state == OFFLOAD_STATE_PLAYING || offload_stream.offload_state == OFFLOAD_STATE_EARLY_DRAIN) {
+ offload_stream.offload_state = OFFLOAD_STATE_PAUSED;
+ }
+ break;
+ case OFFLOAD_CMD_RESUME:
+ if (offload_stream.offload_state == OFFLOAD_STATE_PAUSED) {
+ offload_stream.offload_state = OFFLOAD_STATE_PLAYING;
+ }
+ break;
+ case OFFLOAD_CMD_FLUSH:
+ if (offload_stream.offload_state == OFFLOAD_STATE_PLAYING || offload_stream.offload_state == OFFLOAD_STATE_EARLY_DRAIN
+ || offload_stream.offload_state == OFFLOAD_STATE_PAUSED) {
+ offload_stream.offload_state = OFFLOAD_STATE_IDLE;
+ pOffloadHandler->offload_initialize();
+ offload_stream.remain_write = 0;
+ ret = 0;
+ }
+ break;
+ case OFFLOAD_CMD_CLOSE:
+ exit = true;
+ break;
+ default:
+ ALOGE("%s(),Invalid Command", __FUNCTION__);
+ break;
+ }
+
+ if (callback) {
+ pOffloadHandler->offload_callback(event);
+ }
+
+ pthread_mutex_lock(&offload_thread.offload_mutex);
+
+ if (exit && !offloadRouting) {
+ pOffloadHandler->offload_callback(STREAM_CBK_EVENT_WRITE_READY);
+ pOffloadHandler->offload_callback(STREAM_CBK_EVENT_DRAIN_READY);
+ ALOGD("%s(),decode done, exit threadloop", __FUNCTION__);
+ break;
+ } else if (exit && offloadRouting){
+ offloadRouting = false;
+ break;
+ } else if (pOffloadHandler->isformatnotsupport() == 1) {
+ if (event != STREAM_CBK_EVENT_ERROR) {
+ ALOGD("%s(),Invalid format, STREAM_CBK_EVENT_ERROR", __FUNCTION__);
+ pOffloadHandler->offload_callback(STREAM_CBK_EVENT_ERROR);
+ }
+ ALOGD("%s(),Invalid format, exit threadloop", __FUNCTION__);
+ break;
+ }
+
+ }
+ pthread_mutex_unlock(&offload_thread.offload_mutex);
+ ALOGD("%s()-", __FUNCTION__);
+ threadExit = true;
+
+ return NULL;
+}
+
+static int send_offload_cmd(int command) {
+ struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd));
+
+ cmd->cmd = command;
+
+ if (!threadExit) {
+ list_add_tail(&offload_thread.offload_cmd_list, &cmd->node);
+ pthread_mutex_lock(&offload_thread.offload_mutex);
+ pthread_cond_signal(&offload_thread.offload_cond);
+ pthread_mutex_unlock(&offload_thread.offload_mutex);
+ }
+
+ ALOGD("%s %d", __FUNCTION__, command);
+ return 0;
+}
+
+AudioALSAPlaybackHandlerOffload::AudioALSAPlaybackHandlerOffload(const stream_attribute_t *stream_attribute_source) :
+ AudioALSAPlaybackHandlerBase(stream_attribute_source),
+ mWriteBsbufSize(0),
+ mReady(false) {
+ ALOGD("%s()", __FUNCTION__);
+ mPlaybackHandlerType = PLAYBACK_HANDLER_OFFLOAD;
+ mFormat = stream_attribute_source->audio_format;
+ memset(&mComprConfig, 0, sizeof(mComprConfig));
+ mStreamAttributeTarget.audio_offload_format = stream_attribute_source->audio_offload_format;
+
+}
+
+
+AudioALSAPlaybackHandlerOffload::~AudioALSAPlaybackHandlerOffload() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+void AudioALSAPlaybackHandlerOffload::offload_initialize() {
+ mReady = false;
+ mWriteBsbufSize = 0;
+}
+
+void AudioALSAPlaybackHandlerOffload::set_pcmdump(int enable) {
+ int ret = NO_ERROR;
+ ret = mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "offload set dump"), 0, enable);
+}
+
+status_t AudioALSAPlaybackHandlerOffload::setFilterMng(AudioMTKFilterManager *pFilterMng) {
+#if !defined(MTK_AURISYS_FRAMEWORK_SUPPORT)
+ ALOGD("+%s() mAudioFilterManagerHandler [%p]", __FUNCTION__, pFilterMng);
+ mAudioFilterManagerHandler = pFilterMng;
+#else
+ (void *)pFilterMng;
+#endif
+ return NO_ERROR;
+}
+
+void AudioALSAPlaybackHandlerOffload::offload_callback(stream_callback_event_t event) {
+ if (mCbkCookie != NULL) {
+ mStreamCbk(event, 0, mCbkCookie);
+ }
+}
+
+
+uint32_t AudioALSAPlaybackHandlerOffload::GetLowJitterModeSampleRate() {
+ return 48000;
+}
+
+
+bool AudioALSAPlaybackHandlerOffload::SetLowJitterMode(bool bEnable, uint32_t SampleRate) {
+ ALOGD("%s() bEanble = %d SampleRate = %u", __FUNCTION__, bEnable, SampleRate);
+
+#if !defined(MTK_AUDIO_KS)
+ enum mixer_ctl_type type;
+ struct mixer_ctl *ctl;
+ int retval = 0;
+
+ // check need open low jitter mode
+ if (SampleRate <= GetLowJitterModeSampleRate() && (AudioALSADriverUtility::getInstance()->GetPropertyValue(PROPERTY_KEY_EXTDAC)) == false) {
+ if (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER) {
+ ALOGD("%s(), force enable low jitter mode, bEnable = %d, device = 0x%x", __FUNCTION__, bEnable, mStreamAttributeSource->output_devices);
+ } else {
+ ALOGD("%s(), bypass low jitter mode, bEnable = %d, device = 0x%x", __FUNCTION__, bEnable, mStreamAttributeSource->output_devices);
+ return false;
+ }
+ }
+
+ ctl = mixer_get_ctl_by_name(mMixer, "Audio_I2S0dl1_hd_Switch");
+
+ if (ctl == NULL) {
+ ALOGE("Audio_I2S0dl1_hd_Switch not support");
+ return false;
+ }
+
+ if (bEnable == true) {
+ retval = mixer_ctl_set_enum_by_string(ctl, "On");
+ ASSERT(retval == 0);
+ } else {
+ retval = mixer_ctl_set_enum_by_string(ctl, "Off");
+ ASSERT(retval == 0);
+ }
+#endif
+ return true;
+}
+
+int AudioALSAPlaybackHandlerOffload::setAfeDspSharemem(bool condition) {
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "adsp_offload_sharemem_scenario"), 0, condition))
+ ALOGW("%s(), enable fail", __FUNCTION__);
+ return 0;
+}
+
+int AudioALSAPlaybackHandlerOffload::setDspRuntimeEn(bool condition) {
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "dsp_offload_runtime_en"), 0, condition)) {
+ ALOGW("%s(), enable fail", __FUNCTION__);
+ return -1;
+ }
+ return 0;
+}
+
+
+status_t AudioALSAPlaybackHandlerOffload::open() {
+ // debug pcm dump
+ OpenPCMDump(LOG_TAG);
+
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ int ret = 0;
+ int pcmindex;
+ int cardindex;
+ // debug pcm dump
+ OpenPCMDump(LOG_TAG);
+
+#ifdef MTK_AUDIO_SCP_SUPPORT
+ /* Load task scene when opening */
+ mAudioMessengerIPI->loadTaskScene(TASK_SCENE_PLAYBACK_MP3);
+
+ if (mStreamAttributeTarget.audio_offload_format == AUDIO_FORMAT_MP3) {
+ ALOGD("%s(),AUDIO_FORMAT_MP3 loadTaskScene", __FUNCTION__);
+ ret = mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "offload set format"), 0, TASK_SCENE_OFFLOAD_MP3);
+ } else if (mStreamAttributeTarget.audio_offload_format == AUDIO_FORMAT_AAC_LC) {
+ ALOGD("%s(),AUDIO_FORMAT_AAC_LC loadTaskScene", __FUNCTION__);
+ ret = mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "offload set format"), 0, TASK_SCENE_OFFLOAD_AAC);
+ }
+ if (ret != 0) {
+ ALOGE("%s, Failed to initialize Scene!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ int formaterror = mixer_ctl_get_value(mixer_get_ctl_by_name(mMixer, "offload set format"), 1);
+ ALOGD("%s(),offload formaterror = %d", __FUNCTION__, formaterror);
+
+ setAfeDspSharemem(true);
+ setDspRuntimeEn(true);
+#endif
+
+ mHardwareResourceManager->EnableAudBufClk(true);
+
+ mStreamAttributeTarget.buffer_size = 32768; //32K
+#ifdef PLAYBACK_USE_24BITS_ONLY
+ mStreamAttributeTarget.audio_format = AUDIO_FORMAT_PCM_8_24_BIT;
+#else
+ mStreamAttributeTarget.audio_format = (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_32_BIT) ? AUDIO_FORMAT_PCM_8_24_BIT : AUDIO_FORMAT_PCM_16_BIT;
+#endif
+ mStreamAttributeTarget.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ mStreamAttributeTarget.num_channels = popcount(mStreamAttributeTarget.audio_channel_mask);
+ mStreamAttributeTarget.sample_rate = ChooseTargetSampleRate(AudioALSASampleRateController::getInstance()->getPrimaryStreamOutSampleRate());
+ mStreamAttributeTarget.output_devices = mStreamAttributeSource->output_devices;
+ mStreamAttributeTarget.mAudioOutputFlags = mStreamAttributeSource->mAudioOutputFlags;
+
+ int compress_dev_index = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmOffloadPlayback);
+ int compress_cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmOffloadPlayback);
+
+// using DL6 for offload , if not exixst using DL3
+#if defined(MTK_AUDIO_KS)
+ pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmPlayback6);
+ if (pcmindex < 0) {
+ pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmPlayback3);
+ cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmPlayback3);
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK3_TO_ADDA_DL;
+
+#if !defined(MTK_AUDIODSP_SUPPORT)
+ if ((mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER) &&
+ AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(AUDIO_CTL_PLAYBACK3_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+ if (popcount(mStreamAttributeSource->output_devices) > 1) {
+ mApTurnOnSequence2 = AUDIO_CTL_PLAYBACK3_TO_ADDA_DL;
+ }
+ } else {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK3_TO_ADDA_DL;
+ }
+#else
+ if (AudioDspStreamManager::getInstance()->getDspPlaybackEnable() == true) {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK3_TO_CAPTURE6;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK3_TO_DSP;
+ } else {
+ if ((mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER) &&
+ AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(AUDIO_CTL_PLAYBACK3_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+ if (popcount(mStreamAttributeSource->output_devices) > 1) {
+ mApTurnOnSequence2 = AUDIO_CTL_PLAYBACK3_TO_ADDA_DL;
+ }
+ } else {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK3_TO_ADDA_DL;
+ }
+
+ if ((AudioDspStreamManager::getInstance()->getDspA2DPEnable() == true) &&
+ (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+ mApTurnOnSequence3 = AUDIO_CTL_PLAYBACK3_TO_CAPTURE6;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK3_TO_DSP;
+ }
+ }
+#endif // !defined(MTK_AUDIODSP_SUPPORT)
+ } else {
+ cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmPlayback6);
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK6_TO_ADDA_DL;
+
+#if !defined(MTK_AUDIODSP_SUPPORT)
+ if ((mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER) &&
+ AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(AUDIO_CTL_PLAYBACK6_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+ if (popcount(mStreamAttributeSource->output_devices) > 1) {
+ mApTurnOnSequence2 = AUDIO_CTL_PLAYBACK6_TO_ADDA_DL;
+ }
+ } else {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK6_TO_ADDA_DL;
+ }
+#else
+ if (AudioDspStreamManager::getInstance()->getDspPlaybackEnable() == true) {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK6_TO_CAPTURE6;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK6_TO_DSP;
+ } else {
+ if ((mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_SPEAKER) &&
+ AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(AUDIO_CTL_PLAYBACK6_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+ if (popcount(mStreamAttributeSource->output_devices) > 1) {
+ mApTurnOnSequence2 = AUDIO_CTL_PLAYBACK6_TO_ADDA_DL;
+ }
+ } else {
+ mApTurnOnSequence = AUDIO_CTL_PLAYBACK6_TO_ADDA_DL;
+ }
+
+ if ((AudioDspStreamManager::getInstance()->getDspA2DPEnable() == true) &&
+ (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+ mApTurnOnSequence3 = AUDIO_CTL_PLAYBACK6_TO_CAPTURE6;
+ mApTurnOnSequenceDsp = AUDIO_CTL_PLAYBACK6_TO_DSP;
+ }
+ }
+#endif // !defined(MTK_AUDIODSP_SUPPORT)
+ }
+
+#if defined(MTK_AUDIODSP_SUPPORT)
+ if (!mApTurnOnSequenceDsp.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequenceDsp);
+ }
+ if (!mApTurnOnSequence3.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence3);
+ }
+#endif
+
+ if (!mApTurnOnSequence.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+ }
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence2);
+ }
+
+#else
+ pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmDl3Meida);
+ cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmDl3Meida);
+ ALOGD("AudioALSAPlaybackHandlerOffload::open() compress dev index = %d cardindex = %d", compress_dev_index, cardindex);
+#endif // defined(MTK_AUDIO_KS)
+
+ mComprConfig.codec = (struct snd_codec *)malloc(sizeof(struct snd_codec));
+
+ if (mComprConfig.codec == NULL) {
+ ALOGE("%s() mComprConfig.codec malloc failed", __FUNCTION__);
+ goto STATUS_ERROR;
+ }
+ //kernel buffersize = 4M -32K
+ mComprConfig.fragments = 2;
+ mComprConfig.fragment_size = OFFLOAD_BUFFER_SIZE_PER_ACCESSS;
+ mComprConfig.codec->sample_rate = mStreamAttributeSource->offload_codec_info.codec_samplerate;
+ mComprConfig.codec->bit_rate = mStreamAttributeSource->offload_codec_info.codec_bitrate;
+ mComprConfig.codec->reserved[0] = (mStreamAttributeTarget.buffer_size / (mStreamAttributeTarget.num_channels * 2)) / ((mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4);
+ mComprConfig.codec->reserved[1] = mComprConfig.fragments * mComprConfig.fragment_size;
+ mComprConfig.codec->reserved[2] = mStreamAttributeTarget.sample_rate;
+
+ if (transferAudioFormatToPcmFormat(mStreamAttributeTarget.audio_format) == PCM_FORMAT_S16_LE) {
+ mComprConfig.codec->format = SNDRV_PCM_FORMAT_S16_LE;
+ } else {
+ mComprConfig.codec->format = SNDRV_PCM_FORMAT_S32_LE;
+ }
+
+ mComprConfig.codec->id = SND_AUDIOCODEC_MP3;
+ mComprConfig.codec->ch_in = mStreamAttributeTarget.num_channels;
+ mComprConfig.codec->ch_out = mStreamAttributeTarget.num_channels;
+ // set HW pcm config
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = mStreamAttributeTarget.num_channels;
+ mConfig.rate = mStreamAttributeTarget.sample_rate;
+ // Buffer size: 1536(period_size) * 2(ch) * 4(byte) * 2(period_count) = 24 kb
+ mConfig.period_count = 2;
+ mConfig.period_size = (mStreamAttributeTarget.buffer_size / (mConfig.channels * mConfig.period_count)) /
+ ((mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4);
+ mConfig.format = transferAudioFormatToPcmFormat(mStreamAttributeTarget.audio_format);
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = ~(0U);
+ mConfig.silence_threshold = 0;
+ mConfig.avail_min = mStreamAttributeSource->buffer_size / ((mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4) / mStreamAttributeSource->num_channels;
+ //lowjitter mode
+ SetLowJitterMode(true, mStreamAttributeTarget.sample_rate);
+
+ //if( compress_set_gapless_metadata(mComprStream, &offload_stream.offload_mdata) != 0)
+
+ if (openComprDriver(compress_dev_index) != NO_ERROR) {
+ goto STATUS_ERROR;
+ }
+
+ if (openPcmDriver(pcmindex) != NO_ERROR) {
+ goto STATUS_ERROR;
+ }
+ if (pcm_start(mPcm) != 0) {
+ ALOGE("%s(), pcm_start(%p) == false due to %s", __FUNCTION__, mPcm, pcm_get_error(mPcm));
+ }
+ ALOGD("-%s(),", __FUNCTION__);
+
+#if defined(MTK_AUDIODSP_SUPPORT)
+ if (AudioDspStreamManager::getInstance()->getDspPlaybackEnable() == true ||
+ AudioDspStreamManager::getInstance()->getDspA2DPEnable() == true) {
+ AudioDspStreamManager::getInstance()->addPlaybackHandler(this);
+ }
+ audio_ipi_dma_cbk_register(TASK_SCENE_PLAYBACK_MP3,
+ 0,
+ 0x48000,
+ processDmaMsgWrapper,
+ this);
+ OpenPCMDumpDSP(LOG_TAG);
+#endif
+
+ mHardwareResourceManager->startOutputDevice(mStreamAttributeSource->output_devices, mStreamAttributeTarget.sample_rate);
+#if defined(MTK_HYBRID_NLE_SUPPORT) // must be after pcm open
+ mStreamAttributeTarget.output_devices = mStreamAttributeSource->output_devices;
+ initNLEProcessing();
+#endif
+
+ offload_stream.fragment_size = OFFLOAD_BUFFER_SIZE_PER_ACCESSS;
+ offload_stream.tmpbsBuffer = (void *)malloc(offload_stream.fragment_size << 2);
+ offload_write.tmpBuffer = (void *)malloc(offload_stream.fragment_size);
+ offload_write.bytes = offload_stream.fragment_size;
+
+ //mWritebytes = 0;
+ offload_stream.num_channels = mStreamAttributeTarget.num_channels;
+ offload_stream.sample_rate = mStreamAttributeTarget.sample_rate;
+ offload_stream.remain_write = 0;
+ ALOGD("%s open offload num_channels = %d, sample_rate = %d , remain_write = %d, offload_write.tmpBuffer = %p",
+ __FUNCTION__, offload_stream.num_channels, offload_stream.sample_rate, offload_stream.remain_write, offload_write.tmpBuffer);
+
+ list_init(&offload_thread.offload_cmd_list);
+ ret = pthread_mutex_init(&offload_thread.offload_mutex, NULL);
+
+ if (ret != 0) {
+ ALOGE("%s, Failed to initialize Mutex!", __FUNCTION__);
+ goto STATUS_ERROR;
+ }
+
+ ret = pthread_cond_init(&offload_thread.offload_cond, NULL);
+
+ if (ret != 0) {
+ ALOGE("%s, Failed to initialize Cond!", __FUNCTION__);
+ goto STATUS_ERROR;
+ }
+
+ ret = pthread_create(&offload_thread.offload_pthread, NULL, &offload_threadloop, this);
+
+ if (ret != 0) {
+ ALOGE("%s() create thread OffloadWrite fail!!", __FUNCTION__);
+ goto STATUS_ERROR;
+ }
+ threadExit = false;
+ usleep(1 * 1000);
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+STATUS_ERROR:
+ ALOGD("-%s() STATUS_ERROR ret = %d", __FUNCTION__, ret);
+ return INVALID_OPERATION;
+}
+
+status_t AudioALSAPlaybackHandlerOffload::close() {
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ if (offload_stream.offload_state == OFFLOAD_STATE_PLAYING
+ || offload_stream.offload_state == OFFLOAD_STATE_PAUSED
+ || offload_stream.offload_state == OFFLOAD_STATE_DRAINED) {
+ offload_stream.offload_state = OFFLOAD_STATE_IDLE;
+ }
+ closeComprDriver();
+ //close compress device driver
+ send_offload_cmd(OFFLOAD_CMD_CLOSE);
+
+#if defined(MTK_AUDIODSP_SUPPORT)
+ if (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+ AudioALSAStreamManager::getInstance()->setA2dpPlaybackPaused(false);
+ }
+#endif
+
+ ALOGD("%s() start wait", __FUNCTION__);
+ while (!threadExit) {
+ usleep(1 * 1000);
+ }
+ pthread_join(offload_thread.offload_pthread, (void **) NULL);
+ pthread_cond_destroy(&offload_thread.offload_cond);
+ pthread_mutex_destroy(&offload_thread.offload_mutex);
+
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+
+ if (VUnlockhdl != NULL) {
+ VUnlockhdl->SetInputStandBy(true);
+ }
+ //===========================================
+
+#if defined(MTK_HYBRID_NLE_SUPPORT)
+ // Must do this before close analog path
+ deinitNLEProcessing();
+#endif
+ // close codec driver
+ mHardwareResourceManager->stopOutputDevice();
+ // close pcm driver
+ closePcmDriver();
+
+#if defined(MTK_AUDIODSP_SUPPORT)
+ if (AudioDspStreamManager::getInstance()->getDspPlaybackEnable() == true ||
+ AudioDspStreamManager::getInstance()->getDspA2DPEnable() == true) {
+ AudioDspStreamManager::getInstance()->removePlaybackHandler(this);
+ }
+#endif
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence2);
+ mApTurnOnSequence2.clear();
+ }
+#ifdef MTK_AUDIODSP_SUPPORT
+ if (!mApTurnOnSequenceDsp.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequenceDsp);
+ mApTurnOnSequenceDsp.clear();
+ }
+ if (!mApTurnOnSequence3.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence3);
+ mApTurnOnSequence3.clear();
+ }
+#endif
+#endif
+
+ // disable lowjitter mode //doug to check
+ SetLowJitterMode(false, mStreamAttributeTarget.sample_rate);
+
+ setDspRuntimeEn(false);
+ setAfeDspSharemem(false);
+
+ // debug pcm dump
+ ClosePCMDump();
+#ifdef MTK_AUDIODSP_SUPPORT
+ audio_ipi_dma_cbk_deregister(TASK_SCENE_PLAYBACK_MP3);
+ ClosePCMDumpDSP();
+#endif
+
+ //release pmic clk
+ mHardwareResourceManager->EnableAudBufClk(false);
+
+ if (mComprConfig.codec != NULL) {
+ free(mComprConfig.codec);
+ mComprConfig.codec = NULL;
+ }
+ if (offload_stream.tmpbsBuffer != NULL) {
+ free(offload_stream.tmpbsBuffer);
+ offload_stream.tmpbsBuffer = NULL;
+ }
+ if (offload_write.tmpBuffer != NULL) {
+ free(offload_write.tmpBuffer);
+ offload_write.tmpBuffer = NULL;
+ }
+
+ ALOGD("%s() closed", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerOffload::routing(const audio_devices_t output_devices) {
+ mHardwareResourceManager->changeOutputDevice(output_devices);
+#if !defined(MTK_AURISYS_FRAMEWORK_SUPPORT)
+ if (mAudioFilterManagerHandler) { mAudioFilterManagerHandler->setDevice(output_devices); }
+#endif
+ return NO_ERROR;
+}
+
+int AudioALSAPlaybackHandlerOffload::pause() {
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+ if (threadExit) {
+ return INVALID_OPERATION;
+ }
+
+ int ret = NO_ERROR;
+
+#if defined(MTK_AUDIODSP_SUPPORT)
+ if (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+ AudioALSAStreamManager::getInstance()->setA2dpPlaybackPaused(true);
+ int status = AudioALSAStreamManager::getInstance()->getA2dpSuspendStatus();
+ if (status != 4) { // Send SUSPEND request when status is not SUSPEND SUCCESS
+ ALOGD("%s() status=%d, setA2dpSuspend true", __FUNCTION__, status);
+ AudioALSAStreamManager::getInstance()->setA2dpSuspend(true);
+ }
+ }
+#endif
+
+ ALOGD("%s() state:%x", __FUNCTION__, offload_stream.offload_state);
+ send_offload_cmd(OFFLOAD_CMD_PAUSE);
+ ret = compress_pause(mComprStream);
+ if (ret != 0) {
+ ALOGE("%s() error %d", __FUNCTION__, ret);
+ return -ENODATA;
+ }
+ return 0;
+}
+
+int AudioALSAPlaybackHandlerOffload::resume() {
+ if (threadExit) {
+ return INVALID_OPERATION;
+ }
+
+ int ret = NO_ERROR;
+
+#if defined(MTK_AUDIODSP_SUPPORT)
+ if (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+ AudioALSAStreamManager::getInstance()->setA2dpPlaybackPaused(false);
+ int status = AudioALSAStreamManager::getInstance()->getA2dpSuspendStatus();
+ if (status != 0) { // Send START request when status is not START SUCCESS
+ ALOGD("%s() status=%d, setA2dpSuspend false", __FUNCTION__, status);
+ AudioALSAStreamManager::getInstance()->setA2dpSuspend(false);
+ }
+ }
+#endif
+ ALOGD("%s() state:%x", __FUNCTION__, offload_stream.offload_state);
+ send_offload_cmd(OFFLOAD_CMD_RESUME);
+ ret = compress_resume(mComprStream);
+ if (ret != 0) {
+ ALOGE("%s() error %d", __FUNCTION__, ret);
+ return -ENODATA;
+ }
+ return 0;
+}
+
+status_t AudioALSAPlaybackHandlerOffload::setVolume(uint32_t vl) {
+ int ret = NO_ERROR;
+
+ offload_stream.offload_gain[0] = vl;
+ offload_stream.offload_gain[1] = 1;
+ ret = mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "offload digital volume"), 0, vl);
+ ALOGD("%s() VOL:0x%x ", __FUNCTION__, vl);
+ return ret;
+}
+
+int AudioALSAPlaybackHandlerOffload::drain(audio_drain_type_t type) {
+ if (threadExit) {
+ return INVALID_OPERATION;
+ }
+ /* make sure to let kernel blocking in drain state*/
+ int ret = NO_ERROR;
+ offload_stream.offload_state = OFFLOAD_STATE_EARLY_DRAIN;
+ process_write();
+ //ret = compress_drain(mComprStream);
+ send_offload_cmd(OFFLOAD_CMD_DRAIN);
+ ALOGD("%s() drain type = %d", __FUNCTION__, type);
+
+ return 0;
+}
+
+int AudioALSAPlaybackHandlerOffload::flush() {
+ if (threadExit) {
+ return INVALID_OPERATION;
+ }
+
+ int ret = NO_ERROR;
+
+ ALOGD("%s() state:%x", __FUNCTION__, offload_stream.offload_state);
+ ret = compress_stop(mComprStream);
+ if (ret != 0) {
+ ALOGE("%s() error %d", __FUNCTION__, ret);
+ }
+ send_offload_cmd(OFFLOAD_CMD_FLUSH);
+ return 0;
+}
+
+
+ssize_t AudioALSAPlaybackHandlerOffload::write(const void *buffer, size_t bytes) {
+ // const -> to non const
+ void *pBuffer = const_cast<void *>(buffer);
+
+ if (offload_stream.offload_state == OFFLOAD_STATE_DRAINED) { //gapless:no close & flush
+ if (compress_stop(mComprStream) != 0) {
+ ALOGE("%s() error", __FUNCTION__);
+ }
+ offload_stream.offload_state = OFFLOAD_STATE_IDLE;
+ }
+
+ memcpy((char *)offload_stream.tmpbsBuffer + mWriteBsbufSize, buffer, bytes);
+ mWriteBsbufSize += bytes;
+ ALOGV("%s(), offload_write buffer = %p, bytes = %zu, mWriteBsbufSize =%d", __FUNCTION__, offload_write.tmpBuffer, bytes, mWriteBsbufSize);
+ send_offload_cmd(OFFLOAD_CMD_WRITE);
+ return bytes;
+}
+
+
+
+
+uint32_t AudioALSAPlaybackHandlerOffload::ChooseTargetSampleRate(uint32_t SampleRate) {
+ uint32_t TargetSampleRate = 44100;
+
+ if (SampleRate <= 192000 && SampleRate > 96000) {
+ TargetSampleRate = 192000;
+ } else if (SampleRate <= 96000 && SampleRate > 48000) {
+ TargetSampleRate = 96000;
+ } else {
+ TargetSampleRate = SampleRate;
+ }
+ return TargetSampleRate;
+}
+
+int AudioALSAPlaybackHandlerOffload::process_writewait() {
+ ALOGD("%s()", __FUNCTION__);
+ compress_wait(mComprStream, -1);
+ return 0;
+}
+
+int AudioALSAPlaybackHandlerOffload::isformatnotsupport() {
+ int formaterror = mixer_ctl_get_value(mixer_get_ctl_by_name(mMixer, "offload set format"), 0);
+ if (mStreamAttributeSource->offload_codec_info.disable_codec == 1 || formaterror == 1) {
+ ALOGD("%s(), formaterror:%d, mStreamAttributeSource.offload_codec_info.disable_codec:%d", __FUNCTION__, formaterror, mStreamAttributeSource->offload_codec_info.disable_codec);
+ return true;
+ }
+ return false;
+}
+
+int AudioALSAPlaybackHandlerOffload::process_drain() {
+ ALOGD("%s()", __FUNCTION__);
+ compress_drain(mComprStream);
+ return 0;
+}
+int AudioALSAPlaybackHandlerOffload::process_write() {
+ int ret = NO_ERROR;
+ int remained_bitstream = 0;
+
+ // check setwriteblock flag
+ if (mWriteBsbufSize >= offload_stream.fragment_size) {
+ remained_bitstream = mWriteBsbufSize - offload_stream.fragment_size;
+ memcpy(offload_write.tmpBuffer, offload_stream.tmpbsBuffer, offload_stream.fragment_size);
+ ret = compress_write(mComprStream, offload_write.tmpBuffer, offload_stream.fragment_size);
+ if (offload_stream.offload_state == OFFLOAD_STATE_EARLY_DRAIN) {
+ ALOGD("%s(), OFFLOAD_STATE_EARLY_DRAIN, process_write 1", __FUNCTION__);
+ }
+ if (ret < 0) {
+ ALOGE("%s(), write() error, ret = %d", __FUNCTION__, ret);
+ return OFFLOAD_WRITE_ERROR;
+ }
+ } else {
+ if (offload_stream.offload_state == OFFLOAD_STATE_EARLY_DRAIN && mWriteBsbufSize != 0) {
+ mWriteBsbufSize = mWriteBsbufSize & 0Xffffff80;
+ memcpy(offload_write.tmpBuffer, offload_stream.tmpbsBuffer, mWriteBsbufSize);
+ ret = compress_write(mComprStream, offload_write.tmpBuffer, mWriteBsbufSize);
+ ALOGD("%s(), OFFLOAD_STATE_EARLY_DRAIN, compress_write 2 , ret = %d, mWriteBsbufSize = %d", __FUNCTION__, ret, mWriteBsbufSize);
+ if (ret < 0) {
+ ALOGE("%s(), write() error, ret = %d", __FUNCTION__, ret);
+ return OFFLOAD_WRITE_ERROR;
+ }
+ mWriteBsbufSize = 0;
+ }
+ return OFFLOAD_WRITE_EMPTY;
+ }
+ if (!mReady) {
+ mReady = true;
+ if (offload_stream.offload_state == OFFLOAD_STATE_IDLE) {
+ offload_stream.offload_state = OFFLOAD_STATE_PLAYING;
+ compress_start(mComprStream);
+ compress_nonblock(mComprStream, 1);
+ ALOGD("%s(), OFFLOADSERVICE_START", __FUNCTION__);
+#if defined(MTK_AUDIODSP_SUPPORT)
+ if (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+ int status = AudioALSAStreamManager::getInstance()->getA2dpSuspendStatus();
+ if (status != 0) { // Send start request when status is not START SUCCESS
+ ALOGD("%s() status=%d, setA2dpSuspend false", __FUNCTION__, status);
+ AudioALSAStreamManager::getInstance()->setA2dpSuspend(false); // for seek+next or pause+seek+resume operation
+ }
+ }
+#endif
+ }
+ }
+ if (ret == (int)offload_stream.fragment_size) {
+ memmove(offload_stream.tmpbsBuffer, (char *)offload_stream.tmpbsBuffer + offload_stream.fragment_size, remained_bitstream);
+ mWriteBsbufSize = remained_bitstream;
+ ALOGV("%s(), ret = %d mWriteBsbufSize = Remained BS = %d", __FUNCTION__, ret, remained_bitstream);
+ return OFFLOAD_WRITE_EMPTY;
+ } else {
+ remained_bitstream = mWriteBsbufSize - ret;
+
+ if (ret != 0) {
+ memmove(offload_stream.tmpbsBuffer, (char *)offload_stream.tmpbsBuffer + ret, remained_bitstream);
+ mWriteBsbufSize = remained_bitstream;
+ }
+ ALOGV("%s(), REMAIN ret = %d Remained BS = %d", __FUNCTION__, ret, remained_bitstream);
+ return OFFLOAD_WRITE_REMAIN;
+ }
+
+ return ret;
+}
+
+bool AudioALSAPlaybackHandlerOffload::setOffloadRoutingFlag(bool enable) {
+
+ ALOGD("%s(), set offloadRouting = %d", __FUNCTION__, enable);
+ offloadRouting = enable;
+ return offloadRouting;
+}
+
+} // end of namespace android
+
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerSpeakerProtection.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerSpeakerProtection.cpp
new file mode 100644
index 0000000..ae2b25f
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerSpeakerProtection.cpp
@@ -0,0 +1,1023 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <math.h>
+#include <dlfcn.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
+#include <utils/threads.h>
+#include <dlfcn.h>
+
+#include "AudioALSAPlaybackHandlerSpeakerProtection.h"
+#include "AudioALSAHardwareResourceManager.h"
+#include "AudioVolumeFactory.h"
+#include "AudioMTKFilter.h"
+#include "AudioVUnlockDL.h"
+#include "AudioALSADeviceParser.h"
+#include "AudioALSADriverUtility.h"
+#include "AudioALSASampleRateController.h"
+#include "AudioALSAStreamManager.h"
+
+#if defined(MTK_AUDIO_KS)
+#include "AudioALSADeviceConfigManager.h"
+
+#define SPK_PROTECT_AP_SEQUENCE AUDIO_CTL_PLAYBACK1_TO_ADDA_I2S
+#endif
+
+#include <mlds_api.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioSpkProtect"
+
+// define this to by pass processing
+//#define BY_PASS_PROCESSING
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
+
+/*
+* need add config for DSM lib
+*/
+
+extern "C" {
+#include <cutils/str_parms.h>
+#include <cutils/hashmap.h>
+#include <cutils/memory.h>
+#include <log/log.h>
+#include <cutils/properties.h>
+}
+
+static const char *SpeakerLibPath[] = {
+ "/vendor/lib/dsm_interface.so",
+ "/system/lib/libdsm_interface.so"
+};
+
+static const char *SpeakerLib64Path[] = {
+ "/vendor/lib64/dsm_interface.so",
+ "/system/lib64/libdsm_interface.so"
+};
+
+#define SPEAKER_LIB_PATH ("libdsm_interface.so")
+#define DSM_LIB_PATH ("libdsm.so")
+#define SPEAKER_CONFIGPARSER_LIB_PATH ("libdsmconfigparser.so")
+
+//#define DEBUG_LATENCY
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+static const char PROPERTY_KEY_BYPASSPROTECTION[PROPERTY_KEY_MAX] = "vendor.speakerprotection_bypass";
+
+namespace android {
+
+AudioALSAPlaybackHandlerSpeakerProtection::AudioALSAPlaybackHandlerSpeakerProtection(const stream_attribute_t *stream_attribute_source) :
+ AudioALSAPlaybackHandlerBase(stream_attribute_source) {
+ ALOGD("%s()", __FUNCTION__);
+ mPlaybackHandlerType = PLAYBACK_HANDLER_SPEAKERPROTECTION;
+ mDumpPlayIVFileNum = 0;
+ mDsmpcmOut = NULL;
+ mDsmiData = NULL;
+ mDsmvData = NULL;
+ mSpeakerChannelProcessingBuffer = NULL;
+ mDsmProcessingbuffer = NULL;
+ mDsmIvReadData = NULL;
+ mPCMPlayIVDumpFile = NULL;
+ dsm_handler = NULL;
+ mDsmMemBuffer = NULL;
+ memset((void *)&mPcmIvConfig, 0, sizeof(pcm_config));
+ mBypassSpeakerProtection = (bool)AudioALSADriverUtility::getInstance()->GetPropertyValue(PROPERTY_KEY_BYPASSPROTECTION);
+ mAudioAlsaPcmIn = AudioALSAPcmDataCaptureIn::getInstance();
+ mMlds_handle = NULL;
+#ifdef DEBUG_LATENCY
+ memset((void *)&mNewtime, 0, sizeof(timespec));
+ memset((void *)&mOldtime, 0, sizeof(timespec));
+#endif
+ mu4DsmMemSize = 0;
+ mDsmMemSize = 0;
+ remaining_bytes = 0;
+ mDsmSamples = 0;
+ mDsmChannels = 0;
+ mInputChannels = 0;
+ mDsmSampleRate = 0;
+
+ mmlds_task_config = (mlds_task_config_t *)malloc(sizeof(mlds_task_config_t));
+ ASSERT(mmlds_task_config != NULL);
+ memset((void *)mmlds_task_config, 0, sizeof(mlds_task_config_t));
+
+ mMlds_Interace_pointer = (mlds_interface *)malloc(sizeof(mlds_interface));
+ ASSERT(mMlds_Interace_pointer != NULL);
+ memset((void *)mMlds_Interace_pointer, 0, sizeof(mlds_interface));
+ mDsmConfigHandle = NULL;
+ mDsmInterfaceHandle = NULL;
+}
+
+AudioALSAPlaybackHandlerSpeakerProtection::~AudioALSAPlaybackHandlerSpeakerProtection() {
+ ALOGD("%s()", __FUNCTION__);
+
+ if (mmlds_task_config != NULL) {
+ free(mmlds_task_config);
+ }
+
+ if (mMlds_Interace_pointer != NULL) {
+ free(mMlds_Interace_pointer);
+ }
+}
+
+uint32_t AudioALSAPlaybackHandlerSpeakerProtection::ChooseTargetSampleRate(uint32_t SampleRate) {
+ //ALOGD("ChooseTargetSampleRate SampleRate = %d outputdevice = %d", SampleRate, outputdevice);
+ uint32_t TargetSampleRate = 48000;
+
+ if (SampleRate >= 48000) {
+ TargetSampleRate = 48000;
+ } else if (SampleRate < 48000 && SampleRate >= 44100) {
+ TargetSampleRate = 44100;
+ } else if (SampleRate == 16000) {
+ TargetSampleRate = 16000;
+ }
+ return TargetSampleRate;
+}
+
+#ifdef MTK_MAXIM_SPEAKER_SUPPORT
+static int audio_get_parameters(struct str_parms *query,
+ struct str_parms *reply, int *param, void *dsm_handler) {
+ int ret, val;
+ char value[32] = {0};
+ char *str = NULL;
+
+#define AUDIO_DSM_PARAMETER "DSM"
+ ret = str_parms_get_str(query, AUDIO_DSM_PARAMETER, value,
+ sizeof(value));
+ if (ret >= 0) {
+ ret = DsmGetParams(dsm_handler, 1, param);
+ if (NO_ERROR != ret) {
+ ALOGE("%s: DSM get params failed", __func__);
+ }
+ ALOGE("%s: DSM get params %d", __func__, param[1]);
+ str_parms_add_int(reply, AUDIO_DSM_PARAMETER, param[1]);
+ }
+
+ return 0;
+}
+
+static void audio_extn_dsm_parameters(struct str_parms *query,
+ struct str_parms *reply, int *param, void *dsm_handler) {
+ char *kv_pairs = NULL;
+ audio_get_parameters(query, reply, param, dsm_handler);
+
+ kv_pairs = str_parms_to_str(reply);
+ ALOGD_IF(kv_pairs != NULL, "%s: returns %s", __func__, kv_pairs);
+ free(kv_pairs);
+}
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::setParameters(const String8 &keyValuePairs) {
+ ALOGD("%s %s", __FUNCTION__, keyValuePairs.string());
+ struct str_parms *parms = NULL;
+ char *str;
+ char value[32];
+ int val;
+ int ret = 0, err;
+ parms = str_parms_create_str(keyValuePairs.string());
+
+ {
+ int param[4];
+ /*parse the id and value*/
+ err = str_parms_get_str(parms, "DSM", value, sizeof(value));
+ if (err >= 0) {
+ char *id, *cp, *ptr;
+ const char delimiters[] = " ";
+ double ret;
+
+ cp = strdup(value);
+ id = strtok(cp, delimiters);
+ param[2 * 0] = strtol(id, NULL, 10);
+ id = strtok(NULL, delimiters);
+ ret = strtod(id, &ptr);
+ param[2 * 0 + 1] = ret;
+ ALOGD("param[1] = %d", param[1]);
+ err = DsmSetParams(dsm_handler, 1, param);
+ if (NO_ERROR != err) {
+ ALOGE("%s: DSM set params failed err = %d", __func__, err);
+ }
+ free(cp);
+ }
+ }
+ ALOGD("-%s %s", __FUNCTION__, keyValuePairs.string());
+ str_parms_destroy(parms);
+ return NO_ERROR;
+}
+
+#else
+status_t AudioALSAPlaybackHandlerSpeakerProtection::setParameters(const String8 &keyValuePairs) {
+ ALOGD("%s %s", __FUNCTION__, keyValuePairs.string());
+ return NO_ERROR;
+}
+#endif
+
+#ifdef MTK_MAXIM_SPEAKER_SUPPORT
+String8 AudioALSAPlaybackHandlerSpeakerProtection::getParameters(const String8 &keys) {
+ ALOGD("%s %s", __FUNCTION__, keys.string());
+ struct str_parms *reply = str_parms_create();
+ struct str_parms *query = str_parms_create_str(keys.string());
+ char *str = NULL;
+
+ {
+ ALOGE("%s: enter: %s", __func__, keys.string());
+ int param[4], err;
+ char value[32], *id;
+ /*parse the id and value*/
+ err = str_parms_get_str(query, "DSM", value, sizeof(value));
+ if (err >= 0) {
+ char *id, *cp, *ptr;
+ const char delimiters[] = " ";
+ double ret;
+
+ cp = strdup(value);
+ id = strtok(cp, delimiters);
+ param[0] = strtol(id, NULL, 10);
+ ALOGE("%s: param %d id = %s", __func__, param[0], id);
+ free(cp);
+ }
+ ALOGD("%s , dsm_handler = %p", __FUNCTION__, dsm_handler);
+ audio_extn_dsm_parameters(query, reply, param, dsm_handler);
+ }
+ str = str_parms_to_str(reply);
+
+ str_parms_destroy(query);
+ str_parms_destroy(reply);
+
+ ALOGE("-%s: enter", __func__);
+ String8 ReturnValue(str);
+ free(str);
+ return ReturnValue;
+}
+
+#else
+String8 AudioALSAPlaybackHandlerSpeakerProtection::getParameters(const String8 &keys) {
+ ALOGD("%s %s", __FUNCTION__, keys.string());
+ struct str_parms *reply = str_parms_create();
+ struct str_parms *query = str_parms_create_str(keys.string());
+ char *str = NULL;
+ String8 ReturnValue(str);
+ return ReturnValue;
+}
+#endif
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::open() {
+ ALOGD("+%s(), mDevice = 0x%x", __FUNCTION__, mStreamAttributeSource->output_devices);
+
+ // debug pcm dump
+ OpenPCMDump(LOG_TAG);
+ // acquire pmic clk
+ mHardwareResourceManager->EnableAudBufClk(true);
+#if defined(MTK_AUDIO_KS)
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmPlayback1);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmPlayback1);
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(SPK_PROTECT_AP_SEQUENCE);
+#else
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmI2S0Dl1Playback);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmI2S0Dl1Playback);
+#endif
+
+ mStreamAttributeTarget.buffer_size = AudioALSADeviceParser::getInstance()->GetPcmBufferSize(pcmindex, PCM_OUT);
+
+#ifdef PLAYBACK_USE_24BITS_ONLY
+ mStreamAttributeTarget.audio_format = AUDIO_FORMAT_PCM_8_24_BIT;
+#else
+ mStreamAttributeTarget.audio_format = (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_32_BIT) ? AUDIO_FORMAT_PCM_8_24_BIT : AUDIO_FORMAT_PCM_16_BIT;
+#endif
+ mStreamAttributeTarget.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ mStreamAttributeTarget.num_channels = popcount(mStreamAttributeTarget.audio_channel_mask);
+
+ mStreamAttributeTarget.sample_rate = ChooseTargetSampleRate(AudioALSASampleRateController::getInstance()->getPrimaryStreamOutSampleRate());
+
+ ALOGD("mStreamAttributeTarget.sample_rate = %d", mStreamAttributeTarget.sample_rate);
+
+#ifdef HIFI_DEEP_BUFFER
+ if (mStreamAttributeTarget.sample_rate <= 48000) {
+ mStreamAttributeTarget.buffer_size = KERNEL_BUFFER_SIZE_DL1_NORMAL;
+ } else if (mStreamAttributeTarget.sample_rate > 48000 && mStreamAttributeTarget.sample_rate <= 96000) {
+ if (mStreamAttributeTarget.buffer_size >= KERNEL_BUFFER_SIZE_DL1_HIFI_96K) {
+ mStreamAttributeTarget.buffer_size = KERNEL_BUFFER_SIZE_DL1_HIFI_96K;
+ }
+ } else {
+ if (mStreamAttributeTarget.buffer_size >= KERNEL_BUFFER_SIZE_DL1_HIFI_192K) {
+ mStreamAttributeTarget.buffer_size = KERNEL_BUFFER_SIZE_DL1_HIFI_192K;
+ }
+ }
+#endif
+
+ // HW pcm config
+ mConfig.channels = mStreamAttributeTarget.num_channels;
+ mConfig.rate = mStreamAttributeTarget.sample_rate;
+
+ if (mStreamAttributeTarget.sample_rate > 16000) {
+
+ mConfig.period_count = 2;
+ mConfig.period_size = (mStreamAttributeTarget.buffer_size / (mConfig.channels * mConfig.period_count)) / ((mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4);
+
+ mConfig.format = transferAudioFormatToPcmFormat(mStreamAttributeTarget.audio_format);
+
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+ ALOGD("%s(), mConfig: channels = %d, rate = %d, period_size = %d, period_count = %d, format = %d",
+ __FUNCTION__, mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mConfig.format);
+ } else { // voice playback , need low latency.
+ mConfig.period_count = 12;
+ mConfig.period_size = 160;
+
+ mConfig.format = transferAudioFormatToPcmFormat(mStreamAttributeTarget.audio_format);
+
+ mConfig.start_threshold = mConfig.period_size * 3;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+ ALOGD("%s(), mConfig: channels = %d, rate = %d, period_size = %d, period_count = %d, format = %d",
+ __FUNCTION__, mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mConfig.format);
+ }
+
+ // post processing
+ initPostProcessing();
+
+ // SRCS_ESTSAMPLERATE
+ initBliSrc();
+
+ // bit conversion
+ initBitConverter();
+
+ initDataPending();
+
+ // init DC Removal
+ initDcRemoval();
+
+ // open pcm driver
+ openPcmDriver(pcmindex);
+
+ // open codec driver
+ if (mStreamAttributeSource->output_devices != AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
+ mHardwareResourceManager->startOutputDevice(mStreamAttributeSource->output_devices, mStreamAttributeTarget.sample_rate);
+ }
+
+
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ VUnlockhdl->SetInputStandBy(false);
+ VUnlockhdl->GetSRCInputParameter(mStreamAttributeTarget.sample_rate, mStreamAttributeTarget.num_channels, mStreamAttributeSource->audio_format);
+ VUnlockhdl->GetFirstDLTime();
+ }
+ //===========================================
+
+ // maxmim init
+ Initmldsconfig(mStreamAttributeSource, &mStreamAttributeTarget);
+ //SpeakerProtectionInit(mStreamAttributeTarget.sample_rate, mStreamAttributeTarget.num_channels, mStreamAttributeTarget.audio_format);
+ SpeakerProtectionInterfaceInit(mStreamAttributeTarget.sample_rate, mStreamAttributeTarget.num_channels, mStreamAttributeTarget.audio_format);
+
+
+ pcm_config mIVConfig;
+ memcpy((void *)&mIVConfig, (void *)&mConfig, sizeof(pcm_config));
+ if (mStreamAttributeTarget.sample_rate > 16000) {
+ mIVConfig.period_size = mIVConfig.period_size >> 1;
+ }
+ ALOGD("%s(), mIVConfig: channels = %d, rate = %d, period_size = %d, period_count = %d, format = %d",
+ __FUNCTION__, mIVConfig.channels, mIVConfig.rate, mIVConfig.period_size, mIVConfig.period_count, mIVConfig.format);
+
+ EnableIVTask(mIVConfig);
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ VUnlockhdl->SetInputStandBy(true);
+ }
+ //===========================================
+
+ if (mStreamAttributeSource->output_devices != AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
+ mHardwareResourceManager->stopOutputDevice();
+ }
+
+ // close pcm driver
+ closePcmDriver();
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(SPK_PROTECT_AP_SEQUENCE);
+#endif
+
+ //DC removal
+ deinitDcRemoval();
+
+ DeinitDataPending();
+
+ // bit conversion
+ deinitBitConverter();
+
+ // SRC
+ deinitBliSrc();
+
+ // post processing
+ deinitPostProcessing();
+
+ // debug pcm dump
+ ClosePCMDump();
+
+ //release pmic clk
+ mHardwareResourceManager->EnableAudBufClk(false);
+
+ //ClosePCMIVDump();
+ DisableIVTask();
+
+ SpeakerProtectionInterfaceDeinit();
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::routing(const audio_devices_t output_devices) {
+ mHardwareResourceManager->changeOutputDevice(output_devices);
+#if !defined(MTK_AURISYS_FRAMEWORK_SUPPORT)
+ if (mAudioFilterManagerHandler) { mAudioFilterManagerHandler->setDevice(output_devices); }
+#endif
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::SpeakerProtectionInterfaceInit(unsigned int SampleRate, unsigned int channels, unsigned int Format) {
+ ALOGD("+%s SampleRate = %d channels = %d Format = %d", __FUNCTION__, SampleRate, channels, Format);
+ unsigned int retCode = 0;
+ int i = 0;
+ retCode = InitmldsInterface();
+ if (dsm_handler == NULL && retCode == NO_ERROR) {
+ //retCode = mlds_query_working_buf_size(mmlds_task_config,&mu4DsmMemSize);
+ retCode = mMlds_Interace_pointer->mlds_query_working_buf_size(mmlds_task_config, &mu4DsmMemSize);
+
+ if (LIB_OK == retCode) {
+ if (dsm_handler == NULL) {
+ dsm_handler = new int[mu4DsmMemSize];
+ memset((void *)dsm_handler, 0, mu4DsmMemSize);
+ retCode = mMlds_Interace_pointer->mlds_create_handler(mmlds_task_config, 0, NULL, 0, NULL, &dsm_handler);
+ ALOGD("- mMlds_Interace_pointer mlds_create_handler dsm_handler = %p", dsm_handler);
+ }
+
+ if (0 == dsm_handler) {
+ ALOGD("dsm_handler new is %p", dsm_handler);
+ }
+ } else {
+ ALOGD("retCode is %d", retCode);
+ }
+ } else {
+ ALOGE("DSM Handle exist = %p", dsm_handler);
+ }
+
+ SpeakerBufferInit();
+ if (dsm_handler) {
+ DsmConfigure(2, dsm_handler);
+ }
+
+ ALOGD("-%s", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::Initmldsconfig(const stream_attribute_t *mStreamAttributeSource, stream_attribute_t *mStreamAttributeTarget) {
+ ALOGD("%s", __FUNCTION__);
+ mmlds_task_config->api_version = 0x01;
+ mmlds_task_config->frame_size_ms = 5;
+ mmlds_task_config->vendor_id = 0x10;
+ mmlds_task_config->task_scene = TASK_SCENE_SPEAKER_PROTECTION;
+
+ // information about dl playback
+ if (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_32_BIT || mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_8_24_BIT) {
+ mmlds_task_config->stream_downlink.bit_format_in = BIT_FORMAT_S32_LE;
+ mmlds_task_config->stream_downlink.bit_format_out = BIT_FORMAT_S32_LE;
+ } else {
+ mmlds_task_config->stream_downlink.bit_format_in = BIT_FORMAT_S16_LE;
+ mmlds_task_config->stream_downlink.bit_format_out = BIT_FORMAT_S16_LE;
+ }
+
+ mmlds_task_config->stream_downlink.num_channels_in = mStreamAttributeTarget->num_channels;
+ mmlds_task_config->stream_downlink.num_channels_out = mStreamAttributeTarget->num_channels;
+
+ mmlds_task_config->stream_downlink.sample_rate_in = mStreamAttributeTarget->sample_rate;
+ mmlds_task_config->stream_downlink.sample_rate_out = mStreamAttributeTarget->sample_rate;
+
+ // only for speaker mode
+ mmlds_task_config->stream_downlink.device = TASK_DEVICE_OUT_SPEAKER;
+ mmlds_task_config->stream_downlink.device_extra_info = 1; // processing channel
+
+ // information about ref buf
+ mmlds_task_config->stream_dl_fbk.bit_format_in = BIT_FORMAT_S16_LE;
+ mmlds_task_config->stream_dl_fbk.bit_format_out = BIT_FORMAT_S16_LE;
+
+ mmlds_task_config->stream_dl_fbk.num_channels_in = 2;
+ mmlds_task_config->stream_dl_fbk.num_channels_out = 2;
+
+ mmlds_task_config->stream_dl_fbk.sample_rate_in = mStreamAttributeTarget->sample_rate;
+ mmlds_task_config->stream_dl_fbk.sample_rate_out = mStreamAttributeTarget->sample_rate;
+
+ mmlds_task_config->stream_downlink.device = TASK_DEVICE_OUT_SPEAKER;
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::SpeakerBufferInit(void) {
+ ALOGD("+%s", __FUNCTION__);
+ if (mDsmpcmOut == NULL) {
+ mDsmpcmOut = new int [mDsmBufferSize];
+ memset((void *)mDsmpcmOut, 0, mDsmBufferSize * sizeof(int));
+ }
+ if (mDsmiData == NULL) {
+ mDsmiData = new int [mDsmBufferSize];
+ memset((void *)mDsmiData, 0, mDsmBufferSize * sizeof(int));
+ }
+ if (mDsmvData == NULL) {
+ mDsmvData = new int [mDsmBufferSize];
+ memset((void *)mDsmvData, 0, mDsmBufferSize * sizeof(int));
+ }
+
+ if (mDsmProcessingbuffer == NULL) {
+ mDsmProcessingbuffer = new int [mDsmBufferSize];
+ memset((void *)mDsmProcessingbuffer, 0, mDsmBufferSize * sizeof(int));
+ }
+
+ if (mDsmIvReadData == NULL) {
+ mDsmIvReadData = new int [mDsmBufferSize];
+ memset((void *)mDsmIvReadData, 0, mDsmBufferSize * sizeof(int));
+ }
+
+ if (mSpeakerChannelProcessingBuffer == NULL) {
+ mSpeakerChannelProcessingBuffer = new int [mDsmBufferSize];
+ memset((void *)mSpeakerChannelProcessingBuffer, 0, mDsmBufferSize * sizeof(int));
+ }
+ ALOGD("-%s", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::SpeakerProtectionInterfaceDeinit() {
+ ALOGD("%s", __FUNCTION__);
+ int retCode = 0;
+ if (dsm_handler != NULL) {
+ retCode = mMlds_Interace_pointer->mlds_destroy_handler(dsm_handler);
+ if (dsm_handler != NULL) {
+ delete[](int *)dsm_handler;
+ dsm_handler = NULL;
+ }
+ }
+
+ if (mDsmMemBuffer) {
+ delete[] mDsmMemBuffer;
+ mDsmMemBuffer = NULL;
+ }
+
+ SpeakerBufferDeInit();
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::SpeakerBufferDeInit(void) {
+ ALOGD("+%s", __FUNCTION__);
+ if (mDsmpcmOut != NULL) {
+ delete []mDsmpcmOut;
+ mDsmpcmOut = NULL;
+ }
+ if (mDsmiData != NULL) {
+ delete []mDsmiData;
+ mDsmiData = NULL;
+ }
+
+ if (mDsmvData != NULL) {
+ delete []mDsmvData;
+ mDsmvData = NULL;
+ }
+
+ if (mDsmProcessingbuffer != NULL) {
+ delete []mDsmProcessingbuffer;
+ mDsmProcessingbuffer = NULL;
+ }
+
+ if (mDsmIvReadData != NULL) {
+ delete []mDsmIvReadData;
+ mDsmIvReadData = NULL;
+ }
+
+ if (mSpeakerChannelProcessingBuffer != NULL) {
+ delete []mSpeakerChannelProcessingBuffer;
+ mSpeakerChannelProcessingBuffer = NULL;
+ }
+
+ ALOGD("-%s", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::setScreenState(bool mode, size_t buffer_size, size_t reduceInterruptSize, bool bforce) {
+ // don't increase irq period when play hifi
+ if (mode == 0 && mStreamAttributeSource->sample_rate > 48000) {
+ return NO_ERROR;
+ }
+
+ if (0 == buffer_size) {
+ buffer_size = mStreamAttributeSource->buffer_size;
+ }
+
+ int rate = mode ? (buffer_size / mStreamAttributeSource->num_channels) / ((mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4) :
+ ((mStreamAttributeTarget.buffer_size >> 1) / mConfig.channels) / ((mStreamAttributeTarget.audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4);
+
+ // check for low latency mode interrupt rate
+ if (mode == true) {
+ int mConfigRate = mConfig.period_count * mConfig.period_size / 2; // at least ping pong
+
+ while ((rate > mConfigRate) && (rate > 0)) {
+ rate = rate / 2 ;
+ }
+ ALOGD("mode = %d rate = %d mConfigRate = %d", mode, rate, mConfigRate);
+ }
+
+ mStreamAttributeTarget.mInterrupt = (rate + 0.0) / mStreamAttributeTarget.sample_rate;
+
+ ALOGD("%s, rate %d %f, mode = %d , buffer_size = %d, channel %d, format%d", __FUNCTION__, rate, mStreamAttributeTarget.mInterrupt, mode, buffer_size, mConfig.channels, mStreamAttributeTarget.audio_format);
+
+ mHardwareResourceManager->setInterruptRate(mStreamAttributeSource->mAudioOutputFlags, rate);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::DoSpeakerProctionPacking(int *pbuffer, int ValidInputBuffersize) {
+ // first copy data to processing buffer with ValidInputBuffersize
+ memcpy((void *)mSpeakerChannelProcessingBuffer, (void *)pbuffer, ValidInputBuffersize);
+ int *ppostProcessingL = pbuffer;
+ int *ppostProcessingR = (int *)((char *)pbuffer + (ValidInputBuffersize / 2));
+ int *pTempprocessingBuffer = mSpeakerChannelProcessingBuffer;
+
+
+ while (ValidInputBuffersize > 0) {
+ *ppostProcessingL = *pTempprocessingBuffer;
+ ppostProcessingL++;
+ pTempprocessingBuffer++;
+ *ppostProcessingR = *pTempprocessingBuffer;
+ ppostProcessingR++;
+ pTempprocessingBuffer++;
+ ValidInputBuffersize -= 8;
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::MonoToStereo(int *pbuffer, int ValidInputBuffersize) {
+ if (DSM_CHANNELS == 2) {
+ return NO_ERROR;
+ }
+
+ int *pTempprocessingBuffer = pbuffer + 1;
+
+ while (ValidInputBuffersize > 0) {
+ *pTempprocessingBuffer = *pbuffer;
+ pTempprocessingBuffer += 2;
+ pbuffer += 2;
+ ValidInputBuffersize -= 8;
+ }
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::DoSpeakerProctionUnPacking(int *pbuffer, int ValidInputBuffersize) {
+ memcpy((void *)mSpeakerChannelProcessingBuffer, (void *)pbuffer, ValidInputBuffersize);
+ int *ppostProcessingL = mSpeakerChannelProcessingBuffer;
+ int *ppostProcessingR = (int *)((char *)mSpeakerChannelProcessingBuffer + (ValidInputBuffersize / 2));
+ int *pTempprocessingBuffer = pbuffer;
+
+ /*
+ ALOGD("%s ValidInputBuffersize =%d ppostProcessingR = % pppostProcessingL = %p Dsmtempbuffer = %p",
+ __FUNCTION__,ValidInputBuffersize,ppostProcessingR,ppostProcessingL,pbuffer);*/
+
+ while (ValidInputBuffersize > 0) {
+ *pTempprocessingBuffer = *ppostProcessingL;
+ pTempprocessingBuffer++;
+ ppostProcessingL++;
+ *pTempprocessingBuffer = *ppostProcessingR;
+ pTempprocessingBuffer++;
+ ppostProcessingR++;
+ ValidInputBuffersize -= 8;
+ }
+ return NO_ERROR;
+}
+
+// here using android define format
+unsigned int AudioALSAPlaybackHandlerSpeakerProtection::GetSampleSize(unsigned int Format) {
+ unsigned returnsize = 2;
+ if (Format == AUDIO_FORMAT_PCM_16_BIT) {
+ returnsize = 2;
+ } else if (Format == AUDIO_FORMAT_PCM_32_BIT || Format == AUDIO_FORMAT_PCM_8_24_BIT) {
+ returnsize = 4;
+ } else if (Format == AUDIO_FORMAT_PCM_8_BIT) {
+ returnsize = 1;
+ } else {
+ ALOGD("%s Format == %d", __FUNCTION__, Format);
+ }
+ return returnsize;
+}
+
+// here using android define format
+unsigned int AudioALSAPlaybackHandlerSpeakerProtection::GetFrameSize(unsigned int channels, unsigned int Format) {
+ unsigned returnsize = 2;
+ if (Format == AUDIO_FORMAT_PCM_16_BIT) {
+ returnsize = 2;
+ } else if (Format == AUDIO_FORMAT_PCM_32_BIT || Format == AUDIO_FORMAT_PCM_8_24_BIT) {
+ returnsize = 4;
+ } else if (Format == AUDIO_FORMAT_PCM_8_BIT) {
+ returnsize = 1;
+ } else {
+ ALOGD("%s Format = %d", __FUNCTION__, Format);
+ }
+ returnsize *= channels;
+ return returnsize;;
+}
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::DoSpeakerProtionInterfaceProcessing(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes) {
+ //ALOGD("+%s", __FUNCTION__);
+ if (mBypassSpeakerProtection == false) {
+ unsigned int outSize = mDsmBufferSize;
+ unsigned int IVSize = inBytes / GetFrameSize(mStreamAttributeTarget.num_channels, mStreamAttributeTarget.audio_format);
+ IVSize *= GetFrameSize(mStreamAttributeTarget.num_channels, AUDIO_FORMAT_PCM_16_BIT);
+ int retcode = 0;
+
+ if (dsm_handler != NULL) { // do processing
+ IVSize = mAudioAlsaPcmIn->read(mDsmIvReadData, IVSize);
+ uint32_t InbyteTemp = inBytes;
+ /*
+ ALOGD("+mlds_process_dl_buf mDsmpcmOut = %p mDsmIvReadData = %p outSize = %d inBytes = %d",
+ mDsmpcmOut,mDsmIvReadData, outSize,inBytes);
+ */
+ retcode = mMlds_Interace_pointer->mlds_process_dl_buf(
+ pInBuffer,
+ &inBytes,
+ mDsmpcmOut,
+ &outSize,
+ mDsmIvReadData,
+ &IVSize,
+ &dsm_handler,
+ NULL);
+ //ALOGD("-mlds_process_dl_buf mDsmpcmOut = %p mDsmIvReadData = %p outSize = %d retcode = %d", mDsmpcmOut, mDsmIvReadData, outSize,retcode);
+ if (retcode == LIB_OK) {
+ *ppOutBuffer = mDsmpcmOut;
+ *pOutBytes = outSize;
+ } else {
+ //ALOGD("-mlds_process_dl_buf ppOutBuffer = %p pOutBytes %d", ppOutBuffer,*pOutBytes);
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = InbyteTemp;
+ }
+ } else {
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ }
+ } else {
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ }
+ //ALOGD("-%s outSize = %d *ppOutBuffer = %p", __FUNCTION__, outSize , *ppOutBuffer);
+ ASSERT(*ppOutBuffer != NULL && *pOutBytes != 0);
+ return NO_ERROR;
+}
+
+
+ssize_t AudioALSAPlaybackHandlerSpeakerProtection::write(const void *buffer, size_t bytes) {
+ //ALOGD("%s(), buffer = %p, bytes = %d", __FUNCTION__, buffer, bytes);
+
+ if (mPcm == NULL) {
+ ALOGE("%s(), mPcm == NULL, return", __FUNCTION__);
+ return bytes;
+ }
+
+ // const -> to non const
+ void *pBuffer = const_cast<void *>(buffer);
+ ASSERT(pBuffer != NULL);
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[0] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+
+ void *pBufferAfterDcRemoval = NULL;
+ uint32_t bytesAfterDcRemoval = 0;
+ // DC removal before DRC
+ doDcRemoval(pBuffer, bytes, &pBufferAfterDcRemoval, &bytesAfterDcRemoval);
+
+ doStereoToMonoConversionIfNeed(pBufferAfterDcRemoval, bytesAfterDcRemoval);
+
+ // post processing (can handle both Q1P16 and Q1P31 by audio_format_t)
+ void *pBufferAfterPostProcessing = NULL;
+ uint32_t bytesAfterPostProcessing = 0;
+ doPostProcessing(pBufferAfterDcRemoval, bytesAfterDcRemoval, &pBufferAfterPostProcessing, &bytesAfterPostProcessing);
+
+ // SRC
+ void *pBufferAfterBliSrc = NULL;
+ uint32_t bytesAfterBliSrc = 0;
+ doBliSrc(pBufferAfterPostProcessing, bytesAfterPostProcessing, &pBufferAfterBliSrc, &bytesAfterBliSrc);
+
+ //
+ void *pBufferPostProcessing = NULL;
+ uint32_t bytesAfterpostprocessings = 0;
+ //DoSpeakerProtionProcessing(pBufferAfterBliSrc, bytesAfterBliSrc, &pBufferPostProcessing, &bytesAfterpostprocessings);
+ DoSpeakerProtionInterfaceProcessing(pBufferAfterBliSrc, bytesAfterBliSrc, &pBufferPostProcessing, &bytesAfterpostprocessings);
+ //ALOGD("DoSpeakerProtionInterfaceProcessing bytesAfterBliSrc = %d bytesAfterpostprocessings = %d", bytesAfterBliSrc, bytesAfterpostprocessings);
+
+ // pcm dump
+ WritePcmDumpData(pBufferPostProcessing, bytesAfterpostprocessings);
+
+ // bit conversion
+ void *pBufferAfterBitConvertion = NULL;
+ uint32_t bytesAfterBitConvertion = 0;
+ doBitConversion(pBufferPostProcessing, bytesAfterpostprocessings, &pBufferAfterBitConvertion, &bytesAfterBitConvertion);
+
+ // data pending
+ void *pBufferAfterPending = NULL;
+ uint32_t bytesAfterpending = 0;
+ dodataPending(pBufferAfterBitConvertion, bytesAfterBitConvertion, &pBufferAfterPending, &bytesAfterpending);
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[1] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+
+ // write data to pcm driver
+ int retval = pcm_write(mPcm, pBufferAfterPending, bytesAfterpending);
+
+ updateHardwareBufferInfo(bytes, bytesAfterpending);
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[2] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+
+#if 1 // TODO(Harvey, Wendy), temporary disable Voice Unlock until 24bit ready
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ // get remain time
+ //VUnlockhdl->SetDownlinkStartTime(ret_ms);
+ VUnlockhdl->GetFirstDLTime();
+
+ //VUnlockhdl->SetInputStandBy(false);
+ if (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+ mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+ memset((void *)pBufferAfterBliSrc, 0, bytesAfterBliSrc);
+ }
+ VUnlockhdl->WriteStreamOutToRing(pBufferAfterBliSrc, bytesAfterBliSrc);
+ }
+ //===========================================
+#endif
+
+
+ if (retval != 0) {
+ ALOGE("%s(), pcm_write() error, retval = %d", __FUNCTION__, retval);
+ }
+
+#ifdef DEBUG_LATENCY
+ ALOGD("%s ::write (-) latency_in_us,%1.6lf,%1.6lf,%1.6lf", __FUNCTION__, latencyTime[0], latencyTime[1], latencyTime[2]);
+#endif
+
+ return bytes;
+}
+
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::setFilterMng(AudioMTKFilterManager *pFilterMng) {
+ ALOGD("+%s() mAudioFilterManagerHandler [0x%x]", __FUNCTION__, pFilterMng);
+ mAudioFilterManagerHandler = pFilterMng;
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::CopyIVbuffer(void *InputBuffert, short *Rbuffer, short *Lbuffer, unsigned int samplecount) {
+ short *pTemp = (short *)InputBuffert;
+ //ALOGD("samplecount = %d",samplecount);
+ while (samplecount > 0) {
+ *Rbuffer++ = *pTemp++;
+ *Lbuffer++ = *pTemp++;
+ samplecount--;
+ }
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::EnableIVTask(pcm_config mPcm_config) {
+ ASSERT(mAudioAlsaPcmIn != NULL);
+
+ /*
+ ALOGD("%s mPcm_config period_size = %d rate = %d period_count = %d", __FUNCTION__,
+ mPcm_config.period_size, mPcm_config.rate, mPcm_config.period_count);
+ */
+
+ // settting for IV config setting
+ mPcmIvConfig.channels = mPcm_config.channels;
+ mPcmIvConfig.format = mPcm_config.format;
+ mPcmIvConfig.rate = mPcm_config.rate;
+ if (mPcmIvConfig.rate == 16000) {
+ mPcmIvConfig.period_count = 8;
+ mPcmIvConfig.period_size = 256;
+ } else {
+ mPcmIvConfig.period_count = 2;
+ mPcmIvConfig.period_size = 1024;
+ }
+ mPcmIvConfig.start_threshold = 0;
+ mPcmIvConfig.stop_threshold = 0;
+ mPcmIvConfig.silence_threshold = 0;
+
+ mAudioAlsaPcmIn->SetPcmConfig(mPcmIvConfig);
+ mAudioAlsaPcmIn->SetThreadEnable();
+ ALOGD("-%s period_size = %d rate = %d period_count = %d", __FUNCTION__,
+ mPcmIvConfig.period_size, mPcmIvConfig.rate, mPcmIvConfig.period_count);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSpeakerProtection::DisableIVTask(void) {
+ if (mAudioAlsaPcmIn != NULL) {
+ mAudioAlsaPcmIn->SetThreadDisable();
+ }
+ ALOGD("-%s", __func__);
+
+ return NO_ERROR;
+}
+
+// using dl to do function open
+status_t AudioALSAPlaybackHandlerSpeakerProtection::InitmldsInterface() {
+ ALOGD("%s", __FUNCTION__);
+
+ //ALOGD("dlopen %s", SPEAKER_LIB_PATH);
+ mMlds_handle = dlopen(SPEAKER_LIB_PATH, RTLD_NOW);
+ //ALOGD("dlopen %s", SPEAKER_CONFIGPARSER_LIB_PATH);
+ mDsmConfigHandle = dlopen(SPEAKER_CONFIGPARSER_LIB_PATH, RTLD_NOW);
+ //ALOGD("dlopen %s", DSM_LIB_PATH);
+ mDsmInterfaceHandle = dlopen(DSM_LIB_PATH, RTLD_NOW);
+
+ if (mMlds_handle == NULL || mDsmConfigHandle == NULL || mDsmInterfaceHandle == NULL) {
+ ALOGD("%s err, mMlds_handle = %p, mDsmConfigHandle = %p, mDsmInterfaceHandle = %p\n", __FUNCTION__,
+ mMlds_handle, mDsmConfigHandle, mDsmInterfaceHandle);
+ return INVALID_OPERATION;
+ }
+
+ mMlds_Interace_pointer->mlds_query_working_buf_size = (lib_status_t (*)(const mlds_task_config_t *, uint32_t *))dlsym(mMlds_handle, "mlds_query_working_buf_size");
+ mMlds_Interace_pointer->mlds_create_handler = (lib_status_t (*)(
+ const mlds_task_config_t *p_mlds_task_config,
+ const uint32_t param_buf_size,
+ void *p_param_buf,
+ const uint32_t working_buf_size,
+ void *p_working_buf,
+ void **pp_handler))dlsym(mMlds_handle, "mlds_create_handler");
+ mMlds_Interace_pointer->mlds_process_dl_buf = (lib_status_t (*)(
+ void *p_dl_buf_in,
+ uint32_t *InSize,
+ void *p_dl_buf_out,
+ uint32_t *OutSize,
+ void *p_ref_buf,
+ uint32_t *RefBufSize,
+ void *p_handler,
+ void *arg))dlsym(mMlds_handle, "mlds_process_dl_buf");
+ mMlds_Interace_pointer->mlds_destroy_handler = (lib_status_t (*)(void *p_handler))dlsym(mMlds_handle, "mlds_destroy_handler");
+
+ DsmConfigure = (void (*)(int usecase, void *dsm_handler))dlsym(mDsmConfigHandle, "dsm_configure");
+ if (DsmConfigure == NULL) {
+ ALOGW("%s(), DsmConfigure dlsym failed, dlerror = %s", __func__);
+ }
+ DsmSetParams = (unsigned int (*)(void *ipModuleHandler, int iCommandNumber, void *ipParamsBuffer))dlsym(mDsmInterfaceHandle, "DSM_API_Set_Params");
+ if (DsmSetParams == NULL) {
+ ALOGW("%s(), DsmSetParams dlsym failed, dlerror = %s", __func__);
+ }
+ DsmGetParams = (unsigned int (*)(void *ipModuleHandler, int iCommandNum, void *opParams))dlsym(mDsmInterfaceHandle, "DSM_API_Get_Params");
+ if (DsmGetParams == NULL) {
+ ALOGW("%s(), DsmGetParams dlsym failed, dlerror = %s", __func__);
+ }
+
+ return NO_ERROR;
+}
+
+void AudioALSAPlaybackHandlerSpeakerProtection::OpenPCMIVDump(const char *class_name) {
+ ALOGD("%s()", __FUNCTION__);
+ char mDumpFileName[128];
+ sprintf(mDumpFileName, "%s.%d.%s.pcm", streaminIVCPMIn, mDumpPlayIVFileNum, class_name);
+
+ mPCMPlayIVDumpFile = AudioOpendumpPCMFile(mDumpFileName, streamin_propty);
+
+ if (strlen(mDumpFileName) != 0) {
+ ALOGD("%s DumpFileName = %s", __FUNCTION__, mDumpFileName);
+ mDumpPlayIVFileNum++;
+ mDumpPlayIVFileNum %= MAX_DUMP_NUM;
+ }
+}
+
+void AudioALSAPlaybackHandlerSpeakerProtection::ClosePCMIVDump() {
+ ALOGD("%s()", __FUNCTION__);
+ if (mPCMPlayIVDumpFile) {
+ AudioCloseDumpPCMFile(mPCMPlayIVDumpFile);
+ mPCMPlayIVDumpFile = NULL;
+ ALOGD("%s(), close it", __FUNCTION__);
+ }
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerSphDL.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerSphDL.cpp
new file mode 100644
index 0000000..ea7f9a4
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerSphDL.cpp
@@ -0,0 +1,940 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <math.h>
+#include <dlfcn.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
+#include <utils/threads.h>
+#include <dlfcn.h>
+
+#include "AudioALSAPlaybackHandlerSphDL.h"
+#include "AudioALSAHardwareResourceManager.h"
+#include "AudioVolumeFactory.h"
+#include "AudioMTKFilter.h"
+#include "AudioVUnlockDL.h"
+#include "AudioALSADeviceParser.h"
+#include "AudioALSADriverUtility.h"
+
+#include <mlds_api.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSAPlaybackHandlerSphDL"
+
+// define this to by pass processing
+//#define BY_PASS_PROCESSING
+
+/*
+* need add config for DSM lib
+*/
+
+#include "dsm_api.h"
+#include "dsm_api_types.h".
+#include <dsm_config_parser.h>
+extern "C" {
+#include <cutils/str_parms.h>
+#include <cutils/hashmap.h>
+#include <cutils/memory.h>
+#include <log/log.h>
+#include <cutils/properties.h>
+}
+
+#define SPEAKER_LIB_PATH ("/system/lib/libdsm_interface.so")
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+static const char* PROPERTY_KEY_EXTDAC = "vendor.audiohal.resource.extdac.support";
+
+namespace android {
+
+AudioALSAPlaybackHandlerSphDL::AudioALSAPlaybackHandlerSphDL(const stream_attribute_t *stream_attribute_source) :
+ AudioALSAPlaybackHandlerBase(stream_attribute_source) {
+ ALOGD("%s()", __FUNCTION__);
+ mPlaybackHandlerType = PLAYBACK_HANDLER_SPEAKERPROTECTION;
+ mDumpPlayIVFileNum = 0;
+ mDsmpcmOut = NULL;
+ mDsmpcmIn = NULL;
+ mDsmiData = NULL;
+ mDsmvData = NULL;
+ mSpeakerChannelProcessingBuffer = NULL;
+ mDsmProcessingbuffer = NULL;
+ mDsmIvReadData = NULL;
+ mPCMPlayIVDumpFile = NULL;
+ dsm_handler = NULL;
+ mDsmMemBuffer = NULL;
+ memset((void *)&mMlds_Interace_pointer, 0, sizeof(mlds_interface));
+ mMlds_handle = NULL;
+
+ mmlds_task_config = (mlds_task_config_t *)malloc(sizeof(mlds_task_config_t));
+ ASSERT(mmlds_task_config != NULL);
+ memset((void *)mmlds_task_config, 0, sizeof(mlds_task_config_t));
+
+ mMlds_Interace_pointer = (mlds_interface *)malloc(sizeof(mlds_interface));
+ ASSERT(mMlds_Interace_pointer != NULL);
+ memset((void *)mMlds_Interace_pointer, 0, sizeof(mlds_interface));
+}
+
+
+AudioALSAPlaybackHandlerSphDL::~AudioALSAPlaybackHandlerSphDL() {
+ ALOGD("%s()", __FUNCTION__);
+
+ if (mmlds_task_config != NULL) {
+ free(mmlds_task_config);
+ }
+
+ if (mMlds_Interace_pointer != NULL) {
+ free(mMlds_Interace_pointer);
+ }
+}
+
+uint32_t AudioALSAPlaybackHandlerSphDL::ChooseTargetSampleRate(uint32_t SampleRate, audio_devices_t outputdevice) {
+ ALOGD("ChooseTargetSampleRate SampleRate = %d outputdevice = %d", SampleRate, outputdevice);
+ uint32_t TargetSampleRate = 16000;
+ return TargetSampleRate;
+}
+
+#ifdef MTK_MAXIM_SPEAKER_SUPPORT
+static int audio_get_parameters(struct str_parms *query,
+ struct str_parms *reply, int *param, void *dsm_handler) {
+ int ret, val;
+ char value[32] = {0};
+ char *str = NULL;
+
+#define AUDIO_DSM_PARAMETER "DSM"
+ ret = str_parms_get_str(query, AUDIO_DSM_PARAMETER, value,
+ sizeof(value));
+ if (ret >= 0) {
+ ret = DSM_API_Get_Params(dsm_handler, 1, param);
+ if (DSM_API_OK != ret) {
+ ALOGE("%s: DSM get params failed", __func__);
+ }
+ ALOGE("%s: DSM get params %d", __func__, param[1]);
+ str_parms_add_int(reply, AUDIO_DSM_PARAMETER, param[1]);
+ }
+
+ return 0;
+}
+
+static void audio_extn_dsm_parameters(struct str_parms *query,
+ struct str_parms *reply, int *param, void *dsm_handler) {
+ char *kv_pairs = NULL;
+ audio_get_parameters(query, reply, param, dsm_handler);
+
+ kv_pairs = str_parms_to_str(reply);
+ ALOGD_IF(kv_pairs != NULL, "%s: returns %s", __func__, kv_pairs);
+ free(kv_pairs);
+}
+
+status_t AudioALSAPlaybackHandlerSphDL::setParameters(const String8 &keyValuePairs) {
+ ALOGD("%s %s", __FUNCTION__, keyValuePairs.string());
+ struct str_parms *parms = NULL;
+ char *str;
+ char value[32];
+ int val;
+ int ret = 0, err;
+ parms = str_parms_create_str(keyValuePairs.string());
+
+ {
+ int param[4];
+ /*parse the id and value*/
+ err = str_parms_get_str(parms, "DSM", value, sizeof(value));
+ if (err >= 0) {
+ char *id, *cp, *ptr;
+ const char delimiters[] = " ";
+ double ret;
+
+ cp = strdup(value);
+ id = strtok(cp, delimiters);
+ param[2 * 0] = strtol(id, NULL, 10);
+ id = strtok(NULL, delimiters);
+ ret = strtod(id, &ptr);
+ param[2 * 0 + 1] = ret;
+ ALOGD("param[1] = %d", param[1]);
+ err = DSM_API_Set_Params(dsm_handler, 1, param);
+ if (DSM_API_OK != err) {
+ ALOGE("%s: DSM set params failed err = %d", __func__, err);
+ }
+ free(cp);
+ }
+ }
+ ALOGD("-%s %s", __FUNCTION__, keyValuePairs.string());
+ return NO_ERROR;
+}
+#else
+status_t AudioALSAPlaybackHandlerSphDL::setParameters(const String8 &keyValuePairs) {
+ ALOGD("%s %s", __FUNCTION__, keyValuePairs.string());
+ return NO_ERROR;
+}
+#endif
+
+#ifdef MTK_MAXIM_SPEAKER_SUPPORT
+
+String8 AudioALSAPlaybackHandlerSphDL::getParameters(const String8 &keys) {
+ ALOGD("%s %s", __FUNCTION__, keys.string());
+ struct str_parms *reply = str_parms_create();
+ struct str_parms *query = str_parms_create_str(keys.string());
+ char *str = NULL;
+
+ {
+ ALOGE("%s: enter: %s", __func__, keys.string());
+ int param[4], err;
+ char value[32], *id;
+ /*parse the id and value*/
+ err = str_parms_get_str(query, "DSM", value, sizeof(value));
+ if (err >= 0) {
+ char *id, *cp, *ptr;
+ const char delimiters[] = " ";
+ double ret;
+
+ cp = strdup(value);
+ id = strtok(cp, delimiters);
+ param[0] = strtol(id, NULL, 10);
+ ALOGE("%s: param %d id = %s", __func__, param[0], id);
+ free(cp);
+ }
+ ALOGD("%s , dsm_handler = %p", __FUNCTION__, dsm_handler);
+ audio_extn_dsm_parameters(query, reply, param, dsm_handler);
+ }
+ str = str_parms_to_str(reply);
+ str_parms_destroy(query);
+ str_parms_destroy(reply);
+
+ ALOGE("-%s: enter", __func__);
+ String8 ReturnValue(str);
+ return ReturnValue;
+}
+#else
+String8 AudioALSAPlaybackHandlerSphDL::getParameters(const String8 &keys) {
+ ALOGD("%s %s", __FUNCTION__, keys.string());
+ struct str_parms *reply = str_parms_create();
+ struct str_parms *query = str_parms_create_str(keys.string());
+ char *str = NULL;
+ String8 ReturnValue(str);
+ return ReturnValue;
+}
+#endif
+
+status_t AudioALSAPlaybackHandlerSphDL::open() {
+ ALOGD("+%s(), mDevice = 0x%x", __FUNCTION__, mStreamAttributeSource->output_devices);
+
+ // debug pcm dump
+ OpenPCMDump(LOG_TAG);
+
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ // acquire pmic clk
+ mHardwareResourceManager->EnableAudBufClk(true);
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmExtSpkMeida);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmExtSpkMeida);
+
+ ALOGD("AudioALSAPlaybackHandlerSphDL::open() pcmindex = %d", pcmindex);
+ //ListPcmDriver(cardindex, pcmindex);
+
+ struct pcm_params *params;
+ params = pcm_params_get(cardindex, pcmindex, PCM_OUT);
+ if (params == NULL) {
+ ALOGD("Device does not exist.\n");
+ }
+ mStreamAttributeTarget.buffer_size = pcm_params_get_max(params, PCM_PARAM_BUFFER_BYTES);
+ pcm_params_free(params);
+
+ // HW attribute config // TODO(Harvey): query this
+#ifdef PLAYBACK_USE_24BITS_ONLY
+ mStreamAttributeTarget.audio_format = AUDIO_FORMAT_PCM_8_24_BIT;
+#else
+ mStreamAttributeTarget.audio_format = (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_32_BIT) ? AUDIO_FORMAT_PCM_8_24_BIT :
+ AUDIO_FORMAT_PCM_16_BIT;
+#endif
+ mStreamAttributeTarget.audio_channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ mStreamAttributeTarget.num_channels = popcount(mStreamAttributeTarget.audio_channel_mask);
+
+ mStreamAttributeTarget.sample_rate = ChooseTargetSampleRate(mStreamAttributeSource->sample_rate, mStreamAttributeSource->output_devices);
+
+ ALOGD("mStreamAttributeTarget.sample_rate = %d", mStreamAttributeTarget.sample_rate);
+
+ // HW pcm config
+ mConfig.channels = mStreamAttributeTarget.num_channels;
+ mConfig.rate = mStreamAttributeTarget.sample_rate;
+
+ if (mStreamAttributeTarget.sample_rate > 16000) {
+
+ // Buffer size: 1536(period_size) * 2(ch) * 4(byte) * 2(period_count) = 24 kb
+ mConfig.period_count = 2;
+ mConfig.period_size = (mStreamAttributeTarget.buffer_size / (mConfig.channels * mConfig.period_count)) / ((mStreamAttributeTarget.
+ audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4);
+
+ mConfig.format = transferAudioFormatToPcmFormat(mStreamAttributeTarget.audio_format);
+
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+ ALOGD("%s(), mConfig: channels = %d, rate = %d, period_size = %d, period_count = %d, format = %d",
+ __FUNCTION__, mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mConfig.format);
+ } else { // voice playback , need low latency.
+ mConfig.period_count = 8;
+ mConfig.period_size = 256;
+
+ mConfig.format = transferAudioFormatToPcmFormat(mStreamAttributeTarget.audio_format);
+
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+ ALOGD("%s(), mConfig: channels = %d, rate = %d, period_size = %d, period_count = %d, format = %d",
+ __FUNCTION__, mConfig.channels, mConfig.rate, mConfig.period_size, mConfig.period_count, mConfig.format);
+
+ }
+
+ // post processing
+ initPostProcessing();
+
+ // SRCS_ESTSAMPLERATE
+ initBliSrc();
+
+ // bit conversion
+ initBitConverter();
+
+ initDataPending();
+
+ // init DC Removal
+ initDcRemoval();
+
+ // open pcm driver
+ openPcmDriver(pcmindex);
+
+ // open codec driver
+ if (mStreamAttributeSource->output_devices != AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
+ mHardwareResourceManager->startOutputDevice(mStreamAttributeSource->output_devices, mStreamAttributeTarget.sample_rate);
+ }
+
+
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ VUnlockhdl->SetInputStandBy(false);
+ VUnlockhdl->GetSRCInputParameter(mStreamAttributeTarget.sample_rate, mStreamAttributeTarget.num_channels, mStreamAttributeTarget.
+ audio_format);
+ VUnlockhdl->GetFirstDLTime();
+ }
+ //===========================================
+
+ // maxmim init
+ Initmldsconfig(mStreamAttributeSource, &mStreamAttributeTarget);
+ //SpeakerProtectionInit(mStreamAttributeTarget.sample_rate, mStreamAttributeTarget.num_channels, mStreamAttributeTarget.audio_format);
+ SpeakerProtectionInterfaceInit(mStreamAttributeTarget.sample_rate, mStreamAttributeTarget.num_channels, mStreamAttributeTarget.audio_format);
+#ifndef BY_PASS_PROCESSING
+ EnableIVTask(mConfig);
+ OpenPCMIVDump("PlayBackNormalIVBuffer");
+#endif
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerSphDL::close() {
+ ALOGD("+%s()", __FUNCTION__);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ VUnlockhdl->SetInputStandBy(true);
+ }
+ //===========================================
+
+
+ // close codec driver
+ if (mStreamAttributeSource->output_devices != AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
+ mHardwareResourceManager->stopOutputDevice();
+ }
+
+ //DC removal
+ deinitDcRemoval();
+
+ // close pcm driver
+ closePcmDriver();
+
+ DeinitDataPending();
+
+ // bit conversion
+ deinitBitConverter();
+
+ // SRC
+ deinitBliSrc();
+
+ // post processing
+ deinitPostProcessing();
+
+ // debug pcm dump
+ ClosePCMDump();
+
+ //release pmic clk
+ mHardwareResourceManager->EnableAudBufClk(false);
+
+#ifndef BY_PASS_PROCESSING
+ ClosePCMIVDump();
+ DisableIVTask();
+#endif
+
+ SpeakerProtectionInterfaceDeinit();
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerSphDL::routing(const audio_devices_t output_devices) {
+ mHardwareResourceManager->changeOutputDevice(output_devices);
+#if !defined(MTK_AURISYS_FRAMEWORK_SUPPORT)
+ if (mAudioFilterManagerHandler) { mAudioFilterManagerHandler->setDevice(output_devices); }
+#endif
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSphDL::SpeakerProtectionInterfaceInit(unsigned int SampleRate, unsigned int channels, unsigned int Format) {
+ ALOGD("+%s SampleRate = %d channels = %d Format = %d", __FUNCTION__, SampleRate, channels, Format);
+ unsigned int retCode = 0;
+ int i = 0;
+ InitmldsInterface();
+ if (dsm_handler == NULL) {
+ //retCode = mlds_query_working_buf_size(mmlds_task_config,&mu4DsmMemSize);
+ retCode = mMlds_Interace_pointer->mlds_query_working_buf_size(mmlds_task_config, &mu4DsmMemSize);
+
+ if (LIB_OK == retCode) {
+ if (dsm_handler == NULL) {
+ dsm_handler = new int[mu4DsmMemSize];
+ ALOGD("mMlds_Interace_pointer dsm_handler = %p", dsm_handler);
+ //retCode = mlds_create_handler(mmlds_task_config,0,NULL,0,NULL,&dsm_handler);
+ retCode = mMlds_Interace_pointer->mlds_create_handler(mmlds_task_config, 0, NULL, 0, NULL, &dsm_handler);
+ ALOGD("- mMlds_Interace_pointer mlds_create_handler dsm_handler = %p", dsm_handler);
+ }
+
+ if (0 == dsm_handler) {
+ ALOGD("dsm_handler new is %p", dsm_handler);
+ }
+ } else {
+ ALOGD("retCode is dp", retCode);
+ }
+ } else {
+ ALOGE("DSM Handle exist = %p", dsm_handler);
+ }
+
+ SpeakerBufferInit();
+ //dsm_configure(2, dsm_handler);
+
+ ALOGD("-%s", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSphDL::Initmldsconfig(const stream_attribute_t *mStreamAttributeSource, stream_attribute_t *mStreamAttributeTarget) {
+ ALOGD("%s", __FUNCTION__);
+ mmlds_task_config->api_version = 0x01;
+ mmlds_task_config->frame_size_ms = 5;
+ mmlds_task_config->vendor_id = 0x10;
+ mmlds_task_config->task_scene = TASK_SCENE_SPEAKER_PROTECTION;
+
+ // information about dl playback
+ if (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_32_BIT || mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_8_24_BIT) {
+ mmlds_task_config->stream_downlink.bit_format_in = BIT_FORMAT_S32_LE;
+ mmlds_task_config->stream_downlink.bit_format_out = BIT_FORMAT_S32_LE;
+ } else {
+ mmlds_task_config->stream_downlink.bit_format_in = BIT_FORMAT_S16_LE;
+ mmlds_task_config->stream_downlink.bit_format_out = BIT_FORMAT_S16_LE;
+ }
+
+ mmlds_task_config->stream_downlink.num_channels_in = mStreamAttributeTarget->num_channels;
+ mmlds_task_config->stream_downlink.num_channels_out = mStreamAttributeTarget->num_channels;
+
+ mmlds_task_config->stream_downlink.sample_rate_in = mStreamAttributeTarget->sample_rate;
+ mmlds_task_config->stream_downlink.sample_rate_out = mStreamAttributeTarget->sample_rate;
+
+ // only for speaker mode
+ mmlds_task_config->stream_downlink.device = TASK_DEVICE_OUT_SPEAKER;
+ mmlds_task_config->stream_downlink.device_extra_info = 1; // processing channel
+
+ // information about ref buf
+ mmlds_task_config->stream_dl_fbk.bit_format_in = BIT_FORMAT_S16_LE;
+ mmlds_task_config->stream_dl_fbk.bit_format_out = BIT_FORMAT_S16_LE;
+
+ mmlds_task_config->stream_dl_fbk.num_channels_in = 2;
+ mmlds_task_config->stream_dl_fbk.num_channels_out = 2;
+
+ mmlds_task_config->stream_dl_fbk.sample_rate_in = mStreamAttributeTarget->sample_rate;
+ mmlds_task_config->stream_dl_fbk.sample_rate_out = mStreamAttributeTarget->sample_rate;
+
+ mmlds_task_config->stream_downlink.device = TASK_DEVICE_OUT_SPEAKER;
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSphDL::SpeakerBufferInit(void) {
+ ALOGD("+%s", __FUNCTION__);
+ if (mDsmpcmIn == NULL) {
+ mDsmpcmIn = new int [mDsmBufferSize];
+ memset((void *)mDsmpcmIn, 0, mDsmBufferSize * sizeof(int));
+ ALOGD("%s new mDsmpcmIn = %p", __FUNCTION__, mDsmpcmIn);
+ }
+ if (mDsmpcmOut == NULL) {
+ mDsmpcmOut = new int [mDsmBufferSize];
+ memset((void *)mDsmpcmOut, 0, mDsmBufferSize * sizeof(int));
+ ALOGD("%s new mDsmpcmOut = %p", __FUNCTION__, mDsmpcmOut);
+ }
+ if (mDsmiData == NULL) {
+ mDsmiData = new int [mDsmBufferSize];
+ memset((void *)mDsmiData, 0, mDsmBufferSize * sizeof(int));
+ ALOGD("%s new mDsmiData = %p", __FUNCTION__, mDsmiData);
+ }
+ if (mDsmvData == NULL) {
+ mDsmvData = new int [mDsmBufferSize];
+ memset((void *)mDsmvData, 0, mDsmBufferSize * sizeof(int));
+ ALOGD("%s new mDsmvData = %p", __FUNCTION__, mDsmvData);
+ }
+
+ if (mDsmProcessingbuffer == NULL) {
+ mDsmProcessingbuffer = new int [mDsmBufferSize];
+ memset((void *)mDsmProcessingbuffer, 0, mDsmBufferSize * sizeof(int));
+ ALOGD("%s new mDsmProcessingbuffer = %p", __FUNCTION__, mDsmProcessingbuffer);
+ }
+
+ if (mDsmIvReadData == NULL) {
+ mDsmIvReadData = new int [mDsmBufferSize];
+ memset((void *)mDsmIvReadData, 0, mDsmBufferSize * sizeof(int));
+ ALOGD("%s new mDsmIvReadData = %p", __FUNCTION__, mDsmIvReadData);
+ }
+
+ if (mSpeakerChannelProcessingBuffer == NULL) {
+ mSpeakerChannelProcessingBuffer = new int [mDsmBufferSize];
+ memset((void *)mSpeakerChannelProcessingBuffer, 0, mDsmBufferSize * sizeof(int));
+ }
+
+ ALOGD("-%s", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSphDL::SpeakerProtectionInterfaceDeinit() {
+ ALOGD("%s", __FUNCTION__);
+ int retCode = 0;
+ //retCode = mlds_destroy_handler(dsm_handler);
+ retCode = mMlds_Interace_pointer->mlds_destroy_handler(dsm_handler);
+ dsm_handler = NULL;
+ if (mDsmMemBuffer) {
+ delete[] mDsmMemBuffer;
+ mDsmMemBuffer = NULL;
+ }
+ SpeakerBufferDeInit();
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSphDL::SpeakerBufferDeInit(void) {
+ ALOGD("+%s", __FUNCTION__);
+ if (mDsmpcmOut != NULL) {
+ ALOGD("%s delete mDsmpcmOut", __FUNCTION__);
+ delete []mDsmpcmOut;
+ mDsmpcmOut = NULL;
+ }
+ if (mDsmiData != NULL) {
+ ALOGD("%s delete mDsmiData", __FUNCTION__);
+ delete []mDsmiData;
+ mDsmiData = NULL;
+ }
+ if (mDsmvData != NULL) {
+ ALOGD("%s delete mDsmvData", __FUNCTION__);
+ delete []mDsmvData;
+ mDsmvData = NULL;
+ }
+
+ if (mDsmProcessingbuffer != NULL) {
+ delete []mDsmProcessingbuffer;
+ mDsmProcessingbuffer = NULL;
+ ALOGD("%s new mDsmProcessingbuffer = %p", __FUNCTION__, mDsmProcessingbuffer);
+ }
+
+ if (mDsmIvReadData != NULL) {
+ delete []mDsmIvReadData;
+ mDsmIvReadData = NULL;
+ ALOGD("%s new mDsmIvReadData = %p", __FUNCTION__, mDsmIvReadData);
+ }
+
+ if (mSpeakerChannelProcessingBuffer != NULL) {
+ delete []mSpeakerChannelProcessingBuffer;
+ mSpeakerChannelProcessingBuffer = NULL;
+ }
+
+ ALOGD("-%s", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerSphDL::setScreenState(bool mode, size_t lowLatencyHalBufferSize, size_t reduceInterruptSize, bool bforce) {
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSphDL::DoSpeakerProctionPacking(int *pbuffer, int ValidInputBuffersize) {
+ // first copy data to processing buffer with ValidInputBuffersize
+ memcpy((void *)mSpeakerChannelProcessingBuffer, (void *)pbuffer, ValidInputBuffersize);
+ int *ppostProcessingL = pbuffer;
+ int *ppostProcessingR = (int *)((char *)pbuffer + (ValidInputBuffersize / 2));
+ int *pTempprocessingBuffer = mSpeakerChannelProcessingBuffer;
+
+
+ while (ValidInputBuffersize > 0) {
+ *ppostProcessingL = *pTempprocessingBuffer;
+ ppostProcessingL++;
+ pTempprocessingBuffer++;
+ *ppostProcessingR = *pTempprocessingBuffer;
+ ppostProcessingR++;
+ pTempprocessingBuffer++;
+ ValidInputBuffersize -= 8;
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSphDL::MonoToStereo(int *pbuffer, int ValidInputBuffersize) {
+ if (DSM_CHANNELS == 2) {
+ return NO_ERROR;
+ }
+
+ int *pTempprocessingBuffer = pbuffer + 1;
+
+ while (ValidInputBuffersize > 0) {
+ *pTempprocessingBuffer = *pbuffer;
+ pTempprocessingBuffer += 2;
+ pbuffer += 2;
+ ValidInputBuffersize -= 8;
+ }
+ return NO_ERROR;
+}
+
+
+
+status_t AudioALSAPlaybackHandlerSphDL::DoSpeakerProctionUnPacking(int *pbuffer, int ValidInputBuffersize) {
+ memcpy((void *)mSpeakerChannelProcessingBuffer, (void *)pbuffer, ValidInputBuffersize);
+ int *ppostProcessingL = mSpeakerChannelProcessingBuffer;
+ int *ppostProcessingR = (int *)((char *)mSpeakerChannelProcessingBuffer + (ValidInputBuffersize / 2));
+ int *pTempprocessingBuffer = pbuffer;
+
+ /*
+ ALOGD("%s ValidInputBuffersize =%d ppostProcessingR = % pppostProcessingL = %p Dsmtempbuffer = %p",
+ __FUNCTION__,ValidInputBuffersize,ppostProcessingR,ppostProcessingL,pbuffer);*/
+
+ while (ValidInputBuffersize > 0) {
+ *pTempprocessingBuffer = *ppostProcessingL;
+ pTempprocessingBuffer++;
+ ppostProcessingL++;
+ *pTempprocessingBuffer = *ppostProcessingR;
+ pTempprocessingBuffer++;
+ ppostProcessingR++;
+ ValidInputBuffersize -= 8;
+ }
+ return NO_ERROR;
+}
+
+// here using android define format
+unsigned int AudioALSAPlaybackHandlerSphDL::GetSampleSize(unsigned int Format) {
+ unsigned returnsize = 2;
+ if (Format == AUDIO_FORMAT_PCM_16_BIT) {
+ returnsize = 2;
+ } else if (Format == AUDIO_FORMAT_PCM_32_BIT || Format == AUDIO_FORMAT_PCM_8_24_BIT) {
+ returnsize = 4;
+ } else if (Format == AUDIO_FORMAT_PCM_8_BIT) {
+ returnsize = 1;
+ } else {
+ ALOGD("%s Format == %d", Format);
+ }
+ return returnsize;
+}
+
+// here using android define format
+unsigned int AudioALSAPlaybackHandlerSphDL::GetFrameSize(unsigned int channels, unsigned int Format) {
+ unsigned returnsize = 2;
+ if (Format == AUDIO_FORMAT_PCM_16_BIT) {
+ returnsize = 2;
+ } else if (Format == AUDIO_FORMAT_PCM_32_BIT || Format == AUDIO_FORMAT_PCM_8_24_BIT) {
+ returnsize = 4;
+ } else if (Format == AUDIO_FORMAT_PCM_8_BIT) {
+ returnsize = 1;
+ } else {
+ ALOGD("%s Format = %d", Format);
+ }
+ returnsize *= channels;
+ return returnsize;;
+}
+
+status_t AudioALSAPlaybackHandlerSphDL::DoSpeakerProtionInterfaceProcessing(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *
+ pOutBytes) {
+ //ALOGD("+%s", __FUNCTION__);
+#ifndef BY_PASS_PROCESSING
+ unsigned long long diffns, diffus = 0;
+ unsigned long long diffcounter = 1;
+ unsigned long long diffsum = 0;
+ struct timespec tstemp1, tstemp2;
+ unsigned int outSize = mDsmBufferSize;
+ unsigned int IVSize = inBytes / GetFrameSize(mStreamAttributeSource->num_channels, mStreamAttributeSource->audio_format);
+ IVSize *= GetFrameSize(mStreamAttributeSource->num_channels, AUDIO_FORMAT_PCM_16_BIT);
+ int retcode = 0;
+
+ if (dsm_handler != NULL) { // do processing
+ IVSize = mAudioAlsaPcmIn->read(mDsmIvReadData, IVSize);
+ if (mPCMPlayIVDumpFile != NULL) {
+ ALOGD("%s WritePcmDumpData IVSize = %d", __FUNCTION__, IVSize);
+ //WritePcmDumpData(mDsmIvReadData,IVSize);
+ }
+ /*
+ retcode = mlds_process_dl_buf(
+ pInBuffer,
+ &inBytes,
+ mDsmpcmOut,
+ &outSize,
+ mDsmIvReadData,
+ &IVSize,
+ &dsm_handler,
+ NULL);*/
+ retcode = mMlds_Interace_pointer->mlds_process_dl_buf(
+ pInBuffer,
+ &inBytes,
+ mDsmpcmOut,
+ &outSize,
+ mDsmIvReadData,
+ &IVSize,
+ &dsm_handler,
+ NULL);
+ ALOGD("mMlds_Interace_pointer mlds_process_dl_buf mDsmpcmOut = %p mDsmIvReadData = %p outSize = %d", mDsmpcmOut, mDsmIvReadData, outSize);
+ *ppOutBuffer = mDsmpcmOut;
+ *pOutBytes = outSize;
+ } else {
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ }
+#else
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+#endif
+
+ ASSERT(*ppOutBuffer != NULL && *pOutBytes != 0);
+ //ALOGD("-%s outSize = %d *ppOutBuffer = %p", __FUNCTION__, outSize , *ppOutBuffer);
+ return NO_ERROR;
+}
+
+
+ssize_t AudioALSAPlaybackHandlerSphDL::write(const void *buffer, size_t bytes) {
+ ALOGD("%s(), buffer = %p, bytes = %d", __FUNCTION__, buffer, bytes);
+
+ if (mPcm == NULL) {
+ ALOGE("%s(), mPcm == NULL, return", __FUNCTION__);
+ return bytes;
+ }
+
+ // const -> to non const
+ void *pBuffer = const_cast<void *>(buffer);
+ ASSERT(pBuffer != NULL);
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[0] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+
+ void *pBufferAfterDcRemoval = NULL;
+ uint32_t bytesAfterDcRemoval = 0;
+ // DC removal before DRC
+ doDcRemoval(pBuffer, bytes, &pBufferAfterDcRemoval, &bytesAfterDcRemoval);
+ pBuffer = pBufferAfterDcRemoval;
+ bytes = bytesAfterDcRemoval;
+
+ // stereo to mono for speaker
+ if (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_16_BIT) { // AudioMixer will perform stereo to mono when 32-bit
+ doStereoToMonoConversionIfNeed(pBuffer, bytes);
+ }
+
+ // post processing (can handle both Q1P16 and Q1P31 by audio_format_t)
+ void *pBufferAfterPostProcessing = NULL;
+ uint32_t bytesAfterPostProcessing = 0;
+ doPostProcessing(pBuffer, bytes, &pBufferAfterPostProcessing, &bytesAfterPostProcessing);
+
+ // SRC
+ void *pBufferAfterBliSrc = NULL;
+ uint32_t bytesAfterBliSrc = 0;
+ doBliSrc(pBufferAfterPostProcessing, bytesAfterPostProcessing, &pBufferAfterBliSrc, &bytesAfterBliSrc);
+
+ //
+ void *pBufferPostProcessing = NULL;
+ uint32_t bytesAfterpostprocessings = 0;
+ //DoSpeakerProtionProcessing(pBufferAfterBliSrc, bytesAfterBliSrc, &pBufferPostProcessing, &bytesAfterpostprocessings);
+ DoSpeakerProtionInterfaceProcessing(pBufferAfterBliSrc, bytesAfterBliSrc, &pBufferPostProcessing, &bytesAfterpostprocessings);
+ ALOGD("DoSpeakerProtionInterfaceProcessing bytesAfterBliSrc = %d bytesAfterpostprocessings = %d", bytesAfterBliSrc, bytesAfterpostprocessings);
+
+ // pcm dump
+ WritePcmDumpData(pBufferPostProcessing, bytesAfterpostprocessings);
+
+ // bit conversion
+ void *pBufferAfterBitConvertion = NULL;
+ uint32_t bytesAfterBitConvertion = 0;
+ doBitConversion(pBufferPostProcessing, bytesAfterpostprocessings, &pBufferAfterBitConvertion, &bytesAfterBitConvertion);
+
+ // data pending
+ void *pBufferAfterPending = NULL;
+ uint32_t bytesAfterpending = 0;
+ dodataPending(pBufferAfterBitConvertion, bytesAfterBitConvertion, &pBufferAfterPending, &bytesAfterpending);
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[1] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+
+ // write data to pcm driver
+ int retval = pcm_write(mPcm, pBufferAfterPending, bytesAfterpending);
+
+#ifdef DEBUG_LATENCY
+ clock_gettime(CLOCK_REALTIME, &mNewtime);
+ latencyTime[2] = calc_time_diff(mNewtime, mOldtime);
+ mOldtime = mNewtime;
+#endif
+
+#if 1 // TODO(Harvey, Wendy), temporary disable Voice Unlock until 24bit ready
+ //============Voice UI&Unlock REFERECE=============
+ AudioVUnlockDL *VUnlockhdl = AudioVUnlockDL::getInstance();
+ if (VUnlockhdl != NULL) {
+ // get remain time
+ //VUnlockhdl->SetDownlinkStartTime(ret_ms);
+ VUnlockhdl->GetFirstDLTime();
+
+ //VUnlockhdl->SetInputStandBy(false);
+ if (mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+ mStreamAttributeSource->output_devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+ memset((void *)pBufferAfterBitConvertion, 0, bytesAfterBitConvertion);
+ }
+ VUnlockhdl->WriteStreamOutToRing(pBufferAfterBitConvertion, bytesAfterBitConvertion);
+ }
+ //===========================================
+#endif
+
+
+ if (retval != 0) {
+ ALOGE("%s(), pcm_write() error, retval = %d", __FUNCTION__, retval);
+ }
+
+#ifdef DEBUG_LATENCY
+ ALOGD("AudioALSAPlaybackHandlerSphDL::write (-) latency_in_us,%1.6lf,%1.6lf,%1.6lf", latencyTime[0], latencyTime[1], latencyTime[2]);
+#endif
+
+ return bytes;
+}
+
+status_t AudioALSAPlaybackHandlerSphDL::setFilterMng(AudioMTKFilterManager *pFilterMng) {
+#if !defined(MTK_AURISYS_FRAMEWORK_SUPPORT)
+ ALOGD("+%s() mAudioFilterManagerHandler [%p]", __FUNCTION__, pFilterMng);
+ mAudioFilterManagerHandler = pFilterMng;
+#else
+ (void *)pFilterMng;
+#endif
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSphDL::CopyIVbuffer(void *InputBuffert, short *Rbuffer, short *Lbuffer, unsigned int samplecount) {
+ short *pTemp = (short *)InputBuffert;
+ //ALOGD("samplecount = %d",samplecount);
+ while (samplecount > 0) {
+ *Rbuffer++ = *pTemp++;
+ *Lbuffer++ = *pTemp++;
+ samplecount--;
+ }
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerSphDL::EnableIVTask(pcm_config mPcm_config) {
+ ALOGD("+%s", __FUNCTION__);
+
+ mAudioAlsaPcmIn = AudioALSAPcmDataCaptureIn::getInstance();
+ ASSERT(mAudioAlsaPcmIn != NULL);
+
+ // settting for IV config setting
+ mPcmIvConfig.channels = 2;
+ mPcmIvConfig.format = PCM_FORMAT_S16_LE;
+ mPcmIvConfig.rate = mPcm_config.rate;
+ mPcmIvConfig.period_count = mPcm_config.period_count;
+ mPcmIvConfig.period_size = mPcm_config.period_size;
+ mPcmIvConfig.start_threshold = 0;
+ mPcmIvConfig.stop_threshold = 0;
+ mPcmIvConfig.silence_threshold = 0;
+
+ mAudioAlsaPcmIn->SetPcmConfig(mPcmIvConfig);
+ mAudioAlsaPcmIn->SetThreadEnable();
+
+ ALOGD("-%s", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerSphDL::DisableIVTask(void) {
+ ALOGD("+%s", __func__);
+ if (mAudioAlsaPcmIn != NULL) {
+ mAudioAlsaPcmIn->SetThreadDisable();
+ }
+ ALOGD("-%s", __func__);
+
+ return NO_ERROR;
+}
+
+
+// using dl to do function open
+status_t AudioALSAPlaybackHandlerSphDL::InitmldsInterface() {
+ ALOGD("%s", __FUNCTION__);
+ mMlds_handle = dlopen(SPEAKER_LIB_PATH, RTLD_NOW);
+ if (mMlds_handle == NULL) {
+ ALOGD("%s err", __FUNCTION__);
+ }
+ mMlds_Interace_pointer->mlds_query_working_buf_size = (lib_status_t (*)(const mlds_task_config_t *, uint32_t *))dlsym(mMlds_handle, "mlds_query_working_buf_size");
+ mMlds_Interace_pointer->mlds_create_handler = (lib_status_t (*)(
+ const mlds_task_config_t *p_mlds_task_config,
+ const uint32_t param_buf_size,
+ void *p_param_buf,
+ const uint32_t working_buf_size,
+ void *p_working_buf,
+ void **pp_handler))dlsym(mMlds_handle, "mlds_create_handler");
+ mMlds_Interace_pointer->mlds_process_dl_buf = (lib_status_t (*)(
+ void *p_dl_buf_in,
+ uint32_t *InSize,
+ void *p_dl_buf_out,
+ uint32_t *OutSize,
+ void *p_ref_buf,
+ uint32_t *RefBufSize,
+ void *p_handler,
+ void *arg))dlsym(mMlds_handle, "mlds_process_dl_buf");
+ mMlds_Interace_pointer->mlds_destroy_handler = (lib_status_t (*)(void *p_handler))dlsym(mMlds_handle, "mlds_destroy_handler");
+
+ return NO_ERROR;
+}
+
+
+void AudioALSAPlaybackHandlerSphDL::OpenPCMIVDump(const char *class_name) {
+ ALOGD("%s()", __FUNCTION__);
+ char mDumpFileName[128];
+ sprintf(mDumpFileName, "%s.%d.%s.pcm", streaminIVCPMIn, mDumpPlayIVFileNum, class_name);
+
+ mPCMPlayIVDumpFile = NULL;
+ mPCMPlayIVDumpFile = AudioOpendumpPCMFile(mDumpFileName, streamin_propty);
+
+ if (mDumpFileName != NULL) {
+ ALOGD("%s DumpFileName = %s", __FUNCTION__, mDumpFileName);
+ mDumpPlayIVFileNum++;
+ mDumpPlayIVFileNum %= MAX_DUMP_NUM;
+ }
+}
+
+void AudioALSAPlaybackHandlerSphDL::ClosePCMIVDump() {
+ ALOGD("%s()", __FUNCTION__);
+ if (mPCMPlayIVDumpFile) {
+ AudioCloseDumpPCMFile(mPCMPlayIVDumpFile);
+ mPCMPlayIVDumpFile = NULL;
+ ALOGD("%s(), close it", __FUNCTION__);
+ }
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerVoice.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerVoice.cpp
new file mode 100644
index 0000000..e69f2ff
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerVoice.cpp
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAPlaybackHandlerVoice.h"
+
+#include "SpeechDriverFactory.h"
+#include "SpeechBGSPlayer.h"
+
+#include <SpeechUtility.h>
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSAPlaybackHandlerVoice"
+
+namespace android {
+
+const char *PROPERTY_KEY_BGS_NO_SLEEP = "persist.vendor.audiohal.speech.bgs.no_sleep";
+
+
+
+AudioALSAPlaybackHandlerVoice::AudioALSAPlaybackHandlerVoice(const stream_attribute_t *stream_attribute_source) :
+ AudioALSAPlaybackHandlerBase(stream_attribute_source),
+ mBGSPlayer(BGSPlayer::GetInstance()) {
+ mSpeechDriver = NULL;
+ mPlaybackHandlerType = PLAYBACK_HANDLER_VOICE;
+ mBGSPlayBuffer = NULL;
+
+ memset((void *)&mOpenTime, 0, sizeof(mOpenTime));
+ memset((void *)&mCurTime, 0, sizeof(mCurTime));
+ mWriteCnt = 0;
+
+ memset((void *)&mNewtimeLatency, 0, sizeof(mNewtimeLatency));
+ memset((void *)&mOldtimeLatency, 0, sizeof(mOldtimeLatency));
+ memset((void *)&mLatencyTimeMs, 0, sizeof(mLatencyTimeMs));
+
+ mLatencyUs = 0;
+
+ mBypassBgsSleep = 0;
+}
+
+
+AudioALSAPlaybackHandlerVoice::~AudioALSAPlaybackHandlerVoice() {
+}
+
+status_t AudioALSAPlaybackHandlerVoice::open() {
+ // debug pcm dump
+ OpenPCMDump(LOG_TAG);
+
+
+ // HW attribute config // TODO(Harvey): query this
+ mStreamAttributeTarget.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ mStreamAttributeTarget.audio_channel_mask = AUDIO_CHANNEL_OUT_MONO;
+ mStreamAttributeTarget.num_channels = popcount(mStreamAttributeTarget.audio_channel_mask);
+ mStreamAttributeTarget.sample_rate = BGS_TARGET_SAMPLE_RATE; // same as source stream
+ mStreamAttributeTarget.u8BGSDlGain = mStreamAttributeSource->u8BGSDlGain;
+ mStreamAttributeTarget.u8BGSUlGain = mStreamAttributeSource->u8BGSUlGain;
+ mStreamAttributeTarget.buffer_size = BGS_PLAY_BUFFER_LEN;
+
+ mLatencyUs = getBufferLatencyUs(mStreamAttributeSource,
+ mStreamAttributeSource->buffer_size);
+
+ ALOGD("%s(), audio_mode: %d, u8BGSUlGain: %d, u8BGSDlGain: %d"
+ ", audio_format: %d => %d, sample_rate: %u => %u, ch: %u => %u"
+ ", buffer_size: (write)%u, (bgs)%u, flag: 0x%x, mLatencyUs: %u",
+ __FUNCTION__, mStreamAttributeSource->audio_mode,
+ mStreamAttributeSource->u8BGSUlGain,
+ mStreamAttributeSource->u8BGSDlGain,
+ mStreamAttributeSource->audio_format,
+ mStreamAttributeTarget.audio_format,
+ mStreamAttributeSource->sample_rate,
+ mStreamAttributeTarget.sample_rate,
+ mStreamAttributeSource->num_channels,
+ mStreamAttributeTarget.num_channels,
+ mStreamAttributeSource->buffer_size,
+ mStreamAttributeTarget.buffer_size,
+ mStreamAttributeSource->mAudioOutputFlags,
+ (uint32_t)(mLatencyUs & 0xFFFFFFFF));
+
+
+ // bit conversion
+ initBitConverter();
+
+
+ // open background sound
+ if (mStreamAttributeTarget.num_channels > 2) {
+ mBGSPlayBuffer = mBGSPlayer->CreateBGSPlayBuffer(
+ mStreamAttributeSource->sample_rate,
+ 2,
+ mStreamAttributeTarget.audio_format);
+
+ } else {
+ mBGSPlayBuffer = mBGSPlayer->CreateBGSPlayBuffer(
+ mStreamAttributeSource->sample_rate,
+ mStreamAttributeSource->num_channels,
+ mStreamAttributeTarget.audio_format);
+ }
+
+ mSpeechDriver = SpeechDriverFactory::GetInstance()->GetSpeechDriver();
+ mBGSPlayer->Open(mSpeechDriver, mStreamAttributeTarget.u8BGSUlGain, mStreamAttributeTarget.u8BGSDlGain);
+
+ mBypassBgsSleep = get_uint32_from_property(PROPERTY_KEY_BGS_NO_SLEEP);
+
+ clock_gettime(CLOCK_MONOTONIC, &mOpenTime);
+ mWriteCnt = 0;
+
+ clock_gettime(CLOCK_MONOTONIC, &mNewtimeLatency);
+ mOldtimeLatency = mNewtimeLatency;
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerVoice::close() {
+ ALOGD("%s(), flag: 0x%x", __FUNCTION__, mStreamAttributeSource->mAudioOutputFlags);
+
+ // close background sound
+ mBGSPlayer->Close();
+
+ mBGSPlayer->DestroyBGSPlayBuffer(mBGSPlayBuffer);
+
+
+ // bit conversion
+ deinitBitConverter();
+
+
+ // debug pcm dump
+ ClosePCMDump();
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAPlaybackHandlerVoice::routing(const audio_devices_t output_devices __unused) {
+ return INVALID_OPERATION;
+}
+
+uint32_t AudioALSAPlaybackHandlerVoice::ChooseTargetSampleRate(uint32_t SampleRate) {
+ ALOGD("ChooseTargetSampleRate SampleRate = %d ", SampleRate);
+ uint32_t TargetSampleRate = 44100;
+ if ((SampleRate % 8000) == 0) { // 8K base
+ TargetSampleRate = 48000;
+ }
+ return TargetSampleRate;
+}
+
+ssize_t AudioALSAPlaybackHandlerVoice::write(const void *buffer, size_t bytes) {
+ ALOGV("%s()", __FUNCTION__);
+
+ uint64_t spendTimeUs = 0;
+ uint64_t writeTimeUs = 0;
+ uint64_t sleepUs = 0;
+
+ mWriteCnt++;
+
+ if (mSpeechDriver == NULL) {
+ ALOGW("%s(), mSpeechDriver == NULL!!", __FUNCTION__);
+ return bytes;
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &mNewtimeLatency);
+ mLatencyTimeMs[0] = get_time_diff_ms(&mOldtimeLatency, &mNewtimeLatency);
+ mOldtimeLatency = mNewtimeLatency;
+
+ if (mSpeechDriver->CheckModemIsReady() == false) {
+ uint32_t sleep_ms = getBufferLatencyMs(mStreamAttributeSource, bytes);
+ if (sleep_ms != 0) {
+ ALOGW("%s(), modem not ready, sleep %u ms", __FUNCTION__, sleep_ms);
+ usleep(sleep_ms * 1000);
+ }
+ return bytes;
+ }
+
+ void *newbuffer[96 * 1024] = {0};
+ unsigned char *aaa;
+ unsigned char *bbb;
+ size_t i = 0;
+ size_t j = 0;
+ int retval = 0;
+ // const -> to non const
+ void *pBuffer = const_cast<void *>(buffer);
+ ASSERT(pBuffer != NULL);
+
+ aaa = (unsigned char *)newbuffer;
+ bbb = (unsigned char *)buffer;
+
+
+ if (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_16_BIT) {
+ if (mStreamAttributeTarget.num_channels == 8) {
+ for (i = 0 ; j < bytes; i += 4) {
+ memcpy(aaa + i, bbb + j, 4);
+ j += 16;
+ }
+ bytes = (bytes >> 2);
+ } else if (mStreamAttributeTarget.num_channels == 6) {
+ for (i = 0 ; j < bytes; i += 4) {
+ memcpy(aaa + i, bbb + j, 4);
+ j += 12;
+ }
+ bytes = (bytes / 3);
+ } else {
+ memcpy(aaa, bbb, bytes);
+ }
+ } else {
+ if (mStreamAttributeTarget.num_channels == 8) {
+ for (i = 0 ; j < bytes; i += 8) {
+ memcpy(aaa + i, bbb + j, 8);
+ j += 32;
+ }
+ bytes = (bytes >> 2);
+ } else if (mStreamAttributeTarget.num_channels == 6) {
+ for (i = 0 ; j < bytes; i += 8) {
+ memcpy(aaa + i, bbb + j, 8);
+ j += 24;
+ }
+ bytes = (bytes / 3);
+ } else {
+ memcpy(aaa, bbb, bytes);
+ }
+
+ }
+
+ // bit conversion
+ void *pBufferAfterBitConvertion = NULL;
+ uint32_t bytesAfterBitConvertion = 0;
+ doBitConversion(newbuffer, bytes, &pBufferAfterBitConvertion, &bytesAfterBitConvertion);
+
+
+ // write data to background sound
+ WritePcmDumpData(pBufferAfterBitConvertion, bytesAfterBitConvertion);
+
+ uint32_t u4WrittenBytes = BGSPlayer::GetInstance()->Write(mBGSPlayBuffer, pBufferAfterBitConvertion, bytesAfterBitConvertion);
+ if (u4WrittenBytes != bytesAfterBitConvertion) { // TODO: 16/32
+ ALOGE("%s(), BGSPlayer::GetInstance()->Write() error, u4WrittenBytes(%u) != bytesAfterBitConvertion(%u)", __FUNCTION__, u4WrittenBytes, bytesAfterBitConvertion);
+ }
+ clock_gettime(CLOCK_MONOTONIC, &mNewtimeLatency);
+ mLatencyTimeMs[1] = get_time_diff_ms(&mOldtimeLatency, &mNewtimeLatency);
+ mOldtimeLatency = mNewtimeLatency;
+
+ /* HAL sleep latency time to consume data smoothly */
+ if (mBypassBgsSleep == false) {
+ clock_gettime(CLOCK_MONOTONIC, &mCurTime);
+ spendTimeUs = get_time_diff_ns(&mOpenTime, &mCurTime) / 1000;
+ writeTimeUs = mWriteCnt * mLatencyUs;
+ if (spendTimeUs < writeTimeUs) {
+ sleepUs = writeTimeUs - spendTimeUs;
+ if (mBGSPlayBuffer->isBufferEnough()) {
+ usleep(sleepUs);
+ } else {
+ if (sleepUs > 1000) {
+ sleepUs -= 1000;
+ usleep(sleepUs);
+ } else {
+ sleepUs = 0;
+ }
+ }
+ } else if (spendTimeUs > (writeTimeUs + MODEM_FRAME_MS * 1000)) {
+ if (getBGSLogEnableByLevel(BGS_LOG_LEVEL_PLAYBACK_HANDLER)) {
+ ALOGW("%s(), spendTimeUs %u, writeTimeUs %u", __FUNCTION__,
+ (uint32_t)(spendTimeUs & 0xFFFFFFFF),
+ (uint32_t)(writeTimeUs & 0xFFFFFFFF));
+ }
+ }
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &mNewtimeLatency);
+ mLatencyTimeMs[2] = get_time_diff_ms(&mOldtimeLatency, &mNewtimeLatency);
+ mOldtimeLatency = mNewtimeLatency;
+
+ uint64_t logThresholdMs = (mLatencyUs) / 1000;
+ if (logThresholdMs < MODEM_FRAME_MS) {
+ logThresholdMs = MODEM_FRAME_MS;
+ }
+
+ if (mLatencyTimeMs[0] > logThresholdMs ||
+ mLatencyTimeMs[1] > logThresholdMs ||
+ mLatencyTimeMs[2] > logThresholdMs) {
+ ALOGW("latency_in_ms, %3u, %3u, %3u, u4WrittenBytes: %u, mLatencyUs: %u, spendTimeUs: %u, writeTimeUs: %u, sleepUs: %u",
+ (uint32_t)(mLatencyTimeMs[0] & 0xFFFFFFFF),
+ (uint32_t)(mLatencyTimeMs[1] & 0xFFFFFFFF),
+ (uint32_t)(mLatencyTimeMs[2] & 0xFFFFFFFF),
+ u4WrittenBytes,
+ (uint32_t)(mLatencyUs & 0xFFFFFFFF),
+ (uint32_t)(spendTimeUs & 0xFFFFFFFF),
+ (uint32_t)(writeTimeUs & 0xFFFFFFFF),
+ (uint32_t)(sleepUs & 0xFFFFFFFF));
+ } else if (getBGSLogEnableByLevel(BGS_LOG_LEVEL_PLAYBACK_HANDLER)) {
+ ALOGD("latency_in_ms, %3u, %3u, %3u, u4WrittenBytes: %u, mLatencyUs: %u, spendTimeUs: %u, writeTimeUs: %u, sleepUs: %u",
+ (uint32_t)(mLatencyTimeMs[0] & 0xFFFFFFFF),
+ (uint32_t)(mLatencyTimeMs[1] & 0xFFFFFFFF),
+ (uint32_t)(mLatencyTimeMs[2] & 0xFFFFFFFF),
+ u4WrittenBytes,
+ (uint32_t)(mLatencyUs & 0xFFFFFFFF),
+ (uint32_t)(spendTimeUs & 0xFFFFFFFF),
+ (uint32_t)(writeTimeUs & 0xFFFFFFFF),
+ (uint32_t)(sleepUs & 0xFFFFFFFF));
+ }
+
+ return bytes;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerVoiceMixer.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerVoiceMixer.cpp
new file mode 100644
index 0000000..7e73fc5
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAPlaybackHandlerVoiceMixer.cpp
@@ -0,0 +1,287 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAPlaybackHandlerVoiceMixer.h"
+
+#include "SpeechDriverFactory.h"
+#include "SpeechVoiceMixer.h"
+
+#include <SpeechUtility.h>
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSAPlaybackHandlerVoiceMixer"
+
+namespace android {
+/*
+ * =============================================================================
+ * Property keys
+ * =============================================================================
+ */
+const char *PROPERTY_KEY_VOICEMIXER_NO_SLEEP = "persist.vendor.audiohal.speech.voicemixer.no_sleep";
+
+
+/*
+ * =============================================================================
+ * class
+ * =============================================================================
+ */
+AudioALSAPlaybackHandlerVoiceMixer::AudioALSAPlaybackHandlerVoiceMixer(const stream_attribute_t *stream_attribute_source) :
+ AudioALSAPlaybackHandlerBase(stream_attribute_source),
+ mVoiceMixerPlayer(VoiceMixerPlayer::getInstance()) {
+ mSpeechDriver = NULL;
+ mPlaybackHandlerType = PLAYBACK_HANDLER_VOICE;
+ mVoiceMixerPlayBuffer = NULL;
+
+ memset((void *)&mOpenTime, 0, sizeof(mOpenTime));
+ memset((void *)&mCurTime, 0, sizeof(mCurTime));
+ mWriteCnt = 0;
+
+ memset((void *)&mNewtimeLatency, 0, sizeof(mNewtimeLatency));
+ memset((void *)&mOldtimeLatency, 0, sizeof(mOldtimeLatency));
+ memset((void *)&mLatencyTimeMs, 0, sizeof(mLatencyTimeMs));
+ mLatencyUs = 0;
+ mBypassVoiceMixerSleep = 0;
+}
+
+status_t AudioALSAPlaybackHandlerVoiceMixer::open() {
+ // debug pcm dump
+ OpenPCMDump(LOG_TAG);
+
+ // HW attribute config
+ mStreamAttributeTarget.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ mStreamAttributeTarget.audio_channel_mask = AUDIO_CHANNEL_OUT_MONO;
+ mStreamAttributeTarget.num_channels = popcount(mStreamAttributeTarget.audio_channel_mask);
+ mStreamAttributeTarget.sample_rate = VOICEMIXER_TARGET_SAMPLE_RATE; // same as source stream
+ mStreamAttributeTarget.buffer_size = VOICEMIXER_PLAY_BUFFER_LEN;
+ mStreamAttributeTarget.mPcmMixTypeDl = VOICE_MIXER_TYPE_REPLACE;
+
+ mLatencyUs = getBufferLatencyUs(mStreamAttributeSource,
+ mStreamAttributeSource->buffer_size);
+
+ ALOGD("%s(), audio_mode: %d, audio_format: %d => %d, sample_rate: %u => %u, ch: %u => %u, "
+ " buffer_size: (write)%u, (voicemixer)%u, flag: 0x%x, mLatencyUs: %u, mPcmMixTypeDl: %u",
+ __FUNCTION__, mStreamAttributeSource->audio_mode,
+ mStreamAttributeSource->audio_format,
+ mStreamAttributeTarget.audio_format,
+ mStreamAttributeSource->sample_rate,
+ mStreamAttributeTarget.sample_rate,
+ mStreamAttributeSource->num_channels,
+ mStreamAttributeTarget.num_channels,
+ mStreamAttributeSource->buffer_size,
+ mStreamAttributeTarget.buffer_size,
+ mStreamAttributeSource->mAudioOutputFlags,
+ (uint32_t)(mLatencyUs & 0xFFFFFFFF),
+ mStreamAttributeTarget.mPcmMixTypeDl);
+ // bit conversion
+ initBitConverter();
+ // open VoiceMixer
+ if (mStreamAttributeTarget.num_channels > 2) {
+ mVoiceMixerPlayBuffer = mVoiceMixerPlayer->createPlayBuffer(
+ mStreamAttributeSource->sample_rate,
+ 2,
+ mStreamAttributeTarget.audio_format);
+
+ } else {
+ mVoiceMixerPlayBuffer = mVoiceMixerPlayer->createPlayBuffer(
+ mStreamAttributeSource->sample_rate,
+ mStreamAttributeSource->num_channels,
+ mStreamAttributeTarget.audio_format);
+ }
+
+ mSpeechDriver = SpeechDriverFactory::GetInstance()->GetSpeechDriver();
+ mVoiceMixerPlayer->open(mSpeechDriver, mStreamAttributeTarget.mPcmMixTypeDl);
+
+ mBypassVoiceMixerSleep = get_uint32_from_property(PROPERTY_KEY_VOICEMIXER_NO_SLEEP);
+
+ clock_gettime(CLOCK_MONOTONIC, &mOpenTime);
+ mWriteCnt = 0;
+
+ clock_gettime(CLOCK_MONOTONIC, &mNewtimeLatency);
+ mOldtimeLatency = mNewtimeLatency;
+
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerVoiceMixer::close() {
+ ALOGD("%s(), flag: 0x%x", __FUNCTION__, mStreamAttributeSource->mAudioOutputFlags);
+ // close VoiceMixer
+ mVoiceMixerPlayer->close();
+ mVoiceMixerPlayer->destroyPlayBuffer(mVoiceMixerPlayBuffer);
+ // bit conversion
+ deinitBitConverter();
+ // debug pcm dump
+ ClosePCMDump();
+ return NO_ERROR;
+}
+
+status_t AudioALSAPlaybackHandlerVoiceMixer::routing(const audio_devices_t output_devices __unused) {
+ return INVALID_OPERATION;
+}
+
+ssize_t AudioALSAPlaybackHandlerVoiceMixer::write(const void *buffer, size_t bytes) {
+ ALOGV("%s()", __FUNCTION__);
+
+ uint64_t spendTimeUs = 0;
+ uint64_t writeTimeUs = 0;
+ uint64_t sleepUs = 0;
+ uint32_t sourceChannelNum = mStreamAttributeSource->num_channels;
+ uint32_t targetChannelNum = 2;// set target channel = 2 for doBitConversion(2->1)
+
+ mWriteCnt++;
+
+ if (mSpeechDriver == NULL) {
+ ALOGW("%s(), mSpeechDriver == NULL!!", __FUNCTION__);
+ return bytes;
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &mNewtimeLatency);
+ mLatencyTimeMs[0] = get_time_diff_ms(&mOldtimeLatency, &mNewtimeLatency);
+ mOldtimeLatency = mNewtimeLatency;
+
+ if (mSpeechDriver->CheckModemIsReady() == false) {
+ uint32_t sleep_ms = getBufferLatencyMs(mStreamAttributeSource, bytes);
+ if (sleep_ms != 0) {
+ ALOGW("%s(), modem not ready, sleep %u ms", __FUNCTION__, sleep_ms);
+ usleep(sleep_ms * 1000);
+ }
+ return bytes;
+ }
+
+ if (buffer == NULL) {
+ ALOGE("%s(), sourceBuf == NULL!!, bytes = %zu", __FUNCTION__, bytes);
+ return bytes;
+ }
+
+ // make data convert according to source and target channel
+ float channelRatio = ((float)targetChannelNum / sourceChannelNum);
+ void *targetBuf = NULL;
+ size_t targetBytes = (size_t)(channelRatio * bytes + 1); // +1 avoid round off error
+ uint32_t sampleBytes = (mStreamAttributeSource->audio_format == AUDIO_FORMAT_PCM_16_BIT) ? 2 : 4;
+
+ AUDIO_ALLOC_BUFFER(targetBuf, targetBytes);
+ if (targetBuf == NULL) {
+ ALOGE("%s(), targetBuf == NULL!!, targetBytes = %zu, bytes = %zu", __FUNCTION__, targetBytes, bytes);
+ return bytes;
+ }
+
+ uint32 targetIdx = 0;
+ uint32 sourceIdx = 0;
+ uint32 targetCopyBytes = sampleBytes * targetChannelNum;
+ uint32 sourceCopyBytes = sampleBytes * sourceChannelNum;
+ unsigned char *sourceBufBase = (unsigned char *) buffer;
+ unsigned char *targetBufBase = (unsigned char *) targetBuf;
+
+ // copy data with different index move
+ for (targetIdx = 0; sourceIdx < bytes; targetIdx += targetCopyBytes) {
+ memcpy(targetBufBase + sourceIdx, sourceBufBase + targetIdx, targetCopyBytes);
+ sourceIdx += sourceCopyBytes;
+ }
+ ALOGV("%s() Source_ch:%d, bytes:%zu, Target_ch:%d, bytes:%zu, channel_ratio:%f",
+ __FUNCTION__, sourceChannelNum, bytes, targetChannelNum, targetBytes, channelRatio);
+
+ // bit conversion
+ void *pBufferAfterBitConvertion = NULL;
+ uint32_t bytesAfterBitConvertion = 0;
+ doBitConversion(targetBuf, targetBytes, &pBufferAfterBitConvertion, &bytesAfterBitConvertion);
+
+ // write data to background sound
+ WritePcmDumpData(pBufferAfterBitConvertion, bytesAfterBitConvertion);
+
+ uint32_t writtenBytes = VoiceMixerPlayer::getInstance()->write(mVoiceMixerPlayBuffer, pBufferAfterBitConvertion,
+ bytesAfterBitConvertion);
+ if (writtenBytes != bytesAfterBitConvertion) { // TODO: 16/32
+ ALOGE("%s(), VoiceMixerPlayer::getInstance()->write() error, writtenBytes(%u) != bytesAfterBitConvertion(%u)",
+ __FUNCTION__, writtenBytes, bytesAfterBitConvertion);
+ }
+ clock_gettime(CLOCK_MONOTONIC, &mNewtimeLatency);
+ mLatencyTimeMs[1] = get_time_diff_ms(&mOldtimeLatency, &mNewtimeLatency);
+ mOldtimeLatency = mNewtimeLatency;
+
+ /* HAL sleep latency time to consume data smoothly */
+ if (mBypassVoiceMixerSleep == false) {
+ clock_gettime(CLOCK_MONOTONIC, &mCurTime);
+ spendTimeUs = get_time_diff_ns(&mOpenTime, &mCurTime) / 1000;
+ writeTimeUs = mWriteCnt * mLatencyUs;
+ if (spendTimeUs < writeTimeUs) {
+ sleepUs = writeTimeUs - spendTimeUs;
+ if (mVoiceMixerPlayBuffer->isBufferEnough()) {
+ usleep(sleepUs);
+ } else {
+ if (sleepUs > 1000) {
+ sleepUs -= 1000;
+ usleep(sleepUs);
+ } else {
+ sleepUs = 0;
+ }
+ }
+ } else if (spendTimeUs > (writeTimeUs + MODEM_FRAME_MS * 1000)) {
+ if (getLogEnableByLevel(VOICEMIXER_LOG_LEVEL_PLAYBACK_HANDLER)) {
+ ALOGW("%s(), spendTimeUs %u, writeTimeUs %u", __FUNCTION__,
+ (uint32_t)(spendTimeUs & 0xFFFFFFFF),
+ (uint32_t)(writeTimeUs & 0xFFFFFFFF));
+ }
+ }
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &mNewtimeLatency);
+ mLatencyTimeMs[2] = get_time_diff_ms(&mOldtimeLatency, &mNewtimeLatency);
+ mOldtimeLatency = mNewtimeLatency;
+
+ uint64_t logThresholdMs = (mLatencyUs) / 1000;
+ if (logThresholdMs < MODEM_FRAME_MS) {
+ logThresholdMs = MODEM_FRAME_MS;
+ }
+
+ if (mLatencyTimeMs[0] > logThresholdMs ||
+ mLatencyTimeMs[1] > logThresholdMs ||
+ mLatencyTimeMs[2] > logThresholdMs) {
+ ALOGW("%s(), latency_in_ms, %3u, %3u, %3u, writtenBytes: %u, mLatencyUs: %u, spendTimeUs: %u, "
+ "writeTimeUs: %u, sleepUs: %u", __FUNCTION__,
+ (uint32_t)(mLatencyTimeMs[0] & 0xFFFFFFFF),
+ (uint32_t)(mLatencyTimeMs[1] & 0xFFFFFFFF),
+ (uint32_t)(mLatencyTimeMs[2] & 0xFFFFFFFF),
+ writtenBytes,
+ (uint32_t)(mLatencyUs & 0xFFFFFFFF),
+ (uint32_t)(spendTimeUs & 0xFFFFFFFF),
+ (uint32_t)(writeTimeUs & 0xFFFFFFFF),
+ (uint32_t)(sleepUs & 0xFFFFFFFF));
+ } else if (getLogEnableByLevel(VOICEMIXER_LOG_LEVEL_PLAYBACK_HANDLER)) {
+ ALOGD("%s(), latency_in_ms, %3u, %3u, %3u, writtenBytes: %u, mLatencyUs: %u, spendTimeUs: %u, "
+ "writeTimeUs: %u, sleepUs: %u", __FUNCTION__,
+ (uint32_t)(mLatencyTimeMs[0] & 0xFFFFFFFF),
+ (uint32_t)(mLatencyTimeMs[1] & 0xFFFFFFFF),
+ (uint32_t)(mLatencyTimeMs[2] & 0xFFFFFFFF),
+ writtenBytes,
+ (uint32_t)(mLatencyUs & 0xFFFFFFFF),
+ (uint32_t)(spendTimeUs & 0xFFFFFFFF),
+ (uint32_t)(writeTimeUs & 0xFFFFFFFF),
+ (uint32_t)(sleepUs & 0xFFFFFFFF));
+ }
+
+ AUDIO_FREE_POINTER(targetBuf);
+ return targetBytes;
+}
+
+uint32_t AudioALSAPlaybackHandlerVoiceMixer::chooseTargetSampleRate(uint32_t sampleRate) {
+ ALOGD("ChooseTargetSampleRate sampleRate = %d ", sampleRate);
+ uint32_t targetSampleRate = 44100;
+ if ((sampleRate % 8000) == 0) { // 8K base
+ targetSampleRate = 48000;
+ }
+ return targetSampleRate;
+}
+
+int AudioALSAPlaybackHandlerVoiceMixer::configMixType(const uint8_t mixType) {
+ if (mixType != mStreamAttributeTarget.mPcmMixTypeDl) {
+ ALOGD("%s(), dlMixType(%d ->%d)", __FUNCTION__, mStreamAttributeTarget.mPcmMixTypeDl, mixType);
+ mStreamAttributeTarget.mPcmMixTypeDl = mixType;
+ return mVoiceMixerPlayer->configMixType(mSpeechDriver, mStreamAttributeTarget.mPcmMixTypeDl);
+ } else {
+ ALOGV("%s(), the same mPcmMixTypeDl(%d)", __FUNCTION__, mStreamAttributeTarget.mPcmMixTypeDl);
+ return NO_ERROR;
+ }
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSASampleRateController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSASampleRateController.cpp
new file mode 100644
index 0000000..1033ba1
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSASampleRateController.cpp
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSASampleRateController.h"
+
+#include <AudioLock.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSASampleRateController"
+
+namespace android {
+
+AudioALSASampleRateController *AudioALSASampleRateController::mAudioALSASampleRateController = NULL;
+AudioALSASampleRateController *AudioALSASampleRateController::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSASampleRateController == NULL) {
+ mAudioALSASampleRateController = new AudioALSASampleRateController();
+ }
+ ASSERT(mAudioALSASampleRateController != NULL);
+ return mAudioALSASampleRateController;
+}
+
+
+AudioALSASampleRateController::AudioALSASampleRateController() :
+ mPrimaryStreamOutSampleRate(44100) {
+ ALOGD("%s()", __FUNCTION__);
+ memset(&mScenarioReference, 0, sizeof(mScenarioReference));
+}
+
+
+AudioALSASampleRateController::~AudioALSASampleRateController() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+status_t AudioALSASampleRateController::setPrimaryStreamOutSampleRate(const uint32_t sample_rate) {
+ AL_AUTOLOCK(mLock);
+
+ ALOGD("+%s(), mPrimaryStreamOutSampleRate: %u => %u", __FUNCTION__, mPrimaryStreamOutSampleRate, sample_rate);
+
+ if (hasActiveScenario()) {
+ ALOGW("-%s() some other scenatio is active", __FUNCTION__);
+ return INVALID_OPERATION;
+ } else if (sample_rate == mPrimaryStreamOutSampleRate) {
+ ALOGW("-%s(), sample_rate == mPrimaryStreamOutSampleRate, return", __FUNCTION__);
+ return ALREADY_EXISTS;
+ }
+
+
+ mPrimaryStreamOutSampleRate = sample_rate;
+
+
+ ALOGD("-%s(), mPrimaryStreamOutSampleRate: %u", __FUNCTION__, mPrimaryStreamOutSampleRate);
+ return NO_ERROR;
+}
+
+
+uint32_t AudioALSASampleRateController::getPrimaryStreamOutSampleRate() {
+ AL_AUTOLOCK(mLock);
+ return mPrimaryStreamOutSampleRate;
+}
+
+
+void AudioALSASampleRateController::setScenarioStatus(const playback_scenario_mask_t playback_scenario_mask) {
+ AL_AUTOLOCK(mLock);
+
+ mScenarioReference[playback_scenario_mask]++;
+}
+
+void AudioALSASampleRateController::resetScenarioStatus(const playback_scenario_mask_t playback_scenario_mask) {
+ AL_AUTOLOCK(mLock);
+
+ mScenarioReference[playback_scenario_mask]--;
+
+ if (mScenarioReference[playback_scenario_mask] < 0) {
+ ALOGW("%s unexpected operation for scenario %d", __FUNCTION__, playback_scenario_mask);
+ mScenarioReference[playback_scenario_mask] = 0;
+ }
+}
+
+bool AudioALSASampleRateController::hasActiveScenario() {
+ for (int i = 0; i < PLAYBACK_SCENARIO_COUNT; i++) {
+ if (mScenarioReference[i] > 0) {
+ ALOGV("%s scenario %d is active", __FUNCTION__, i);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAVoiceWakeUpController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAVoiceWakeUpController.cpp
new file mode 100644
index 0000000..eff8a07
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioALSAVoiceWakeUpController.cpp
@@ -0,0 +1,994 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAVoiceWakeUpController.h"
+
+#include "AudioLock.h"
+#include "AudioALSADriverUtility.h"
+
+#include "AudioMTKHeadsetMessager.h"
+
+#include "AudioCustParamClient.h"
+#include "AudioUtility.h"
+#include "AudioALSAHardwareResourceManager.h"
+#include "AudioALSADeviceConfigManager.h"
+#include "AudioALSADeviceParser.h"
+#include "AudioALSAStreamManager.h"
+#include "AudioALSADeviceParser.h"
+#include "AudioALSASampleRateController.h"
+#include "AudioSmartPaController.h"
+#if defined(MTK_AUDIODSP_SUPPORT)
+#include "AudioDspStreamManager.h"
+#endif
+#include <linux/vow.h>
+
+
+#ifdef MTK_AUDIO_SCP_SUPPORT
+#include <audio_task.h>
+#include <AudioMessengerIPI.h>
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSAVoiceWakeUpController"
+#define VOW_POWER_ON_SLEEP_MS 50
+namespace android {
+
+AudioALSAVoiceWakeUpController *AudioALSAVoiceWakeUpController::mAudioALSAVoiceWakeUpController = NULL;
+AudioALSAVoiceWakeUpController *AudioALSAVoiceWakeUpController::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioALSAVoiceWakeUpController == NULL) {
+ mAudioALSAVoiceWakeUpController = new AudioALSAVoiceWakeUpController();
+ }
+ ASSERT(mAudioALSAVoiceWakeUpController != NULL);
+ return mAudioALSAVoiceWakeUpController;
+}
+
+/*==============================================================================
+ * Callback Function
+ *============================================================================*/
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+void callbackVowXmlChanged(AppHandle *appHandle, const char *audioTypeName)
+{
+ AppOps *appOps = appOpsGetInstance();
+ ALOGD("+%s(), audioType = %s", __FUNCTION__, audioTypeName);
+
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return;
+ }
+ // reload XML file
+ if (appOps->appHandleReloadAudioType(appHandle, audioTypeName) == APP_ERROR) {
+ ALOGE("%s(), Reload xml fail!(audioType = %s)", __FUNCTION__, audioTypeName);
+ } else {
+ if (strcmp(audioTypeName, "VOW") == 0) {
+ AudioALSAVoiceWakeUpController::getInstance()->updateVOWCustParam();
+ }
+ }
+}
+#endif
+
+AudioALSAVoiceWakeUpController::AudioALSAVoiceWakeUpController() :
+ mDebug_Enable(false),
+ mMixer(AudioALSADriverUtility::getInstance()->getMixer()),
+ mPcm(NULL),
+ mEnable(false),
+ mBargeInEnable(false),
+ mBargeInEnableOngoing(false),
+ mBargeInPcm(NULL),
+ mPcmHostlessUl(NULL),
+ mPcmHostlessDl(NULL),
+ mIsUseHeadsetMic(false),
+ mHardwareResourceManager(AudioALSAHardwareResourceManager::getInstance()),
+ mIsNeedToUpdateParamToKernel(true) {
+ ALOGD("%s()", __FUNCTION__);
+
+ mHandsetMicMode = mHardwareResourceManager->getPhoneMicMode();
+ mHeadsetMicMode = mHardwareResourceManager->getHeadsetMicMode();
+
+ mIsSpeakerPlaying = false;
+ memset(&mSrcDlConfig, 0, sizeof(mSrcDlConfig));
+ memset(&mSrcUlConfig, 0, sizeof(mSrcUlConfig));
+
+ mFd_vow = 0;
+ mFd_vow = ::open("/dev/vow", O_RDONLY);
+
+ //mVOWCaptureDataProvider = AudioALSACaptureDataProviderVOW::getInstance();
+ mDeviceConfigManager = AudioALSADeviceConfigManager::getInstance();
+
+ stream_attribute_target = new stream_attribute_t;
+ memset(stream_attribute_target, 0, sizeof(stream_attribute_t));
+ stream_attribute_target->input_source = AUDIO_SOURCE_HOTWORD;
+ // Init input stream attribute here
+ stream_attribute_target->audio_mode = AUDIO_MODE_NORMAL; // set mode to stream attribute for mic gain setting
+ stream_attribute_target->output_devices = AUDIO_DEVICE_NONE; // set output devices to stream attribute for mic gain setting and BesRecord parameter
+ hDumyReadThread = 0;
+ mDumpReadStart = false;
+ mFd_dnn = -1;
+ // BesRecordInfo
+
+ besrecord_info_struct_t besrecord;
+ //native_preprocess_info_struct_t nativePreprocess_Info;
+ memset(&besrecord, 0, sizeof(besrecord_info_struct_t));
+ stream_attribute_target->BesRecord_Info = besrecord;
+
+ stream_attribute_target->BesRecord_Info.besrecord_enable = false; // default set besrecord off
+ stream_attribute_target->BesRecord_Info.besrecord_bypass_dualmicprocess = false; // bypass dual MIC preprocess
+ stream_attribute_target->NativePreprocess_Info.PreProcessEffect_Update = false;
+ stream_attribute_target->sample_rate = 16000;
+ stream_attribute_target->audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ //stream_attribute_target->audio_channel_mask = AUDIO_CHANNEL_IN_MONO;
+ //mStreamAttributeSource.num_channels = popcount(mStreamAttributeSource.audio_channel_mask);
+ //mStreamAttributeSource.sample_rate = 16000;
+ ALOGD("%s() , stream_attribute_target->BesRecord_Info.besrecord_enable %d", __FUNCTION__, stream_attribute_target->BesRecord_Info.besrecord_enable);
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ /* Init AppHandle */
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ } else {
+ mAppHandle = appOps->appHandleGetInstance();
+ /* XML changed callback process */
+ appOps->appHandleRegXmlChangedCb(mAppHandle, callbackVowXmlChanged);
+ }
+#endif
+ updateParamToKernel();
+}
+
+AudioALSAVoiceWakeUpController::~AudioALSAVoiceWakeUpController() {
+ if (mFd_vow > 0) {
+ ::close(mFd_vow);
+ mFd_vow = 0;
+ }
+ ALOGD("%s()", __FUNCTION__);
+}
+
+status_t AudioALSAVoiceWakeUpController::SeamlessRecordEnable() {
+ int ret = NO_ERROR;
+
+ AL_AUTOLOCK(mSeamlessLock);
+ ALOGD("+%s()", __FUNCTION__);
+ if (mFd_dnn < 0) {
+ mFd_dnn = open("/dev/vow", O_RDONLY);
+ }
+ if (mFd_dnn < 0) {
+ ALOGI("open device fail!%s\n", strerror(errno));
+ }
+
+ ret = ::ioctl(mFd_dnn, VOW_SET_CONTROL, (unsigned int)VOWControlCmd_EnableSeamlessRecord);
+ if (ret != 0) {
+ ALOGE("%s(), VOWControlCmd_EnableHotwordRecord error, ret = %d", __FUNCTION__, ret);
+ }
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+bool AudioALSAVoiceWakeUpController::getVoiceWakeUpEnable() {
+ AL_AUTOLOCK(mLock);
+ return mEnable;
+}
+
+
+status_t AudioALSAVoiceWakeUpController::setVoiceWakeUpEnable(const bool enable) {
+ int ret = -1;
+ unsigned int temp;
+ unsigned int cnt;
+
+ ALOGD("+%s(), mEnable: %d => %d, mIsUseHeadsetMic = %d, mHeadsetMicMode = %d, mHandsetMicMode = %d",
+ __FUNCTION__, mEnable, enable, mIsUseHeadsetMic, mHeadsetMicMode, mHandsetMicMode);
+ AL_AUTOLOCK(mLock);
+
+ if (mEnable == enable) {
+ ALOGW("-%s(), enable(%d) == mEnable(%d), return", __FUNCTION__, enable, mEnable);
+ return INVALID_OPERATION;
+ }
+
+ if (enable == true) {
+ unsigned int mic_type = 0;
+ unsigned int mtkif_type = 0;
+ unsigned int vow_channel = 0;
+
+ /* Switch SCP Dynamic Object */
+#ifdef MTK_AUDIO_SCP_SUPPORT
+ /* Load task scene when opening */
+ AudioMessengerIPI::getInstance()->loadTaskScene(TASK_SCENE_VOW);
+#endif
+
+ setVoiceWakeUpDebugDumpEnable(true);
+
+ updateParamToKernel();
+#if defined(MTK_AUDIO_KS) && defined(MTK_VOW_SUPPORT)
+ struct pcm_config config;
+
+ memset(&config, 0, sizeof(config));
+ config.rate = 16000;
+ config.period_count = 2;
+ config.format = PCM_FORMAT_S16_LE;
+ config.stop_threshold = ~(0U);
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_VOW_DUAL_MIC)) {
+ ALOGD("VOW SET DUAL MIC");
+ config.channels = 2;
+ config.period_size = 512;
+ } else {
+ ALOGD("VOW SET SINGLE MIC");
+ config.channels = 1;
+ config.period_size = 1024;
+ }
+
+ vow_channel = config.channels;
+
+ int cardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVOWCapture);
+ int pcmIndex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVOWCapture);
+
+
+ if (mIsUseHeadsetMic) {
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_HEADSET_VOW_MIC);
+ if (mHeadsetMicMode == AUDIO_MIC_MODE_ACC) {
+ ALOGD("VOW1 HEADSET ACC");
+ mDeviceConfigManager->ApplyDeviceSettingByName(VOWMIC2_TYPE_ACCMODE);
+ } else if (mHeadsetMicMode == AUDIO_MIC_MODE_DCC) {
+ ALOGD("VOW1 HEADSET DCC");
+ mDeviceConfigManager->ApplyDeviceSettingByName(VOWMIC2_TYPE_DCCMODE);
+ } else if (mHeadsetMicMode == AUDIO_MIC_MODE_DCCECMDIFF) {
+ ALOGD("VOW1 HEADSET DCC DIFF");
+ mDeviceConfigManager->ApplyDeviceSettingByName(VOWMIC2_TYPE_DCCECMDIFFMODE);
+ } else if (mHeadsetMicMode == AUDIO_MIC_MODE_DCCECMSINGLE) {
+ ALOGD("VOW1 HEADSET DCC SINGLE");
+ mDeviceConfigManager->ApplyDeviceSettingByName(VOWMIC2_TYPE_DCCECMSINGLEMODE);
+ } else {
+ ALOGD("%s(), vow mic type error, mHeadsetMicMode=%d", __FUNCTION__, mHeadsetMicMode);
+ }
+ } else {
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_DMIC)) {
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_VOW_MIC);
+ if (mHandsetMicMode == AUDIO_MIC_MODE_DMIC_LP) {
+ ALOGD("VOW1 DMIC");
+ mDeviceConfigManager->ApplyDeviceSettingByName(VOWMIC1_TYPE_DMICLPMODE);
+ } else if (mHandsetMicMode == AUDIO_MIC_MODE_DMIC) {
+ ALOGD("VOW1 DMIC LP");
+ mDeviceConfigManager->ApplyDeviceSettingByName(VOWMIC1_TYPE_DMICMODE);
+ } else {
+ ALOGD("%s(), vow mic type error, mHandsetMicMode=%d", __FUNCTION__, mHandsetMicMode);
+ }
+ } else {
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_VOW_DUAL_MIC)) {
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_VOW_DUAL_MIC);
+ if (mHandsetMicMode == AUDIO_MIC_MODE_ACC) {
+ } else if (mHandsetMicMode == AUDIO_MIC_MODE_DCC) {
+ ALOGD("VOW1 VOW3 MAIN MIC DCC");
+ mDeviceConfigManager->ApplyDeviceSettingByName(VOWMIC1_TYPE_DCCMODE);
+ mDeviceConfigManager->ApplyDeviceSettingByName(VOWMIC3_TYPE_DCCMODE);
+ } else if (mHandsetMicMode == AUDIO_MIC_MODE_DCCECMDIFF) {
+ } else if (mHandsetMicMode == AUDIO_MIC_MODE_DCCECMSINGLE) {
+ } else {
+ ALOGD("%s(), vow mic type error, mHandsetMicMode=%d", __FUNCTION__, mHandsetMicMode);
+ }
+ } else {
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_VOW_MIC);
+ if (mHandsetMicMode == AUDIO_MIC_MODE_ACC) {
+ ALOGD("VOW1 MAIN MIC ACC");
+ mDeviceConfigManager->ApplyDeviceSettingByName(VOWMIC1_TYPE_ACCMODE);
+ } else if (mHandsetMicMode == AUDIO_MIC_MODE_DCC) {
+ ALOGD("VOW1 MAIN MIC DCC");
+ mDeviceConfigManager->ApplyDeviceSettingByName(VOWMIC1_TYPE_DCCMODE);
+ } else if (mHandsetMicMode == AUDIO_MIC_MODE_DCCECMDIFF) {
+ ALOGD("VOW1 MAIN MIC DCC DIFF");
+ mDeviceConfigManager->ApplyDeviceSettingByName(VOWMIC1_TYPE_DCCECMDIFFMODE);
+ } else if (mHandsetMicMode == AUDIO_MIC_MODE_DCCECMSINGLE) {
+ ALOGD("VOW1 MAIN MIC DCC SINGLE");
+ mDeviceConfigManager->ApplyDeviceSettingByName(VOWMIC1_TYPE_DCCECMSINGLEMODE);
+ } else {
+ ALOGD("%s(), vow mic type error, mHandsetMicMode=%d", __FUNCTION__, mHandsetMicMode);
+ }
+ }
+ }
+ }
+
+ mPcm = pcm_open(cardIndex, pcmIndex , PCM_IN, &config);
+ if (mPcm == NULL || pcm_is_ready(mPcm) == false) {
+ ALOGE("%s(), Unable to open pcm device %u (%s)", __FUNCTION__, pcmIndex, pcm_get_error(mPcm));
+ } else {
+ if (pcm_start(mPcm)) {
+ ALOGE("%s(), pcm_start %p fail due to %s", __FUNCTION__, mPcm, pcm_get_error(mPcm));
+ }
+ }
+#else
+ vow_channel = 1;
+
+ //set input MIC type
+ if (mIsUseHeadsetMic) {
+ //use headset mic
+ if (mHeadsetMicMode == AUDIO_MIC_MODE_ACC) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Vow_MIC_Type_Select"), "HeadsetMIC")) {
+ ALOGE("Error: Audio_Vow_MIC_Type_Select invalid value HeadsetMIC");
+ }
+ } else if (mHeadsetMicMode == AUDIO_MIC_MODE_DCC) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Vow_MIC_Type_Select"), "HeadsetMIC_DCC")) {
+ ALOGE("Error: Audio_Vow_MIC_Type_Select invalid value HeadsetMIC_DCC");
+ }
+ } else if (mHeadsetMicMode == AUDIO_MIC_MODE_DCCECMDIFF) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Vow_MIC_Type_Select"), "HeadsetMIC_DCCECM")) {
+ ALOGE("Error: Audio_Vow_MIC_Type_Select invalid value AUDIO_MIC_MODE_DCCECMDIFF");
+ }
+ } else if (mHeadsetMicMode == AUDIO_MIC_MODE_DCCECMSINGLE) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Vow_MIC_Type_Select"), "HeadsetMIC_DCCECM")) {
+ ALOGE("Error: Audio_Vow_MIC_Type_Select invalid value AUDIO_MIC_MODE_DCCECMSINGLE");
+ }
+ } else {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Vow_MIC_Type_Select"), "HeadsetMIC")) {
+ ALOGE("Error: Audio_Vow_MIC_Type_Select invalid value HeadsetMIC");
+ }
+ }
+ } else {
+ //DMIC device
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_DMIC)) {
+ if (mHandsetMicMode == AUDIO_MIC_MODE_DMIC_LP) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Vow_MIC_Type_Select"), "HandsetDMIC_800K")) {
+ ALOGE("Error: Audio_Vow_MIC_Type_Select invalid value HandsetDMIC_800K");
+ }
+ } else if(mHandsetMicMode == AUDIO_MIC_MODE_DMIC_VENDOR01) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Vow_MIC_Type_Select"), "HandsetDMIC_VENDOR01")) {
+ ALOGE("Error: Audio_Vow_MIC_Type_Select invalid value HandsetDMIC_VENDOR01");
+ }
+ } else { //normal DMIC
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Vow_MIC_Type_Select"), "HandsetDMIC")) {
+ ALOGE("Error: Audio_Vow_MIC_Type_Select invalid value HandsetDMIC");
+ }
+ }
+ } else { //analog MIC device
+ if (mHandsetMicMode == AUDIO_MIC_MODE_ACC) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Vow_MIC_Type_Select"), "HandsetAMIC")) {
+ ALOGE("Error: Audio_Vow_MIC_Type_Select invalid value HandsetAMIC");
+ }
+ } else if (mHandsetMicMode == AUDIO_MIC_MODE_DCC) { //DCC mems mic
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Vow_MIC_Type_Select"), "HandsetAMIC_DCC")) {
+ ALOGE("Error: Audio_Vow_MIC_Type_Select invalid value HandsetAMIC_DCC");
+ }
+ } else if (mHandsetMicMode == AUDIO_MIC_MODE_DCCECMDIFF) { //DCC ecm mic
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Vow_MIC_Type_Select"), "HandsetAMIC_DCCECM")) {
+ ALOGE("Error: Audio_Vow_MIC_Type_Select invalid value AUDIO_MIC_MODE_DCCECMDIFF");
+ }
+ } else if (mHandsetMicMode == AUDIO_MIC_MODE_DCCECMSINGLE) { //DCC ecm mic
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Vow_MIC_Type_Select"), "HandsetAMIC_DCCECM")) {
+ ALOGE("Error: Audio_Vow_MIC_Type_Select invalid value AUDIO_MIC_MODE_DCCECMSINGLE");
+ }
+ } else {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Vow_MIC_Type_Select"), "HandsetAMIC")) {
+ ALOGE("Error: Audio_Vow_MIC_Type_Select invalid value HandsetAMIC");
+ }
+ }
+ }
+ }
+
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Vow_ADC_Func_Switch"), "On")) {
+ ALOGE("Error: Audio_Vow_ADC_Func_Switch invalid value");
+ }
+
+ usleep(VOW_POWER_ON_SLEEP_MS * 1000);
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Vow_Digital_Func_Switch"), "On")) {
+ ALOGE("Error: Audio_Vow_Digital_Func_Switch invalid value");
+ }
+#endif
+ mic_type = getVOWMicType();
+ switch (mic_type) {
+ case AUDIO_MIC_MODE_DMIC:
+ mtkif_type = VOW_MTKIF_DMIC;
+ break;
+ case AUDIO_MIC_MODE_DMIC_LP:
+ case AUDIO_MIC_MODE_DMIC_VENDOR01:
+ mtkif_type = VOW_MTKIF_DMIC_LP;
+ break;
+ case AUDIO_MIC_MODE_ACC:
+ case AUDIO_MIC_MODE_DCC:
+ case AUDIO_MIC_MODE_DCCECMDIFF:
+ case AUDIO_MIC_MODE_DCCECMSINGLE:
+ mtkif_type = VOW_MTKIF_AMIC;
+ break;
+ default:
+ ALOGI("err: get wrong mic type, need check!\n");
+ ASSERT(0);
+ break;
+ }
+ temp = ((vow_channel - 1) << 4) | mtkif_type;
+ ret = ::ioctl(mFd_vow, VOW_RECOG_ENABLE, temp);
+ if (ret != 0) {
+ ALOGE("%s(), VOW_RECOG_ENABLE error, ret = %d", __FUNCTION__, ret);
+ }
+#ifdef MTK_VOW_BARGE_IN_SUPPORT
+ if (mIsSpeakerPlaying == true) {
+ cnt = 0;
+ while (mBargeInEnableOngoing) {
+ usleep(10 * 1000); // wait for BargeInEnable working
+ cnt++;
+ if (cnt > 100) { // if > 1sec not over then, assert it
+ ASSERT(0);
+ break;
+ }
+ }
+ setBargeInEnable(true);
+ }
+#endif
+ } else {
+ setVoiceWakeUpDebugDumpEnable(false);
+ temp = (0x00 << 4) | VOW_MTKIF_NONE;
+ ret = ::ioctl(mFd_vow, VOW_RECOG_DISABLE, temp);
+ if (ret != 0) {
+ ALOGE("%s(), VOW_RECOG_DISABLE error, ret = %d", __FUNCTION__, ret);
+ }
+#if defined(MTK_AUDIO_KS)
+ if (mPcm) {
+ pcm_stop(mPcm);
+ pcm_close(mPcm);
+ mPcm = NULL;
+ }
+
+ if (mIsUseHeadsetMic) {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_HEADSET_VOW_MIC);
+ } else {
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_DMIC)) {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_VOW_MIC);
+ } else {
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_VOW_DUAL_MIC)) {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_VOW_DUAL_MIC);
+ } else {
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(AUDIO_DEVICE_BUILTIN_MIC_VOW_MIC);
+ }
+ }
+ }
+#else
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Vow_Digital_Func_Switch"), "Off")) {
+ ALOGE("Error: Audio_Vow_Digital_Func_Switch invalid value");
+ }
+
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Vow_ADC_Func_Switch"), "Off")) {
+ ALOGE("Error: Audio_Vow_ADC_Func_Switch invalid value");
+ }
+#endif
+#ifdef MTK_VOW_BARGE_IN_SUPPORT
+ cnt = 0;
+ while (mBargeInEnableOngoing) {
+ usleep(10 * 1000); // wait for BargeInEnable working
+ cnt++;
+ if (cnt > 100) { // if > 1sec not over then, assert it
+ ASSERT(0);
+ break;
+ }
+ }
+ if (mBargeInEnable) {
+ setBargeInEnable(false);
+ }
+#endif
+ }
+
+ mEnable = enable;
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAVoiceWakeUpController::updateDeviceInfoForVoiceWakeUp() {
+ ALOGD("+%s(), mIsUseHeadsetMic = %d", __FUNCTION__, mIsUseHeadsetMic);
+
+ bool bIsUseHeadsetMic = AudioALSAStreamManager::getInstance()->getDeviceConnectionState(AUDIO_DEVICE_OUT_WIRED_HEADSET);
+
+ if (bIsUseHeadsetMic != mIsUseHeadsetMic) {
+ if (mEnable == false) {
+ mIsUseHeadsetMic = bIsUseHeadsetMic;
+ } else {
+ setVoiceWakeUpEnable(false);
+ mIsUseHeadsetMic = bIsUseHeadsetMic;
+ setVoiceWakeUpEnable(true);
+ }
+ }
+
+ ALOGD("-%s(), mIsUseHeadsetMic = %d, bIsUseHeadsetMic = %d", __FUNCTION__, mIsUseHeadsetMic, bIsUseHeadsetMic);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSAVoiceWakeUpController::updateVOWCustParam() {
+ AL_AUTOLOCK(mLock);
+
+ mIsNeedToUpdateParamToKernel = true;
+ return NO_ERROR;
+}
+
+unsigned int AudioALSAVoiceWakeUpController::getVOWMicType() {
+
+ if (mIsUseHeadsetMic) {
+ /* Headset */
+ return mHeadsetMicMode;
+ } else {
+ /* DMIC or Handset */
+ return mHandsetMicMode;
+ }
+}
+
+status_t AudioALSAVoiceWakeUpController::updateParamToKernel() {
+ if (mIsNeedToUpdateParamToKernel == true) {
+ mIsNeedToUpdateParamToKernel = false;
+
+ int vowCfg0 = 0;
+ int vowCfg1 = 0;
+ int vowCfg2 = 0;
+ int vowCfg3 = 0;
+ int vowCfg4 = 0;
+ int vowCfg5 = 0;
+ int vowPeriodicOnOffIdx = 0;
+
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ int custParam[10] = {0}; // all elements 0
+ unsigned long long *vowPeriodicOnOffParam;
+ unsigned int arraySize = 0;
+ struct mixer_ctl *ctl;
+ unsigned int i = 0;
+ unsigned int *ptr;
+
+ /* Get the vow common parameter from XML */
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ } else {
+ AudioType *audioType;
+ // define xml names
+ char audioTypeName[] = "VOW";
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, "VOW");
+ if (!audioType) {
+ ALOGE("%s(), get audioType fail, audioTypeName = %s",
+ __FUNCTION__, audioTypeName);
+ return BAD_VALUE;
+ }
+ Param *param = 0;
+ ALOGD("%s(), get vow param from XML:%p", __FUNCTION__, audioType);
+
+ std::string paramCommonPath = "VOW,VOW_common";
+
+ ParamUnit *paramUnit;
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramCommonPath.c_str());
+ if (!paramUnit) {
+ ALOGD("%s(), get paramUnit fail, paramPath = %s, use common",
+ __FUNCTION__,
+ paramCommonPath.c_str());
+ return BAD_VALUE;
+ }
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ param = appOps->paramUnitGetParamByName(paramUnit, "Par_01");
+ ASSERT(param);
+ custParam[0] = *(int *)param->data;
+ param = appOps->paramUnitGetParamByName(paramUnit, "Par_02");
+ ASSERT(param);
+ custParam[1] = *(int *)param->data;
+ param = appOps->paramUnitGetParamByName(paramUnit, "Par_03");
+ ASSERT(param);
+ custParam[2] = *(int *)param->data;
+ param = appOps->paramUnitGetParamByName(paramUnit, "Par_04");
+ ASSERT(param);
+ custParam[3] = *(int *)param->data;
+ param = appOps->paramUnitGetParamByName(paramUnit, "Par_05");
+ ASSERT(param);
+ custParam[4] = *(int *)param->data;
+ param = appOps->paramUnitGetParamByName(paramUnit, "Par_06");
+ ASSERT(param);
+ custParam[5] = *(int *)param->data;
+ param = appOps->paramUnitGetParamByName(paramUnit, "Par_07");
+ ASSERT(param);
+ custParam[6] = *(int *)param->data;
+ param = appOps->paramUnitGetParamByName(paramUnit, "Par_08");
+ ASSERT(param);
+ custParam[7] = *(int *)param->data;
+ param = appOps->paramUnitGetParamByName(paramUnit, "Par_09");
+ ASSERT(param);
+ custParam[8] = *(int *)param->data;
+ param = appOps->paramUnitGetParamByName(paramUnit, "Par_10");
+ ASSERT(param);
+ custParam[9] = *(int *)param->data;
+ /* Set Preiodic On/Off */
+ switch (custParam[9]) {
+ case 1:
+ param = appOps->paramUnitGetParamByName(paramUnit, "PeriodicOnOff_90");
+ break;
+ case 2:
+ param = appOps->paramUnitGetParamByName(paramUnit, "PeriodicOnOff_80");
+ break;
+ case 3:
+ param = appOps->paramUnitGetParamByName(paramUnit, "PeriodicOnOff_70");
+ break;
+ case 4:
+ param = appOps->paramUnitGetParamByName(paramUnit, "PeriodicOnOff_60");
+ break;
+ case 5:
+ param = appOps->paramUnitGetParamByName(paramUnit, "PeriodicOnOff_50");
+ break;
+ default:
+ param = appOps->paramUnitGetParamByName(paramUnit, "PeriodicOnOff_50");
+ break;
+ }
+ ASSERT(param);
+ arraySize = (unsigned int)param->arraySize;
+ vowPeriodicOnOffParam = new unsigned long long[arraySize];
+
+ ptr = (unsigned int *)param->data;
+ for (i = 0; i < arraySize; i++) {
+ vowPeriodicOnOffParam[i] = (unsigned long long)*ptr++;
+ }
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ ALOGD("%s(), vow periodic param size = %d", __FUNCTION__, arraySize);
+ for (i = 0; i < arraySize; i++) {
+ ALOGD("vow Perio[%d] = 0x%x", i, (unsigned int)vowPeriodicOnOffParam[i]);
+ }
+
+ if (mixer_ctl_set_array(mixer_get_ctl_by_name(mMixer, "Audio_VOW_Periodic_Param"),
+ &vowPeriodicOnOffParam[0],
+ sizeof(unsigned long long) * arraySize)) {
+ ALOGE("Error: Audio VOW Periodic On Off Param Data invalid value");
+ }
+ delete[] vowPeriodicOnOffParam;
+ }
+
+ ctl = mixer_get_ctl_by_name(mMixer, "Audio VOWCFG4 Data");
+ vowCfg4 = mixer_ctl_get_value(ctl, 0);
+ ALOGD("%s(), vowCfg4 load = 0x%x", __FUNCTION__, vowCfg4);
+ vowCfg0 = 0x0000;
+ vowCfg1 = 0x0000;
+ vowCfg2 = ((custParam[5] & 0x0007) << 12) |
+ ((custParam[6] & 0x0007) << 8) |
+ ((custParam[7] & 0x0007) << 4) |
+ ((custParam[8] & 0x0007));
+ vowCfg3 = ((custParam[0] & 0x000f) << 12) |
+ ((custParam[1] & 0x000f) << 8) |
+ ((custParam[2] & 0x000f) << 4) |
+ ((custParam[3] & 0x000f));
+ vowCfg4 &= 0xFFF0;
+ vowCfg4 |= custParam[4];
+ vowCfg5 = 0x0001;
+ vowPeriodicOnOffIdx = custParam[9];
+#endif
+ ALOGD("%s(), CFG0=0x%x, CFG1=0x%x, CFG2=0x%x, CF3=0x%x, CFG4=0x%x, CFG5=0x%x, Perio=0x%x",
+ __FUNCTION__,
+ vowCfg0,
+ vowCfg1,
+ vowCfg2,
+ vowCfg3,
+ vowCfg4,
+ vowCfg5,
+ vowPeriodicOnOffIdx);
+
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Audio VOWCFG0 Data"), 0, vowCfg0)) {
+ ALOGE("Error: Audio VOWCFG0 Data invalid value");
+ }
+
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Audio VOWCFG1 Data"), 0, vowCfg1)) {
+ ALOGE("Error: Audio VOWCFG1 Data invalid value");
+ }
+
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Audio VOWCFG2 Data"), 0, vowCfg2)) {
+ ALOGE("Error: Audio VOWCFG2 Data invalid value");
+ }
+
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Audio VOWCFG3 Data"), 0, vowCfg3)) {
+ ALOGE("Error: Audio VOWCFG3 Data invalid value");
+ }
+
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Audio VOWCFG4 Data"), 0, vowCfg4)) {
+ ALOGE("Error: Audio VOWCFG4 Data invalid value");
+ }
+
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Audio VOWCFG5 Data"), 0, vowCfg5)) {
+ ALOGE("Error: Audio VOWCFG5 Data invalid value");
+ }
+
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Audio_VOW_Periodic"), 0, vowPeriodicOnOffIdx)) {
+ ALOGE("Error: Audio VOW Periodic On Off Data invalid value");
+ }
+ }
+ return NO_ERROR;
+}
+
+void *AudioALSAVoiceWakeUpController::dumyReadThread(void *arg) {
+ AudioALSAVoiceWakeUpController *pWakeupController = static_cast<AudioALSAVoiceWakeUpController *>(arg);
+ short *pbuf = new short[160];
+
+ if (arg == 0) {
+ ALOGD("%s(), Error, arg=NULL", __FUNCTION__);
+ goto exit;
+ }
+ if (pWakeupController == 0) {
+ ALOGD("%s(), Error, pWakeupController=NULL", __FUNCTION__);
+ goto exit;
+ }
+ if (pWakeupController->hDumyReadThread == 0) {
+ goto exit;
+ }
+ if (!pWakeupController->mCaptureHandler) {
+ ALOGD("%s(), Error, mCaptureHandler not here", __FUNCTION__);
+ goto exit;
+ }
+ ALOGD("+%s(), dumyReadThread end, arg=%p", __FUNCTION__, arg);
+ while(pWakeupController->mDumpReadStart) {
+ pWakeupController->mCaptureHandler->read(&pbuf[0], 320);
+ ALOGV("read once");
+ }
+exit:
+ delete[] pbuf;
+ ALOGD("-%s(), dumyReadThread end", __FUNCTION__);
+ pthread_exit(NULL);
+ return NULL;
+}
+
+status_t AudioALSAVoiceWakeUpController::setVoiceWakeUpDebugDumpEnable(const bool enable) {
+ ALOGD("+%s(), mDebug_Enable: %d => %d", __FUNCTION__, mDebug_Enable, enable);
+ status_t status;
+ int ret = -1;
+
+ AL_AUTOLOCK(mDebugDumpLock);
+ if (mDebug_Enable == enable) {
+ ALOGW("-%s(), enable(%d) == mDebug_Enable(%d), return", __FUNCTION__, enable, mDebug_Enable);
+ return INVALID_OPERATION;
+ }
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get(streamin_propty, value, "0");
+ int bflag = atoi(value);
+
+ if (bflag && enable) {
+ if (!mDebug_Enable) {
+ //enable VOW debug dump
+ mCaptureHandler = new AudioALSACaptureHandlerVOW(stream_attribute_target);
+ status = mCaptureHandler->open();
+ if (mDumpReadStart == false) {
+ mDumpReadStart = true;
+ ret = pthread_create(&hDumyReadThread, NULL, AudioALSAVoiceWakeUpController::dumyReadThread, (void *)this);
+ // if pthread_create pass will return 0, otherwise is error message
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+ }
+#ifdef MTK_VOW_BARGE_IN_SUPPORT
+ ret = ::ioctl(mFd_vow, VOW_SET_CONTROL, (unsigned int)VOWControlCmd_EnableBargeinDump);
+ ALOGD("%s(), EnableBargeinDump set, ret = %d", __FUNCTION__, ret);
+ if (ret != 0) {
+ ALOGE("%s(), EnableBargeinDump error, ret = %d", __FUNCTION__, ret);
+ }
+#endif // #ifdef MTK_VOW_BARGE_IN_SUPPORT
+ mDebug_Enable = true;
+ }
+ } else {
+ if (mDebug_Enable) {
+ //disable VOW debug dump
+ if (mDumpReadStart == true) {
+ mDumpReadStart = false;
+ pthread_join(hDumyReadThread, NULL);
+ }
+ status = mCaptureHandler->close();
+ delete mCaptureHandler;
+#ifdef MTK_VOW_BARGE_IN_SUPPORT
+ ret = ::ioctl(mFd_vow, VOW_SET_CONTROL, (unsigned int)VOWControlCmd_DisableBargeinDump);
+ ALOGD("%s(), DisableBargeinDump set, ret = %d", __FUNCTION__, ret);
+ if (ret != 0) {
+ ALOGE("%s(), DisableBargeinDump error, ret = %d", __FUNCTION__, ret);
+ }
+#endif // #ifdef MTK_VOW_BARGE_IN_SUPPORT
+ mDebug_Enable = false;
+ }
+ }
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+bool AudioALSAVoiceWakeUpController::getVoiceWakeUpStateFromKernel() {
+ ALOGD("%s()+", __FUNCTION__);
+ bool bRet = false;
+ struct mixer_ctl *ctl;
+ ctl = mixer_get_ctl_by_name(mMixer, "Audio_VOW_State");
+ bRet = mixer_ctl_get_value(ctl, 0);
+ ALOGD("%s(), state = 0x%x", __FUNCTION__, bRet);
+
+ return bRet;
+}
+
+
+bool AudioALSAVoiceWakeUpController::updateSpeakerPlaybackStatus(bool isSpeakerPlaying) {
+ ALOGD("%s(), isSpeakerPlaying = %d", __FUNCTION__, isSpeakerPlaying);
+ bool ret = true;
+#ifdef MTK_VOW_BARGE_IN_SUPPORT
+ unsigned int cnt;
+ mIsSpeakerPlaying = isSpeakerPlaying;
+
+ if (getVoiceWakeUpEnable()) {
+ cnt = 0;
+ while (mBargeInEnableOngoing) {
+ usleep(10 * 1000); // wait for BargeInEnable working
+ cnt++;
+ if (cnt > 100) { // if > 1sec not over then, assert it
+ ASSERT(0);
+ break;
+ }
+ }
+ if ((isSpeakerPlaying == true) && !mBargeInEnable) {
+ ret = setBargeInEnable(true);
+ } else if ((isSpeakerPlaying == false) && mBargeInEnable) {
+ ret = setBargeInEnable(false);
+ }
+ }
+#endif
+ return ret;
+}
+
+bool AudioALSAVoiceWakeUpController::setBargeInEnable(const bool enable) {
+ ALOGD("+%s(), enable = %d", __FUNCTION__, enable);
+#ifdef MTK_VOW_BARGE_IN_SUPPORT
+ int ret;
+ if (enable) {
+ ASSERT(mBargeInPcm == NULL);
+ mBargeInEnableOngoing = true;
+
+ // open and start barge-in PCM device
+ int pcmUlIndex = 0;
+ int cardUlIndex = 0;
+ int pcmUlRet = 0;
+ const int interruptIntervalMs = 10; // Interrupt rate from AP to SCP is 10ms
+
+#if defined(MTK_AUDIO_KS)
+ int pcmHostlessSrcIndex = 0;
+ int cardHostlessSrcIndex = 0;
+ int pcmHostlessUlRet = 0;
+ int pcmHostlessDlRet = 0;
+
+ AudioALSASampleRateController *pAudioALSASampleRateController = AudioALSASampleRateController::getInstance();
+ pAudioALSASampleRateController->setScenarioStatus(PLAYBACK_SCENARIO_VOW_BARGE_IN);
+
+ mSrcUlConfig.stop_threshold = ~(0U);
+ mSrcUlConfig.rate = AudioALSASampleRateController::getInstance()->getPrimaryStreamOutSampleRate();
+ mSrcUlConfig.format = PCM_FORMAT_S16_LE;
+ mSrcUlConfig.channels = 2;
+ mSrcUlConfig.period_size = interruptIntervalMs * mSrcUlConfig.rate / 1000;
+ mSrcUlConfig.period_count = 4;
+ mSrcUlConfig.start_threshold = 0;
+ mSrcUlConfig.silence_size = 0;
+ mSrcUlConfig.silence_threshold = 0;
+ mSrcUlConfig.avail_min = 0;
+
+ ALOGD("%s(), format = %d, channels=%d, rate=%d, period_size=%d, period_count=%d", __FUNCTION__,
+ mSrcUlConfig.format, mSrcUlConfig.channels, mSrcUlConfig.rate, mSrcUlConfig.period_size, mSrcUlConfig.period_count);
+
+#ifdef MTK_AUDIODSP_SUPPORT
+ if (AudioDspStreamManager::getInstance()->getDspPlaybackEnable() == true) {
+ mBargeInTurnOnSequence = AUDIO_CTL_VOW_BARGE_IN_ECHO_SPEAKER_HIFI3;
+ } else if (AudioSmartPaController::getInstance()->getSpkProtectType() == SPK_ONBOARD_DSP) {
+ mBargeInTurnOnSequence = AUDIO_CTL_VOW_BARGE_IN_ECHO_DSP_SMARTPA;
+ } else {
+ mBargeInTurnOnSequence = AUDIO_CTL_VOW_BARGE_IN_ECHO;
+ }
+#else
+ if (AudioSmartPaController::getInstance()->getSpkProtectType() == SPK_ONBOARD_DSP) {
+ mBargeInTurnOnSequence = AUDIO_CTL_VOW_BARGE_IN_ECHO_DSP_SMARTPA;
+ } else {
+ mBargeInTurnOnSequence = AUDIO_CTL_VOW_BARGE_IN_ECHO;
+ }
+#endif
+ mDeviceConfigManager->ApplyDeviceTurnonSequenceByName(mBargeInTurnOnSequence);
+
+ if (AudioSmartPaController::getInstance()->getSpkProtectType() == SPK_ONBOARD_DSP) {
+ pcmHostlessSrcIndex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessSRCBargein);
+ cardHostlessSrcIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmHostlessSRCBargein);
+
+ mPcmHostlessUl = pcm_open(cardHostlessSrcIndex, pcmHostlessSrcIndex, PCM_IN, &mSrcUlConfig);
+ mPcmHostlessDl = pcm_open(cardHostlessSrcIndex, pcmHostlessSrcIndex, PCM_OUT, &mSrcUlConfig);
+
+ if (mPcmHostlessUl == NULL) {
+ ALOGE("%s(), mPcmHostlessUl == NULL!! mPcmHostlessUl = %p, pcmUlIndex = %d, cardUlIndex = %d", __FUNCTION__, mPcmHostlessUl, pcmHostlessSrcIndex, cardHostlessSrcIndex);
+ } else if (pcm_is_ready(mPcmHostlessUl) == false) {
+ ALOGE("%s(), pcm_is_ready(%p) == false due to %s, close pcm.", __FUNCTION__, mPcmHostlessUl, pcm_get_error(mPcmHostlessUl));
+ pcm_close(mPcmHostlessUl);
+ mPcmHostlessUl = NULL;
+ } else {
+ pcmHostlessUlRet = pcm_start(mPcmHostlessUl);
+ }
+
+ if (mPcmHostlessDl == NULL) {
+ ALOGE("%s(), mPcmHostlessDl == NULL!! mPcmHostlessDl = %p, pcmUlIndex = %d, cardUlIndex = %d", __FUNCTION__, mPcmHostlessDl, pcmHostlessSrcIndex, cardHostlessSrcIndex);
+ } else if (pcm_is_ready(mPcmHostlessDl) == false) {
+ ALOGE("%s(), pcm_is_ready(%p) == false due to %s, close pcm.", __FUNCTION__, mPcmHostlessDl, pcm_get_error(mPcmHostlessDl));
+ pcm_close(mPcmHostlessDl);
+ mPcmHostlessDl = NULL;
+ } else {
+ pcmHostlessDlRet = pcm_start(mPcmHostlessDl);
+ }
+ ALOGD("-%s(),mPcmHostlessUl = %p, pcmHostlessUlRet = %d, mPcmHostlessDl = %p, pcmHostlessDlRet = %d", __FUNCTION__, mPcmHostlessUl, pcmHostlessUlRet, mPcmHostlessDl, pcmHostlessDlRet);
+ }
+
+ pcmUlIndex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmCapture2);
+ cardUlIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmCapture2);
+
+#else
+ pcmUlIndex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVOWBargeInCapture);
+ cardUlIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVOWBargeInCapture);
+#endif
+
+ memset((void *)&mSrcDlConfig, 0, sizeof(mSrcDlConfig));
+ mSrcDlConfig.channels = 2;
+ mSrcDlConfig.rate = 16000;
+ mSrcDlConfig.format = PCM_FORMAT_S16_LE;
+
+ //mSrcDlConfig.period_size = 640;
+ mSrcDlConfig.period_size = interruptIntervalMs * mSrcDlConfig.rate / 1000;
+ mSrcDlConfig.period_count = 4; // Allocate 40ms DMA buffer
+
+ mSrcDlConfig.start_threshold = 0;
+ mSrcDlConfig.stop_threshold = ~(0U);
+ mSrcDlConfig.silence_threshold = 0;
+
+ mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Vow_bargein_echo_ref"), 0, 1);
+ mBargeInPcm = pcm_open(cardUlIndex, pcmUlIndex, PCM_IN, &mSrcDlConfig);
+ if (mBargeInPcm == NULL) {
+ ALOGE("%s(), mBargeInPcm == NULL!! mBargeInPcm = %p, pcmUlIndex = %d, cardUlIndex = %d", __FUNCTION__, mBargeInPcm, pcmUlIndex, cardUlIndex);
+ } else if (pcm_is_ready(mBargeInPcm) == false) {
+ ALOGE("%s(), pcm_is_ready(%p) == false due to %s, close pcm.", __FUNCTION__, mBargeInPcm, pcm_get_error(mBargeInPcm));
+ pcm_close(mBargeInPcm);
+ mBargeInPcm = NULL;
+ } else {
+ pcmUlRet = pcm_start(mBargeInPcm);
+ }
+ mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "Vow_bargein_echo_ref"), 0, 0);
+
+ ALOGD("%s(), mBargeInPcm = %p, pcmUlRet = %d", __FUNCTION__, mBargeInPcm, pcmUlRet);
+ ASSERT(mBargeInPcm != NULL);
+ mBargeInEnable = true;
+ mBargeInEnableOngoing = false;
+ ret = ::ioctl(mFd_vow, VOW_SET_CONTROL, (unsigned int)VOW_BARGEIN_ON);
+ ALOGD("%s(), VOW_BARGEIN_ON set, ret = %d", __FUNCTION__, ret);
+ if (ret != 0) {
+ ALOGE("%s(), VOW_BARGEIN_ON error, ret = %d", __FUNCTION__, ret);
+ }
+ } else {
+ if (mBargeInPcm != NULL) {
+ mBargeInEnableOngoing = true;
+ ret = ::ioctl(mFd_vow, VOW_SET_CONTROL, (unsigned int)VOW_BARGEIN_OFF);
+ ALOGD("%s(), VOW_BARGEIN_OFF set, ret = %d", __FUNCTION__, ret);
+ if (ret != 0) {
+ ALOGE("%s(), VOW_BARGEIN_OFF error, ret = %d", __FUNCTION__, ret);
+ }
+ pcm_stop(mBargeInPcm);
+ pcm_close(mBargeInPcm);
+ if (mPcmHostlessUl != NULL) {
+ pcm_stop(mPcmHostlessUl);
+ pcm_close(mPcmHostlessUl);
+ }
+ if (mPcmHostlessDl != NULL) {
+ pcm_stop(mPcmHostlessDl);
+ pcm_close(mPcmHostlessDl);
+ }
+
+#if defined(MTK_AUDIO_KS)
+ mDeviceConfigManager->ApplyDeviceTurnoffSequenceByName(mBargeInTurnOnSequence);
+ AudioALSASampleRateController *pAudioALSASampleRateController = AudioALSASampleRateController::getInstance();
+ pAudioALSASampleRateController->resetScenarioStatus(PLAYBACK_SCENARIO_VOW_BARGE_IN);
+#endif
+
+ mBargeInPcm = NULL;
+ mBargeInEnable = false;
+ mBargeInEnableOngoing = false;
+ }
+
+ ALOGD("-%s(), mBargeInPcm = %p", __FUNCTION__, mBargeInPcm);
+ }
+#endif
+ return true;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioAMPControlInterface..cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioAMPControlInterface..cpp
new file mode 100644
index 0000000..df3c167
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioAMPControlInterface..cpp
@@ -0,0 +1,314 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#define LOG_TAG "AudioAMPControl"
+#define MTK_LOG_ENABLE 1
+#include <log/log.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+//#include "AudioIoctl.h" //ccc mark for build pass
+#include <utils/threads.h>
+#include"AudioAMPControlInterface.h"
+
+namespace {
+
+using namespace android;
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// AMP Control
+
+class AudioAMPControl : public AudioAMPControlInterface {
+public:
+ AudioAMPControl(int fb);
+ ~AudioAMPControl();
+ bool setSpeaker(bool on);
+ bool setHeadphone(bool on);
+ bool setReceiver(bool on);
+ status_t setVolume(void *points, int num, int device);
+ void setMode(audio_mode_t mode);
+ int setParameters(int command1, int command2, unsigned int data);
+ int getParameters(int command1, int command2, void *data);
+private:
+ int selectPathMask(audio_mode_t phoneState, audio_devices_t device);
+private:
+ int mFd;
+ bool mSpeakerOn;
+ bool mReceiverOn;
+ bool mHeadphoneOn;
+ audio_mode_t mMode;
+ Mutex mLock;
+};
+
+
+static int shiftAMPGain(uint8_t *points, int num, int mask)
+//points 0: in1 index, 1: SPK index, 2: in 2 index, 3: HP index
+//mask IN1 IN2 SPK HP
+{
+ // Analog, INPUT1, INPUT2 , SPEAKER , HP , mask
+ //xxxxxxxxxxxxxx, xx, xx, xxxxx, xxxxx, xxxx (32 bits)
+ uint8_t *p = points;
+ int amp = 0;
+ SLOGD("p[0] is 0x%x, p[1] is 0x%x, p[2] is 0x%x, p[3] is 0x%x", p[0], p[1], p[2], p[3]);
+
+ amp = mask & 0xF; //mask
+ amp = ((p[3] & 0x1F) << 5 | amp); //hpr
+ amp = ((p[3] & 0x1F) << 10 | amp); //hpl
+ amp = ((p[1] & 0x1F) << 15 | amp); //speaker
+ amp = ((p[2] & 0x03) << 20 | amp); //IN2
+ amp = ((p[0] & 0x03) << 22 | amp); //IN1
+
+ return amp;
+}
+
+AudioAMPControl::AudioAMPControl(int fd)
+ : mFd(fd),
+ mSpeakerOn(false),
+ mReceiverOn(false),
+ mHeadphoneOn(false),
+ mMode(AUDIO_MODE_INVALID) {
+}
+
+AudioAMPControl::~AudioAMPControl() {
+
+}
+
+bool AudioAMPControl::setSpeaker(bool on) {
+ SLOGD("setSpeaker::mode=%d,prestate=%d,state=%d", mMode, mSpeakerOn, on);
+ Mutex::Autolock autoLock(mLock);
+ int ret = NO_ERROR;
+ if (mSpeakerOn == on) {
+ return true;
+ }
+ if (on) {
+ //ret = ::ioctl(mFd,SET_SPEAKER_ON,Channel_Stereo);// enable speaker //ccc mark for build pass
+ } else {
+ //ret = ::ioctl(mFd,SET_SPEAKER_OFF,Channel_Stereo);// disable speaker //ccc mark for build pass
+ }
+ if (ret < 0) {
+ SLOGW(" setSpeaker(%d) error %s (%d)", on, ::strerror(errno), errno);
+ return false;
+ }
+ mSpeakerOn = on;
+ return true;
+}
+
+bool AudioAMPControl::setHeadphone(bool on) {
+ SLOGD("setHeadphone::mode=%d,prestate=%d,state=%d", mMode, mHeadphoneOn, on);
+ Mutex::Autolock autoLock(mLock);
+ int ret = NO_ERROR;
+ if (mHeadphoneOn == on) {
+ return true;
+ }
+ if (on) {
+ //ret = ::ioctl(mFd,SET_HEADPHONE_ON,Channel_Stereo);// enable headphone, //ccc mark for build pass
+ } else {
+ //ret = ::ioctl(mFd,SET_HEADPHONE_OFF,Channel_Stereo);// disable headphone, //ccc mark for build pass
+ }
+ if (ret < 0) {
+ SLOGW(" setHeadphone(%d) error %s (%d)", on, ::strerror(errno), errno);
+ return false;
+ }
+ mHeadphoneOn = on;
+ return true;
+}
+
+bool AudioAMPControl::setReceiver(bool on) {
+ SLOGD("setReceiver::mode=%d,prestate=%d,state=%d", mMode, mReceiverOn, on);
+ Mutex::Autolock autoLock(mLock);
+ int ret = NO_ERROR;
+ if (mReceiverOn == on) {
+ return true;
+ }
+ if (on) {
+ //ret = ::ioctl(mFd,SET_EARPIECE_ON,Channel_Stereo);// enable earpiece, //ccc mark for build pass
+ } else {
+ //ret = ::ioctl(mFd,SET_EARPIECE_OFF,Channel_Stereo);// diable earpiece //ccc mark for build pass
+ }
+ if (ret < 0) {
+ SLOGW(" setreceiver(%d) error %s (%d)", on, ::strerror(errno), errno);
+ return false;
+ }
+ mReceiverOn = on;
+ return true;
+}
+
+status_t AudioAMPControl::setVolume(void *points, int num, int device) {
+ Mutex::Autolock autoLock(mLock);
+ int mask = selectPathMask(mMode, (audio_devices_t)device);
+ SLOGD("setVolume mask 0x%x", mask);
+ int amp = shiftAMPGain((uint8_t *)points, num, mask);
+ SLOGD("setVolume amp 0x%x", amp);
+ return setParameters(AUD_AMP_SET_AMPGAIN, 0, amp);
+}
+
+void AudioAMPControl::setMode(audio_mode_t mode) {
+ SLOGD("setMode mode=%d", mode);
+ // do not use lock here ,because setparameter will try to get lock.
+ setParameters(AUD_AMP_SET_MODE, 0, mode);
+ return;
+}
+
+status_t AudioAMPControl::setParameters(int command1, int command2, unsigned int data) {
+ SLOGD("setparameters commad1 = %d command2 = %d,data=%u", command1, command2, data);
+ status_t ret = NO_ERROR;
+ AMP_Control command;
+ memset(&command, 0, sizeof(AMP_Control));
+ switch (command1) {
+ case AUD_AMP_SET_REGISTER: {
+ command.command = command1;
+ command.param1 = command2;
+ command.param2 = data;
+ //ret =::ioctl(mFd,SET_EAMP_PARAMETER,&command);//ccc mark for build pass
+ break;
+ }
+ case AUD_AMP_SET_AMPGAIN: {
+ command.command = command1;
+ command.param1 = data;
+ //ret =::ioctl(mFd,SET_EAMP_PARAMETER,&command);//ccc mark for build pass
+ break;
+ }
+ case AUD_AMP_SET_MODE: {
+ command.command = command1;
+ command.param1 = data;
+ mMode = (audio_mode_t)data;
+ //ret =::ioctl(mFd,SET_EAMP_PARAMETER,&command);//ccc mark for build pass
+ break;
+ }
+ default:
+ break;
+ }
+ if (ret < 0) {
+ SLOGW(" setParameters(%d) error %s (%d)", command1, ::strerror(errno), errno);
+ }
+ return ret;
+}
+
+int AudioAMPControl::getParameters(int command1, int command2, void *data) {
+ SLOGD("getparameters command = %d command2 = %d,data=%p", command1, command2, data);
+ Mutex::Autolock autoLock(mLock);
+ int ret = NO_ERROR;
+ AMP_Control command;
+ memset(&command, 0, sizeof(AMP_Control));
+ switch (command1) {
+ case AUD_AMP_GET_CTRP_NUM:
+ case AUD_AMP_GET_CTRP_BITS:
+ case AUD_AMP_GET_REGISTER:
+ case AUD_AMP_GET_AMPGAIN: {
+ command.command = command1;
+ command.param1 = command2;
+ //ret =::ioctl(mFd,GET_EAMP_PARAMETER,&command);//ccc mark for build pass
+ if (data) {
+ int *p = (int *)data;
+ *p = ret;
+ }
+ break;
+ }
+ case AUD_AMP_GET_CTRP_TABLE: {
+ command.command = command1;
+ command.param1 = command2;
+ command.param2 = (unsigned long int)data;
+ //ret =::ioctl(mFd,GET_EAMP_PARAMETER,&command);//ccc mark for build pass
+ break;
+ }
+
+ default:
+ break;
+
+ }
+ if (ret < 0) {
+ SLOGW(" getParameters(%d) error %s (%d)", command1, ::strerror(errno), errno);
+ }
+ return ret;
+}
+
+int AudioAMPControl::selectPathMask(audio_mode_t phoneState, audio_devices_t device) {
+ ALOGV("getAmpValidMask phoneState %d, device 0x%x", phoneState, device);
+ //use 5bits for valid amp gain
+ //IN1(CP0), IN2(CP2), SPK(CP1), HP(CP3):xxxx(4bits)
+ //normal mode/call mode disable USING_EXTAMP_ALL_VOICE_BUFFER:headphone:cp0,cp3;speaker:cp1,cp2
+ //call mode enable USING_EXTAMP_ALL_VOICE_BUFFER:headphone:cp2,cp3;speaker:cp1,cp2
+ int mask = 0; //00000 (not use)
+ if (device & AUDIO_DEVICE_OUT_SPEAKER || device == 0) {
+ mask = 0x6;//0110
+
+ }
+ if (device & AUDIO_DEVICE_OUT_WIRED_HEADSET || device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+#ifdef USING_EXTAMP_ALL_VOICE_BUFFER
+ if (phoneState == AUDIO_MODE_IN_CALL) {
+ mask = mask | 0x5; //0101
+ } else
+#endif
+ {
+ mask = mask | 0x9; //1001
+ }
+
+ }
+ if (device & AUDIO_DEVICE_OUT_EARPIECE) {
+ mask = 0; //0000 not use
+ }
+ return mask;
+}
+
+//AMP Control end
+//---------------------------------------------------------------------------------
+}
+
+namespace android {
+
+AudioAMPControlInterface *AudioDeviceManger::mInstance = NULL;
+
+AudioAMPControlInterface *AudioDeviceManger::createInstance() {
+ if (! mInstance) {
+#if 0//ccc mark for build pass
+ int fd = -1;
+ // here open audio hardware for register setting
+ fd = ::open(kAudioDeviceName, O_RDWR);
+ if (fd < 0) {
+ ALOGE("AudioDeviceManger open fd fail");
+ return NULL;
+ }
+ mInstance = new AudioAMPControl(fd);
+#endif
+ }
+ return mInstance;
+}
+
+
+}
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioBTCVSDControl.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioBTCVSDControl.cpp
new file mode 100644
index 0000000..3a14e9b
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioBTCVSDControl.cpp
@@ -0,0 +1,2786 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioBTCVSDControl.h"
+
+#include <sys/ioctl.h>
+#include <utils/Log.h>
+#include <dlfcn.h>
+#include <inttypes.h>
+
+#include <AudioLock.h>
+#include "AudioAssert.h"
+
+#if 1 // TODO(Harvey): BT Loopback
+#include "AudioALSALoopbackController.h"
+#endif
+
+#include "AudioALSADeviceParser.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioBTCVSDControl"
+
+/// kernel/drivers/btcvsd related
+static char const *const kBTCVSDDeviceName = "/dev/ebc";
+
+#define AUD_DRV_IOC_MAGIC 'C'
+#define ALLOCATE_FREE_BTCVSD_BUF _IOWR(AUD_DRV_IOC_MAGIC, 0xE0, unsigned int)
+#define SET_BTCVSD_STATE _IOWR(AUD_DRV_IOC_MAGIC, 0xE1, unsigned int)
+#define GET_BTCVSD_STATE _IOWR(AUD_DRV_IOC_MAGIC, 0xE2, unsigned int)
+#define GET_BTCVSD_RX_TIME_BUFFER_INFO _IOWR(AUD_DRV_IOC_MAGIC, 0xE3, unsigned long long)
+#define GET_BTCVSD_TX_TIME_BUFFER_INFO _IOWR(AUD_DRV_IOC_MAGIC, 0xE4, unsigned long long)
+
+
+
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+
+namespace android {
+
+#define BTSCO_CVSD_SAMPLERATE_DOMAIN 64000
+#define BTSCO_MSBC_SAMPLERATE_DOMAIN 16000
+#define BTSCO_CVSD_PLC_SAMPLERATE 8000
+#define BTSCO_CVSD_CHANNEL_NUM 1
+#define BTSCO_MSBC_CHANNEL_NUM 1
+
+#ifdef EXT_MODEM_BT_CVSD
+#define BTSCO_EXTMD_SAMPLERATE 8000
+#endif
+
+static const int32_t btsco_FilterCoeff_64K[4] = {0x07F54A0C, (int32_t)0xF017CB31, 0x07F2EB36, 0x7F41C0BE};
+static const int32_t btsco_FilterCoeff_8K[4] = {0x07AB676D, (int32_t)0xF0BB80B9, 0x079933A1, 0x79F9C5B0};
+BTSCO_CVSD_Context *AudioBTCVSDControl::mBTSCOCVSDContext = NULL;
+
+
+AudioBTCVSDControl *AudioBTCVSDControl::UniqueAudioBTCVSDControl = NULL;
+
+static TimeBufferInfo gTimeBufferInfo;
+
+AudioBTCVSDControl *AudioBTCVSDControl::getInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+
+ if (UniqueAudioBTCVSDControl == NULL) {
+ ALOGD("+AudioBTCVSDControl");
+ UniqueAudioBTCVSDControl = new AudioBTCVSDControl();
+ ALOGD("-AudioBTCVSDControl");
+ }
+ ALOGD("AudioBTCVSDControl getInstance()");
+ return UniqueAudioBTCVSDControl;
+}
+
+void AudioBTCVSDControl::freeInstance() {
+ if (UniqueAudioBTCVSDControl != NULL) {
+ delete UniqueAudioBTCVSDControl;
+ }
+ ALOGD("AudioBTCVSDControl freeInstance()");
+}
+
+AudioBTCVSDControl::AudioBTCVSDControl() :
+ mBTCVSDRXTempInBuf(NULL),
+ mBTCVSDRXInBuf(NULL),
+ mBTCVSDTXOutBuf(NULL),
+#ifdef EXT_MODEM_BT_CVSD
+ mExtMDbtscoULBuf(NULL),
+ mExtMDbtscoULWTmpBuf(NULL),
+ mExtMDbtscoULWTmpBuf2(NULL),
+ mExtMDbtscoDLBuf(NULL),
+#endif
+ mTXSRCPCMDumpFile(NULL),
+ mBTCVSDRXDumpFile(NULL),
+ mBTCVSDRXInDumpFile(NULL),
+ BTmode(BT_SCO_MODE_CVSD),
+ mExtMDBTSCORunning(false),
+ mAudioBTCVSDControl(NULL)
+#if defined(BTCVSD_ENC_DEC_LOOPBACK) || defined(BTCVSD_KERNEL_LOOPBACK)
+ , mCVSDloopbackPCMDumpFile(NULL)
+#endif
+{
+#ifdef EXT_MODEM_BT_CVSD
+ memset(&mULRingBuf, 0, sizeof(mULRingBuf));
+ memset(&mDLRingBuf, 0, sizeof(mDLRingBuf));
+#endif
+ ALOGD("AudioBTCVSDControl constructor");
+
+ ASSERT(initCvsdLib() == 0);
+ ASSERT(initMsbcLib() == 0);
+
+ BT_SCO_CVSD_Init();
+
+ mFd2 = -1;
+}
+
+AudioBTCVSDControl::~AudioBTCVSDControl() {
+ ALOGD("AudioBTCVSDControl destructor");
+
+ BT_SCO_CVSD_DeInit();
+
+ // close lib
+ if (mCvsdLib.handle) {
+ if (dlclose(mCvsdLib.handle)) {
+ ALOGE("%s(), dlclose cvsd lib failed, dlerror = %s", __FUNCTION__, dlerror());
+ }
+ }
+
+ if (mMsbcLib.handle) {
+ if (dlclose(mMsbcLib.handle)) {
+ ALOGE("%s(), dlclose msbc lib failed, dlerror = %s", __FUNCTION__, dlerror());
+ }
+ }
+}
+
+int AudioBTCVSDControl::initCvsdLib() {
+#if defined(__LP64__)
+#define AUDIO_CVSD_LIB_VENDOR_PATH "/vendor/lib64/libcvsd_mtk.so"
+#define AUDIO_CVSD_LIB_PATH "/system/lib64/libcvsd_mtk.so"
+#else
+#define AUDIO_CVSD_LIB_VENDOR_PATH "/vendor/lib/libcvsd_mtk.so"
+#define AUDIO_CVSD_LIB_PATH "/system/lib/libcvsd_mtk.so"
+#endif
+
+ memset(&mCvsdLib, 0, sizeof(struct BtCodecLib));
+
+ // load bt lib
+ if (access(AUDIO_CVSD_LIB_VENDOR_PATH, R_OK) == 0) {
+ mCvsdLib.handle = dlopen(AUDIO_CVSD_LIB_VENDOR_PATH, RTLD_NOW);
+ } else if (access(AUDIO_CVSD_LIB_PATH, R_OK) == 0) {
+ mCvsdLib.handle = dlopen(AUDIO_CVSD_LIB_PATH, RTLD_NOW);
+ } else {
+ ALOGE("%s(), no valid lib path", __FUNCTION__);
+ }
+
+ // dlsym lib func
+ if (!mCvsdLib.handle) {
+ ALOGE("%s(), dlopen failed, dlerror = %s", __FUNCTION__, dlerror());
+ } else {
+ mCvsdLib.decInit = (void *(*)(signed char *))dlsym(mCvsdLib.handle, "CVSD_DEC_Init");
+ if (!mCvsdLib.decInit) {
+ ALOGE("%s(), mCvsdLib.decInit dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ return -EIO;
+ }
+ mCvsdLib.encInit = (void *(*)(signed char *))dlsym(mCvsdLib.handle, "CVSD_ENC_Init");
+ if (!mCvsdLib.encInit) {
+ ALOGE("%s(), mCvsdLib.encInit dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ return -EIO;
+ }
+ mCvsdLib.decProcess = (int (*)(void *, char *, int *, short *, int *))dlsym(mCvsdLib.handle, "CVSD_DEC_Process");
+ if (!mCvsdLib.decProcess) {
+ ALOGE("%s(), mCvsdLib.decProcess dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ return -EIO;
+ }
+ mCvsdLib.encProcess = (int (*)(void *, short *, int *, char *, int *))dlsym(mCvsdLib.handle, "CVSD_ENC_Process");
+ if (!mCvsdLib.encProcess) {
+ ALOGE("%s(), mCvsdLib.encProcess dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ return -EIO;
+ }
+ mCvsdLib.decGetBufferSize = (int (*)())dlsym(mCvsdLib.handle, "CVSD_DEC_GetBufferSize");
+ if (!mCvsdLib.decGetBufferSize) {
+ ALOGE("%s(), mCvsdLib.decGetBufferSize dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ return -EIO;
+ }
+ mCvsdLib.encGetBufferSize = (int (*)())dlsym(mCvsdLib.handle, "CVSD_ENC_GetBufferSize");
+ if (!mCvsdLib.encGetBufferSize) {
+ ALOGE("%s(), mCvsdLib.encGetBufferSize dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ return -EIO;
+ }
+ // plc
+ mCvsdLib.g711plc_GetMemorySize_v2 = (int (*)())dlsym(mCvsdLib.handle, "g711plc_GetMemorySize_v2");
+ if (!mCvsdLib.g711plc_GetMemorySize_v2) {
+ ALOGE("%s(), mCvsdLib.g711plc_GetMemorySize_v2 dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ return -EIO;
+ }
+ mCvsdLib.g711plc_construct_v2 = (void (*)(void *, unsigned int))dlsym(mCvsdLib.handle, "g711plc_construct_v2");
+ if (!mCvsdLib.g711plc_construct_v2) {
+ ALOGE("%s(), mCvsdLib.g711plc_construct_v2 dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ return -EIO;
+ }
+ mCvsdLib.g711plc_addtohistory_v2 = (void (*)(void *, short *, unsigned int))dlsym(mCvsdLib.handle, "g711plc_addtohistory_v2");
+ if (!mCvsdLib.g711plc_addtohistory_v2) {
+ ALOGE("%s(), mCvsdLib.g711plc_addtohistory_v2 dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ return -EIO;
+ }
+ mCvsdLib.g711plc_dofe_v2 = (void (*)(void *, short *, unsigned int))dlsym(mCvsdLib.handle, "g711plc_dofe_v2");
+ if (!mCvsdLib.g711plc_dofe_v2) {
+ ALOGE("%s(), mCvsdLib.g711plc_dofe_v2 dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ return -EIO;
+ }
+ }
+
+ mCvsdLib.ready = true;
+
+ return 0;
+}
+
+int AudioBTCVSDControl::initMsbcLib() {
+#if defined(__LP64__)
+#define AUDIO_MSBC_LIB_VENDOR_PATH "/vendor/lib64/libmsbc_mtk.so"
+#define AUDIO_MSBC_LIB_PATH "/system/lib64/libmsbc_mtk.so"
+#else
+#define AUDIO_MSBC_LIB_VENDOR_PATH "/vendor/lib/libmsbc_mtk.so"
+#define AUDIO_MSBC_LIB_PATH "/system/lib/libmsbc_mtk.so"
+#endif
+
+ memset(&mMsbcLib, 0, sizeof(struct BtCodecLib));
+
+ // load bt lib
+ if (access(AUDIO_MSBC_LIB_VENDOR_PATH, R_OK) == 0) {
+ mMsbcLib.handle = dlopen(AUDIO_MSBC_LIB_VENDOR_PATH, RTLD_NOW);
+ } else if (access(AUDIO_MSBC_LIB_PATH, R_OK) == 0) {
+ mMsbcLib.handle = dlopen(AUDIO_MSBC_LIB_PATH, RTLD_NOW);
+ } else {
+ ALOGE("%s(), no valid lib path", __FUNCTION__);
+ }
+
+ // dlsym lib func
+ if (!mMsbcLib.handle) {
+ ALOGE("%s(), dlopen failed, dlerror = %s", __FUNCTION__, dlerror());
+ } else {
+ mMsbcLib.decInit = (void *(*)(signed char *))dlsym(mMsbcLib.handle, "MSBC_DEC_Init");
+ if (!mMsbcLib.decInit) {
+ ALOGE("%s(), mMsbcLib.decInit dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ return -EIO;
+ }
+ mMsbcLib.encInit = (void *(*)(signed char *))dlsym(mMsbcLib.handle, "MSBC_ENC_Init");
+ if (!mMsbcLib.encInit) {
+ ALOGE("%s(), mMsbcLib.encInit dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ return -EIO;
+ }
+ mMsbcLib.decProcess = (int (*)(void *, char *, int *, short *, int *))dlsym(mMsbcLib.handle, "MSBC_DEC_Process");
+ if (!mMsbcLib.decProcess) {
+ ALOGE("%s(), mMsbcLib.decProcess dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ return -EIO;
+ }
+ mMsbcLib.encProcess = (int (*)(void *, short *, int *, char *, int *))dlsym(mMsbcLib.handle, "MSBC_ENC_Process");
+ if (!mMsbcLib.encProcess) {
+ ALOGE("%s(), mMsbcLib.encProcess dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ return -EIO;
+ }
+ mMsbcLib.decGetBufferSize = (int (*)())dlsym(mMsbcLib.handle, "MSBC_DEC_GetBufferSize");
+ if (!mMsbcLib.decGetBufferSize) {
+ ALOGE("%s(), mMsbcLib.decGetBufferSize dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ return -EIO;
+ }
+ mMsbcLib.encGetBufferSize = (int (*)())dlsym(mMsbcLib.handle, "MSBC_ENC_GetBufferSize");
+ if (!mMsbcLib.encGetBufferSize) {
+ ALOGE("%s(), mMsbcLib.encGetBufferSize dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ return -EIO;
+ }
+ }
+
+ mMsbcLib.ready = true;
+
+ return 0;
+}
+
+int AudioBTCVSDControl::getFd() {
+ static AudioLock mGetFdLock;
+ AL_AUTOLOCK(mGetFdLock);
+
+ // open btcvsd kernel device
+ if (mFd2 < 0) {
+ mFd2 = ::open(kBTCVSDDeviceName, O_RDWR);
+ if (mFd2 < 0) {
+ ALOGE("%s(), open(%s) fail, mFd2 = %d, errno: %d", __FUNCTION__, kBTCVSDDeviceName, mFd2, errno);
+ }
+ }
+
+ ASSERT(mFd2 >= 0);
+ return mFd2;
+}
+
+void AudioBTCVSDControl::BT_SCO_CVSD_Init(void) {
+ mBTSCOCVSDContext = NULL;
+ mBTSCOCVSDContext = (BTSCO_CVSD_Context *)new char[sizeof(BTSCO_CVSD_Context)];
+ ASSERT(mBTSCOCVSDContext);
+ memset((void *)mBTSCOCVSDContext, 0, sizeof(BTSCO_CVSD_Context));
+#if 0 //set to 1 for WB BTSCO test
+ ALOGD("BT_SCO_CVSD_Init() !!!force to WB BTSCO(test code)!!!");
+ BT_SCO_SetMode(1);
+#endif
+
+ BT_SCO_SET_TXState(BT_SCO_TXSTATE_IDLE);
+ BT_SCO_SET_RXState(BT_SCO_RXSTATE_IDLE);
+
+ ALOGD("BT_SCO_CVSD_Init() allocate mBTSCOCVSDContext");
+}
+
+void AudioBTCVSDControl::BT_SCO_CVSD_DeInit(void) {
+ if (mBTSCOCVSDContext) {
+ delete []mBTSCOCVSDContext;
+ mBTSCOCVSDContext = NULL;
+ ALOGD("BT_SCO_CVSD_DeInit() release mBTSCOCVSDContext");
+ }
+}
+
+void AudioBTCVSDControl::BT_SCO_SetMode(uint32_t mode) {
+
+ if (mode == 1) {
+ BTmode = BT_SCO_MODE_MSBC;
+ } else {
+ BTmode = BT_SCO_MODE_CVSD;
+ }
+ ALOGD("BT_SCO_SetMode, mode=%d, BTmode=%d", mode, BTmode);
+
+ if (mBTSCOCVSDContext) {
+ mBTSCOCVSDContext->fIsWideBand = BTmode;
+ }
+}
+
+bool AudioBTCVSDControl::BT_SCO_isWideBand(void) {
+ return (BTmode == BT_SCO_MODE_MSBC);
+}
+
+uint32_t AudioBTCVSDControl::BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MODULE uModule) {
+ uint32_t uSize;
+ switch (uModule) {
+ case BT_SCO_MOD_CVSD_ENCODE:
+ uSize = (uint32_t)mCvsdLib.encGetBufferSize();
+ break;
+ case BT_SCO_MOD_CVSD_DECODE:
+ uSize = (uint32_t)mCvsdLib.decGetBufferSize();
+ break;
+ case BT_SCO_MOD_FILTER_TX:
+ case BT_SCO_MOD_FILTER_RX:
+ uSize = (uint32_t)Audio_IIRHPF_GetBufferSize();
+ break;
+ case BT_SCO_MOD_PLC_NB:
+ case BT_SCO_MOD_PLC_WB:
+ uSize = (uint32_t)mCvsdLib.g711plc_GetMemorySize_v2();
+ break;
+ case BT_SCO_MOD_CVSD_TX_SRC:
+ //BLI_GetMemSize(mBTSCOCVSDContext->pTX->uSampleRate, mBTSCOCVSDContext->pTX->uChannelNumber, BTSCO_CVSD_SAMPLERATE_DOMAIN, BTSCO_CVSD_CHANNEL_NUM, &uSize);
+ uSize = 0;
+ break;
+ case BT_SCO_MOD_CVSD_RX_SRC1:
+ //BLI_GetMemSize(BTSCO_CVSD_SAMPLERATE_DOMAIN, BTSCO_CVSD_CHANNEL_NUM, BTSCO_CVSD_PLC_SAMPLERATE, BTSCO_CVSD_CHANNEL_NUM, &uSize);
+ uSize = 0;
+ break;
+ case BT_SCO_MOD_CVSD_RX_SRC2:
+ //BLI_GetMemSize(8000, 1, mBTSCOCVSDContext->pRX->uSampleRate, mBTSCOCVSDContext->pRX->uChannelNumber, &uSize);
+ uSize = 0;
+ break;
+#if defined(__MSBC_CODEC_SUPPORT__)
+ case BT_SCO_MOD_MSBC_ENCODE:
+ uSize = (uint32_t)mMsbcLib.encGetBufferSize();
+ break;
+ case BT_SCO_MOD_MSBC_DECODE:
+ uSize = (uint32_t)mMsbcLib.decGetBufferSize();
+ break;
+ case BT_SCO_MOD_MSBC_TX_SRC:
+ //BLI_GetMemSize(mBTSCOCVSDContext->pTX->uSampleRate, mBTSCOCVSDContext->pTX->uChannelNumber, BTSCO_MSBC_SAMPLERATE_DOMAIN, BTSCO_MSBC_CHANNEL_NUM, &uSize);
+ uSize = 0;
+ break;
+ case BT_SCO_MOD_MSBC_RX_SRC:
+ //BLI_GetMemSize(BTSCO_MSBC_SAMPLERATE_DOMAIN, BTSCO_MSBC_CHANNEL_NUM, BTSCO_EXTMD_SAMPLERATE, BTSCO_MSBC_CHANNEL_NUM, &uSize);
+ uSize = 0;
+ break;
+#endif
+ default:
+ uSize = 0;
+ ASSERT(0);
+ }
+ uSize = (uSize + 3) & ~3 ;
+ ALOGV("BT_SCO_GetMemorySize_4ByteAlign uModule=%d, uSize=%d", uModule, uSize);
+ return uSize;
+}
+
+void AudioBTCVSDControl::BT_SCO_TX_DestroyModule(void) {
+ if (mBTSCOCVSDContext->pTX) {
+ if (mBTSCOCVSDContext->pTX->pSRCHandle) {
+ mBTSCOCVSDContext->pTX->pSRCHandle->close();
+ deleteMtkAudioSrc(mBTSCOCVSDContext->pTX->pSRCHandle);
+ mBTSCOCVSDContext->pTX->pSRCHandle = NULL;
+ }
+ }
+}
+
+void AudioBTCVSDControl::BT_SCO_RX_DestroyModule(void) {
+ if (mBTSCOCVSDContext->pRX) {
+ if (mBTSCOCVSDContext->pRX->pSRCHandle_1) {
+ mBTSCOCVSDContext->pRX->pSRCHandle_1->close();
+ deleteMtkAudioSrc(mBTSCOCVSDContext->pRX->pSRCHandle_1);
+ mBTSCOCVSDContext->pRX->pSRCHandle_1 = NULL;
+ }
+ if (mBTSCOCVSDContext->pRX->pSRCHandle_2) {
+ mBTSCOCVSDContext->pRX->pSRCHandle_2->close();
+ deleteMtkAudioSrc(mBTSCOCVSDContext->pRX->pSRCHandle_2);
+ mBTSCOCVSDContext->pRX->pSRCHandle_2 = NULL;
+ }
+ }
+}
+
+
+void AudioBTCVSDControl::BT_SCO_InitialModule(BT_SCO_MODULE uModule, uint8_t *pBuf) {
+ ASSERT(pBuf);
+ switch (uModule) {
+ case BT_SCO_MOD_CVSD_ENCODE:
+ mBTSCOCVSDContext->pTX->pEncHandle = mCvsdLib.encInit((int8_t *)pBuf);
+ break;
+ case BT_SCO_MOD_CVSD_DECODE:
+ mBTSCOCVSDContext->pRX->pDecHandle = mCvsdLib.decInit((int8_t *)pBuf);
+ break;
+ case BT_SCO_MOD_FILTER_TX:
+ mBTSCOCVSDContext->pTX->pHPFHandle = Audio_IIRHPF_Init();
+ break;
+ case BT_SCO_MOD_FILTER_RX:
+ mBTSCOCVSDContext->pRX->pHPFHandle = Audio_IIRHPF_Init();
+ break;
+ case BT_SCO_MOD_PLC_NB:
+ mCvsdLib.g711plc_construct_v2((void *)pBuf, BTSCO_CVSD_PLC_SAMPLERATE);
+ mBTSCOCVSDContext->pRX->pPLCHandle = (void *)pBuf;
+ break;
+ case BT_SCO_MOD_CVSD_TX_SRC:
+ ALOGD("BT_SCO_InitialModule BT_SCO_MOD_CVSD_TX_SRC source: uSampleRate=%d, uChannelNumber=%d", mBTSCOCVSDContext->pTX->uSampleRate, mBTSCOCVSDContext->pTX->uChannelNumber);
+ mBTSCOCVSDContext->pTX->pSRCHandle = newMtkAudioSrc(mBTSCOCVSDContext->pTX->uSampleRate, mBTSCOCVSDContext->pTX->uChannelNumber, BTSCO_CVSD_SAMPLERATE_DOMAIN, BTSCO_CVSD_CHANNEL_NUM, SRC_IN_Q1P15_OUT_Q1P15);
+ mBTSCOCVSDContext->pTX->pSRCHandle->open();
+ ALOGD("BT_SCO_InitialModule BT_SCO_MOD_CVSD_TX_SRC pTX->pSRCHandle=%p", (void *)(mBTSCOCVSDContext->pTX->pSRCHandle));
+ break;
+ case BT_SCO_MOD_CVSD_RX_SRC1:
+ ALOGD("BT_SCO_InitialModule BT_SCO_MOD_CVSD_RX_SRC1 target: uSampleRate=%d, uChannelNumber=%d", mBTSCOCVSDContext->pRX->uSampleRate, mBTSCOCVSDContext->pRX->uChannelNumber);
+ mBTSCOCVSDContext->pRX->pSRCHandle_1 = newMtkAudioSrc(BTSCO_CVSD_SAMPLERATE_DOMAIN, BTSCO_CVSD_CHANNEL_NUM, mBTSCOCVSDContext->pRX->uSampleRate, mBTSCOCVSDContext->pRX->uChannelNumber, SRC_IN_Q1P15_OUT_Q1P15);
+ mBTSCOCVSDContext->pRX->pSRCHandle_1->open();
+ ALOGD("BT_SCO_InitialModule BT_SCO_MOD_CVSD_RX_SRC1 pRX->pSRCHandle_1=%p", (void *)(mBTSCOCVSDContext->pRX->pSRCHandle_1));
+ break;
+ case BT_SCO_MOD_CVSD_RX_SRC2:
+ mBTSCOCVSDContext->pRX->pSRCHandle_2 = newMtkAudioSrc(8000, 1, mBTSCOCVSDContext->pRX->uSampleRate, mBTSCOCVSDContext->pRX->uChannelNumber, SRC_IN_Q1P15_OUT_Q1P15);
+ mBTSCOCVSDContext->pRX->pSRCHandle_2->open();
+ break;
+#if defined(__MSBC_CODEC_SUPPORT__)
+ case BT_SCO_MOD_MSBC_ENCODE:
+ mBTSCOCVSDContext->pTX->pEncHandle = mMsbcLib.encInit((int8_t *)pBuf);
+ break;
+ case BT_SCO_MOD_MSBC_DECODE:
+ mBTSCOCVSDContext->pRX->pDecHandle = mMsbcLib.decInit((int8_t *)pBuf);
+ break;
+ case BT_SCO_MOD_PLC_WB:
+ mCvsdLib.g711plc_construct_v2((void *)pBuf, BTSCO_MSBC_SAMPLERATE_DOMAIN);
+ mBTSCOCVSDContext->pRX->pPLCHandle = (void *)pBuf;
+ break;
+ case BT_SCO_MOD_MSBC_TX_SRC:
+ if (mExtMDBTSCORunning == true) {
+ mBTSCOCVSDContext->pTX->pSRCHandle = newMtkAudioSrc(BTSCO_EXTMD_SAMPLERATE, BTSCO_MSBC_CHANNEL_NUM, BTSCO_MSBC_SAMPLERATE_DOMAIN, BTSCO_MSBC_CHANNEL_NUM, SRC_IN_Q1P15_OUT_Q1P15);
+ mBTSCOCVSDContext->pTX->pSRCHandle->open();
+ } else {
+ mBTSCOCVSDContext->pTX->pSRCHandle = newMtkAudioSrc(mBTSCOCVSDContext->pTX->uSampleRate, mBTSCOCVSDContext->pTX->uChannelNumber, BTSCO_MSBC_SAMPLERATE_DOMAIN, BTSCO_MSBC_CHANNEL_NUM, SRC_IN_Q1P15_OUT_Q1P15);
+ mBTSCOCVSDContext->pTX->pSRCHandle->open();
+ }
+ break;
+ case BT_SCO_MOD_MSBC_RX_SRC:
+ mBTSCOCVSDContext->pRX->pSRCHandle_1 = newMtkAudioSrc(BTSCO_MSBC_SAMPLERATE_DOMAIN, BTSCO_MSBC_CHANNEL_NUM, BTSCO_EXTMD_SAMPLERATE, BTSCO_MSBC_CHANNEL_NUM, SRC_IN_Q1P15_OUT_Q1P15);
+ mBTSCOCVSDContext->pRX->pSRCHandle_1->open();
+ break;
+#endif
+ default:
+ ASSERT(0);
+ }
+}
+
+
+void AudioBTCVSDControl::BT_SCO_SET_TXState(BT_SCO_STATE state) {
+ ALOGD("BT_SCO_SET_TXState state=0x%x", state);
+ mBTSCOCVSDContext->uTXState = state;
+}
+
+void AudioBTCVSDControl::BT_SCO_SET_RXState(BT_SCO_STATE state) {
+ ALOGD("BT_SCO_SET_RXState state=0x%x", state);
+ mBTSCOCVSDContext->uRXState = state;
+}
+
+
+void AudioBTCVSDControl::BT_SCO_TX_Open(void) {
+ uint32_t uTxMemSize = 0;
+ char *pAllocMemory;
+ ALOGD("BT_SCO_TX_Open(+), BTmode=%d", BTmode);
+
+ uTxMemSize += (sizeof(BT_SCO_TX) + 3) & ~0x3;
+
+ mBTSCOCVSDContext->pTX = (BT_SCO_TX *)new char[uTxMemSize];
+ ASSERT(mBTSCOCVSDContext->pTX);
+ memset((void *)mBTSCOCVSDContext->pTX, 0, uTxMemSize);
+
+ mBTCVSDTXOutBuf = (uint8_t *)new char[BTSCO_CVSD_TX_OUTBUF_SIZE];
+ ALOGD("mBTSCOCVSDContext->uTXState=0x%x", mBTSCOCVSDContext->uTXState);
+ ASSERT(mBTSCOCVSDContext->uTXState == BT_SCO_TXSTATE_IDLE);
+
+ time_t rawtime;
+ time(&rawtime);
+ struct tm *timeinfo = localtime(&rawtime);
+ char timeBufStr[128];
+ String8 mDumpFileName;
+ strftime(timeBufStr, sizeof(timeBufStr), "CVSDTXOut_%Y_%m_%d_%H%M%S.pcm", timeinfo);
+ mDumpFileName.appendFormat("%s%s", audio_dump_path, timeBufStr);
+ mTXSRCPCMDumpFile = NULL;
+ mTXSRCPCMDumpFile = AudioOpendumpPCMFile(mDumpFileName, streamout_propty);
+
+ ALOGD("BT_SCO_TX_Open(-)");
+}
+
+void AudioBTCVSDControl::BT_SCO_TX_Close(void) {
+ ALOGD("BT_SCO_TX_Close(+)");
+
+ if (mBTCVSDTXOutBuf) {
+ delete []mBTCVSDTXOutBuf;
+ mBTCVSDTXOutBuf = NULL;
+ ALOGD("BT_SCO_TX_Close() release mBTCVSDTXOutBuf");
+ }
+
+ if (mBTSCOCVSDContext->pTX) {
+ delete []mBTSCOCVSDContext->pTX;
+ mBTSCOCVSDContext->pTX = NULL;
+ ALOGD("BT_SCO_TX_Close() release mBTSCOCVSDContext->pTX");
+ }
+
+ if (mTXSRCPCMDumpFile) {
+ AudioCloseDumpPCMFile(mTXSRCPCMDumpFile);;
+ }
+
+ ALOGD("BT_SCO_TX_Close(-)");
+}
+
+void AudioBTCVSDControl::btsco_AllocMemory_TX_CVSD(void) {
+ uint32_t uTotalMemory = 0;
+ uint8_t *pBuf = NULL;
+ ALOGD("BT_SCO_TX_Start() (+)");
+ ASSERT(mBTSCOCVSDContext->uTXState == BT_SCO_TXSTATE_READY);
+ if (mBTSCOCVSDContext->pTX) {
+ uTotalMemory += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_CVSD_ENCODE);
+ uTotalMemory += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_CVSD_TX_SRC);
+ if (mBTSCOCVSDContext->pTX->fEnableFilter) {
+ uTotalMemory += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_FILTER_TX);
+ }
+ }
+
+ pBuf = new uint8_t[uTotalMemory];
+ mBTSCOCVSDContext->pTXWorkingMemory = pBuf;
+ ASSERT(mBTSCOCVSDContext->pTXWorkingMemory);
+
+ if (mBTSCOCVSDContext->pTX) {
+ BT_SCO_InitialModule(BT_SCO_MOD_CVSD_ENCODE, pBuf);
+ pBuf += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_CVSD_ENCODE);
+ BT_SCO_InitialModule(BT_SCO_MOD_CVSD_TX_SRC, pBuf);
+ pBuf += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_CVSD_TX_SRC);
+ if (mBTSCOCVSDContext->pTX->fEnableFilter) {
+ BT_SCO_InitialModule(BT_SCO_MOD_FILTER_TX, pBuf);
+ pBuf += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_FILTER_TX);
+ }
+ }
+ ALOGD("btsco_AllocMemory_TX_CVSD %d", uTotalMemory);
+}
+
+#if defined(__MSBC_CODEC_SUPPORT__)
+void AudioBTCVSDControl::btsco_AllocMemory_TX_MSBC(void) {
+ uint32_t uTotalMemory = 0;
+ uint8_t *pBuf = NULL;
+
+ ASSERT(mBTSCOCVSDContext->uTXState == BT_SCO_TXSTATE_READY);
+ if (mBTSCOCVSDContext->pTX) {
+ uTotalMemory += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_MSBC_ENCODE);
+ uTotalMemory += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_MSBC_TX_SRC);
+ if (mBTSCOCVSDContext->pTX->fEnableFilter) {
+ uTotalMemory += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_FILTER_TX);
+ }
+ }
+
+ pBuf = new uint8_t[uTotalMemory];
+ mBTSCOCVSDContext->pTXWorkingMemory = pBuf;
+ ASSERT(mBTSCOCVSDContext->pTXWorkingMemory);
+
+ if (mBTSCOCVSDContext->pTX) {
+ BT_SCO_InitialModule(BT_SCO_MOD_MSBC_ENCODE, pBuf);
+ pBuf += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_MSBC_ENCODE);
+ BT_SCO_InitialModule(BT_SCO_MOD_MSBC_TX_SRC, pBuf);
+ pBuf += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_MSBC_TX_SRC);
+ if (mBTSCOCVSDContext->pTX->fEnableFilter) {
+ BT_SCO_InitialModule(BT_SCO_MOD_FILTER_TX, pBuf);
+ pBuf += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_FILTER_TX);
+ }
+ }
+
+ ALOGD("btsco_AllocMemory_TX_MSBC %d", uTotalMemory);
+}
+#endif
+
+void AudioBTCVSDControl::BT_SCO_TX_Start(void) {
+
+ ALOGD("BT_SCO_TX_Start() (+), BTmode=%d", BTmode);
+
+ mBTSCOCVSDContext->fIsWideBand = BTmode;
+
+ if (mBTSCOCVSDContext->fIsWideBand) {
+#if defined(__MSBC_CODEC_SUPPORT__)
+ btsco_AllocMemory_TX_MSBC();
+#else
+ ASSERT(0);
+#endif
+ } else {
+ btsco_AllocMemory_TX_CVSD();
+ }
+
+ ALOGD("BT_SCO_TX_Start() (-)");
+}
+
+
+void AudioBTCVSDControl::BT_SCO_TX_Stop(void) {
+ ALOGD("BT_SCO_TX_Stop(+)");
+ BT_SCO_TX_DestroyModule();
+
+ if (mBTSCOCVSDContext->pTXWorkingMemory) {
+ delete []mBTSCOCVSDContext->pTXWorkingMemory;
+ mBTSCOCVSDContext->pTXWorkingMemory = NULL;
+ }
+ ALOGD("BT_SCO_TX_Stop(-)");
+}
+
+void AudioBTCVSDControl::BT_SCO_TX_Begin(int mFd2, uint32_t uSampleRate, uint32_t uChannelNumber) {
+ BT_SCO_TX_Open(); //Allocate btsco_cvsd_tx_outbuf and working buffer
+ ALOGD("ioctl mFd2=0x%x, cmd=0x%x", mFd2, (uint32_t)ALLOCATE_FREE_BTCVSD_BUF);
+#ifndef MTK_SUPPORT_BTCVSD_ALSA
+ ::ioctl(mFd2, ALLOCATE_FREE_BTCVSD_BUF, 0); //allocate TX working buffers in kernel
+#endif
+ BT_SCO_SET_TXState(BT_SCO_TXSTATE_INIT);
+ BT_SCO_TX_SetHandle(NULL, NULL, uSampleRate, uChannelNumber, 0);
+ BT_SCO_SET_TXState(BT_SCO_TXSTATE_READY);
+ BT_SCO_TX_Start();
+ BT_SCO_SET_TXState(BT_SCO_TXSTATE_RUNNING);
+#ifndef MTK_SUPPORT_BTCVSD_ALSA
+ ::ioctl(mFd2, SET_BTCVSD_STATE, BT_SCO_TXSTATE_RUNNING); //set state to kernel, ISR will not do anything until state is set to RUNNING
+#endif
+
+}
+
+void AudioBTCVSDControl::BT_SCO_TX_End(int mFd2) {
+ ALOGV("mFd2=0x%x", mFd2);
+ BT_SCO_SET_TXState(BT_SCO_TXSTATE_ENDING);
+#ifndef MTK_SUPPORT_BTCVSD_ALSA
+ ::ioctl(mFd2, SET_BTCVSD_STATE, BT_SCO_TXSTATE_ENDING); //set kernel state to ENDING for push remaining TX datat to BT HW
+#endif
+ BT_SCO_TX_Stop();
+ BT_SCO_TX_Close();
+ BT_SCO_SET_TXState(BT_SCO_TXSTATE_IDLE);
+#ifndef MTK_SUPPORT_BTCVSD_ALSA
+ ::ioctl(mFd2, SET_BTCVSD_STATE, BT_SCO_TXSTATE_IDLE);
+ ::ioctl(mFd2, ALLOCATE_FREE_BTCVSD_BUF, 1); //free TX working buffers in kernel
+#endif
+}
+
+int AudioBTCVSDControl::BT_SCO_TX_SetHandle(void(*pCallback)(void *pData), void *pData, uint32_t uSampleRate, uint32_t uChannelNumber, uint32_t uEnableFilter) {
+ ASSERT(mBTSCOCVSDContext->uTXState == BT_SCO_TXSTATE_INIT);
+ if (uChannelNumber != 1 && uChannelNumber != 2) {
+ ALOGE("%s(), invalid uChannelNumber %u, use 2", __FUNCTION__, uChannelNumber);
+ uChannelNumber = 2;
+ ASSERT(0);
+ }
+
+ ASSERT(mBTSCOCVSDContext->pTX);
+ mBTSCOCVSDContext->pTX->pCallback = pCallback;
+ mBTSCOCVSDContext->pTX->uSampleRate = (uint16_t)uSampleRate;
+ mBTSCOCVSDContext->pTX->uChannelNumber = (uint8_t)uChannelNumber;
+ mBTSCOCVSDContext->pTX->pUserData = pData;
+ mBTSCOCVSDContext->pTX->fEnableFilter = uEnableFilter;
+
+ return 0;
+}
+
+int AudioBTCVSDControl::BT_SCO_RX_SetHandle(void(*pCallback)(void *pData), void *pData, uint32_t uSampleRate, uint32_t uChannelNumber, uint32_t uEnableFilter) {
+ ASSERT(mBTSCOCVSDContext->uRXState == BT_SCO_RXSTATE_INIT);
+ if (uChannelNumber != 1 && uChannelNumber != 2) {
+ ALOGE("%s(), invalid uChannelNumber %u, use 2", __FUNCTION__, uChannelNumber);
+ uChannelNumber = 2;
+ ASSERT(0);
+ }
+
+ if (uSampleRate == 8000) {
+ mBTSCOCVSDContext->pRX->fEnablePLC = true;
+ }
+
+ ASSERT(mBTSCOCVSDContext->pRX);
+ mBTSCOCVSDContext->pRX->pCallback = pCallback;
+ mBTSCOCVSDContext->pRX->uSampleRate = (uint16_t)uSampleRate;
+ mBTSCOCVSDContext->pRX->uChannelNumber = (uint8_t)uChannelNumber;
+ mBTSCOCVSDContext->pRX->pUserData = pData;
+ mBTSCOCVSDContext->pRX->fEnableFilter = uEnableFilter;
+ if (mBTSCOCVSDContext->pRX->uSampleRate != 8000 || mBTSCOCVSDContext->pRX->uChannelNumber != 1) {
+ mBTSCOCVSDContext->pRX->fEnableSRC2 = true;
+ }
+
+ return 0;
+}
+
+
+
+/*
+btsco_process_RX_CVSD(void *inbuf, uint32_t *insize, void *outbuf, uint32_t *outsize, void *workbuf, const uint32_t workbufsize, uint8_t packetvalid)
+
+void *inbuf : inbuf of CVSD bitstream for decode
+uint32_t *insize : in: CVSD bitstream length for decode (i.e. SCO_RX_PLC_SIZE),
+ out: consumed length of CVSD bitstream
+void *outbuf : outbuf of CVSD decoded pcm data (I.e. PcmBuf_8k)
+uint32_t *outsize : in: desired output length of CVSD decoded pcm data (i.e. SCO_RX_PCM8K_BUF_SIZE)
+ out: practical output length of CVSD decoded pcm data
+void *workbuf : working buf during CVSD decode (i.e. PcmBuf_64k)
+const uint32_t workbufsize : working buf size during CVSD decode (i.e. SCO_RX_PCM64K_BUF_SIZE)
+uint8_t packetvalid : Is this SCO_RX_PLC_SIZE packet valid (without packet loss)
+*/
+
+void AudioBTCVSDControl::btsco_process_RX_CVSD(void *inbuf, uint32_t *insize, void *outbuf, uint32_t *outsize, void *workbuf, const uint32_t workbufsize, uint8_t packetvalid) {
+ uint16_t *pDst, *pSrc, i;
+ int32_t iOutSample = 0, iInByte = 0, consumed;
+
+ consumed = *insize;
+ iOutSample = workbufsize >> 1;
+ ALOGVV("btsco_process_RX_CVSD() mCvsdLib.decProcess(+) *insize=%d, iOutSample=%d", *insize, iOutSample);
+ mCvsdLib.decProcess(mBTSCOCVSDContext->pRX->pDecHandle, (char *)inbuf, (int *)insize, (short *)workbuf, (int *)&iOutSample);
+ ALOGVV("btsco_process_RX_CVSD() mCvsdLib.decProcess(-) remaining=%d, iOutSample=%d", *insize, iOutSample);
+
+ if (iOutSample != (SCO_RX_PCM64K_BUF_SIZE >> 1)) {
+ ALOGE("ERROR!!!btsco_process_RX_CVSD() iOutSample!=(SCO_RX_PCM64K_BUF_SIZE>>1)!!!!,iOutSample=%d", iOutSample);
+ }
+
+ consumed -= *insize;
+ *insize = consumed;
+
+ if (mBTCVSDRXInDumpFile) {
+ fwrite((void *)inbuf, 1, *insize, mBTCVSDRXInDumpFile);
+ }
+
+ {
+ uint32_t uOutByte = 0, uInByte = 0, uConsumeByte = 0;
+ uInByte = iOutSample << 1; //should be SCO_RX_PCM64K_BUF_SIZE!!!
+ uOutByte = *outsize;
+
+ ALOGVV("btsco_process_RX_CVSD() BLI_Convert(+) uInByte=%d, uOutByte=%d", uInByte, uOutByte);
+
+ uConsumeByte = uInByte;
+ mBTSCOCVSDContext->pRX->pSRCHandle_1->process((int16_t *)workbuf, &uInByte, (int16_t *)outbuf, &uOutByte);
+ uConsumeByte -= uInByte;
+
+ ALOGVV("btsco_process_RX_CVSD() BLI_Convert(-) remaining=%d, uConsumeByte=%d, uOutByte=%d", uInByte, uConsumeByte, uOutByte);
+ ASSERT(uConsumeByte == workbufsize);
+ *outsize = uOutByte;
+ }
+
+ if (mBTCVSDRXDumpFile) {
+ fwrite((void *)outbuf, 1, *outsize, mBTCVSDRXDumpFile);
+ }
+
+#if 1 // TODO(Harvey): BT Loopback
+ if (AudioALSALoopbackController::getInstance()->IsAPBTLoopbackWithCodec() == true) {
+ mBTSCOCVSDContext->pRX->fEnablePLC = false;
+ if (packetvalid == 0) {
+ ALOGD("btsco_process_RX_CVSD(), packet lost, in loopback mode, no PLC!!!");
+ }
+ }
+#endif
+
+ if (mBTSCOCVSDContext->pRX->fEnablePLC) {
+ //do PLC
+ if (packetvalid) {
+ //packet not lost
+ mCvsdLib.g711plc_addtohistory_v2(mBTSCOCVSDContext->pRX->pPLCHandle, (short *)outbuf, 0);
+ } else {
+ //packet lost
+
+ ALOGD("btsco_process_RX_CVSD(), packetvalid=%d, packet lost, do PLC!!!", packetvalid);
+#if 0
+ for (i = 0; i < SCO_RX_PLC_SIZE; i++) {
+ ALOGD("%x ", *((char *)inbuf + i)); //should be 0x55
+ }
+#endif
+
+ mCvsdLib.g711plc_dofe_v2(mBTSCOCVSDContext->pRX->pPLCHandle, (short *)outbuf, 0);
+ }
+ }
+ if (mBTSCOCVSDContext->pRX->fEnableFilter) {
+ //do filter
+ int32_t iInSample = *outsize >> 1;
+ int32_t iOutSample = *outsize >> 1;
+ Audio_IIRHPF_Process();
+ *outsize = iOutSample << 1;
+ }
+
+ ALOGVV("btsco_process_RX_CVSD() consumed=%d, *outsize=%d", *insize, *outsize);
+}
+
+/*
+btsco_process_RX_MSBC(void *inbuf, uint32_t *insize, void *outbuf, uint32_t *outsize, void *workbuf, uint8_t packetvalid)
+
+void *inbuf : inbuf of MSBC bitstream for decode
+uint32_t *insize : in: MSBC bitstream length for decode,
+ out: consumed length of MSBC bitstream
+void *outbuf : outbuf of CVSD decoded pcm data (I.e. PcmBuf_8k)
+uint32_t *outsize : in: desired output length of MSBC decoded pcm data
+ out: practical output length of MSBC decoded pcm data
+void *workbuf : working buf during MSBC decode
+const uint32_t workbufsize : working buf size during MSBC decode
+uint8_t packetvalid : Is this SCO_RX_PLC_SIZE packet valid (without packet loss)
+*/
+
+#if defined(__MSBC_CODEC_SUPPORT__)
+
+void AudioBTCVSDControl::btsco_process_RX_MSBC(void *inbuf, uint32_t *insize, void *outbuf, uint32_t *outsize,
+ void *workbuf, uint8_t packetvalid) {
+ uint16_t *pDst, *pSrc, i;
+ uint32_t iOutSample = 0, inByte = 0, consumed, inBytePacket = 0;
+ uint32_t index1 = 0, index2 = 0, index3 = 0, dwBtEv3HalfBad = 0;
+ uint8_t *pSrc8;
+ int32_t status = -1;
+
+ pSrc8 = (uint8_t *)inbuf;
+ inByte = MSBC_PACKET_SIZE_BYTE >> 1;// 30bytes per block
+ inBytePacket = MSBC_BTSTREAM_FRAME_BYTE;// whole packet(2 blocks) 60 bytes
+ iOutSample = MSBC_PCM_FRAME_BYTE >> 1;
+
+ // Put into packet buffer
+ if (*insize < inByte) {
+ *insize = 0;
+ *outsize = 0;
+ return;
+ }
+ index1 = mBTSCOCVSDContext->pRX->iPacket_w & SCO_RX_PACKET_MASK;
+ memcpy(mBTSCOCVSDContext->pRX->PacketBuf[index1], inbuf, inByte);
+ mBTSCOCVSDContext->pRX->PacketValid[index1] = packetvalid;
+ mBTSCOCVSDContext->pRX->iPacket_w++;
+//at least 3 packets
+ if (((mBTSCOCVSDContext->pRX->iPacket_w - mBTSCOCVSDContext->pRX->iPacket_r) < 3) ||
+ (*outsize < MSBC_PCM_FRAME_BYTE)) {
+ //*insize = iInByte;
+ *outsize = 0;
+ return;
+ }
+
+ index1 = mBTSCOCVSDContext->pRX->iPacket_r & SCO_RX_PACKET_MASK;
+ index2 = (mBTSCOCVSDContext->pRX->iPacket_r + 1) & SCO_RX_PACKET_MASK;
+ index3 = (mBTSCOCVSDContext->pRX->iPacket_r + 2) & SCO_RX_PACKET_MASK;
+ mBTSCOCVSDContext->pRX->iPacket_r++; // Consume 30 bytes
+
+ if ((mBTSCOCVSDContext->pRX->PacketBuf[index1][0] == 0x1) &&
+ ((mBTSCOCVSDContext->pRX->PacketBuf[index1][1] & 0xF) == 0x8)) {
+ ALOGV("%s(), found MSBC header at offset:0, header1:0x%x, header2:0x%x", __FUNCTION__,
+ mBTSCOCVSDContext->pRX->PacketBuf[index1][0],
+ mBTSCOCVSDContext->pRX->PacketBuf[index1][1]);
+
+ // Copy to bitstream buffer for decoding
+ memcpy(mBTSCOCVSDContext->pRX->EntirePacket, &mBTSCOCVSDContext->pRX->PacketBuf[index1][2], 28);
+ memcpy(mBTSCOCVSDContext->pRX->EntirePacket + 28, &mBTSCOCVSDContext->pRX->PacketBuf[index2][0], 29);
+
+ ALOGVV("btsco_process_RX_MSBC() MSBC_DEC_Process(+)");
+ if (mBTCVSDRXInDumpFile) {
+ fwrite((void *)mBTSCOCVSDContext->pRX->EntirePacket, 1, 57, mBTCVSDRXInDumpFile);
+ }
+ status = mMsbcLib.decProcess(mBTSCOCVSDContext->pRX->pDecHandle, (char *)mBTSCOCVSDContext->pRX->EntirePacket,
+ (int32_t *)&inBytePacket, (int16_t *)workbuf, (int32_t *)&iOutSample);
+ ALOGVV("btsco_process_RX_MSBC() MSBC_DEC_Process(-) status=%d, iOutSample=%d", status, iOutSample);
+ ASSERT((iOutSample == MSBC_PCM_FRAME_BYTE >> 1) || (iOutSample == 0));
+
+ if (mBTCVSDRXDumpFile) {
+ fwrite((void *)workbuf, 1, iOutSample << 1, mBTCVSDRXDumpFile);
+ }
+
+ mBTSCOCVSDContext->pRX->iPacket_r++; // Consume another 30 bytes for entire packet
+ } else if (mBTSCOCVSDContext->pRX->PacketValid[index1] == 1) {
+ //wrong header, but packet not lost, sync to next 30 byte block (should only happenes on packetsize 30)
+ status = -1;
+
+ for(i = 1; i < 29; i++) {
+ if ((mBTSCOCVSDContext->pRX->PacketBuf[index1][i] == 0x1) &&
+ ((mBTSCOCVSDContext->pRX->PacketBuf[index1][i+1] & 0xF) == 0x8)) {
+ ALOGD("%s(), found MSBC header at offset:%d, header1:0x%x, header2:0x%x", __FUNCTION__, i,
+ mBTSCOCVSDContext->pRX->PacketBuf[index1][i],
+ mBTSCOCVSDContext->pRX->PacketBuf[index1][i+1]);
+ // Copy to bitstream buffer for decoding
+ memcpy(mBTSCOCVSDContext->pRX->EntirePacket, &mBTSCOCVSDContext->pRX->PacketBuf[index1][i + 2], 28 - i);
+ memcpy(mBTSCOCVSDContext->pRX->EntirePacket + 28 - i, &mBTSCOCVSDContext->pRX->PacketBuf[index2][0], 30);
+ memcpy(mBTSCOCVSDContext->pRX->EntirePacket + 58 - i, &mBTSCOCVSDContext->pRX->PacketBuf[index3][0], i - 1);
+ if (mBTCVSDRXInDumpFile) {
+ fwrite((void *)mBTSCOCVSDContext->pRX->EntirePacket, 1, 57, mBTCVSDRXInDumpFile);
+ }
+
+ ALOGV("btsco_process_RX_MSBC() MSBC_DEC_Process(+)");
+ status = mMsbcLib.decProcess(mBTSCOCVSDContext->pRX->pDecHandle,
+ (char *)mBTSCOCVSDContext->pRX->EntirePacket, (int32_t *)&inBytePacket,
+ (int16_t *)workbuf, (int32_t *)&iOutSample);
+ ALOGV("btsco_process_RX_MSBC() MSBC_DEC_Process(-) status=%d, iOutSample=%d", status, iOutSample);
+ ASSERT((iOutSample == MSBC_PCM_FRAME_BYTE >> 1) || (iOutSample == 0));
+ if (status != MSBC_BTSTREAM_FRAME_BYTE) {
+ ALOGE("btsco_process_RX_MSBC() MSBC_DEC_Process(-) status=%d, iOutSample=%d", status, iOutSample);
+ iOutSample = 0;
+ }
+ if (mBTCVSDRXDumpFile) {
+ fwrite((void *)workbuf, 1, iOutSample << 1, mBTCVSDRXDumpFile);
+ }
+ mBTSCOCVSDContext->pRX->iPacket_r++; // Consume another 30 bytes for entire packet
+ break;
+ }
+ }
+ if (status == -1) {
+ ALOGW("btsco_process_RX_MSBC() wrong header, but packet[%d]=%d valid, sync to next 30 byte block!!!",
+ index1, mBTSCOCVSDContext->pRX->PacketValid[index1]);
+ }
+ } else {
+ status = -1;
+
+ mBTSCOCVSDContext->pRX->iPacket_r++; // Consume another 30 bytes for entire packet
+ ALOGW("btsco_process_RX_MSBC() wrong header, packet[%d]=%d invalid!!!",
+ index1, mBTSCOCVSDContext->pRX->PacketValid[index1]);
+
+ }
+ if (status == MSBC_BTSTREAM_FRAME_BYTE) {
+ if (mBTSCOCVSDContext->pRX->PacketValid[index1] == 1 && mBTSCOCVSDContext->pRX->PacketValid[index2] == 0) {
+ dwBtEv3HalfBad = 1;
+ } else {
+ dwBtEv3HalfBad = 0;
+ }
+
+ ALOGVV("btsco_process_RX_MSBC() dwBtEv3HalfBad = %d", dwBtEv3HalfBad);
+ }
+
+ if (mBTSCOCVSDContext->pRX->fEnablePLC) {
+ if ((status == MSBC_BTSTREAM_FRAME_BYTE) && (mBTSCOCVSDContext->pRX->PacketValid[index1] == 1) &&
+ (mBTSCOCVSDContext->pRX->PacketValid[index2] == 1)) {
+ //packet not lost
+ mCvsdLib.g711plc_addtohistory_v2(mBTSCOCVSDContext->pRX->pPLCHandle, (short *)workbuf, 0);
+ } else {
+ //packet lost
+ ALOGW("btsco_process_RX_MSBC(), packet lost, do PLC!!!status(%d), PacketValid[%d]=%d, PacketValid[%d]=%d",
+ status, index1, mBTSCOCVSDContext->pRX->PacketValid[index1], index1,
+ mBTSCOCVSDContext->pRX->PacketValid[index2]);
+ mCvsdLib.g711plc_dofe_v2(mBTSCOCVSDContext->pRX->pPLCHandle, (short *)workbuf, dwBtEv3HalfBad);
+ }
+ }
+
+ if (mBTSCOCVSDContext->pRX->fEnableFilter) {
+ ALOGD("btsco_process_RX_MSBC() fEnableFilter iOutSample=%d", iOutSample);
+ //do filter
+ uint32_t iInSampleTemp = iOutSample;
+ uint32_t iOutSampleTemp = iOutSample;
+ Audio_IIRHPF_Process();
+ iOutSample = iOutSampleTemp;
+ }
+
+ if (mExtMDBTSCORunning == true) { //SRC from 16K to 8K
+ uint32_t uOutByte = 0, uInByte = 0, uConsumeByte = 0;
+ uInByte = iOutSample << 1; //should be MSBC_PCM_FRAME_BYTE!!!
+ uOutByte = *outsize >> 1; //MSBC_PCM_FRAME_BYTE/2
+
+ ALOGVV("btsco_process_RX_MSBC() BLI_Convert(+) uInByte=%d, uOutByte=%d", uInByte, uOutByte);
+
+ uConsumeByte = uInByte;
+ mBTSCOCVSDContext->pRX->pSRCHandle_1->process((int16_t *)workbuf, &uInByte, (int16_t *)outbuf, &uOutByte);
+ uConsumeByte -= uInByte;
+
+ ALOGVV("btsco_process_RX_MSBC() BLI_Convert(-) remaining=%d, uConsumeByte=%d, uOutByte=%d",
+ uInByte, uConsumeByte, uOutByte);
+ ASSERT(uConsumeByte == (iOutSample << 1));
+ *outsize = uOutByte; //MSBC_PCM_FRAME_BYTE/2 because of 16kto8k SRC
+ } else {
+ memcpy(outbuf, workbuf, iOutSample << 1);
+ //*insize = iInByte;
+ *outsize = iOutSample << 1;
+ }
+
+ ALOGVV("btsco_process_RX_MSBC() consumed=%d, *outsize=%d", *insize, *outsize);
+}
+
+#endif
+
+/*
+btsco_process_TX_CVSD(void *inbuf, uint32_t *insize, void *outbuf, uint32_t *outsize, void *workbuf, const uint32_t workbufsize)
+
+void *inbuf : inbuf of pcm data(for SRC to 64k)
+uint32_t *insize : in: inbuf length of pcm data(for SRC to 64k)
+ out: consumed inbuf length of pcm data (i.e. SRC consumed buf length)
+void *outbuf : outbuf of CVSD encoded bitstream
+uint32_t *outsize : in: desired output length of CVSD encoded bitstream (i.e. SCO_TX_ENCODE_SIZE)
+ out: practical output length of CVSD encoded bitstream
+void *workbuf : workingbuf during CVSD encode (i.e. PcmBuf_64k)
+const uint32_t workbufsize : workingbuf size during CVSD encode (i.e. SCO_RX_PCM64K_BUF_SIZE)
+unint32 src_fs_s : SRC source sample rate(for SRC to 64k)
+*/
+
+void AudioBTCVSDControl::btsco_process_TX_CVSD(void *inbuf, uint32_t *insize, void *outbuf, uint32_t *outsize, void *workbuf, const uint32_t workbufsize) {
+ uint32_t src_outsize, iInSample, iOutSample, iOutByte, uConsumeByte, i;
+
+ if (*insize != 0 && *outsize != 0) {
+ src_outsize = workbufsize;
+ ALOGVV("btsco_process_TX_CVSD() BLI_Convert *insize=%d, *outsize=%d", *insize, *outsize);
+
+ uConsumeByte = *insize;
+ mBTSCOCVSDContext->pTX->pSRCHandle->process((int16_t *)inbuf, insize, (int16_t *)workbuf, &src_outsize);
+ uConsumeByte -= *insize;
+
+ ALOGVV("btsco_process_TX_CVSD() BLI_Convert consumed=%d, remaining=%d, src_outsize=%d", uConsumeByte, *insize, src_outsize);
+
+ if (mTXSRCPCMDumpFile) {
+ fwrite((void *)workbuf, 1, src_outsize, mTXSRCPCMDumpFile);
+ }
+
+ *insize = uConsumeByte;
+ iInSample = src_outsize >> 1;
+
+ if (mBTSCOCVSDContext->pTX->fEnableFilter) {
+ //filter
+ iInSample = src_outsize >> 1;
+ iOutSample = src_outsize >> 1;
+ Audio_IIRHPF_Process();
+ iInSample = iOutSample;
+ }
+ //encode
+ iOutByte = SCO_TX_ENCODE_SIZE;
+ //uint32_t iGain = 0x7FFF;
+
+ mCvsdLib.encProcess(mBTSCOCVSDContext->pTX->pEncHandle, (short *)workbuf, (int *)&iInSample, (char *)outbuf, (int *)&iOutByte);
+ ALOGVV("mCvsdLib.encProcess BLI_Convert iInSample=%d, iOutByte=%d", iInSample, iOutByte);
+
+#ifdef TXOUT_RXIN_TEST // use sequence number to replace ENC out
+ for (i = 0; i < iOutByte; i++) {
+ *((char *)outbuf + i) = i;
+ }
+#endif
+
+ *outsize = iOutByte;
+ } else {
+ *insize = 0;
+ *outsize = 0;
+ }
+}
+
+/*
+btsco_process_TX_MSBC(void *inbuf, uint32_t *insize, void *outbuf, uint32_t *outsize, void *workbuf)
+
+void *inbuf : inbuf of pcm data
+uint32_t *insize : in: inbuf length of pcm data(for SRC to 64k)
+ out: consumed inbuf length of pcm data (i.e. SRC consumed buf length)
+void *outbuf : outbuf of CVSD encoded bitstream
+uint32_t *outsize : in: desired output length of mSBC encoded bitstream
+ out: practical output length of mSBC encoded bitstream
+void *workbuf : workingbuf during CVSD encode (i.e. PcmBuf_64k)
+const uint32_t workbufsize : workingbuf size during mSBC encode
+unint32 src_fs_s : SRC source sample rate
+*/
+
+#if defined(__MSBC_CODEC_SUPPORT__)
+
+static const uint8_t btsco_MsbcHeader[4] = {0x08, 0x38, 0xc8, 0xf8};
+
+void AudioBTCVSDControl::btsco_process_TX_MSBC(void *inbuf, uint32_t *insize, void *outbuf, uint32_t *outsize, void *workbuf) {
+ uint32_t src_outsize, iInSample, iOutSample, iOutByte, uConsumeByte, i, status, index;
+
+ if (*insize != 0 && *outsize != 0) {
+ src_outsize = MSBC_PCM_FRAME_BYTE;
+ uConsumeByte = *insize;
+ mBTSCOCVSDContext->pTX->pSRCHandle->process((int16_t *)inbuf, insize, (int16_t *)workbuf, &src_outsize);
+ uConsumeByte -= *insize;
+
+ ALOGVV("btsco_process_TX_MSBC() BLI_Convert consumed=%d, remaining=%d, src_outsize=%d", uConsumeByte, *insize, src_outsize);
+
+ if (mTXSRCPCMDumpFile) {
+ fwrite((void *)workbuf, 1, src_outsize, mTXSRCPCMDumpFile);
+ }
+
+ *insize = uConsumeByte;
+
+ char *pOutput8 = (char *)outbuf;
+
+ //*insize = MSBC_PCM_FRAME_BYTE;
+ //iInSample = MSBC_PCM_FRAME_BYTE >> 1;
+ iInSample = src_outsize >> 1;
+
+ if (mBTSCOCVSDContext->pTX->fEnableFilter) {
+ //filter
+ iInSample = src_outsize >> 1;
+ iOutSample = src_outsize >> 1;
+ Audio_IIRHPF_Process();
+ ASSERT(iInSample == iOutSample);
+ } else {
+ //memcpy((uint16_t *)workbuf, (uint16_t *)inbuf, MSBC_PCM_FRAME_BYTE);
+ }
+
+ //encode
+ iOutByte = MSBC_BTSTREAM_FRAME_BYTE;
+
+ status = mMsbcLib.encProcess(mBTSCOCVSDContext->pTX->pEncHandle, (short *)workbuf, (int *)&iInSample, pOutput8 + 2, (int *)&iOutByte); //out 57 bytes
+ ALOGVV("MSBC_ENC_Process iInSample=%d, iOutByte=%d, status=%d, BTmode=%d", iInSample, iOutByte, status, BTmode);
+ ASSERT(iOutByte == MSBC_BTSTREAM_FRAME_BYTE);
+
+ index = mBTSCOCVSDContext->pTX->iPacket_w;
+ pOutput8[0 ] = 0x01; //header
+ pOutput8[1 ] = btsco_MsbcHeader[index & 0x3]; //header
+ pOutput8[59] = 0; //header
+ mBTSCOCVSDContext->pTX->iPacket_w++;
+
+#ifdef TXOUT_RXIN_TEST // use sequence number to replace ENC out
+ for (i = 0; i < iOutByte; i++) {
+ *((char *)outbuf + i) = i;
+ }
+#endif
+
+ *outsize = SCO_TX_ENCODE_SIZE;
+ } else {
+ *insize = 0;
+ *outsize = 0;
+ }
+}
+
+#endif
+
+void AudioBTCVSDControl::BT_SCO_RX_Open(void) {
+ uint32_t uRxMemSize = 0;
+ char *pAllocMemory;
+
+ ALOGD("BT_SCO_RX_Open(+) mBTSCOCVSDContext->uRXState=0x%x, BTmode=%d", mBTSCOCVSDContext->uRXState, BTmode);
+
+ ASSERT(mBTSCOCVSDContext->uRXState == BT_SCO_RXSTATE_IDLE);
+
+ uRxMemSize += (sizeof(BT_SCO_RX) + 3) & ~0x3;
+
+ mBTSCOCVSDContext->pRX = (BT_SCO_RX *)new char[uRxMemSize];
+ ASSERT(mBTSCOCVSDContext->pRX);
+ memset((void *)mBTSCOCVSDContext->pRX, 0, uRxMemSize);
+
+ mBTCVSDRXTempInBuf = (uint8_t *)new char[BTSCO_CVSD_RX_TEMPINPUTBUF_SIZE];
+ mBTCVSDRXInBuf = (uint8_t *)new char[BTSCO_CVSD_RX_INBUF_SIZE];
+
+ time_t rawtime;
+ time(&rawtime);
+ struct tm *timeinfo = localtime(&rawtime);
+ char timeBufStr[128];
+ String8 mDumpFileName;
+ strftime(timeBufStr, sizeof(timeBufStr), "CVSDRXOut_%Y_%m_%d_%H%M%S.pcm", timeinfo);
+ mDumpFileName.appendFormat("%s%s", audio_dump_path, timeBufStr);
+ mBTCVSDRXDumpFile = NULL;
+
+ mBTCVSDRXDumpFile = AudioOpendumpPCMFile(mDumpFileName, streamin_propty);
+ String8 mDumpRxInFileName;
+ strftime(timeBufStr, sizeof(timeBufStr), "CVSDRXIn_%Y_%m_%d_%H%M%S.dat", timeinfo);
+ mDumpRxInFileName.appendFormat("%s%s", audio_dump_path, timeBufStr);
+ mBTCVSDRXInDumpFile = NULL;
+ mBTCVSDRXInDumpFile = AudioOpendumpPCMFile(mDumpRxInFileName, streamin_propty);
+
+ ALOGD("BT_SCO_RX_Open(-)");
+}
+
+void AudioBTCVSDControl::BT_SCO_RX_Close(void) {
+ ALOGD("BT_SCO_RX_Close(+)");
+
+ if (mBTCVSDRXTempInBuf) {
+ delete []mBTCVSDRXTempInBuf;
+ mBTCVSDRXTempInBuf = NULL;
+ ALOGD("BT_SCO_RX_Close() release mBTCVSDRXTempInBuf");
+ }
+
+ if (mBTCVSDRXInBuf) {
+ delete []mBTCVSDRXInBuf;
+ mBTCVSDRXInBuf = NULL;
+ ALOGD("BT_SCO_RX_Close() release mBTCVSDRXInBuf");
+ }
+
+ if (mBTSCOCVSDContext->pRX) {
+ delete []mBTSCOCVSDContext->pRX;
+ mBTSCOCVSDContext->pRX = NULL;
+ ALOGD("BT_SCO_RX_Close(-) release mBTSCOCVSDContext->pRX");
+ }
+
+ if (mBTCVSDRXDumpFile) {
+ AudioCloseDumpPCMFile(mBTCVSDRXDumpFile);
+ ALOGD("ClosePcmDumpFile mBTCVSDRXDumpFile");
+ }
+ if (mBTCVSDRXInDumpFile) {
+ AudioCloseDumpPCMFile(mBTCVSDRXInDumpFile);
+ ALOGD("ClosePcmDumpFile mBTCVSDRXInDumpFile");
+ }
+
+ ALOGD("BT_SCO_RX_Close(-)");
+}
+
+void AudioBTCVSDControl::BT_SCO_RX_Begin(int mFd2) {
+ ALOGD("%s() mFd2=%d", __FUNCTION__, mFd2);
+ BT_SCO_RX_Open();
+#ifndef MTK_SUPPORT_BTCVSD_ALSA
+ ::ioctl(mFd2, ALLOCATE_FREE_BTCVSD_BUF, 2); //allocate RX working buffers in kernel
+#endif
+ BT_SCO_SET_RXState(BT_SCO_RXSTATE_INIT);
+ BT_SCO_RX_SetHandle(NULL, NULL, BTSCO_CVSD_PLC_SAMPLERATE, BTSCO_CVSD_CHANNEL_NUM, 0);
+ BT_SCO_SET_RXState(BT_SCO_RXSTATE_READY);
+ BT_SCO_RX_Start();
+ BT_SCO_SET_RXState(BT_SCO_RXSTATE_RUNNING);
+#ifndef MTK_SUPPORT_BTCVSD_ALSA
+ ::ioctl(mFd2, SET_BTCVSD_STATE, BT_SCO_RXSTATE_RUNNING); //set state to kernel
+#endif
+}
+
+void AudioBTCVSDControl::BT_SCO_RX_End(int mFd2) {
+ ALOGD("%s() mFd2=%d", __FUNCTION__, mFd2);
+ BT_SCO_RX_Stop();
+ BT_SCO_SET_RXState(BT_SCO_RXSTATE_ENDING);
+#ifndef MTK_SUPPORT_BTCVSD_ALSA
+ ::ioctl(mFd2, SET_BTCVSD_STATE, BT_SCO_RXSTATE_ENDING); //set kernel state
+#endif
+ BT_SCO_RX_Close();
+ BT_SCO_SET_RXState(BT_SCO_RXSTATE_IDLE);
+#ifndef MTK_SUPPORT_BTCVSD_ALSA
+ ::ioctl(mFd2, SET_BTCVSD_STATE, BT_SCO_RXSTATE_IDLE);
+ ::ioctl(mFd2, ALLOCATE_FREE_BTCVSD_BUF, 3); //free RX working buffers in kernel
+#endif
+}
+
+uint8_t *AudioBTCVSDControl::BT_SCO_RX_GetCVSDOutBuf(void) {
+ return mBTSCOCVSDContext->pRX->PcmBuf_8k;
+}
+
+uint8_t *AudioBTCVSDControl::BT_SCO_RX_GetMSBCOutBuf(void) {
+ return mBTSCOCVSDContext->pRX->PcmBuf_mSBC;
+}
+
+uint8_t *AudioBTCVSDControl::BT_SCO_RX_GetCVSDWorkBuf(void) {
+ return mBTSCOCVSDContext->pRX->PcmBuf_64k;
+}
+
+void *AudioBTCVSDControl::BT_SCO_RX_GetTimeBufferInfo(void) {
+ ::ioctl(mFd2, GET_BTCVSD_RX_TIME_BUFFER_INFO, (unsigned long long)&gTimeBufferInfo);
+
+ ALOGD("%s(), dataCountEquiTime=%" PRIu64 ", uimestampUS=%" PRIu64 "", __FUNCTION__, gTimeBufferInfo.dataCountEquiTime, gTimeBufferInfo.timestampUS);
+ return &gTimeBufferInfo;
+}
+
+void AudioBTCVSDControl::btsco_AllocMemory_RX_CVSD(void) {
+ uint32_t uTotalMemory = 0;
+ uint8_t *pBuf = NULL;
+ ALOGD("btsco_AllocMemory_RX_CVSD(+)");
+ ASSERT(mBTSCOCVSDContext->uRXState == BT_SCO_RXSTATE_READY);
+
+ if (mBTSCOCVSDContext->pRX) {
+ //uTotalMemory += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_PCM_RINGBUF_RX);
+ uTotalMemory += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_CVSD_DECODE);
+ uTotalMemory += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_CVSD_RX_SRC1);
+ if (mBTSCOCVSDContext->pRX->fEnableFilter) {
+ uTotalMemory += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_FILTER_RX);
+ }
+ if (mBTSCOCVSDContext->pRX->fEnablePLC) {
+ uTotalMemory += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_PLC_NB);
+ }
+ if (mBTSCOCVSDContext->pRX->fEnableSRC2) {
+ uTotalMemory += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_CVSD_RX_SRC2);
+ }
+ }
+
+ pBuf = new uint8_t[uTotalMemory];
+ mBTSCOCVSDContext->pRXWorkingMemory = pBuf;
+ ASSERT(mBTSCOCVSDContext->pRXWorkingMemory);
+
+ if (mBTSCOCVSDContext->pRX) {
+ BT_SCO_InitialModule(BT_SCO_MOD_CVSD_DECODE, pBuf);
+ pBuf += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_CVSD_DECODE);
+ BT_SCO_InitialModule(BT_SCO_MOD_CVSD_RX_SRC1, pBuf);
+ pBuf += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_CVSD_RX_SRC1);
+ if (mBTSCOCVSDContext->pRX->fEnableFilter) {
+ BT_SCO_InitialModule(BT_SCO_MOD_FILTER_RX, pBuf);
+ pBuf += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_FILTER_RX);
+ }
+ if (mBTSCOCVSDContext->pRX->fEnablePLC) {
+ BT_SCO_InitialModule(BT_SCO_MOD_PLC_NB, pBuf);
+ pBuf += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_PLC_NB);
+ }
+ if (mBTSCOCVSDContext->pRX->fEnableSRC2) {
+ BT_SCO_InitialModule(BT_SCO_MOD_CVSD_RX_SRC2, pBuf);
+ pBuf += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_CVSD_RX_SRC2);
+ }
+ }
+}
+
+#if defined(__MSBC_CODEC_SUPPORT__)
+void AudioBTCVSDControl::btsco_AllocMemory_RX_MSBC(void) {
+ uint32_t uTotalMemory = 0;
+ uint8_t *pBuf = NULL;
+
+ ASSERT(mBTSCOCVSDContext->uRXState == BT_SCO_RXSTATE_READY);
+
+ if (mBTSCOCVSDContext->pRX) {
+ uTotalMemory += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_MSBC_DECODE);
+ uTotalMemory += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_MSBC_RX_SRC);
+ if (mBTSCOCVSDContext->pRX->fEnableFilter) {
+ uTotalMemory += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_FILTER_RX);
+ }
+ if (mBTSCOCVSDContext->pRX->fEnablePLC) {
+ uTotalMemory += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_PLC_WB);
+ }
+ if (mBTSCOCVSDContext->pRX->fEnableSRC2) {
+ uTotalMemory += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_CVSD_RX_SRC2);
+ }
+ }
+
+ pBuf = new uint8_t[uTotalMemory];
+ mBTSCOCVSDContext->pRXWorkingMemory = pBuf;
+ ASSERT(mBTSCOCVSDContext->pRXWorkingMemory);
+
+ if (mBTSCOCVSDContext->pRX) {
+ BT_SCO_InitialModule(BT_SCO_MOD_MSBC_DECODE, pBuf);
+ pBuf += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_MSBC_DECODE);
+ BT_SCO_InitialModule(BT_SCO_MOD_MSBC_RX_SRC, pBuf);
+ pBuf += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_MSBC_RX_SRC);
+ if (mBTSCOCVSDContext->pRX->fEnableFilter) {
+ BT_SCO_InitialModule(BT_SCO_MOD_FILTER_RX, pBuf);
+ pBuf += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_FILTER_RX);
+ }
+ if (mBTSCOCVSDContext->pRX->fEnablePLC) {
+ BT_SCO_InitialModule(BT_SCO_MOD_PLC_WB, pBuf);
+ pBuf += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_PLC_WB);
+ }
+ if (mBTSCOCVSDContext->pRX->fEnableSRC2) {
+ BT_SCO_InitialModule(BT_SCO_MOD_CVSD_RX_SRC2, pBuf);
+ pBuf += BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MOD_CVSD_RX_SRC2);
+ }
+ }
+}
+#endif
+
+void AudioBTCVSDControl::BT_SCO_RX_Start(void) {
+ ALOGD("BT_SCO_RX_Start(+) BTmode=%d", BTmode);
+
+ mBTSCOCVSDContext->fIsWideBand = BTmode;
+
+ if (mBTSCOCVSDContext->fIsWideBand) {
+#if defined(__MSBC_CODEC_SUPPORT__)
+ btsco_AllocMemory_RX_MSBC();
+#else
+ ASSERT(0);
+#endif
+ } else {
+ btsco_AllocMemory_RX_CVSD();
+ }
+
+ ALOGD("BT_SCO_RX_Start(-)");
+}
+
+void AudioBTCVSDControl::BT_SCO_RX_Stop(void) {
+ ALOGD("BT_SCO_RX_Stop(+)");
+
+ BT_SCO_RX_DestroyModule();
+
+ if (mBTSCOCVSDContext->pRXWorkingMemory) {
+ delete []mBTSCOCVSDContext->pRXWorkingMemory;
+ mBTSCOCVSDContext->pRXWorkingMemory = NULL;
+ }
+ ALOGD("BT_SCO_RX_Stop(-)");
+}
+
+uint8_t *AudioBTCVSDControl::BT_SCO_RX_GetCVSDTempInBuf(void) {
+ return mBTCVSDRXTempInBuf;
+}
+
+void AudioBTCVSDControl::BT_SCO_RX_SetCVSDTempInBuf(uint8_t *addr) {
+ mBTCVSDRXTempInBuf = addr;
+}
+
+
+uint8_t *AudioBTCVSDControl::BT_SCO_RX_GetCVSDInBuf(void) {
+ return mBTCVSDRXInBuf;
+}
+
+void AudioBTCVSDControl::BT_SCO_RX_SetCVSDInBuf(uint8_t *addr) {
+ mBTCVSDRXInBuf = addr;
+}
+
+uint8_t *AudioBTCVSDControl::BT_SCO_TX_GetCVSDOutBuf(void) {
+ return mBTCVSDTXOutBuf;
+}
+
+void AudioBTCVSDControl::BT_SCO_TX_SetCVSDOutBuf(uint8_t *addr) {
+ mBTCVSDTXOutBuf = addr;
+}
+
+uint8_t *AudioBTCVSDControl::BT_SCO_TX_GetCVSDWorkBuf(void) {
+ return mBTSCOCVSDContext->pTX->PcmBuf_64k;
+}
+
+void *AudioBTCVSDControl::BT_SCO_TX_GetTimeBufferInfo(void) {
+ ::ioctl(mFd2, GET_BTCVSD_TX_TIME_BUFFER_INFO, (unsigned long long)&gTimeBufferInfo);
+
+ ALOGD("%s(), dataCountEquiTime=%" PRIu64 ", uimestampUS=%" PRIu64 "", __FUNCTION__, gTimeBufferInfo.dataCountEquiTime, gTimeBufferInfo.timestampUS);
+ return &gTimeBufferInfo;
+}
+
+uint32_t AudioBTCVSDControl::Audio_IIRHPF_GetBufferSize(void) {
+ return 1024;
+}
+
+void *AudioBTCVSDControl::Audio_IIRHPF_Init(void) {
+ return NULL;
+}
+
+void AudioBTCVSDControl::Audio_IIRHPF_Process(void) {
+
+}
+
+#ifdef EXT_MODEM_BT_CVSD
+
+void AudioBTCVSDControl::BT_SCO_ExtMD_ULBuf_Open(void) {
+ ALOGD("BT_SCO_ExtMD_ULBuf_Open(+)");
+ mExtMDbtscoULBuf = (uint8_t *)new char[BTSCO_CVSD_RX_INBUF_SIZE * 2 * 2];
+ memset(mExtMDbtscoULBuf, 0, BTSCO_CVSD_RX_INBUF_SIZE * 2 * 2);
+ mExtMDbtscoULWTmpBuf = (uint8_t *)new char[BTSCO_CVSD_RX_INBUF_SIZE * 2];
+ memset(mExtMDbtscoULWTmpBuf, 0, BTSCO_CVSD_RX_INBUF_SIZE * 2);
+ mExtMDbtscoULWTmpBuf2 = (uint8_t *)new char[BTSCO_CVSD_RX_INBUF_SIZE * 2 * 2]; //for duplicate 1ch to 2ch to AFE DL1 mem intf
+ memset(mExtMDbtscoULWTmpBuf2, 0, BTSCO_CVSD_RX_INBUF_SIZE * 2 * 2);
+ ALOGD("BT_SCO_ExtMD_ULBuf_Open(-)");
+}
+
+void AudioBTCVSDControl::BT_SCO_ExtMD_ULBuf_Close(void) {
+ if (mExtMDbtscoULBuf) {
+ delete []mExtMDbtscoULBuf;
+ mExtMDbtscoULBuf = NULL;
+ ALOGD("BT_SCO_ExtMD_ULBuf_Close() release mExtMDbtscoULBuf");
+ }
+
+ if (mExtMDbtscoULWTmpBuf) {
+ delete []mExtMDbtscoULWTmpBuf;
+ mExtMDbtscoULWTmpBuf = NULL;
+ ALOGD("BT_SCO_ExtMD_ULBuf_Close() release mExtMDbtscoULWTmpBuf");
+ }
+
+ if (mExtMDbtscoULWTmpBuf2) {
+ delete []mExtMDbtscoULWTmpBuf2;
+ mExtMDbtscoULWTmpBuf2 = NULL;
+ ALOGD("BT_SCO_ExtMD_ULBuf_Close() release mExtMDbtscoULWTmpBuf2");
+ }
+}
+
+void AudioBTCVSDControl::BT_SCO_ExtMD_DLBuf_Open(void) {
+ ALOGD("BT_SCO_ExtMD_DLBuf_Open(+)");
+ mExtMDbtscoDLBuf = (uint8_t *)new char[BTSCO_CVSD_TX_OUTBUF_SIZE * 2 * 2];
+ memset(mExtMDbtscoDLBuf, 0, BTSCO_CVSD_TX_OUTBUF_SIZE * 2 * 2);
+ ALOGD("BT_SCO_ExtMD_DLBuf_Open(-)");
+}
+
+void AudioBTCVSDControl::BT_SCO_ExtMD_DLBuf_Close(void) {
+ if (mExtMDbtscoDLBuf) {
+ delete []mExtMDbtscoDLBuf;
+ mExtMDbtscoDLBuf = NULL;
+ ALOGD("BT_SCO_ExtMD_DLBuf_Close() release mExtMDbtscoDLBuf");
+ }
+}
+
+bool AudioBTCVSDControl::BT_SCO_ExtMDULBufLock(void) {
+ ALOGV("BT_SCO_ExtMDULBufLock (1)");
+ mLockUL.lock();
+ ALOGV("BT_SCO_ExtMDULBufLock (2)");
+ return true;
+}
+
+bool AudioBTCVSDControl::BT_SCO_ExtMDULBufUnLock(void) {
+ ALOGV("BT_SCO_ExtMDULBufUnLock (1)");
+ mLockUL.unlock();
+ ALOGV("BT_SCO_ExtMDULBufUnLock (2)");
+ return true;
+}
+
+bool AudioBTCVSDControl::BT_SCO_ExtMDDLBufLock(void) {
+ ALOGV("BT_SCO_ExtMDDLBufLock (1)");
+ mLockDL.lock();
+ ALOGV("BT_SCO_ExtMDDLBufLock (2)");
+ return true;
+}
+
+bool AudioBTCVSDControl::BT_SCO_ExtMDDLBufUnLock(void) {
+ ALOGV("BT_SCO_ExtMDDLBufUnLock (1)");
+ mLockDL.unlock();
+ ALOGV("BT_SCO_ExtMDDLBufUnLock (2)");
+ return true;
+}
+
+void AudioBTCVSDControl::BT_SCO_ExtMDInitBuf(EXTMD_BTSCO_DIRECTION direction) {
+ if (direction == ExtMD_BTSCO_UL) {
+ mULRingBuf.pBufBase = (char *)mExtMDbtscoULBuf;
+ //if (mBTSCOCVSDContext->fIsWideBand == true)
+ if (0) {
+ mULRingBuf.bufLen = BTSCO_CVSD_RX_INBUF_SIZE * 2 * 2 * 2;
+ } else {
+ mULRingBuf.bufLen = BTSCO_CVSD_RX_INBUF_SIZE * 2 * 2;
+ }
+ mULRingBuf.pRead = mULRingBuf.pBufBase + (mULRingBuf.bufLen >> 1) - 2;
+ mULRingBuf.pWrite = mULRingBuf.pBufBase;
+ } else if (direction == ExtMD_BTSCO_DL) {
+ mDLRingBuf.pBufBase = (char *)mExtMDbtscoDLBuf;
+ //if (mBTSCOCVSDContext->fIsWideBand == true)
+ if (0) {
+ mDLRingBuf.bufLen = BTSCO_CVSD_TX_OUTBUF_SIZE * 2 * 2 * 2;
+ } else {
+ mDLRingBuf.bufLen = BTSCO_CVSD_TX_OUTBUF_SIZE * 2 * 2;
+ }
+ mDLRingBuf.pRead = mDLRingBuf.pBufBase + (mDLRingBuf.bufLen >> 1) - 2;
+ mDLRingBuf.pWrite = mDLRingBuf.pBufBase;
+ }
+}
+uint32_t AudioBTCVSDControl::BT_SCO_ExtMDGetBufSpace(EXTMD_BTSCO_DIRECTION direction) {
+ int count = 0;
+
+ if (direction == ExtMD_BTSCO_UL) {
+ count = mULRingBuf.pRead - mULRingBuf.pWrite;
+ if (count < 0) { count += mULRingBuf.bufLen; }
+ } else if (direction == ExtMD_BTSCO_DL) {
+ count = mDLRingBuf.pRead - mDLRingBuf.pWrite;
+ if (count < 0) { count += mDLRingBuf.bufLen; }
+ }
+
+ return count;
+}
+
+uint32_t AudioBTCVSDControl::BT_SCO_ExtMDGetBufCount(EXTMD_BTSCO_DIRECTION direction) {
+ int count = 0;
+
+ if (direction == ExtMD_BTSCO_UL) {
+ count = mULRingBuf.pWrite - mULRingBuf.pRead;
+ if (count <= 0) { count += mULRingBuf.bufLen; }
+ } else if (direction == ExtMD_BTSCO_DL) {
+ count = mDLRingBuf.pWrite - mDLRingBuf.pRead;
+ if (count <= 0) { count += mDLRingBuf.bufLen; }
+ }
+
+ return count;
+}
+
+void AudioBTCVSDControl::BT_SCO_ExtMDWriteDataToRingBuf(uint8_t *buf, uint32_t size, EXTMD_BTSCO_DIRECTION direction) {
+ RingBuf *pRingBuf = NULL;
+
+ if (direction == ExtMD_BTSCO_UL) {
+ pRingBuf = &mULRingBuf;
+ } else if (direction == ExtMD_BTSCO_DL) {
+ pRingBuf = &mDLRingBuf;
+ }
+
+ ASSERT(pRingBuf != NULL);
+
+ char *end = pRingBuf->pBufBase + pRingBuf->bufLen;
+ uint32_t size1, size2;
+ ALOGD("BT_SCO_ExtMDWriteDataToRingBuf end=%p,pRingBuf->pWrite=%p, size=%d, direction=%d", (void *)end, (void *)pRingBuf->pWrite, size, direction);
+ if (size <= (uint32_t)(end - pRingBuf->pWrite)) { //copy once
+ memcpy(pRingBuf->pWrite, buf, size);
+ pRingBuf->pWrite += size;
+
+ if (pRingBuf->pWrite >= end) {
+ pRingBuf->pWrite -= pRingBuf->bufLen;
+ }
+ } else {
+ size1 = end - pRingBuf->pWrite;
+ size2 = size - size1;
+ memcpy(pRingBuf->pWrite, buf, size1);
+ memcpy(pRingBuf->pBufBase, buf + size1, size2);
+ pRingBuf->pWrite = pRingBuf->pBufBase + size2;
+ }
+}
+
+void AudioBTCVSDControl::BT_SCO_ExtMDReadDataFromRingBuf(uint8_t *buf, uint32_t size, EXTMD_BTSCO_DIRECTION direction) {
+ RingBuf *pRingBuf = NULL;
+
+ if (direction == ExtMD_BTSCO_UL) {
+ pRingBuf = &mULRingBuf;
+ } else if (direction == ExtMD_BTSCO_DL) {
+ pRingBuf = &mDLRingBuf;
+ }
+
+ ASSERT(pRingBuf != NULL);
+
+ char *end = pRingBuf->pBufBase + pRingBuf->bufLen;
+ uint32_t size1, size2;
+ ALOGD("BT_SCO_ExtMDReadDataFromRingBuf end=%p,pRingBuf->pRead=%p, size=%d, direction=%d", (void *)end, (void *)pRingBuf->pRead, size, direction);
+
+ if (size <= (uint32_t)(end - pRingBuf->pRead)) { //copy once
+ memcpy(buf, pRingBuf->pRead, size);
+ pRingBuf->pRead += size;
+
+ if (pRingBuf->pRead >= end) {
+ pRingBuf->pRead -= pRingBuf->bufLen;
+ }
+ } else {
+ size1 = end - pRingBuf->pRead;
+ size2 = size - size1;
+ memcpy(buf, pRingBuf->pRead, size1);
+ memcpy(buf + size1, pRingBuf->pBufBase, size2);
+ pRingBuf->pRead = pRingBuf->pBufBase + size2;
+ }
+}
+
+
+uint8_t *AudioBTCVSDControl::BT_SCO_ExtMDGetCVSDAccuOutBuf(void) {
+ return mBTSCOCVSDContext->pRX->PcmBuf_8k_accu;
+}
+
+uint8_t *AudioBTCVSDControl::BT_SCO_ExtMDGetCVSDULWriteTmpBuf(void) {
+ return mExtMDbtscoULWTmpBuf;
+}
+
+uint8_t *AudioBTCVSDControl::BT_SCO_ExtMDGetCVSDULWriteTmpBuf2(void) {
+ return mExtMDbtscoULWTmpBuf2;
+}
+
+bool AudioBTCVSDControl::BT_SCO_ExtMDGetBTSCORunning(void) {
+ return mExtMDBTSCORunning;
+}
+
+void AudioBTCVSDControl::AudioExtMDCVSDCreateThread(void) {
+ mExtMDBTSCORunning = true;
+ ALOGD("mExtMDBTSCORunning = %d", mExtMDBTSCORunning);
+
+ mExtMDCVSDULThread1 = new AudioExtMDCVSDThread(ExtMD_BTSCO_UL_READTHREAD, NULL, 0);
+ if (mExtMDCVSDULThread1.get()) {
+ mExtMDCVSDULThread1->run("mExtMDCVSDULThread1");
+ }
+
+ mExtMDCVSDULThread2 = new AudioExtMDCVSDThread(ExtMD_BTSCO_UL_WRITETHREAD, NULL, 0);
+ if (mExtMDCVSDULThread2.get()) {
+ mExtMDCVSDULThread2->run("mExtMDCVSDULThread2");
+ }
+
+ mExtMDCVSDDLThread1 = new AudioExtMDCVSDThread(ExtMD_BTSCO_DL_READTHREAD, NULL, 0);
+ if (mExtMDCVSDDLThread1.get()) {
+ mExtMDCVSDDLThread1->run("mExtMDCVSDDLThread1");
+ }
+
+ mExtMDCVSDDLThread2 = new AudioExtMDCVSDThread(ExtMD_BTSCO_DL_WRITETHREAD, NULL, 0);
+ if (mExtMDCVSDDLThread2.get()) {
+ mExtMDCVSDDLThread2->run("mExtMDCVSDDLThread2");
+ }
+
+}
+
+void AudioBTCVSDControl::AudioExtMDCVSDDeleteThread(void) {
+ int ret = 0;
+
+#if 1 // close AFE interconnection first in AudioExtMDCVSDDeleteThread()
+ //mAudioDigitalControl = AudioDigitalControlFactory::CreateAudioDigitalControl();
+
+ //mAudioDigitalControl->SetinputConnection(AudioDigitalType::DisConnect, AudioDigitalType::I05, AudioDigitalType::O07);
+ //mAudioDigitalControl->SetinputConnection(AudioDigitalType::DisConnect, AudioDigitalType::I06, AudioDigitalType::O08);
+
+ //mAudioDigitalControl->SetinputConnection(AudioDigitalType::DisConnect, AudioDigitalType::I09, AudioDigitalType::O12);
+#endif
+
+
+ if (mExtMDCVSDULThread2.get()) { //deleted UL write thread first to prevent DL1 underflow!
+ ret = mExtMDCVSDULThread2->requestExitAndWait();
+ if (ret == WOULD_BLOCK) {
+ mExtMDCVSDULThread2->requestExit();
+ }
+ mExtMDCVSDULThread2.clear();
+ }
+
+ ret = 0;
+ if (mExtMDCVSDULThread1.get()) { //delete UL read thread
+ ret = mExtMDCVSDULThread1->requestExitAndWait();
+ if (ret == WOULD_BLOCK) {
+ mExtMDCVSDULThread1->requestExit();
+ }
+ mExtMDCVSDULThread1.clear();
+ }
+
+ ret = 0;
+ if (mExtMDCVSDDLThread2.get()) { //delete DL write thread
+ ret = mExtMDCVSDDLThread2->requestExitAndWait();
+ if (ret == WOULD_BLOCK) {
+ mExtMDCVSDDLThread2->requestExit();
+ }
+ mExtMDCVSDDLThread2.clear();
+ }
+
+ ret = 0;
+ if (mExtMDCVSDDLThread1.get()) { //delete DL read thread
+ ret = mExtMDCVSDDLThread1->requestExitAndWait();
+ if (ret == WOULD_BLOCK) {
+ mExtMDCVSDDLThread1->requestExit();
+ }
+ mExtMDCVSDDLThread1.clear();
+ }
+
+ BT_SCO_ExtMD_ULBuf_Close();
+ BT_SCO_ExtMD_DLBuf_Close();
+
+ mExtMDBTSCORunning = false;
+ ALOGD("mExtMDBTSCORunning = %d", mExtMDBTSCORunning);
+}
+
+AudioBTCVSDControl::AudioExtMDCVSDThread::AudioExtMDCVSDThread(EXTMD_BTSCO_THREAD_TYPE Thread_type, char *RingBuffer, uint32_t BufferSize) :
+ mAFEDLStarting(false),
+ mAFEULStarting(false),
+ mPAdcPCMDumpFile(NULL),
+ mPI2SPCMDumpFile(NULL),
+ mExtMDULReadPCMDumpFile(NULL),
+ mExtMDULWritePCMDumpFile(NULL),
+ mExtMDDLReadPCMDumpFile(NULL),
+ mExtMDDLWritePCMDumpFile(NULL),
+ mAudioBTCVSDControl(NULL)
+#ifndef EXTMD_SUPPORT_WB
+ , pULSRCHandle(NULL)
+#endif
+{
+ ALOGD("AudioExtMDCVSDThread constructor Thread_type = %d", Thread_type);
+
+ mAudioBTCVSDControl = AudioBTCVSDControl::getInstance();
+
+ if (!mAudioBTCVSDControl) {
+ ALOGE("AudioBTCVSDControl::getInstance() fail");
+ }
+
+ mFd = 0;
+ mFd2 = mAudioBTCVSDControl->getFd();
+
+ mThreadType = Thread_type;
+
+ switch (mThreadType) {
+ case ExtMD_BTSCO_UL_READTHREAD:
+ mName = String8("ExtMDCVSDULReadThread");
+ mExtMDULReadPCMDumpFile = AudioOpendumpPCMFile("/data/vendor/audiohal/audio_dump/extmd_ul_read.pcm", "extmd_ul_read.dump");
+
+ mAudioBTCVSDControl->BT_SCO_RX_Begin(mFd2);
+ mAudioBTCVSDControl->BT_SCO_ExtMD_ULBuf_Open();
+ mAudioBTCVSDControl->BT_SCO_ExtMDInitBuf(ExtMD_BTSCO_UL); //init ULBuf bufbase/read write pointer
+ break;
+ case ExtMD_BTSCO_UL_WRITETHREAD:
+ if (mFd == 0) {
+ //mFd = ::open(kAudioDeviceName, O_RDWR);
+ if (mFd <= 0) {
+ ALOGW("open AFE kernel device fail");
+ }
+ }
+ mName = String8("ExtMDCVSDULWriteThread");
+ mExtMDULWritePCMDumpFile = NULL;
+ mExtMDULWritePCMDumpFile = AudioOpendumpPCMFile("/data/vendor/audiohal/audio_dump/extmd_ul_write.pcm", "extmd_ul_write.dump");
+
+ mAFEULStarting = false;
+ //mAudioResourceManager = AudioResourceManager::getInstance();
+ //mAudioDigitalControl = AudioDigitalControlFactory::CreateAudioDigitalControl();
+
+ //RequesetPlaybackclock();
+#ifdef EXTMD_LOOPBACK_TEST
+ //mAudioResourceManager->EnableAudioClock(AudioResourceManagerInterface::CLOCK_AUD_ANA, true); // ANA CLK only for test mode
+#endif
+ //mAudioResourceManager->EnableAudioClock(AudioResourceManagerInterface::CLOCK_AUD_AFE, true); //no need ANA CLK
+
+ //mAudioDigitalControl->FreeMemBufferSize(AudioDigitalType::MEM_DL1); // default DL1 buf size is 16k, too big... Need to reallocate
+ //if (mBTSCOCVSDContext->fIsWideBand == true)
+ if (0) {
+ //mAudioDigitalControl->SetMemBufferSize(AudioDigitalType::MEM_DL1, BTSCO_CVSD_RX_INBUF_SIZE * 2 * 2 * 2 * 2); //480*2*2*2*2, 2ch
+#ifndef EXTMD_SUPPORT_WB
+ pULSRCHandle = newMtkAudioSrc(BTSCO_MSBC_SAMPLERATE_DOMAIN, BTSCO_MSBC_CHANNEL_NUM, BTSCO_EXTMD_SAMPLERATE, BTSCO_MSBC_CHANNEL_NUM, SRC_IN_Q1P15_OUT_Q1P15);
+ pULSRCHandle->open();
+#endif
+ } else {
+ //mAudioDigitalControl->SetMemBufferSize(AudioDigitalType::MEM_DL1, BTSCO_CVSD_RX_INBUF_SIZE * 2 * 2 * 2); //480*2*2*2, 2ch
+ }
+ //mAudioDigitalControl->AllocateMemBufferSize(AudioDigitalType::MEM_DL1);
+
+ //::ioctl(mFd, START_MEMIF_TYPE, AudioDigitalType::MEM_DL1); // fp for write indentify
+ break;
+ case ExtMD_BTSCO_DL_READTHREAD:
+ if (mFd == 0) {
+ //mFd = ::open(kAudioDeviceName, O_RDWR);
+ if (mFd <= 0) {
+ ALOGW("open AFE kernel device fail");
+ }
+ }
+ mName = String8("ExtMDCVSDDLReadThread");
+ mExtMDDLReadPCMDumpFile = NULL;
+ mExtMDDLReadPCMDumpFile = AudioOpendumpPCMFile("/data/vendor/audiohal/audio_dump/extmd_dl_read.pcm", "vendor.extmd_dl_read.dump");
+
+ mAFEDLStarting = false;
+ mAudioBTCVSDControl->BT_SCO_ExtMD_DLBuf_Open();
+ mAudioBTCVSDControl->BT_SCO_ExtMDInitBuf(ExtMD_BTSCO_DL); //init ULBuf bufbase/read write pointer
+
+ //mAudioResourceManager = AudioResourceManager::getInstance();
+ //mAudioDigitalControl = AudioDigitalControlFactory::CreateAudioDigitalControl();
+
+ //mAudioDigitalControl->FreeMemBufferSize(AudioDigitalType::MEM_MOD_DAI); // default MEM_MOD_DAI buf size is 8k, too big... Need to reallocate
+
+ //if (mBTSCOCVSDContext->fIsWideBand == true)
+ if (0) {
+ //mAudioDigitalControl->SetMemBufferSize(AudioDigitalType::MEM_MOD_DAI, BTSCO_CVSD_TX_OUTBUF_SIZE * 2 * 2 * 2); //480*2*2*2
+ } else {
+ //mAudioDigitalControl->SetMemBufferSize(AudioDigitalType::MEM_MOD_DAI, BTSCO_CVSD_TX_OUTBUF_SIZE * 2 * 2); //480*2*2
+ }
+ //mAudioDigitalControl->AllocateMemBufferSize(AudioDigitalType::MEM_MOD_DAI);
+
+ //::ioctl(mFd, START_MEMIF_TYPE, AudioDigitalType::MEM_MOD_DAI); // fp for write indentify
+ break;
+ case ExtMD_BTSCO_DL_WRITETHREAD:
+ mName = String8("ExtMDCVSDDLWriteThread");
+ mExtMDDLWritePCMDumpFile = NULL;
+ mExtMDDLWritePCMDumpFile = AudioOpendumpPCMFile("/data/vendor/audiohal/audio_dump/extmd_dl_write.pcm", "vendor.extmd_dl_write.dump");
+ mAudioBTCVSDControl->BT_SCO_TX_Begin(mFd2, EXTMD_BTSCO_AFE_SAMPLERATE, 1);
+ break;
+ default:
+ ALOGD("unsupport ExtMD_BTSCO_Thread type");
+ break;
+ }
+ // ring buffer to copy data into this ring buffer
+ mRingBuffer = RingBuffer;
+ mBufferSize = BufferSize;
+}
+
+AudioBTCVSDControl::AudioExtMDCVSDThread::~AudioExtMDCVSDThread() {
+#define DL1_BUFFER_SIZE (0x4000)
+
+ ALOGD("+~AudioExtMDCVSDThread()mThreadType=%d", mThreadType);
+ ClosePcmDumpFile();
+
+ switch (mThreadType) {
+ case ExtMD_BTSCO_UL_READTHREAD:
+ mAudioBTCVSDControl->BT_SCO_RX_End(mFd2);
+ //mAudioBTCVSDControl->BT_SCO_ExtMD_ULBuf_Close();
+ break;
+ case ExtMD_BTSCO_UL_WRITETHREAD:
+
+ mAFEULStarting = false;
+
+ //mAudioDigitalControl->SetIrqMcuEnable(AudioDigitalType::IRQ1_MCU_MODE, false);
+
+ //mAudioDigitalControl->SetMemIfEnable(AudioDigitalType::MEM_DL1, false);
+ ////mAudioDigitalControl->SetAfeEnable(false);
+
+ if (mFd) {
+ ALOGD("threadLoop exit STANDBY_MEMIF_TYPE mThreadType = %d", mThreadType);
+ //::ioctl(mFd, STANDBY_MEMIF_TYPE, AudioDigitalType::MEM_DL1); // disable mem interface DL1
+ }
+
+#ifdef EXTMD_LOOPBACK_TEST
+ //close DAC
+ //mAudioResourceManager->StopOutputDevice();
+#endif
+ //mAudioDigitalControl->FreeMemBufferSize(AudioDigitalType::MEM_DL1); // revert to default DL1 size
+ //mAudioDigitalControl->SetMemBufferSize(AudioDigitalType::MEM_DL1, DL1_BUFFER_SIZE);
+ //mAudioDigitalControl->AllocateMemBufferSize(AudioDigitalType::MEM_DL1);
+
+ //if (mBTSCOCVSDContext->fIsWideBand == true)
+ if (0) {
+#ifndef EXTMD_SUPPORT_WB
+ pULSRCHandle->close();
+ deleteMtkAudioSrc(pULSRCHandle);
+ pULSRCHandle = NULL;
+#endif
+ }
+ break;
+ case ExtMD_BTSCO_DL_READTHREAD:
+ mAFEDLStarting = false;
+
+ //mAudioDigitalControl->SetMemIfEnable(AudioDigitalType::MEM_MOD_DAI, false);
+ //mAudioDigitalControl->SetIrqMcuEnable(AudioDigitalType::IRQ2_MCU_MODE, false);
+
+#ifdef EXTMD_LOOPBACK_TEST
+ //close ADC (no need if use sine wave gen to test)
+ ////mAudioResourceManager->StopInputDevice();
+#endif
+
+ if (mFd) {
+ ALOGD("threadLoop exit STANDBY_MEMIF_TYPE mThreadType = %d", mThreadType);
+ //::ioctl(mFd, STANDBY_MEMIF_TYPE, AudioDigitalType::MEM_MOD_DAI);
+ ::close(mFd);
+ mFd = 0;
+ }
+
+#if 0
+ // No need to revert to default MEM_MOD_DAI size since it will be reinit each time on start
+ //mAudioDigitalControl->FreeMemBufferSize(AudioDigitalType::MEM_MOD_DAI);
+ //mAudioDigitalControl->SetMemBufferSize(AudioDigitalType::MEM_MOD_DAI, DL1_BUFFER_SIZE);
+ //mAudioDigitalControl->AllocateMemBufferSize(AudioDigitalType::MEM_MOD_DAI);
+#endif
+
+ //ReleaseRecordclock();
+ //mAudioResourceManager->EnableAudioClock(AudioResourceManagerInterface::CLOCK_AUD_AFE, false);
+#ifdef EXTMD_LOOPBACK_TEST
+ //no need if use sine wave gen to test
+ ////mAudioResourceManager->EnableAudioClock(AudioResourceManagerInterface::CLOCK_AUD_ANA, false);
+#endif
+ //mAudioBTCVSDControl->BT_SCO_ExtMD_DLBuf_Close();
+ break;
+ case ExtMD_BTSCO_DL_WRITETHREAD:
+ mAudioBTCVSDControl->BT_SCO_TX_End(mFd2);
+ if (mFd2) {
+ ::close(mFd2);
+ mFd2 = 0;
+ }
+ break;
+ default:
+ ALOGD("unsupport ExtMD_BTSCO_Thread type");
+ break;
+ }
+ ALOGD("-~AudioExtMDCVSDThread()");
+}
+
+void AudioBTCVSDControl::AudioExtMDCVSDThread::onFirstRef() {
+ ALOGD("AudioExtMDCVSDThread onFirstRef");
+
+ run(mName, ANDROID_PRIORITY_URGENT_AUDIO);
+}
+
+// Good place to do one-time initializations
+status_t AudioBTCVSDControl::AudioExtMDCVSDThread::readyToRun() {
+ ALOGD("AudioExtMDCVSDThread::readyToRun(),mThreadType=%d", mThreadType);
+
+ return NO_ERROR;
+}
+
+void AudioBTCVSDControl::AudioExtMDCVSDThread::WritePcmDumpData(uint8_t *buf, uint32_t size) {
+ int written_data = 0;
+ switch (mThreadType) {
+ case ExtMD_BTSCO_UL_READTHREAD:
+ if (mExtMDULReadPCMDumpFile) {
+ written_data = fwrite((void *)buf, 1, size, mExtMDULReadPCMDumpFile);
+ }
+ break;
+ case ExtMD_BTSCO_UL_WRITETHREAD:
+ if (mExtMDULWritePCMDumpFile) {
+ written_data = fwrite((void *)buf, 1, size, mExtMDULWritePCMDumpFile);
+ }
+ break;
+ case ExtMD_BTSCO_DL_READTHREAD:
+ if (mExtMDDLReadPCMDumpFile) {
+ written_data = fwrite((void *)buf, 1, size, mExtMDDLReadPCMDumpFile);
+ }
+ break;
+ case ExtMD_BTSCO_DL_WRITETHREAD:
+ if (mExtMDDLWritePCMDumpFile) {
+ written_data = fwrite((void *)buf, 1, size, mExtMDDLWritePCMDumpFile);
+ }
+ break;
+ default:
+ ALOGW("AudioExtMDCVSDThread::WritePcmDumpData unknown mThreadType!!! ");
+ break;
+ }
+}
+
+void AudioBTCVSDControl::AudioExtMDCVSDThread::ClosePcmDumpFile() {
+ ALOGD("ClosePcmDumpFile");
+ switch (mThreadType) {
+ case ExtMD_BTSCO_UL_READTHREAD:
+ if (mExtMDULReadPCMDumpFile) {
+ AudioCloseDumpPCMFile(mExtMDULReadPCMDumpFile);
+ ALOGD("ClosePcmDumpFile mExtMDULReadPCMDumpFile");
+ }
+ break;
+ case ExtMD_BTSCO_UL_WRITETHREAD:
+ if (mExtMDULWritePCMDumpFile) {
+ AudioCloseDumpPCMFile(mExtMDULWritePCMDumpFile);
+ ALOGD("ClosePcmDumpFile mExtMDULWritePCMDumpFile");
+ }
+ break;
+ case ExtMD_BTSCO_DL_READTHREAD:
+ if (mExtMDDLReadPCMDumpFile) {
+ AudioCloseDumpPCMFile(mExtMDDLReadPCMDumpFile);
+ ALOGD("ClosePcmDumpFile mExtMDDLReadPCMDumpFile");
+ }
+ break;
+ case ExtMD_BTSCO_DL_WRITETHREAD:
+ if (mExtMDDLWritePCMDumpFile) {
+ AudioCloseDumpPCMFile(mExtMDDLWritePCMDumpFile);
+ ALOGD("ClosePcmDumpFile mExtMDDLWritePCMDumpFile");
+ }
+ break;
+ default:
+ ALOGW("AudioExtMDCVSDThread::ClosePcmDumpFile unknown mThreadType!!! ");
+ break;
+ }
+}
+
+void AudioBTCVSDControl::AudioExtMDCVSDThread::ExtMD_btsco_cvsd_UL_Read_main(void) {
+ uint8_t packetvalid, *outbuf, *workbuf, *tempbuf, *inbuf, *accuoutbuf, trycount;
+ uint32_t i, outsize, workbufsize, insize, bytes, offset, accuoutsize;
+ int32_t Read_Size;
+
+ ALOGD("ExtMD_btsco_cvsd_UL_Read_main(+)");
+ Read_Size = ::read(mFd2, mAudioBTCVSDControl->BT_SCO_RX_GetCVSDTempInBuf(), BTSCO_CVSD_RX_TEMPINPUTBUF_SIZE);
+ ALOGD("ExtMD_btsco_cvsd_UL_Read_main ::read() done Read_Size=%d", Read_Size);
+
+ if (Read_Size <= 0) {
+ ALOGW("ExtMD_btsco_cvsd_UL_Read_main Read_Size=%d!!!", Read_Size);
+ usleep(15 * 1000);
+ return;
+ }
+
+ if (Read_Size % (SCO_RX_PLC_SIZE + BTSCO_CVSD_PACKET_VALID_SIZE) != 0) {
+ ALOGE("Read_Size %% (SCO_RX_PLC_SIZE + BTSCO_CVSD_PACKET_VALID_SIZE) != 0");
+ ASSERT(false);
+ }
+
+ accuoutbuf = mAudioBTCVSDControl->BT_SCO_ExtMDGetCVSDAccuOutBuf();
+ accuoutsize = 0;
+
+ if (mBTSCOCVSDContext->fIsWideBand == true) {
+ outbuf = mAudioBTCVSDControl->BT_SCO_RX_GetMSBCOutBuf();
+ outsize = MSBC_PCM_FRAME_BYTE;
+ } else {
+ outbuf = mAudioBTCVSDControl->BT_SCO_RX_GetCVSDOutBuf();
+ outsize = SCO_RX_PCM8K_BUF_SIZE;
+ }
+ workbuf = mAudioBTCVSDControl->BT_SCO_RX_GetCVSDWorkBuf();
+ workbufsize = SCO_RX_PCM64K_BUF_SIZE;
+ tempbuf = mAudioBTCVSDControl->BT_SCO_RX_GetCVSDTempInBuf();
+ inbuf = mAudioBTCVSDControl->BT_SCO_RX_GetCVSDInBuf();
+ insize = SCO_RX_PLC_SIZE;
+ //bytes = BTSCO_CVSD_RX_INBUF_SIZE;
+ bytes = (Read_Size / (SCO_RX_PLC_SIZE + BTSCO_CVSD_PACKET_VALID_SIZE)) * SCO_RX_PLC_SIZE;
+ i = 0;
+ offset = 0;
+ do {
+ packetvalid = *((char *)tempbuf + SCO_RX_PLC_SIZE + offset + i * BTSCO_CVSD_PACKET_VALID_SIZE); //parser packet valid info for each 30-byte packet
+ //packetvalid = 1; //force packvalid to 1 for test
+ memcpy(inbuf + offset, tempbuf + offset + i * BTSCO_CVSD_PACKET_VALID_SIZE, SCO_RX_PLC_SIZE);
+
+ if (mBTSCOCVSDContext->fIsWideBand == true) {
+ ALOGD("btsco_process_RX_MSBC(+) insize=%d,outsize=%d,packetvalid=%d ", insize, outsize, packetvalid);
+ mAudioBTCVSDControl->btsco_process_RX_MSBC(inbuf + offset, &insize, outbuf, &outsize, workbuf, packetvalid);
+ } else {
+ ALOGVV("btsco_process_RX_CVSD(+) insize=%d,outsize=%d,packetvalid=%d ", insize, outsize, packetvalid);
+ mAudioBTCVSDControl->btsco_process_RX_CVSD(inbuf + offset, &insize, outbuf, &outsize, workbuf, workbufsize, packetvalid);
+ }
+ offset += SCO_RX_PLC_SIZE;
+ bytes -= insize;
+ ALOGVV("btsco_process_RX(-) consumed=%d, outsize=%d, bytes=%d", insize, outsize, bytes);
+
+ if (outsize != 0) {
+ memcpy(accuoutbuf, outbuf, outsize);
+ accuoutbuf += outsize;
+ accuoutsize += outsize;
+ }
+
+ if (mBTSCOCVSDContext->fIsWideBand == true) {
+ outsize = MSBC_PCM_FRAME_BYTE;
+ } else {
+ outsize = SCO_RX_PCM8K_BUF_SIZE;
+ }
+ insize = SCO_RX_PLC_SIZE;
+ i++;
+ } while (bytes > 0);
+
+ // total outsize is: BTSCO_CVSD_RX_INBUF_SIZE*2
+ trycount = 0;
+ uint32_t FreeSpace;
+
+ accuoutbuf = mAudioBTCVSDControl->BT_SCO_ExtMDGetCVSDAccuOutBuf();
+ ALOGD("accuoutsize=%d", accuoutsize);
+
+ do {
+ mAudioBTCVSDControl->BT_SCO_ExtMDULBufLock();
+ FreeSpace = mAudioBTCVSDControl->BT_SCO_ExtMDGetBufSpace(ExtMD_BTSCO_UL);
+ ALOGVV("ExtMD_btsco_cvsd_UL_Read_main FreeSpace=%d", FreeSpace);
+ if (FreeSpace >= BTSCO_CVSD_RX_INBUF_SIZE * 2) {
+ mAudioBTCVSDControl->BT_SCO_ExtMDWriteDataToRingBuf(accuoutbuf, accuoutsize, ExtMD_BTSCO_UL);
+ mAudioBTCVSDControl->BT_SCO_ExtMDULBufUnLock();
+ WritePcmDumpData(accuoutbuf, accuoutsize);
+ break;
+ } else {
+ ALOGD("ExtMD_btsco_cvsd_UL_Read_main FreeSpace=%d < %d,", FreeSpace, BTSCO_CVSD_RX_INBUF_SIZE * 2);
+ mAudioBTCVSDControl->BT_SCO_ExtMDULBufUnLock();
+ usleep(10 * 1000);
+ }
+ trycount++;
+ } while (trycount < 10);
+
+ if (trycount == 10) {
+ ALOGW("AudioExtMDCVSDThread::ExtMD_btsco_cvsd_UL_Read_main() BT_SCO_RX_ExtMDWriteDataToULBuf() Timeout!!!");
+ }
+
+ ALOGVV("ExtMD_btsco_cvsd_UL_Read_main(-)");
+}
+
+void AudioBTCVSDControl::AudioExtMDCVSDThread::ExtMD_btsco_cvsd_UL_Write_main(void) {
+ uint32_t DataCount, trycount = 0, i, src_inszie, src_outsize;
+ uint8_t *wtmpbuf, *wtmpbuf2, *pbuf1, *pbuf2;
+ uint16_t *pSrc, *pDst, threshold, samplecount;
+
+ ALOGVV("ExtMD_btsco_cvsd_UL_Write_main(+)");
+
+#ifndef EXTMD_SUPPORT_WB
+ //if (mBTSCOCVSDContext->fIsWideBand == true)
+ if (0) {
+ pbuf1 = mAudioBTCVSDControl->BT_SCO_ExtMDGetCVSDULWriteTmpBuf2();
+ pbuf2 = mAudioBTCVSDControl->BT_SCO_ExtMDGetCVSDULWriteTmpBuf();
+ } else
+#endif
+ {
+ pbuf1 = mAudioBTCVSDControl->BT_SCO_ExtMDGetCVSDULWriteTmpBuf();
+ }
+ do {
+ mAudioBTCVSDControl->BT_SCO_ExtMDULBufLock();
+ DataCount = mAudioBTCVSDControl->BT_SCO_ExtMDGetBufCount(ExtMD_BTSCO_UL);
+ ALOGVV("ExtMD_btsco_cvsd_UL_Write_main DataCount=%d", DataCount);
+ //if (mBTSCOCVSDContext->fIsWideBand == true)
+ if (0) {
+ threshold = BTSCO_CVSD_RX_INBUF_SIZE * 2 * 2;
+ } else {
+ threshold = BTSCO_CVSD_RX_INBUF_SIZE * 2;
+ }
+ if (DataCount >= threshold) {
+ mAudioBTCVSDControl->BT_SCO_ExtMDReadDataFromRingBuf(pbuf1, threshold, ExtMD_BTSCO_UL); //use temp buf to avoid blocking Lock
+ mAudioBTCVSDControl->BT_SCO_ExtMDULBufUnLock();
+ break;
+ } else {
+ ALOGVV("ExtMD_btsco_cvsd_UL_Write_main DataCount=%d < %d,", DataCount, threshold);
+ mAudioBTCVSDControl->BT_SCO_ExtMDULBufUnLock();
+ usleep(10 * 1000);
+ }
+ trycount++;
+ } while (trycount < 10);
+
+ if (trycount == 10) {
+ ALOGW("AudioExtMDCVSDThread::ExtMD_btsco_cvsd_UL_Write_main() BT_SCO_RX_ExtMDReadDataFromULBuf() Timeout!!!");
+ return;
+ }
+
+#ifndef EXTMD_SUPPORT_WB
+ //16k to 8k SRC for extMD 8k case (if extMD support 16k, only need to remove this SRC)
+ //if (pULSRCHandle!=NULL)
+ if (0) {
+ src_inszie = threshold;
+ src_outsize = threshold >> 1;
+
+ pULSRCHandle->process(pbuf1, &src_inszie, pbuf2, &src_outsize);
+ ASSERT(src_outsize == (BTSCO_CVSD_RX_INBUF_SIZE * 2));
+ }
+#endif
+
+ // duplicate (1ch 16 byte) to (2ch 16 byte)
+ pSrc = (uint16_t *)mAudioBTCVSDControl->BT_SCO_ExtMDGetCVSDULWriteTmpBuf();
+ pDst = (uint16_t *)mAudioBTCVSDControl->BT_SCO_ExtMDGetCVSDULWriteTmpBuf2();
+#ifdef EXTMD_SUPPORT_WB
+ //if (mBTSCOCVSDContext->fIsWideBand == true)
+ if (0) {
+ samplecount = BTSCO_CVSD_RX_INBUF_SIZE * 2;
+ } else
+#endif
+ {
+ samplecount = BTSCO_CVSD_RX_INBUF_SIZE;
+ }
+
+ ALOGVV("ExtMD_btsco_cvsd_UL_Write_main pSrc=0x%x, pDst=0x%x, samplecount=%d", pSrc, pDst, samplecount);
+
+ for (i = 0; i < samplecount; i++) {
+ *pDst = *pSrc;
+ pDst++;
+ *pDst = *pSrc;
+ pDst++;
+ pSrc++;
+ }
+
+ wtmpbuf2 = mAudioBTCVSDControl->BT_SCO_ExtMDGetCVSDULWriteTmpBuf2();
+
+ WritePcmDumpData(wtmpbuf2, samplecount * 2 * 2);
+
+ ALOGD("ExtMD_btsco_cvsd_UL_Write_main ::write to kernel (+),size=%d", samplecount * 2 * 2);
+ ::write(mFd, wtmpbuf2, samplecount * 2 * 2); //BTSCO_CVSD_RX_INBUF_SIZE*2
+ ALOGD("ExtMD_btsco_cvsd_UL_Write_main ::write to kernel (-)");
+
+ if (mAFEULStarting == false) { //mAudioBTCVSDControl->BT_SCO_RX_ExtMDInitAFEDLHW();
+ ALOGD("ExtMD_btsco_cvsd_UL_Write_main mAFEULStarting=false");
+ ::write(mFd, wtmpbuf2, samplecount * 2 * 2);
+ mAFEULStarting = true;
+
+ //SetIMcuIRQ(AudioDigitalType::IRQ1_MCU_MODE, mDL1Attribute);
+ //mAudioDigitalControl->SetIrqMcuSampleRate(AudioDigitalType::IRQ1_MCU_MODE, EXTMD_BTSCO_AFE_SAMPLERATE);
+ //mAudioDigitalControl->SetIrqMcuCounter(AudioDigitalType::IRQ1_MCU_MODE, BTSCO_CVSD_RX_INBUF_SIZE); // 480 samples, 60ms
+ //EnableIMcuIRQ(AudioDigitalType::IRQ1_MCU_MODE, true);
+ //mAudioDigitalControl->SetIrqMcuEnable(AudioDigitalType::IRQ1_MCU_MODE, true);
+
+#ifdef EXTMD_LOOPBACK_TEST
+ //TurnOnAfeDigital(DigitalPart);
+
+ //mAudioDigitalControl->SetMemIfFetchFormatPerSample(AudioDigitalType::MEM_DL1, AudioMEMIFAttribute::AFE_WLEN_16_BIT);
+ //mAudioDigitalControl->SetoutputConnectionFormat(AudioDigitalType::OUTPUT_DATA_FORMAT_16BIT, AudioDigitalType::O03);
+ //mAudioDigitalControl->SetoutputConnectionFormat(AudioDigitalType::OUTPUT_DATA_FORMAT_16BIT, AudioDigitalType::O04);
+
+ // interconnection to DAC output
+ //mAudioDigitalControl->SetinputConnection(AudioDigitalType::Connection, AudioDigitalType::I05, AudioDigitalType::O03);
+ //mAudioDigitalControl->SetinputConnection(AudioDigitalType::Connection, AudioDigitalType::I06, AudioDigitalType::O04);
+
+ // turn on digital part
+ //mAudioDigitalControl->SetMemIfEnable(AudioDigitalType::I2S_OUT_DAC, true);
+
+ // turn on DAC_I2S out
+ {
+ AudioDigtalI2S *mDL1Out;
+ mDL1Out = new AudioDigtalI2S();
+
+ ALOGD("EXTMD_LOOPBACK_TEST SetI2SOutDACAttribute");
+ mDL1Out->mLR_SWAP = AudioDigtalI2S::NO_SWAP;
+ mDL1Out->mI2S_SLAVE = AudioDigtalI2S::MASTER_MODE;
+ mDL1Out->mINV_LRCK = AudioDigtalI2S::NO_INVERSE;
+ mDL1Out->mI2S_FMT = AudioDigtalI2S::I2S;
+ mDL1Out->mI2S_WLEN = AudioDigtalI2S::WLEN_16BITS;
+ mDL1Out->mI2S_SAMPLERATE = EXTMD_BTSCO_AFE_SAMPLERATE;
+ //mAudioDigitalControl->SetI2SDacOut(mDL1Out);
+ }
+ //mAudioDigitalControl->SetI2SDacEnable(true);
+
+ //turn on analog part
+ //SetAnalogFrequency(DigitalPart);
+ //mAudioAnalogControl = AudioAnalogControlFactory::CreateAudioAnalogControl();
+ if (! { //mAudioAnalogControl)
+ ALOGD("EXTMD_LOOPBACK_TEST CreateAudioAnalogControl fail!!!");
+ }
+
+ ////mAudioAnalogControl->SetFrequency(AudioAnalogType::DEVICE_OUT_DAC, EXTMD_BTSCO_AFE_SAMPLERATE);
+
+ //SetPlayBackPinmux();
+ //mAudioAnalogControl->AnalogSetMux(AudioAnalogType::DEVICE_OUT_HEADSETR, AudioAnalogType::MUX_AUDIO);
+ //mAudioAnalogControl->AnalogSetMux(AudioAnalogType::DEVICE_OUT_HEADSETL, AudioAnalogType::MUX_AUDIO);
+ //mAudioAnalogControl->AnalogSetMux(AudioAnalogType::DEVICE_OUT_SPEAKERR, AudioAnalogType::MUX_AUDIO);
+ //mAudioAnalogControl->AnalogSetMux(AudioAnalogType::DEVICE_OUT_SPEAKERL, AudioAnalogType::MUX_AUDIO);
+
+ //mAudioResourceManager = AudioResourceManager::getInstance();
+ //mAudioResourceManager->SetFrequency(AudioResourceManagerInterface::DEVICE_OUT_DAC, EXTMD_BTSCO_AFE_SAMPLERATE);
+ //mAudioResourceManager->StartOutputDevice(); // open analog device and set master volume
+
+#else
+ //mAudioDigitalControl->SetMemIfFetchFormatPerSample(AudioDigitalType::MEM_DL1, AudioMEMIFAttribute::AFE_WLEN_16_BIT);
+ //mAudioDigitalControl->SetoutputConnectionFormat(AudioDigitalType::OUTPUT_DATA_FORMAT_16BIT, AudioDigitalType::O07);
+ //mAudioDigitalControl->SetoutputConnectionFormat(AudioDigitalType::OUTPUT_DATA_FORMAT_16BIT, AudioDigitalType::O08);
+
+ //mAudioDigitalControl->SetinputConnection(AudioDigitalType::Connection, AudioDigitalType::I05, AudioDigitalType::O07);
+ //mAudioDigitalControl->SetinputConnection(AudioDigitalType::Connection, AudioDigitalType::I06, AudioDigitalType::O08);
+#endif
+
+ //mAudioDigitalControl->SetAfeEnable(true);
+
+ //Note: MOD_PCM interface enable is done in OpenModemSpeechControlFlow() and ChangeDeviceForModemSpeechControlFlow()
+ //mAudioDigitalControl->SetMemIfSampleRate(AudioDigitalType::MEM_DL1, EXTMD_BTSCO_AFE_SAMPLERATE);
+ //mAudioDigitalControl->SetMemIfChannelCount(AudioDigitalType::MEM_DL1, 2);
+ //mAudioDigitalControl->SetMemIfEnable(AudioDigitalType::MEM_DL1, true);
+ }
+ ALOGVV("ExtMD_btsco_cvsd_UL_Write_main(-)");
+}
+
+void AudioBTCVSDControl::AudioExtMDCVSDThread::ExtMD_btsco_cvsd_DL_Read_main(void) {
+ uint8_t rtmpbuf[BTSCO_CVSD_TX_OUTBUF_SIZE * 2];
+ uint32_t FreeSpace, readsize;
+ uint8_t trycount = 0;
+ int32_t Read_Size;
+
+ ALOGVV("ExtMD_btsco_cvsd_DL_Read_main(+)");
+
+ if (mAFEDLStarting == false) {
+ ALOGD("ExtMD_btsco_cvsd_DL_Read_main mAFEDLStarting = false");
+ mAFEDLStarting = true;
+
+ //mAudioDigitalControl->SetMemIfSampleRate(AudioDigitalType::MEM_MOD_DAI, EXTMD_BTSCO_AFE_SAMPLERATE);
+ //mAudioDigitalControl->SetMemIfChannelCount(AudioDigitalType::MEM_MOD_DAI, 1);
+ //mAudioDigitalControl->SetMemIfEnable(AudioDigitalType::MEM_MOD_DAI, true);
+
+ // set irq enable , need handle with irq2 mcu mode.
+ //AudioIrqMcuMode IrqStatus;
+ //mAudioDigitalControl->GetIrqStatus(AudioDigitalType::IRQ2_MCU_MODE, &IrqStatus);
+ //if (IrqStatus.mStatus == false)
+ {
+ ALOGD("SetIrqMcuSampleRate mSampleRate = %d", EXTMD_BTSCO_AFE_SAMPLERATE);
+ //mAudioDigitalControl->SetIrqMcuSampleRate(AudioDigitalType::IRQ2_MCU_MODE, EXTMD_BTSCO_AFE_SAMPLERATE);
+ //mAudioDigitalControl->SetIrqMcuCounter(AudioDigitalType::IRQ2_MCU_MODE, BTSCO_CVSD_TX_OUTBUF_SIZE); // 480 samples, 60ms
+ //mAudioDigitalControl->SetIrqMcuEnable(AudioDigitalType::IRQ2_MCU_MODE, true);
+ }
+ //else
+ {
+ ALOGD("IRQ2_MCU_MODE is enabled , use original irq2 interrupt mode");
+ }
+
+ //mAudioDigitalControl->SetMemIfFetchFormatPerSample(AudioDigitalType::MEM_MOD_DAI, AudioMEMIFAttribute::AFE_WLEN_16_BIT);
+ //mAudioDigitalControl->SetoutputConnectionFormat(AudioDigitalType::OUTPUT_DATA_FORMAT_16BIT, AudioDigitalType::O12);
+
+ // set interconnection
+#ifdef EXTMD_LOOPBACK_TEST
+ //mAudioDigitalControl->EnableSideToneHw(AudioDigitalType::O12 , false, true);
+#else
+ //mAudioDigitalControl->SetinputConnection(AudioDigitalType::Connection, AudioDigitalType::I09, AudioDigitalType::O12);
+#endif
+
+ //mAudioDigitalControl->SetAfeEnable(true);
+
+ }
+
+ //if (mBTSCOCVSDContext->fIsWideBand == true)
+ if (0) {
+ readsize = BTSCO_CVSD_TX_OUTBUF_SIZE * 2 * 2;
+ } else {
+ readsize = BTSCO_CVSD_TX_OUTBUF_SIZE * 2;
+ }
+
+ Read_Size = ::read(mFd, rtmpbuf, readsize);
+ ALOGVV("ExtMD_btsco_cvsd_DL_Read_main ::read() done Read_Size=%d", Read_Size);
+ //ASSERT(Read_Size==sizeof(rtmpbuf));
+
+ if (Read_Size <= 0) {
+ ALOGW("ExtMD_btsco_cvsd_DL_Read_main Read_Size=%d!!!", Read_Size);
+ usleep(15 * 1000);
+ return;
+ }
+
+ do {
+ mAudioBTCVSDControl->BT_SCO_ExtMDDLBufLock();
+ FreeSpace = mAudioBTCVSDControl->BT_SCO_ExtMDGetBufSpace(ExtMD_BTSCO_DL);
+ ALOGVV("ExtMD_btsco_cvsd_DL_Read_main FreeSpace=%d", FreeSpace);
+ if (FreeSpace >= (uint32_t)Read_Size) {
+ mAudioBTCVSDControl->BT_SCO_ExtMDWriteDataToRingBuf(rtmpbuf, Read_Size, ExtMD_BTSCO_DL);
+ mAudioBTCVSDControl->BT_SCO_ExtMDDLBufUnLock();
+ WritePcmDumpData(rtmpbuf, Read_Size);
+ break;
+ } else {
+ ALOGVV("ExtMD_btsco_cvsd_DL_Read_main FreeSpace=%d < %d,", FreeSpace, Read_Size);
+ mAudioBTCVSDControl->BT_SCO_ExtMDDLBufUnLock();
+ usleep(10 * 1000);
+ }
+ trycount++;
+ } while (trycount < 10);
+
+ if (trycount == 10) {
+ ALOGW("AudioExtMDCVSDThread::ExtMD_btsco_cvsd_DL_Read_main() BT_SCO_ExtMDWriteDataToRingBuf(DL) Timeout!!!");
+ }
+
+ ALOGVV("ExtMD_btsco_cvsd_DL_Read_main(-)");
+}
+
+void AudioBTCVSDControl::AudioExtMDCVSDThread::ExtMD_btsco_cvsd_DL_Write_main(void) {
+
+ uint32_t DataCount, trycount = 0;
+ ssize_t WrittenBytes = 0, bytes;
+ size_t outputSize = 0;
+ uint8_t *outbuffer, *inbuf, *workbuf, i;
+ uint32_t insize, outsize, workbufsize, total_outsize, src_fs_s, readsize;
+
+ uint8_t wtmpbuf[BTSCO_CVSD_TX_OUTBUF_SIZE * 2];
+
+ ALOGD("ExtMD_btsco_cvsd_DL_Write_main(+)");
+
+ //if (mBTSCOCVSDContext->fIsWideBand == true)
+ if (0) {
+ readsize = BTSCO_CVSD_TX_OUTBUF_SIZE * 2 * 2;
+ } else {
+ readsize = BTSCO_CVSD_TX_OUTBUF_SIZE * 2;
+ }
+
+ do {
+ mAudioBTCVSDControl->BT_SCO_ExtMDDLBufLock();
+ DataCount = mAudioBTCVSDControl->BT_SCO_ExtMDGetBufCount(ExtMD_BTSCO_DL);
+ ALOGVV("ExtMD_btsco_cvsd_DL_Write_main DataCount=%d", DataCount);
+ if (DataCount >= readsize) {
+ mAudioBTCVSDControl->BT_SCO_ExtMDReadDataFromRingBuf(wtmpbuf, readsize, ExtMD_BTSCO_DL); //use temp buf to avoid blocking Lock
+ mAudioBTCVSDControl->BT_SCO_ExtMDDLBufUnLock();
+ break;
+ } else {
+ ALOGVV("ExtMD_btsco_cvsd_DL_Write_main DataCount=%d < %d,", DataCount, readsize);
+ mAudioBTCVSDControl->BT_SCO_ExtMDDLBufUnLock();
+ usleep(10 * 1000);
+ }
+ trycount++;
+ } while (trycount < 10);
+
+ if (trycount == 10) {
+ ALOGW("AudioExtMDCVSDThread::ExtMD_btsco_cvsd_DL_Write_main() BT_SCO_ExtMDReadDataFromRingBuf(DL) Timeout!!!");
+ return;
+ }
+
+ inbuf = (uint8_t *)wtmpbuf;
+ bytes = readsize;
+
+ WritePcmDumpData(wtmpbuf, bytes);
+
+ do {
+ outbuffer = mAudioBTCVSDControl->BT_SCO_TX_GetCVSDOutBuf();
+ outsize = SCO_TX_ENCODE_SIZE;
+ insize = bytes;
+ workbuf = mAudioBTCVSDControl->BT_SCO_TX_GetCVSDWorkBuf();
+ workbufsize = SCO_TX_PCM64K_BUF_SIZE;
+ src_fs_s = EXTMD_BTSCO_AFE_SAMPLERATE;//source sample rate for SRC
+ total_outsize = 0;
+ i = 0;
+ do {
+ if (mBTSCOCVSDContext->fIsWideBand == true) {
+ mAudioBTCVSDControl->btsco_process_TX_MSBC(inbuf, &insize, outbuffer, &outsize, workbuf); //return insize is consumed size
+ ALOGVV("btsco_process_TX_MSBC, do mSBC encode outsize=%d, consumed size=%d, bytes=%d", outsize, insize, bytes);
+ } else {
+ mAudioBTCVSDControl->btsco_process_TX_CVSD(inbuf, &insize, outbuffer, &outsize, workbuf, workbufsize); //return insize is consumed size
+ ALOGVV("btsco_process_TX_CVSD outsize=%d, consumed size=%d, bytes=%d", outsize, insize, bytes);
+ }
+ outbuffer += outsize;
+ inbuf += insize;
+ bytes -= insize;
+ insize = bytes;
+ ASSERT(bytes >= 0);
+ total_outsize += outsize;
+ i++;
+ } while ((total_outsize < BTSCO_CVSD_TX_OUTBUF_SIZE) && (outsize != 0));
+
+ ALOGD("ExtMD_btsco_cvsd_DL_Write_main write to kernel(+) total_outsize=%d", total_outsize);
+ WrittenBytes =::write(mFd2, mAudioBTCVSDControl->BT_SCO_TX_GetCVSDOutBuf(), total_outsize); //total_outsize should be BTSCO_CVSD_TX_OUTBUF_SIZE!!!
+ ALOGD("ExtMD_btsco_cvsd_DL_Write_main write to kernel(-) remaining bytes=%zd", bytes);
+ } while (bytes > 0);
+
+ ALOGD("ExtMD_btsco_cvsd_DL_Write_main(-)");
+
+}
+
+bool AudioBTCVSDControl::AudioExtMDCVSDThread::threadLoop() {
+ uint32_t Read_Size = 0;
+ while (!(exitPending() == true)) {
+ ALOGD("threadLoop mThreadType=%d", mThreadType);
+ if (mThreadType == ExtMD_BTSCO_UL_READTHREAD) {
+ //usleep(200*1000); //wait BT CVSD IRQ enable
+ ExtMD_btsco_cvsd_UL_Read_main();
+ return true;
+ } else if (mThreadType == ExtMD_BTSCO_UL_WRITETHREAD) {
+ ExtMD_btsco_cvsd_UL_Write_main();
+ return true;
+ } else if (mThreadType == ExtMD_BTSCO_DL_READTHREAD) {
+ ExtMD_btsco_cvsd_DL_Read_main();
+ return true;
+ } else if (mThreadType == ExtMD_BTSCO_DL_WRITETHREAD) {
+ ExtMD_btsco_cvsd_DL_Write_main();
+ return true;
+ }
+ }
+ ALOGD("threadLoop exit mThreadType=%d", mThreadType);
+ return false;
+}
+#endif
+
+void AudioBTCVSDControl::BTCVSD_Init(int mFd2, uint32_t mSourceSampleRate, uint32_t mSourceChannels) {
+ mAudioBTCVSDControl = AudioBTCVSDControl::getInstance();
+ if (!mAudioBTCVSDControl) {
+ ALOGE("BTCVSD_Init getInstance() fail");
+ }
+
+ mAudioBTCVSDControl->BT_SCO_TX_Begin(mFd2, mSourceSampleRate, mSourceChannels);
+
+#if 1 // TODO(Harvey): BT Loopback
+ if (AudioALSALoopbackController::getInstance()->IsAPBTLoopbackWithCodec() == true) {
+ ALOGD("****************BTCVSD loopbacktest create AudioBTCVSDLoopbackRxThread************** \n");
+ mBTCVSDRxTestThread = new AudioBTCVSDLoopbackRxThread(3, NULL, 0);
+ if (mBTCVSDRxTestThread.get()) {
+ mBTCVSDRxTestThread->run("mBTCVSDRxTestThread");
+ }
+ }
+#endif
+
+#if defined(BTCVSD_KERNEL_LOOPBACK) // create MTKRecordthread for test BTCVSD RX
+ ALOGD("****************BTCVSD TEST create AudioBTCVSDLoopbackRxThread************** \n");
+ mBTCVSDRxTestThread = new AudioBTCVSDLoopbackRxThread(3, NULL, 0);
+ if (mBTCVSDRxTestThread.get()) {
+ mBTCVSDRxTestThread->run("mBTCVSDRxTestThread");
+ }
+#elif defined(BTCVSD_ENC_DEC_LOOPBACK)
+ ALOGD("write()===BTCVSD_ENC_DEC_LOOPBACK=== START");
+ mAudioBTCVSDControl->BT_SCO_RX_Begin(mFd2);
+ mCVSDloopbackPCMDumpFile = NULL;
+ mCVSDloopbackPCMDumpFile = AudioOpendumpPCMFile("/data/vendor/audiohal/audio_dump/cvsdloopback.pcm", "vendor.cvsdloopback.pcm.dump");
+#endif
+}
+
+void AudioBTCVSDControl::BTCVSD_StandbyProcess(int mFd2) {
+ mAudioBTCVSDControl->BT_SCO_TX_End(mFd2);
+
+#if 1 // TODO(Harvey): BT Loopback
+ if (AudioALSALoopbackController::getInstance()->IsAPBTLoopbackWithCodec() == true) {
+ int ret = 0;
+ if (mBTCVSDRxTestThread.get()) {
+ //ret = mBTCVSDRxTestThread->requestExitAndWait();
+ //if (ret == WOULD_BLOCK) {
+ mBTCVSDRxTestThread->requestExit();
+ //}
+ mBTCVSDRxTestThread.clear();
+ }
+ }
+#endif
+
+#if defined(BTCVSD_KERNEL_LOOPBACK) // close AudioBTCVSDControl::AudioBTCVSDLoopbackRxThread
+ int ret = 0;
+ if (mBTCVSDRxTestThread.get()) {
+ ret = mBTCVSDRxTestThread->requestExitAndWait();
+ if (ret == WOULD_BLOCK) {
+ mBTCVSDRxTestThread->requestExit();
+ }
+ mBTCVSDRxTestThread.clear();
+ }
+ if (mCVSDloopbackPCMDumpFile) {
+ AudioCloseDumpPCMFile(mCVSDloopbackPCMDumpFile);
+ ALOGD("ClosePcmDumpFile mCVSDloopbackPCMDumpFile");
+ }
+#elif defined(BTCVSD_ENC_DEC_LOOPBACK)
+ ALOGD("standby()===BTCVSD_ENC_DEC_LOOPBACK=== STOP");
+ mAudioBTCVSDControl->BT_SCO_RX_End(mFd2);
+
+ if (mCVSDloopbackPCMDumpFile) {
+ AudioCloseDumpPCMFile(mCVSDloopbackPCMDumpFile);
+ ALOGD("ClosePcmDumpFile mCVSDloopbackPCMDumpFile");
+ }
+#endif
+}
+
+
+#if defined(BTCVSD_ENC_DEC_LOOPBACK)
+void AudioBTCVSDControl::BTCVSD_Test_UserSpace_TxToRx(uint32_t total_outsize) {
+ uint32_t offset, loopback_total_outsize, packetvalid, workbufsize, insize, outsize, bytes;
+ uint8_t *outbuf;
+ uint8_t *inbuf, *workbuf, i;
+
+ ALOGD("WriteDataToBTSCOHW()===BTCVSD_ENC_DEC_LOOPBACK===, total_outsize=%d", total_outsize);
+ memcpy(mAudioBTCVSDControl->BT_SCO_RX_GetCVSDInBuf(), mAudioBTCVSDControl->BT_SCO_TX_GetCVSDOutBuf(), total_outsize); //copy data directly from mBTCVSDTXOutBuf to mBTCVSDRXInBuf
+
+ outbuf = mAudioBTCVSDControl->BT_SCO_RX_GetCVSDOutBuf();
+ outsize = SCO_RX_PCM8K_BUF_SIZE;
+ workbuf = mAudioBTCVSDControl->BT_SCO_RX_GetCVSDWorkBuf();
+ workbufsize = SCO_RX_PCM64K_BUF_SIZE;
+ inbuf = mAudioBTCVSDControl->BT_SCO_RX_GetCVSDInBuf();
+ insize = SCO_RX_PLC_SIZE;
+
+ bytes = total_outsize;//BTSCO_CVSD_RX_INBUF_SIZE;
+ i = 0;
+ offset = 0;
+ loopback_total_outsize = 0;
+
+ do {
+ packetvalid = 1;
+
+ ALOGD("BTCVSD_ENC_DEC_LOOPBACK btsco_process_RX_CVSD(+) insize=%d,outsize=%d,packetvalid=%d ", insize, outsize, packetvalid);
+ mAudioBTCVSDControl->btsco_process_RX_CVSD(inbuf + offset, &insize, outbuf, &outsize, workbuf, workbufsize, packetvalid);
+ offset += SCO_RX_PLC_SIZE;
+ bytes -= insize;
+ ALOGD("BTCVSD_ENC_DEC_LOOPBACK btsco_process_RX_CVSD(-) consumed=%d,outsize=%d, bytes=%d", insize, outsize, bytes);
+ loopback_total_outsize += outsize;
+
+ if (mCVSDloopbackPCMDumpFile) {
+ fwrite((void *)outbuf, 1, outsize, mCVSDloopbackPCMDumpFile);
+ }
+
+ outsize = SCO_RX_PCM8K_BUF_SIZE;
+ insize = SCO_RX_PLC_SIZE;
+ i++;
+ } while (bytes > 0);
+
+ ALOGD("BTCVSD_ENC_DEC_LOOPBACK input=%d, remaining=%d,loopback_total_outsize=%d", total_outsize, bytes, loopback_total_outsize);
+
+}
+#endif
+
+AudioBTCVSDControl::AudioBTCVSDLoopbackRxThread::AudioBTCVSDLoopbackRxThread(uint32_t Mem_type, char *RingBuffer, uint32_t BufferSize) :
+ mFd(-1),
+ mFd2(-1),
+ mMemType(Mem_type),
+ tempdata(0),
+ mRecordDropms(0),
+ mBTCVSDLoopbackDumpFile(NULL),
+ mAudioBTCVSDControl(AudioBTCVSDControl::getInstance()) {
+ ALOGD("BT_SW_CVSD CODEC LOOPBACK record thread: AudioBTCVSDLoopbackRxThread(+) constructor Mem_type = %d", Mem_type);
+
+ memset(&mConfig_LoopbackRx, 0, sizeof(mConfig_LoopbackRx));
+
+ if (!mAudioBTCVSDControl) {
+ ALOGE("BT_SW_CVSD CODEC LOOPBACK record thread: AudioBTCVSDControl::getInstance() fail");
+ }
+#if 1 // TODO(Harvey): BT Loopback
+ if (mMemType == 3) {
+#ifndef MTK_SUPPORT_BTCVSD_ALSA
+ mFd2 = mAudioBTCVSDControl->getFd();
+ if (mFd2 <= 0) {
+ ALOGW("BT_SW_CVSD CODEC LOOPBACK record thread: open fail");
+ }
+#endif
+ }
+
+ switch (mMemType) {
+ case 3:
+ mName = String8("AudioBTCVSDLoopbackRxThreadDAI");
+ mBTCVSDLoopbackDumpFile = AudioOpendumpPCMFile("/data/vendor/audiohal/audio_dump/CVSDloopbackOut.pcm", "vendor.CVSDloopbackOut.pcm.dump");
+#ifdef MTK_SUPPORT_BTCVSD_ALSA
+ mConfig_LoopbackRx.channels = AUDIO_CHANNEL_OUT_MONO;
+ if (WCNChipController::GetInstance()->BTChipSamplingRate() == 0) {
+ mConfig_LoopbackRx.rate = 8000;
+ } else {
+ mConfig_LoopbackRx.rate = 16000;
+ }
+ mConfig_LoopbackRx.period_size = 1024;
+ mConfig_LoopbackRx.period_count = 2;
+ mConfig_LoopbackRx.format = PCM_FORMAT_S16_LE;
+ mConfig_LoopbackRx.start_threshold = 0;
+ mConfig_LoopbackRx.stop_threshold = 0;
+ mConfig_LoopbackRx.silence_threshold = 0;
+
+ ASSERT(mPcm_LoopbackRx == NULL);
+ mPcm_LoopbackRx = pcm_open(AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmBTCVSDCapture),
+ AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmBTCVSDCapture),
+ PCM_IN, &mConfig_LoopbackRx);
+ ASSERT(mPcm_LoopbackRx != NULL && pcm_is_ready(mPcm_LoopbackRx) == true);
+ mAudioBTCVSDControl->BT_SCO_RX_Begin(mFd2);
+ pcm_start(mPcm_LoopbackRx);
+#else
+ mAudioBTCVSDControl->BT_SCO_RX_Begin(mFd2);
+#endif
+ break;
+ default:
+ ALOGD("BT_SW_CVSD CODEC LOOPBACK record thread: NO support for memory interface");
+ break;
+ }
+#endif
+ // ring buffer to copy data into this ring buffer
+ mRingBuffer = RingBuffer;
+ mBufferSize = BufferSize;
+ ALOGD("BT_SW_CVSD CODEC LOOPBACK record thread: AudioBTCVSDLoopbackRxThread(-)");
+}
+
+AudioBTCVSDControl::AudioBTCVSDLoopbackRxThread::~AudioBTCVSDLoopbackRxThread() {
+ ALOGD("BT_SW_CVSD CODEC LOOPBACK record thread: ~AudioBTCVSDLoopbackRxThread(+)");
+ ClosePcmDumpFile();
+
+#if 1 // TODO(Harvey): BT Loopback
+ if (mMemType == 3) {
+ mAudioBTCVSDControl->BT_SCO_RX_End(mFd2);
+#ifdef MTK_SUPPORT_BTCVSD_ALSA
+ pcm_stop(mPcm_LoopbackRx);
+ pcm_close(mPcm_LoopbackRx);
+ mPcm_LoopbackRx = NULL;
+#else
+ if (mFd2 > 0) {
+ ::close(mFd2);
+ mFd2 = 0;
+ }
+#endif
+ }
+#endif
+ ALOGD("BT_SW_CVSD CODEC LOOPBACK record thread: ~AudioBTCVSDLoopbackRxThread(-)");
+}
+
+void AudioBTCVSDControl::AudioBTCVSDLoopbackRxThread::onFirstRef() {
+ ALOGD("BT_SW_CVSD CODEC LOOPBACK record thread: onFirstRef");
+ tempdata = 0;
+ mRecordDropms = 0;
+
+ run(mName, ANDROID_PRIORITY_URGENT_AUDIO);
+}
+
+// Good place to do one-time initializations
+status_t AudioBTCVSDControl::AudioBTCVSDLoopbackRxThread::readyToRun() {
+ ALOGD("BT_SW_CVSD CODEC LOOPBACK record thread: readyToRun");
+ return NO_ERROR;
+}
+
+void AudioBTCVSDControl::AudioBTCVSDLoopbackRxThread::WritePcmDumpData(void *outbuf, uint32_t outsize) {
+ int written_data = 0;
+#if 1 // TODO(Harvey): BT Loopback
+ switch (mMemType) {
+ case 3:
+ if (mBTCVSDLoopbackDumpFile) {
+ written_data = fwrite((void *)outbuf, 1, outsize, mBTCVSDLoopbackDumpFile);
+ }
+ break;
+ }
+#endif
+}
+
+void AudioBTCVSDControl::AudioBTCVSDLoopbackRxThread::ClosePcmDumpFile() {
+ ALOGD("BT_SW_CVSD Test ClosePcmDumpFile");
+
+#if 1 // TODO(Harvey): BT Loopback
+ switch (mMemType) {
+ case 3:
+ if (mBTCVSDLoopbackDumpFile) {
+ AudioCloseDumpPCMFile(mBTCVSDLoopbackDumpFile);
+ ALOGD("ClosePcmDumpFile mBTCVSDLoopbackDumpFile");
+ }
+ break;
+ }
+#endif
+}
+
+void AudioBTCVSDControl::AudioBTCVSDLoopbackRxThread::btsco_cvsd_RX_main(void) {
+ uint8_t packetvalid, *outbuf, *workbuf, *tempbuf, *inbuf;
+ uint32_t i, Read_Size, outsize, workbufsize, insize, bytes, offset, dump_size;
+ ALOGD("BT_SW_CVSD CODEC LOOPBACK record thread: btsco_cvsd_RX_main(+)");
+#ifdef MTK_SUPPORT_BTCVSD_ALSA
+ ASSERT(mPcm_LoopbackRx != NULL);
+ uint8_t *cvsd_raw_data = mAudioBTCVSDControl->BT_SCO_RX_GetCVSDTempInBuf();
+ int retval = pcm_read(mPcm_LoopbackRx, cvsd_raw_data, BTSCO_CVSD_RX_TEMPINPUTBUF_SIZE);
+ if (retval != 0) {
+ ALOGE("%s(), pcm_read() error, retval = %d", __FUNCTION__, retval);
+ }
+#else
+ Read_Size = ::read(mFd2, mAudioBTCVSDControl->BT_SCO_RX_GetCVSDTempInBuf(), BTSCO_CVSD_RX_TEMPINPUTBUF_SIZE);
+#endif
+
+ outbuf = mAudioBTCVSDControl->BT_SCO_RX_GetCVSDOutBuf();
+ outsize = SCO_RX_PCM8K_BUF_SIZE;
+ workbuf = mAudioBTCVSDControl->BT_SCO_RX_GetCVSDWorkBuf();
+ workbufsize = SCO_RX_PCM64K_BUF_SIZE;
+ tempbuf = mAudioBTCVSDControl->BT_SCO_RX_GetCVSDTempInBuf();
+ inbuf = mAudioBTCVSDControl->BT_SCO_RX_GetCVSDInBuf();
+ insize = SCO_RX_PLC_SIZE;
+ bytes = BTSCO_CVSD_RX_INBUF_SIZE;
+ i = 0;
+ offset = 0;
+ dump_size = 0;
+ do {
+ packetvalid = *((char *)tempbuf + SCO_RX_PLC_SIZE + offset + i * BTSCO_CVSD_PACKET_VALID_SIZE); //parser packet valid info for each 30-byte packet
+ //packetvalid = 1; //force packvalid to 1 for test
+ memcpy(inbuf + offset, tempbuf + offset + i * BTSCO_CVSD_PACKET_VALID_SIZE, SCO_RX_PLC_SIZE);
+
+ ALOGVV("btsco_process_RX_CVSD(+) insize=%d,outsize=%d,packetvalid=%d ", insize, outsize, packetvalid);
+ mAudioBTCVSDControl->btsco_process_RX_CVSD(inbuf + offset, &insize, outbuf, &outsize, workbuf, workbufsize, packetvalid);
+ offset += SCO_RX_PLC_SIZE;
+ bytes -= insize;
+ ALOGVV("btsco_process_RX_CVSD(-) consumed=%d,outsize=%d, bytes=%d", insize, outsize, bytes);
+ //#if !defined(BTCVSD_LOOPBACK_WITH_CODEC)
+
+ //#ifdef BTCVSD_TEST_HW_ONLY
+ WritePcmDumpData(outbuf, outsize);
+ //#endif
+
+ uint8_t *pWriteBuffer;
+ uint32_t uWriteByte;
+ uint32_t uTotalWriteByte;
+ CVSDLoopbackGetWriteBuffer(&pWriteBuffer, &uWriteByte);
+ if (uWriteByte) {
+ uint32_t uCopyByte = 0;
+ if (uWriteByte >= outsize) {
+ memcpy(pWriteBuffer, outbuf, outsize);
+ uCopyByte += outsize;
+ CVSDLoopbackWriteDataDone(outsize);
+ } else {
+ memcpy(pWriteBuffer, outbuf, uWriteByte);
+ uCopyByte += uWriteByte;
+ CVSDLoopbackWriteDataDone(uWriteByte);
+ CVSDLoopbackGetWriteBuffer(&pWriteBuffer, &uWriteByte);
+ if (uWriteByte == 0) {
+ ALOGD("BT_SW_CVSD CODEC LOOPBACK record thread: btsco_cvsd_RX_main underflow: uWriteByte: %d, datalen:%d", uWriteByte, outsize - uCopyByte);
+ } else if (outsize - uCopyByte >= uWriteByte) {
+ //overflow
+ memcpy(pWriteBuffer, outbuf + uCopyByte, uWriteByte);
+ uCopyByte += uWriteByte;
+ CVSDLoopbackWriteDataDone(uWriteByte);
+ } else {
+ memcpy(pWriteBuffer, outbuf + uCopyByte, outsize - uCopyByte);
+ uCopyByte += outsize - uCopyByte;
+ CVSDLoopbackWriteDataDone(outsize - uCopyByte);
+ }
+ }
+ }
+
+ outsize = SCO_RX_PCM8K_BUF_SIZE;
+ insize = SCO_RX_PLC_SIZE;
+ i++;
+ } while (bytes > 0);
+
+ ALOGD("BT_SW_CVSD CODEC LOOPBACK record thread: btsco_cvsd_RX_main(-)");
+}
+
+bool AudioBTCVSDControl::AudioBTCVSDLoopbackRxThread::threadLoop() {
+ uint32_t Read_Size = 0;
+ ALOGD("BT_SW_CVSD CODEC LOOPBACK RX thread: threadLoop(+)");
+
+#if 1 // TODO(Harvey): BT Loopback
+ while (!(exitPending() == true)) {
+ if (mMemType == 3) {
+ btsco_cvsd_RX_main();
+ // return true;
+ }
+ }
+ ALOGD("BT_SW_CVSD CODEC LOOPBACK RX thread: threadLoop(-), threadLoop exit");
+#endif
+ return false;
+}
+
+}
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioBitTrueTest.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioBitTrueTest.cpp
new file mode 100644
index 0000000..584eae1
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioBitTrueTest.cpp
@@ -0,0 +1,549 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioBitTrueTest.h"
+#include "AudioALSADriverUtility.h"
+#include "AudioALSADeviceParser.h"
+#include "AudioALSAHardwareResourceManager.h"
+#include "AudioALSADeviceConfigManager.h"
+
+#include <hardware_legacy/power.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioBitTrueTest"
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
+#define TEST_DUMP_FILE_PREFIX "/sdcard/mtklog/audio_dump/bit_true"
+
+#define PLAY_MS_PER_WRITE 5
+#define VERIFY_MS_PER_READ 20
+#define VERIFY_TIME_MS 3000
+
+const unsigned int sgenTable16Bit[] =
+{
+ 0x0FE50FE5, 0x285E1C44, 0x3F4A285E, 0x53C73414,
+ 0x650C3F4A, 0x726F49E3, 0x7B6C53C7, 0x7FAB5CDC,
+ 0x7F02650C, 0x79776C43, 0x6F42726F, 0x60C67781,
+ 0x4E917B6C, 0x39587E27, 0x21EB7FAB, 0x09307FF4,
+ 0xF01A7F02, 0xD7A17CD6, 0xC0B67977, 0xAC3874ED,
+ 0x9AF36F42, 0x8D906884, 0x849360C6, 0x80545818,
+ 0x80FD4E91, 0x86884449, 0x90BD3958, 0x9F3A2DDA,
+ 0xB16E21EB, 0xC6A715A8, 0xDE140930, 0xF6CFFCA1,
+ 0x0FE5F01A, 0x285EE3BB, 0x3F4AD7A1, 0x53C7CBEB,
+ 0x650CC0B6, 0x726FB61C, 0x7B6CAC38, 0x7FABA323,
+ 0x7F029AF3, 0x797793BC, 0x6F428D90, 0x60C6887E,
+ 0x4E918493, 0x395881D8, 0x21EB8054, 0x0930800B,
+ 0xF01A80FD, 0xD7A18329, 0xC0B68688, 0xAC388B12,
+ 0x9AF390BD, 0x8D90977B, 0x84939F3A, 0x8054A7E7,
+ 0x80FDB16E, 0x8688BBB6, 0x90BDC6A7, 0x9F3AD225,
+ 0xB16EDE14, 0xC6A7EA57, 0xDE14F6CF, 0xF6CF035E
+};
+
+// from dvt check_bit_true_half_way_in
+static bool checkBitTrue(char *inData, size_t dataSize, const unsigned int *goldenTable, size_t goldenElementCount) {
+ bool ret = false;
+ bool flagStart = false;
+
+ unsigned int reviceVal;
+
+ unsigned int idxTable = 0;
+
+ unsigned int *data = (unsigned int *)inData;
+ unsigned int maxDataIdx = dataSize / sizeof(unsigned int);
+
+ for (size_t i = 0; i < maxDataIdx; i++) {
+ reviceVal = data[i];
+
+ if (!flagStart) {
+ if (reviceVal == 0) {
+ continue;
+ } else {
+ flagStart = true;
+ // Find the corresponding table idx for first data
+ for (size_t j = 0; j < goldenElementCount; j++) {
+ if (reviceVal == goldenTable[j]) {
+ idxTable = j;
+ //ALOGD("%s(), start idxTable %d", __FUNCTION__, idxTable);
+ break;
+ }
+ }
+ }
+ }
+
+ if (reviceVal != goldenTable[idxTable++]) {
+ if (reviceVal == 0) { // all zerio
+ for (; i < maxDataIdx; i++) {
+ reviceVal = data[i];
+
+ if (reviceVal != 0) {
+ ALOGW("i %zu, revice_val %x != 0\n", i, reviceVal);
+ return false;
+ }
+ }
+
+ return ret;
+ } else {
+ ALOGW("i %zu, revice_val %x != golden %x\n", i, reviceVal, goldenTable[idxTable - 1]);
+ ret = false;
+ return ret;
+ }
+ }
+ else {
+ ret = true;
+ }
+
+ if (idxTable == goldenElementCount) {
+ idxTable = 0;
+ }
+ }
+
+ if (!flagStart) {
+ ALOGW("[check_bit_true] PANIC, It's all zero in here....");
+ }
+
+ return ret;
+}
+
+namespace android {
+AudioBitTrueTest *AudioBitTrueTest::mAudioBitTrueTest = NULL;
+AudioBitTrueTest *AudioBitTrueTest::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioBitTrueTest == NULL) {
+ mAudioBitTrueTest = new AudioBitTrueTest();
+ }
+ ASSERT(mAudioBitTrueTest != NULL);
+ return mAudioBitTrueTest;
+}
+
+AudioBitTrueTest::AudioBitTrueTest() :
+ mTestState(BIT_TRUE_TEST_DISABLE),
+ mPlayReady(0),
+ mMixer(AudioALSADriverUtility::getInstance()->getMixer()),
+ mPlayThread(0),
+ mVerifyThread(0) {
+}
+
+AudioBitTrueTest::~AudioBitTrueTest() {
+
+}
+
+int AudioBitTrueTest::setTestType(int testType) {
+ AL_AUTOLOCK(mLock);
+
+ if (testType == BIT_TRUE_TEST_DISABLE) {
+ return close();
+ } else {
+ return open(testType);
+ }
+}
+
+static const char bitTrueWakeLockName[] = "BIT_TRUE_WAKELOCK_NAME";
+int AudioBitTrueTest::open(int testType) {
+ ALOGD("+%s(), testType %d", __FUNCTION__, testType);
+
+ if (mTestState != BIT_TRUE_TEST_DISABLE) {
+ ALOGW("%s(), already in mTestState %d", __FUNCTION__, mTestState);
+ return -EINVAL;
+ }
+
+ mTestState = testType;
+
+ int ret;
+
+ ret = acquire_wake_lock(PARTIAL_WAKE_LOCK, bitTrueWakeLockName);
+ if (ret) {
+ ALOGW("%s(), acquire_wake_lock fail, ret %d", __FUNCTION__, ret);
+ }
+
+ ret = pthread_create(&mPlayThread, NULL, AudioBitTrueTest::playThread, this);
+ if (ret) {
+ ALOGE("%s() create mPlayThread fail, ret = %d!!", __FUNCTION__, ret);
+ ASSERT(0);
+ }
+
+ // wait for play setup finish
+ int sleepTotal_us = 0;
+ while (!mPlayReady) {
+ usleep(500);
+ if (sleepTotal_us >= 3 * 1000 * 1000) {
+ ALOGE("%s(), timeout > 3 sec, mPlayReady %d", __FUNCTION__, mPlayReady);
+ ASSERT(0);
+ break;
+ }
+ sleepTotal_us += 500;
+ }
+
+ ret = pthread_create(&mVerifyThread, NULL, AudioBitTrueTest::verifyThread, this);
+ if (ret) {
+ ALOGE("%s() create mPlayThread fail, ret = %d!!", __FUNCTION__, ret);
+ ASSERT(0);
+ }
+
+ ALOGD("-%s()", __FUNCTION__);
+ return 0;
+}
+
+int AudioBitTrueTest::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ if (mTestState == BIT_TRUE_TEST_DISABLE) {
+ ALOGW("%s(), no test running", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ mTestState = BIT_TRUE_TEST_DISABLE;
+
+ int ret;
+ void *retval;
+
+ ret = pthread_join(mPlayThread, &retval);
+ if (ret) {
+ ALOGE("%s(), mPlayThread pthread_join fail, ret = %d", __FUNCTION__, ret);
+ ASSERT(0);
+ }
+
+ ret = pthread_join(mVerifyThread, &retval);
+ if (ret) {
+ ALOGE("%s(), mVerifyThread pthread_join fail, ret = %d", __FUNCTION__, ret);
+ ASSERT(0);
+ }
+
+ release_wake_lock(bitTrueWakeLockName);
+
+ ALOGD("-%s()", __FUNCTION__);
+ return 0;
+}
+
+int AudioBitTrueTest::getTestState() {
+ return mTestState;
+}
+
+void *AudioBitTrueTest::playThread(void *arg) {
+ AudioBitTrueTest *test = static_cast<AudioBitTrueTest *>(arg);
+ int ret;
+ int testState = test->getTestState();
+
+ ALOGD("+%s(), pid: %d, tid: %d, testState %d", __FUNCTION__, getpid(), gettid(), testState);
+#if defined(MTK_AUDIO_KS)
+ // prepare FE
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmPlayback1);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmPlayback1);
+
+ struct pcm_config pcmConfig;
+ memset(&pcmConfig, 0, sizeof(pcmConfig));
+ pcmConfig.channels = 2;
+ pcmConfig.rate = 48000;
+ pcmConfig.period_size = 1024;
+ pcmConfig.period_count = 2;
+ pcmConfig.format = PCM_FORMAT_S16_LE;
+ pcmConfig.start_threshold = 0;
+ pcmConfig.stop_threshold = 0;
+ pcmConfig.silence_threshold = 0;
+
+ // connect path
+ switch (testState) {
+ case BIT_TRUE_TEST_DL_UL:
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S3_CH1 DL1_CH1"), String8("1"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S3_CH2 DL1_CH2"), String8("1"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S3_HD_Mux"), String8("Low_Jitter"));
+ break;
+ case BIT_TRUE_TEST_4_PIN_I2S:
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S3_CH1 DL1_CH1"), String8("1"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S3_CH2 DL1_CH2"), String8("1"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S3_HD_Mux"), String8("Low_Jitter"));
+ break;
+ default:
+ break;
+ }
+
+ struct pcm *pcm = pcm_open(cardIdx, pcmIdx, PCM_OUT | PCM_MONOTONIC, &pcmConfig);
+ if (pcm == NULL) {
+ ALOGE("%s(), pcm == NULL!!", __FUNCTION__);
+ } else if (pcm_is_ready(pcm) == false) {
+ ALOGE("%s(), pcm_is_ready(%p) == false due to %s, close pcm.", __FUNCTION__, pcm, pcm_get_error(pcm));
+ pcm_close(pcm);
+ pcm = NULL;
+ } else if (pcm_prepare(pcm) != 0) {
+ ALOGE("%s(), pcm_prepare(%p) == false due to %s, close pcm.", __FUNCTION__, pcm, pcm_get_error(pcm));
+ pcm_close(pcm);
+ pcm = NULL;
+ }
+
+ // prepare data
+ size_t sizePerFrame = getSizePerFrame(audio_format_from_pcm_format(pcmConfig.format), pcmConfig.channels);
+ size_t sgenTableSize = ARRAY_SIZE(sgenTable16Bit) * sizePerFrame;
+ size_t testDataSize = ((PLAY_MS_PER_WRITE * pcmConfig.rate) / 1000) * sizePerFrame;
+ testDataSize = (testDataSize / sgenTableSize) * sgenTableSize;
+ char *testData = new char[testDataSize];
+
+ ALOGD("%s(), sgenTableSize %zu, testDataSize %zu", __FUNCTION__, sgenTableSize, testDataSize);
+
+ if (!testData) {
+ ALOGE("%s(), allocate testData failed", __FUNCTION__);
+ ASSERT(0);
+ }
+
+ for (size_t i = 0; i < testDataSize; i += sgenTableSize) {
+ memcpy(testData + i, sgenTable16Bit, sgenTableSize);
+ }
+
+ test->mPlayReady = true;
+
+ // play start
+ while (test->getTestState() != BIT_TRUE_TEST_DISABLE && pcm && testData) {
+ ret = pcm_write(pcm, testData, testDataSize);
+ if (ret) {
+ ALOGE("%s(), pcm_write() error, ret = %d", __FUNCTION__, ret);
+ }
+ }
+
+ // stop pcm
+ if (pcm != NULL) {
+ pcm_stop(pcm);
+ pcm_close(pcm);
+ pcm = NULL;
+ }
+
+ // disconnect path
+ switch (testState) {
+ case BIT_TRUE_TEST_DL_UL:
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S3_CH1 DL1_CH1"), String8("0"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S3_CH2 DL1_CH2"), String8("0"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S3_HD_Mux"), String8("Normal"));
+ break;
+ case BIT_TRUE_TEST_4_PIN_I2S:
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S3_CH1 DL1_CH1"), String8("0"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S3_CH2 DL1_CH2"), String8("0"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S3_HD_Mux"), String8("Normal"));
+ break;
+ default:
+ break;
+ }
+
+ if (testData) {
+ delete[] testData;
+ }
+#endif
+ test->mPlayReady = false;
+
+ ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ return NULL;
+}
+
+static int verifyRoutineUpdate(bool enable, int testState) {
+ if (enable) {
+ switch (testState) {
+ case BIT_TRUE_TEST_4_PIN_I2S:
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S3_CH1 DL1_CH1"), String8("1"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S3_CH2 DL1_CH2"), String8("1"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S0_Lpbk_Mux"), String8("Lpbk"));
+ break;
+ case BIT_TRUE_TEST_DL_UL:
+ default:
+ break;
+ }
+ } else {
+ switch (testState) {
+ case BIT_TRUE_TEST_4_PIN_I2S:
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S3_CH1 DL1_CH1"), String8("0"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S3_CH2 DL1_CH2"), String8("0"));
+ break;
+ case BIT_TRUE_TEST_DL_UL:
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+void *AudioBitTrueTest::verifyThread(void *arg) {
+ AudioBitTrueTest *test = static_cast<AudioBitTrueTest *>(arg);
+ int ret;
+ int testState = test->getTestState();
+
+ unsigned long long round = 0;
+
+ ALOGD("+%s(), pid: %d, tid: %d, testState %d", __FUNCTION__, getpid(), gettid(), testState);
+#if defined(MTK_AUDIO_KS)
+ // prepare FE
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmCapture2);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmCapture2);
+
+ struct pcm_config pcmConfig;
+ memset(&pcmConfig, 0, sizeof(pcmConfig));
+ pcmConfig.channels = 2;
+ pcmConfig.rate = 48000;
+ pcmConfig.format = PCM_FORMAT_S16_LE;
+ pcmConfig.period_size = 1024;
+ pcmConfig.period_count = 4;
+ pcmConfig.start_threshold = 0;
+ pcmConfig.stop_threshold = 0;
+ pcmConfig.silence_threshold = 0;
+
+ // connect path
+ switch (testState) {
+ case BIT_TRUE_TEST_DL_UL:
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("UL2_CH1 DL1_CH1"), String8("1"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("UL2_CH2 DL1_CH2"), String8("1"));
+ break;
+ case BIT_TRUE_TEST_4_PIN_I2S:
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("UL2_CH1 I2S0_CH1"), String8("1"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("UL2_CH2 I2S0_CH2"), String8("1"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S0_HD_Mux"), String8("Low_Jitter"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S0_Lpbk_Mux"), String8("Lpbk"));
+ break;
+ default:
+ break;
+ }
+
+ struct pcm *pcm = pcm_open(cardIdx, pcmIdx, PCM_IN | PCM_MONOTONIC, &pcmConfig);
+ if (pcm == NULL) {
+ ALOGE("%s(), pcm == NULL!!", __FUNCTION__);
+ } else if (pcm_is_ready(pcm) == false) {
+ ALOGE("%s(), pcm_is_ready(%p) == false due to %s, close pcm.", __FUNCTION__, pcm, pcm_get_error(pcm));
+ pcm_close(pcm);
+ pcm = NULL;
+ } else if (pcm_prepare(pcm) != 0) {
+ ALOGE("%s(), pcm_prepare(%p) == false due to %s, close pcm.", __FUNCTION__, pcm, pcm_get_error(pcm));
+ pcm_close(pcm);
+ pcm = NULL;
+ }
+
+ // prepare data
+ size_t sizePerFrame = getSizePerFrame(audio_format_from_pcm_format(pcmConfig.format), pcmConfig.channels);
+ size_t readDataSize = ((VERIFY_MS_PER_READ * pcmConfig.rate) / 1000) * sizePerFrame;
+
+ char *readData = new char[readDataSize];
+ if (!readData) {
+ ALOGE("%s(), allocate readData failed", __FUNCTION__);
+ ASSERT(0);
+ }
+
+ size_t verifyDataSize = ((VERIFY_TIME_MS * pcmConfig.rate) / 1000) * sizePerFrame;
+ verifyDataSize = (verifyDataSize / readDataSize) * readDataSize; // verifyDataSize must be multiple of readDataSize
+ char *verifyData = new char[verifyDataSize];
+ if (!verifyData) {
+ ALOGE("%s(), allocate verifyData failed", __FUNCTION__);
+ ASSERT(0);
+ }
+
+ ALOGD("%s(), readDataSize %zu, verifyDataSize %zu", __FUNCTION__, readDataSize, verifyDataSize);
+
+ // verify start
+ while (test->getTestState() != BIT_TRUE_TEST_DISABLE && pcm && readData) {
+ size_t curVerifyDataSize = 0;
+ ret = 0;
+ bool pass;
+
+ // clean data
+ memset(verifyData, 0, verifyDataSize);
+
+ // collect verify data
+ verifyRoutineUpdate(true, testState);
+ while (test->getTestState() != BIT_TRUE_TEST_DISABLE && curVerifyDataSize < verifyDataSize && ret == 0) {
+
+ ret = pcm_read(pcm, readData, readDataSize);
+ if (ret) {
+ ALOGE("%s(), echo ref pcm_read() error, ret = %d", __FUNCTION__, ret);
+ }
+
+ memcpy(verifyData + curVerifyDataSize, readData, readDataSize);
+ curVerifyDataSize += readDataSize;
+ }
+ pcm_stop(pcm);
+
+ // verify data
+ pass = checkBitTrue(verifyData, curVerifyDataSize, sgenTable16Bit, ARRAY_SIZE(sgenTable16Bit));
+
+ // dump data
+ FILE *dumpFile;
+ if (!pass) {
+ ALOGW("%s(), fail at round %llu\n", __FUNCTION__, round);
+ dumpFile = testDumpOpen("fail", streamout_propty);
+ testDumpWriteData(dumpFile, verifyData, curVerifyDataSize);
+ usleep(1 * 1000 * 1000); // wait for dump ready
+ testDumpClose(dumpFile);
+ }
+
+ verifyRoutineUpdate(false, testState);
+ round++;
+ }
+
+ // stop pcm
+ if (pcm != NULL) {
+ pcm_stop(pcm);
+ pcm_close(pcm);
+ pcm = NULL;
+ }
+
+ // disconnect path
+ switch (testState) {
+ case BIT_TRUE_TEST_DL_UL:
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("UL2_CH1 DL1_CH1"), String8("0"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("UL2_CH2 DL1_CH2"), String8("0"));
+ break;
+ case BIT_TRUE_TEST_4_PIN_I2S:
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("UL2_CH1 I2S0_CH1"), String8("0"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("UL2_CH2 I2S0_CH2"), String8("0"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S0_HD_Mux"), String8("Normal"));
+ AudioALSADeviceConfigManager::getInstance()->setMixerCtl(String8("I2S0_Lpbk_Mux"), String8("Normal"));
+ break;
+ default:
+ break;
+ }
+
+ if (readData) {
+ delete[] readData;
+ }
+
+ if (verifyData) {
+ delete[] verifyData;
+ }
+#endif
+ ALOGD("-%s(), pid: %d, tid: %d, round %llu", __FUNCTION__, getpid(), gettid(), round);
+ return NULL;
+}
+
+// dump file
+FILE *AudioBitTrueTest::testDumpOpen(const char *name, const char *property) {
+ static unsigned int dumpFileCount = 0;
+
+ ALOGV("%s()", __FUNCTION__);
+ FILE *file = NULL;
+ char dumpFileName[128];
+ sprintf(dumpFileName, "%s.%s.%u.pid%d.tid%d.pcm", TEST_DUMP_FILE_PREFIX, name, dumpFileCount, getpid(), gettid());
+
+ file = NULL;
+ file = AudioOpendumpPCMFile(dumpFileName, property);
+
+ if (file != NULL) {
+ ALOGD("%s DumpFileName = %s", __FUNCTION__, dumpFileName);
+
+ dumpFileCount++;
+ dumpFileCount %= MAX_DUMP_NUM;
+ }
+
+ return file;
+}
+
+void AudioBitTrueTest::testDumpClose(FILE *file) {
+ ALOGV("%s()", __FUNCTION__);
+ if (file) {
+ AudioCloseDumpPCMFile(file);
+ ALOGD("%s(), close it", __FUNCTION__);
+ }
+}
+
+void AudioBitTrueTest::testDumpWriteData(FILE *file, const void *buffer, size_t bytes) {
+ if (file) {
+ AudioDumpPCMData((void *)buffer, bytes, file);
+ }
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioExternWrapper.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioExternWrapper.cpp
new file mode 100644
index 0000000..be7a443
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioExternWrapper.cpp
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioExternWrapper.h"
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+#include "AudioALSACaptureDataClientAurisysNormal.h"
+#else
+#include "AudioALSACaptureDataClient.h"
+#endif
+
+namespace android {
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+extern "C" IAudioALSACaptureDataClient *createMTKAudioDataClient(AudioALSACaptureDataProviderBase *pCaptureDataProvider, stream_attribute_t *stream_attribute_target, AudioALSACaptureDataProviderBase *pCaptureDataProviderEchoRef) {
+ IAudioALSACaptureDataClient *pCaptureDataClient = NULL;
+ pCaptureDataClient = new AudioALSACaptureDataClientAurisysNormal(pCaptureDataProvider, stream_attribute_target, pCaptureDataProviderEchoRef);
+ return pCaptureDataClient;
+}
+#else
+extern "C" IAudioALSACaptureDataClient *createMTKAudioDataClient(AudioALSACaptureDataProviderBase *pCaptureDataProvider, stream_attribute_t *stream_attribute_target) {
+ IAudioALSACaptureDataClient *pCaptureDataClient = NULL;
+ pCaptureDataClient = new AudioALSACaptureDataClient(pCaptureDataProvider, stream_attribute_target);
+ return pCaptureDataClient;
+}
+#endif
+
+extern "C" AudioALSACaptureDataProviderUsb *createMTKAudioUSBProvider() {
+ return AudioALSACaptureDataProviderUsb::getInstance();
+}
+
+extern "C" AudioALSACaptureDataProviderEchoRefUsb *createMTKAudioUSBProviderEchoRef() {
+ return AudioALSACaptureDataProviderEchoRefUsb::getInstance();
+}
+
+extern "C" AudioALSAPlaybackHandlerUsb *createMTKAudioUSBPlaybackHandler(stream_attribute_t *stream_attribute_source) {
+ AudioALSAPlaybackHandlerUsb *mAudioALSAPlaybackHandlerUsb = new AudioALSAPlaybackHandlerUsb(stream_attribute_source);
+ return mAudioALSAPlaybackHandlerUsb;
+
+}
+
+}
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioGainTableParamParser.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioGainTableParamParser.cpp
new file mode 100644
index 0000000..bef0cf9
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioGainTableParamParser.cpp
@@ -0,0 +1,1614 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioGainTableParamParser.h"
+
+#include <utils/Log.h>
+#include "AudioUtility.h"//Mutex/assert
+#include <system/audio.h>
+
+#include <string>
+#include "AudioSmartPaController.h"
+#include "AudioALSAHardwareResourceManager.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "GainTableParamParser"
+
+#ifdef ALOGG
+#undef ALOGG
+#endif
+#ifdef CONFIG_MT_ENG_BUILD
+#define ALOGG(...) ALOGD(__VA_ARGS__)
+#else
+#define ALOGG(...)
+#endif
+
+namespace android {
+
+// Stream Type
+const std::string gppStreamTypeXmlName[GAIN_STREAM_TYPE_SIZE] = {"Voice",
+ "System",
+ "Ring",
+ "Music",
+ "Alarm",
+ "Notification",
+ "Bluetooth_sco",
+ "Enforced_Audible",
+ "DTMF",
+ "TTS",
+ "Accessibility"
+ };
+// Device
+const std::string gppDeviceXmlName[NUM_GAIN_DEVICE] = {"RCV",
+ "HS",
+ "SPK",
+ "HP",
+ "HSSPK",
+ "HS5POLE",
+ "HS5POLE_ANC",
+ "HAC",
+ "BT",
+ "TTY",
+ "LPBK_RCV",
+ "LPBK_SPK",
+ "LPBK_HP",
+ "USB",
+ "BT_A2DP",
+ "BT_A2DP_HP",
+ "BT_A2DP_SPK",
+ "RCV_SV",
+ "SPK_SV"
+ };
+// Speech
+const std::string gppBandXmlName[NUM_GAIN_SPEECH_BAND] = {"NB",
+ "WB",
+ "SWB"
+ };
+
+const std::string gppNetXmlName[NUM_GAIN_SPEECH_NETWORK] = {"GSM",
+ "WCDMA",
+ "VoLTE"
+ };
+
+// MIC
+const std::string gppMicModeXmlName[NUM_GAIN_MIC_MODE] = {"Sound recording",
+ "Voice Call",
+ "Camera recording",
+ "VR",
+ "VoIP",
+ "VOICE_UNLOCK",
+ "CUSTOMIZATION1",
+ "CUSTOMIZATION2",
+ "CUSTOMIZATION3",
+ "Unprocessed"
+ };
+/*==============================================================================
+ * Singleton Pattern
+ *============================================================================*/
+
+GainTableParamParser *GainTableParamParser::mGainTableParamParser = NULL;
+
+GainTableParamParser *GainTableParamParser::getInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+ ALOGG("%s()", __FUNCTION__);
+
+ if (mGainTableParamParser == NULL) {
+ ALOGD("%s()", __FUNCTION__);
+ mGainTableParamParser = new GainTableParamParser();
+ }
+ ASSERT(mGainTableParamParser != NULL);
+ return mGainTableParamParser;
+}
+/*==============================================================================
+ * Constructor / Destructor / Init / Deinit
+ *============================================================================*/
+
+GainTableParamParser::GainTableParamParser() {
+ ALOGD("%s()", __FUNCTION__);
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(appOps);
+ mAppHandle = NULL;
+ } else {
+ mAppHandle = appOps->appHandleGetInstance();
+ }
+ loadGainTableParam();
+}
+
+GainTableParamParser::~GainTableParamParser() {
+ for (unsigned int i = 0; i < NUM_GAIN_DEVICE; i++) {
+ mMapDlDigital[i].clear();
+ mMapDlAnalog[i].clear();
+ mSpec.swagcGainMap[i].clear();
+ mSpec.swagcGainMapDmic[i].clear();
+ mSpec.ulPgaGainMap[i].clear();
+ }
+}
+
+status_t GainTableParamParser::getGainTableParam(GainTableParam *_gainTable, std::vector<std::string> *sceneList) {
+ ALOGD("%s()", __FUNCTION__);
+ clearTableParam(_gainTable, sceneList->size());
+
+ status_t status = NO_ERROR;
+ _gainTable->sceneCount = (int)(sceneList->size());
+ status |= updatePlaybackDigitalGain(_gainTable, sceneList);
+ status |= updatePlaybackAnalogGain(_gainTable, sceneList);
+ status |= updateSpeechVol(_gainTable);
+ status |= updateRecordVol(_gainTable, sceneList);
+ status |= updateVoIPVol(_gainTable, sceneList);
+ // Ringback tone need to be updated after VOIP for initializing with voice stream gain
+ status |= updateRingbackVol(_gainTable);
+
+ if (status != NO_ERROR) {
+ ALOGE("error, %s() failed, status = %d", __FUNCTION__, status);
+ return status;
+ }
+
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::getCategoryList(AudioType *audioType, std::vector<std::string> *sceneList) {
+ int i, j;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ std::string sceneStr = "Scene";
+
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+ int numOfCategoryType = appOps->audioTypeGetNumOfCategoryType(audioType);
+
+ ALOGV("\n====%s AudioType's Category, numOfCategoryType = %d====\n\n", audioType->name, numOfCategoryType);
+
+ for (i = 0; i < numOfCategoryType; i++) {
+ CategoryType *categoryType = appOps->audioTypeGetCategoryTypeByIndex(audioType, i);
+ ALOGV("CategoryGroup[%d] name = %s wording = %s %s\n", i, categoryType->name, categoryType->wording, categoryType->visible ? "" : "visible = 0");
+ std::string xmlStr = categoryType->name;
+ if (sceneStr == xmlStr) {
+ /* Scene CategoryType's category */
+ int numOfCategory = appOps->categoryTypeGetNumOfCategory(categoryType);
+ for (j = 0; j < numOfCategory; j++) {
+ Category *category = appOps->categoryTypeGetCategoryByIndex(categoryType, j);
+ ALOGV("\tCategory[%d] name = %s wording = %s %s\n", j , category->name, category->wording, category->visible ? "" : "visible = 0");
+ if (!isInSceneList(sceneList, category->name)) {
+ sceneList->push_back(category->name);
+ }
+ }
+ break;
+ }
+ }
+ appOps->audioTypeUnlock(audioType);
+ return NO_ERROR;
+}
+
+bool GainTableParamParser::isInSceneList(std::vector<std::string> *sceneList, std::string scene) {
+ bool inSceneList = false;
+ for (size_t i = 0; i < sceneList->size(); i++) {
+ if ((*sceneList)[i] == scene) {
+ inSceneList = true;
+ break;
+ }
+ }
+ ALOGD("%s(): inSceneList = %d", __FUNCTION__, inSceneList);
+ return inSceneList;
+}
+
+status_t GainTableParamParser::getSceneList(std::vector<std::string> *sceneList) {
+ ALOGD("%s()", __FUNCTION__);
+
+ AudioType *audioType;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ // Initialize scene list and add Default scene
+ sceneList->clear();
+ sceneList->push_back("Default");
+
+ // Get scene from XML
+ // PlaybackVolDigi
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, PLAY_DIGI_AUDIOTYPE_NAME);
+ if (!audioType) {
+ ALOGW("error: get audioType fail, audioTypeName = %s", PLAY_DIGI_AUDIOTYPE_NAME);
+ return BAD_VALUE;
+ }
+ getCategoryList(audioType, sceneList);
+
+ // PlaybackVolAna
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, PLAY_ANA_AUDIOTYPE_NAME);
+ if (!audioType) {
+ ALOGW("error: get audioType fail, audioTypeName = %s", PLAY_ANA_AUDIOTYPE_NAME);
+ return BAD_VALUE;
+ }
+ getCategoryList(audioType, sceneList);
+
+ // RecordVol
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, REC_VOL_AUDIOTYPE_NAME);
+ if (!audioType) {
+ ALOGW("error: get audioType fail, audioTypeName = %s", REC_VOL_AUDIOTYPE_NAME);
+ return BAD_VALUE;
+ }
+ getCategoryList(audioType, sceneList);
+
+ // VoIPVol
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, VOIP_VOL_AUDIOTYPE_NAME);
+ if (!audioType) {
+ ALOGW("error: get audioType fail, audioTypeName = %s", VOIP_VOL_AUDIOTYPE_NAME);
+ return BAD_VALUE;
+ }
+ getCategoryList(audioType, sceneList);
+
+ for (int i = 0; i < (int)sceneList->size(); i++) {
+ ALOGG("%s(): sceneList[%d] = %s", __FUNCTION__, i, (*sceneList)[i].c_str());
+ }
+
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::getGainTableSpec(GainTableSpec **_gainTableSpec) {
+ *_gainTableSpec = &mSpec;
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::clearTableParam(GainTableParam *_gainTable, int sceneCount) {
+ memset((void *)_gainTable->sceneGain, 0, sceneCount * sizeof(GainTableForScene));
+ memset((void *)&_gainTable->nonSceneGain, 0, sizeof(GainTableForNonScene));
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::updatePlaybackDigitalGain(GainTableParam *_gainTable, std::vector<std::string> *sceneList) {
+ ALOGD("%s()", __FUNCTION__);
+
+ // define xml names
+ const char audioTypeName[] = PLAY_DIGI_AUDIOTYPE_NAME;
+ const char paramName[] = "digital_gain";
+ const std::string *profileName = gppDeviceXmlName;
+ const std::string *volumeTypeName = gppStreamTypeXmlName;
+
+ // extract parameters from xml
+ AudioType *audioType;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, audioTypeName);
+ if (!audioType) {
+ ALOGW("error: get audioType fail, audioTypeName = %s", audioTypeName);
+ return BAD_VALUE;
+ }
+
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ for (int scene = 0; scene < (int)(sceneList->size()); scene++) {
+ for (int stream = GAIN_MIN_STREAM_TYPE; stream <= GAIN_MAX_STREAM_TYPE; stream++) {
+ for (int device = 0; device < NUM_GAIN_DEVICE; device++) {
+ // get param unit using param path
+ std::string paramPath = "Scene," +
+ (*sceneList)[scene] +
+ ",Volume type," +
+ volumeTypeName[stream] +
+ ",Profile," +
+ profileName[device];
+ ALOGV("paramPath = %s", paramPath.c_str());
+
+ ParamUnit *paramUnit;
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramPath.c_str());
+ if (!paramUnit) {
+ ALOGV("warn: get paramUnit fail, paramPath = %s", paramPath.c_str());
+
+ if (device == GAIN_DEVICE_BT_A2DP ||
+ device == GAIN_DEVICE_BT_A2DP_HP ||
+ device == GAIN_DEVICE_BT_A2DP_SPK) {
+ // handle xml without bt a2dp gain table, use headphone
+ memcpy(_gainTable->sceneGain[scene].streamGain[stream][device],
+ _gainTable->sceneGain[scene].streamGain[stream][GAIN_DEVICE_HEADPHONE],
+ sizeof(struct GainTableUnit) * GAIN_VOL_INDEX_SIZE);
+ }
+
+ continue;
+ }
+
+ Param *param;
+ param = appOps->paramUnitGetParamByName(paramUnit, paramName);
+ if (!param) {
+ ALOGW("error: get param fail");
+ continue;
+ }
+
+ // convert xml param to gain table
+ short *shortArray = (short *)param->data;
+ int arraySize = param->arraySize;
+ if (arraySize > GAIN_VOL_INDEX_SIZE) {
+ ALOGW("error, param->arraySize %d exceed digital array size %d", arraySize, GAIN_VOL_INDEX_SIZE);
+ arraySize = GAIN_VOL_INDEX_SIZE;
+ }
+
+ for (int i = 0; i < arraySize; i++) {
+ unsigned char *digital = &_gainTable->sceneGain[scene].streamGain[stream][device][i].digital;
+ // convert 0~-64 dB to 0~255
+ if (shortArray[i] > mSpec.digiDbMax) {
+ ALOGW("error, param out of range, val %d > %d", shortArray[i], mSpec.digiDbMax);
+ *digital = 0;
+ } else if (shortArray[i] <= mSpec.digiDbMin) {
+ ALOGV("error, param out of range, val %d <= %d", shortArray[i], mSpec.digiDbMin);
+ *digital = mSpec.keyVolumeStep;
+ } else {
+ *digital = (shortArray[i] * -1 * mSpec.keyStepPerDb);
+ }
+
+ ALOGV("\tscene = %d, stream = %d, device = %d, array[%d] = %d, convert result = %d\n",
+ scene, stream, device, i, shortArray[i], *digital);
+ }
+ }
+ }
+ }
+
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::updatePlaybackAnalogGain(GainTableParam *_gainTable, std::vector<std::string> *sceneList) {
+ ALOGD("%s()", __FUNCTION__);
+
+ // define xml names
+ const char audioTypeName[] = PLAY_ANA_AUDIOTYPE_NAME;
+ const char paramHsName[] = "headset_pga";
+ const char paramSpkName[] = "speaker_pga";
+ const char paramRcvName[] = "receiver_pga";
+ const std::string *profileName = gppDeviceXmlName;
+ const std::string *volumeTypeName = gppStreamTypeXmlName;
+
+ // extract parameters from xml
+ AudioType *audioType;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, audioTypeName);
+ if (!audioType) {
+ ALOGW("error: get audioType fail, audioTypeName = %s", audioTypeName);
+ return BAD_VALUE;
+ }
+
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ for (int scene = 0; scene < (int)(sceneList->size()); scene++) {
+ for (int stream = GAIN_MIN_STREAM_TYPE; stream <= GAIN_MAX_STREAM_TYPE; stream++) {
+ for (int device = 0; device < NUM_GAIN_DEVICE; device++) {
+ // get param unit using param path
+ std::string paramPath = "Scene," +
+ (*sceneList)[scene] +
+ ",Volume type," +
+ volumeTypeName[stream] +
+ ",Profile," +
+ profileName[device];
+ ALOGV("paramPath = %s", paramPath.c_str());
+
+ ParamUnit *paramUnit;
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramPath.c_str());
+ if (!paramUnit) {
+ ALOGV("warn: get paramUnit fail, paramPath = %s", paramPath.c_str());
+ continue;
+ }
+ Param *param_hs;
+ param_hs = appOps->paramUnitGetParamByName(paramUnit, paramHsName);
+ if (!param_hs) {
+ ALOGW("warn: get param_hs fail");
+ continue;
+ }
+ Param *param_spk;
+ param_spk = appOps->paramUnitGetParamByName(paramUnit, paramSpkName);
+ if (!param_spk) {
+ ALOGW("warn: get param_spk fail");
+ continue;
+ }
+ Param *param_rcv;
+ param_rcv = appOps->paramUnitGetParamByName(paramUnit, paramRcvName);
+ if (!param_rcv) {
+ ALOGW("warn: get param_rcv fail");
+ continue;
+ }
+
+ // TODO: check if param is in range using checlist field
+ if (param_hs->arraySize != 1 || param_spk->arraySize != 1 || param_rcv->arraySize != 1) {
+ ALOGW("warn: %s arraySize(%zu) != 1 || %s arraySize(%zu) != 1|| %s arraySize(%zu) != 1",
+ paramHsName,
+ param_hs->arraySize,
+ paramSpkName,
+ param_spk->arraySize,
+ paramRcvName,
+ param_rcv->arraySize);
+ }
+
+ // analog is the same for different volume level for normal playbck
+ for (int i = 0; i < GAIN_VOL_INDEX_SIZE; i++) {
+ unsigned char *analog = _gainTable->sceneGain[scene].streamGain[stream][device][i].analog;
+ if (*(short *)param_spk->data >= 0 && mSpec.spkAnaType >= 0 && mSpec.spkAnaType < NUM_GAIN_ANA_TYPE) {
+ analog[mSpec.spkAnaType] = *(short *)param_spk->data;
+ ALOGV("\tscene = %d, stream = %d, device = %d, i = %d, analog[mSpec.spkAnaType] = %d\n",
+ scene, stream, device, i, analog[mSpec.spkAnaType]);
+ }
+ if (*(short *)param_rcv->data >= 0) {
+ analog[GAIN_ANA_HANDSET] = *(short *)param_rcv->data;
+ ALOGV("\tscene = %d, stream = %d, device = %d, i = %d, analog[GAIN_ANA_HANDSET] = %d\n",
+ scene, stream, device, i, analog[GAIN_ANA_HANDSET]);
+ }
+ if (*(short *)param_hs->data >= 0) {
+ analog[GAIN_ANA_HEADPHONE] = *(short *)param_hs->data;
+ ALOGV("\tscene = %d, stream = %d, device = %d, i = %d, analog[GAIN_ANA_HEADPHONE] = %d\n",
+ scene, stream, device, i, analog[GAIN_ANA_HEADPHONE]);
+ }
+ }
+ }
+ }
+ }
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::updateSpeechVol(GainTableParam *_gainTable) {
+ ALOGD("%s()", __FUNCTION__);
+
+ // define xml names
+ char audioTypeName[] = SPEECH_VOL_AUDIOTYPE_NAME;
+ char paramStfName[] = "stf_gain";
+ char paramUlName[] = "ul_gain";
+ char paramDlName[] = "dl_gain";
+
+ const std::string *profileName = gppDeviceXmlName;
+ const std::string *bandName = gppBandXmlName;
+ const std::string *netName = gppNetXmlName;
+
+ // extract parameters from xml
+ AudioType *audioType;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, audioTypeName);
+ if (!audioType) {
+ ALOGW("error: get audioType fail, audioTypeName = %s", audioTypeName);
+ return BAD_VALUE;
+ }
+
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ for (int net = 0; net < NUM_GAIN_SPEECH_NETWORK; net++) {
+ for (int band = 0; band < NUM_GAIN_SPEECH_BAND; band++) {
+ for (int device = 0; device < NUM_GAIN_DEVICE; device++) {
+ // get param unit using param path
+ std::string paramPath = "Band," +
+ bandName[band] +
+ ",Profile," +
+ profileName[device] +
+ ",Network," +
+ netName[net];
+ ALOGG("paramPath = %s", paramPath.c_str());
+
+ ParamUnit *paramUnit;
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramPath.c_str());
+ if (!paramUnit) {
+ ALOGV("warn: get paramUnit fail, paramPath = %s", paramPath.c_str());
+ continue;
+ }
+
+ // Sidetone gain
+ Param *param_stf_gain;
+ param_stf_gain = appOps->paramUnitGetParamByName(paramUnit, paramStfName);
+ if (!param_stf_gain) {
+ ALOGW("error: get param_stf_gain fail");
+ continue;
+ }
+
+ if (*(short *)param_stf_gain->data > mSpec.sidetoneIdxMax ||
+ *(short *)param_stf_gain->data < mSpec.sidetoneIdxMin) {
+ ALOGW("error, band %d, device %d, stf_gain = %d out of bound", band, device, *(short *)param_stf_gain->data);
+ }
+ _gainTable->nonSceneGain.sidetoneGain[band][net][device].gain = *(short *)param_stf_gain->data;
+
+ // Uplink gain
+ Param *param_ul_gain;
+ param_ul_gain = appOps->paramUnitGetParamByName(paramUnit, paramUlName);
+ if (!param_ul_gain) {
+ ALOGW("error: get param_ul_gain fail");
+ continue;
+ }
+
+ if (*(int *)param_ul_gain->data > mSpec.micIdxMax[device] ||
+ *(int *)param_ul_gain->data < mSpec.micIdxMin[device]) {
+ ALOGW("error, ul_gain = %d out of bound, band %d, device %d", *(int *)param_ul_gain->data, band, device);
+ }
+ _gainTable->nonSceneGain.speechMicGain[band][net][device].gain = *(int *)param_ul_gain->data;
+
+ // Downlink gain
+ Param *param_dl_gain;
+ param_dl_gain = appOps->paramUnitGetParamByName(paramUnit, paramDlName);
+ if (!param_dl_gain) {
+ ALOGW("error: get param_dl_gain fail");
+ continue;
+ }
+
+ short *shortArray = (short *)param_dl_gain->data;
+ int arraySize = param_dl_gain->arraySize;
+ if (arraySize + 1 > GAIN_VOL_INDEX_SIZE) {
+ ALOGW("error, param->arraySize + 1 %d exceed digital array size %d", arraySize, GAIN_VOL_INDEX_SIZE);
+ arraySize = GAIN_VOL_INDEX_SIZE - 1;
+ }
+
+ if (mMapDlDigital[device].size() == 0 ||
+ mMapDlAnalog[device].size() == 0 ||
+ mMapDlDigital[device].size() != mMapDlAnalog[device].size()) {
+ ALOGE("error, digi & analog map size = %zu & %zu", mMapDlDigital[device].size(),
+ mMapDlAnalog[device].size());
+ continue;
+ }
+
+ // xml 0~6 map to 1~7 here, index 0 is hard code mute
+ for (int i = 0; i < arraySize + 1; i++) {
+ short dl_idx, digital, analog;
+
+ if (i == 0) {
+ dl_idx = shortArray[i];
+ digital = -64;
+ analog = mMapDlAnalog[device][dl_idx];
+ } else {
+ dl_idx = shortArray[i - 1];
+ digital = mMapDlDigital[device][dl_idx];
+ analog = mMapDlAnalog[device][dl_idx];
+ }
+ // set digital gain
+
+ // convert 0~-64 dB to 0~255
+ if (digital > mSpec.digiDbMax) {
+ ALOGW("error, param out of range, val %d > %d", digital, mSpec.digiDbMax);
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].digital = 0;
+ } else if (digital <= mSpec.digiDbMin) {
+ ALOGV("error, param out of range, val %d <= %d", digital, mSpec.digiDbMin);
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].digital = mSpec.keyVolumeStep;
+ } else {
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].digital = (digital * -1 * mSpec.keyStepPerDb);
+ }
+
+ // set analog gain
+ if (mMapDlAnalogType[device] < 0 || mMapDlAnalogType[device] >= NUM_GAIN_ANA_TYPE) {
+ if (i == 0) {
+ ALOGG("\tcontinue, paramPath = %s, mMapDlAnalogType[%d] = %d",
+ paramPath.c_str(), device, mMapDlAnalogType[device]);
+ }
+ continue;
+ }
+
+ if (mMapDlAnalogType[device] == GAIN_ANA_SPEAKER) {
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].analog[mMapDlAnalogType[device]] = spkGainDb2Idx(analog);
+ } else if (mMapDlAnalogType[device] == GAIN_ANA_LINEOUT) {
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].analog[mMapDlAnalogType[device]] = lineoutBufferGainDb2Idx(analog);
+ } else if (mMapDlAnalogType[device] == GAIN_ANA_HEADPHONE) {
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].analog[mMapDlAnalogType[device]] = audioBufferGainDb2Idx(analog);
+ } else { // if (mMapDlAnalogType[device] == GAIN_ANA_HANDSET)
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].analog[mMapDlAnalogType[device]] = voiceBufferGainDb2Idx(analog);
+ }
+
+ ALOGV("\tvol_idx = %d, dl_gain_idx = %d, digital = %d, analog = %d, digitaldB = %d, analogdB = %d\n",
+ i,
+ dl_idx,
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].digital,
+ _gainTable->nonSceneGain.speechGain[band][net][device][i].analog[mMapDlAnalogType[device]],
+ digital,
+ analog);
+ }
+ }
+ }
+ }
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::updateRecordVol(GainTableParam *_gainTable, std::vector<std::string> *sceneList) {
+ ALOGD("%s()", __FUNCTION__);
+
+ // define xml names
+ char audioTypeName[] = REC_VOL_AUDIOTYPE_NAME;
+ const std::string *micModeName = gppMicModeXmlName;
+ const std::string *profileName = gppDeviceXmlName;
+
+ // extract parameters from xml
+ AudioType *audioType;
+ ParamUnit *paramUnit;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, audioTypeName);
+ if (!audioType) {
+ ALOGW("error: get audioType fail, audioTypeName = %s", audioTypeName);
+ return BAD_VALUE;
+ }
+
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ for (int scene = 0; scene < (int)(sceneList->size()); scene++) {
+ for (int mode = 0; mode < NUM_GAIN_MIC_MODE; mode++) {
+ for (int device = 0; device < NUM_GAIN_DEVICE; device++) {
+ // get param unit using param path
+ std::string paramPath = "Scene," +
+ (*sceneList)[scene] +
+ ",Application," +
+ micModeName[mode] +
+ ",Profile," +
+ profileName[device];
+ ALOGV("paramPath = %s", paramPath.c_str());
+
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramPath.c_str());
+ if (!paramUnit) {
+ ALOGV("warn: get paramUnit fail, paramPath = %s", paramPath.c_str());
+ continue;
+ }
+
+ // Uplink gain
+ Param *param_ul_gain;
+ param_ul_gain = appOps->paramUnitGetParamByName(paramUnit, "ul_gain");
+ if (!param_ul_gain) {
+ ALOGW("error: get param_ul_gain fail");
+ continue;
+ }
+
+ if (*(int *)param_ul_gain->data > mSpec.micIdxMax[device] ||
+ *(int *)param_ul_gain->data < mSpec.micIdxMin[device]) {
+ ALOGW("error, ul_gain = %d out of bound, paramPath = %s", *(int *)param_ul_gain->data, paramPath.c_str());
+ }
+ _gainTable->sceneGain[scene].micGain[mode][device].gain = *(int *)param_ul_gain->data;
+ ALOGV("\tscene = %d, mode = %d, device = %d, gain = %d\n",
+ scene, mode, device, _gainTable->sceneGain[scene].micGain[mode][device].gain);
+ }
+ }
+ }
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::updateVoIPVol(GainTableParam *_gainTable, std::vector<std::string> *sceneList) {
+ ALOGD("%s()", __FUNCTION__);
+
+ // define xml names
+ char audioTypeName[] = VOIP_VOL_AUDIOTYPE_NAME;
+ char paramUlName[] = "ul_gain";
+ char paramDlName[] = "dl_gain";
+ const std::string *profileName = gppDeviceXmlName;
+
+ // extract parameters from xml
+ AudioType *audioType;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, audioTypeName);
+ if (!audioType) {
+ ALOGW("error: get audioType fail, audioTypeName = %s", audioTypeName);
+ return BAD_VALUE;
+ }
+
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ for (int scene = 0; scene < (int)(sceneList->size()); scene++) {
+ for (int device = 0; device < NUM_GAIN_DEVICE; device++) {
+ // get param unit using param path
+ std::string paramPath = "Scene," +
+ (*sceneList)[scene] +
+ ",Profile," +
+ profileName[device];
+ ALOGV("paramPath = %s", paramPath.c_str());
+
+ ParamUnit *paramUnit;
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramPath.c_str());
+ if (!paramUnit) {
+ ALOGG("error: get paramUnit fail, paramPath = %s", paramPath.c_str());
+ continue;
+ }
+
+ // Uplink gain
+ const GAIN_MIC_MODE micType = GAIN_MIC_VOICE_COMMUNICATION;
+
+ if (micType >= 0 && micType < NUM_GAIN_MIC_MODE) {
+ Param *param_ul_gain;
+ param_ul_gain = appOps->paramUnitGetParamByName(paramUnit, paramUlName);
+ if (!param_ul_gain) {
+ ALOGW("error: get param_ul_gain fail, param name = %s", paramUlName);
+ continue;
+ }
+
+ if (*(int *)param_ul_gain->data > mSpec.micIdxMax[device] ||
+ *(int *)param_ul_gain->data < mSpec.micIdxMin[device]) {
+ ALOGW("error, ul_gain = %d out of bound, device %d", *(int *)param_ul_gain->data, device);
+ }
+ _gainTable->sceneGain[scene].micGain[micType][device].gain = *(int *)param_ul_gain->data;
+ ALOGV("\tscene = %d, micType = %d, device = %d, gain = %d\n",
+ scene, micType, device, _gainTable->sceneGain[scene].micGain[micType][device].gain);
+ }
+
+ // Downlink gain
+ // convert xml param to gain table
+ Param *param_dl_gain;
+ param_dl_gain = appOps->paramUnitGetParamByName(paramUnit, paramDlName);
+ if (!param_dl_gain) {
+ ALOGW("error: get param_dl_gain fail, param name = %s", paramDlName);
+ continue;
+ }
+
+ short *shortArray = (short *)param_dl_gain->data;
+ int arraySize = param_dl_gain->arraySize;
+ if (arraySize + 1 > GAIN_VOL_INDEX_SIZE) {
+ ALOGW("error, param->arraySize + 1 %d exceed digital array size %d", arraySize, GAIN_VOL_INDEX_SIZE);
+ arraySize = GAIN_VOL_INDEX_SIZE - 1;
+ }
+
+ if (mMapDlDigital[device].size() == 0 ||
+ mMapDlAnalog[device].size() == 0 ||
+ mMapDlDigital[device].size() != mMapDlAnalog[device].size()) {
+ ALOGE("error, digi & analog map size = %zu & %zu", mMapDlDigital[device].size(),
+ mMapDlAnalog[device].size());
+ continue;
+ }
+
+ // xml 0~6 map to 1~7 here, 0 is hard code mute
+ for (int i = 0; i < arraySize + 1; i++) {
+ short dl_idx, digital, analog;
+
+ if (i == 0) {
+ dl_idx = shortArray[i];
+ digital = -64;
+ analog = mMapDlAnalog[device][dl_idx];
+ } else {
+ dl_idx = shortArray[i - 1];
+ digital = mMapDlDigital[device][dl_idx];
+ analog = mMapDlAnalog[device][dl_idx];
+ }
+
+ // set digital gain
+ // convert 0~-64 dB to 0~255
+ if (digital > mSpec.digiDbMax) {
+ ALOGW("error, param out of range, val %d > %d", digital, mSpec.digiDbMax);
+ _gainTable->sceneGain[scene].streamGain[AUDIO_STREAM_VOICE_CALL][device][i].digital = 0;
+ } else if (digital <= mSpec.digiDbMin) {
+ ALOGV("error, param out of range, val %d <= %d", digital, mSpec.digiDbMin);
+ _gainTable->sceneGain[scene].streamGain[AUDIO_STREAM_VOICE_CALL][device][i].digital = mSpec.keyVolumeStep;
+ } else {
+ _gainTable->sceneGain[scene].streamGain[AUDIO_STREAM_VOICE_CALL][device][i].digital = (digital * -1 * mSpec.keyStepPerDb);
+ }
+
+ // set analog gain
+ if (mMapDlAnalogType[device] < 0 || mMapDlAnalogType[device] >= NUM_GAIN_ANA_TYPE) {
+ if (i == 0) {
+ ALOGG("\tcontinue, paramPath = %s, mMapDlAnalogType[%d] = %d",
+ paramPath.c_str(), device, mMapDlAnalogType[device]);
+ }
+ continue;
+ }
+
+ if (mMapDlAnalogType[device] == GAIN_ANA_SPEAKER) {
+ _gainTable->sceneGain[scene].streamGain[AUDIO_STREAM_VOICE_CALL][device][i].analog[mMapDlAnalogType[device]] = spkGainDb2Idx(analog);
+ } else if (mMapDlAnalogType[device] == GAIN_ANA_LINEOUT) {
+ _gainTable->sceneGain[scene].streamGain[AUDIO_STREAM_VOICE_CALL][device][i].analog[mMapDlAnalogType[device]] = lineoutBufferGainDb2Idx(analog);
+ } else if (mMapDlAnalogType[device] == GAIN_ANA_HEADPHONE) {
+ _gainTable->sceneGain[scene].streamGain[AUDIO_STREAM_VOICE_CALL][device][i].analog[mMapDlAnalogType[device]] = audioBufferGainDb2Idx(analog);
+ } else { // if (mMapDlAnalogType[device] == GAIN_ANA_HANDSET)
+ _gainTable->sceneGain[scene].streamGain[AUDIO_STREAM_VOICE_CALL][device][i].analog[mMapDlAnalogType[device]] = voiceBufferGainDb2Idx(analog);
+ }
+
+ ALOGV("\tvol_idx = %d, dl_gain_idx = %d, digital = %d, analog = %d, digitaldB = %d, analogdB = %d\n",
+ i,
+ dl_idx,
+ _gainTable->sceneGain[scene].streamGain[AUDIO_STREAM_VOICE_CALL][device][i].digital,
+ _gainTable->sceneGain[scene].streamGain[AUDIO_STREAM_VOICE_CALL][device][i].analog[mMapDlAnalogType[device]],
+ digital,
+ analog);
+
+ }
+ }
+ }
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::updateRingbackVol(GainTableParam *_gainTable) {
+ ALOGD("%s()", __FUNCTION__);
+
+ // define xml names
+ char audioTypeName[] = RINGBACK_VOL_AUDIOTYPE_NAME;
+ char paramRingbackName[] = "ringback_gain";
+ const std::string *profileName = gppDeviceXmlName;
+
+ // Initialize ringback tone with voice stream gain
+ int streamDevice = 0;
+ for (int device = 0; device < NUM_GAIN_DEVICE; device++) {
+ // Using speaker stream gain to initialize hs + spk ringback tone gain
+ if (device != GAIN_DEVICE_HSSPK) {
+ streamDevice = device;
+ } else {
+ streamDevice = GAIN_DEVICE_SPEAKER;
+ }
+ for (int i = 0; i < GAIN_VOL_INDEX_SIZE; i++) {
+ _gainTable->nonSceneGain.ringbackToneGain[device][i].digital =
+ _gainTable->sceneGain[GAIN_SCENE_INDEX_DEFAULT].streamGain[AUDIO_STREAM_VOICE_CALL][streamDevice][i].digital;
+ }
+ }
+
+ // extract parameters from xml
+ AudioType *audioType;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, audioTypeName);
+ if (!audioType) {
+ ALOGW("error: get audioType fail, audioTypeName = %s", audioTypeName);
+ return BAD_VALUE;
+ }
+
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ for (int device = 0; device < NUM_GAIN_DEVICE; device++) {
+ // get param unit using param path
+ std::string paramPath = "Profile," +
+ profileName[device];
+ ALOGV("paramPath = %s", paramPath.c_str());
+
+ ParamUnit *paramUnit;
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramPath.c_str());
+ if (!paramUnit) {
+ ALOGG("warn: get paramUnit fail, paramPath = %s", paramPath.c_str());
+ continue;
+ }
+
+ // Ringback tone gain
+ // convert xml param to gain table
+ Param *param_ringback_gain;
+ param_ringback_gain = appOps->paramUnitGetParamByName(paramUnit, paramRingbackName);
+ if (!param_ringback_gain) {
+ ALOGW("error: get param_ringback_gain fail, param name = %s", paramRingbackName);
+ continue;
+ }
+
+ short *shortArray = (short *)param_ringback_gain->data;
+ int arraySize = param_ringback_gain->arraySize;
+ if (arraySize + 1 > GAIN_VOL_INDEX_SIZE) {
+ ALOGW("error, param->arraySize + 1 %d exceed digital array size %d", arraySize, GAIN_VOL_INDEX_SIZE);
+ arraySize = GAIN_VOL_INDEX_SIZE - 1;
+ }
+
+ if (mMapDlDigital[device].size() == 0) {
+ ALOGE("error, digi = %zu", mMapDlDigital[device].size());
+ continue;
+ }
+
+ // xml 0~6 map to 1~7 here, 0 is hard code mute
+ for (int i = 0; i < arraySize + 1; i++) {
+ short dl_idx, digital;
+
+ if (i == 0) {
+ dl_idx = shortArray[i];
+ digital = -64;
+ } else {
+ dl_idx = shortArray[i - 1];
+ digital = mMapDlDigital[device][dl_idx];
+ }
+
+ // set digital gain
+ // convert 0~-64 dB to 0~255
+ if (digital > mSpec.digiDbMax) {
+ ALOGW("error, param out of range, val %d > %d", digital, mSpec.digiDbMax);
+ _gainTable->nonSceneGain.ringbackToneGain[device][i].digital = 0;
+ } else if (digital <= mSpec.digiDbMin) {
+ ALOGV("error, param out of range, val %d <= %d", digital, mSpec.digiDbMin);
+ _gainTable->nonSceneGain.ringbackToneGain[device][i].digital = mSpec.keyVolumeStep;
+ } else {
+ _gainTable->nonSceneGain.ringbackToneGain[device][i].digital = (digital * -1 * mSpec.keyStepPerDb);
+ }
+
+ ALOGV("\tvol_idx = %d, dl_gain_idx = %d, digital = %d, digitaldB = %d\n",
+ i,
+ dl_idx,
+ _gainTable->nonSceneGain.ringbackToneGain[device][i].digital,
+ digital);
+
+ // Fill HSSPK ringback gain with SPK
+ if (device == GAIN_DEVICE_SPEAKER) {
+ _gainTable->nonSceneGain.ringbackToneGain[GAIN_DEVICE_HSSPK][i].digital =
+ _gainTable->nonSceneGain.ringbackToneGain[device][i].digital;
+ }
+ }
+ }
+
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::loadGainTableParam() {
+ loadGainTableSpec();
+ loadGainTableMapDl();
+ loadGainTableMapUl();
+ loadGainTableHpImpedance();
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::loadGainTableSpec() {
+ ALOGD("%s()", __FUNCTION__);
+
+ // define xml names
+ char audioTypeName[] = VOLUME_AUDIOTYPE_NAME;
+
+ // extract parameters from xml
+ AudioType *audioType;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, audioTypeName);
+ if (!audioType) {
+ ALOGE("error: get audioType fail, audioTypeName = %s", audioTypeName);
+ return BAD_VALUE;
+ }
+
+ std::string paramPath = "VolumeParam,Common";
+
+ ParamUnit *paramUnit;
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramPath.c_str());
+ if (!paramUnit) {
+ ALOGE("error: get paramUnit fail, paramPath = %s", paramPath.c_str());
+ return BAD_VALUE;
+ }
+
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ // spec
+ getParam<int>(paramUnit, &mSpec.keyStepPerDb, "step_per_db");
+ ALOGV("mSpec.keyStepPerDb = %d", mSpec.keyStepPerDb);
+ getParam<float>(paramUnit, &mSpec.keyDbPerStep, "db_per_step");
+ ALOGV("mSpec.keyDbPerStep = %f", mSpec.keyDbPerStep);
+ getParam<float>(paramUnit, &mSpec.keyVolumeStep, "volume_step");
+ ALOGV("mSpec.keyVolumeStep = %f", mSpec.keyVolumeStep);
+
+ getParam<int>(paramUnit, &mSpec.digiDbMax, "play_digi_range_max");
+ ALOGV("mSpec.digiDbMax = %d", mSpec.digiDbMax);
+ getParam<int>(paramUnit, &mSpec.digiDbMin, "play_digi_range_min");
+ ALOGV("mSpec.digiDbMin = %d", mSpec.digiDbMin);
+ getParam<int>(paramUnit, &mSpec.sidetoneIdxMax, "stf_idx_range_max");
+ ALOGV("mSpec.sidetoneIdxMax = %d", mSpec.sidetoneIdxMax);
+ getParam<int>(paramUnit, &mSpec.sidetoneIdxMin, "stf_idx_range_min");
+ ALOGV("mSpec.sidetoneIdxMin = %d", mSpec.sidetoneIdxMin);
+
+ getParam<int>(paramUnit, &mSpec.decRecMax, "dec_rec_max");
+ ALOGV("mSpec.decRecMax = %d", mSpec.decRecMax);
+ getParam<int>(paramUnit, &mSpec.decRecStepPerDb, "dec_rec_step_per_db");
+ ALOGV("mSpec.decRecStepPerDb = %d", mSpec.decRecStepPerDb);
+
+ getParam<int>(paramUnit, &mSpec.ulGainOffset, "ul_gain_offset");
+ ALOGV("mSpec.ulGainOffset = %d", mSpec.ulGainOffset);
+ getParam<int>(paramUnit, &mSpec.ulPgaGainMapMax, "ul_pga_gain_map_max");
+ ALOGV("mSpec.ulPgaGainMapMax = %d", mSpec.ulPgaGainMapMax);
+ getParam<int>(paramUnit, &mSpec.ulHwPgaIdxMax, "ul_hw_pga_max_idx");
+ ALOGV("mSpec.ulHwPgaIdxMax = %d", mSpec.ulHwPgaIdxMax);
+
+ // audio buffer gain spec
+ getParamVector<short>(paramUnit, &mSpec.audioBufferGainDb, "audio_buffer_gain_db");
+ getParamVector<short>(paramUnit, &mSpec.audioBufferGainIdx, "audio_buffer_gain_idx");
+ getParamVector(paramUnit, &mSpec.audioBufferGainString, "audio_buffer_gain_string");
+
+ getParam<int>(paramUnit, &mSpec.audioBufferGainPreferMaxIdx, "audio_buffer_gain_prefer_max_idx");
+ getParam(paramUnit, &mSpec.audioBufLMixerName, "audio_buffer_l_mixer_name");
+ getParam(paramUnit, &mSpec.audioBufRMixerName, "audio_buffer_r_mixer_name");
+ ALOGD("mSpec.audioBufferGainPreferMaxIdx = %d, audioBufLMixerName = %s, audioBufRMixerName = %s",
+ mSpec.audioBufferGainPreferMaxIdx,
+ mSpec.audioBufLMixerName.c_str(),
+ mSpec.audioBufRMixerName.c_str());
+
+ size_t db_size = mSpec.audioBufferGainDb.size();
+ size_t idx_size = mSpec.audioBufferGainIdx.size();
+ size_t str_size = mSpec.audioBufferGainString.size();
+
+ if (db_size != idx_size || db_size != str_size) {
+ ALOGW("warn: db & idx & str_size mapping array size is not the same, db.size()=%zu, idx.size()=%zu, str_size()=%zu",
+ db_size,
+ idx_size,
+ str_size);
+ }
+
+ mSpec.numAudioBufferGainLevel = (db_size <= idx_size) ? db_size : idx_size;
+
+ for (unsigned int i = 0; i < mSpec.numAudioBufferGainLevel; i++) {
+ ALOGG("audio buffer, db = %d, idx = %d", mSpec.audioBufferGainDb[i], mSpec.audioBufferGainIdx[i]);
+ }
+
+ // voice buffer gain spec
+ getParamVector<short>(paramUnit, &mSpec.voiceBufferGainDb, "voice_buffer_gain_db");
+ getParamVector<short>(paramUnit, &mSpec.voiceBufferGainIdx, "voice_buffer_gain_idx");
+ getParamVector(paramUnit, &mSpec.voiceBufferGainString, "voice_buffer_gain_string");
+ getParam<int>(paramUnit, &mSpec.voiceBufferGainPreferMaxIdx, "voice_buffer_gain_prefer_max_idx");
+ getParam(paramUnit, &mSpec.voiceBufMixerName, "voice_buffer_mixer_name");
+ ALOGD("mSpec.voiceBufferGainPreferMaxIdx = %d, voiceBufMixerName = %s",
+ mSpec.voiceBufferGainPreferMaxIdx,
+ mSpec.voiceBufMixerName.c_str());
+
+ db_size = mSpec.voiceBufferGainDb.size();
+ idx_size = mSpec.voiceBufferGainIdx.size();
+ str_size = mSpec.voiceBufferGainString.size();
+
+ if (db_size != idx_size || db_size != str_size) {
+ ALOGW("warn: db & idx & str_size mapping array size is not the same, db.size()=%zu, idx.size()=%zu, str_size()=%zu",
+ db_size,
+ idx_size,
+ str_size);
+ }
+
+ mSpec.numVoiceBufferGainLevel = (db_size <= idx_size) ? db_size : idx_size;
+
+ for (unsigned int i = 0; i < mSpec.numVoiceBufferGainLevel; i++) {
+ ALOGG("voice buffer, db = %d, idx = %d", mSpec.voiceBufferGainDb[i], mSpec.voiceBufferGainIdx[i]);
+ }
+
+ // lineout buffer gain spec
+ getParamVector<short>(paramUnit, &mSpec.lineoutBufferGainDb, "lineout_buffer_gain_db");
+ getParamVector<short>(paramUnit, &mSpec.lineoutBufferGainIdx, "lineout_buffer_gain_idx");
+ getParamVector(paramUnit, &mSpec.lineoutBufferGainString, "lineout_buffer_gain_string");
+ getParam<int>(paramUnit, &mSpec.lineoutBufferGainPreferMaxIdx, "lineout_buffer_gain_prefer_max_idx");
+ ALOGD("mSpec.lineoutBufferGainPreferMaxIdx = %d", mSpec.lineoutBufferGainPreferMaxIdx);
+
+ db_size = mSpec.lineoutBufferGainDb.size();
+ idx_size = mSpec.lineoutBufferGainIdx.size();
+ str_size = mSpec.lineoutBufferGainString.size();
+
+ if (db_size != idx_size || db_size != str_size) {
+ ALOGW("warn: db & idx & str_size mapping array size is not the same, db.size()=%zu, idx.size()=%zu, str_size()=%zu",
+ db_size,
+ idx_size,
+ str_size);
+ }
+
+ mSpec.numLineoutBufferGainLevel = (db_size <= idx_size) ? db_size : idx_size;
+
+ for (unsigned int i = 0; i < mSpec.numLineoutBufferGainLevel; i++) {
+ ALOGG("lineout buffer, db = %d, idx = %d", mSpec.lineoutBufferGainDb[i], mSpec.lineoutBufferGainIdx[i]);
+ }
+
+ // spk gain spec
+ getParamVector<short>(paramUnit, &mSpec.spkGainDb, "spk_gain_db");
+ getParamVector<short>(paramUnit, &mSpec.spkGainIdx, "spk_gain_idx");
+ getParamVector(paramUnit, &mSpec.spkGainString, "spk_gain_string");
+
+ if (AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ mSpec.spkAnaType = GAIN_ANA_NONE;
+ } else {
+ if (AudioSmartPaController::getInstance()->isSmartPADynamicDetectSupport()) {
+ int spkType = AudioALSAHardwareResourceManager::getInstance()->getNonSmartPAType();
+ switch (spkType) {
+ case AUDIO_SPK_INTAMP:
+ mSpec.spkAnaType = GAIN_ANA_SPEAKER;
+ break;
+ case AUDIO_SPK_EXTAMP_LO:
+ mSpec.spkAnaType = GAIN_ANA_LINEOUT;
+ break;
+ case AUDIO_SPK_EXTAMP_HP:
+ mSpec.spkAnaType = GAIN_ANA_HEADPHONE;
+ break;
+ default:
+ ALOGW("error! default set ANA_LINEOUT\n");
+ mSpec.spkAnaType = GAIN_ANA_LINEOUT;
+ break;
+ }
+ } else {
+ getParam<GAIN_ANA_TYPE>(paramUnit, &mSpec.spkAnaType, "spk_analog_type");
+ }
+ }
+
+ getParam(paramUnit, &mSpec.spkLMixerName, "spk_l_mixer_name");
+ getParam(paramUnit, &mSpec.spkRMixerName, "spk_r_mixer_name");
+ ALOGD("mSpec.spkAnaType = %d, spkLMixerName = %s, spkRMixerName = %s",
+ mSpec.spkAnaType,
+ mSpec.spkLMixerName.c_str(),
+ mSpec.spkRMixerName.c_str());
+
+
+ db_size = mSpec.spkGainDb.size();
+ idx_size = mSpec.spkGainIdx.size();
+ str_size = mSpec.spkGainString.size();
+
+ if (db_size != idx_size || db_size != str_size) {
+ ALOGW("warn: db & idx & str_size mapping array size is not the same, db.size()=%zu, idx.size()=%zu, str_size()=%zu",
+ db_size,
+ idx_size,
+ str_size);
+ }
+
+ mSpec.numSpkGainLevel = (db_size <= idx_size) ? db_size : idx_size;
+
+ for (unsigned int i = 0; i < mSpec.numSpkGainLevel; i++) {
+ ALOGG("spk, db = %d, idx = %d", mSpec.spkGainDb[i], mSpec.spkGainIdx[i]);
+ }
+
+ // ul gain map
+ getParamVector(paramUnit, &mSpec.ulPgaGainString, "ul_pga_gain_string");
+ getParam(paramUnit, &mSpec.ulPgaLMixerName, "ul_pga_l_mixer_name");
+ getParam(paramUnit, &mSpec.ulPgaRMixerName, "ul_pga_r_mixer_name");
+ ALOGD("mSpec.ulPgaLMixerName = %s, ulPgaRMixerName = %s",
+ mSpec.ulPgaLMixerName.c_str(), mSpec.ulPgaRMixerName.c_str());
+
+
+ // stf gain map
+ getParamVector<short>(paramUnit, &mSpec.stfGainMap, "stf_gain_map");
+ if ((int)mSpec.stfGainMap.size() != mSpec.sidetoneIdxMax + 1) {
+ ALOGW("warn: stfGainMap.size %zu != sidetoneIdxMax %d + 1",
+ mSpec.stfGainMap.size(),
+ mSpec.sidetoneIdxMax);
+ }
+
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ return NO_ERROR;
+}
+
+
+status_t GainTableParamParser::loadGainTableMapDl() {
+ ALOGD("%s()", __FUNCTION__);
+
+ // define xml names
+ char audioTypeName[] = GAIN_MAP_AUDIOTYPE_NAME;
+ char paramTotalName[] = "dl_total_gain";
+ char paramDigitalName[] = "dl_digital_gain";
+ char paramAnalogName[] = "dl_analog_gain";
+ char paramAnaTypeName[] = "dl_analog_type";
+
+ const std::string *profileName = gppDeviceXmlName;
+
+ // extract parameters from xml
+ AudioType *audioType;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, audioTypeName);
+ if (!audioType) {
+ ALOGW("error: get audioType fail, audioTypeName = %s", audioTypeName);
+ return BAD_VALUE;
+ }
+
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ for (int device = 0; device < NUM_GAIN_DEVICE; device++) {
+ // get param unit using param path
+ std::string paramPath = "Profile," +
+ profileName[device];
+ ALOGV("paramPath = %s", paramPath.c_str());
+
+ ParamUnit *paramUnit;
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramPath.c_str());
+ if (!paramUnit) {
+ ALOGW("error: get paramUnit fail, paramPath = %s", paramPath.c_str());
+ continue;
+ }
+ Param *param_total;
+ param_total = appOps->paramUnitGetParamByName(paramUnit, paramTotalName);
+ if (!param_total) {
+ ALOGW("error: get param_total fail, param_name = %s", paramTotalName);
+ continue;
+ }
+
+ Param *param_digital;
+ param_digital = appOps->paramUnitGetParamByName(paramUnit, paramDigitalName);
+ if (!param_digital) {
+ ALOGW("error: get param_digital fail, param_name = %s", paramDigitalName);
+ continue;
+ }
+ Param *param_analog;
+ param_analog = appOps->paramUnitGetParamByName(paramUnit, paramAnalogName);
+ if (!param_analog) {
+ ALOGW("error: get param_analog fail, param_name = %s", paramAnalogName);
+ continue;
+ }
+ Param *param_ana_type;
+ param_ana_type = appOps->paramUnitGetParamByName(paramUnit, paramAnaTypeName);
+ if (!param_ana_type) {
+ ALOGW("error: get param_ana_type fail, param_name = %s", paramAnaTypeName);
+ continue;
+ }
+ mMapDlAnalogType[device] = (GAIN_ANA_TYPE) * (int *)param_ana_type->data;
+
+ if (param_digital->arraySize != param_analog->arraySize) {
+ ALOGE("error: digi & ana mapping array size is not the same, digi.size()=%zu, ana.size()=%zu", param_digital->arraySize, param_analog->arraySize);
+ continue;
+ }
+
+ if (param_total->arraySize != param_digital->arraySize) {
+ ALOGW("error, total gain && digi & ana array size does not match, total.size()=%zu, digi.size()=%zu", param_total->arraySize, param_digital->arraySize);
+ }
+
+ short *digital_raw = (short *)param_digital->data;
+ mMapDlDigital[device].assign(digital_raw, digital_raw + param_digital->arraySize);
+
+ short *analog_raw = (short *)param_analog->data;
+ mMapDlAnalog[device].assign(analog_raw, analog_raw + param_analog->arraySize);
+
+ for (unsigned int i = 0; i < mMapDlDigital[device].size(); i++) {
+ ALOGV("digi = %d, ana = %d", mMapDlDigital[device][i], mMapDlAnalog[device][i]);
+ }
+ }
+
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ return NO_ERROR;
+
+}
+
+status_t GainTableParamParser::loadGainTableMapUl() {
+ ALOGD("%s()", __FUNCTION__);
+
+ // define xml names
+ char audioTypeName[] = GAIN_MAP_UL_AUDIOTYPE_NAME;
+ char paramSwagcMapName[] = "swagc_gain_map";
+ char paramSwagcMapDmicName[] = "swagc_gain_map_dmic";
+ char paramUlPgaName[] = "ul_pga_gain_map";
+
+ const std::string *profileName = gppDeviceXmlName;
+
+ // extract parameters from xml
+ AudioType *audioType;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, audioTypeName);
+ if (!audioType) {
+ ALOGW("error: get audioType fail, audioTypeName = %s", audioTypeName);
+ return BAD_VALUE;
+ }
+
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ for (int device = 0; device < NUM_GAIN_DEVICE; device++) {
+ // get param unit using param path
+ std::string paramPath = "Profile," +
+ profileName[device];
+ ALOGG("paramPath = %s", paramPath.c_str());
+
+ ParamUnit *paramUnit;
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramPath.c_str());
+ if (!paramUnit) {
+ ALOGW("error: get paramUnit fail, paramPath = %s", paramPath.c_str());
+ continue;
+ }
+
+ Param *param_swagc;
+ param_swagc = appOps->paramUnitGetParamByName(paramUnit, paramSwagcMapName);
+ if (!param_swagc) {
+ ALOGW("error: get param_swagc fail, param_name = %s", paramSwagcMapName);
+ continue;
+ }
+
+ Param *param_swagc_dmic;
+ param_swagc_dmic = appOps->paramUnitGetParamByName(paramUnit, paramSwagcMapDmicName);
+ if (!param_swagc_dmic) {
+ ALOGW("error: get param_swagc_dmic fail, param_name = %s", paramSwagcMapDmicName);
+ continue;
+ }
+
+ Param *param_ul_pga;
+ param_ul_pga = appOps->paramUnitGetParamByName(paramUnit, paramUlPgaName);
+ if (!param_ul_pga) {
+ ALOGW("error: get param_ul_pga fail, param_name = %s", paramUlPgaName);
+ continue;
+ }
+
+ getParam<int>(paramUnit, &mSpec.micIdxMax[device], "mic_idx_range_max");
+ ALOGG("mSpec.micIdxMax[%d] = %d", device, mSpec.micIdxMax[device]);
+
+ getParam<int>(paramUnit, &mSpec.micIdxMin[device], "mic_idx_range_min");
+ ALOGG("mSpec.micIdxMin[%d] = %d", device, mSpec.micIdxMin[device]);
+
+ if (param_swagc->arraySize != param_ul_pga->arraySize ||
+ param_swagc->arraySize != param_swagc_dmic->arraySize) {
+ ALOGW("error, swagc gain && ul_pga array size does not match, swagc.size()=%zu, pga.size()=%zu, swagc_dmic.size()=%zu", param_swagc->arraySize, param_ul_pga->arraySize, param_swagc_dmic->arraySize);
+ }
+
+ short *swagc_raw = (short *)param_swagc->data;
+ mSpec.swagcGainMap[device].assign(swagc_raw, swagc_raw + param_swagc->arraySize);
+
+ short *swagc_dmic_raw = (short *)param_swagc_dmic->data;
+ mSpec.swagcGainMapDmic[device].assign(swagc_dmic_raw, swagc_dmic_raw + param_swagc_dmic->arraySize);
+
+ short *pga_raw = (short *)param_ul_pga->data;
+ mSpec.ulPgaGainMap[device].assign(pga_raw, pga_raw + param_ul_pga->arraySize);
+
+ for (unsigned int i = 0; i < mSpec.swagcGainMap[device].size(); i++) {
+ ALOGV("swagc = %d, swagc_dmic = %d, pga = %d", mSpec.swagcGainMap[device][i], mSpec.swagcGainMapDmic[device][i], mSpec.ulPgaGainMap[device][i]);
+ }
+ }
+
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::loadGainTableHpImpedance() {
+ ALOGD("%s()", __FUNCTION__);
+
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(false);
+ return UNKNOWN_ERROR;
+ }
+
+ // define xml names
+ char audioTypeName[] = HP_IMPEDANCE_AUDIOTYPE_NAME;
+
+ // extract parameters from xml
+ AudioType *audioType;
+ audioType = appOps->appHandleGetAudioTypeByName(appOps->appHandleGetInstance(), audioTypeName);
+ if (!audioType) {
+ ALOGE("%s(), get audioType fail, audioTypeName = %s", __FUNCTION__, audioTypeName);
+ return BAD_VALUE;
+ }
+
+ std::string paramCommonPath = "HpImpedance,Common";
+ std::string paramPath = "HpImpedance,";
+ const char *platformChar = appOps->appHandleGetFeatureOptionValue(appOps->appHandleGetInstance(), "MTK_PLATFORM");
+
+ if (platformChar) {
+ paramPath += std::string(platformChar);
+ }
+
+ ParamUnit *paramUnit;
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramPath.c_str());
+ if (!paramUnit) {
+ ALOGW("%s(), get paramUnit fail, paramPath = %s, use common", __FUNCTION__, paramPath.c_str());
+
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramCommonPath.c_str());
+ if (!paramUnit) {
+ ALOGE("%s(), get paramUnit fail, paramCommonPath = %s", __FUNCTION__, paramCommonPath.c_str());
+ return BAD_VALUE;
+ }
+ }
+
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ // headphone impedance related
+ getParam<int>(paramUnit, &mSpec.hpImpEnable, "hp_impedance_enable");
+ ALOGD("mSpec.hpImpEnable = %d", mSpec.hpImpEnable);
+ if (mSpec.hpImpEnable) {
+ mSpec.hpImpOnBoardResistor = 0;
+ getParam<int>(paramUnit, &mSpec.hpImpOnBoardResistor, "hp_impedance_onboard_resistor");
+ getParam<int>(paramUnit, &mSpec.hpImpDefaultIdx, "hp_impedance_default_idx");
+ ALOGD("mSpec.hpImpDefaultIdx = %d", mSpec.hpImpDefaultIdx);
+ getParamVector<short>(paramUnit, &mSpec.hpImpThresholdList, "hp_impedance_threshold_list");
+ getParamVector<short>(paramUnit, &mSpec.hpImpCompensateList, "hp_impedance_gain_degrade_list");
+ ASSERT(mSpec.hpImpThresholdList.size() == (mSpec.hpImpCompensateList.size() - 1));
+ ASSERT(mSpec.hpImpThresholdList.size() != 0);
+ ASSERT(mSpec.hpImpDefaultIdx >= 0 && mSpec.hpImpDefaultIdx < (int)mSpec.hpImpThresholdList.size());
+ }
+
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ return NO_ERROR;
+}
+
+/*
+ * Utility functions
+ */
+unsigned int GainTableParamParser::audioBufferGainDb2Idx(int dB) {
+ for (unsigned int i = 0; i < mSpec.numAudioBufferGainLevel; i++) {
+ if (dB == mSpec.audioBufferGainDb[i]) {
+ return mSpec.audioBufferGainIdx[i];
+ }
+ }
+
+ ALOGW("error, %s(), cannot find corresponding BufferGainIdx, return idx 0, %ddB", __FUNCTION__, mSpec.audioBufferGainDb[0]);
+ return 0;
+}
+
+unsigned int GainTableParamParser::voiceBufferGainDb2Idx(int dB) {
+ for (unsigned int i = 0; i < mSpec.numVoiceBufferGainLevel; i++) {
+ if (dB == mSpec.voiceBufferGainDb[i]) {
+ return mSpec.voiceBufferGainIdx[i];
+ }
+ }
+
+ ALOGW("error, %s(), cannot find corresponding BufferGainIdx, return idx 0, %ddB", __FUNCTION__, mSpec.voiceBufferGainDb[0]);
+ return 0;
+}
+
+unsigned int GainTableParamParser::lineoutBufferGainDb2Idx(int dB) {
+ for (unsigned int i = 0; i < mSpec.numLineoutBufferGainLevel; i++) {
+ if (dB == mSpec.lineoutBufferGainDb[i]) {
+ return mSpec.lineoutBufferGainIdx[i];
+ }
+ }
+
+ ALOGW("error, %s(), cannot find corresponding BufferGainIdx, return idx 0, %ddB", __FUNCTION__, mSpec.lineoutBufferGainDb[0]);
+ return 0;
+}
+
+unsigned int GainTableParamParser::spkGainDb2Idx(int dB) {
+ for (size_t i = 0; i < mSpec.numSpkGainLevel; i++) {
+ if (dB == mSpec.spkGainDb[i]) {
+ return mSpec.spkGainIdx[i];
+ }
+ }
+
+ ALOGW("error, %s(), cannot find corresponding BufferGainIdx, return idx 1, %ddB", __FUNCTION__, mSpec.spkGainDb[1]);
+ return 1;
+}
+
+GAIN_SPEECH_NETWORK GainTableParamParser::getGainSpeechNetwork(const char *name) {
+ for (int i = 0; i < NUM_GAIN_SPEECH_NETWORK; i++) {
+ if (strcmp(name, gppNetXmlName[i].c_str()) == 0) {
+ return (GAIN_SPEECH_NETWORK)i;
+ }
+ }
+
+ ALOGW("%s(), speech network not found, name %s, return 0", __FUNCTION__, name);
+
+ return (GAIN_SPEECH_NETWORK)0;
+}
+
+template<class T>
+status_t GainTableParamParser::getParam(ParamUnit *_paramUnit, T *_param, const char *_paramName) {
+ Param *param;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ param = appOps->paramUnitGetParamByName(_paramUnit, _paramName);
+ if (!param) {
+ ALOGE("error: get param fail, param_name = %s", _paramName);
+ return BAD_VALUE;
+ } else {
+ *_param = *(T *)param->data;
+ }
+
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::getParam(ParamUnit *_paramUnit, std::string *_param, const char *_paramName) {
+ Param *param;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ param = appOps->paramUnitGetParamByName(_paramUnit, _paramName);
+ if (!param) {
+ ALOGE("error: get param fail, param_name = %s", _paramName);
+ return BAD_VALUE;
+ } else {
+ if (param->paramInfo->dataType == TYPE_STR) {
+ *_param = (char *)param->data;
+ } else {
+ ALOGW("warn, param->paramInfo->dataType %d != TYPE_STR %d", param->paramInfo->dataType, TYPE_STR);
+ return BAD_VALUE;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+
+template<class T>
+status_t GainTableParamParser::getParamVector(ParamUnit *_paramUnit, std::vector<T> *_param, const char *_paramName) {
+ Param *param;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ param = appOps->paramUnitGetParamByName(_paramUnit, _paramName);
+ if (!param) {
+ ALOGE("error: get param fail, param_name = %s", _paramName);
+ return BAD_VALUE;
+ } else {
+ T *raw = (T *)param->data;
+ _param->assign(raw, raw + param->arraySize);
+ }
+
+ return NO_ERROR;
+}
+
+status_t GainTableParamParser::getParamVector(ParamUnit *_paramUnit, std::vector<std::string> *_param, const char *_paramName) {
+ Param *param;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+ param = appOps->paramUnitGetParamByName(_paramUnit, _paramName);
+ if (!param) {
+ ALOGE("error: get param fail, param_name = %s", _paramName);
+ return BAD_VALUE;
+ } else {
+ if (param->paramInfo->dataType == TYPE_STR) {
+ _param->clear();
+ std::string raw((char *)param->data);
+ ALOGV("%s = %s", _paramName, raw.c_str());
+
+ ASSERT(!raw.empty());
+
+ int pre_pos = -1;
+ size_t find_pos = raw.find(',', pre_pos + 1);
+
+ std::string sub_str = raw.substr(pre_pos + 1, find_pos - pre_pos - 1);
+ do {
+ _param->push_back(sub_str);
+ ALOGV("\t%s", _param->back().c_str());
+ if (find_pos == std::string::npos) {
+ break;
+ }
+ pre_pos = find_pos;
+ find_pos = raw.find(',', pre_pos + 1);
+ sub_str = raw.substr(pre_pos + 1, find_pos - pre_pos - 1);
+ } while (!sub_str.empty());
+ } else {
+ ALOGW("warn, param->paramInfo->dataType %d != %d", param->paramInfo->dataType, TYPE_STR);
+ return BAD_VALUE;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+
+}
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioMessengerIPI.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioMessengerIPI.cpp
new file mode 100644
index 0000000..395d6bb
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioMessengerIPI.cpp
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <AudioMessengerIPI.h>
+
+#include <system/audio.h>
+#include <log/log.h>
+
+#include <AudioAssert.h>
+
+
+#ifdef MTK_AUDIODSP_SUPPORT
+#include <audio_dsp_service.h>
+#endif
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioMessengerIPI"
+
+
+
+unsigned int getDspFeatureID(const uint16_t flag) {
+#ifndef MTK_AUDIODSP_SUPPORT
+ ALOGD("%s() not support!! %d", __FUNCTION__, flag);
+ return 0;
+#else
+ switch (flag) {
+ case (AUDIO_OUTPUT_FLAG_DEEP_BUFFER):
+ return DEEPBUF_FEATURE_ID;
+ case (AUDIO_OUTPUT_FLAG_DEEP_BUFFER|AUDIO_OUTPUT_FLAG_PRIMARY):
+ case (AUDIO_OUTPUT_FLAG_PRIMARY):
+ return PRIMARY_FEATURE_ID;
+ case (AUDIO_OUTPUT_FLAG_VOIP_RX):
+ return VOIP_FEATURE_ID;
+ default:
+ ALOGE("%s: no support flag %d, use PRIMARY_FEATURE_ID instead", __FUNCTION__, flag);
+ return PRIMARY_FEATURE_ID;
+ }
+#endif
+}
+
+
+
+namespace android {
+
+AudioMessengerIPI *AudioMessengerIPI::mAudioMessengerIPI = NULL;
+AudioMessengerIPI *AudioMessengerIPI::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioMessengerIPI == NULL) {
+ mAudioMessengerIPI = new AudioMessengerIPI();
+ }
+ ASSERT(mAudioMessengerIPI != NULL);
+ return mAudioMessengerIPI;
+}
+
+
+AudioMessengerIPI::AudioMessengerIPI() {
+ audio_messenger_ipi_init();
+}
+
+
+AudioMessengerIPI::~AudioMessengerIPI() {
+ audio_messenger_ipi_deinit();
+}
+
+
+void AudioMessengerIPI::loadTaskScene(const uint8_t task_scene) {
+ audio_load_task_scene(task_scene);
+}
+
+
+status_t AudioMessengerIPI::sendIpiMsg(
+ struct ipi_msg_t *p_ipi_msg,
+ uint8_t task_scene,
+ uint8_t target_layer,
+ uint8_t data_type,
+ uint8_t ack_type,
+ uint16_t msg_id,
+ uint32_t param1,
+ uint32_t param2,
+ void *data_buffer) {
+ return audio_send_ipi_msg(
+ p_ipi_msg,
+ task_scene,
+ target_layer,
+ data_type,
+ ack_type,
+ msg_id,
+ param1,
+ param2,
+ data_buffer);
+}
+
+
+void AudioMessengerIPI::registerDmaCbk(
+ const uint8_t task_scene,
+ const uint32_t a2dSize,
+ const uint32_t d2aSize,
+ audio_ipi_dma_cbk_t cbk,
+ void *arg) {
+#ifndef MTK_AUDIO_IPI_DMA_SUPPORT
+ ALOGD("%s() not support!! %d %u %u %p %p",
+ __FUNCTION__, task_scene, a2dSize, d2aSize, cbk, arg);
+#else
+ audio_ipi_dma_cbk_register(
+ task_scene,
+ a2dSize,
+ d2aSize,
+ cbk,
+ arg);
+#endif
+}
+
+
+void AudioMessengerIPI::deregisterDmaCbk(const uint8_t task_scene) {
+#ifndef MTK_AUDIO_IPI_DMA_SUPPORT
+ ALOGD("%s() not support!! %d", __FUNCTION__, task_scene);
+#else
+ audio_ipi_dma_cbk_deregister(task_scene);
+#endif
+}
+
+
+void AudioMessengerIPI::registerAdspFeature(const uint16_t feature_id) {
+#ifndef MTK_AUDIODSP_SUPPORT
+ ALOGD("%s() not support!! %d", __FUNCTION__, feature_id);
+#else
+ adsp_register_feature(feature_id);
+#endif
+}
+
+
+void AudioMessengerIPI::deregisterAdspFeature(const uint16_t feature_id) {
+#ifndef MTK_AUDIODSP_SUPPORT
+ ALOGD("%s() not support!! %d", __FUNCTION__, feature_id);
+#else
+ adsp_deregister_feature(feature_id);
+#endif
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioMixerOut.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioMixerOut.cpp
new file mode 100644
index 0000000..d082359
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioMixerOut.cpp
@@ -0,0 +1,1106 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioMixerOut.h"
+
+#include <audio_utils/format.h>
+#include <fstream>
+#include <limits>
+#include <unordered_map>
+
+#include "AudioALSAPlaybackHandlerBase.h"
+#include "AudioALSAStreamManager.h"
+#include "AudioALSADriverUtility.h"
+#include "AudioUtility.h"
+#include "MtkAudioComponent.h"
+#include "WCNChipController.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioMixerOut"
+
+#define MIX_OUT_MIX_FORMAT AUDIO_FORMAT_PCM_FLOAT
+
+// pcm dump
+#define MIX_OUT_DUMP_FILE_PREFIX "/data/vendor/audiohal/audio_dump/mix.out.pcm"
+#define MIX_OUT_DUMP_NAME "mixed"
+
+// debug
+#define MIX_OUT_DEBUG "vendor.mix.out.debug"
+
+enum MIX_OUT_DBG_TYPE {
+ MIX_OUT_DBG_ALL = 0xFFFFFFFF,
+};
+
+namespace android {
+
+using namespace std;
+
+static AudioLock mGetInstanceLock;
+unordered_map<enum MIXER_USAGE, AudioMixerOut *> mInstanceSet;
+
+AudioMixerOut *AudioMixerOut::getInstance(enum MIXER_USAGE usage) {
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ AudioMixerOut *instance;
+
+ if (mInstanceSet.find(usage) == mInstanceSet.end()) {
+ instance = new AudioMixerOut(usage);
+ mInstanceSet.insert({usage, instance});
+ } else {
+ instance = mInstanceSet.find(usage)->second;
+ }
+
+ return instance;
+}
+
+AudioMixerOut::AudioMixerOut(enum MIXER_USAGE usage) :
+ mUsage(usage),
+ mOutThread(0),
+ mDebugType(0) {
+ ALOGD("%s(), usage %d", __FUNCTION__, usage);
+ memset(&mOutInfo, 0, sizeof(struct MixerOutInfo));
+
+ mClients.clear();
+ mClientsLock.clear();
+}
+
+AudioMixerOut::~AudioMixerOut() {
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mClients.size() > 0) {
+ for (size_t i = 0; i < mClients.size(); i++) {
+ detach(mClients.keyAt(i));
+ }
+ }
+
+ AL_AUTOLOCK(mLock);
+
+ mClients.clear();
+
+ for (size_t i = 0; i < mClientsLock.size(); i++) {
+ delete mClientsLock[i];
+ }
+ mClientsLock.clear();
+
+ mInstanceSet.erase(mUsage);
+}
+
+status_t AudioMixerOut::attach(const void *id, const stream_attribute_t *attribute) {
+ status_t status = NO_ERROR;
+
+ ALOGD("+%s(), id %p, flag %d, mClients.size() %zu, mUsage %d",
+ __FUNCTION__, id, attribute->mAudioOutputFlags, mClients.size(), mUsage);
+
+ AL_AUTOLOCK(mLock);
+ AL_AUTOLOCK(mThreadLock);
+
+ // check if already exist
+ ssize_t idx = mClients.indexOfKey(id);
+ if (idx >= 0) {
+ ALOGE("%s(), id %p already exixt, flag %d, mClients.size() %zu",
+ __FUNCTION__, id, attribute->mAudioOutputFlags, mClients.size());
+ ASSERT(0);
+ return INVALID_OPERATION;
+ }
+
+ // create client
+ struct MixerOutClient *client = new MixerOutClient();
+ if (!client) {
+ ALOGE("%s(), new MixerOutClient failed, id %p, flag %d, mClients.size() %zu",
+ __FUNCTION__, id, attribute->mAudioOutputFlags, mClients.size());
+ ASSERT(0);
+ return NO_MEMORY;
+ }
+
+ memset(client, 0, sizeof(struct MixerOutClient));
+
+ client->id = id;
+ client->attribute = *attribute;
+ client->dataBufferLock = new AudioLock();
+
+ // rate, format convert if needed
+ if (mClients.size() > 0) {
+ initBliSrc(client, &mOutInfo);
+ }
+
+ initBitConverter(client, MIX_OUT_MIX_FORMAT);
+
+ // allocate data buffer for client
+ size_t sizePerFrame = getSizePerFrame(MIX_OUT_MIX_FORMAT, attribute->num_channels);
+ size_t dataBufferSize = (attribute->latency * attribute->sample_rate * sizePerFrame) / 1000; // TODO: use latency(int) are not accurate...
+ if (attribute->frame_count * 2 * sizePerFrame > dataBufferSize) {
+ dataBufferSize = attribute->frame_count * 2 * sizePerFrame; // at least, require two buffersize
+ }
+
+ if (client->blisrc) {
+ dataBufferSize *= mOutInfo.attribute.sample_rate;
+ dataBufferSize /= attribute->sample_rate;
+ }
+
+ AL_LOCK(client->dataBufferLock);
+ client->dataBuffer.bufLen = dataBufferSize + RING_BUF_SIZE_OFFSET;
+ client->dataBuffer.pBufBase = new char[client->dataBuffer.bufLen];
+ client->dataBuffer.pRead = client->dataBuffer.pBufBase;
+ client->dataBuffer.pWrite = client->dataBuffer.pBufBase;
+ client->dataBuffer.pBufEnd = client->dataBuffer.pBufBase + client->dataBuffer.bufLen;
+ AL_UNLOCK(client->dataBufferLock);
+
+ if (!client->dataBuffer.pBufBase) {
+ ALOGE("%s(), allocate dataBuffer failed, id %p, flag %d, mClients.size() %zu",
+ __FUNCTION__, id, attribute->mAudioOutputFlags, mClients.size());
+ ASSERT(0);
+ delete client;
+ return NO_MEMORY;
+ }
+
+ ALOGD("%s(), client->dataBuffer.bufLen %d, frame_count %zu, ch %u, rate %u",
+ __FUNCTION__,
+ client->dataBuffer.bufLen,
+ client->attribute.frame_count,
+ attribute->num_channels,
+ attribute->sample_rate);
+
+ // add client
+ mClients.add(client->id, client);
+
+ // open when 1st attach
+ if (mClients.size() == 1) {
+ status = createOutThread();
+ }
+
+ // create client lock if needed, expect id will not change among same stream out(s), e.g. 3 streamout 3 id
+ if (mClientsLock.indexOfKey(id) < 0) {
+ mClientsLock.add(id, new AudioLock);
+ }
+
+ setScreenState_l(&mOutInfo);
+
+ ALOGD("-%s()", __FUNCTION__);
+ return status;
+}
+
+void AudioMixerOut::detach(const void *id) {
+ ALOGD("+%s(), id %p, mClients.size() %zu, mUsage %d",
+ __FUNCTION__, id, mClients.size(), mUsage);
+
+ AL_AUTOLOCK(mLock);
+ ssize_t idx = mClients.indexOfKey(id);
+ if (idx >= 0) {
+ AL_LOCK(mThreadLock);
+
+ AL_LOCK(mClientsLock.valueFor(id));
+
+ deleteClient(mClients[idx]);
+
+ // remove client
+ mClients.removeItem(id);
+
+ AL_UNLOCK(mClientsLock.valueFor(id));
+
+ // remove client lock
+ delete mClientsLock.valueFor(id);
+ mClientsLock.removeItem(id);
+
+ // signal out thread a client is detached
+ AL_LOCK(mWaitOutThreadLock);
+ AL_SIGNAL(mWaitOutThreadLock);
+ AL_UNLOCK(mWaitOutThreadLock);
+
+ setScreenState_l(&mOutInfo);
+
+ AL_UNLOCK(mThreadLock);
+ // destroy out thread when no client attached
+ if (mClients.size() == 0) {
+ destroyOutThread();
+ }
+ } else {
+ ALOGE("%s(), client not found, idx %zd, id %p", __FUNCTION__, idx, id);
+ ASSERT(0);
+ }
+
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+size_t AudioMixerOut::write(const void *id, const void *buffer, size_t bytes) {
+ ALOGV("%s(), bytes %zu, id %p", __FUNCTION__, bytes, id);
+
+ AL_AUTOLOCK(mClientsLock.valueFor(id));
+
+ ssize_t idx = mClients.indexOfKey(id);
+ if (idx < 0) {
+ ALOGE("%s(), client not found, idx %zd, id %p", __FUNCTION__, idx, id);
+ ASSERT(0);
+ return 0;
+ }
+
+ struct MixerOutClient *client = mClients[idx];
+
+ // src
+ // const -> to non const
+ void *pBuffer = const_cast<void *>(buffer);
+ void *pBufferAfterBliSrc = NULL;
+ uint32_t bytesAfterBliSrc = 0;
+ doBliSrc(client,
+ pBuffer, bytes,
+ &pBufferAfterBliSrc, &bytesAfterBliSrc);
+
+ // bit conversion
+ void *pBufferAfterBitConvertion = NULL;
+ uint32_t bytesAfterBitConvertion = 0;
+ doBitConversion(client,
+ pBufferAfterBliSrc, bytesAfterBliSrc,
+ &pBufferAfterBitConvertion, &bytesAfterBitConvertion);
+
+ char *writeBuffer = (char *)pBufferAfterBitConvertion;
+ int writeBytes = bytesAfterBitConvertion;
+
+ AL_LOCK(client->dataBufferLock);
+
+ // check if buffer enough
+ RingBuf_dynamicChangeBufSize(&client->dataBuffer, writeBytes);
+
+ if (writeBytes) {
+ RingBuf_copyFromLinear(&client->dataBuffer, writeBuffer, writeBytes);
+ }
+ AL_UNLOCK(client->dataBufferLock);
+
+ // signal out thread of data written
+ AL_LOCK(mWaitOutThreadLock);
+ AL_SIGNAL(mWaitOutThreadLock);
+ AL_UNLOCK(mWaitOutThreadLock);
+
+ return bytes;
+}
+
+status_t AudioMixerOut::setSuspend(const void *id, bool suspend) {
+ ALOGD("%s(), id %p, suspend %d", __FUNCTION__, id, suspend);
+
+ AL_AUTOLOCK(mWaitSuspendLock);
+ AL_LOCK(mLock);
+
+ ssize_t idx = mClients.indexOfKey(id);
+ if (idx < 0) {
+ ALOGW("%s(), client not found, idx %zd, id %p", __FUNCTION__, idx, id);
+ AL_UNLOCK(mLock);
+ return 0;
+ }
+
+ if (mClients[idx]->suspend == suspend) {
+ ALOGW("%s(), suspend status not changed, suspend %d", __FUNCTION__, suspend);
+ ASSERT(0);
+
+ AL_UNLOCK(mLock);
+ return 0;
+ }
+
+ mClients[idx]->suspend = suspend;
+
+ // wait for close hardware when all client suspend
+ mOutInfo.clientAllSuspend = clientAllSuspend(&mClients);
+
+ AL_UNLOCK(mLock);
+
+ // signal out thread to check suspend status
+ AL_LOCK(mWaitOutThreadLock);
+ AL_SIGNAL(mWaitOutThreadLock);
+ AL_UNLOCK(mWaitOutThreadLock);
+
+ if (mOutInfo.clientAllSuspend) {
+ ALOGD("%s(), all clients suspend, wait for hardware close", __FUNCTION__);
+
+ CLEANUP_PUSH_ALOCK(mWaitSuspendLock.getAlock());
+
+ int waitResult = AL_WAIT_MS(mWaitSuspendLock, 2800);
+
+ if (waitResult != 0) {
+ ALOGW("%s(), waitResult %d", __FUNCTION__, waitResult);
+ ASSERT(0);
+ }
+
+ CLEANUP_POP_ALOCK(mWaitSuspendLock.getAlock());
+ }
+
+ ALOGD("-%s()", __FUNCTION__);
+ return 0;
+}
+
+status_t AudioMixerOut::getHardwareBufferInfo(const void *id, time_info_struct_t *HWBuffer_Time_Info) {
+ AL_AUTOLOCK(mThreadLock);
+ AL_AUTOLOCK(mClientsLock.valueFor(id));
+
+ ssize_t idx = mClients.indexOfKey(id);
+ if (idx < 0) {
+ ALOGE("%s(), client not found, idx %zd, id %p", __FUNCTION__, idx, id);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ struct MixerOutClient *client = mClients[idx];
+
+ if (!mOutInfo.playHandler) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (mOutInfo.playHandler->getHardwareBufferInfo(HWBuffer_Time_Info) != NO_ERROR) {
+ return UNKNOWN_ERROR;
+ } else {
+ size_t outSizePerFrame = getSizePerFrame(MIX_OUT_MIX_FORMAT, mOutInfo.attribute.num_channels);
+ AL_LOCK(client->dataBufferLock);
+ HWBuffer_Time_Info->halQueuedFrame += RingBuf_getDataCount(&client->dataBuffer) / outSizePerFrame;
+ AL_UNLOCK(client->dataBufferLock);
+ }
+ return NO_ERROR;
+}
+
+status_t AudioMixerOut::setScreenState(const void *id, bool mode, size_t bufferSize, size_t reduceInterruptSize, bool force) {
+ AL_AUTOLOCK(mThreadLock);
+ AL_AUTOLOCK(mClientsLock.valueFor(id));
+
+ ssize_t idx = mClients.indexOfKey(id);
+ if (idx < 0) {
+ ALOGE("%s(), client not found, idx %zd, id %p", __FUNCTION__, idx, id);
+ return UNKNOWN_ERROR;
+ }
+
+ struct MixerOutClient *client = mClients[idx];
+
+ client->screenMode = mode;
+ client->screenBufferSize = bufferSize;
+ client->screenReduceInterruptSize = reduceInterruptSize;
+ client->screenForce = force;
+
+ // will decide which client's param to use in setScreenState_l
+ return setScreenState_l(&mOutInfo);
+}
+
+status_t AudioMixerOut::setScreenState_l(struct MixerOutInfo *info) {
+ ASSERT(AL_TRYLOCK(info->threadLock) != 0);
+
+ status_t ret = NO_ERROR;
+
+ // bt don't need set screen
+ if (info->usage == MIXER_USAGE_BT) {
+ return 0;
+ }
+
+ // decide among clinets
+ bool useMinBufferSize = true;
+
+ if (info->clients->size() == 1) {
+ struct MixerOutClient *client = info->clients->valueAt(0);
+
+ if (client->attribute.mAudioOutputFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
+ useMinBufferSize = false;
+ info->screenMode = client->screenMode;
+ info->screenBufferSize = client->screenBufferSize;
+ info->screenReduceInterruptSize = client->screenReduceInterruptSize;
+ info->screenForce = client->screenForce;
+ }
+ }
+
+ if (useMinBufferSize) {
+ // interrupt period use buffer size
+ info->screenMode = true;
+
+ // get minimum buffer size
+ info->screenBufferSize = std::numeric_limits<size_t>::max();
+ for (size_t i = 0; i < info->clients->size(); i++) {
+ struct MixerOutClient *client = info->clients->valueAt(i);
+
+ if (client->screenBufferSize < info->screenBufferSize) {
+ info->screenBufferSize = client->screenBufferSize;
+ }
+ }
+ }
+
+ if (info->screenBufferSize == 0) {
+ return NO_ERROR;
+ }
+
+ if (info->playHandler) {
+ ret = info->playHandler->setScreenState(info->screenMode,
+ info->screenBufferSize,
+ info->screenReduceInterruptSize,
+ info->screenForce);
+ if (ret == NO_ERROR && info->playHandler2) {
+ ret = info->playHandler2->setScreenState(info->screenMode,
+ info->screenBufferSize,
+ info->screenReduceInterruptSize,
+ info->screenForce);
+ }
+ }
+
+ return ret;
+}
+
+int AudioMixerOut::getLatency() {
+ AL_AUTOLOCK(mThreadLock);
+
+ if (!mOutInfo.playHandler)
+ return -EPERM;
+
+ int latency = mOutInfo.playHandler->getLatency();
+
+ if (latency <= 0) {
+ const stream_attribute_t *pStreamAttributeTarget = mOutInfo.playHandler->getStreamAttributeTarget();
+ latency = getBufferLatencyMs(pStreamAttributeTarget, pStreamAttributeTarget->buffer_size);
+ }
+
+ return latency;
+}
+
+status_t AudioMixerOut::createOutThread() {
+ ALOGD("+%s(), mOutInfo %p", __FUNCTION__, &mOutInfo);
+
+ // initialize mixer out info
+ memset(&mOutInfo, 0, sizeof(struct MixerOutInfo));
+
+ mOutInfo.id = &mOutInfo;
+ mOutInfo.usage = mUsage;
+ mOutInfo.attribute = mClients[0]->attribute;
+ mOutInfo.attribute.isMixerOut = true;
+
+ if (mUsage == MIXER_USAGE_BT) {
+ mOutInfo.minWriteFrameCnt = 512; // limitation from SWIP
+ mOutInfo.attribute.mAudioOutputFlags = (audio_output_flags_t)(mOutInfo.attribute.mAudioOutputFlags & (~AUDIO_OUTPUT_FLAG_FAST));
+ mOutInfo.attribute.mAudioOutputFlags = (audio_output_flags_t)(mOutInfo.attribute.mAudioOutputFlags & (~AUDIO_OUTPUT_FLAG_DEEP_BUFFER));
+ } else if (mUsage == MIXER_USAGE_DEEP_FAST) {
+ mOutInfo.attribute.mAudioOutputFlags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+ } else if (mUsage == MIXER_USAGE_SMARTPA) {
+ mOutInfo.attribute.mAudioOutputFlags = (audio_output_flags_t)(mOutInfo.attribute.mAudioOutputFlags | AUDIO_OUTPUT_FLAG_FAST);
+ }
+
+ mOutInfo.threadLock = &mThreadLock;
+ mOutInfo.waitSuspendLock = &mWaitSuspendLock;
+ mOutInfo.waitOutThreadLock = &mWaitOutThreadLock;
+
+ mOutInfo.clients = &mClients;
+ mOutInfo.clientAllSuspend = false;
+
+ mOutInfo.readBufferTimeUs = mOutInfo.attribute.frame_count * 1000 * 1000 / mOutInfo.attribute.sample_rate;
+
+ initBitConverter(&mOutInfo, MIX_OUT_MIX_FORMAT);
+
+ // set debug info
+ char value[PROPERTY_VALUE_MAX];
+ property_get(MIX_OUT_DEBUG, value, "0");
+ mDebugType = atoi(value);
+
+ // create output thread
+ int ret = pthread_create(&mOutThread, NULL, AudioMixerOut::outThread, &mOutInfo);
+ if (ret) {
+ ALOGE("%s() create outThread fail, ret = %d!!", __FUNCTION__, ret);
+ ASSERT(0);
+ }
+ ret = pthread_setname_np(mOutThread, "audio_mixer_out");
+ if (ret) {
+ ALOGW("%s(), set mOutThread name fail", __FUNCTION__);
+ }
+
+ ALOGD("-%s(), ret %d, output flag %d", __FUNCTION__,
+ ret, mOutInfo.attribute.mAudioOutputFlags);
+ return ret;
+}
+
+void AudioMixerOut::destroyOutThread() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ int ret;
+ void *retval;
+
+ // pthread_join
+ ret = pthread_join(mOutThread, &retval);
+ if (ret) {
+ ALOGE("%s(), mOutThread pthread_join fail, ret = %d", __FUNCTION__, ret);
+ ASSERT(0);
+ }
+
+ deinitBitConverter(&mOutInfo);
+
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+void AudioMixerOut::deleteClient(struct MixerOutClient *client) {
+ // clean client
+ if (client->dataBuffer.pBufBase != NULL) {
+ delete [] client->dataBuffer.pBufBase;
+ }
+
+ if (client->dataBufferLock != NULL) {
+ delete client->dataBufferLock;
+ }
+
+ deinitBitConverter(client);
+ deinitBliSrc(client);
+
+ // delete client
+ delete client;
+}
+
+void *AudioMixerOut::outThread(void *arg) {
+ struct MixerOutInfo *info = (struct MixerOutInfo *)arg;
+ MixerOutClientVector *clients = info->clients;
+ int ret = 0;
+
+ ALOGD("+%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+
+ AudioALSAStreamManager *streamManager = AudioALSAStreamManager::getInstance();
+ info->playHandler= NULL;
+ info->playHandler2 = NULL;
+ struct mixer *mixer = AudioALSADriverUtility::getInstance()->getMixer();
+
+ if (!streamManager) {
+ ALOGD("-%s(), streamManager == NULL, pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ ASSERT(0);
+ return NULL;
+ }
+
+ // data pending buf
+ RingBuf pendingBuf;
+ pendingBuf.bufLen = 0x10000; // 64k
+ pendingBuf.pBufBase = new char[pendingBuf.bufLen];
+ pendingBuf.pRead = pendingBuf.pBufBase;
+ pendingBuf.pWrite = pendingBuf.pBufBase;
+
+ if (!pendingBuf.pBufBase) {
+ ALOGE("%s(), allocate pendingBuf failed", __FUNCTION__);
+ ASSERT(0);
+ }
+
+ bool isBtMerge = WCNChipController::GetInstance()->IsBTMergeInterfaceSupported();
+
+ FILE *pcmMixedDumpFile = mixerOutDumpOpen(MIX_OUT_DUMP_NAME, streamout_propty);
+
+ char *inDataBuffer = NULL;
+ char *outDataBuffer = NULL;
+ size_t outDataBufferSize = 0;
+
+ char *tempWriteBuf = NULL;
+ size_t tempWriteBufSize = 0;
+
+ do {
+ AL_LOCK(info->threadLock);
+
+ if (clients->size() == 0) {
+ AL_UNLOCK(info->threadLock);
+ break;
+ }
+
+ // handle all suspend
+ if (info->clientAllSuspend) {
+ destroyPlaybackHandler(info->playHandler, streamManager);
+ info->playHandler = NULL;
+ destroyPlaybackHandler(info->playHandler2, streamManager);
+ info->playHandler2 = NULL;
+
+ AL_SIGNAL(info->waitSuspendLock);
+
+ AL_UNLOCK(info->threadLock);
+
+ // sleep until state change signal
+ int waitResult = waitSignal(info->waitOutThreadLock, 100 * 1000,
+ "out, all suspend, wait state change signal");
+
+ if (waitResult != 0) {
+ ALOGW("%s(), waitResult %d", __FUNCTION__, waitResult);
+ }
+
+ continue;
+ }
+
+ // determine read frame count
+ size_t readBufferFrameCount = std::numeric_limits<size_t>::max();
+ for (size_t i = 0; i < clients->size(); i++) {
+ struct MixerOutClient *client = clients->valueAt(i);
+
+ if (client->attribute.frame_count == 0) {
+ ALOGE("%s(), client id %p, frame_count == 0", __FUNCTION__, client->id);
+ ASSERT(0);
+ continue;
+ }
+
+ if (client->attribute.frame_count < readBufferFrameCount) {
+ readBufferFrameCount = client->attribute.frame_count;
+ }
+ }
+
+ info->readBufferTimeUs = readBufferFrameCount * 1000 * 1000 / info->attribute.sample_rate;
+
+ size_t outSizePerFrame = getSizePerFrame(MIX_OUT_MIX_FORMAT, info->attribute.num_channels);
+ unsigned int readBufferSize = readBufferFrameCount * outSizePerFrame;
+
+ // check if data enough
+ unsigned int waitDataTimeUs = 0;
+ for (size_t i = 0; i < clients->size(); i++) {
+ struct MixerOutClient *client = clients->valueAt(i);
+ AL_LOCK(client->dataBufferLock);
+ unsigned int availDataSize = RingBuf_getDataCount(&client->dataBuffer);
+ AL_UNLOCK(client->dataBufferLock);
+
+ if (availDataSize < readBufferSize && !client->suspend) {
+ waitDataTimeUs = (readBufferSize - availDataSize) * 1000 * 1000 / outSizePerFrame / info->attribute.sample_rate;
+ //ALOGD("%s(), waitDataTimeUs %u, readBufferSize %u, availDataSize %u, outSizePerFrame %zu, freeSpace %d, dataCount %d",
+ // __FUNCTION__, waitDataTimeUs, readBufferSize, availDataSize, outSizePerFrame,
+ // RingBuf_getFreeSpace(&client->dataBuffer), RingBuf_getDataCount(&client->dataBuffer));
+ break;
+ }
+ }
+
+ // wait for data if needed
+ if (waitDataTimeUs) {
+ AL_UNLOCK(info->threadLock);
+
+ int waitResult = waitSignal(info->waitOutThreadLock, waitDataTimeUs,
+ "out, wait for avail data");
+
+ if (waitResult != 0) {
+ ALOGW("%s(), waitResult %d, waitDataTimeUs %u", __FUNCTION__, waitResult, waitDataTimeUs);
+ }
+
+ continue;
+ }
+
+ // prepare out buffer
+ if (outDataBufferSize < readBufferSize) {
+ if (outDataBuffer) {
+ delete[] outDataBuffer;
+ }
+
+ outDataBuffer = new char[readBufferSize];
+ outDataBufferSize = readBufferSize;
+
+ if (inDataBuffer) {
+ delete[] inDataBuffer;
+ }
+
+ inDataBuffer = new char[readBufferSize];
+ }
+
+ if (!outDataBuffer) {
+ ALOGE("%s(), outDataBuffer == NULL, outDataBufferSize %zu, readBufferSize %u",
+ __FUNCTION__, outDataBufferSize, readBufferSize);
+ ASSERT(0);
+ AL_UNLOCK(info->threadLock);
+ continue;
+ }
+
+ memset(outDataBuffer, 0, readBufferSize);
+
+ // mix data
+ float *mixBuffer = (float *)outDataBuffer;
+ unsigned int mixBufferSize = readBufferSize;
+ unsigned int mixBufferCount = mixBufferSize / audio_bytes_per_sample(MIX_OUT_MIX_FORMAT);
+
+ for (size_t c = 0; c < clients->size(); c++) {
+ struct MixerOutClient *client = clients->valueAt(c);
+
+ if (client->suspend) {
+ continue;
+ }
+
+ AL_LOCK(client->dataBufferLock);
+ RingBuf_copyToLinear(inDataBuffer, &client->dataBuffer, mixBufferSize);
+ AL_UNLOCK(client->dataBufferLock);
+
+ float *tempBuffer = (float *)inDataBuffer;
+
+ for (unsigned int i = 0; i < mixBufferCount; i++) {
+ mixBuffer[i] += tempBuffer[i];
+ }
+ }
+
+ // open playback handler
+ if (info->playHandler == NULL) {
+ info->playHandler = streamManager->createPlaybackHandler(&info->attribute);
+ info->playHandler->open();
+ info->playHandler->setFirstDataWriteFlag(true);
+
+ if (isBtSpkDevice(info->attribute.output_devices)) {
+ info->attribute2 = info->attribute;
+ info->attribute2.output_devices = AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+ info->playHandler2 = streamManager->createPlaybackHandler(&info->attribute2);
+ info->playHandler2->open();
+ info->playHandler2->setFirstDataWriteFlag(true);
+ }
+
+ setScreenState_l(info);
+ } else {
+ info->playHandler->setFirstDataWriteFlag(false);
+ if (info->playHandler2) {
+ info->playHandler2->setFirstDataWriteFlag(false);
+ }
+ }
+
+ AL_UNLOCK(info->threadLock);
+
+ // insure minimum frame count
+ // minWriteFrameCnt default is zero and set it if needed
+ if (pendingBuf.pBufBase != NULL &&
+ (readBufferFrameCount < info->minWriteFrameCnt || RingBuf_getDataCount(&pendingBuf) != 0)) {
+
+ RingBuf_copyFromLinear(&pendingBuf, (char *)mixBuffer, mixBufferSize);
+
+ size_t dataSize = RingBuf_getDataCount(&pendingBuf);
+
+ if (dataSize < info->minWriteFrameCnt * outSizePerFrame) {
+ continue;
+ } else {
+ // calculate write size, should be the multiple of min frame count
+ size_t remainDataSize = dataSize % (info->minWriteFrameCnt * outSizePerFrame);
+ mixBufferSize = remainDataSize == 0 ? dataSize : (dataSize - remainDataSize);
+
+ if (RingBuf_checkDataCrossBoundary(&pendingBuf, mixBufferSize) == 0) {
+ // direct use ring buf buffer
+ mixBuffer = (float *)pendingBuf.pRead;
+
+ RingBuf_discardData(&pendingBuf, mixBufferSize);
+ } else {
+ // copy to new
+ if (tempWriteBufSize < mixBufferSize) {
+ if (tempWriteBuf) {
+ delete[] tempWriteBuf;
+ }
+
+ tempWriteBuf = new char[mixBufferSize];
+ tempWriteBufSize = mixBufferSize;
+ }
+ RingBuf_copyToLinear(tempWriteBuf, &pendingBuf, mixBufferSize);
+ mixBuffer = (float *)tempWriteBuf;
+ }
+ }
+ }
+
+// ALOGD("%s(), pRead %p, pbase %p, diff %ld, mixBufferSize %u",
+// __FUNCTION__, pendingBuf.pRead, pendingBuf.pBufBase, (long)(pendingBuf.pRead - pendingBuf.pBufBase), mixBufferSize);
+
+ // write
+ void *pBufferAfterBitConvertion = NULL;
+ uint32_t bytesAfterBitConvertion = 0;
+ doBitConversion(info,
+ mixBuffer, mixBufferSize,
+ &pBufferAfterBitConvertion, &bytesAfterBitConvertion);
+
+ char *writeBuffer = (char *)pBufferAfterBitConvertion;
+ int writeBytes = bytesAfterBitConvertion;
+
+ info->playHandler->write(writeBuffer, writeBytes); // TODO: propagate return value back up?
+
+ if (info->playHandler2) {
+#ifdef MTK_SUPPORT_BTCVSD_ALSA
+ bool skipWrite = false;
+ if (!isBtMerge) {
+ // check if timeout during write bt data
+ struct mixer_ctl *ctl = mixer_get_ctl_by_name(mixer, "btcvsd_tx_timeout");
+ int index = mixer_ctl_get_value(ctl, 0);
+ skipWrite = index != 0;
+ }
+
+ if (!skipWrite)
+#endif
+ {
+ info->playHandler2->write(writeBuffer, writeBytes);
+ }
+ }
+
+ mixerOutDumpWriteData(pcmMixedDumpFile, writeBuffer, writeBytes);
+
+ if (pendingBuf.pBufBase != NULL) {
+ pendingBuf.pRead = pendingBuf.pBufBase;
+ pendingBuf.pWrite = pendingBuf.pBufBase;
+ }
+ } while (clients->size() > 0);
+
+ destroyPlaybackHandler(info->playHandler, streamManager);
+ info->playHandler = NULL;
+ destroyPlaybackHandler(info->playHandler2, streamManager);
+ info->playHandler2 = NULL;
+
+ AL_SIGNAL(info->waitSuspendLock);
+
+ if (outDataBuffer) {
+ delete[] outDataBuffer;
+ }
+
+ if (inDataBuffer) {
+ delete[] inDataBuffer;
+ }
+
+ mixerOutDumpClose(pcmMixedDumpFile);
+
+ if (pendingBuf.pBufBase != NULL) {
+ delete [] pendingBuf.pBufBase;
+ }
+
+ ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ return NULL;
+}
+
+int AudioMixerOut::destroyPlaybackHandler(AudioALSAPlaybackHandlerBase *playbackHandler,
+ AudioALSAStreamManager *streamManager) {
+ status_t status = 0;
+
+ if (playbackHandler) {
+ status = playbackHandler->close();
+ if (status != NO_ERROR) {
+ ALOGE("%s(), playbackHandler->close() fail!!", __FUNCTION__);
+ ASSERT(0);
+ }
+
+ // destroy playback handler
+ streamManager->destroyPlaybackHandler(playbackHandler);
+ playbackHandler = NULL;
+ }
+
+ return status;
+}
+
+bool AudioMixerOut::clientAllSuspend(const MixerOutClientVector *clients) {
+ for (size_t i = 0; i < clients->size(); i++) {
+ if (!clients->valueAt(i)->suspend) {
+ return false;
+ }
+ }
+ return true;
+}
+
+int AudioMixerOut::waitSignal(AudioLock *mWaitLock, unsigned int waitTimeUs, const char *dbgString __unused) {
+ int waitResult;
+
+ // sleep until signalled
+ CLEANUP_PUSH_ALOCK(mWaitLock->getAlock());
+ AL_LOCK(mWaitLock);
+
+ //ALOGD("%s(), %s, waitTimeUs %u", __FUNCTION__, dbgString, waitTimeUs);
+
+ waitTimeUs = (waitTimeUs < 1000) ? 1000 : waitTimeUs; // TODO: add AL_WAIT_US API?
+ waitResult = AL_WAIT_MS(mWaitLock, waitTimeUs / 1000);
+
+ AL_UNLOCK(mWaitLock);
+ CLEANUP_POP_ALOCK(mWaitLock->getAlock());
+
+ return waitResult;
+}
+
+// dump file
+FILE *AudioMixerOut::mixerOutDumpOpen(const char *name, const char *property) {
+ static unsigned int dumpFileCount = 0;
+
+ ALOGV("%s()", __FUNCTION__);
+ FILE *file = NULL;
+ char dumpFileName[128];
+ sprintf(dumpFileName, "%s.%s.%u.pid%d.tid%d.pcm", MIX_OUT_DUMP_FILE_PREFIX, name, dumpFileCount, getpid(), gettid());
+
+ file = NULL;
+ file = AudioOpendumpPCMFile(dumpFileName, property);
+
+ if (file != NULL) {
+ ALOGD("%s DumpFileName = %s", __FUNCTION__, dumpFileName);
+
+ dumpFileCount++;
+ dumpFileCount %= MAX_DUMP_NUM;
+ }
+
+ return file;
+}
+
+void AudioMixerOut::mixerOutDumpClose(FILE *file) {
+ ALOGV("%s()", __FUNCTION__);
+ if (file) {
+ AudioCloseDumpPCMFile(file);
+ ALOGD("%s(), close it", __FUNCTION__);
+ }
+}
+
+void AudioMixerOut::mixerOutDumpWriteData(FILE *file, const void *buffer, size_t bytes) {
+ if (file) {
+ AudioDumpPCMData((void *)buffer, bytes, file);
+ }
+}
+
+static const uint32_t kBliSrcOutputBufferSize = 0x10000; // 64k
+status_t AudioMixerOut::initBliSrc(struct MixerOutClient *client, const struct MixerOutInfo *outInfo) {
+ unsigned int sourceRate, targetRate;
+ unsigned int sourceChannels, targetChannels;
+ audio_format_t format;
+
+ sourceRate = client->attribute.sample_rate;
+ sourceChannels = client->attribute.num_channels;
+ format = client->attribute.audio_format;
+
+ targetRate = outInfo->attribute.sample_rate;
+ targetChannels = outInfo->attribute.num_channels;
+
+ if (sourceRate != targetRate || sourceChannels != targetChannels) {
+ ALOGD("%s(), flag %d, sample_rate: %d => %d, num_channels: %d => %d, mStreamAttributeSource->audio_format: 0x%x",
+ __FUNCTION__, client->attribute.mAudioOutputFlags,
+ sourceRate, targetRate, sourceChannels, targetChannels, format);
+
+ SRC_PCM_FORMAT src_pcm_format = SRC_IN_Q1P15_OUT_Q1P15;
+ if (format == AUDIO_FORMAT_PCM_32_BIT) {
+ src_pcm_format = SRC_IN_Q1P31_OUT_Q1P31;
+ } else if (format == AUDIO_FORMAT_PCM_16_BIT) {
+ src_pcm_format = SRC_IN_Q1P15_OUT_Q1P15;
+ } else {
+ ALOGE("%s(), not support mStreamAttributeSource->audio_format(0x%x) SRC!!", __FUNCTION__, format);
+ ASSERT(0);
+ }
+
+ client->blisrc = newMtkAudioSrc(sourceRate, sourceChannels,
+ targetRate, targetChannels,
+ src_pcm_format);
+ ASSERT(client->blisrc != NULL);
+ client->blisrc->open();
+
+ client->blisrcOutBuffer = new char[kBliSrcOutputBufferSize];
+ ASSERT(client->blisrcOutBuffer != NULL);
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioMixerOut::deinitBliSrc(struct MixerOutClient *client) {
+ // deinit BLI SRC if need
+ if (client->blisrc != NULL) {
+ client->blisrc->close();
+ delete client->blisrc;
+ client->blisrc = NULL;
+ }
+
+ if (client->blisrcOutBuffer != NULL) {
+ delete[] client->blisrcOutBuffer;
+ client->blisrcOutBuffer = NULL;
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioMixerOut::doBliSrc(struct MixerOutClient *client, void *pInBuffer, uint32_t inBytes,
+ void **ppOutBuffer, uint32_t *pOutBytes) {
+ if (client->blisrc == NULL) { // No need SRC
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ } else {
+ char *p_read = (char *)pInBuffer;
+ uint32_t num_raw_data_left = inBytes;
+ uint32_t num_converted_data = kBliSrcOutputBufferSize; // max convert num_free_space
+
+ uint32_t consumed = num_raw_data_left;
+ client->blisrc->process((int16_t *)p_read, &num_raw_data_left,
+ (int16_t *)client->blisrcOutBuffer, &num_converted_data);
+ consumed -= num_raw_data_left;
+ p_read += consumed;
+
+ ALOGV("%s(), num_raw_data_left = %u, num_converted_data = %u",
+ __FUNCTION__, num_raw_data_left, num_converted_data);
+
+ if (num_raw_data_left > 0) {
+ ALOGW("%s(), num_raw_data_left(%u) > 0", __FUNCTION__, num_raw_data_left);
+ ASSERT(num_raw_data_left == 0);
+ }
+
+ *ppOutBuffer = client->blisrcOutBuffer;
+ *pOutBytes = num_converted_data;
+ }
+
+ ASSERT(*ppOutBuffer != NULL && *pOutBytes != 0);
+ return NO_ERROR;
+}
+
+unsigned int AudioMixerOut::getBitConvertDstBufferSize(audio_format_t dstFmt,
+ audio_format_t srcFmt,
+ unsigned int srcBufSizeByte) {
+ size_t dstFmtByte = audio_bytes_per_sample(dstFmt);
+ size_t srcFmtByte = audio_bytes_per_sample(srcFmt);
+
+ if (dstFmtByte == 0) {
+ ALOGE("%s(), invalid dstFmt %d, dstFmtByte = %zu", __FUNCTION__, dstFmt, dstFmtByte);
+ ASSERT(0);
+ dstFmtByte = audio_bytes_per_sample(AUDIO_FORMAT_PCM_16_BIT);
+ }
+
+ if (srcFmtByte == 0) {
+ ALOGE("%s(), invalid srcFmt %d, srcFmtByte = %zu", __FUNCTION__, srcFmt, srcFmtByte);
+ ASSERT(0);
+ srcFmtByte = audio_bytes_per_sample(AUDIO_FORMAT_PCM_16_BIT);
+ }
+
+ return (srcBufSizeByte * dstFmtByte) / srcFmtByte;
+}
+
+static const uint32_t kMaxBitConvertBufferSize = 0x10000; // 64k
+status_t AudioMixerOut::initBitConverter(struct MixerOutClient *client, audio_format_t dstFmt) {
+ return initBitConverter(client, client->attribute.audio_format, dstFmt);
+}
+
+status_t AudioMixerOut::initBitConverter(struct MixerOutInfo *info, audio_format_t srcFmt) {
+ return initBitConverter(info, srcFmt, info->attribute.audio_format);
+}
+
+template<class T>
+status_t AudioMixerOut::initBitConverter(T *client, audio_format_t srcFmt, audio_format_t dstFmt) {
+ client->srcFmt = srcFmt;
+ client->dstFmt = dstFmt;
+
+ // init bit converter if need
+ if (client->srcFmt != client->dstFmt) {
+ ALOGD("%s(), id %p, format: 0x%x => 0x%x, size %zu => %zu",
+ __FUNCTION__, client->id, client->srcFmt, client->dstFmt,
+ audio_bytes_per_sample(client->srcFmt), audio_bytes_per_sample(client->dstFmt));
+ client->bitConvertBuffer = new char[kMaxBitConvertBufferSize];
+ }
+
+ return NO_ERROR;
+}
+
+template<class T>
+status_t AudioMixerOut::deinitBitConverter(T *client) {
+ // deinit bit converter if need
+ if (client->bitConvertBuffer != NULL) {
+ delete[] client->bitConvertBuffer;
+ client->bitConvertBuffer = NULL;
+ }
+
+ return NO_ERROR;
+}
+
+template<class T>
+status_t AudioMixerOut::doBitConversion(T *client,
+ void *pInBuffer, uint32_t inBytes,
+ void **ppOutBuffer, uint32_t *pOutBytes) {
+ if (client->bitConvertBuffer != NULL) {
+ audio_format_t dstFmt = client->dstFmt;
+ audio_format_t srcFmt = client->srcFmt;
+ unsigned int srcSizeBytes = inBytes;
+
+ size_t srcFmtByte = audio_bytes_per_sample(srcFmt);
+ if (srcFmtByte == 0) {
+ ALOGE("%s(), flag %d, invalid srcFmt %d, srcFmtByte = %zu",
+ __FUNCTION__, client->attribute.mAudioOutputFlags, srcFmt, srcFmtByte);
+ ASSERT(0);
+ srcFmtByte = audio_bytes_per_sample(AUDIO_FORMAT_PCM_16_BIT);
+ }
+ unsigned int srcNumSample = srcSizeBytes / srcFmtByte;
+ void *srcBuffer = pInBuffer;
+ unsigned int bitConvertBufferSizeByte = getBitConvertDstBufferSize(dstFmt, srcFmt, srcSizeBytes);
+
+ ALOGV("%s(), bit convert, format: 0x%x => 0x%x, srcNumSample %d, src size %d, dst size %d",
+ __FUNCTION__, srcFmt, dstFmt, srcNumSample, srcSizeBytes, bitConvertBufferSizeByte);
+
+ memcpy_by_audio_format(client->bitConvertBuffer,
+ dstFmt,
+ srcBuffer,
+ srcFmt,
+ srcNumSample);
+
+ *pOutBytes = bitConvertBufferSizeByte;
+ *ppOutBuffer = client->bitConvertBuffer;
+ } else {
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ }
+
+ ASSERT(*ppOutBuffer != NULL && *pOutBytes != 0);
+ return NO_ERROR;
+}
+
+}
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioPreProcess.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioPreProcess.cpp
new file mode 100644
index 0000000..7697b3f
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioPreProcess.cpp
@@ -0,0 +1,813 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sched.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <cutils/properties.h>
+#include "AudioPreProcess.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+
+#define LOG_TAG "AudioPreProcess"
+
+namespace android {
+static FILE *pEchoRefFile = NULL;
+
+AudioPreProcess::AudioPreProcess(const stream_attribute_t *streamIn_attribute) :
+ mStreamInAttribute(streamIn_attribute) {
+
+#ifdef CONFIG_MT_ENG_BUILD
+ mLogEnable = 1;
+#else
+ mLogEnable = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);
+#endif
+
+ ALOGD_IF(mLogEnable, "%s()+", __FUNCTION__);
+
+ //Mutex::Autolock lock(mLock);
+ AL_AUTOLOCK(mLock);
+
+ num_preprocessors = 0;;
+ need_echo_reference = false;
+
+ proc_buf_in = NULL;
+ proc_buf_out = NULL;
+ proc_buf_size = 0;
+ proc_buf_frames = 0;
+
+ ref_buf = NULL;
+ ref_buf_size = 0;
+ ref_buf_frames = 0;
+
+ mEcho_Reference = NULL;
+
+ for (int i = 0; i < MAX_PREPROCESSORS; i++)
+ preprocessors[i] = {0, 0, 0, 0};
+
+ mInChn = 0;
+ mInSampleRate = 16000;
+
+ mAudioSpeechEnhanceInfoInstance = AudioSpeechEnhanceInfo::getInstance();
+ if (!mAudioSpeechEnhanceInfoInstance) {
+ ALOGE("%s() mAudioSpeechEnhanceInfoInstance get fail", __FUNCTION__);
+ }
+
+ //time_info_struct_t mTime_Info;
+ memset((void *)&mTime_Info, 0, sizeof(time_info_struct_t));
+ memset((void *)&mTime_Info_echoref, 0, sizeof(time_info_struct_t));
+ ALOGD_IF(mLogEnable, "%s()-", __FUNCTION__);
+}
+
+
+AudioPreProcess::~AudioPreProcess() {
+ ALOGD_IF(mLogEnable, "%s()+", __FUNCTION__);
+ //MutexLock();
+ AL_AUTOLOCK(mLock);
+
+ if (proc_buf_in) {
+ free(proc_buf_in);
+ proc_buf_in = NULL;
+ }
+ /*
+ if(proc_buf_out)
+ free(proc_buf_out);
+ */
+ if (ref_buf) {
+ free(ref_buf);
+ ref_buf = NULL;
+ }
+
+ //MutexUnlock();
+ if (mEcho_Reference != NULL) {
+ stop_echo_reference(mEcho_Reference);
+ }
+
+ ALOGD_IF(mLogEnable, "%s()-", __FUNCTION__);
+}
+
+status_t AudioPreProcess::CheckNativeEffect(void) {
+ if (mStreamInAttribute->NativePreprocess_Info.PreProcessEffect_Update == true) {
+ ALOGD_IF(mLogEnable, "%s()+ %d using PreProcessEffect_Count %d", __FUNCTION__, num_preprocessors, mStreamInAttribute->NativePreprocess_Info.PreProcessEffect_Count);
+ bool bRemoveEffectMatch = false;
+ bool bAddEffectMatch = false;
+ //check if effect need remove
+ do {
+ bRemoveEffectMatch = false;
+ if (mStreamInAttribute->NativePreprocess_Info.PreProcessEffect_Count == 0) { //no effect is enabled
+ //remove all effect
+ ALOGD("%s(), remove all effect %d", __FUNCTION__, num_preprocessors);
+ for (int i = 0; i < num_preprocessors; i++) {
+ removeAudioEffect(preprocessors[i].effect_itfe);
+ bRemoveEffectMatch = true;
+ break;
+ }
+ } else {
+ for (int i = 0; i < num_preprocessors; i++) {
+ for (int j = 0; j < mStreamInAttribute->NativePreprocess_Info.PreProcessEffect_Count; j++) {
+ if (preprocessors[i].effect_itfe == mStreamInAttribute->NativePreprocess_Info.PreProcessEffect_Record[j]) {
+ //find match effect which still needed
+ break;
+ }
+ if (j == (mStreamInAttribute->NativePreprocess_Info.PreProcessEffect_Count - 1)) { //no match effect find, need to remove this effect
+ //remove effect in i
+ ALOGD("%s(), find effect need remove", __FUNCTION__);
+ removeAudioEffect(preprocessors[i].effect_itfe);
+ bRemoveEffectMatch = true;
+ }
+ }
+ if (bRemoveEffectMatch) {
+ break;
+ }
+ }
+ }
+ } while (bRemoveEffectMatch);
+
+
+ //add effect
+ do {
+ bAddEffectMatch = false;
+ if (num_preprocessors == 0) { //if there is no effect active, all new effect need added
+ for (int i = 0; i < mStreamInAttribute->NativePreprocess_Info.PreProcessEffect_Count; i++) {
+ //add effect in i
+ addAudioEffect(mStreamInAttribute->NativePreprocess_Info.PreProcessEffect_Record[i]);
+ }
+ } else {
+ for (int i = 0; i < mStreamInAttribute->NativePreprocess_Info.PreProcessEffect_Count; i++) {
+ for (int j = 0; j < num_preprocessors; j++) {
+ if (preprocessors[j].effect_itfe == mStreamInAttribute->NativePreprocess_Info.PreProcessEffect_Record[i]) {
+ //find match effect which already added
+ break;
+ }
+ if (j == (num_preprocessors - 1)) { //no match effect find, need to add this effect
+ //add effect in
+ ALOGD("%s(), find effect need add", __FUNCTION__);
+ addAudioEffect(mStreamInAttribute->NativePreprocess_Info.PreProcessEffect_Record[i]);
+ bAddEffectMatch = true;
+ }
+ }
+ if (bAddEffectMatch) {
+ break;
+ }
+ }
+ }
+ } while (bAddEffectMatch);
+
+ ALOGD_IF(mLogEnable, "%s()-", __FUNCTION__);
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPreProcess::addAudioEffect(effect_handle_t effect) {
+ ALOGD("%s()+ %p", __FUNCTION__, effect);
+
+ AL_AUTOLOCK(mLock);
+
+ status_t RetStatus = -EINVAL;
+ effect_descriptor_t desc;
+ int i;
+
+ if (num_preprocessors >= MAX_PREPROCESSORS) {
+ RetStatus = -ENOSYS;
+ ALOGD("%s(), exceed the uplimit", __FUNCTION__);
+ goto exit;
+ }
+
+ RetStatus = (*effect)->get_descriptor(effect, &desc);
+ if (RetStatus != 0) {
+ goto exit;
+ }
+
+ for (i = 0; i < num_preprocessors; i++) {
+ if (preprocessors[i].effect_itfe == effect) {
+ ALOGD("%s() already found %s at index %d", __FUNCTION__, desc.name, i);
+ RetStatus = -ENOSYS;
+ goto exit;
+ }
+ }
+
+ preprocessors[num_preprocessors].effect_itfe = effect;
+ preprocessors[num_preprocessors].enable = true;
+
+ if (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) {
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ /* For aurisys architecture, disable google AEC effect and using MTK Record AEC processing instead */
+ preprocessors[num_preprocessors].enable = false;
+#else
+ /* Enable google AEC effect */
+ need_echo_reference = true;
+ ALOGD("find AEC: %p", mEcho_Reference);
+ if (mEcho_Reference == NULL) {
+ ALOGD("open AEC even record is already start");
+ mEcho_Reference = start_echo_reference(
+ AUDIO_FORMAT_PCM_16_BIT,
+ mStreamInAttribute->num_channels,
+ mStreamInAttribute->sample_rate);
+ }
+ in_configure_reverse(mStreamInAttribute->num_channels, mStreamInAttribute->sample_rate);
+#endif
+ }
+
+ /* add the supported channel of the effect in the channel_configs */
+ //in_read_audio_effect_channel_configs(&preprocessors[num_preprocessors]);
+
+ num_preprocessors++;
+
+ ALOGD("%s(), effect type: %08x, effect name:%s", __FUNCTION__, desc.type.timeLow, desc.name);
+ ALOGD("%s(), StreamInAttributeinfo num_channels=%d, audio_channel_mask=%x, sample_rate=%d", __FUNCTION__,
+ mStreamInAttribute->num_channels, mStreamInAttribute->audio_channel_mask, mStreamInAttribute->sample_rate);
+
+exit:
+ ALOGD("%s()-, RetStatus=%d", __FUNCTION__, RetStatus);
+ return RetStatus;
+}
+
+status_t AudioPreProcess::removeAudioEffect(effect_handle_t effect) {
+ ALOGD("%s()+ %p", __FUNCTION__, effect);
+
+ AL_AUTOLOCK(mLock);
+
+ int i;
+ status_t RetStatus = -EINVAL;
+ effect_descriptor_t desc;
+
+ if (num_preprocessors <= 0) {
+ RetStatus = -ENOSYS;
+ ALOGD("%s(), num_preprocessors wrong", __FUNCTION__);
+ goto exit;
+ }
+
+ for (i = 0; i < num_preprocessors; i++) {
+ if (RetStatus == 0) { /* status == 0 means an effect was removed from a previous slot */
+ preprocessors[i - 1].effect_itfe = preprocessors[i].effect_itfe;
+ preprocessors[i - 1].channel_configs = preprocessors[i].channel_configs;
+ preprocessors[i - 1].num_channel_configs = preprocessors[i].num_channel_configs;
+ ALOGD("%s() moving fx from %d to %d", __FUNCTION__, i, i - 1);
+ continue;
+ }
+ if (preprocessors[i].effect_itfe == effect) {
+ ALOGD("%s() found fx at index %d", __FUNCTION__, i);
+ // free(preprocessors[i].channel_configs);
+ RetStatus = 0;
+ }
+ }
+
+ if (RetStatus != 0) {
+ goto exit;
+ }
+
+ num_preprocessors--;
+ /* if we remove one effect, at least the last preproc should be reset */
+ preprocessors[num_preprocessors].num_channel_configs = 0;
+ preprocessors[num_preprocessors].effect_itfe = NULL;
+ preprocessors[num_preprocessors].channel_configs = NULL;
+
+ // Not use effect handle because it may remove from framework
+
+#if 0
+ RetStatus = (*effect)->get_descriptor(effect, &desc);
+ if (RetStatus != 0) {
+ goto exit;
+ }
+
+ ALOGD("%s(), effect type: %08x, effect name:%s", __FUNCTION__, desc.type.timeLow, desc.name);
+
+ //echo reference
+ if (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) {
+ need_echo_reference = false;
+
+ if (mEcho_Reference != NULL) {
+ /* stop reading from echo reference */
+ stop_echo_reference(mEcho_Reference);
+ ALOGD("stop_echo_reference done");
+ //mEcho_Reference = NULL;
+ }
+ }
+#endif
+
+ if (mStreamInAttribute->NativePreprocess_Info.PreProcessEffect_AECOn == false) {
+ need_echo_reference = false;
+
+ if (mEcho_Reference != NULL) {
+ /* stop reading from echo reference */
+ stop_echo_reference(mEcho_Reference);
+ ALOGD("stop_echo_reference done");
+ //mEcho_Reference = NULL;
+ }
+ }
+
+exit:
+
+
+ ALOGD_IF(mLogEnable, "%s()-, RetStatus=%d", __FUNCTION__, RetStatus);
+ return RetStatus;
+}
+
+uint32_t AudioPreProcess::WriteEchoRefData(void *buffer, uint32_t bytes, const time_info_struct_t *Time_Info) {
+ AL_AUTOLOCK(mLock);
+ if (mEcho_Reference != NULL) {
+ //ALOGD("%s(), %p", __FUNCTION__, mEcho_Reference);
+
+ if (pEchoRefFile != NULL) {
+ fwrite(buffer, sizeof(char), bytes, pEchoRefFile);
+ }
+
+ struct echo_reference_buffer b;
+ b.raw = (void *)buffer;
+ b.frame_count = bytes / sizeof(int16_t) / mEchoRefChannelCount;
+
+ mTime_Info_echoref.timestamp_get = Time_Info->timestamp_get;
+ mTime_Info_echoref.frameInfo_get = Time_Info->frameInfo_get;
+ mTime_Info_echoref.buffer_per_time = Time_Info->buffer_per_time;
+ mTime_Info_echoref.kernelbuffer_ns = Time_Info->kernelbuffer_ns;
+
+ get_echoref_delay(b.frame_count, &b);
+ mEcho_Reference->write(mEcho_Reference, &b);
+ }
+ return bytes;
+}
+
+uint32_t AudioPreProcess::NativePreprocess(void *buffer, uint32_t bytes, const time_info_struct_t *Time_Info) {
+ ALOGV("%s()+", __FUNCTION__);
+ //AL_AUTOLOCK(mLock);
+
+ if (num_preprocessors == 0) {
+ return bytes;
+ } else {
+ mTime_Info.timestamp_get = Time_Info->timestamp_get;
+ mTime_Info.frameInfo_get = Time_Info->frameInfo_get;
+ mTime_Info.buffer_per_time = Time_Info->buffer_per_time;
+ mTime_Info.kernelbuffer_ns = Time_Info->kernelbuffer_ns;
+
+ ssize_t frames_wr = 0;
+ audio_buffer_t in_buf;
+ audio_buffer_t out_buf;
+ const uint8_t num_channel = mStreamInAttribute->num_channels;
+ ssize_t frames = bytes / sizeof(int16_t) / num_channel;
+ ssize_t needframes = frames + proc_buf_frames;
+ int i;
+
+ ALOGD("%s: %d bytes, %zu frames, proc_buf_frames=%zu, mAPPS->num_preprocessors=%d,num_channel=%d", __FUNCTION__, bytes, frames, proc_buf_frames, num_preprocessors, num_channel);
+ proc_buf_out = (int16_t *)buffer;
+
+ if ((proc_buf_size < (size_t)needframes) || (proc_buf_in == NULL)) {
+ proc_buf_size = (size_t)needframes;
+ proc_buf_in = (int16_t *)realloc(proc_buf_in, proc_buf_size * num_channel * sizeof(int16_t));
+ //mpPreProcessIn->proc_buf_out = (int16_t *)realloc(mpPreProcessIn->proc_buf_out, mpPreProcessIn->proc_buf_size*mChNum*sizeof(int16_t));
+
+ if (proc_buf_in == NULL) {
+ ALOGW("%s(), proc_buf_in realloc fail", __FUNCTION__);
+ return bytes;
+ }
+ ALOGD("%s: proc_buf_in %p extended to %zu bytes", __FUNCTION__, proc_buf_in, proc_buf_size * sizeof(int16_t)*num_channel);
+ }
+
+ memcpy(proc_buf_in + proc_buf_frames * num_channel, buffer, bytes);
+
+ proc_buf_frames += frames;
+
+ while (frames_wr < frames) {
+ //AEC
+ if (mEcho_Reference != NULL) {
+ push_echo_reference(proc_buf_frames);
+ } else {
+ //prevent start_echo_reference fail previously due to output not enable
+ if (need_echo_reference) {
+ ALOGD("try start_echo_reference");
+ mEcho_Reference = start_echo_reference(
+ AUDIO_FORMAT_PCM_16_BIT,
+ num_channel,
+ mStreamInAttribute->sample_rate);
+ }
+ }
+
+ /* in_buf.frameCount and out_buf.frameCount indicate respectively
+ * the maximum number of frames to be consumed and produced by process() */
+ in_buf.frameCount = proc_buf_frames;
+ in_buf.s16 = proc_buf_in;
+ out_buf.frameCount = frames - frames_wr;
+ out_buf.s16 = (int16_t *)proc_buf_out + frames_wr * num_channel;
+
+ /* FIXME: this works because of current pre processing library implementation that
+ * does the actual process only when the last enabled effect process is called.
+ * The generic solution is to have an output buffer for each effect and pass it as
+ * input to the next.
+ */
+
+ for (i = 0; i < num_preprocessors; i++) {
+ if (preprocessors[i].enable) {
+ (*preprocessors[i].effect_itfe)->process(preprocessors[i].effect_itfe,
+ &in_buf,
+ &out_buf);
+ }
+ }
+
+ /* process() has updated the number of frames consumed and produced in
+ * in_buf.frameCount and out_buf.frameCount respectively
+ * move remaining frames to the beginning of in->proc_buf_in */
+ proc_buf_frames -= in_buf.frameCount;
+
+ if (proc_buf_frames) {
+ memcpy(proc_buf_in,
+ proc_buf_in + in_buf.frameCount * num_channel,
+ proc_buf_frames * num_channel * sizeof(int16_t));
+ }
+
+ /* if not enough frames were passed to process(), read more and retry. */
+ if (out_buf.frameCount == 0) {
+ ALOGV("%s, No frames produced by preproc", __FUNCTION__);
+ break;
+ }
+
+ if ((frames_wr + (ssize_t)out_buf.frameCount) <= frames) {
+ frames_wr += out_buf.frameCount;
+ ALOGV("%s, out_buf.frameCount=%zu,frames_wr=%zu", __FUNCTION__, out_buf.frameCount, frames_wr);
+ } else {
+ /* The effect does not comply to the API. In theory, we should never end up here! */
+ ALOGE("%s, preprocessing produced too many frames: %d + %zu > %d !", __FUNCTION__,
+ (unsigned int)frames_wr, out_buf.frameCount, (unsigned int)frames);
+ frames_wr = frames;
+ }
+ }
+ // ALOGD("frames_wr=%d, bytes=%d",frames_wr,frames_wr*num_channel*sizeof(int16_t));
+ return frames_wr * num_channel * sizeof(int16_t);
+ }
+ ALOGD("%s()-", __FUNCTION__);
+}
+
+void AudioPreProcess::stop_echo_reference(struct echo_reference_itfe *reference) {
+ ALOGD_IF(mLogEnable, "%s()+", __FUNCTION__);
+ //AL_AUTOLOCK(mLock);
+
+ /* stop reading from echo reference */
+ if (mEcho_Reference != NULL && mEcho_Reference == reference) {
+ if (pEchoRefFile != NULL) {
+ fclose(pEchoRefFile);
+ }
+ mEcho_Reference->read(reference, NULL);
+ clear_echo_reference(reference);
+ }
+ ALOGD_IF(mLogEnable, "%s()-", __FUNCTION__);
+}
+
+void AudioPreProcess::clear_echo_reference(struct echo_reference_itfe *reference) {
+ ALOGD_IF(mLogEnable, "%s()+ %p", __FUNCTION__, reference);
+ if ((reference == mEcho_Reference) && (reference != NULL)) {
+ // if (mAudioSpeechEnhanceInfoInstance->IsOutputRunning())
+ remove_echo_reference(reference);
+
+ release_echo_reference(reference);
+ mEcho_Reference = NULL;
+ }
+ ALOGD_IF(mLogEnable, "%s()-", __FUNCTION__);
+}
+
+void AudioPreProcess::remove_echo_reference(struct echo_reference_itfe *reference) {
+ ALOGD_IF(mLogEnable, "%s()+ %p", __FUNCTION__, reference);
+ //TODO:Sam
+ //mAudioSpeechEnhanceInfoInstance->remove_echo_reference(reference);
+ ALOGD_IF(mLogEnable, "%s()-", __FUNCTION__);
+}
+
+struct echo_reference_itfe *AudioPreProcess::start_echo_reference(audio_format_t format __unused,
+ uint32_t channel_count, uint32_t sampling_rate) {
+ ALOGD_IF(mLogEnable, "%s()+ channel_count=%d,sampling_rate=%d,mEcho_Reference=%p", __FUNCTION__, channel_count, sampling_rate, mEcho_Reference);
+ //AL_AUTOLOCK(mLock);
+
+ clear_echo_reference(mEcho_Reference);
+ /* echo reference is taken from the low latency output stream used
+ * for voice use cases */
+
+ {
+ //TODO: need to check the samplerate and channel
+ uint32_t wr_channel_count = mEchoRefChannelCount;
+ uint32_t wr_sampling_rate = sampling_rate;
+
+ mInChn = channel_count;
+ mInSampleRate = sampling_rate;
+ ALOGD("start_echo_reference,wr_channel_count=%d,wr_sampling_rate=%d", wr_channel_count, wr_sampling_rate);
+ ALOGD("%s(),wr_channel_count=%d,wr_sampling_rate=%d", __FUNCTION__, wr_channel_count, wr_sampling_rate);
+ int status = create_echo_reference(AUDIO_FORMAT_PCM_16_BIT,
+ channel_count,
+ sampling_rate,
+ AUDIO_FORMAT_PCM_16_BIT,
+ wr_channel_count,
+ wr_sampling_rate,
+ &mEcho_Reference);
+
+#if 0
+ pEchoRefFile = fopen("/data/vendor/audiohal/NativeEchoRef.pcm", "wb");
+ if (pEchoRefFile == NULL) {
+ ALOGW("%s(), create pEchoRefFile fail ", __FUNCTION__);
+ }
+#endif
+
+ if (status == 0) {
+ add_echo_reference(mEcho_Reference);
+ } else {
+ ALOGW("%s() fail", __FUNCTION__);
+ }
+ }
+ ALOGD_IF(mLogEnable, "%s()-", __FUNCTION__);
+ return mEcho_Reference;
+}
+
+void AudioPreProcess::add_echo_reference(struct echo_reference_itfe *reference) {
+ ALOGD_IF(mLogEnable, "%s()+, reference=%p", __FUNCTION__, reference);
+ //TODO:Sam
+ //mAudioSpeechEnhanceInfoInstance->add_echo_reference(reference);
+ ALOGD_IF(mLogEnable, "%s()-", __FUNCTION__);
+}
+
+void AudioPreProcess::push_echo_reference(size_t frames) {
+ //AL_AUTOLOCK(mLock);
+
+ /* read frames from echo reference buffer and update echo delay
+ * in->ref_buf_frames is updated with frames available in in->ref_buf */
+ int32_t delay_us = update_echo_reference(frames) / 1000;
+ int i;
+ audio_buffer_t buf;
+
+ if (ref_buf_frames < frames) {
+ frames = ref_buf_frames;
+ }
+
+ buf.frameCount = frames;
+ buf.raw = ref_buf;
+
+ for (i = 0; i < num_preprocessors; i++) {
+ if ((*preprocessors[i].effect_itfe)->process_reverse == NULL) {
+ continue;
+ }
+
+ (*preprocessors[i].effect_itfe)->process_reverse(preprocessors[i].effect_itfe,
+ &buf,
+ NULL);
+ set_preprocessor_echo_delay(preprocessors[i].effect_itfe, delay_us);
+ }
+
+ ref_buf_frames -= buf.frameCount;
+ if (ref_buf_frames) {
+ // ALOGV("push_echo_reference,ref_buf_frames=%d",ref_buf_frames);
+ memcpy(ref_buf,
+ ref_buf + buf.frameCount * mInChn,
+ ref_buf_frames * mInChn * sizeof(int16_t));
+ }
+}
+
+int32_t AudioPreProcess::update_echo_reference(size_t frames) {
+
+ struct echo_reference_buffer b;
+ b.delay_ns = 0;
+
+ // ALOGD("update_echo_reference, frames = [%d], ref_buf_frames = [%d], "
+ // "b.frame_count = [%d]", frames, ref_buf_frames, frames - ref_buf_frames);
+ if (ref_buf_frames < frames) {
+ if (ref_buf_size < frames) {
+ ref_buf_size = frames;
+ ref_buf = (int16_t *)realloc(ref_buf, frames * sizeof(int16_t) * mInChn);
+ ALOG_ASSERT((ref_buf != NULL),
+ "update_echo_reference() failed to reallocate ref_buf");
+
+ ALOGD("%s(), ref_buf %p extended to %zu bytes", __FUNCTION__, ref_buf, frames * sizeof(int16_t)*mInChn);
+ }
+ b.frame_count = frames - ref_buf_frames;
+ //fixme? raw address?
+ b.raw = (void *)(ref_buf + ref_buf_frames * mInChn);
+
+ get_capture_delay(frames, &b);
+
+ if (mEcho_Reference->read(mEcho_Reference, &b) == 0) {
+ ref_buf_frames += b.frame_count;
+ /* ALOGD("update_echo_reference(): ref_buf_frames:[%d], "
+ "ref_buf_size:[%d], frames:[%d], b.frame_count:[%d]",
+ ref_buf_frames, ref_buf_size, frames, b.frame_count);*/
+ }
+ } else {
+ ALOGV("%s(): NOT enough frames to read ref buffer", __FUNCTION__);
+ }
+ return b.delay_ns;
+}
+
+int AudioPreProcess::set_preprocessor_echo_delay(effect_handle_t handle, int32_t delay_us) {
+ uint32_t buf[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
+ effect_param_t *param = (effect_param_t *)buf;
+
+ param->psize = sizeof(uint32_t);
+ param->vsize = sizeof(uint32_t);
+ *(uint32_t *)param->data = AEC_PARAM_ECHO_DELAY;
+ *((int32_t *)param->data + 1) = delay_us;
+
+ return set_preprocessor_param(handle, param);
+}
+
+int AudioPreProcess::set_preprocessor_param(effect_handle_t handle, effect_param_t *param) {
+ uint32_t size = sizeof(int);
+ uint32_t psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) +
+ param->vsize;
+
+ int status = (*handle)->command(handle,
+ EFFECT_CMD_SET_PARAM,
+ sizeof(effect_param_t) + psize,
+ param,
+ &size,
+ ¶m->status);
+ if (status == 0) {
+ status = param->status;
+ }
+
+ return status;
+}
+
+void AudioPreProcess::get_capture_delay(size_t frames __unused, struct echo_reference_buffer *buffer) {
+ //FIXME:: calculate for more precise time delay
+ struct timespec tstamp;
+ long buf_delay = 0;
+ long rsmp_delay = 0;
+ long kernel_delay = 0;
+ long delay_ns = 0;
+
+#if 1
+ buffer->time_stamp = mTime_Info.timestamp_get;
+ buf_delay = (long)(((int64_t)(proc_buf_frames) * 1000000000) / mInSampleRate); //streamintarget attribute sample rate
+ kernel_delay = mTime_Info.kernelbuffer_ns; //kernel remain frame + read size(convert to frame)
+ delay_ns = kernel_delay + buf_delay + rsmp_delay;
+ buffer->delay_ns = delay_ns;
+
+ //ALOGD("%s time_stamp = [%ld].[%ld], delay_ns: [%ld], buf_delay= %ld, kernel_delay=%ld",__FUNCTION__,
+ // buffer->time_stamp.tv_sec , buffer->time_stamp.tv_nsec, buffer->delay_ns, buf_delay, kernel_delay);
+
+#else
+ int rc = clock_gettime(CLOCK_MONOTONIC, &tstamp);
+ if (rc != 0) {
+ buffer->time_stamp.tv_sec = 0;
+ buffer->time_stamp.tv_nsec = 0;
+ buffer->delay_ns = 0;
+ ALOGD("%s(): clock_gettime error", __FUNCTION__);
+ return;
+ }
+
+
+ buf_delay = (long)(((int64_t)(proc_buf_frames) * 1000000000) / mInSampleRate);
+
+ delay_ns = kernel_delay + buf_delay + rsmp_delay;
+
+ buffer->time_stamp = tstamp;
+ buffer->delay_ns = delay_ns;
+ // ALOGV("get_capture_delay time_stamp = [%ld].[%ld], delay_ns: [%d]",
+ // buffer->time_stamp.tv_sec , buffer->time_stamp.tv_nsec, buffer->delay_ns);
+#endif
+}
+
+void AudioPreProcess::get_echoref_delay(size_t frames __unused, struct echo_reference_buffer *buffer) {
+ struct timespec tstamp;
+ long buf_delay = 0;
+ long rsmp_delay = 0;
+ long kernel_delay = 0;
+ long delay_ns = 0;
+
+#if 1
+
+ buffer->time_stamp = mTime_Info_echoref.timestamp_get;
+ buf_delay = (long)(((int64_t)(proc_buf_frames) * 1000000000) / mInSampleRate); //streamintarget attribute sample rate
+ kernel_delay = mTime_Info_echoref.kernelbuffer_ns; //kernel remain frame + read size(convert to frame)
+ delay_ns = kernel_delay + buf_delay + rsmp_delay;
+ buffer->delay_ns = delay_ns;
+
+ //ALOGD("%s time_stamp = [%ld].[%ld], delay_ns: [%ld], buf_delay=%ld, kernel_delay=%ld",__FUNCTION__,
+ // buffer->time_stamp.tv_sec , buffer->time_stamp.tv_nsec, buffer->delay_ns,buf_delay,kernel_delay);
+
+#else
+ int rc = clock_gettime(CLOCK_MONOTONIC, &tstamp);
+ if (rc != 0) {
+ buffer->time_stamp.tv_sec = 0;
+ buffer->time_stamp.tv_nsec = 0;
+ buffer->delay_ns = 0;
+ ALOGD("%s(): clock_gettime error", __FUNCTION__);
+ return;
+ }
+
+
+ buf_delay = (long)(((int64_t)(proc_buf_frames) * 1000000000) / mInSampleRate);
+
+ delay_ns = kernel_delay + buf_delay + rsmp_delay;
+
+ buffer->time_stamp = tstamp;
+ buffer->delay_ns = delay_ns;
+ // ALOGV("get_capture_delay time_stamp = [%ld].[%ld], delay_ns: [%d]",
+ // buffer->time_stamp.tv_sec , buffer->time_stamp.tv_nsec, buffer->delay_ns);
+#endif
+}
+
+bool AudioPreProcess::MutexLock(void) {
+ AL_LOCK(mLock);
+ return true;
+}
+bool AudioPreProcess::MutexUnlock(void) {
+ AL_UNLOCK(mLock);
+ return true;
+}
+
+
+#define GET_COMMAND_STATUS(status, fct_status, cmd_status) \
+ do { \
+ if (fct_status != 0) \
+ status = fct_status; \
+ else if (cmd_status != 0) \
+ status = cmd_status; \
+ } while(0)
+
+int AudioPreProcess::in_configure_reverse(uint32_t channel_count __unused, uint32_t sampling_rate) {
+ ALOGD_IF(mLogEnable, "%s()+", __FUNCTION__);
+ //AL_AUTOLOCK(mLock);
+
+ int32_t cmd_status;
+ uint32_t size = sizeof(int);
+ effect_config_t config;
+ int32_t status = 0;
+ int32_t fct_status = 0;
+ int i;
+
+ //fixme:: currently AEC stereo channel has problem, force using mono while AEC enable
+ if (num_preprocessors > 0) {
+ config.inputCfg.channels = mStreamInAttribute->audio_channel_mask;//1;//mChNum;channel_count
+ config.outputCfg.channels = mStreamInAttribute->audio_channel_mask;//1;//mHw->mStreamHandler->mOutput[0]->GetChannelInfo();
+ config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ config.inputCfg.samplingRate = sampling_rate;
+ //TODO:Sam
+ //config.outputCfg.samplingRate = mAudioSpeechEnhanceInfoInstance->GetOutputSampleRateInfo();
+ config.outputCfg.samplingRate = sampling_rate;
+
+ config.inputCfg.mask =
+ (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
+ config.outputCfg.mask =
+ (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
+
+ for (i = 0; i < num_preprocessors; i++) {
+ if ((*preprocessors[i].effect_itfe)->process_reverse == NULL) {
+ continue;
+ }
+ fct_status = (*(preprocessors[i].effect_itfe))->command(
+ preprocessors[i].effect_itfe,
+ EFFECT_CMD_SET_CONFIG_REVERSE,
+ sizeof(effect_config_t),
+ &config,
+ &size,
+ &cmd_status);
+
+ GET_COMMAND_STATUS(status, fct_status, cmd_status);
+ }
+ }
+ ALOGD_IF(mLogEnable, "%s()-, status=%d", __FUNCTION__, status);
+ return status;
+}
+
+// ----------------------------------------------------------------------------
+}
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioSCPPhoneCallController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioSCPPhoneCallController.cpp
new file mode 100644
index 0000000..348822e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioSCPPhoneCallController.cpp
@@ -0,0 +1,520 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioSCPPhoneCallController.h"
+#include <audio_utils/format.h>
+#include <tinyalsa/asoundlib.h>
+#include <math.h>
+#include <sys/resource.h>
+
+#include "SpeechDriverFactory.h"
+#include "AudioALSADriverUtility.h"
+#include "AudioALSADeviceParser.h"
+#include "AudioVolumeFactory.h"
+#include "AudioALSAHardwareResourceManager.h"
+#include "AudioUtility.h"
+#include "SpeechDriverFactory.h"
+#include "AudioSmartPaController.h"
+#include "AudioALSADeviceConfigManager.h"
+#include "AudioSmartPaParam.h"
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+#include <audio_task.h>
+#endif
+#ifdef HAVE_AEE_FEATURE
+#include <aee.h>
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioSCPPhoneCallController"
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+#define SCP_SPH_PERIOD_BYTES (2 * 1024)
+
+
+namespace android {
+
+AudioSCPPhoneCallController *AudioSCPPhoneCallController::mSCPPhoneCallController = NULL;
+struct mixer *AudioSCPPhoneCallController::mMixer = NULL;
+
+AudioSCPPhoneCallController *AudioSCPPhoneCallController::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (!mSCPPhoneCallController) {
+ mSCPPhoneCallController = new AudioSCPPhoneCallController();
+ }
+
+ return mSCPPhoneCallController;
+}
+
+AudioSCPPhoneCallController::AudioSCPPhoneCallController() {
+ mEnable = 0;
+ mSpeechRate = 0;
+ mModemIndex = MODEM_1;
+ memset((void *)&mConfig, 0, sizeof(pcm_config));
+ memset(&mLpbkNewTime, 0, sizeof(struct timespec));
+ memset(&mLpbkOldTime, 0, sizeof(struct timespec));
+ memset(&mLpbkStartTime, 0, sizeof(struct timespec));
+ memset((void *)&mScpSpkHwConfig, 0, sizeof(mScpSpkHwConfig));
+ mPcmMicIn = NULL;
+ mPcmMicOut = NULL;
+ mScpSpkPcmIn = NULL;
+ mScpSpkMdUlHwPcm = NULL;
+ mScpSpkIvHwPcm = NULL;
+ mScpSpkDlHwPcm = NULL;
+
+ if (mMixer == NULL) {
+ mMixer = AudioALSADriverUtility::getInstance()->getMixer();
+ ASSERT(mMixer != NULL);
+ }
+}
+
+AudioSCPPhoneCallController::~AudioSCPPhoneCallController() {
+
+}
+
+int AudioSCPPhoneCallController::setPcmDump(bool enable) {
+ ALOGD("%s() enable = %d", __FUNCTION__, enable);
+
+ char value[PROPERTY_VALUE_MAX];
+ int ret;
+
+ enum mixer_ctl_type type;
+ struct mixer_ctl *ctl;
+ int retval = 0;
+
+ property_get(streamout_propty, value, "0");
+ int flag = atoi(value);
+
+ if (flag == 0) {
+ ALOGD("%s() %s property not set no dump", __FUNCTION__, streamout_propty);
+ return 0;
+ }
+
+ ret = AudiocheckAndCreateDirectory(audio_dump_path);
+ if (ret < 0) {
+ ALOGE("AudiocheckAndCreateDirectory(%s) fail!", audio_dump_path);
+ flag = 0;
+ }
+
+ ctl = mixer_get_ctl_by_name(mMixer, "mtk_scp_spk_pcm_dump");
+
+ if (ctl == NULL) {
+ ALOGE("mtk_scp_spk_pcm_dump not support");
+ return -1;
+ }
+
+ if (enable == true) {
+ retval = mixer_ctl_set_enum_by_string(ctl, "normal_dump");
+ ALOGD("%s(), On enable = %d", __FUNCTION__, enable);
+ ASSERT(retval == 0);
+ } else {
+ retval = mixer_ctl_set_enum_by_string(ctl, "off");
+ ALOGD("%s(), Off enable = %d", __FUNCTION__, enable);
+ ASSERT(retval == 0);
+ }
+
+ return 0;
+}
+
+int AudioSCPPhoneCallController::closeScpSpkHwPcm() {
+ if (mScpSpkMdUlHwPcm != NULL) {
+ pcm_close(mScpSpkMdUlHwPcm);
+ mScpSpkMdUlHwPcm = NULL;
+ }
+
+ if (mScpSpkDlHwPcm != NULL) {
+ pcm_close(mScpSpkDlHwPcm);
+ mScpSpkDlHwPcm = NULL;
+ }
+
+ if (mScpSpkIvHwPcm != NULL) {
+ pcm_close(mScpSpkIvHwPcm);
+ mScpSpkIvHwPcm = NULL;
+ }
+
+ // disconnect path from md to ul memif
+ mApTurnOnSequence = (mModemIndex == MODEM_1) ? AUDIO_CTL_MD1_TO_CAPTURE2 : AUDIO_CTL_MD2_TO_CAPTURE2;
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+
+ // disconnect dl path
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(AUDIO_CTL_PLAYBACK1_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(false);
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+
+ // disconnect iv path
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(
+ AUDIO_CTL_I2S_TO_CAPTURE4, true);
+ AudioSmartPaController::getInstance()->setI2sInHD(false);
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "mtk_scp_spk_dl_scenario"), 0, false)) {
+ ALOGE("Error: mtk_scp_spk_dl_scenario invalid value");
+ }
+
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "mtk_scp_spk_iv_scenario"), 0, false)) {
+ ALOGE("Error: mtk_scp_spk_iv_scenario invalid value");
+ }
+
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "mtk_scp_spk_mdul_scenario"), 0, false)) {
+ ALOGE("Error: mtk_scp_spk_mdul_scenario invalid value");
+ }
+
+ ALOGV("-%s(), mScpSpkDlHwPcm = %p, mScpSpkIvHwPcm = %p",
+ __FUNCTION__, mScpSpkDlHwPcm, mScpSpkIvHwPcm);
+ return 0;
+}
+
+int AudioSCPPhoneCallController::openScpSpkPcmDriverWithFlag(const unsigned int device,
+ unsigned int flag) {
+ struct pcm *mScpSpkPcm = NULL;
+ int ret = NO_ERROR;
+ ALOGD("+%s(), pcm device = %d, flag = 0x%x", __FUNCTION__, device, flag);
+
+ if (flag & PCM_IN) {
+ if (mScpSpkMdUlHwPcm == NULL) {
+ mScpSpkMdUlHwPcm = pcm_open(AudioALSADeviceParser::getInstance()->GetCardIndex(),
+ device, flag, &mScpSpkHwConfig);
+ mScpSpkPcm = mScpSpkMdUlHwPcm;
+ } else {
+ mScpSpkIvHwPcm = pcm_open(AudioALSADeviceParser::getInstance()->GetCardIndex(),
+ device, flag, &mScpSpkHwConfig);
+ mScpSpkPcm = mScpSpkIvHwPcm;
+ }
+ } else {
+ mScpSpkDlHwPcm = pcm_open(AudioALSADeviceParser::getInstance()->GetCardIndex(),
+ device, flag, &mScpSpkHwConfig);
+ mScpSpkPcm = mScpSpkDlHwPcm;
+ }
+
+ if (mScpSpkPcm == NULL) {
+ ALOGE("%s(), mScpSpkPcm == NULL!!", __FUNCTION__);
+ ret = INVALID_OPERATION;
+ } else if (pcm_is_ready(mScpSpkPcm) == false) {
+ ALOGE("%s(), pcm_is_ready(%p) == false due to %s, close pcm.",
+ __FUNCTION__, mScpSpkPcm, pcm_get_error(mScpSpkPcm));
+ pcm_close(mScpSpkPcm);
+ mScpSpkPcm = NULL;
+ ret = INVALID_OPERATION;
+ } else if (pcm_prepare(mScpSpkPcm) != 0) {
+ ALOGE("%s(), pcm_prepare(%p) == false due to %s, close pcm.",
+ __FUNCTION__, mScpSpkPcm, pcm_get_error(mScpSpkPcm));
+ pcm_close(mScpSpkPcm);
+ mScpSpkPcm = NULL;
+ ret = INVALID_OPERATION;
+ }
+
+ ASSERT(mScpSpkPcm != NULL);
+
+ return ret;
+}
+
+int AudioSCPPhoneCallController::openScpSpkPcmDriver(const unsigned int mdUlDevice,
+ const unsigned int dlDevice,
+ const unsigned int ivDevice) {
+ int ret;
+ ASSERT(mScpSpkMdUlHwPcm == NULL);
+ ASSERT(mScpSpkDlHwPcm == NULL);
+ ASSERT(mScpSpkIvHwPcm == NULL);
+ ret = openScpSpkPcmDriverWithFlag(ivDevice, PCM_IN | PCM_MONOTONIC);
+ ret = openScpSpkPcmDriverWithFlag(mdUlDevice, PCM_IN | PCM_MONOTONIC);
+ ret = openScpSpkPcmDriverWithFlag(dlDevice, PCM_OUT | PCM_MONOTONIC);
+
+ return ret;
+}
+
+int AudioSCPPhoneCallController::openScpSpkHwPcm() {
+#if defined(MTK_AUDIO_KS)
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "mtk_scp_spk_dl_scenario"), 0, true)) {
+ ALOGE("Error: mtk_scp_spk_dl_scenario invalid value");
+ }
+
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "mtk_scp_spk_iv_scenario"), 0, true)) {
+ ALOGE("Error: mtk_scp_spk_iv_scenario invalid value");
+ }
+
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "mtk_scp_spk_mdul_scenario"), 0, true)) {
+ ALOGE("Error: mtk_scp_spk_mdul_scenario invalid value");
+ }
+
+ // data from md dl to afe ul control path
+ int pcmMdUlIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmCapture2);
+ int cardMdUlIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmCapture2);
+ mApTurnOnSequence = (mModemIndex == MODEM_1) ? AUDIO_CTL_MD1_TO_CAPTURE2 : AUDIO_CTL_MD2_TO_CAPTURE2;
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+
+ // scp spk dl control path
+ int pcmDlIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmPlayback1);
+ int cardDlIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmPlayback1);
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(AUDIO_CTL_PLAYBACK1_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+
+
+ // scp spk iv control path
+ int pcmIvIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmCapture4);
+ int cardIvIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmCapture4);
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(
+ AUDIO_CTL_I2S_TO_CAPTURE4, true);
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+ AudioSmartPaController::getInstance()->setI2sInHD(true);
+
+ ASSERT(mScpSpkMdUlHwPcm == NULL);
+ ASSERT(mScpSpkDlHwPcm == NULL);
+ ASSERT(mScpSpkIvHwPcm == NULL);
+
+ memcpy(&mScpSpkHwConfig, &mConfig, sizeof(struct pcm_config));
+
+ if (openScpSpkPcmDriver(pcmMdUlIdx, pcmDlIdx, pcmIvIdx)) {
+ return INVALID_OPERATION;
+ }
+#endif
+ return NO_ERROR;
+}
+
+int AudioSCPPhoneCallController::speechULPhoneMicPath(bool enable) {
+ ALOGD("%s(), enable %d", __FUNCTION__, enable);
+#if defined(MTK_AUDIO_KS)
+ String8 apTurnOnSequence = String8(mModemIndex == MODEM_1 ? AUDIO_CTL_ADDA_UL_TO_MD1 : AUDIO_CTL_ADDA_UL_TO_MD2);
+
+ if (enable) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(apTurnOnSequence);
+
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessSpeech);
+ int cardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmHostlessSpeech);
+
+ ASSERT(mPcmMicOut == NULL && mPcmMicIn == NULL);
+ mPcmMicIn = pcm_open(cardIndex, pcmIdx, PCM_IN, &mScpSpkHwConfig);
+ mPcmMicOut = pcm_open(cardIndex, pcmIdx, PCM_OUT, &mScpSpkHwConfig);
+ ASSERT(mPcmMicOut != NULL && mPcmMicIn != NULL);
+
+ AudioALSAHardwareResourceManager::getInstance()->startInputDevice(mInputDevice);
+
+ if (mPcmMicIn == NULL || pcm_is_ready(mPcmMicIn) == false) {
+ ALOGE("%s(), Unable to open mPcmMicIn device %u (%s)", __FUNCTION__, pcmIdx, pcm_get_error(mPcmMicIn));
+ } else {
+ if (pcm_prepare(mPcmMicIn)) {
+ ALOGE("%s(), pcm_prepare mPcmMicIn %p fail due to %s", __FUNCTION__, mPcmMicIn, pcm_get_error(mPcmMicIn));
+ pcm_close(mPcmMicIn);
+ mPcmMicIn = NULL;
+ }
+ }
+
+ if (mPcmMicOut == NULL || pcm_is_ready(mPcmMicOut) == false) {
+ ALOGE("%s(), Unable to open mPcmMicOut device %u (%s)", __FUNCTION__, pcmIdx, pcm_get_error(mPcmMicOut));
+ } else {
+ if (pcm_prepare(mPcmMicOut)) {
+ ALOGE("%s(), pcm_prepare mPcmMicOut %p fail due to %s", __FUNCTION__, mPcmMicOut, pcm_get_error(mPcmMicOut));
+ pcm_close(mPcmMicOut);
+ mPcmMicOut = NULL;
+ }
+ }
+ } else {
+ if (mPcmMicIn != NULL) {
+ pcm_close(mPcmMicIn);
+ mPcmMicIn = NULL;
+ }
+
+ if (mPcmMicOut != NULL) {
+ pcm_close(mPcmMicOut);
+ mPcmMicOut = NULL;
+ }
+
+ AudioALSAHardwareResourceManager::getInstance()->stopInputDevice(mInputDevice);
+
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(apTurnOnSequence);
+ }
+#endif
+ return 0;
+}
+
+int AudioSCPPhoneCallController::enable(unsigned int speechRate, const audio_devices_t inputDevice) {
+ int pcmInIdx, cardIndex, ret;
+ mModemIndex = SpeechDriverFactory::GetInstance()->GetActiveModemIndex();
+ mInputDevice = inputDevice;
+
+ ALOGD("+%s(), mEnable %d, md %d, rate %u ", __FUNCTION__, mEnable, mModemIndex, speechRate);
+
+ AL_AUTOLOCK(mLock);
+
+ if (mEnable) {
+ ALOGW("%s(), already enabled, mEnable %d", __FUNCTION__, mEnable);
+ return INVALID_OPERATION;
+ }
+
+ // set enable flag
+ mEnable = true;
+ mSpeechRate = speechRate;
+
+#if defined(MTK_AUDIO_KS)
+ pcmInIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmScpSpkPlayback);
+ cardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmScpSpkPlayback);
+#else
+ // set modem
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_Scp_Voice_MD_Select"), mModemIndex == MODEM_1 ? "md1" : "md2")) {
+ ALOGE("Error: SCP_voice_Modem_Select invalid value");
+ }
+
+ pcmInIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmScpVoicePlayback);
+ cardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmScpVoicePlayback);
+#endif
+
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = 2;
+ mConfig.rate = speechRate;
+ mConfig.period_count = 4;
+ mConfig.format = PCM_FORMAT_S32_LE;
+ mConfig.period_size = (SCP_SPH_PERIOD_BYTES / mConfig.channels) / (mConfig.format == PCM_FORMAT_S32_LE ? 4 : 2);
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+
+ ASSERT(mScpSpkPcmIn == NULL);
+
+ /* smartpa param*/
+ initSmartPaConfig();
+
+ setPcmDump(true);
+
+#if defined(MTK_AUDIO_KS)
+ ret = openScpSpkHwPcm();
+ if (ret) {
+ ALOGE("%s(), openScpSpkHwPcm fail", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+#endif
+
+ ALOGD("%s(), mConfig: channels = %d, rate = %d, period_size = %d, period_count = %d, format = %d",
+ __FUNCTION__, mConfig.channels, mConfig.rate,
+ mConfig.period_size, mConfig.period_count, mConfig.format);
+
+ mScpSpkPcmIn = pcm_open(cardIndex, pcmInIdx, PCM_IN, &mConfig);
+
+ if (pcm_start(mScpSpkPcmIn) != 0) {
+ ALOGE("%s(), pcm_start(%p) == false due to %s, close pcm.",
+ __FUNCTION__, mScpSpkPcmIn, pcm_get_error(mScpSpkPcmIn));
+ pcm_close(mScpSpkPcmIn);
+ mScpSpkPcmIn = NULL;
+ }
+
+
+#if defined(MTK_AUDIO_KS)
+ speechULPhoneMicPath(true);
+#endif
+
+ return 0;
+}
+
+int AudioSCPPhoneCallController::disable() {
+ ALOGD("+%s(), mEnable %d", __FUNCTION__, mEnable);
+
+ AL_AUTOLOCK(mLock);
+
+ if (!mEnable) {
+ ALOGW("%s(), already disabled, mEnable %d", __FUNCTION__, mEnable);
+ return INVALID_OPERATION;
+ }
+
+#if defined(MTK_AUDIO_KS)
+ speechULPhoneMicPath(false);
+#endif
+
+ if (mScpSpkPcmIn != NULL) {
+ pcm_stop(mScpSpkPcmIn);
+ pcm_close(mScpSpkPcmIn);
+ mScpSpkPcmIn = NULL;
+ }
+
+#if defined(MTK_AUDIO_KS)
+ closeScpSpkHwPcm();
+#endif
+
+ mEnable = false;
+
+ setPcmDump(false);
+
+ return 0;
+}
+
+int AudioSCPPhoneCallController::initSmartPaConfig() {
+ ALOGD("%s", __FUNCTION__);
+ AudioSmartPaParam *mAudioSmartPainstance = AudioSmartPaParam::getInstance();
+
+ if (mAudioSmartPainstance == NULL) {
+ return -1;
+ }
+ /* output device */
+ arsi_task_config_t ArsiTaskConfig;
+ ArsiTaskConfig.output_device_info.devices = AUDIO_DEVICE_OUT_SPEAKER;
+ ArsiTaskConfig.output_device_info.audio_format = AUDIO_FORMAT_PCM_32_BIT;
+ ArsiTaskConfig.output_device_info.sample_rate = mConfig.rate;
+ ArsiTaskConfig.output_device_info.channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ ArsiTaskConfig.output_device_info.num_channels = 2;
+ ArsiTaskConfig.output_device_info.hw_info_mask = 0;
+
+ /* task scene */
+ ArsiTaskConfig.task_scene = TASK_SCENE_SPEAKER_PROTECTION;
+
+ /* audio mode */
+ ArsiTaskConfig.audio_mode = AUDIO_MODE_IN_CALL;
+
+ /* max device capability for allocating memory */
+ ArsiTaskConfig.max_output_device_sample_rate = mConfig.rate;
+ ArsiTaskConfig.max_output_device_num_channels = 2;
+
+ mAudioSmartPainstance->setArsiTaskConfig(&ArsiTaskConfig);
+ mAudioSmartPainstance->setSmartpaParam();
+
+ return 0;
+}
+
+bool AudioSCPPhoneCallController::deviceSupport(const audio_devices_t output_devices) {
+ if (output_devices == AUDIO_DEVICE_OUT_SPEAKER) {
+ return true;
+ }
+ return false;
+}
+
+bool AudioSCPPhoneCallController::isSupportPhonecall(const audio_devices_t output_devices) {
+ if (AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ if (deviceSupport(output_devices) &&
+ AudioSmartPaController::getInstance()->getSpkProtectType() == SPK_APSCP_DSP) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioSCPPhoneCallController::isEnable() {
+ return mEnable;
+}
+
+unsigned int AudioSCPPhoneCallController::getSpeechRate() {
+ return mSpeechRate;
+}
+
+unsigned int AudioSCPPhoneCallController::getPeriodByte(const struct pcm_config *config) {
+ return config->period_size * config->channels * (pcm_format_to_bits(config->format) / 8);
+}
+
+void AudioSCPPhoneCallController::setSCPDebugInfo(bool enable, int dbgType) {
+ int previousDebugEnable = mixer_ctl_get_value(mixer_get_ctl_by_name(mMixer, "ScpSpk_Voice_Debug"), 0);
+ int debugEnable = 0;
+
+ if (enable) {
+ debugEnable = dbgType | previousDebugEnable;
+ } else {
+ debugEnable = (~dbgType) & previousDebugEnable;
+ }
+
+
+ ALOGD("%s(), enable %d, dbgType 0x%x, previousDebugEnable 0x%x, debugEnable 0x%x",
+ __FUNCTION__, enable, dbgType, previousDebugEnable, debugEnable);
+
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "ScpSpk_Voice_Debug"), 0, debugEnable)) {
+ ALOGW("%s(), set ScpSpk_Voice_Debug %d fail", __FUNCTION__, debugEnable);
+ }
+}
+
+}
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioSmartPaController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioSmartPaController.cpp
new file mode 100644
index 0000000..a18552c
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioSmartPaController.cpp
@@ -0,0 +1,908 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioSmartPaController.h"
+#include "SpeechDriverFactory.h"
+#include "AudioParamParser.h"
+#include "AudioUtility.h"
+#include "AudioALSAStreamManager.h"
+#include "AudioALSASpeechPhoneCallController.h"
+#include "AudioALSADeviceParser.h"
+#include "AudioALSADeviceConfigManager.h"
+#include "LoopbackManager.h"
+#include <system/audio.h>
+
+#include <string>
+#include <dlfcn.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioSmartPaController"
+
+namespace android {
+
+typedef enum {
+ PLAYBACK_DEVICE_NONE = -1,
+ PLAYBACK_DEVICE_SPEAKER,
+ PLAYBACK_DEVICE_RECEIVER,
+ PLAYBACK_DEVICE_NUM
+} playback_device_t;
+
+/*
+ * singleton
+ */
+AudioSmartPaController *AudioSmartPaController::mAudioSmartPaController = NULL;
+AudioSmartPaController *AudioSmartPaController::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioSmartPaController == NULL) {
+ mAudioSmartPaController = new AudioSmartPaController();
+ }
+
+ ASSERT(mAudioSmartPaController != NULL);
+ return mAudioSmartPaController;
+}
+
+/*
+ * constructor / destructor
+ */
+AudioSmartPaController::AudioSmartPaController() :
+ mMixer(AudioALSADriverUtility::getInstance()->getMixer()),
+ mPcmEcho(NULL),
+ mPcmEchoUL(NULL),
+ mLibHandle(NULL),
+ mtk_smartpa_init(NULL),
+ isCalibrating(false) {
+ // init variables
+ memset(&mSmartPa, 0, sizeof(mSmartPa));
+
+ // init process
+ init();
+};
+
+AudioSmartPaController::~AudioSmartPaController() {
+ deinit();
+
+ if (mLibHandle) {
+ if (dlclose(mLibHandle)) {
+ ALOGE("%s(), dlclose failed, dlerror = %s", __FUNCTION__, dlerror());
+ }
+ }
+};
+
+/*
+ * function implementations
+ */
+int AudioSmartPaController::init() {
+ int ret;
+
+ ret = initSmartPaAttribute();
+ if (ret) {
+ ALOGE("%s(), initSmartPaAttribute failed, ret = %d", __FUNCTION__, ret);
+ return ret;
+ }
+
+ if (!mSmartPa.attribute.isSmartPAUsed) {
+ return 0;
+ }
+
+ ret = initSmartPaRuntime();
+ if (ret) {
+ ALOGE("%s(), initSmartPaRuntime failed, ret = %d", __FUNCTION__, ret);
+ ASSERT(ret != 0);
+ return ret;
+ }
+
+ // load lib
+ ALOGD("%s(), dlopen lib path: %s", __FUNCTION__, mSmartPa.attribute.spkLibPath);
+ mLibHandle = dlopen(mSmartPa.attribute.spkLibPath, RTLD_NOW);
+
+ if (!mLibHandle) {
+ ALOGW("%s(), dlopen failed, dlerror = %s", __FUNCTION__, dlerror());
+ } else {
+ mtk_smartpa_init = (int (*)(struct SmartPa *))dlsym(mLibHandle, "mtk_smartpa_init");
+ if (!mtk_smartpa_init) {
+ ALOGW("%s(), dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ }
+ }
+
+ // lib init
+ if (mtk_smartpa_init) {
+ ret = mtk_smartpa_init(&mSmartPa);
+ if (ret) {
+ ALOGE("%s(), mtk_smartpa_init failed, ret = %d", __FUNCTION__, ret);
+ ASSERT(ret != 0);
+ return ret;
+ }
+ }
+
+#ifndef MTK_APLL_DEFAULT_OFF
+ if (mSmartPa.attribute.isApllNeeded) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_always_hd_Switch"), "On")) {
+ ALOGE("Error: Audio_always_hd_Switch invalid value");
+ }
+ }
+#endif
+
+ // reset
+ speakerOff();
+ dspOnBoardSpeakerOff();
+
+ // callback init
+ if (mSmartPa.ops.init) {
+ if (getI2sSetStage() & SPK_I2S_AUDIOSERVER_INIT) {
+#if defined(MTK_AUDIO_KS)
+ struct pcm_config config;
+ String8 apTurnOnSequence = String8(AUDIO_CTL_SPK_INIT);
+
+ memset(&config, 0, sizeof(config));
+ config.channels = 2;
+ config.rate = 44100;
+ config.period_size = 1024;
+ config.period_count = 2;
+ config.format = PCM_FORMAT_S32_LE;
+ config.stop_threshold = ~(0U);
+
+ int cardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmHostlessSpkInit);
+ int pcmIndex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessSpkInit);
+
+ struct pcm *pcm = pcm_open(cardIndex, pcmIndex , PCM_OUT, &config);
+ if (pcm == NULL || pcm_is_ready(pcm) == false) {
+ ALOGE("%s(), Unable to open pcm device %u (%s)", __FUNCTION__, pcmIndex , pcm_get_error(pcm));
+ } else {
+ if (pcm_start(pcm)) {
+ ALOGE("%s(), pcm_start %p fail due to %s", __FUNCTION__, pcm, pcm_get_error(pcm));
+ }
+ }
+
+ // put after pcm_open, since apll + output widget, will trigger i2s at this stage
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(apTurnOnSequence);
+#else
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_hd_Switch"), "On")) {
+ ALOGE("Error: Audio_i2s0_hd_Switch invalid value");
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "On44100")) {
+ ALOGE("Error: Audio_i2s0_SideGen_Switch invalid value");
+ }
+#endif
+
+ mSmartPa.ops.init(&mSmartPa);
+
+#if defined(MTK_AUDIO_KS)
+ if (pcm) {
+ pcm_stop(pcm);
+ pcm_close(pcm);
+ pcm = NULL;
+ }
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(apTurnOnSequence);
+#else
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "Off")) {
+ ALOGE("Error: Audio_i2s0_SideGen_Switch invalid value");
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_hd_Switch"), "Off")) {
+ ALOGE("Error: Audio_i2s0_hd_Switch invalid value");
+ }
+#endif
+ } else {
+ mSmartPa.ops.init(&mSmartPa);
+ }
+ }
+
+#if defined(MTK_AUDIO_SMARTPASCP_SUPPORT)
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "mtk_scp_spk_set_iv_tcm_buf"), 0, true)) {
+ ALOGE("Error: mtk_scp_spk_set_iv_tcm_buf invalid value");
+ }
+#endif
+ return ret;
+}
+
+int AudioSmartPaController::deinit() {
+ if (mSmartPa.ops.deinit) {
+ mSmartPa.ops.deinit();
+ }
+
+ return 0;
+}
+
+int AudioSmartPaController::getI2sSetStage() {
+ return mSmartPa.attribute.i2sSetStage;
+}
+
+bool AudioSmartPaController::isInCalibration() {
+ ALOGD("+%s(), isCalibrating %d\n",__FUNCTION__, isCalibrating);
+
+ return isCalibrating;
+}
+
+bool AudioSmartPaController::isSmartPAUsed() {
+ if (mSmartPa.attribute.isSmartPAUsed)
+ return true;
+ else
+ return false;
+}
+
+bool AudioSmartPaController::isSmartPADynamicDetectSupport() {
+#if defined(SMARTPA_DYNAMIC_DETECT)
+ return true;
+#else
+ return false;
+#endif
+}
+
+int AudioSmartPaController::initSpkAmpType() {
+ struct mixer_ctl *ctl = mixer_get_ctl_by_name(mMixer, "MTK_SPK_TYPE_GET");
+
+ if (ctl == NULL) {
+ return SPK_INVALID_TYPE;
+ }
+
+ return mixer_ctl_get_value(ctl, 0);
+}
+
+int AudioSmartPaController::initSmartPaAttribute() {
+ struct SmartPaAttribute *attr = &mSmartPa.attribute;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ return -ENOENT;
+ }
+
+ AppHandle *appHandle = appOps->appHandleGetInstance();
+ const char *spkType = appOps->appHandleGetFeatureOptionValue(appHandle, "MTK_AUDIO_SPEAKER_PATH");
+ const char audioTypeName[] = "SmartPa";
+
+ if (strstr(spkType, "smartpa")) {
+ attr->isSmartPAUsed = true;
+ } else {
+ attr->isSmartPAUsed = false;
+ }
+
+ ALOGD("%s(), spkType: %s, isSmartPAUsed: %d, SmartPA dynamic detect: %d\n",
+ __FUNCTION__, spkType, attr->isSmartPAUsed, isSmartPADynamicDetectSupport());
+
+ if (!attr->isSmartPAUsed) {
+ return 0;
+ }
+
+ // extract parameters from xml
+ AudioType *audioType;
+ audioType = appOps->appHandleGetAudioTypeByName(appHandle, audioTypeName);
+ if (!audioType) {
+ ALOGW("error: get audioType fail, audioTypeName = %s", audioTypeName);
+ ASSERT(false);
+ return -ENOENT;
+ }
+
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ ParamUnit *paramUnit;
+ std::string paramName(spkType);
+ paramName = "Speaker type," + paramName;
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramName.c_str());
+ if (!paramUnit) {
+ ALOGW("error: get paramUnit fail, spkType = %s", paramName.c_str());
+ appOps->audioTypeUnlock(audioType);
+ ASSERT(false);
+ return -ENOENT;
+ }
+
+ Param *param;
+ param = appOps->paramUnitGetParamByName(paramUnit, "have_dsp");
+ ASSERT(param);
+ attr->dspType = *(int *)param->data;
+
+ param = appOps->paramUnitGetParamByName(paramUnit, "chip_delay_us");
+ ASSERT(param);
+ attr->chipDelayUs = *(unsigned int *)param->data;
+
+ // load lib path
+ if (In64bitsProcess()) {
+ param = appOps->paramUnitGetParamByName(paramUnit, "spk_lib64_path");
+ } else {
+ param = appOps->paramUnitGetParamByName(paramUnit, "spk_lib_path");
+ }
+ ASSERT(param);
+ ASSERT(sizeof(attr->spkLibPath) / sizeof(char) > strlen((char *)param->data));
+ memcpy(attr->spkLibPath, param->data, strlen((char *)param->data));
+
+ // get supported sample rate list, max rate, min rate
+ param = appOps->paramUnitGetParamByName(paramUnit, "supported_rate_list");
+ ASSERT(param);
+
+ if (param->arraySize * sizeof(attr->supportedRateList[0]) < sizeof(attr->supportedRateList)) {
+ memcpy(attr->supportedRateList, param->data, param->arraySize * sizeof(unsigned int));
+ } else {
+ ALOGE("%s(), support rate list too much", __FUNCTION__);
+ }
+
+ //get if is alsa codec
+ param = appOps->paramUnitGetParamByName(paramUnit, "is_alsa_codec");
+ ASSERT(param);
+ attr->isAlsaCodec = *(int *)param->data;
+
+ //get codec control name, for not dsp supported SmartPA
+ param = appOps->paramUnitGetParamByName(paramUnit, "codec_ctl_name");
+ ASSERT(param);
+ ASSERT(sizeof(attr->codecCtlName) / sizeof(char) > strlen((char *)param->data));
+ memcpy(attr->codecCtlName, param->data, strlen((char *)param->data));
+
+ //get is_apll_needed
+ param = appOps->paramUnitGetParamByName(paramUnit, "is_apll_needed");
+ ASSERT(param);
+ attr->isApllNeeded = *(int *)param->data;
+
+ //get i2s_set_stage
+ param = appOps->paramUnitGetParamByName(paramUnit, "i2s_set_stage");
+ ASSERT(param);
+ attr->i2sSetStage = *(unsigned int *)param->data;
+
+ ALOGD("dspType = %d, chipDelayUs = %d, spkLibPath = %s, is_alsa_codec = %d, codec_ctl_name = %s, is_apll_needed = %d, i2sSetStage = %d",
+ attr->dspType, attr->chipDelayUs, attr->spkLibPath, attr->isAlsaCodec,
+ attr->codecCtlName, attr->isApllNeeded, attr->i2sSetStage);
+
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ char rateStr[16] = {0};
+ char totalRateStr[512] = {0};
+ attr->supportedRateMax = 0;
+ attr->supportedRateMin = UINT_MAX;
+ for (size_t i = 0; i * sizeof(attr->supportedRateList[0]) < sizeof(attr->supportedRateList); i++) {
+ if (attr->supportedRateList[i] == 0) {
+ break;
+ }
+
+ if (attr->supportedRateList[i] > attr->supportedRateMax) {
+ attr->supportedRateMax = attr->supportedRateList[i];
+ }
+
+ if (attr->supportedRateList[i] < attr->supportedRateMin) {
+ attr->supportedRateMin = attr->supportedRateList[i];
+ }
+
+ memset(rateStr, 0, sizeof(rateStr));
+ snprintf(rateStr, sizeof(rateStr), "%d ", attr->supportedRateList[i]);
+ strncat(totalRateStr, rateStr, sizeof(totalRateStr) - strlen(totalRateStr) - 1);
+ }
+ ALOGD("%s(), supported rate: %s", __FUNCTION__, totalRateStr);
+
+#if defined(MTK_AUDIO_KS)
+ struct mixer_ctl *ctl;
+ ctl = mixer_get_ctl_by_name(mMixer, "MTK_SPK_I2S_OUT_TYPE_GET");
+ if (ctl == NULL) {
+ ASSERT(false);
+ return AUDIO_I2S_INVALID;
+ }
+ attr->i2sOutSelect = mixer_ctl_get_value(ctl, 0);
+
+ ctl = mixer_get_ctl_by_name(mMixer, "MTK_SPK_I2S_IN_TYPE_GET");
+ if (ctl == NULL) {
+ ASSERT(false);
+ return AUDIO_I2S_INVALID;
+ }
+ attr->i2sInSelect = mixer_ctl_get_value(ctl, 0);
+ ALOGD("i2sOutSelect = %d, i2sInSelect = %d",
+ attr->i2sOutSelect, attr->i2sInSelect);
+#endif
+
+ return 0;
+}
+
+int AudioSmartPaController::initSmartPaRuntime() {
+ mSmartPa.runtime.sampleRate = 44100;
+ mSmartPa.runtime.mode = AUDIO_MODE_NORMAL;
+ mSmartPa.runtime.device = PLAYBACK_DEVICE_SPEAKER;
+
+ return 0;
+}
+
+int AudioSmartPaController::speakerOn(unsigned int sampleRate, unsigned int device) {
+ ALOGD("%s(), sampleRate = %d, device = %d", __FUNCTION__, sampleRate, device);
+ int ret = 0;
+
+ // set runtime
+ mSmartPa.runtime.sampleRate = sampleRate;
+
+ // mixer ctrl
+#if !defined(MTK_AUDIO_KS)
+ if (getI2sSetStage() & SPK_I2S_BEFORE_SPK_ON)
+#endif
+ {
+ ret = dspOnBoardSpeakerOn(sampleRate);
+ }
+
+ if (strlen(mSmartPa.attribute.codecCtlName)) {
+ ret = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, mSmartPa.attribute.codecCtlName), "On");
+ if (ret) {
+ ALOGE("Error: %s invalid value, ret = %d", mSmartPa.attribute.codecCtlName, ret);
+ }
+ }
+
+ // speakerOn callback
+ if (mSmartPa.ops.speakerOn) {
+ setSmartPaRuntime(device);
+ mSmartPa.ops.speakerOn(&mSmartPa.runtime);
+ }
+
+ return ret;
+}
+
+int AudioSmartPaController::speakerOff() {
+ ALOGD("%s()", __FUNCTION__);
+
+ int ret = 0;
+
+ // speakerOff callback
+ if (mSmartPa.ops.speakerOff) {
+ mSmartPa.ops.speakerOff();
+ }
+
+ // mixer ctrl
+#if !defined(MTK_AUDIO_KS)
+ if (getI2sSetStage() & SPK_I2S_BEFORE_SPK_ON)
+#endif
+ {
+ ret = dspOnBoardSpeakerOff();
+ }
+
+ if (strlen(mSmartPa.attribute.codecCtlName)) {
+ ret = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, mSmartPa.attribute.codecCtlName), "Off");
+ if (ret) {
+ ALOGE("Error: %s invalid value, ret = %d", mSmartPa.attribute.codecCtlName, ret);
+ }
+ }
+
+ setI2sHD(false, getI2sOutSelect());
+
+ return ret;
+}
+
+unsigned int AudioSmartPaController::getSmartPaDelayUs() {
+ return mSmartPa.attribute.chipDelayUs;
+}
+
+unsigned int AudioSmartPaController::getMaxSupportedRate() {
+ return mSmartPa.attribute.supportedRateMax;
+}
+
+unsigned int AudioSmartPaController::getMinSupportedRate() {
+ return mSmartPa.attribute.supportedRateMin;
+}
+
+bool AudioSmartPaController::isRateSupported(unsigned int rate) {
+ struct SmartPaAttribute *attr = &mSmartPa.attribute;
+
+ for (size_t i = 0; i * sizeof(attr->supportedRateList[0]) < sizeof(attr->supportedRateList); i++) {
+ if (rate == attr->supportedRateList[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioSmartPaController::isAlsaCodec() {
+ if (mSmartPa.attribute.isAlsaCodec) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AudioSmartPaController::isHwDspSpkProtect(const int device) {
+ if (!(device & AUDIO_DEVICE_OUT_SPEAKER)) {
+ return false;
+ }
+
+ if (!mSmartPa.attribute.isSmartPAUsed) {
+ return false;
+ }
+
+ if (mSmartPa.attribute.dspType == SPK_ONBOARD_DSP) {
+ return true;
+ }
+
+ return false;
+}
+
+bool AudioSmartPaController::isSwDspSpkProtect(const int device) {
+ if (!(device & AUDIO_DEVICE_OUT_SPEAKER)) {
+ return false;
+ }
+
+ if (!mSmartPa.attribute.isSmartPAUsed) {
+ return false;
+ }
+
+ if (mSmartPa.attribute.dspType != SPK_ONBOARD_DSP) {
+ return true;
+ }
+
+ return false;
+}
+
+bool AudioSmartPaController::isApSideSpkProtect() {
+ if (!mSmartPa.attribute.isSmartPAUsed) {
+ return false;
+ }
+
+ if (mSmartPa.attribute.dspType == SPK_AP_DSP) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AudioSmartPaController::isBypassSwDspSpkProtect() {
+ if(mSmartPa.attribute.dspType != SPK_APSCP_DSP) {
+ return false;
+ }
+#if defined(MTK_AUDIODSP_SUPPORT)
+ if(mixer_ctl_get_value(mixer_get_ctl_by_name(mMixer,"swdsp_smartpa_process_enable"),0) == 1) {
+ ALOGD("%s(), ap smartpa process enabled", __FUNCTION__);
+ return false;
+ } else {
+ ALOGD("%s(), ap smartpa process not enabled", __FUNCTION__);
+ return true;
+ }
+#elif defined(MTK_AUDIO_SMARTPASCP_SUPPORT)
+ return false;
+#endif
+
+ return true;
+}
+
+unsigned int AudioSmartPaController::getSpkProtectType() {
+ return mSmartPa.attribute.dspType;
+}
+
+int AudioSmartPaController::getI2sOutSelect() {
+ return mSmartPa.attribute.i2sOutSelect;
+}
+
+int AudioSmartPaController::getI2sInSelect() {
+ return mSmartPa.attribute.i2sInSelect;
+}
+
+String8 AudioSmartPaController::getI2sSequence(const char *sequence, bool input) {
+ String8 i2sString;
+
+ switch (input ? getI2sInSelect() : getI2sOutSelect()) {
+ case AUDIO_I2S0:
+ i2sString = "I2S0";
+ break;
+ case AUDIO_I2S1:
+ i2sString = "I2S1";
+ break;
+ case AUDIO_I2S2:
+ i2sString = "I2S2";
+ break;
+ case AUDIO_I2S3:
+ i2sString = "I2S3";
+ break;
+ case AUDIO_I2S5:
+ i2sString = "I2S5";
+ break;
+ default:
+ ASSERT(0);
+ i2sString = input ? "I2S0" : "I2S3";
+ break;
+ }
+
+ return input ? i2sString + String8(sequence) : String8(sequence) + i2sString;
+}
+
+String8 AudioSmartPaController::getSphEchoRefSequence(bool enable, int md) {
+#if defined(MTK_AUDIO_KS)
+ switch(getI2sInSelect()) {
+ case AUDIO_I2S0:
+ if (md == MODEM_1) {
+ return String8(enable ? AUDIO_CTL_MD1_ECHO_REF_I2S0_ON : AUDIO_CTL_MD1_ECHO_REF_I2S0_OFF);
+ } else {
+ return String8(enable ? AUDIO_CTL_MD2_ECHO_REF_I2S0_ON : AUDIO_CTL_MD2_ECHO_REF_I2S0_OFF);
+ }
+ case AUDIO_I2S2:
+ if (md == MODEM_1) {
+ return String8(enable ? AUDIO_CTL_MD1_ECHO_REF_I2S2_ON : AUDIO_CTL_MD1_ECHO_REF_I2S2_OFF);
+ } else {
+ return String8(enable ? AUDIO_CTL_MD2_ECHO_REF_I2S2_ON : AUDIO_CTL_MD2_ECHO_REF_I2S2_OFF);
+ }
+ default:
+ ALOGE("%s(), i2s in %d not support", __FUNCTION__, getI2sInSelect());
+ ASSERT(0);
+ return String8();
+ };
+#else
+ ALOGV("%s(), enable %d, md %d", __FUNCTION__, enable, md);
+ return String8();
+#endif
+}
+
+int AudioSmartPaController::setI2sHD(bool enable, int i2sSelect) {
+#if defined(MTK_AUDIO_KS)
+ if (!mSmartPa.attribute.isApllNeeded) {
+ return 0;
+ }
+
+ String8 setting;
+
+ switch (i2sSelect) {
+ case AUDIO_I2S0:
+ setting = enable ? AUDIO_CTL_I2S0_HD_ON : AUDIO_CTL_I2S0_HD_OFF;
+ break;
+ case AUDIO_I2S1:
+ setting = enable ? AUDIO_CTL_I2S1_HD_ON : AUDIO_CTL_I2S1_HD_OFF;
+ break;
+ case AUDIO_I2S2:
+ setting = enable ? AUDIO_CTL_I2S2_HD_ON : AUDIO_CTL_I2S2_HD_OFF;
+ break;
+ case AUDIO_I2S3:
+ setting = enable ? AUDIO_CTL_I2S3_HD_ON : AUDIO_CTL_I2S3_HD_OFF;
+ break;
+ case AUDIO_I2S5:
+ setting = enable ? AUDIO_CTL_I2S5_HD_ON : AUDIO_CTL_I2S5_HD_OFF;
+ break;
+ default:
+ ALOGE("%s(), i2sOutSelect %d not support", __FUNCTION__, mSmartPa.attribute.i2sOutSelect);
+ ASSERT(0);
+ return -EINVAL;
+ break;
+ };
+
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceSettingByName(setting);
+ return 0;
+#else
+ ALOGV("%s(), enable %d, i2sSelect %d", __FUNCTION__, enable, i2sSelect);
+ return 0;
+#endif
+}
+
+int AudioSmartPaController::setI2sOutHD(bool enable) {
+ return setI2sHD(enable, getI2sOutSelect());
+}
+
+int AudioSmartPaController::setI2sInHD(bool enable) {
+ return setI2sHD(enable, getI2sInSelect());
+}
+
+int AudioSmartPaController::dspOnBoardSpeakerOn(unsigned int sampleRate) {
+ int ret = 0;
+ modem_index_t modem_index = SpeechDriverFactory::GetInstance()->GetActiveModemIndex();
+ ALOGD("+%s(), SampleRate = %d, MD_type = %d, Audio_i2s0_hd_Switch = %d\n",
+ __FUNCTION__, sampleRate, modem_index, mSmartPa.attribute.isApllNeeded);
+#if !defined(MTK_AUDIO_KS)
+ if (mSmartPa.attribute.isApllNeeded) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_hd_Switch"), "On")) {
+ ALOGE("Error: Audio_i2s0_hd_Switch invalid value");
+ }
+ }
+#endif
+
+ /* Config echo reference */
+ if ((AudioALSAStreamManager::getInstance()->isModeInPhoneCall() && isHwDspSpkProtect(AUDIO_DEVICE_OUT_SPEAKER)) ||
+ LoopbackManager::GetInstance()->CheckIsModemLoopback(LoopbackManager::GetInstance()->GetLoopbackType()) ||
+ AudioALSASpeechPhoneCallController::getInstance()->isAudioTaste()) {
+ ALOGD("Enable speaker echo reference path for MD");
+#if defined(MTK_AUDIO_KS)
+ struct pcm_config config;
+
+ memset(&config, 0, sizeof(config));
+ config.channels = 2;
+ config.rate = sampleRate;
+ config.period_size = 1024;
+ config.period_count = 2;
+ config.format = PCM_FORMAT_S16_LE;
+ config.stop_threshold = ~(0U);
+
+ int cardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmHostlessSphEchoRef);
+ int pcmIndex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessSphEchoRef);
+
+ setI2sHD(true, getI2sInSelect());
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceSettingByName(getSphEchoRefSequence(true, modem_index));
+
+ mPcmEcho = pcm_open(cardIndex, pcmIndex , PCM_OUT, &config);
+ mPcmEchoUL = pcm_open(cardIndex, pcmIndex , PCM_IN, &config);
+ if (mPcmEcho == NULL || pcm_is_ready(mPcmEcho) == false) {
+ ALOGE("%s(), Unable to open mPcmEcho device %u (%s)", __FUNCTION__, pcmIndex , pcm_get_error(mPcmEcho));
+ ASSERT(0);
+ } else {
+ if (pcm_start(mPcmEcho)) {
+ ALOGE("%s(), pcm_start mPcmEcho %p fail due to %s", __FUNCTION__, mPcmEcho, pcm_get_error(mPcmEcho));
+ ASSERT(0);
+ }
+ }
+ if (mPcmEchoUL == NULL || pcm_is_ready(mPcmEchoUL) == false) {
+ ALOGE("%s(), Unable to open mPcmEchoUL device %u (%s)", __FUNCTION__, pcmIndex , pcm_get_error(mPcmEchoUL));
+ ASSERT(0);
+ } else {
+ if (pcm_start(mPcmEchoUL)) {
+ ALOGE("%s(), pcm_start mPcmEchoUL %p fail due to %s", __FUNCTION__, mPcmEchoUL, pcm_get_error(mPcmEchoUL));
+ ASSERT(0);
+ }
+ }
+#else
+ if (modem_index == MODEM_1) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_ExtCodec_EchoRef_Switch"), "MD1")) {
+ ALOGE("Error: Audio_ExtCodec_EchoRef_Switch MD1 invalid value");
+ }
+ } else {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_ExtCodec_EchoRef_Switch"), "MD3")) {
+ ALOGE("Error: Audio_ExtCodec_EchoRef_Switch MD3 invalid value");
+ }
+ }
+#endif
+ }
+
+#if !defined(MTK_AUDIO_KS)
+ /* Config smartpa iv data */
+ if (getSpkProtectType() == SPK_APSCP_DSP) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_ExtCodec_EchoRef_Switch"), "SCP")) {
+ ALOGE("Error: Audio_ExtCodec_EchoRef_Switch SCP invalid value");
+ }
+ }
+
+ /* Enable SmartPa i2s */
+ switch (sampleRate) {
+ case 8000:
+ ret = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "On8000");
+ break;
+ case 16000:
+ ret = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "On16000");
+ break;
+ case 32000:
+ ret = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "On32000");
+ break;
+ case 44100:
+ ret = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "On44100");
+ break;
+ case 48000:
+ ret = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "On48000");
+ break;
+ case 96000:
+ ret = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "On96000");
+ break;
+ case 192000:
+ ret = mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "On192000");
+ break;
+ }
+
+ if (ret > 0) {
+ ALOGE("%s(), ERROR: Audio_i2s0_SideGen_Switch, ret = %d, samplerate = %d\n", __FUNCTION__, ret, sampleRate);
+ }
+#endif
+ return 0;
+}
+
+int AudioSmartPaController::dspOnBoardSpeakerOff() {
+ ALOGD("+%s()", __FUNCTION__);
+#if defined(MTK_AUDIO_KS)
+ if (mPcmEcho) {
+ pcm_stop(mPcmEcho);
+ pcm_close(mPcmEcho);
+ mPcmEcho = NULL;
+ }
+ if (mPcmEchoUL) {
+ pcm_stop(mPcmEchoUL);
+ pcm_close(mPcmEchoUL);
+ mPcmEchoUL = NULL;
+ }
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceSettingByName(getSphEchoRefSequence(false, MODEM_1));
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceSettingByName(getSphEchoRefSequence(false, MODEM_2));
+ setI2sHD(false, getI2sInSelect());
+#else
+ if (mixer_ctl_get_value(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), 0) > 0) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_SideGen_Switch"), "Off")) {
+ ALOGE("Error: Audio_i2s0_SideGen_Switch invalid value");
+ }
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_ExtCodec_EchoRef_Switch"), "Off")) {
+ ALOGE("Error: Audio_ExtCodec_EchoRef_Switch invalid value");
+ }
+
+ if (mSmartPa.attribute.isApllNeeded) {
+ ALOGV("+%s(), Audio_i2s0_hd_Switch off", __FUNCTION__);
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Audio_i2s0_hd_Switch"), "Off")) {
+ ALOGE("Error: Audio_i2s0_hd_Switch invalid value");
+ }
+ }
+#endif
+ return 0;
+}
+
+void AudioSmartPaController::setSmartPaRuntime(unsigned int device) {
+ struct SmartPaRuntime *runtime = &mSmartPa.runtime;
+
+ /* Get information of playback mode */
+ if (AudioALSAStreamManager::getInstance()->isModeInPhoneCall()) {
+ runtime->mode = AUDIO_MODE_IN_CALL;
+ } else if (AudioALSAStreamManager::getInstance()->isModeInVoipCall()) {
+ runtime->mode = AUDIO_MODE_IN_COMMUNICATION;
+ } else {
+ runtime->mode = AUDIO_MODE_NORMAL;
+ }
+
+ /* Get information of output device */
+ runtime->device = transformDeviceIndex(device);
+
+ ALOGD("+%s(), device = %d, mode = %d", __FUNCTION__, runtime->device, runtime->mode);
+}
+
+int AudioSmartPaController::transformDeviceIndex(const unsigned int device) {
+ unsigned int ret;
+
+ if (device & AUDIO_DEVICE_OUT_SPEAKER) {
+ ret = PLAYBACK_DEVICE_SPEAKER;
+ } else if (device == AUDIO_DEVICE_OUT_EARPIECE) {
+ ret = PLAYBACK_DEVICE_RECEIVER;
+ } else {
+ ALOGE("%s(), no such device supported.", __FUNCTION__);
+ ret = PLAYBACK_DEVICE_NONE;
+ ASSERT(false);
+ }
+
+ return ret;
+}
+
+int AudioSmartPaController::setSmartPaCalibration(int calibStage) {
+ ALOGD("+%s()", __FUNCTION__);
+ int result = 0;
+ char rmoveFolderCmd[64] = "rm -r ";
+ const char calibParamfilePath[] =
+ "/system/vendor/etc/smartpa_param/calib.dat";
+
+ if (!isSmartPAUsed()) {
+ ALOGD("%s(), SmartPA not support", __FUNCTION__);
+ return -1;
+ }
+
+ if (mSmartPa.ops.speakerCalibrate == NULL) {
+ ALOGE("%s(), speakerCalibrate callback not implement", __FUNCTION__);
+ ASSERT(0);
+ return -1;
+ }
+
+ int spk_type = getSpkProtectType();
+
+ if (spk_type == SPK_APSCP_DSP) {
+ switch (calibStage) {
+ case SPK_CALIB_STAGE_INIT:
+ // only use stream in dump
+ property_set(streamout_propty, "0");
+ property_set(streamin_propty, "1");
+ isCalibrating = true;
+
+#if defined(MTK_AUDIO_SMARTPASCP_SUPPORT)
+ AudioSmartPaParam::getInstance()->setParamFilePath(calibParamfilePath);
+#endif
+ result = mSmartPa.ops.speakerCalibrate(calibStage);
+ strncat(rmoveFolderCmd, audio_dump_path,
+ sizeof(rmoveFolderCmd) - strlen(rmoveFolderCmd) - 1);
+ strncat(rmoveFolderCmd, "*",
+ sizeof(rmoveFolderCmd) - strlen(rmoveFolderCmd) - 1);
+ result = system(rmoveFolderCmd);
+ if (result < 0) {
+ ALOGE("%s error", rmoveFolderCmd);
+ ASSERT(0);
+ } else {
+ ALOGD("%s pass", rmoveFolderCmd);
+ }
+ return result;
+ case SPK_CALIB_STAGE_DEINIT:
+ property_set(streamin_propty, "0");
+ isCalibrating = false;
+ return result;
+ default:
+ break;
+ }
+ }
+
+ result = mSmartPa.ops.speakerCalibrate(SPK_CALIB_STAGE_CALCULATE_AND_SAVE);
+
+ ALOGD("-%s(), result: %d", __FUNCTION__, result);
+ return result;
+}
+
+}
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioSmartPaParam.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioSmartPaParam.cpp
new file mode 100644
index 0000000..2412f26
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioSmartPaParam.cpp
@@ -0,0 +1,702 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioSmartPaParam.h"
+#include "AudioUtility.h"
+#include "AudioALSAStreamManager.h"
+#include <string>
+#include <dlfcn.h>
+#include <AudioMessengerIPI.h>
+#include <audio_task.h>
+#include "audio_spkprotect_msg_id.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioSmartPaParam"
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define DMA_BUFFER_SIZE (4096)
+#define AUDIO_SMARTPA_KEY_LEN (512)
+#define AUDIO_SMARTPA_DEFAULT_SAMPLERATE (48000)
+static char svalue[DMA_BUFFER_SIZE];
+
+
+namespace android {
+enum {
+ SMARTPA_VENDOR_DUMMY,
+ SMARTPA_VENDOR_MAXIM,
+ SMARTPA_VENDOR_NXP,
+ SMARTPA_VENDOR_RICHTEK,
+ SMARTPA_VENDOR_CIRRUS,
+ SMARTPA_VENDOR_MTK,
+ SMARTPA_VENDOR_NUM,
+};
+
+static const char *aurisys_param_suffix[] = {
+ ",PARAM_FILE,",
+ ",APPLY_PARAM,",
+ ",ADDR_VALUE,",
+ ",KEY_VALUE,",
+ ",ENABLE_DUMP,",
+ ",ENABLE_LOG,",
+};
+
+enum {
+ AURISYS_SET_PARAM_FILE,
+ AURISYS_SET_APPLY_PARAM,
+ AURISYS_SET_ADDR_VALUE,
+ AURISYS_SET_KEY_VALUE,
+ AURISYS_SET_ENABLE_DUMP,
+ AURISYS_SET_ENABLE_DSP_LOG,
+ AURISYS_SET_ENABLE_HAL_LOG,
+ AURISYS_GET_OFFSET = 0x10,
+ AURISYS_GET_ADDR_VALUE = AURISYS_GET_OFFSET + AURISYS_SET_ADDR_VALUE,
+ AURISYS_GET_KEY_VALUE,
+ AURISYS_PARAM_TOTAL_NUM,
+};
+
+static const char *aurisys_param_layer[] = {
+ ",DSP",
+ ",HAL",
+};
+
+enum {
+ AURISYS_PARAM_LAYER_DSP,
+ AURISYS_PARAM_LAYER_HAL,
+ AURISYS_PARAM_LAYER_NUM,
+};
+
+static const char *PROPERTY_KEY_SMARTPA_PARAM_PATH = "persist.vendor.audiohal.aurisys.smartpa_path";
+static const char *PROPERTY_KEY_PRODUCT_NAME = "ro.vendor.mediatek.platform";
+static const char *PROPERTY_KEY_PLATFROM_NAME = "ro.product.model";
+static const char *PROPERTY_KEY_PCM_DUMP_ON = "persist.vendor.audiohal.aurisys.pcm_dump_on";
+static char DEFAULT_SMARTPA_SYSTEM_PARAM_PATH[] = "/system/vendor/etc/smartpa_param/SmartPaVendor1_AudioParam.dat";
+static bool mEnableLibLogHAL = true;
+
+/* lib path reserve for flexibility*/
+#if defined(__LP64__)
+static char aurisys_vendor_lib_path[SMARTPA_VENDOR_NUM][256] = {
+ "/vendor/lib64/libaudiosmartpadummy.so",
+ "/vendor/lib64/libaudiosmartpamaxim.so",
+ "/vendor/lib64/libaudiosmartpanxp.so",
+ "/vendor/lib64/libaudiosmartparichtek.so",
+ "/vendor/lib64/libaudiosmartpacirrus.so",
+ "/vendor/lib64/libaudiosmartpamtk.so",
+};
+#else
+static char aurisys_vendor_lib_path[SMARTPA_VENDOR_NUM][256] = {
+ "/vendor/lib/libaudiosmartpadummy.so",
+ "/vendor/lib/libaudiosmartpamaxim.so",
+ "/vendor/lib/libaudiosmartpanxp.so",
+ "/vendor/lib/libaudiosmartparichtek.so",
+ "/vendor/lib/libaudiosmartpacirrus.so",
+ "/vendor/lib/libaudiosmartpamtk.so",
+};
+#endif
+
+static void smartPaPrint(const char *message, ...) {
+ if (mEnableLibLogHAL) {
+ static char printf_msg[DMA_BUFFER_SIZE];
+
+ va_list args;
+ va_start(args, message);
+
+ vsnprintf(printf_msg, sizeof(printf_msg), message, args);
+ ALOGD("%s", printf_msg);
+
+ va_end(args);
+ }
+}
+
+/*
+ * singleton
+ */
+AudioSmartPaParam *AudioSmartPaParam::mAudioSmartPaParam = NULL;
+
+AudioSmartPaParam *AudioSmartPaParam::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_UNLOCK(mGetInstanceLock);
+
+ if (mAudioSmartPaParam == NULL) {
+ mAudioSmartPaParam = new AudioSmartPaParam();
+ }
+
+ ASSERT(mAudioSmartPaParam != NULL);
+ return mAudioSmartPaParam;
+}
+
+/*
+ * constructor / destructor
+ */
+AudioSmartPaParam::AudioSmartPaParam() :
+ mAudioMessengerIPI(AudioMessengerIPI::getInstance()) {
+ getDefalutParamFilePath();
+ getDefaultProductName();
+ char property_value[PROPERTY_VALUE_MAX];
+
+ memset((void *)mSmartParamFilePath, 0, SMARTPA_STR_LENGTH);
+ memset((void *)mPhoneProductName, 0, SMARTPA_STR_LENGTH);
+ mParamBuf = NULL;
+ mEnableLibLogHAL = false;
+
+ mArsiTaskConfig = (arsi_task_config_t *)malloc(sizeof(arsi_task_config_t));
+ ASSERT(mArsiTaskConfig != NULL);
+ memset(mArsiTaskConfig, 0, sizeof(arsi_task_config_t));
+ initArsiTaskConfig();
+
+ mArsiLibConfig = (arsi_lib_config_t *)malloc(sizeof(arsi_lib_config_t));
+ ASSERT(mArsiLibConfig != NULL);
+ memset(mArsiLibConfig, 0, sizeof(arsi_lib_config_t));
+
+ initArsiLibconfig();
+
+ mParamBuf = (data_buf_t *)malloc(sizeof(data_buf_t));
+ ASSERT(mParamBuf != NULL);
+ memset(mParamBuf, 0, sizeof(data_buf_t));
+
+ mParamBuf->memory_size = DMA_BUFFER_SIZE;
+ mParamBuf->data_size = 0;
+ mParamBuf->p_buffer = malloc(mParamBuf->memory_size);
+ ASSERT(mParamBuf->p_buffer != NULL);
+
+ mAudioMessengerIPI->registerDmaCbk(TASK_SCENE_SPEAKER_PROTECTION,
+ DMA_BUFFER_SIZE,
+ DMA_BUFFER_SIZE,
+ processSmartPaDmaMsg,
+ NULL);
+
+ char *dlopen_lib_path = NULL;
+ int ret;
+ /* check and get dlopen_lib_path */
+ for (unsigned int i = 0 ; i < ARRAY_SIZE(aurisys_vendor_lib_path); i++) {
+ if (access(aurisys_vendor_lib_path[i], R_OK) == 0) {
+ dlopen_lib_path = aurisys_vendor_lib_path[i];
+ break;
+ }
+ }
+
+ // load lib
+ mLibHandle = dlopen(dlopen_lib_path, RTLD_NOW);
+
+ if (!mLibHandle) {
+ ALOGW("%s(), dlopen failed, dlerror = %s", __FUNCTION__, dlerror());
+ } else {
+ mtk_smartpa_param_init = (int (*)(struct SmartPAParamOps *))dlsym(mLibHandle, "mtk_smartpa_param_init");
+ if (!mtk_smartpa_param_init) {
+ ALOGW("%s(), dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ }
+ }
+
+ // lib init
+ if (mtk_smartpa_param_init) {
+ ret = mtk_smartpa_param_init(&mSmartPAParam);
+ if (ret) {
+ ALOGE("%s(), mtk_smartpa_param_init failed, ret = %d", __FUNCTION__, ret);
+ ASSERT(ret != 0);
+ }
+ }
+
+ /* get param_file_path */
+ char *param_file_path = NULL;
+ if (access(DEFAULT_SMARTPA_SYSTEM_PARAM_PATH, R_OK) == 0) {
+ param_file_path = DEFAULT_SMARTPA_SYSTEM_PARAM_PATH;
+ } else {
+ ALOGE("%s(), param_file_path not found!!", __FUNCTION__);
+ }
+
+ mEnableLibLogHAL = false;
+
+ setParamFilePath(DEFAULT_SMARTPA_SYSTEM_PARAM_PATH);
+ property_get(PROPERTY_KEY_PLATFROM_NAME, mPhoneProductName, "");
+
+ string_buf_t platform_info;
+ platform_info.memory_size = strlen(mPhoneProductName) + 1;
+ platform_info.string_size = strlen(mPhoneProductName);
+ platform_info.p_string = mPhoneProductName;
+
+ string_buf_t file_path;
+ file_path.memory_size = strlen(mSmartParamFilePath) + 1;
+ file_path.string_size = strlen(mSmartParamFilePath);
+ file_path.p_string = mSmartParamFilePath;
+
+ if (mSmartPAParam.loadParam) {
+ mSmartPAParam.loadParam(&platform_info, &file_path, smartPaPrint);
+ } else {
+ ALOGE("%s() mSmartPAParam.loadParam is NULL", __FUNCTION__);
+ ASSERT(0);
+ }
+
+ ALOGD("%s(), mSmartParamFilePath = %s, dlopen lib path: %s",
+ __FUNCTION__, mSmartParamFilePath, dlopen_lib_path);
+}
+
+AudioSmartPaParam::~AudioSmartPaParam() {
+
+ mAudioMessengerIPI->deregisterDmaCbk(TASK_SCENE_SPEAKER_PROTECTION);
+
+ if (mLibHandle) {
+ if (dlclose(mLibHandle)) {
+ ALOGE("%s(), dlclose failed, dlerror = %s",
+ __FUNCTION__, dlerror());
+ }
+ }
+
+ if (mArsiTaskConfig != NULL) {
+ free(mArsiTaskConfig);
+ mArsiTaskConfig = NULL;
+ }
+
+ if (mArsiLibConfig != NULL) {
+ free(mArsiLibConfig);
+ mArsiLibConfig = NULL;
+ }
+
+ if (mParamBuf->p_buffer != NULL) {
+ free(mParamBuf->p_buffer);
+ }
+
+ if (mParamBuf != NULL) {
+ free(mParamBuf);
+ mParamBuf = NULL;
+ }
+}
+
+void AudioSmartPaParam::initArsiLibconfig() {
+ /* alloc buffer in SCP */
+ mArsiLibConfig->p_ul_buf_in = NULL;
+ mArsiLibConfig->p_ul_buf_out = NULL;
+ mArsiLibConfig->p_ul_ref_bufs = NULL;
+
+ mArsiLibConfig->p_dl_buf_in = NULL;
+ mArsiLibConfig->p_dl_buf_out = NULL;
+ mArsiLibConfig->p_dl_ref_bufs = NULL;
+
+ /* lib */
+ mArsiLibConfig->sample_rate = AUDIO_SMARTPA_DEFAULT_SAMPLERATE;
+ mArsiLibConfig->audio_format = AUDIO_SMARTPA_DEFAULT_SAMPLERATE;
+ mArsiLibConfig->frame_size_ms = 0;
+ mArsiLibConfig->b_interleave = 0;
+}
+
+
+void AudioSmartPaParam::initArsiTaskConfig() {
+ /* output device */
+ mArsiTaskConfig->output_device_info.devices = AUDIO_DEVICE_OUT_SPEAKER;
+ mArsiTaskConfig->output_device_info.audio_format = AUDIO_FORMAT_PCM_32_BIT;
+ mArsiTaskConfig->output_device_info.sample_rate = AUDIO_SMARTPA_DEFAULT_SAMPLERATE;
+ mArsiTaskConfig->output_device_info.channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ mArsiTaskConfig->output_device_info.num_channels = 2;
+ mArsiTaskConfig->output_device_info.hw_info_mask = 0;
+
+ /* task scene */
+ mArsiTaskConfig->task_scene = TASK_SCENE_SPEAKER_PROTECTION;
+
+ /* audio mode */
+ mArsiTaskConfig->audio_mode = AUDIO_MODE_NORMAL;
+
+ /* max device capability for allocating memory */
+ mArsiTaskConfig->max_output_device_sample_rate = AUDIO_SMARTPA_DEFAULT_SAMPLERATE;
+ mArsiTaskConfig->max_output_device_num_channels = 2;
+}
+
+int AudioSmartPaParam::setArsiTaskConfig(const arsi_task_config_t *ArsiTaskConfig) {
+ memcpy((void *)mArsiTaskConfig, (void *)ArsiTaskConfig, sizeof(arsi_task_config_t));
+ return 0;
+}
+
+int AudioSmartPaParam::setArsiLibConfig(const arsi_lib_config_t *mArsiLibConfig) {
+ memcpy((void *)mArsiLibConfig, (void *)mArsiLibConfig, sizeof(arsi_lib_config_t));
+ return 0;
+}
+
+/* get param from lib and set to scp*/
+int AudioSmartPaParam::setSmartpaParam() {
+ ipi_msg_t ipi_msg;
+ int retval = NO_ERROR;
+ int ret;
+ uint32_t param_buf_size = 0;
+
+ string_buf_t platform_info;
+ platform_info.memory_size = strlen(mPhoneProductName) + 1;
+ platform_info.string_size = strlen(mPhoneProductName);
+ platform_info.p_string = mPhoneProductName;
+
+ string_buf_t file_path;
+ file_path.memory_size = strlen(mSmartParamFilePath) + 1;
+ file_path.string_size = strlen(mSmartParamFilePath);
+ file_path.p_string = mSmartParamFilePath;
+
+ string_buf_t custom_info;
+ char custom_info_str[2] = "";
+ custom_info.memory_size = strlen(custom_info_str) + 1;
+ custom_info.string_size = strlen(custom_info_str);
+ custom_info.p_string = custom_info_str;
+
+ if (mSmartPAParam.queryParamSize == NULL) {
+ ALOGE("%s arsi_query_param_buf_size == NULL", __FUNCTION__);
+ return -1;
+ }
+
+ ret = mSmartPAParam.queryParamSize(mArsiTaskConfig,
+ mArsiLibConfig,
+ &platform_info,
+ &file_path,
+ &custom_info,
+ ¶m_buf_size,
+ smartPaPrint);
+ if (mSmartPAParam.parsingParamFile == NULL) {
+ ALOGE("%s queryParamSize == NULL", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ memset(mParamBuf->p_buffer, 0, mParamBuf->memory_size);
+ ret = mSmartPAParam.parsingParamFile(mArsiTaskConfig,
+ mArsiLibConfig,
+ &platform_info,
+ &file_path,
+ &custom_info,
+ mParamBuf,
+ smartPaPrint);
+ ALOGD("%s mParamBuf->data_size = %u p_buffer = %s, param_buf_size = %u",
+ __FUNCTION__, mParamBuf->data_size,
+ (char *)mParamBuf->p_buffer, param_buf_size);
+ if (ret != NO_ERROR) {
+ ALOGW("parsingParamFile fail");
+ return UNKNOWN_ERROR;
+ }
+
+ retval = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_SPEAKER_PROTECTION, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_DMA, AUDIO_IPI_MSG_NEED_ACK,
+ SPK_IPI_MSG_A2D_PARAM, mParamBuf->data_size, 0,
+ (char *)mParamBuf->p_buffer);
+ return 0;
+}
+
+/* set param path to lib*/
+int AudioSmartPaParam::setParamFilePath(const char *str) {
+
+ if (str == NULL) {
+ strncpy(mSmartParamFilePath, DEFAULT_SMARTPA_SYSTEM_PARAM_PATH, strlen(DEFAULT_SMARTPA_SYSTEM_PARAM_PATH));
+ } else {
+ if (access(str, R_OK) != 0) {
+ ALOGE("%s(), %s can not access", __FUNCTION__, str);
+ return INVALID_OPERATION;
+ }
+ memset((void *)mSmartParamFilePath, '\0', SMARTPA_STR_LENGTH);
+ strncpy(mSmartParamFilePath, str, strlen(str));
+ ALOGD("%s(), SmartParamFilePath = %s", __FUNCTION__, mSmartParamFilePath);
+ }
+
+ property_set(PROPERTY_KEY_SMARTPA_PARAM_PATH, mSmartParamFilePath);
+
+ return 0;
+}
+
+int AudioSmartPaParam::setProductName(const char *str) {
+ if (str == NULL) {
+ property_get("ro.product.model", mPhoneProductName, "0");
+ } else {
+ ALOGD("mPhoneProductName = %s", mPhoneProductName);
+ }
+ return 0;
+}
+
+char *AudioSmartPaParam::getParamFilePath(void) {
+ return mSmartParamFilePath;
+}
+
+char *AudioSmartPaParam::getProductName(void) {
+ return mPhoneProductName;
+}
+
+int AudioSmartPaParam::getDefalutParamFilePath(void) {
+ memset(mSmartParamFilePath, 0, SMARTPA_STR_LENGTH);
+ strncpy(mSmartParamFilePath, DEFAULT_SMARTPA_SYSTEM_PARAM_PATH, strlen(DEFAULT_SMARTPA_SYSTEM_PARAM_PATH));
+ return 0;
+}
+
+int AudioSmartPaParam::getDefaultProductName(void) {
+ memset(mPhoneProductName, 0, SMARTPA_STR_LENGTH);
+ property_get("ro.product.model", mPhoneProductName, "0");
+ return 0;
+}
+
+
+int AudioSmartPaParam::getsetParameterPrefixlength(int paramindex) {
+ int parameterslength;
+ ALOGD("%s strlen(smartpa_aurisys_set_param_prefix = %zu %s", __FUNCTION__,
+ strlen(smartpa_aurisys_set_param_prefix), smartpa_aurisys_set_param_prefix);
+ ALOGD("%s strlen(aurisys_param_suffix[paramindex]) = %zu %s", __FUNCTION__,
+ strlen(aurisys_param_suffix[paramindex]), aurisys_param_suffix[paramindex]);
+ if (paramindex >= 0 && paramindex < AURISYS_PARAM_TOTAL_NUM)
+ parameterslength = strlen(smartpa_aurisys_set_param_prefix) + strlen(aurisys_param_suffix[paramindex]);
+ else {
+ parameterslength = 0;
+ }
+ ALOGD("%s parameterslength = %d", __FUNCTION__ , parameterslength);
+ return parameterslength;
+}
+
+int AudioSmartPaParam::getgetParameterPrefixlength(int paramindex) {
+ int parameterslength;
+ ALOGD("%s strlen(smartpa_aurisys_get_param_prefix = %zu %s", __FUNCTION__ ,
+ strlen(smartpa_aurisys_get_param_prefix), smartpa_aurisys_get_param_prefix);
+ ALOGD("%s strlen(aurisys_param_suffix[paramindex]) = %zu %s", __FUNCTION__,
+ strlen(aurisys_param_suffix[paramindex]), aurisys_param_suffix[paramindex]);
+ if (paramindex >= 0 && paramindex < AURISYS_PARAM_TOTAL_NUM)
+ parameterslength = strlen(smartpa_aurisys_get_param_prefix) + strlen(aurisys_param_suffix[paramindex]);
+ else {
+ parameterslength = 0;
+ }
+ ALOGD("%s parameterslength = %d", __FUNCTION__ , parameterslength);
+ return parameterslength;
+}
+
+void AudioSmartPaParam::parseSetParameterStr(const char *inputStr, char **outputStr,
+ const int paramindex) {
+ char *end = NULL;
+ char *comma = NULL;
+ strncpy(*outputStr, inputStr + getsetParameterPrefixlength(paramindex),
+ strlen(inputStr) - getsetParameterPrefixlength(paramindex));
+
+ end = strstr(*outputStr, "=SET");
+ if (end == NULL) {
+ AUD_LOG_W("%s() fail", __FUNCTION__);
+ }
+ *end = '\0';
+
+ comma = strstr(*outputStr, ",");
+ if (comma == NULL) {
+ AUD_LOG_W("%s() fail", __FUNCTION__);
+ }
+ *comma = '=';
+
+ ALOGD("%s parse_str = %s strlen = %zu paramindex = %d",
+ __FUNCTION__, *outputStr, strlen(*outputStr), paramindex);
+}
+
+bool AudioSmartPaParam::checkParameter(int ¶mindex, int &direction, const char *keyValue) {
+ int ret = 0;
+ /* init for index*/
+ paramindex = 0;
+ char *pch;
+ char keyValuePair[AUDIO_SMARTPA_KEY_LEN];
+ if (keyValue == NULL) {
+ ALOGD("%s = NULL", __FUNCTION__);
+ } else {
+ memcpy(keyValuePair, keyValue , AUDIO_SMARTPA_KEY_LEN);
+ }
+ ALOGD("%s = %s", __FUNCTION__, keyValuePair);
+
+ if (strncmp(smartpa_aurisys_set_param_prefix, keyValuePair, strlen(smartpa_aurisys_set_param_prefix)) == 0) {
+ ret = true;
+ } else if (strncmp(smartpa_aurisys_get_param_prefix, keyValuePair, strlen(smartpa_aurisys_get_param_prefix)) == 0) {
+ ret = true;
+ direction = AURISYS_GET_OFFSET;
+ } else {
+ ALOGE("%s return false", __FUNCTION__);
+ ret = false;
+ }
+
+ if (ret == true) {
+ ALOGD("1 %s = %s", __FUNCTION__, keyValuePair);
+ for (unsigned int i = 0; i < ARRAY_SIZE(aurisys_param_suffix) ; i++) {
+ pch = strstr(keyValuePair, aurisys_param_suffix[i]);
+ if (pch != NULL) {
+ paramindex = i;
+ ALOGD("%s aurisys_param_suffix pch = %s paramindex = %d", __FUNCTION__, pch, paramindex);
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+int AudioSmartPaParam::setParameter(const char *keyValuePair) {
+ ALOGD("%s keyValuePair = %s strlen = %zu",
+ __FUNCTION__, keyValuePair, strlen(keyValuePair));
+
+ int ret = 0;
+ const int max_parse_len = DMA_BUFFER_SIZE;
+ char output_str[DMA_BUFFER_SIZE];
+ char *parse_str = NULL;
+ int paramindex, direction;
+ ipi_msg_t ipi_msg;
+ int enable_dump = 0;
+ int enable_log = 0;
+ uint32_t aurisys_addr = 0;
+ uint32_t aurisys_value = 0;
+
+ memset(output_str, '\0', DMA_BUFFER_SIZE);
+
+ /* check if keyValuePair valid*/
+ if (checkParameter(paramindex, direction, keyValuePair) == true) {
+ parse_str = output_str;
+ parseSetParameterStr(keyValuePair, &parse_str, paramindex);
+ switch (paramindex) {
+ case AURISYS_SET_PARAM_FILE: {
+ setParamFilePath(output_str);
+ setSmartpaParam();
+ break;
+ }
+ case AURISYS_SET_ADDR_VALUE: {
+
+ sscanf(output_str, "%x,%x", &aurisys_addr, &aurisys_value);
+ ALOGD("addr = 0x%x, value = 0x%x", aurisys_addr, aurisys_value);
+ ret = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_SPEAKER_PROTECTION, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_NEED_ACK,
+ SPK_IPI_MSG_A2D_SET_ADDR_VALUE, aurisys_addr, aurisys_value, NULL);
+ break;
+ }
+ case AURISYS_SET_KEY_VALUE: {
+ ALOGD("key_value = %s", output_str);
+ ret = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_SPEAKER_PROTECTION, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_DMA, AUDIO_IPI_MSG_NEED_ACK,
+ SPK_IPI_MSG_A2D_SET_KEY_VALUE, strlen(output_str) + 1, 0,
+ output_str);
+ if (ret != NO_ERROR) {
+ ALOGW("SPK_IPI_MSG_A2D_SET_KEY_VALUE fail");
+ } else {
+ ALOGD("return %d", ipi_msg.param1);
+ }
+ break;
+ }
+ case AURISYS_SET_ENABLE_DUMP: {
+ sscanf(output_str, "%d", &enable_dump);
+ ret = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_SPEAKER_PROTECTION, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_BYPASS_ACK,
+ SPK_IPI_MSG_A2D_PCM_DUMP_ON, enable_dump, 0,
+ NULL);
+ break;
+ }
+ case AURISYS_SET_ENABLE_DSP_LOG: {
+ sscanf(output_str, "%d", &enable_log);
+ ALOGV("enh mode = %d", enable_log);
+ ret = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_SPEAKER_PROTECTION, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_BYPASS_ACK,
+ SPK_IPI_MSG_A2D_LIB_LOG_ON, enable_log, 0,
+ NULL);
+
+ break;
+ }
+ case AURISYS_SET_ENABLE_HAL_LOG: {
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ return ret;
+
+}
+
+char *AudioSmartPaParam::getParameter(const char *key) {
+ char *Retval = NULL;
+ status_t retval = NO_ERROR;
+ const int max_parse_len = DMA_BUFFER_SIZE;
+ char parse_str[DMA_BUFFER_SIZE];
+ char output_str[DMA_BUFFER_SIZE];
+ memset(parse_str, '\0', DMA_BUFFER_SIZE);
+ memset(output_str, '\0', DMA_BUFFER_SIZE);
+ int paramindex, direction;
+ ipi_msg_t ipi_msg;
+ uint32_t aurisys_addr = 0;
+ uint32_t aurisys_value = 0;
+
+ ALOGD("%s keyValuePair = %s strlen = %zu", __FUNCTION__, key, strlen(key));
+
+ /* check if keyValuePair valid*/
+ if (checkParameter(paramindex, direction, key) == true) {
+ strncpy(parse_str, key + getgetParameterPrefixlength(paramindex),
+ strlen(key) - getgetParameterPrefixlength(paramindex));
+ ALOGD("%s parse_str = %s strlen = %zu paramindex = %d direction = %d",
+ __FUNCTION__, parse_str, strlen(parse_str), paramindex, direction);
+
+ switch ((paramindex + direction)) {
+ case AURISYS_GET_ADDR_VALUE: {
+ uint32_t aurisys_addr = 0;
+ ALOGD("AURISYS_GET_KEY_VALUE key = %s", parse_str);
+ sscanf(parse_str, "%x", &aurisys_addr);
+ retval = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_SPEAKER_PROTECTION, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_PAYLOAD, AUDIO_IPI_MSG_NEED_ACK,
+ SPK_IPI_MSG_A2D_GET_ADDR_VALUE, aurisys_addr, 0,
+ NULL);
+
+ if (retval != NO_ERROR) {
+ ALOGW("IPI_MSG_A2D_GET_ADDR_VALUE fail");
+ } else {
+ ALOGD("param1 0x%x, param2 0x%x", ipi_msg.param1, ipi_msg.param2);
+ }
+
+ // can be modiied if
+ if (ipi_msg.param1 != 0) {
+ snprintf(svalue, DMA_BUFFER_SIZE - 1, "0x%x", ipi_msg.param2); // -1: for '\0'
+ } else {
+ strncpy(svalue, "GET_FAIL", DMA_BUFFER_SIZE - 1); // -1: for '\0'
+ }
+ ALOGD("svalue = %s", svalue);
+ return svalue;
+ }
+ case AURISYS_GET_KEY_VALUE: {
+ ALOGD("AURISYS_GET_KEY_VALUE key = %s", parse_str);
+
+ ipi_msg_t ipi_msg;
+ retval = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_SPEAKER_PROTECTION, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_DMA, AUDIO_IPI_MSG_NEED_ACK,
+ SPK_IPI_MSG_A2D_GET_KEY_VALUE, strlen(parse_str) + 1, max_parse_len,
+ parse_str);
+
+ if (retval != NO_ERROR) {
+ ALOGW("IPI_MSG_A2D_GET_KEY_VALUE fail");
+ } else {
+ ALOGD("param1 0x%x, param2 0x%x", ipi_msg.param1, ipi_msg.param2);
+ strncpy(output_str, parse_str, ipi_msg.param2);
+ }
+
+ ALOGD("key_value = %s", output_str);
+
+ char *p_eq = strstr(output_str, "=");
+ if (p_eq != NULL) {
+ ALOGD("p_eq = %s", p_eq);
+ }
+
+ if (ipi_msg.param1 == 1 &&
+ p_eq != NULL && p_eq < output_str + max_parse_len - 1) {
+ strncpy(svalue, strstr(output_str, "=") + 1, max_parse_len - 1); // -1: for '\0'
+ } else {
+ strncpy(svalue, "GET_FAIL", max_parse_len - 1); // -1: for '\0'
+ }
+ ALOGD("svalue = %s", svalue);
+ return svalue;
+ }
+ default:
+ break;
+ }
+ }
+
+ return Retval;
+}
+
+
+void AudioSmartPaParam::processSmartPaDmaMsg(ipi_msg_t *msg, void *buf, uint32_t size, void *arg) {
+ ALOGV("%s() msg_id=0x%x, task_scene=%d, param2=0x%x, size=%d, arg=%p, buf=%p\n",
+ __FUNCTION__, msg->msg_id, msg->task_scene, msg->param2, size, arg, buf);
+
+}
+
+
+}
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioSpeechEnhLayer.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioSpeechEnhLayer.cpp
new file mode 100644
index 0000000..650be89
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioSpeechEnhLayer.cpp
@@ -0,0 +1,3897 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sched.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "audio_custom_exp.h"
+#include <assert.h>
+#include <cutils/properties.h>
+#include "AudioSpeechEnhLayer.h"
+
+#include "AudioUtility.h"
+
+//#include <aee.h>
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioSPELayer"
+
+/*
+#define ASSERT(exp) \
+ do { \
+ if (!(exp)) { \
+ ALOGE("ASSERT("#exp") fail: \"" __FILE__ "\", %uL", __LINE__); \
+ aee_system_exception("[Audio]", NULL, DB_OPT_FTRACE, " %s, %uL", strrchr(__FILE__, '/') + 1, __LINE__); \
+ } \
+ } while(0)
+*/
+
+namespace android {
+
+Word16 DefaultRecDMNR_cal_data[DMNRCalDataNum] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+Word16 DefaultRecCompen_filter[CompenFilterNum] = {
+ 32767, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 32767, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 32767, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+uWord32 DefaultRecEnhancePara[EnhanceParasNum] =
+{96, 253, 16388, 32796, 49415, 0, 400, 0, 272, 4325, 99, 0, 0, 0, 0, 8192, 0, 0, 0, 10752, 32769, 0, 0, 0, 0, 0, 0, 0};
+
+Word16 DefaultVoIPDMNR_cal_data[DMNRCalDataNum] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+Word16 DefaultVoIPCompen_filter[CompenFilterNum] = {
+ 26, 15, -56, 27, -17, 39, -18, -44, 40, 5, \
+ 38, -63, 47, -79, 52, -22, 62, -47, 4, 24, \
+ -55, 46, -28, 123, -275, 241, -208, 328, -244, -13, \
+ 98, 176, -108, -746, 476, 111, 1661, -2136, 206, -1707, \
+ 5461, -5885, 2762, -1354, 19656, 19656, -1354, 2762, -5885, 5461, \
+ -1707, 206, -2136, 1661, 111, 476, -746, -108, 176, 98, \
+ -13, -244, 328, -208, 241, -275, 123, -28, 46, -55, \
+ 24, 4, -47, 62, -22, 52, -79, 47, -63, 38, \
+ 5, 40, -44, -18, 39, -17, 27, -56, 15, 26, \
+ \
+ 26, 15, -56, 27, -17, 39, -18, -44, 40, 5, \
+ 38, -63, 47, -79, 52, -22, 62, -47, 4, 24, \
+ -55, 46, -28, 123, -275, 241, -208, 328, -244, -13, \
+ 98, 176, -108, -746, 476, 111, 1661, -2136, 206, -1707, \
+ 5461, -5885, 2762, -1354, 19656, 19656, -1354, 2762, -5885, 5461, \
+ -1707, 206, -2136, 1661, 111, 476, -746, -108, 176, 98, \
+ -13, -244, 328, -208, 241, -275, 123, -28, 46, -55, \
+ 24, 4, -47, 62, -22, 52, -79, 47, -63, 38, \
+ 5, 40, -44, -18, 39, -17, 27, -56, 15, 26, \
+ \
+ -86, 73, -153, 155, -159, 46, 35, -237, 309, -476, \
+ 197, -317, -7, -32, -170, -50, 44, -50, -172, 283, \
+ -355, 226, -380, 453, -1049, 1171, -1117, 733, 624, -1369, \
+ 3057, -3450, 3730, -1053, 478, 3304, -4044, 3533, -3125, 2856, \
+ 4304, -12328, 23197, -17817, 23197, 23197, -17817, 23197, -12328, 4304, \
+ 2856, -3125, 3533, -4044, 3304, 478, -1053, 3730, -3450, 3057, \
+ -1369, 624, 733, -1117, 1171, -1049, 453, -380, 226, -355, \
+ 283, -172, -50, 44, -50, -170, -32, -7, -317, 197, \
+ -476, 309, -237, 35, 46, -159, 155, -153, 73, -86
+};
+uWord32 DefaultVoIPEnhancePara[EnhanceParasNum] =
+{96, 253, 16388, 31, 57607, 31, 400, 64, 80, 4325, 611, 0, 16392, 0, 0, 8192, 0, 0, 0, 10752, 32769, 0, 0, 0, 0, 0, 0, 0};
+
+#define MAX_DUMP_NUM (1024)
+#define COMPENSATE_PCM_DATA (0xCC)
+#define PREPARE_PROCESS_PCM_DATA (0x00)
+#define BYPASS_DL_PCM_DATA (0x00)
+
+int SPELayer::DumpFileNum = 0;
+bool SPELayer::EPLDebugEnable = false;
+
+
+int SPELayer::GetVoIPJitterTime(void) {
+ char value[PROPERTY_VALUE_MAX];
+ int ret = 0;
+ ret = property_get("vendor.SetJitterTime", value, "0");
+ int JitterTime = atoi(value);
+ ALOGD("GetVoIPJitterTime JitterTime=%d,ret=%d", JitterTime, ret);
+
+ return JitterTime;
+}
+int SPELayer::GetVoIPLatencyTime(void) {
+ char value[PROPERTY_VALUE_MAX];
+ int ret = 0;
+ ret = property_get("vendor.SetLatencyTime", value, "0");
+ int LatencyTime = atoi(value);
+ ALOGD("GetVoIPLatencyTime LatencyTime=%d,ret=%d", LatencyTime, ret);
+
+ return LatencyTime;
+}
+
+SPELayer::SPELayer() {
+ Mutex::Autolock lock(mLock);
+ ALOGD("%s+", __FUNCTION__);
+
+ memset(&mSphEnhOps, 0, sizeof(mSphEnhOps));
+
+ mSphCtrlBuffer = NULL;
+ mpSPEBufferUL1 = NULL;
+ mpSPEBufferUL2 = NULL;
+ mpSPEBufferDL = NULL;
+ mpSPEBufferFE = NULL;
+ mpSPEBufferNE = NULL;
+ mpSPEBufferDLDelay = NULL;
+ mULInBufQLenTotal = 0;
+ mDLInBufQLenTotal = 0;
+ mULOutBufQLenTotal = 0;
+ mDLOutBufQLenTotal = 0;
+ mDLDelayBufQLenTotal = 0;
+ mSPEProcessBufSize = 0;
+ mNsecPerSample = 0;
+ mMMI_ctrl_mask = MMI_CONTROL_MASK_ALL;
+
+ //Record settings
+ mRecordSampleRate = 48000; // sample rate=48k HSR record if sample rate=48k normal record
+ mRecordFrameRate = 20; // frame rate=20ms
+ mRecordMICDigitalGain = 16; //MIC_DG for AGC
+ mRecordULTotalGain = 184; //uplink totol gain
+ mRecordApp_table = 8; //mode = "8" stereo record, "4" mono record
+ mRecordFea_Cfg_table = 511; //without turing off anything
+
+ //VoIP settings
+ mPlatformOffsetTime = 0;
+ mLatencyTime = 0;
+ mVoIPSampleRate = 16000; //sample rate=16k
+ mLatencySampleCount = 0; //Latency sample count, one channel
+ mVoIPFrameRate = 20; //frame rate=20ms
+ mVoIPMICDigitalGain = 16; //MIC_DG for AGC
+ mVoIPULTotalGain = 184; //uplink totol gain
+ mVoIPApp_table = 2; //mode=WB_VOIP
+ mVoIPFea_Cfg_table = 511; //without turning off anything
+ mNeedDelayLatency = false;
+ mLatencyDir = true;
+
+ mNeedJitterBuffer = false;
+ mDefaultJitterBufferTime = 0;
+ mJitterBufferTime = GetVoIPJitterTime();
+ mJitterSampleCount = mJitterBufferTime * mVoIPSampleRate / 1000; //Jitter buffer sample count, one channel
+
+ //default record and VoIP parameters
+ for (int i = 0; i < EnhanceParasNum; i++) {
+ mRecordEnhanceParas[i] = DefaultRecEnhancePara[i];
+ mVoIPEnhanceParas[i] = DefaultVoIPEnhancePara[i];
+ }
+
+ for (int i = 0; i < DMNRCalDataNum; i++) {
+ mRecordDMNRCalData[i] = DefaultRecDMNR_cal_data[i];
+ mVoIPDMNRCalData[i] = DefaultVoIPDMNR_cal_data[i];
+ }
+
+ for (int i = 0; i < CompenFilterNum; i++) {
+ mRecordCompenFilter[i] = DefaultRecCompen_filter[i];
+ mVoIPCompenFilter[i] = DefaultVoIPCompen_filter[i];
+ }
+
+
+ mMode = SPE_MODE_NONE;
+ mRoute = ROUTE_NONE;
+ mState = SPE_STATE_IDLE;
+ mError = false;
+ mVoIPRunningbefore = false;
+
+ //for debug purpose
+ mfpInDL = NULL;
+ mfpInUL = NULL;
+ mfpOutDL = NULL;
+ mfpOutUL = NULL;
+ mfpProcessedDL = NULL;
+ mfpProcessedUL = NULL;
+ mfpEPL = NULL;
+ mfpVM = NULL;
+ mVMDumpEnable = false;
+
+ hDumpThread = 0;
+
+ memset(&mSph_Enh_ctrl, 0, sizeof(SPH_ENH_ctrl_struct));
+
+ mOutputStreamRunning = false;
+ mNormalModeVoIP = false;
+ mULDropTime = 0;
+ mDLLatencyTime = 0;
+ mCompensatedBufferSize = 0;
+ mFirstVoIPUplink = true;
+ mFirstVoIPDownlink = true;
+ mPreULBufLen = 0;
+ mPreDLBufLen = 0;
+ mDLNewStart = false;
+ mPrepareProcessDataReady = false;
+ mDLPreQnum = 5 * 4;
+ mDLPreQLimit = true;
+ DLdataPrepareCount = 0;
+ mNewReferenceBufferComes = false;
+ memset(&mUplinkIntrStartTime, 0, sizeof(timespec));
+ memset(&mPreUplinkEstTime, 0, sizeof(timespec));
+ memset(&mULIntrDeltaTime, 0, sizeof(timespec));
+ memset(&mDownlinkIntrStartTime, 0, sizeof(timespec));
+ memset(&mPreDownlinkEstTime, 0, sizeof(timespec));
+ memset(&mPreDownlinkQueueTime, 0, sizeof(timespec));
+
+ mDLStreamAttribute.mBufferSize = 8192;
+ mDLStreamAttribute.mChannels = 2;
+ mDLStreamAttribute.mSampleRate = 44100;
+
+ memset(mVMDumpFileName, 0, VM_DUMP_FILE_NAME_SIZE);
+
+ /* dlopen */
+ const char *error;
+ const char *funName = NULL;
+
+ mSphEnhOps.handle = dlopen("libspeech_enh_lib.so", RTLD_LAZY);
+ if (!mSphEnhOps.handle) {
+ ALOGE("%s(), dlopen fail! (%s)\n", __FUNCTION__, dlerror());
+ ASSERT(0);
+ return;
+ }
+ dlerror(); /* Clear any existing error */
+
+ /* dlsym */
+ funName = "ENH_API_Get_Memory";
+ mSphEnhOps.ENH_API_Get_Memory = (Word32(*)(SPH_ENH_ctrl_struct * Sph_Enh_ctrl)) dlsym(mSphEnhOps.handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ ASSERT(0);
+ return;
+ }
+
+ funName = "ENH_API_Alloc";
+ mSphEnhOps.ENH_API_Alloc = (Word16(*)(SPH_ENH_ctrl_struct * Sph_Enh_ctrl, Word32 * mem_ptr)) dlsym(mSphEnhOps.handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ ASSERT(0);
+ return;
+ }
+
+ funName = "ENH_API_Rst";
+ mSphEnhOps.ENH_API_Rst = (Word16(*)(SPH_ENH_ctrl_struct * Sph_Enh_ctrl)) dlsym(mSphEnhOps.handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ ASSERT(0);
+ return;
+ }
+
+ funName = "ENH_API_Process";
+ mSphEnhOps.ENH_API_Process = (void (*)(SPH_ENH_ctrl_struct * Sph_Enh_ctrl)) dlsym(mSphEnhOps.handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ ASSERT(0);
+ return;
+ }
+
+ funName = "ENH_API_Free";
+ mSphEnhOps.ENH_API_Free = (Word16(*)(SPH_ENH_ctrl_struct * Sph_Enh_ctrl)) dlsym(mSphEnhOps.handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ ASSERT(0);
+ return;
+ }
+
+ funName = "ENH_API_Get_Version";
+ mSphEnhOps.ENH_API_Get_Version = (Word16(*)(SPH_ENH_ctrl_struct * Sph_Enh_ctrl)) dlsym(mSphEnhOps.handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ ASSERT(0);
+ return;
+ }
+
+ Dump_Enalbe_Check();
+ DumpFileNum++;
+ DumpFileNum %= MAX_DUMP_NUM;
+ ALOGD("%s-", __FUNCTION__);
+}
+
+SPELayer::~SPELayer() {
+ Mutex::Autolock lock(mLock);
+ AL_LOCK(mBufMutex);
+ ALOGD("%s+", __FUNCTION__);
+
+ uint32_t timeoutMs = 20; //timeout time 20ms
+
+ mMode = SPE_MODE_NONE;
+ mRoute = ROUTE_NONE;
+ //mState = SPE_STATE_IDLE;
+
+ mError = false;
+
+ Clear();
+
+ FlushBufferQ();
+
+ if (hDumpThread != 0) {
+ hDumpThread = 0;
+ if (AL_WAIT_MS(mDumpExitMutex, timeoutMs) != NO_ERROR) {
+ ALOGD("%s, dumpthread close timeout?", __FUNCTION__);
+ }
+ AL_UNLOCK(mDumpExitMutex);
+ DumpBufferClear();
+ }
+
+ if (mfpInDL) {
+ fclose(mfpInDL);
+ mfpInDL = NULL;
+ }
+ if (mfpInUL) {
+ fclose(mfpInUL);
+ mfpInUL = NULL;
+ }
+ if (mfpOutDL) {
+ fclose(mfpOutDL);
+ mfpOutDL = NULL;
+ }
+ if (mfpOutUL) {
+ fclose(mfpOutUL);
+ mfpOutUL = NULL;
+ }
+ if (mfpProcessedDL) {
+ fclose(mfpProcessedDL);
+ mfpProcessedDL = NULL;
+ }
+ if (mfpProcessedUL) {
+ fclose(mfpProcessedUL);
+ mfpProcessedUL = NULL;
+ }
+ if (mfpEPL) {
+ fclose(mfpEPL);
+ mfpEPL = NULL;
+ }
+ if (mfpVM) {
+ fclose(mfpVM);
+ mfpVM = NULL;
+ }
+
+ if (mSphEnhOps.handle) {
+ dlclose(mSphEnhOps.handle);
+ mSphEnhOps.handle = NULL;
+ }
+
+ AL_UNLOCK(mBufMutex);
+ ALOGD("%s-", __FUNCTION__);
+}
+
+void SPELayer::FlushBufferQ(void) {
+ ALOGD("%s+", __FUNCTION__);
+ //clear the buffer queue, need mutex protect
+
+ ALOGD("FlushBufferQ mULOutBufferQ size=%zu,mULInBufferQ.size=%zu,mDLOutBufferQ.size()=%zu,mDLInBufferQ.size()=%zu,mDLDelayBufferQ.size()=%zu", mULOutBufferQ.size(), mULInBufferQ.size(),
+ mDLOutBufferQ.size(), mDLInBufferQ.size(), mDLDelayBufferQ.size());
+ if (mULOutBufferQ.size() != 0) {
+ while (mULOutBufferQ.size()) {
+ free(mULOutBufferQ[0]->pBufBase);
+ delete mULOutBufferQ[0];
+ mULOutBufferQ.removeAt(0);
+ }
+ mULOutBufferQ.clear();
+ }
+ if (mULInBufferQ.size() != 0) {
+ while (mULInBufferQ.size()) {
+ free(mULInBufferQ[0]->pBufBase);
+ delete mULInBufferQ[0];
+ mULInBufferQ.removeAt(0);
+ }
+ mULInBufferQ.clear();
+ }
+
+ if (mDLOutBufferQ.size() != 0) {
+ while (mDLOutBufferQ.size()) {
+ free(mDLOutBufferQ[0]->pBufBase);
+ delete mDLOutBufferQ[0];
+ mDLOutBufferQ.removeAt(0);
+ }
+ mDLOutBufferQ.clear();
+ }
+ if (mDLInBufferQ.size() != 0) {
+ while (mDLInBufferQ.size()) {
+ if (mDLInBufferQ[0]->pBufBase) {
+ ALOGD("mDLInBufferQ::pBufBase=%p", mDLInBufferQ[0]->pBufBase);
+ // free(mDLInBufferQ[0]->pBufBase);
+ // ALOGD("mDLInBufferQ::free");
+ // delete mDLInBufferQ[0];
+ // ALOGD("mDLInBufferQ::delete");
+ mDLInBufferQ.removeAt(0);
+ ALOGD("mDLInBufferQ::done, free at DLDelay buffer");
+ }
+ }
+ mDLInBufferQ.clear();
+ }
+
+ if (mDLDelayBufferQ.size() != 0) {
+ while (mDLDelayBufferQ.size()) {
+ if (mDLDelayBufferQ[0]->pBufBase) {
+ ALOGD("mDLDelayBufferQ::pBufBase=%p", mDLDelayBufferQ[0]->pBufBase);
+ free(mDLDelayBufferQ[0]->pBufBase);
+ ALOGD("mDLDelayBufferQ::free");
+ delete mDLDelayBufferQ[0];
+ ALOGD("mDLDelayBufferQ::delete");
+ mDLDelayBufferQ.removeAt(0);
+ ALOGD("mDLDelayBufferQ::done");
+ }
+
+ }
+ mDLDelayBufferQ.clear();
+ }
+
+ mULInBufQLenTotal = 0;
+ mDLInBufQLenTotal = 0;
+ mULOutBufQLenTotal = 0;
+ mDLOutBufQLenTotal = 0;
+ mDLDelayBufQLenTotal = 0;
+ mCompensatedBufferSize = 0;
+
+ ALOGD("%s-", __FUNCTION__);
+}
+
+bool SPELayer::MutexLock(void) {
+ mLock.lock();
+ return true;
+}
+bool SPELayer::MutexUnlock(void) {
+ mLock.unlock();
+ return true;
+}
+
+bool SPELayer::DumpMutexLock(void) {
+ mDumpLock.lock();
+ return true;
+}
+bool SPELayer::DumpMutexUnlock(void) {
+ mDumpLock.unlock();
+ return true;
+}
+
+//set MMI table, dynamic on/off
+bool SPELayer::SetDynamicFuncCtrl(const SPE_MMI_CONTROL_TABLE func, const bool enable) {
+ Mutex::Autolock lock(mLock);
+ const bool current_state = ((mMMI_ctrl_mask & func) > 0);
+ ALOGD("%s(), SetDynamicFuncCtrl %x(%x), enable(%d) == current_state(%d)",
+ __FUNCTION__, mMMI_ctrl_mask, func, enable, current_state);
+ /* if (current_state == enable) {
+ return false;
+ }*/
+ if (enable == false) {
+ mMMI_ctrl_mask &= (~func);
+ } else {
+ mMMI_ctrl_mask |= func;
+ //normal/handsfree mode DMNR are exclusive
+ if (func == HANDSFREE_DMNR) {
+ mMMI_ctrl_mask &= (~NORMAL_DMNR);
+ } else if (func == NORMAL_DMNR) {
+ mMMI_ctrl_mask &= (~HANDSFREE_DMNR);
+ }
+ }
+
+ mSph_Enh_ctrl.MMI_ctrl = mMMI_ctrl_mask;
+ ALOGD("%s(), SetDynamicFuncCtrl %x", __FUNCTION__, mMMI_ctrl_mask);
+ return true;
+}
+
+//parameters setting
+bool SPELayer::SetEnhPara(SPE_MODE mode, uWord32 *pEnhance_pars) {
+ switch (mode) {
+ case SPE_MODE_REC:
+ memcpy(&mRecordEnhanceParas, pEnhance_pars, EnhanceParasNum * sizeof(uWord32));
+ break;
+ case SPE_MODE_VOIP:
+ case SPE_MODE_AECREC:
+ memcpy(&mVoIPEnhanceParas, pEnhance_pars, EnhanceParasNum * sizeof(uWord32));
+ break;
+ default:
+ ALOGD("%s, not support mode", __FUNCTION__);
+ return false;
+ break;
+ }
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, SPE_MODE=%d", __FUNCTION__, mode);
+ }
+ /* for(int i=0; i<EnhanceParasNum; i++)
+ {
+ ALOGD("mRecordEnhanceParas[%d] %d",i,mRecordEnhanceParas[i]);
+ ALOGD("mSph_Enh_ctrl.enhance_pars[%d] %d",i,mSph_Enh_ctrl.enhance_pars[i]);
+ } */
+ return true;
+}
+
+bool SPELayer::SetDMNRPara(SPE_MODE mode, Word16 *pDMNR_cal_data) {
+ switch (mode) {
+ case SPE_MODE_REC:
+ memcpy(&mRecordDMNRCalData, pDMNR_cal_data, DMNRCalDataNum * sizeof(short));
+ break;
+ case SPE_MODE_VOIP:
+ case SPE_MODE_AECREC:
+ memcpy(&mVoIPDMNRCalData, pDMNR_cal_data, DMNRCalDataNum * sizeof(short));
+ break;
+ default:
+ ALOGD("%s, not support mode", __FUNCTION__);
+ return false;
+ break;
+ }
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, SPE_MODE=%d", __FUNCTION__, mode);
+ }
+ return true;
+}
+
+bool SPELayer::SetCompFilter(SPE_MODE mode, Word16 *pCompen_filter) {
+ switch (mode) {
+ case SPE_MODE_REC:
+ memcpy(&mRecordCompenFilter, pCompen_filter, CompenFilterNum * sizeof(short));
+ break;
+ case SPE_MODE_VOIP:
+ case SPE_MODE_AECREC:
+ memcpy(&mVoIPCompenFilter, pCompen_filter, CompenFilterNum * sizeof(short));
+ break;
+ default:
+ ALOGD("%s, not support mode", __FUNCTION__);
+ return false;
+ break;
+ }
+
+ ALOGD("%s, SPE_MODE=%d", __FUNCTION__, mode);
+
+ return true;
+}
+
+bool SPELayer::SetMICDigitalGain(SPE_MODE mode, Word32 gain) {
+ switch (mode) {
+ case SPE_MODE_REC:
+ mRecordMICDigitalGain = gain;
+ break;
+ case SPE_MODE_VOIP:
+ case SPE_MODE_AECREC:
+ mVoIPMICDigitalGain = gain;
+ break;
+ default:
+ ALOGD("%s, not support mode", __FUNCTION__);
+ return false;
+ break;
+ }
+
+ ALOGD("%s, MIC_DG, SPE_MODE=%d, gain=%d", __FUNCTION__, mode, gain);
+
+ return true;
+}
+
+
+bool SPELayer::SetUpLinkTotalGain(SPE_MODE mode, uint8_t gain) {
+ switch (mode) {
+ case SPE_MODE_REC:
+ mRecordULTotalGain = gain;
+ break;
+ case SPE_MODE_VOIP:
+ case SPE_MODE_AECREC:
+ mVoIPULTotalGain = gain;
+ break;
+ default:
+ ALOGD("%s, not support mode", __FUNCTION__);
+ return false;
+ break;
+ }
+
+ ALOGD("%s, SPE_MODE=%d, gain=%d", __FUNCTION__, mode, gain);
+
+ return true;
+}
+
+bool SPELayer::SetSampleRate(SPE_MODE mode, long sample_rate) {
+
+ switch (mode) {
+ case SPE_MODE_REC:
+ if (sample_rate != 16000 && sample_rate != 48000) {
+ ALOGD("%s, Record only support 16k or 48k samplerate", __FUNCTION__);
+ mRecordSampleRate = 48000;
+ return false;
+ }
+ mRecordSampleRate = sample_rate;
+ break;
+ case SPE_MODE_VOIP:
+ case SPE_MODE_AECREC:
+ if (sample_rate != 16000) {
+ ALOGD("%s, VOIP only support 16k samplerate", __FUNCTION__);
+ }
+
+ mVoIPSampleRate = 16000;
+ break;
+ default:
+ ALOGD("%s, not support mode", __FUNCTION__);
+ return false;
+ break;
+ }
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, SPE_MODE=%d", __FUNCTION__, mode);
+ }
+ return true;
+}
+
+bool SPELayer::SetFrameRate(SPE_MODE mode, long frame_rate) {
+
+ if (frame_rate != 10 && frame_rate != 20 && frame_rate != 5 && frame_rate != 3 && frame_rate != 2 && frame_rate != 1) {
+ ALOGD("%s, not supported framerate", __FUNCTION__);
+ return false;
+ }
+
+ switch (mode) {
+ case SPE_MODE_REC:
+ mRecordFrameRate = frame_rate;
+ break;
+ case SPE_MODE_VOIP:
+ case SPE_MODE_AECREC:
+ mVoIPFrameRate = frame_rate;
+ break;
+ default:
+ ALOGD("%s, not support mode", __FUNCTION__);
+ return false;
+ break;
+ }
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, SPE_MODE=%d, frame_rate=%lu", __FUNCTION__, mode, frame_rate);
+ }
+ return true;
+}
+
+bool SPELayer::SetAPPTable(SPE_MODE mode, SPE_APP_TABLE App_table) {
+ switch (mode) {
+ case SPE_MODE_REC:
+ mRecordApp_table = App_table;
+ break;
+ case SPE_MODE_VOIP:
+ case SPE_MODE_AECREC:
+ mVoIPApp_table = App_table;
+ break;
+ default:
+ ALOGD("%s, not support mode", __FUNCTION__);
+ return false;
+ break;
+ }
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, SPE_MODE=%d, App_table=%x", __FUNCTION__, mode, App_table);
+ }
+
+ return true;
+}
+
+bool SPELayer::SetFeaCfgTable(SPE_MODE mode, Word32 Fea_Cfg_table) {
+
+ switch (mode) {
+ case SPE_MODE_REC:
+ mRecordFea_Cfg_table = Fea_Cfg_table;
+ break;
+ case SPE_MODE_VOIP:
+ case SPE_MODE_AECREC:
+ mVoIPFea_Cfg_table = Fea_Cfg_table;
+ break;
+ default:
+ ALOGD("%s, not support mode", __FUNCTION__);
+ return false;
+ break;
+ }
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, SPE_MODE=%d,Fea_Cfg_table=%x", __FUNCTION__, mode, Fea_Cfg_table);
+ }
+ return true;
+}
+
+bool SPELayer::SetPlatfromTimeOffset(int ms) {
+ ALOGD("%s, old=%d, new=%d", __FUNCTION__, mPlatformOffsetTime, ms);
+ mPlatformOffsetTime = ms;
+ return true;
+}
+
+bool SPELayer::SetChannel(int channel) {
+ if (channel == 1) { //mono
+ mRecordApp_table = 4; //mode = "8" stereo record, "4" mono record
+ } else { //stereo
+ mRecordApp_table = 8;
+ }
+
+ ALOGD("%s, only for recording, mRecordApp_table=%x", __FUNCTION__, mRecordApp_table);
+ return true;
+}
+
+int SPELayer::GetChannel() {
+ if (mRecordApp_table == 4) {
+ return 1;
+ } else {
+ return 2;
+ }
+}
+/*
+bool SPELayer::SetMode(SPE_MODE mode)
+{
+ ALOGD("SPELayer::SetMode %d",mode);
+
+ if((mode!=SPE_MODE_REC) && (mode!=SPE_MODE_VOIP))
+ {
+ ALOGD("SPELayer::SetMode, SPE_MODE not correct");
+ return false;
+ }
+
+ if (mMode == mode)
+ return true;
+
+ mMode = mode;
+ return true;
+}
+*/
+
+bool SPELayer::SetRoute(SPE_ROUTE route) {
+ ALOGD("%s, %d", __FUNCTION__, route);
+
+ if ((route < ROUTE_NONE) || (route >= ROUTE_MAX)) {
+ ALOGE("%s, route not correct", __FUNCTION__);
+ return false;
+ }
+
+ if (mRoute == route) {
+ return true;
+ }
+
+ mRoute = route;
+ return true;
+}
+
+void SPELayer::SetStreamAttribute(bool direct, StreamAttribute SA) { //direct=0 =>downlink stream info, direct=1 =>uplink stream info
+ ALOGD("%s(), direct=%d", __FUNCTION__, direct);
+ if (direct) {
+ ALOGD("%s(), not support uplink stream info yet", __FUNCTION__);
+ } else {
+ memcpy(&mDLStreamAttribute, &SA, sizeof(StreamAttribute));
+ }
+ ALOGD("%s(), mBufferSize=%d, mChannels=%d, mSampleRate=%d", __FUNCTION__, mDLStreamAttribute.mBufferSize, mDLStreamAttribute.mChannels, mDLStreamAttribute.mSampleRate);
+ CalPreQNumber();
+ return;
+}
+
+void SPELayer::CalPreQNumber(void) {
+ int framecount = mDLStreamAttribute.mBufferSize / mDLStreamAttribute.mChannels / 2;
+ int DLPreQfact = 200 / (framecount * 1000 / mDLStreamAttribute.mSampleRate);
+ mDLPreQnum = DLPreQfact;
+ if (EPLDebugEnable == true) {
+ ALOGD("%s(), mDLPreQnum=%d, DLdataPrepareCount=%d", __FUNCTION__, mDLPreQnum, DLdataPrepareCount);
+ }
+}
+
+void SPELayer::CalPrepareCount(void) {
+ int framecount = mDLStreamAttribute.mBufferSize / mDLStreamAttribute.mChannels / 2;
+ int DLPreparefact = 100 / (framecount * 1000 / mDLStreamAttribute.mSampleRate);
+ DLdataPrepareCount = DLPreparefact;
+ if (EPLDebugEnable == true) {
+ ALOGD("%s(), mDLPreQnum=%d, DLdataPrepareCount=%d", __FUNCTION__, mDLPreQnum, DLdataPrepareCount);
+ }
+}
+
+//Get parameters setting
+int SPELayer::GetLatencyTime() {
+ //only for VoIP
+ return mLatencyTime;
+}
+
+SPE_MODE SPELayer::GetMode() {
+ return mMode;
+}
+
+SPE_ROUTE SPELayer::GetRoute() {
+ return mRoute;
+}
+bool SPELayer::IsSPERunning() {
+ if (mState == SPE_STATE_RUNNING) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+long SPELayer::GetSampleRate(SPE_MODE mode) {
+ long retSampleRate = 0;
+ switch (mode) {
+ case SPE_MODE_REC:
+ retSampleRate = mRecordSampleRate;
+ break;
+ case SPE_MODE_VOIP:
+ case SPE_MODE_AECREC:
+ retSampleRate = mVoIPSampleRate;
+ break;
+ default:
+ retSampleRate = mSph_Enh_ctrl.sample_rate;
+ break;
+ }
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, SPE_MODE=%d, retSampleRate=%lu", __FUNCTION__, mode, retSampleRate);
+ }
+ return retSampleRate;
+}
+
+long SPELayer::GetFrameRate(SPE_MODE mode) {
+ long retFrameRate = 0;
+ switch (mode) {
+ case SPE_MODE_REC:
+ retFrameRate = mRecordFrameRate;
+ break;
+ case SPE_MODE_VOIP:
+ case SPE_MODE_AECREC:
+ retFrameRate = mVoIPFrameRate;
+ break;
+ default:
+ retFrameRate = mSph_Enh_ctrl.frame_rate;
+ break;
+ }
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, SPE_MODE=%d, retFrameRate=%lu", __FUNCTION__, mode, retFrameRate);
+ }
+ return retFrameRate;
+}
+
+Word32 SPELayer::GetMICDigitalGain(SPE_MODE mode) {
+ long retPGAGain = 0;
+ switch (mode) {
+ case SPE_MODE_REC:
+ retPGAGain = mRecordMICDigitalGain;
+ break;
+ case SPE_MODE_VOIP:
+ case SPE_MODE_AECREC:
+ retPGAGain = mVoIPMICDigitalGain;
+ break;
+ default:
+ retPGAGain = mSph_Enh_ctrl.MIC_DG;
+ break;
+ }
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, SPE_MODE=%d, retPGAGain=%lu", __FUNCTION__, mode, retPGAGain);
+ }
+ return retPGAGain;
+}
+
+Word32 SPELayer::GetAPPTable(SPE_MODE mode) {
+ Word32 retAPPTable = 0;
+ switch (mode) {
+ case SPE_MODE_REC:
+ retAPPTable = mRecordApp_table;
+ break;
+ case SPE_MODE_VOIP:
+ case SPE_MODE_AECREC:
+ retAPPTable = mVoIPApp_table;
+ break;
+ default:
+ retAPPTable = mSph_Enh_ctrl.App_table;
+ break;
+ }
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, SPE_MODE=%d, retAPPTable=%x", __FUNCTION__, mode, retAPPTable);
+ }
+ return retAPPTable;
+}
+
+Word32 SPELayer::GetFeaCfgTable(SPE_MODE mode) {
+ long retFeaCfgTable = 0;
+ switch (mode) {
+ case SPE_MODE_REC:
+ retFeaCfgTable = mRecordFea_Cfg_table;
+ break;
+ case SPE_MODE_VOIP:
+ case SPE_MODE_AECREC:
+ retFeaCfgTable = mVoIPFea_Cfg_table;
+ break;
+ default:
+ retFeaCfgTable = mSph_Enh_ctrl.Fea_Cfg_table;
+ break;
+ }
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, SPE_MODE=%d, retFeaCfgTable=%lu", __FUNCTION__, mode, retFeaCfgTable);
+ }
+ return retFeaCfgTable;
+}
+
+bool SPELayer::GetEnhPara(SPE_MODE mode, uWord32 *pEnhance_pars) {
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, SPE_MODE=%d", __FUNCTION__, mode);
+ }
+ switch (mode) {
+ case SPE_MODE_REC:
+ memcpy(pEnhance_pars, &mRecordEnhanceParas, EnhanceParasNum * sizeof(uWord32));
+ break;
+ case SPE_MODE_VOIP:
+ case SPE_MODE_AECREC:
+ memcpy(pEnhance_pars, &mVoIPEnhanceParas, EnhanceParasNum * sizeof(uWord32));
+ break;
+ default:
+ memcpy(pEnhance_pars, &mSph_Enh_ctrl.enhance_pars, EnhanceParasNum * sizeof(uWord32));
+ break;
+ }
+
+ return true;
+}
+
+bool SPELayer::GetDMNRPara(SPE_MODE mode, Word16 *pDMNR_cal_data) {
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, SPE_MODE=%d", __FUNCTION__, mode);
+ }
+ switch (mode) {
+ case SPE_MODE_REC:
+ memcpy(pDMNR_cal_data, &mRecordDMNRCalData, DMNRCalDataNum * sizeof(Word16));
+ break;
+ case SPE_MODE_VOIP:
+ case SPE_MODE_AECREC:
+ memcpy(pDMNR_cal_data, &mVoIPDMNRCalData, DMNRCalDataNum * sizeof(Word16));
+ break;
+ default:
+ memcpy(pDMNR_cal_data, &mSph_Enh_ctrl.DMNR_cal_data, DMNRCalDataNum * sizeof(Word16));
+ break;
+ }
+
+ return true;
+}
+
+bool SPELayer::GetCompFilter(SPE_MODE mode, Word16 *pCompen_filter) {
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, SPE_MODE=%d", __FUNCTION__, mode);
+ }
+ switch (mode) {
+ case SPE_MODE_REC:
+ memcpy(pCompen_filter, &mRecordCompenFilter, CompenFilterNum * sizeof(short));
+ break;
+ case SPE_MODE_VOIP:
+ case SPE_MODE_AECREC:
+ memcpy(pCompen_filter, &mVoIPCompenFilter, CompenFilterNum * sizeof(short));
+ break;
+ default:
+ memcpy(pCompen_filter, &mSph_Enh_ctrl.Compen_filter, CompenFilterNum * sizeof(short));
+ break;
+ }
+
+ return true;
+}
+
+bool SPELayer::GetUPlinkIntrStartTime() {
+ Mutex::Autolock lock(mLock);
+ if (mState == SPE_STATE_RUNNING) {
+ return false;
+ }
+
+ mUplinkIntrStartTime = GetSystemTime();
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, sec=%lu, nsec=%lu", __FUNCTION__, mUplinkIntrStartTime.tv_sec, mUplinkIntrStartTime.tv_nsec);
+ }
+ mFirstVoIPUplink = true;
+ mDLPreQLimit = false;
+ return true;;
+}
+
+bool SPELayer::SetUPLinkIntrStartTime(struct timespec UPlinkStartTime) {
+ Mutex::Autolock lock(mLock);
+ if (mState == SPE_STATE_RUNNING) {
+ return false;
+ }
+
+ mUplinkIntrStartTime = UPlinkStartTime;
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, sec=%lu, nsec=%lu", __FUNCTION__, mUplinkIntrStartTime.tv_sec, mUplinkIntrStartTime.tv_nsec);
+ }
+ mFirstVoIPUplink = true;
+ mDLPreQLimit = false;
+ return true;;
+}
+
+bool SPELayer::GetDownlinkIntrStartTime() {
+ Mutex::Autolock lock(mLock);
+ AL_LOCK(mBufMutex);
+ mDownlinkIntrStartTime = GetSystemTime();
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, sec=%lu, nsec=%lu, size=%zu, mDLDelayBufferQ size()=%zu", __FUNCTION__, mDownlinkIntrStartTime.tv_sec, mDownlinkIntrStartTime.tv_nsec, mDLInBufferQ.size(), mDLDelayBufferQ.size());
+ }
+ if (mDLInBufferQ.size() > 0) {
+ for (size_t i = 0; i < mDLInBufferQ.size() ; i++) {
+ if (mDLInBufferQ[i]->DLfirstBuf == true) {
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, update estimate time", __FUNCTION__);
+ }
+ mDLInBufferQ[i]->time_stamp_estimate.tv_sec = mDownlinkIntrStartTime.tv_sec;
+ mDLInBufferQ[i]->time_stamp_estimate.tv_nsec = mDownlinkIntrStartTime.tv_nsec;
+ mPreDownlinkEstTime.tv_sec = mDownlinkIntrStartTime.tv_sec;
+ mPreDownlinkEstTime.tv_nsec = mDownlinkIntrStartTime.tv_nsec;
+ mPreDownlinkQueueTime.tv_sec = mDownlinkIntrStartTime.tv_sec;
+ mPreDownlinkQueueTime.tv_nsec = mDownlinkIntrStartTime.tv_nsec;
+ }
+ }
+ for (size_t i = 0; i < mDLDelayBufferQ.size() ; i++) {
+ if (mDLDelayBufferQ[i]->DLfirstBuf == true) {
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, update estimate time mDLDelayBufferQ", __FUNCTION__);
+ }
+ mDLDelayBufferQ[i]->time_stamp_estimate.tv_sec = mDownlinkIntrStartTime.tv_sec;
+ mDLDelayBufferQ[i]->time_stamp_estimate.tv_nsec = mDownlinkIntrStartTime.tv_nsec;
+ }
+ }
+ }
+ mDLNewStart = false;
+ AL_UNLOCK(mBufMutex);
+ return true;;
+}
+
+void SPELayer::SetEchoRefStartTime(struct timespec EchoRefStartTime) {
+ Mutex::Autolock lock(mLock);
+ mDownlinkIntrStartTime = EchoRefStartTime;
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, sec=%lu, nsec=%lu, size=%zu, mDLDelayBufferQ size()=%zu", __FUNCTION__, mDownlinkIntrStartTime.tv_sec, mDownlinkIntrStartTime.tv_nsec, mDLInBufferQ.size(), mDLDelayBufferQ.size());
+ }
+ mDLNewStart = false;
+}
+
+//speech enhancement setting and process
+bool SPELayer::Start(SPE_MODE mode) { //for VOIP, both uplink/downlink
+ if (EPLDebugEnable == true) {
+ ALOGD("%s+, mode=%d", __FUNCTION__, mode);
+ }
+ Mutex::Autolock lock(mLock);
+ if (mState == SPE_STATE_RUNNING) {
+ ALOGD("%s already start!", __FUNCTION__);
+ return false;
+ }
+
+ if ((mMode != SPE_MODE_NONE) && (mMode != mode)) {
+ AL_LOCK(mBufMutex);
+ FlushBufferQ();
+ AL_UNLOCK(mBufMutex);
+ }
+
+ // set mSph_Enh_ctrl parameters
+ if (mode == SPE_MODE_REC) {
+ mSph_Enh_ctrl.sample_rate = mRecordSampleRate;
+ mSph_Enh_ctrl.frame_rate = mRecordFrameRate;
+ mSph_Enh_ctrl.MIC_DG = mRecordMICDigitalGain;
+ mSph_Enh_ctrl.Fea_Cfg_table = mRecordFea_Cfg_table;
+ mSph_Enh_ctrl.App_table = mRecordApp_table;
+ mSph_Enh_ctrl.MMI_ctrl = mMMI_ctrl_mask;
+ mSph_Enh_ctrl.MMI_MIC_GAIN = mRecordULTotalGain;
+ memcpy(&mSph_Enh_ctrl.enhance_pars, &mRecordEnhanceParas, EnhanceParasNum * sizeof(uWord32));
+ memcpy(&mSph_Enh_ctrl.DMNR_cal_data, &mRecordDMNRCalData, DMNRCalDataNum * sizeof(Word16));
+ memcpy(&mSph_Enh_ctrl.Compen_filter, &mRecordCompenFilter, CompenFilterNum * sizeof(Word16));
+ ALOGD("mRecordSampleRate=%d, mRecordFrameRate=%d, mRecordApp_table=%x", mRecordSampleRate, mRecordFrameRate, mRecordApp_table);
+ } else if ((mode == SPE_MODE_VOIP) || (mode == SPE_MODE_AECREC)) {
+ mSph_Enh_ctrl.sample_rate = mVoIPSampleRate;
+ mSph_Enh_ctrl.frame_rate = mVoIPFrameRate;
+ mSph_Enh_ctrl.MIC_DG = mVoIPMICDigitalGain;
+ mSph_Enh_ctrl.Fea_Cfg_table = mVoIPFea_Cfg_table;
+ mSph_Enh_ctrl.App_table = mVoIPApp_table;
+ if (mode == SPE_MODE_AECREC) {
+ mNormalModeVoIP = true;
+ }
+
+ mSph_Enh_ctrl.MMI_ctrl = mMMI_ctrl_mask;
+ mSph_Enh_ctrl.MMI_MIC_GAIN = mVoIPULTotalGain;
+ memcpy(&mSph_Enh_ctrl.enhance_pars, &mVoIPEnhanceParas, EnhanceParasNum * sizeof(uWord32));
+ memcpy(&mSph_Enh_ctrl.DMNR_cal_data, &mVoIPDMNRCalData, DMNRCalDataNum * sizeof(Word16));
+ memcpy(&mSph_Enh_ctrl.Compen_filter, &mVoIPCompenFilter, CompenFilterNum * sizeof(Word16));
+
+ mLatencyTime = mPlatformOffsetTime + GetVoIPLatencyTime();
+ if (mLatencyTime != 0) {
+ mNeedDelayLatency = true;
+ }
+
+ if (mLatencyTime < 0) {
+ mLatencyTime = abs(mLatencyTime);
+ mLatencyDir = false;
+ }
+ ALOGD("mLatencyTime=%d,mLatencyDir=%x", mLatencyTime, mLatencyDir);
+ mLatencySampleCount = mLatencyTime * mVoIPSampleRate / 1000; //Latency sample count
+
+ mJitterSampleCount = mJitterBufferTime * mVoIPSampleRate / 1000; //Jitter buffer sample count, one channel
+ if (mJitterBufferTime != 0) {
+ mNeedJitterBuffer = true;
+ }
+
+ } else {
+ ALOGD("%s, wrong mode", __FUNCTION__);
+ return false;
+ }
+
+ mSph_Enh_ctrl.Device_mode = mRoute;
+
+ if (mSphCtrlBuffer) {
+ ALOGD("%s mSphCtrlBuffer already exist, delete and recreate", __FUNCTION__);
+ mSphEnhOps.ENH_API_Free(&mSph_Enh_ctrl);
+ free(mSphCtrlBuffer);
+ mSphCtrlBuffer = NULL;
+ }
+
+ Word16 ver = mSphEnhOps.ENH_API_Get_Version(&mSph_Enh_ctrl);
+ ALOGD("%s, SWIP ver = %d.%d\n", __FUNCTION__, (ver & 0x1FF8) >> 3, ver & 0x7);
+
+ uint32_t mem_size;
+ mem_size = mSphEnhOps.ENH_API_Get_Memory(&mSph_Enh_ctrl);
+ mSphCtrlBuffer = (int *) malloc(mem_size);
+ if (mSphCtrlBuffer == NULL) {
+ ALOGD("%s, create fail", __FUNCTION__);
+ return false;
+ }
+ ALOGD("%s, going to configure,mSphCtrlBuffer=%p,mem_size=%d", __FUNCTION__, mSphCtrlBuffer, mem_size);
+ memset(mSphCtrlBuffer, 0, mem_size);
+
+ dump();
+ AL_LOCK(mBufMutex);
+ mSphEnhOps.ENH_API_Alloc(&mSph_Enh_ctrl, (Word32 *)mSphCtrlBuffer);
+
+ mSphEnhOps.ENH_API_Rst(&mSph_Enh_ctrl);
+
+
+ mMode = mode;
+ mState = SPE_STATE_START;
+
+ //set the address
+ ALOGD("mSph_Enh_ctrl.frame_rate %d", mSph_Enh_ctrl.frame_rate);
+ if (mMode == SPE_MODE_REC) {
+ if (mSph_Enh_ctrl.frame_rate == 20) { //frame rate = 20ms, buffer size 320*2, input/output use the same address
+ mpSPEBufferUL1 = &mSph_Enh_ctrl.PCM_buffer[0];
+
+ if (mSph_Enh_ctrl.sample_rate == 16000) {
+ ALOGD("Start 16K record!!!");
+ mpSPEBufferUL2 = &mSph_Enh_ctrl.PCM_buffer[Rec16KUL2BufStartAddr];
+ mSPEProcessBufSize = RecBufSize16K20ms * 2 * sizeof(short); //for 16k samplerate with 20ms frame rate (stereo)
+ } else { //48k sample rate
+ mpSPEBufferUL2 = &mSph_Enh_ctrl.PCM_buffer[Rec48KUL2BufStartAddr];
+ mSPEProcessBufSize = RecBufSize48K20ms * 2 * sizeof(short); //for 48k samplerate with 20ms frame rate (stereo)
+ }
+
+ } else if (mSph_Enh_ctrl.frame_rate == 10) { //frame rate = 10ms, buffer size 480*2
+
+ mpSPEBufferUL1 = &mSph_Enh_ctrl.PCM_buffer[0];
+
+
+ if (mSph_Enh_ctrl.sample_rate == 16000) {
+ mpSPEBufferUL2 = &mSph_Enh_ctrl.PCM_buffer[Rec16KUL2BufStartAddr];
+ mSPEProcessBufSize = RecBufSize16K10ms * 2 * sizeof(short); //for 16k samplerate with 10ms frame rate (stereo)
+ } else { //48K samplerate
+ mpSPEBufferUL2 = &mSph_Enh_ctrl.PCM_buffer[Rec48KUL2BufStartAddr];
+ mSPEProcessBufSize = RecBufSize48K10ms * 2 * sizeof(short); //for 48k samplerate with 10ms frame rate (stereo)
+ }
+
+ } else if (mSph_Enh_ctrl.frame_rate == 5) { //frame rate = 5ms
+
+ mpSPEBufferUL1 = &mSph_Enh_ctrl.PCM_buffer[0];
+
+
+ if (mSph_Enh_ctrl.sample_rate == 16000) {
+ mpSPEBufferUL2 = &mSph_Enh_ctrl.PCM_buffer[Rec16KUL2BufStartAddr];
+ mSPEProcessBufSize = RecBufSize16K5ms * 2 * sizeof(short); //for 16k samplerate with 5ms frame rate (stereo)
+ } else { //48K samplerate
+ mpSPEBufferUL2 = &mSph_Enh_ctrl.PCM_buffer[Rec48KUL2BufStartAddr];
+ mSPEProcessBufSize = RecBufSize48K5ms * 2 * sizeof(short); //for 48k samplerate with 5ms frame rate (stereo)
+ }
+
+ } else if (mSph_Enh_ctrl.frame_rate == 3) { //frame rate = 3ms
+
+ mpSPEBufferUL1 = &mSph_Enh_ctrl.PCM_buffer[0];
+
+
+ if (mSph_Enh_ctrl.sample_rate == 16000) {
+ mpSPEBufferUL2 = &mSph_Enh_ctrl.PCM_buffer[Rec16KUL2BufStartAddr];
+ mSPEProcessBufSize = RecBufSize16K3ms * 2 * sizeof(short); //for 16k samplerate with 3ms frame rate (stereo)
+ } else { //48K samplerate
+ mpSPEBufferUL2 = &mSph_Enh_ctrl.PCM_buffer[Rec48KUL2BufStartAddr];
+ mSPEProcessBufSize = RecBufSize48K3ms * 2 * sizeof(short); //for 48k samplerate with 3ms frame rate (stereo)
+ }
+
+ } else if (mSph_Enh_ctrl.frame_rate == 2) { //frame rate = 2ms
+
+ mpSPEBufferUL1 = &mSph_Enh_ctrl.PCM_buffer[0];
+
+
+ if (mSph_Enh_ctrl.sample_rate == 16000) {
+ mpSPEBufferUL2 = &mSph_Enh_ctrl.PCM_buffer[Rec16KUL2BufStartAddr];
+ mSPEProcessBufSize = RecBufSize16K2ms * 2 * sizeof(short); //for 16k samplerate with 3ms frame rate (stereo)
+ } else { //48K samplerate
+ mpSPEBufferUL2 = &mSph_Enh_ctrl.PCM_buffer[Rec48KUL2BufStartAddr];
+ mSPEProcessBufSize = RecBufSize48K2ms * 2 * sizeof(short); //for 48k samplerate with 3ms frame rate (stereo)
+ }
+
+ } else if (mSph_Enh_ctrl.frame_rate == 1) { //frame rate = 1ms
+
+ mpSPEBufferUL1 = &mSph_Enh_ctrl.PCM_buffer[0];
+
+
+ if (mSph_Enh_ctrl.sample_rate == 16000) {
+ mpSPEBufferUL2 = &mSph_Enh_ctrl.PCM_buffer[Rec16KUL2BufStartAddr];
+ mSPEProcessBufSize = RecBufSize16K1ms * 2 * sizeof(short); //for 16k samplerate with 3ms frame rate (stereo)
+ } else { //48K samplerate
+ mpSPEBufferUL2 = &mSph_Enh_ctrl.PCM_buffer[Rec48KUL2BufStartAddr];
+ mSPEProcessBufSize = RecBufSize48K1ms * 2 * sizeof(short); //for 48k samplerate with 3ms frame rate (stereo)
+ }
+
+ } else {
+ ALOGD("wrong mSph_Enh_ctrl.frame_rate setting %d", mSph_Enh_ctrl.frame_rate);
+ }
+ } else { //VoIP mode
+ //only support 16K samplerate
+ if (mSph_Enh_ctrl.frame_rate == 20) { //frame rate = 20ms, buffer size 320*4
+ mpSPEBufferUL1 = &mSph_Enh_ctrl.PCM_buffer[0];
+ mpSPEBufferUL2 = &mSph_Enh_ctrl.PCM_buffer[320];
+ mpSPEBufferDL = &mSph_Enh_ctrl.PCM_buffer[640];
+ mpSPEBufferDLDelay = &mSph_Enh_ctrl.PCM_buffer[960];
+
+ mSPEProcessBufSize = 320 * 2 * sizeof(short); //for 16k samplerate with 20ms frame rate (stereo)
+ } else { //frame rate = 10ms, buffer size 160*4
+ mpSPEBufferUL1 = &mSph_Enh_ctrl.PCM_buffer[0];
+ mpSPEBufferUL2 = &mSph_Enh_ctrl.PCM_buffer[160];
+ mpSPEBufferDL = &mSph_Enh_ctrl.PCM_buffer[320];
+ mpSPEBufferDLDelay = &mSph_Enh_ctrl.PCM_buffer[480];
+
+ mSPEProcessBufSize = 160 * 2 * sizeof(short); //for 16k samplerate with 20ms frame rate (stereo)
+
+ }
+ mpSPEBufferNE = mpSPEBufferUL1;
+ mpSPEBufferFE = mpSPEBufferDL;
+ }
+
+ mNsecPerSample = 1000000000 / mVoIPSampleRate;
+ ALOGD("mNsecPerSample=%lld", mNsecPerSample);
+
+ AL_UNLOCK(mBufMutex);
+ /*
+ mfpInDL = NULL;
+ mfpInUL = NULL;
+ mfpOutDL = NULL;
+ mfpOutUL = NULL;
+ mfpProcessedDL = NULL;
+ mfpProcessedUL = NULL;
+ mfpEPL = NULL;
+ mfpVM = NULL;
+ */
+ ALOGD("mSPEProcessBufSize=%d", mSPEProcessBufSize);
+ return true;
+}
+
+void SPELayer::WriteReferenceBuffer(struct InBufferInfo *Binfo) {
+ struct timespec entertime;
+ struct timespec leavetime;
+ unsigned long long timediff = 0;
+ mBufMutexWantLock.lock();
+ entertime = GetSystemTime();
+ mNewReferenceBufferComes = true;
+ AL_LOCK(mBufMutex);
+ mBufMutexWantLock.unlock();
+
+ //normal VoIP is running case, and path routing case
+ if (((mState == SPE_STATE_RUNNING) && ((mMode == SPE_MODE_VOIP) || (mMode == SPE_MODE_AECREC))) || mVoIPRunningbefore) {
+ if (EPLDebugEnable == true) {
+ ALOGD("WriteReferenceBuffer,inBufLength=%u", Binfo->BufLen);
+ }
+ AddtoInputBuffer(DOWNLINK, Binfo);
+ }//prequeue happens before VoIP is running (mode is VoIP and state is START or mode is None and state is IDLE)
+ else if ((mState != SPE_STATE_CLEANING) && (mMode != SPE_MODE_REC)) {
+ if (EPLDebugEnable == true) {
+ ALOGD("WriteDLQueue,inBufLength=%u", Binfo->BufLen);
+ }
+ AddtoInputBuffer(DOWNLINK, Binfo, true);
+ }
+ AL_UNLOCK(mBufMutex);
+ mNewReferenceBufferComes = false;
+ leavetime = GetSystemTime();
+
+ timediff = TimeDifference(leavetime, entertime);
+ if (timediff > 20000000) {
+ ALOGD("WriteReferenceBuffer, process too long? %lld", timediff);
+ }
+
+}
+
+void SPELayer::SetOutputStreamRunning(bool bRunning, bool bFromOutputStart) {
+ Mutex::Autolock lock(mLock);
+ AL_LOCK(mBufMutex);
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, %d, %d, %d", __FUNCTION__, bRunning, mOutputStreamRunning, bFromOutputStart);
+ }
+ if ((bRunning == true) && (bFromOutputStart == true)) {
+ mDLNewStart = true;
+ mPrepareProcessDataReady = false;
+ }
+
+ if (bRunning == false) {
+ mFirstVoIPDownlink = true;
+ }
+#if 1
+ if ((mOutputStreamRunning == false) && (bRunning == true)) { //need to re-add the delay latency when input informed output restart running
+ if (mLatencyTime != 0) {
+ ALOGD("resync the latency delay time");
+ mNeedDelayLatency = true;
+ }
+
+ if (mJitterBufferTime != 0) {
+ mNeedJitterBuffer = true;
+ }
+ }
+#endif
+ mOutputStreamRunning = bRunning;
+ AL_UNLOCK(mBufMutex);
+}
+
+void SPELayer::EnableNormalModeVoIP(bool bSet) {
+ Mutex::Autolock lock(mLock);
+ AL_LOCK(mBufMutex);
+ ALOGD("%s, %d", __FUNCTION__, bSet);
+ mNormalModeVoIP = bSet;
+ AL_UNLOCK(mBufMutex);
+}
+
+void SPELayer::SetUPLinkDropTime(uint32_t droptime) {
+ Mutex::Autolock lock(mLock);
+ AL_LOCK(mBufMutex);
+ mULDropTime = droptime; //ms
+ ALOGD("%s, %d", __FUNCTION__, mULDropTime);
+ AL_UNLOCK(mBufMutex);
+}
+
+void SPELayer::SetDownLinkLatencyTime(uint32_t latencytime) {
+ Mutex::Autolock lock(mLock);
+ AL_LOCK(mBufMutex);
+ mDLLatencyTime = latencytime; //ms
+ ALOGD("%s, %d", __FUNCTION__, mDLLatencyTime);
+ AL_UNLOCK(mBufMutex);
+}
+
+void SPELayer::DropDownlinkData(uint32_t dropsample) {
+ uint32_t diffBufLength = dropsample * 2;
+ while (diffBufLength > 0) {
+ if (mDLInBufferQ.isEmpty() || mDLDelayBufferQ.isEmpty()) {
+ ALOGW("%s, no mDLInBufferQ data", __FUNCTION__);
+ break;
+ }
+ if ((diffBufLength > (uint32_t)mDLInBufQLenTotal) || (diffBufLength > (uint32_t)mDLDelayBufQLenTotal)) {
+ //time diff more than DL preQ data
+ ALOGW("%s, something wrong happened?", __FUNCTION__);
+ diffBufLength = mDLInBufQLenTotal;
+ //break;
+ }
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, drop DL data diffBufLength=%d, mDLInBufferQ.size()=%zu, mDLInBufferQ[0]->BufLen=%d!!!", __FUNCTION__, diffBufLength, mDLInBufferQ.size(), mDLInBufferQ[0]->BufLen);
+ }
+ if (diffBufLength >= (uint32_t)mDLInBufferQ[0]->BufLen) {
+ //drop DL data
+ uint32_t droplength = mDLInBufferQ[0]->BufLen;
+ diffBufLength -= mDLInBufferQ[0]->BufLen;
+ mDLInBufQLenTotal -= mDLInBufferQ[0]->BufLen;
+ mDLInBufferQ.removeAt(0);
+
+ //drop DL delay data
+ while (droplength > 0) {
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, drop DL Delay data droplength=%d, mDLDelayBufferQ.size()=%zu, mDLDelayBufferQ[0]->BufLen4Delay=%d!!!", __FUNCTION__, droplength, mDLDelayBufferQ.size(), mDLDelayBufferQ[0]->BufLen4Delay);
+ }
+ if (droplength < (uint32_t)mDLDelayBufferQ[0]->BufLen4Delay) {
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, mDLDelayBufferQ[0]->pRead=%p", __FUNCTION__, mDLDelayBufferQ[0]->pRead);
+ }
+ mDLDelayBufferQ[0]->BufLen4Delay -= droplength;
+ mDLDelayBufQLenTotal -= droplength;
+ mDLDelayBufferQ[0]->pRead4Delay = mDLDelayBufferQ[0]->pRead4Delay + droplength / 2;
+ droplength = 0;
+ ALOGD("%s, after mDLDelayBufferQ[0]->pRead=%p, mDLDelayBufferQ[0]->BufLen=%d", __FUNCTION__, mDLDelayBufferQ[0]->pRead4Delay, mDLDelayBufferQ[0]->BufLen4Delay);
+ } else {
+ droplength -= mDLDelayBufferQ[0]->BufLen4Delay;
+ mDLDelayBufQLenTotal -= mDLDelayBufferQ[0]->BufLen4Delay;
+ free(mDLDelayBufferQ[0]->pBufBase);
+ delete mDLDelayBufferQ[0];
+ mDLDelayBufferQ.removeAt(0);
+ }
+ }
+ } else {
+ // ALOGW("PrepareProcessData !!! break for test");
+ // break;
+ //drop DL data
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, mDLInBufferQ[0]->pRead=%p , mDLInBufferQ[0]->BufLen=%d, sec %ld, nsec %ld", __FUNCTION__, mDLInBufferQ[0]->pRead, mDLInBufferQ[0]->BufLen, mDLInBufferQ[0]->time_stamp_estimate.tv_sec,
+ mDLInBufferQ[0]->time_stamp_estimate.tv_nsec);
+ }
+ uint32_t droplength = diffBufLength;
+ mDLInBufferQ[0]->BufLen -= diffBufLength; //record the buffer you consumed
+ mDLInBufQLenTotal -= diffBufLength;
+ mDLInBufferQ[0]->pRead = mDLInBufferQ[0]->pRead + diffBufLength / 2;
+
+ //unsigned long long updateDLnsecdiff = (diffBufLength/2)*1000000000/mVoIPSampleRate;
+
+ uint32_t adjustsample = diffBufLength / 2;
+ unsigned long long updateDLnsecdiff = 0;
+ updateDLnsecdiff = (adjustsample * (unsigned long long)1000000) / 16;
+
+ mDLInBufferQ[0]->time_stamp_estimate.tv_sec = mDLInBufferQ[0]->time_stamp_estimate.tv_sec + (mDLInBufferQ[0]->time_stamp_estimate.tv_nsec + updateDLnsecdiff) / 1000000000;
+ mDLInBufferQ[0]->time_stamp_estimate.tv_nsec = (mDLInBufferQ[0]->time_stamp_estimate.tv_nsec + updateDLnsecdiff) % 1000000000;
+
+ ALOGD("%s, after mDLInBufferQ[0]->pRead=%p, mDLInBufferQ[0]->BufLen=%d, updatensecdiff=%lld, sec=%ld, nsec=%ld", __FUNCTION__, mDLInBufferQ[0]->pRead, mDLInBufferQ[0]->BufLen, updateDLnsecdiff,
+ mDLInBufferQ[0]->time_stamp_estimate.tv_sec, mDLInBufferQ[0]->time_stamp_estimate.tv_nsec);
+ diffBufLength = 0;
+
+ //drop DL delay data
+ while (droplength > 0) {
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, drop DL Delay data droplength=%d, mDLDelayBufferQ.size()=%zu, mDLDelayBufferQ[0]->BufLen4Delay=%d!!!", __FUNCTION__, droplength, mDLDelayBufferQ.size(), mDLDelayBufferQ[0]->BufLen4Delay);
+ }
+ if (droplength < (uint32_t)mDLDelayBufferQ[0]->BufLen4Delay) {
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, mDLDelayBufferQ[0]->pRead=%p", __FUNCTION__, mDLDelayBufferQ[0]->pRead4Delay);
+ }
+ mDLDelayBufferQ[0]->BufLen4Delay -= droplength;
+ mDLDelayBufQLenTotal -= droplength;
+ mDLDelayBufferQ[0]->pRead4Delay = mDLDelayBufferQ[0]->pRead4Delay + droplength / 2;
+ droplength = 0;
+ ALOGD("%s, after mDLDelayBufferQ[0]->pRead=%p, mDLDelayBufferQ[0]->BufLen=%d", __FUNCTION__, mDLDelayBufferQ[0]->pRead4Delay, mDLDelayBufferQ[0]->BufLen4Delay);
+ } else {
+ droplength -= mDLDelayBufferQ[0]->BufLen4Delay;
+ mDLDelayBufQLenTotal -= mDLDelayBufferQ[0]->BufLen4Delay;
+ free(mDLDelayBufferQ[0]->pBufBase);
+ delete mDLDelayBufferQ[0];
+ mDLDelayBufferQ.removeAt(0);
+ }
+ }
+
+ }
+ }
+
+}
+
+void SPELayer::AddtoInputBuffer(SPE_DATA_DIRECTION dir, struct InBufferInfo *BInputInfo, bool prequeue) {
+
+ //pthread_mutex_lock(&mBufMutex );
+ int inBufLen = BInputInfo->BufLen;
+ short *inBufAddr = BInputInfo->pBufBase;
+ bool bRemainInfo = BInputInfo->bHasRemainInfo;
+ bool bPreQueue = prequeue;
+
+ Dump_PCM_In(dir, inBufAddr, inBufLen);
+
+ // ALOGD("SPELayer::Process, dir=%x, inBuf=%p,inBufLength=%d,mMode=%x,copysize=%d",dir,inBuf,inBufLength,mMode,copysize);
+
+ BufferInfo *newInBuffer = new BufferInfo;
+ memset(newInBuffer, 0, sizeof(BufferInfo));
+ struct timespec tstamp_queue;
+ newInBuffer->pBufBase = (short *) malloc(inBufLen);
+ ASSERT(newInBuffer->pBufBase != NULL);
+
+ memcpy(newInBuffer->pBufBase, inBufAddr, inBufLen);
+
+ //tstamp_queue = GetSystemTime(true, dir); //modify to use read time
+ tstamp_queue = BInputInfo->time_stamp_queued;
+
+ newInBuffer->BufLen = inBufLen;
+ newInBuffer->pRead = newInBuffer->pBufBase;
+ newInBuffer->pWrite = newInBuffer->pBufBase;
+ newInBuffer->time_stamp_queued = tstamp_queue;
+ memset((void *) & (newInBuffer->time_stamp_process), 0, sizeof(newInBuffer->time_stamp_process));
+ //newInBuffer->time_stamp_process = {0};
+ newInBuffer->DLfirstBuf = false;
+ /*
+ if (prequeue)
+ {
+ ALOGD("AddtoInputBuffer, newInBuffer=%p, pBufBase=%p", newInBuffer, newInBuffer->pBufBase);
+ }
+ */
+ if ((dir == UPLINK) && ((mMode == SPE_MODE_VOIP) || (mMode == SPE_MODE_AECREC))) {
+ if (EPLDebugEnable == true) {
+ ALOGD("uplink estimate time bRemainInfo=%d, pre tv_sec=%ld, pre nsec=%ld, mPreDLBufLen=%d, tv_sec=%ld, nsec=%ld",
+ bRemainInfo, mPreUplinkEstTime.tv_sec, mPreUplinkEstTime.tv_nsec, mPreDLBufLen, BInputInfo->time_stamp_predict.tv_sec, BInputInfo->time_stamp_predict.tv_nsec);
+ }
+ if (mFirstVoIPUplink) {
+ mFirstVoIPUplink = false;
+#if 1 //the first estimation time use the UL intr time, it is absolute time
+ if (bRemainInfo) {
+ mPreUplinkEstTime.tv_sec = BInputInfo->time_stamp_predict.tv_sec;
+ mPreUplinkEstTime.tv_nsec = BInputInfo->time_stamp_predict.tv_nsec;
+ } else {
+ mPreUplinkEstTime.tv_sec = mUplinkIntrStartTime.tv_sec;
+ if (mUplinkIntrStartTime.tv_nsec + mULDropTime * 1000000 >= 1000000000) {
+ mPreUplinkEstTime.tv_sec++;
+ mPreUplinkEstTime.tv_nsec = mUplinkIntrStartTime.tv_nsec + mULDropTime * 1000000 - 1000000000;
+ } else {
+ mPreUplinkEstTime.tv_nsec = mUplinkIntrStartTime.tv_nsec + mULDropTime * 1000000;
+ }
+
+ }
+#else //ULTR
+ //the first estimation time use the first UL buffer queue time, it is corresponding time
+ mPreUplinkEstTime.tv_sec = tstamp_queue.tv_sec;
+ mPreUplinkEstTime.tv_nsec = tstamp_queue.tv_nsec;
+
+ if (tstamp_queue.tv_sec >= mUplinkIntrStartTime.tv_sec) {
+ if (tstamp_queue.tv_nsec >= mUplinkIntrStartTime.tv_nsec) {
+ mULIntrDeltaTime.tv_sec = tstamp_queue.tv_sec - mUplinkIntrStartTime.tv_sec;
+ mULIntrDeltaTime.tv_nsec = tstamp_queue.tv_nsec - mUplinkIntrStartTime.tv_nsec;
+ } else {
+ if (tstamp_queue.tv_sec >= mUplinkIntrStartTime.tv_sec) {
+ ALOGW("first uplink estimate time error");
+ } else {
+ mULIntrDeltaTime.tv_sec = tstamp_queue.tv_sec - mUplinkIntrStartTime.tv_sec - 1;
+ mULIntrDeltaTime.tv_nsec = 1000000000 + tstamp_queue.tv_nsec - mUplinkIntrStartTime.tv_nsec;
+ }
+ }
+ }
+#endif
+ newInBuffer->time_stamp_estimate.tv_sec = mPreUplinkEstTime.tv_sec;
+ newInBuffer->time_stamp_estimate.tv_nsec = mPreUplinkEstTime.tv_nsec;
+ if (EPLDebugEnable == true) {
+ ALOGD("first uplink estimate time bRemainInfo=%d, sec %ld nsec %ld, inBufLength=%d, mULIntrDeltaTime sec %ld nsec %ld",
+ bRemainInfo, mPreUplinkEstTime.tv_sec, mPreUplinkEstTime.tv_nsec, inBufLen, mULIntrDeltaTime.tv_sec, mULIntrDeltaTime.tv_nsec);
+ }
+ mPreULBufLen = inBufLen;
+ } else {
+ if (bRemainInfo) {
+ struct timespec tempTime;
+ tempTime.tv_sec = BInputInfo->time_stamp_predict.tv_sec;
+ tempTime.tv_nsec = BInputInfo->time_stamp_predict.tv_nsec;
+ if (TimeDifference(tempTime, mPreUplinkEstTime) > 40000000) {
+ ALOGD("AddtoInputBuffer uplink interval too long, need to do resync?");
+ }
+
+ mPreUplinkEstTime.tv_sec = BInputInfo->time_stamp_predict.tv_sec;
+ mPreUplinkEstTime.tv_nsec = BInputInfo->time_stamp_predict.tv_nsec;
+
+ newInBuffer->time_stamp_estimate.tv_sec = BInputInfo->time_stamp_predict.tv_sec;
+ newInBuffer->time_stamp_estimate.tv_nsec = BInputInfo->time_stamp_predict.tv_nsec;
+ } else {
+ struct timespec Esttstamp;
+ //unsigned long long ns = (((mPreULBufLen*1000000000)/2)/2)/mVoIPSampleRate;
+ unsigned long long ns = ((mPreULBufLen * (unsigned long long)1000000) / 64);
+ Esttstamp.tv_sec = mPreUplinkEstTime.tv_sec;
+ //ALOGD("uplink estimate mPreUplinkEstTime, ns=%lld, tv_sec=%ld, nsec=%ld, mPreDLBufLen=%d", ns, mPreUplinkEstTime.tv_sec, mPreUplinkEstTime.tv_nsec, mPreULBufLen);
+ if (mPreUplinkEstTime.tv_nsec + ns >= 1000000000) {
+ Esttstamp.tv_sec++;
+ Esttstamp.tv_nsec = mPreUplinkEstTime.tv_nsec + ns - 1000000000;
+ } else {
+ Esttstamp.tv_nsec = mPreUplinkEstTime.tv_nsec + ns;
+ }
+
+ newInBuffer->time_stamp_estimate.tv_sec = Esttstamp.tv_sec;
+ newInBuffer->time_stamp_estimate.tv_nsec = Esttstamp.tv_nsec;
+ if (EPLDebugEnable == true) {
+ ALOGD("uplink estimate time, sec %ld nsec %ld, inBufLength=%d", Esttstamp.tv_sec, Esttstamp.tv_nsec, inBufLen);
+ }
+ mPreUplinkEstTime.tv_sec = Esttstamp.tv_sec;
+ mPreUplinkEstTime.tv_nsec = Esttstamp.tv_nsec;
+ }
+ mPreULBufLen = inBufLen;
+ }
+ }
+
+ if (dir == DOWNLINK) {
+ if (EPLDebugEnable == true) {
+ ALOGD("AddtoInputBuffer queue downlink sec %ld nsec %ld, downlink sec %ld nsec %ld",
+ BInputInfo->time_stamp_queued.tv_sec, BInputInfo->time_stamp_queued.tv_nsec, BInputInfo->time_stamp_predict.tv_sec, BInputInfo->time_stamp_predict.tv_nsec);
+ }
+ if (mFirstVoIPDownlink) {
+ mFirstVoIPDownlink = false;
+ if (mDLNewStart) { //downlink starts first time, the first DL buffer queue will earlier than interrupt enable, it happens when output starts after input stream create
+ //mDLNewStart = false;
+ newInBuffer->DLfirstBuf = true;
+
+ //need to modify the estimate start time again when downlink Interrupt set.
+ newInBuffer->time_stamp_estimate.tv_sec = BInputInfo->time_stamp_queued.tv_sec;
+ newInBuffer->time_stamp_estimate.tv_nsec = BInputInfo->time_stamp_queued.tv_nsec;
+ if (mDLLatencyTime * 1000000 + newInBuffer->time_stamp_estimate.tv_nsec >= 1000000000) {
+ newInBuffer->time_stamp_estimate.tv_sec++;
+ newInBuffer->time_stamp_estimate.tv_nsec = mDLLatencyTime * 1000000 + newInBuffer->time_stamp_estimate.tv_nsec - 1000000000;
+ }
+ mPreDownlinkEstTime.tv_sec = newInBuffer->time_stamp_estimate.tv_sec;
+ mPreDownlinkEstTime.tv_nsec = newInBuffer->time_stamp_estimate.tv_nsec;
+ if (EPLDebugEnable == true) {
+ ALOGD("downlink first time mDLNewStart queue estimate time, sec %ld nsec %ld, inBufLength=%d", mPreDownlinkEstTime.tv_sec, mPreDownlinkEstTime.tv_nsec, inBufLen);
+ }
+ } else { //the first DL buffer queue after downlink already start, it happens when input stream create after output is running
+ if (bRemainInfo) {
+ newInBuffer->time_stamp_estimate.tv_sec = BInputInfo->time_stamp_predict.tv_sec;
+ newInBuffer->time_stamp_estimate.tv_nsec = BInputInfo->time_stamp_predict.tv_nsec;
+ } else {
+ //use DL hardware buffer latency for estimate? or buffer length?
+ newInBuffer->time_stamp_estimate.tv_sec = BInputInfo->time_stamp_queued.tv_sec;
+ newInBuffer->time_stamp_estimate.tv_nsec = BInputInfo->time_stamp_queued.tv_nsec;
+ ALOGD("mDLLatencyTime=%d", mDLLatencyTime);
+ if ((mDLLatencyTime / 2) * 1000000 + newInBuffer->time_stamp_estimate.tv_nsec >= 1000000000) {
+ newInBuffer->time_stamp_estimate.tv_sec++;
+ newInBuffer->time_stamp_estimate.tv_nsec = (mDLLatencyTime / 2) * 1000000 + newInBuffer->time_stamp_estimate.tv_nsec - 1000000000;
+ } else {
+ newInBuffer->time_stamp_estimate.tv_nsec = (mDLLatencyTime / 2) * 1000000 + newInBuffer->time_stamp_estimate.tv_nsec;
+ }
+ }
+
+ mPreDownlinkEstTime.tv_sec = newInBuffer->time_stamp_estimate.tv_sec;
+ mPreDownlinkEstTime.tv_nsec = newInBuffer->time_stamp_estimate.tv_nsec;
+
+ mPreDownlinkQueueTime.tv_sec = BInputInfo->time_stamp_queued.tv_sec;
+ mPreDownlinkQueueTime.tv_nsec = BInputInfo->time_stamp_queued.tv_nsec;
+ if (EPLDebugEnable == true) {
+ ALOGD("downlink first time queue estimate time, sec %ld nsec %ld, inBufLength=%d,bRemainInfo=%d", mPreDownlinkEstTime.tv_sec, mPreDownlinkEstTime.tv_nsec, inBufLen, bRemainInfo);
+ }
+ }
+ mPreDLBufLen = inBufLen;
+ } else { //not the first DL buffer queue, continuos queue
+ if (EPLDebugEnable == true) {
+ ALOGD("downlink estimate time bRemainInfo=%d, pre tv_sec=%ld, pre nsec=%ld, mPreDLBufLen=%d", bRemainInfo, mPreDownlinkEstTime.tv_sec, mPreDownlinkEstTime.tv_nsec, mPreDLBufLen);
+ }
+ if (bRemainInfo) {
+ newInBuffer->time_stamp_estimate.tv_sec = BInputInfo->time_stamp_predict.tv_sec;
+ newInBuffer->time_stamp_estimate.tv_nsec = BInputInfo->time_stamp_predict.tv_nsec;
+
+ //ALOGD("mDLLatencyTime=%d, predict sec= %ld, nsec=%ld, mPreDownlinkEstTime sec=%ld, nsec=%ld" , mDLLatencyTime,BInputInfo->time_stamp_predict.tv_sec, BInputInfo->time_stamp_predict.tv_nsec, mPreDownlinkEstTime.tv_sec, mPreDownlinkEstTime.tv_nsec);
+
+ if ((TimeDifference(BInputInfo->time_stamp_predict, mPreDownlinkEstTime) > (mDLLatencyTime * (unsigned long long)1000000))) {
+ //two downlink queue interval is larger than hardware buffer latency time, this buffer is playing directly since no previous data in the hardware buffer
+ if (EPLDebugEnable == true) {
+ ALOGD("downlink late time predict sec= %ld, nsec=%ld, mPreDownlinkQueueTime sec=%ld, nsec=%ld", BInputInfo->time_stamp_predict.tv_sec, BInputInfo->time_stamp_predict.tv_nsec,
+ mPreDownlinkQueueTime.tv_sec, mPreDownlinkQueueTime.tv_nsec);
+ }
+ }
+
+ } else {
+ struct timespec Esttstamp;
+ //uint32_t ns = mPreDLBufLen*1000000000/sizeof(short)/1/mVoIPSampleRate; //downlink is mono data
+ //unsigned long long ns = ((mPreDLBufLen*1000000000)/2)/mVoIPSampleRate; //downlink is mono data
+ unsigned long long diffns = 0;
+ unsigned long long ns = ((mPreDLBufLen * (unsigned long long)1000000) / 32); //downlink is mono data
+ //ALOGD("downlink estimate time ns=%lld, pre tv_sec=%ld, pre nsec=%ld, mPreDLBufLen=%d", ns, mPreDownlinkEstTime.tv_sec, mPreDownlinkEstTime.tv_nsec, mPreDLBufLen);
+
+ newInBuffer->time_stamp_estimate.tv_sec = BInputInfo->time_stamp_queued.tv_sec;
+ newInBuffer->time_stamp_estimate.tv_nsec = BInputInfo->time_stamp_queued.tv_nsec;
+
+ //when the latest DL buffer queue and this DL buffer queue interval longer than hardware buffer latency, the new buffer will play directly
+ //and if the next buffer queue longer than half hardware buffer latency, it will also play directly
+ //if((TimeDifference(BInputInfo->time_stamp_queued,mPreDownlinkQueueTime)>(mDLLatencyTime*1000000))||
+ //( (TimeDifference(BInputInfo->time_stamp_queued,mPreDownlinkQueueTime)>((mDLLatencyTime/2)*1000000))))
+ if (TimeDifference(BInputInfo->time_stamp_queued, mPreDownlinkQueueTime) > (mDLLatencyTime * (unsigned long long)1000000)) {
+
+ //two downlink queue interval is larger than hardware buffer latency time, this buffer is playing directly since no previous data in the hardware buffer
+ if (EPLDebugEnable == true) {
+ ALOGD("downlink late time queue sec= %ld, nsec=%ld, mPreDownlinkQueueTime sec=%ld, nsec=%ld", BInputInfo->time_stamp_queued.tv_sec, BInputInfo->time_stamp_queued.tv_nsec,
+ mPreDownlinkQueueTime.tv_sec, mPreDownlinkQueueTime.tv_nsec);
+ }
+
+ } else {
+ if ((mDLLatencyTime / 2) * 1000000 + newInBuffer->time_stamp_estimate.tv_nsec >= 1000000000) {
+ newInBuffer->time_stamp_estimate.tv_sec++;
+ newInBuffer->time_stamp_estimate.tv_nsec = (mDLLatencyTime / 2) * 1000000 + newInBuffer->time_stamp_estimate.tv_nsec - 1000000000;
+ } else {
+ newInBuffer->time_stamp_estimate.tv_nsec = (mDLLatencyTime / 2) * 1000000 + newInBuffer->time_stamp_estimate.tv_nsec;
+ }
+ }
+ }
+
+ mPreDownlinkQueueTime.tv_sec = BInputInfo->time_stamp_queued.tv_sec;
+ mPreDownlinkQueueTime.tv_nsec = BInputInfo->time_stamp_queued.tv_nsec;
+#if 1 //use queue time + HW buffer latency time
+ mPreDownlinkEstTime.tv_sec = newInBuffer->time_stamp_estimate.tv_sec;
+ mPreDownlinkEstTime.tv_nsec = newInBuffer->time_stamp_estimate.tv_nsec;
+ if (EPLDebugEnable == true) {
+ ALOGD("downlink queue estimate time, sec %ld nsec %ld, inBufLength=%d", mPreDownlinkEstTime.tv_sec, mPreDownlinkEstTime.tv_nsec, inBufLen);
+ }
+#else
+ //predict by previos time
+ Esttstamp.tv_sec = mPreDownlinkEstTime.tv_sec;
+ if (mPreDownlinkEstTime.tv_nsec + ns >= 1000000000) {
+ Esttstamp.tv_sec++;
+ Esttstamp.tv_nsec = mPreDownlinkEstTime.tv_nsec + ns - 1000000000;
+ } else {
+ Esttstamp.tv_nsec = mPreDownlinkEstTime.tv_nsec + ns;
+ }
+ newInBuffer->time_stamp_estimate.tv_sec = Esttstamp.tv_sec;
+ newInBuffer->time_stamp_estimate.tv_nsec = Esttstamp.tv_nsec;
+ ALOGD("downlink estimate time, sec %ld nsec %ld, inBufLength=%d", Esttstamp.tv_sec, Esttstamp.tv_nsec, inBufLen);
+
+ mPreDownlinkEstTime.tv_sec = Esttstamp.tv_sec;
+ mPreDownlinkEstTime.tv_nsec = Esttstamp.tv_nsec;
+#endif
+
+ mPreDLBufLen = inBufLen;
+ }
+ }
+
+
+ // ALOGD("inBufLength=%d,mULInBufQLenTotal=%d, Qsize=%d",newInBuffer->BufLen,mULInBufQLenTotal,mULInBufferQ.size());
+ if (dir == UPLINK) {
+ mULInBufferQ.add(newInBuffer);
+ mULInBufQLenTotal += inBufLen;
+ // ALOGD("SPELayer::Process, mULInBufQLenTotal=%d, size=%d",mULInBufQLenTotal,mULInBufferQ.size());
+ } else {
+ //queue to the downlink input buffer queue, downlink data channel is mono
+
+ mDLInBufferQ.add(newInBuffer);
+ mDLInBufQLenTotal += inBufLen;
+ if (EPLDebugEnable == true) {
+ ALOGD("AddtoInputBuffer, mDLInBufferQ.size()=%zu, mDLPreQnum=%d,mDLPreQLimit=%d,mFirstVoIPUplink=%d,mDLInBufQLenTotal=%d", mDLInBufferQ.size(), mDLPreQnum, mDLPreQLimit, mFirstVoIPUplink,
+ mDLInBufQLenTotal);
+ }
+ //also add to delay buffer queue
+
+ newInBuffer->BufLen4Delay = inBufLen;
+ newInBuffer->pRead4Delay = newInBuffer->pBufBase;
+ newInBuffer->pWrite4Delay = newInBuffer->pBufBase;
+ mDLDelayBufferQ.add(newInBuffer);
+ mDLDelayBufQLenTotal += inBufLen;
+ // ALOGD("SPELayer::Process, mDLDelayBufQLenTotal=%d, size=%d",mDLDelayBufQLenTotal, mDLDelayBufferQ.size());
+
+ if (bPreQueue) {
+
+ //ALOGD("AddtoInputBuffer, mDLInBufferQ.size()=%d, mDLPreQnum=%d,mDLPreQLimit=%d,mFirstVoIPUplink=%d",mDLInBufferQ.size(),mDLPreQnum,mDLPreQLimit,mFirstVoIPUplink);
+#if 0
+ for (int i; i < mDLInBufferQ.size(); i++) {
+ ALOGD("mDLInBufferQ i=%d, length=%d, %p, Sec=%d, NSec=%ld", i, mDLInBufferQ[i]->BufLen, mDLInBufferQ[i]->pBufBase,
+ mDLInBufferQ[i]->time_stamp_estimate.tv_sec, mDLInBufferQ[i]->time_stamp_estimate.tv_nsec);
+ }
+#endif
+
+ if ((mDLPreQLimit) || (!mDLPreQLimit && mFirstVoIPUplink)) { //wait for uplink comes, only queue five buffer for reference
+ while (mDLInBufferQ.size() > (size_t)mDLPreQnum) {
+ //ALOGD("free over queue, mDLInBufferQ size=%d,mDLInBufQLenTotal=%d, BufLen=%d, %p, %p",mDLInBufferQ.size(),mDLInBufQLenTotal,mDLInBufferQ[0]->BufLen,mDLInBufferQ[0]->pBufBase,mDLInBufferQ[0]);
+ mDLInBufQLenTotal -= mDLInBufferQ[0]->BufLen;
+ mDLInBufferQ.removeAt(0);
+ }
+ } else { //uplink interrupt starts, remove previous queue
+ //for(int i; i<mDLInBufferQ.size(); i++)
+ while (!mDLInBufferQ.isEmpty()) {
+ uint32_t tempSec = mDLInBufferQ[0]->time_stamp_estimate.tv_sec;
+ unsigned long long tempNSec = mDLInBufferQ[0]->time_stamp_estimate.tv_nsec;
+ uint32_t tempsample = mDLInBufferQ[0]->BufLen / 2;
+ unsigned long long tempdeltaNSec = tempsample * (unsigned long long)1000000 / 16;
+ unsigned long long tempEndNSec = tempNSec + tempdeltaNSec;
+ unsigned long long tempFinalNSec = 0;
+ uint32_t tempFinalSec = tempSec;
+ if (EPLDebugEnable == true) {
+ ALOGD("check to move? %p, tempSec=%d, tempNSec=%lld, tempsample=%d", mDLInBufferQ[0]->pBufBase, tempSec, tempNSec, tempsample);
+ }
+ if (tempEndNSec > 1000000000) {
+ tempFinalNSec = tempEndNSec - 1000000000;
+ tempFinalSec = tempFinalSec + 1;
+ } else {
+ tempFinalNSec = tempEndNSec;
+ }
+ if (EPLDebugEnable == true) {
+ ALOGD("tempFinalSec=%d, tempFinalNSec=%llu, tempdeltaNSec=%llu", tempFinalSec, tempFinalNSec, tempdeltaNSec);
+ }
+ if (mUplinkIntrStartTime.tv_sec > (long)tempFinalSec) {
+ mDLInBufQLenTotal -= mDLInBufferQ[0]->BufLen;
+ mDLInBufferQ.removeAt(0);
+ } else if (mUplinkIntrStartTime.tv_sec == (long)tempFinalSec) {
+ if ((unsigned long long)mUplinkIntrStartTime.tv_nsec >= tempFinalNSec) {
+ mDLInBufQLenTotal -= mDLInBufferQ[0]->BufLen;
+ mDLInBufferQ.removeAt(0);
+ } else {
+ //remove previous data in this buffer queue, will do it in the prepare data?
+ if (EPLDebugEnable == true) {
+ ALOGD("remove DL pre queue finish 1");
+ }
+ break;
+ }
+ } else {
+ if (EPLDebugEnable == true) {
+ ALOGD("remove DL pre queue finish 2");
+ }
+ break;
+ }
+
+ }
+ }
+#if 0
+ for (int i; i < mDLDelayBufferQ.size(); i++) {
+ ALOGD("mDLDelayBufferQ i=%d, length=%d, %p", i, mDLDelayBufferQ[i]->BufLen, mDLDelayBufferQ[i]->pBufBase);
+ }
+#endif
+ if (mDLPreQLimit || (!mDLPreQLimit && mFirstVoIPUplink)) { //wait for uplink comes, only queue five buffer for
+ while (mDLDelayBufferQ.size() > (uint32_t)mDLPreQnum) {
+ //ALOGD("free over queue, mDLDelayBufferQ size=%d,mDLDelayBufQLenTotal=%d, BufLen=%d, %p, %p",mDLDelayBufferQ.size(),mDLDelayBufQLenTotal,mDLDelayBufferQ[0]->BufLen4Delay,mDLDelayBufferQ[0]->pBufBase,mDLDelayBufferQ[0]);
+ mDLDelayBufQLenTotal -= mDLDelayBufferQ[0]->BufLen4Delay;
+ free(mDLDelayBufferQ[0]->pBufBase);
+ delete mDLDelayBufferQ[0];
+ mDLDelayBufferQ.removeAt(0);
+ //ALOGD("free mDLDelayBufferQ over queue done");
+ }
+ } else { //uplink interrupt starts, remove previous queue
+ while (!mDLDelayBufferQ.isEmpty()) {
+ uint32_t tempSec = mDLDelayBufferQ[0]->time_stamp_estimate.tv_sec;
+ unsigned long long tempNSec = mDLDelayBufferQ[0]->time_stamp_estimate.tv_nsec;
+ uint32_t tempsample = mDLDelayBufferQ[0]->BufLen / 2;
+ unsigned long long tempdeltaNSec = tempsample * (unsigned long long)1000000 / 16;
+ unsigned long long tempEndNSec = tempNSec + tempdeltaNSec;
+ unsigned long long tempFinalNSec = 0;
+ uint32_t tempFinalSec = tempSec;
+ if (EPLDebugEnable == true) {
+ ALOGD("mDLDelayBufferQ check to move? %p, tempSec=%d, tempNSec=%lld, tempsample=%d", mDLDelayBufferQ[0]->pBufBase, tempSec, tempNSec, tempsample);
+ }
+ if (tempEndNSec > 1000000000) {
+ tempFinalNSec = tempEndNSec - 1000000000;
+ tempFinalSec = tempFinalSec + 1;
+ } else {
+ tempFinalNSec = tempEndNSec;
+ }
+ if (EPLDebugEnable == true) {
+ ALOGD("tempFinalSec=%d, tempFinalNSec=%llu, tempdeltaNSec=%llu", tempFinalSec, tempFinalNSec, tempdeltaNSec);
+ }
+ if (mUplinkIntrStartTime.tv_sec > (long)tempFinalSec) {
+ mDLDelayBufQLenTotal -= mDLDelayBufferQ[0]->BufLen;
+ free(mDLDelayBufferQ[0]->pBufBase);
+ delete mDLDelayBufferQ[0];
+ mDLDelayBufferQ.removeAt(0);
+ } else if (mUplinkIntrStartTime.tv_sec == (long)tempFinalSec) {
+ if ((unsigned long long)mUplinkIntrStartTime.tv_nsec >= tempFinalNSec) {
+ mDLDelayBufQLenTotal -= mDLDelayBufferQ[0]->BufLen;
+ free(mDLDelayBufferQ[0]->pBufBase);
+ delete mDLDelayBufferQ[0];
+ mDLDelayBufferQ.removeAt(0);
+ } else {
+ //remove previous data in this buffer queue, will do it in the prepare data?
+ if (EPLDebugEnable == true) {
+ ALOGD("remove DL delay pre queue finish 1");
+ }
+ break;
+ }
+ } else {
+ if (EPLDebugEnable == true) {
+ ALOGD("remove DL delay pre queue finish 2");
+ }
+ break;
+ }
+
+ }
+ }
+
+ }
+ AL_SIGNAL(mBufMutex);
+ }
+
+ //AL_SIGNAL(mBufMutex);
+ //AL_UNLOCK(mBufMutex);
+}
+
+void SPELayer::CompensateBuffer(size_t BufLength, struct timespec CompenStartTime) {
+ // ALOGD("SPELayer::Process, dir=%x, inBuf=%p,inBufLength=%d,mMode=%x,copysize=%d",dir,inBuf,inBufLength,mMode,copysize);
+
+ ALOGD("CompensateBuffer, BufLength=%zu, sec=%lu, nsec=%lu", BufLength, CompenStartTime.tv_sec, CompenStartTime.tv_nsec);
+ BufferInfo *newInBuffer = new BufferInfo;
+ struct timespec tstamp;
+ newInBuffer->pBufBase = (short *) malloc(BufLength);
+ ASSERT(newInBuffer->pBufBase != NULL);
+
+ //memset(newInBuffer->pBufBase, 0, BufLength);
+ memset(newInBuffer->pBufBase, COMPENSATE_PCM_DATA, BufLength);
+
+ tstamp = GetSystemTime();
+
+ newInBuffer->BufLen = BufLength;
+ newInBuffer->pRead = newInBuffer->pBufBase;
+ newInBuffer->pWrite = newInBuffer->pBufBase;
+ newInBuffer->time_stamp_queued = tstamp;
+ newInBuffer->time_stamp_estimate = CompenStartTime; //need to check the previous eatimate time
+ //newInBuffer->time_stamp_process = {0};
+ memset((void *) & (newInBuffer->time_stamp_process), 0, sizeof(newInBuffer->time_stamp_process));
+ //queue to the downlink input buffer queue, downlink data channel is mono
+ mDLInBufferQ.add(newInBuffer);
+ mDLInBufQLenTotal += BufLength;
+ // ALOGD("CompensateBuffer, mDLInBufQLenTotal=%d, size=%d",mDLInBufQLenTotal,mDLInBufferQ.size());
+
+
+ newInBuffer->BufLen4Delay = BufLength;
+ newInBuffer->pRead4Delay = newInBuffer->pBufBase;
+ newInBuffer->pWrite4Delay = newInBuffer->pBufBase;
+ mDLDelayBufferQ.add(newInBuffer);
+ mDLDelayBufQLenTotal += BufLength;
+ // ALOGD("CompensateBuffer, mDLDelayBufQLenTotal=%d, size=%d",mDLDelayBufQLenTotal, mDLDelayBufferQ.size());
+ //if(!mNeedDelayLatency && mOutputStreamRunning) //compensate happen after DL first time queue, and only count when downlink is playback
+ if (!mFirstVoIPDownlink && mOutputStreamRunning) { //compensate happen after DL first time queue, and only count when downlink is playback
+ mCompensatedBufferSize += BufLength;
+ ALOGD("%s, mCompensatedBufferSize=%zu", __FUNCTION__, mCompensatedBufferSize);
+ if ((mCompensatedBufferSize >= (size_t)160) && mPrepareProcessDataReady) { //5ms data
+ ReSync();
+ }
+ }
+
+}
+
+bool SPELayer::WaitforDownlinkData(void) {
+ bool bRet = true;
+ uint32_t timeoutMs = 40; //timeout time 20ms
+
+ if (mNormalModeVoIP) { //normal mode VoIP
+ if (!mOutputStreamRunning) { //no output running, might be normal record
+ timeoutMs = 0;
+ } else { //output is running
+ if (!mPrepareProcessDataReady) {
+ timeoutMs = 0;
+ } else
+ //if(mNeedDelayLatency) //first time output queue
+ if (mFirstVoIPDownlink) {
+ timeoutMs = 10;
+ }
+ }
+ } else { //In-communication mode VoIP
+ if (mRoute == ROUTE_BT || mRoute == ROUTE_BT_NSEC_OFF_PATH) {
+ timeoutMs = 30; // BTCVSD DL interrupt rate is 20ms
+ } else if (!mOutputStreamRunning) { //no output running, process uplink data directly
+ timeoutMs = 0;
+ } else { //output is running
+ if (!mPrepareProcessDataReady) {
+ timeoutMs = 0;
+ } else {
+ //if(mNeedDelayLatency) //if no DL played before, it is the first time UL earlier case, wait DL for a short time
+ if (mFirstVoIPDownlink) {
+ timeoutMs = 60;
+ }
+ }
+ }
+ }
+ if (EPLDebugEnable == true) {
+ ALOGD("WaitforDownlinkData pthread_cond_timedwait_relative_np start %d,mOutputStreamRunning=%d,mFirstVoIPDownlink=%d,mNormalModeVoIP=%d,mPrepareProcessDataReady=%d", timeoutMs, mOutputStreamRunning,
+ mFirstVoIPDownlink,
+ mNormalModeVoIP, mPrepareProcessDataReady);
+ }
+ if (timeoutMs != 0) {
+ if (AL_WAIT_MS(mBufMutex, timeoutMs) != NO_ERROR) {
+ ALOGD("WaitforDownlinkData pthread_cond_timedwait_relative_np timeout");
+ bRet = false;
+ }
+ } else {
+ bRet = false;
+ }
+
+ return bRet;
+}
+
+bool SPELayer::InsertDownlinkData(void) {
+ bool bRet = true;
+ uint32_t timeoutMs = 3; //timeout time 1ms
+
+ if (EPLDebugEnable == true) {
+ ALOGD("InsertDownlinkData pthread_cond_timedwait_relative_np start %d,mOutputStreamRunning=%d,mFirstVoIPDownlink=%d,mNormalModeVoIP=%d,mPrepareProcessDataReady=%d", timeoutMs, mOutputStreamRunning,
+ mFirstVoIPDownlink, mNormalModeVoIP, mPrepareProcessDataReady);
+ }
+ if (timeoutMs != 0) {
+ if (AL_WAIT_MS(mBufMutex, timeoutMs) != NO_ERROR) {
+ ALOGD("InsertDownlinkData pthread_cond_timedwait_relative_np timeout");
+ bRet = false;
+ }
+ }
+
+ return bRet;
+
+}
+
+//return NS
+unsigned long long SPELayer::TimeStampDiff(BufferInfo *BufInfo1, BufferInfo *BufInfo2) {
+ unsigned long long diffns = 0;
+ struct timespec tstemp1 = BufInfo1->time_stamp_estimate;
+ struct timespec tstemp2 = BufInfo2->time_stamp_estimate;
+
+ // ALOGD("TimeStampDiff time1 sec= %ld, nsec=%ld, time2 sec=%ld, nsec=%ld" ,tstemp1.tv_sec, tstemp1.tv_nsec, tstemp2.tv_sec, tstemp2.tv_nsec);
+
+ if (tstemp1.tv_sec > tstemp2.tv_sec) {
+ if (tstemp1.tv_nsec >= tstemp2.tv_nsec) {
+ diffns = ((tstemp1.tv_sec - tstemp2.tv_sec) * (unsigned long long)1000000000) + tstemp1.tv_nsec - tstemp2.tv_nsec;
+ } else {
+ diffns = ((tstemp1.tv_sec - tstemp2.tv_sec - 1) * (unsigned long long)1000000000) + tstemp1.tv_nsec + 1000000000 - tstemp2.tv_nsec;
+ }
+ } else if (tstemp1.tv_sec == tstemp2.tv_sec) {
+ if (tstemp1.tv_nsec >= tstemp2.tv_nsec) {
+ diffns = tstemp1.tv_nsec - tstemp2.tv_nsec;
+ } else {
+ diffns = tstemp2.tv_nsec - tstemp1.tv_nsec;
+ }
+ } else {
+ if (tstemp2.tv_nsec >= tstemp1.tv_nsec) {
+ diffns = ((tstemp2.tv_sec - tstemp1.tv_sec) * (unsigned long long)1000000000) + tstemp2.tv_nsec - tstemp1.tv_nsec;
+ } else {
+ diffns = ((tstemp2.tv_sec - tstemp1.tv_sec - 1) * (unsigned long long)1000000000) + tstemp2.tv_nsec + 1000000000 - tstemp1.tv_nsec;
+ }
+ }
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, time1 sec= %ld, nsec=%ld, time2 sec=%ld, nsec=%ld, diffns=%lld", __FUNCTION__, tstemp1.tv_sec, tstemp1.tv_nsec, tstemp2.tv_sec, tstemp2.tv_nsec, diffns);
+ }
+ return diffns;
+
+}
+unsigned long long SPELayer::TimeDifference(struct timespec time1, struct timespec time2) {
+ unsigned long long diffns = 0;
+ struct timespec tstemp1 = time1;
+ struct timespec tstemp2 = time2;
+
+ // ALOGD("TimeStampDiff time1 sec= %ld, nsec=%ld, time2 sec=%ld, nsec=%ld" ,tstemp1.tv_sec, tstemp1.tv_nsec, tstemp2.tv_sec, tstemp2.tv_nsec);
+
+ if (tstemp1.tv_sec > tstemp2.tv_sec) {
+ if (tstemp1.tv_nsec >= tstemp2.tv_nsec) {
+ diffns = ((tstemp1.tv_sec - tstemp2.tv_sec) * (unsigned long long)1000000000) + tstemp1.tv_nsec - tstemp2.tv_nsec;
+ } else {
+ diffns = ((tstemp1.tv_sec - tstemp2.tv_sec - 1) * (unsigned long long)1000000000) + tstemp1.tv_nsec + 1000000000 - tstemp2.tv_nsec;
+ }
+ } else if (tstemp1.tv_sec == tstemp2.tv_sec) {
+ if (tstemp1.tv_nsec >= tstemp2.tv_nsec) {
+ diffns = tstemp1.tv_nsec - tstemp2.tv_nsec;
+ } else {
+ diffns = tstemp2.tv_nsec - tstemp1.tv_nsec;
+ }
+ } else {
+ if (tstemp2.tv_nsec >= tstemp1.tv_nsec) {
+ diffns = ((tstemp2.tv_sec - tstemp1.tv_sec) * (unsigned long long)1000000000) + tstemp2.tv_nsec - tstemp1.tv_nsec;
+ } else {
+ diffns = ((tstemp2.tv_sec - tstemp1.tv_sec - 1) * (unsigned long long)1000000000) + tstemp2.tv_nsec + 1000000000 - tstemp1.tv_nsec;
+ }
+ }
+ // ALOGD("TimeDifference time1 sec= %ld, nsec=%ld, time2 sec=%ld, nsec=%ld, diffns=%lld" ,tstemp1.tv_sec, tstemp1.tv_nsec, tstemp2.tv_sec, tstemp2.tv_nsec,diffns);
+ return diffns;
+}
+
+bool SPELayer::TimeCompare(struct timespec time1, struct timespec time2) {
+ bool bRet = 0;
+
+ if (time1.tv_sec > time2.tv_sec) {
+ bRet = true;
+ } else if (time1.tv_sec == time2.tv_sec) {
+ if (time1.tv_nsec >= time2.tv_nsec) {
+ bRet = true;
+ } else {
+ bRet = false;
+ }
+ } else {
+ bRet = false;
+ }
+ return bRet;
+}
+
+//endtime = false => compare the start time
+//endtime = true => compare the end time
+bool SPELayer::TimeStampCompare(BufferInfo *BufInfo1, BufferInfo *BufInfo2, bool Endtime) {
+ bool bRet = 0;
+ struct timespec tstemp1 = BufInfo1->time_stamp_estimate;
+ struct timespec tstemp2 = BufInfo2->time_stamp_estimate;
+ struct timespec tstemp2_end = tstemp2;
+ int inSample = BufInfo2->BufLen / 2; //mono data since BufInfo2 is downlink data
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, time1 sec= %ld, nsec=%ld, time2 sec=%ld, nsec=%ld, Endtime=%d, inSample=%d", __FUNCTION__, tstemp1.tv_sec, tstemp1.tv_nsec, tstemp2.tv_sec, tstemp2.tv_nsec, Endtime, inSample);
+ }
+ if (Endtime == 0) {
+ if (tstemp1.tv_sec > tstemp2.tv_sec) {
+ bRet = true;
+ } else if (tstemp1.tv_sec == tstemp2.tv_sec) {
+ if (tstemp1.tv_nsec >= tstemp2.tv_nsec) {
+ bRet = true;
+ } else {
+ bRet = false;
+ }
+ } else {
+ bRet = false;
+ }
+ } else {
+ if (tstemp1.tv_sec > tstemp2.tv_sec) {
+ bRet = true;
+ } else if (tstemp1.tv_sec == tstemp2.tv_sec) {
+ if (tstemp1.tv_nsec >= tstemp2.tv_nsec) {
+ bRet = true;
+ } else {
+ bRet = false;
+ return bRet;
+ }
+ } else {
+ bRet = false;
+ return bRet;
+ }
+
+ unsigned long long ns = ((inSample * (unsigned long long)1000000) / 16); //sample rate is 16000
+
+ if (tstemp2.tv_nsec + ns >= 1000000000) {
+ tstemp2.tv_sec++;
+ tstemp2.tv_nsec = tstemp2.tv_nsec + ns - 1000000000;
+ } else {
+ tstemp2.tv_nsec = tstemp2.tv_nsec + ns;
+ }
+ if (EPLDebugEnable == true) {
+ ALOGD("%s, tstemp2 sec=%ld, nsec=%ld, ns=%lld", __FUNCTION__, tstemp2.tv_sec, tstemp2.tv_nsec, ns);
+ }
+ if (tstemp1.tv_sec > tstemp2.tv_sec) {
+ bRet = true;
+ } else if (tstemp1.tv_sec == tstemp2.tv_sec) {
+ if (tstemp1.tv_nsec >= tstemp2.tv_nsec) {
+ bRet = true;
+ } else {
+ bRet = false;
+ }
+ } else {
+ bRet = false;
+ }
+ }
+
+ ALOGD("%s, bRet=%d", __FUNCTION__, bRet);
+ return bRet;
+}
+
+void SPELayer::BypassDLBuffer(void) {
+ BufferInfo *newInBuffer = new BufferInfo;
+ struct timespec tstamp;
+ int BufLength = mSPEProcessBufSize / 2;
+ newInBuffer->pBufBase = (short *) malloc(BufLength);
+ ASSERT(newInBuffer->pBufBase != NULL);
+ //ALOGD("PrepareProcessData %p", newInBuffer->pBufBase);
+ //memset(newInBuffer->pBufBase, 0, BufLength);
+ memset(newInBuffer->pBufBase, BYPASS_DL_PCM_DATA, BufLength);
+
+ tstamp = GetSystemTime();
+ newInBuffer->BufLen = BufLength;
+ newInBuffer->pRead = newInBuffer->pBufBase;
+ newInBuffer->pWrite = newInBuffer->pBufBase;
+ newInBuffer->time_stamp_queued = tstamp;
+ memset((void *) & (newInBuffer->time_stamp_estimate), 0, sizeof(newInBuffer->time_stamp_estimate));
+ memset((void *) & (newInBuffer->time_stamp_process), 0, sizeof(newInBuffer->time_stamp_process));
+
+ //newInBuffer->time_stamp_estimate = {0};
+ //newInBuffer->time_stamp_process = {0};
+ newInBuffer->DLfirstBuf = false;
+
+ //queue to the begging of the downlink input buffer queue, downlink data channel is mono
+ //mDLInBufferQ.add(newInBuffer);
+ mDLInBufferQ.push_front(newInBuffer);
+ if (EPLDebugEnable == true) {
+ ALOGD("BypassDLBuffer, size %zu, %p", mDLInBufferQ.size(), mDLInBufferQ[0]->pBufBase);
+ }
+ //mDLInBufferQ.insertVectorAt(newInBuffer,0);
+ mDLInBufQLenTotal += BufLength;
+ // ALOGD("BypassDLBuffer, mDLInBufQLenTotal=%d, size=%d",mDLInBufQLenTotal,mDLInBufferQ.size());
+
+
+ newInBuffer->BufLen4Delay = BufLength;
+ newInBuffer->pRead4Delay = newInBuffer->pBufBase;
+ newInBuffer->pWrite4Delay = newInBuffer->pBufBase;
+ //mDLDelayBufferQ.add(newInBuffer);
+ mDLDelayBufferQ.push_front(newInBuffer);
+ mDLDelayBufQLenTotal += BufLength;
+}
+
+bool SPELayer::PrepareProcessData() {
+ bool bRet = false;
+ if (mPrepareProcessDataReady) {
+ bRet = true;
+ return bRet;
+ }
+
+ ALOGD("%s+", __FUNCTION__);
+ if (mDLNewStart || (DLdataPrepareCount > 0)) { //the first queue downlink buffer is not ready to play yet, only need to process uplink data, so add zero data on downlink
+ //compensate data to DL and DL delay as zero data for first uplink buffer process
+ ALOGD("%s, DL data is not ready yet, size %zu", __FUNCTION__, mDLInBufferQ.size());
+
+ BypassDLBuffer();
+ if (mDLNewStart) {
+ CalPrepareCount(); // 2 * 4;
+ } else {
+ DLdataPrepareCount--;
+ ALOGD("prepare data DLdataPrepareCount=%d put infront of", DLdataPrepareCount);
+ }
+ bRet = false;
+ } else { //when all data is ready, check the estimate time to let DL/UL could start together.
+ if (mDLInBufferQ.isEmpty() || mDLDelayBufferQ.isEmpty()) {
+ ALOGD("no downlink data, no need to sync");
+ return bRet;
+ }
+
+ if (DLdataPrepareCount > 0) {
+ DLdataPrepareCount--;
+ ALOGD("prepare data DLdataPrepareCount=%d", DLdataPrepareCount);
+ return bRet;
+ }
+#if 1
+ if (TimeCompare(mDownlinkIntrStartTime, mULInBufferQ[0]->time_stamp_estimate)) { //if downlink data is later than uplink data, no need to process AEC and not need to do the sync
+ //compensate data to DL and DL delay as zero data for first uplink buffer process
+ ALOGD("%s, downlink data is not ready yet, no need to sync, size %zu, %p", __FUNCTION__, mDLInBufferQ.size(), mDLInBufferQ[0]->pBufBase);
+ BypassDLBuffer();
+ return bRet;
+ }
+#endif
+ for (size_t i = 0; i < mDLInBufferQ.size(); i++) {
+ ALOGD("mDLInBufferQ i=%zu, length=%d, %p, Sec=%lu, NSec=%lu", i, mDLInBufferQ[i]->BufLen, mDLInBufferQ[i]->pBufBase,
+ mDLInBufferQ[i]->time_stamp_estimate.tv_sec, mDLInBufferQ[i]->time_stamp_estimate.tv_nsec);
+ }
+
+ bool bULlate = false;
+ //struct timespec deltatime;
+ int deltaSec = 0;
+ unsigned long long deltaNSec = 0;
+ ALOGD("%s, time_stamp_estimate, mULInBufferQ[0].sec=%ld, mULInBufferQ[0].nsec=%ld", __FUNCTION__, mULInBufferQ[0]->time_stamp_estimate.tv_sec, mULInBufferQ[0]->time_stamp_estimate.tv_nsec);
+ ALOGD("%s, time_stamp_estimate, mDLInBufferQ[0].sec=%ld, mDLInBufferQ[0].nsec=%ld", __FUNCTION__, mDLInBufferQ[0]->time_stamp_estimate.tv_sec, mDLInBufferQ[0]->time_stamp_estimate.tv_nsec);
+ if (TimeStampCompare(mULInBufferQ[0], mDLInBufferQ[0], 0)) { //drop downlink and downlink delay data
+ //remove previous queue downlink data, to match the nearlist DL buffer timestamp as uplink one
+ while ((!mDLInBufferQ.isEmpty()) && (TimeStampCompare(mULInBufferQ[0], mDLInBufferQ[0], 1))) {
+ //drop DL data
+ uint32_t droplength = mDLInBufferQ[0]->BufLen;
+ mDLInBufQLenTotal -= mDLInBufferQ[0]->BufLen;
+ mDLInBufferQ.removeAt(0);
+
+ //drop DL delay data
+ while (droplength > 0) {
+ ALOGD("%s, 1 drop DL Delay data droplength=%d, mDLDelayBufferQ.size()=%zu, mDLDelayBufferQ[0]->BufLen4Delay=%d!!!", __FUNCTION__, droplength, mDLDelayBufferQ.size(), mDLDelayBufferQ[0]->BufLen4Delay);
+ if (droplength < (uint32_t)mDLDelayBufferQ[0]->BufLen4Delay) {
+ ALOGD("%s, 1 mDLDelayBufferQ[0]->pRead=%p", __FUNCTION__, mDLDelayBufferQ[0]->pRead);
+ mDLDelayBufferQ[0]->BufLen4Delay -= droplength;
+ mDLDelayBufQLenTotal -= droplength;
+ mDLDelayBufferQ[0]->pRead4Delay = mDLDelayBufferQ[0]->pRead4Delay + droplength / 2;
+ droplength = 0;
+ ALOGD("%s, 1 after mDLDelayBufferQ[0]->pRead=%p, mDLDelayBufferQ[0]->BufLen=%d", __FUNCTION__, mDLDelayBufferQ[0]->pRead4Delay, mDLDelayBufferQ[0]->BufLen4Delay);
+ } else {
+ droplength -= mDLDelayBufferQ[0]->BufLen4Delay;
+ mDLDelayBufQLenTotal -= mDLDelayBufferQ[0]->BufLen4Delay;
+ free(mDLDelayBufferQ[0]->pBufBase);
+ delete mDLDelayBufferQ[0];
+ mDLDelayBufferQ.removeAt(0);
+ }
+ }
+
+ if (mDLInBufferQ.isEmpty()) {
+ ALOGD("%s, something wrong? no DL buffer data, sync again", __FUNCTION__);
+ return false;
+ //break;
+ }
+ }
+
+ if (TimeStampCompare(mULInBufferQ[0], mDLInBufferQ[0], 0)) {
+ ALOGD("%s, calculate drop downlink data time", __FUNCTION__);
+ bULlate = true; //calculate drop downlink data time
+ if (mULInBufferQ[0]->time_stamp_estimate.tv_nsec >= mDLInBufferQ[0]->time_stamp_estimate.tv_nsec) {
+ deltaSec = mULInBufferQ[0]->time_stamp_estimate.tv_sec - mDLInBufferQ[0]->time_stamp_estimate.tv_sec;
+ deltaNSec = mULInBufferQ[0]->time_stamp_estimate.tv_nsec - mDLInBufferQ[0]->time_stamp_estimate.tv_nsec;
+ } else {
+ deltaSec = mULInBufferQ[0]->time_stamp_estimate.tv_sec - mDLInBufferQ[0]->time_stamp_estimate.tv_sec - 1;
+ deltaNSec = 1000000000 + mULInBufferQ[0]->time_stamp_estimate.tv_nsec - mDLInBufferQ[0]->time_stamp_estimate.tv_nsec;
+ }
+ } else {
+ bULlate = false;
+ ALOGD("%s, actually uplink is earlier!!! need compensate downlink as zero", __FUNCTION__);
+ if (mDLInBufferQ[0]->time_stamp_estimate.tv_nsec >= mULInBufferQ[0]->time_stamp_estimate.tv_nsec) {
+ deltaSec = mDLInBufferQ[0]->time_stamp_estimate.tv_sec - mULInBufferQ[0]->time_stamp_estimate.tv_sec;
+ deltaNSec = mDLInBufferQ[0]->time_stamp_estimate.tv_nsec - mULInBufferQ[0]->time_stamp_estimate.tv_nsec;
+ } else {
+ deltaSec = mDLInBufferQ[0]->time_stamp_estimate.tv_sec - mULInBufferQ[0]->time_stamp_estimate.tv_sec - 1;
+ deltaNSec = 1000000000 + mDLInBufferQ[0]->time_stamp_estimate.tv_nsec - mULInBufferQ[0]->time_stamp_estimate.tv_nsec;
+ }
+ }
+
+ } else { //UL time is earlier
+ //need compensate downlink data as zero
+ bULlate = false;
+ ALOGD("%s, 2 time_stamp_estimate,mDLInBufferQ[0].nsec = %ld, mULInBufferQ[0].nsec=%ld", __FUNCTION__, mDLInBufferQ[0]->time_stamp_estimate.tv_nsec, mULInBufferQ[0]->time_stamp_estimate.tv_nsec);
+ ALOGD("%s, 2 time_stamp_estimate,mDLInBufferQ[0].sec = %ld, mULInBufferQ[0].sec=%ld", __FUNCTION__, mDLInBufferQ[0]->time_stamp_estimate.tv_sec, mULInBufferQ[0]->time_stamp_estimate.tv_sec);
+
+ if (mDLInBufferQ[0]->time_stamp_estimate.tv_nsec >= mULInBufferQ[0]->time_stamp_estimate.tv_nsec) {
+ deltaSec = mDLInBufferQ[0]->time_stamp_estimate.tv_sec - mULInBufferQ[0]->time_stamp_estimate.tv_sec;
+ deltaNSec = mDLInBufferQ[0]->time_stamp_estimate.tv_nsec - mULInBufferQ[0]->time_stamp_estimate.tv_nsec;
+ } else {
+ deltaSec = mDLInBufferQ[0]->time_stamp_estimate.tv_sec - mULInBufferQ[0]->time_stamp_estimate.tv_sec - 1;
+ deltaNSec = 1000000000 + mDLInBufferQ[0]->time_stamp_estimate.tv_nsec - mULInBufferQ[0]->time_stamp_estimate.tv_nsec;
+ }
+
+ }
+ ALOGD("%s, bULlate %d, deltaSec=%d, deltaNSec=%lld", __FUNCTION__, bULlate, deltaSec, deltaNSec);
+
+ if (deltaSec < 0) {
+ ALOGW("%s, deltaSec < 0? sync again", __FUNCTION__);
+ return false;
+ }
+ unsigned long long diffnsec = deltaSec * 1000000000ULL + deltaNSec;
+ //uint32_t diffSample = mVoIPSampleRate*diffnsec/1000000000;
+ uint32_t diffSample = 16 * diffnsec / 1000000;
+ uint32_t diffBufLength = diffSample * sizeof(short);
+
+ ALOGD("%s, diffnsec %llu, diffSample=%d, diffBufLength=%d", __FUNCTION__, diffnsec, diffSample, diffBufLength);
+#if 1
+ while (diffBufLength > 0) {
+ if (bULlate == true) { //drop DL data and DL delay data
+ if (mDLInBufferQ.isEmpty() || mDLDelayBufferQ.isEmpty()) {
+ ALOGW("%s, no mDLInBufferQ data, something wrong? sync again", __FUNCTION__);
+ return false;
+ //break;
+ }
+ if ((diffBufLength > (uint32_t)mDLInBufQLenTotal) || (diffBufLength > (uint32_t)mDLDelayBufQLenTotal)) {
+ //time diff more than DL preQ data
+ ALOGW("%s, something wrong happened?, sync again", __FUNCTION__);
+ diffBufLength = mDLInBufQLenTotal;
+ return false;
+ //break;
+ }
+ ALOGD("%s, drop DL data diffBufLength=%d, mDLInBufferQ.size()=%zu, mDLInBufferQ[0]->BufLen=%d!!!", __FUNCTION__, diffBufLength, mDLInBufferQ.size(), mDLInBufferQ[0]->BufLen);
+ if (diffBufLength >= (uint32_t)mDLInBufferQ[0]->BufLen) {
+ //drop DL data
+ uint32_t droplength = mDLInBufferQ[0]->BufLen;
+ diffBufLength -= mDLInBufferQ[0]->BufLen;
+ mDLInBufQLenTotal -= mDLInBufferQ[0]->BufLen;
+ mDLInBufferQ.removeAt(0);
+
+ //drop DL delay data
+ while (droplength > 0) {
+ ALOGD("%s, drop DL Delay data droplength=%d, mDLDelayBufferQ.size()=%zu, mDLDelayBufferQ[0]->BufLen4Delay=%d!!!", __FUNCTION__, droplength, mDLDelayBufferQ.size(), mDLDelayBufferQ[0]->BufLen4Delay);
+ if (droplength < (uint32_t)mDLDelayBufferQ[0]->BufLen4Delay) {
+ ALOGD("%s, mDLDelayBufferQ[0]->pRead=%p", __FUNCTION__, mDLDelayBufferQ[0]->pRead);
+ mDLDelayBufferQ[0]->BufLen4Delay -= droplength;
+ mDLDelayBufQLenTotal -= droplength;
+ mDLDelayBufferQ[0]->pRead4Delay = mDLDelayBufferQ[0]->pRead4Delay + droplength / 2;
+ droplength = 0;
+ ALOGD("%s, after mDLDelayBufferQ[0]->pRead=%p, mDLDelayBufferQ[0]->BufLen=%d", __FUNCTION__, mDLDelayBufferQ[0]->pRead4Delay, mDLDelayBufferQ[0]->BufLen4Delay);
+ } else {
+ droplength -= mDLDelayBufferQ[0]->BufLen4Delay;
+ mDLDelayBufQLenTotal -= mDLDelayBufferQ[0]->BufLen4Delay;
+ free(mDLDelayBufferQ[0]->pBufBase);
+ delete mDLDelayBufferQ[0];
+ mDLDelayBufferQ.removeAt(0);
+ }
+ }
+ } else {
+ // ALOGW("PrepareProcessData !!! break for test");
+ // break;
+ //drop DL data
+ ALOGD("%s, mDLInBufferQ[0]->pRead=%p , mDLInBufferQ[0]->BufLen=%d, sec %ld, nsec %ld", __FUNCTION__, mDLInBufferQ[0]->pRead, mDLInBufferQ[0]->BufLen, mDLInBufferQ[0]->time_stamp_estimate.tv_sec,
+ mDLInBufferQ[0]->time_stamp_estimate.tv_nsec);
+ uint32_t droplength = diffBufLength;
+ mDLInBufferQ[0]->BufLen -= diffBufLength; //record the buffer you consumed
+ mDLInBufQLenTotal -= diffBufLength;
+ mDLInBufferQ[0]->pRead = mDLInBufferQ[0]->pRead + diffBufLength / 2;
+
+ //unsigned long long updateDLnsecdiff = (diffBufLength/2)*1000000000/mVoIPSampleRate;
+
+ uint32_t adjustsample = diffBufLength / 2;
+ unsigned long long updateDLnsecdiff = 0;
+ updateDLnsecdiff = (adjustsample * (unsigned long long)1000000) / 16;
+
+ mDLInBufferQ[0]->time_stamp_estimate.tv_sec = mDLInBufferQ[0]->time_stamp_estimate.tv_sec + (mDLInBufferQ[0]->time_stamp_estimate.tv_nsec + updateDLnsecdiff) / 1000000000;
+ mDLInBufferQ[0]->time_stamp_estimate.tv_nsec = (mDLInBufferQ[0]->time_stamp_estimate.tv_nsec + updateDLnsecdiff) % 1000000000;
+
+ ALOGD("%s, after mDLInBufferQ[0]->pRead=%p, mDLInBufferQ[0]->BufLen=%d, updatensecdiff=%lld, sec=%ld, nsec=%ld", __FUNCTION__, mDLInBufferQ[0]->pRead, mDLInBufferQ[0]->BufLen, updateDLnsecdiff,
+ mDLInBufferQ[0]->time_stamp_estimate.tv_sec, mDLInBufferQ[0]->time_stamp_estimate.tv_nsec);
+ diffBufLength = 0;
+
+ //drop DL delay data
+ while (droplength > 0) {
+ ALOGD("%s, drop DL Delay data droplength=%d, mDLDelayBufferQ.size()=%zu, mDLDelayBufferQ[0]->BufLen4Delay=%d!!!", __FUNCTION__, droplength, mDLDelayBufferQ.size(), mDLDelayBufferQ[0]->BufLen4Delay);
+ if (droplength < (uint32_t)mDLDelayBufferQ[0]->BufLen4Delay) {
+ ALOGD("%s, mDLDelayBufferQ[0]->pRead=%p", __FUNCTION__, mDLDelayBufferQ[0]->pRead4Delay);
+ mDLDelayBufferQ[0]->BufLen4Delay -= droplength;
+ mDLDelayBufQLenTotal -= droplength;
+ mDLDelayBufferQ[0]->pRead4Delay = mDLDelayBufferQ[0]->pRead4Delay + droplength / 2;
+ droplength = 0;
+ ALOGD("%s, after mDLDelayBufferQ[0]->pRead=%p, mDLDelayBufferQ[0]->BufLen=%d", __FUNCTION__, mDLDelayBufferQ[0]->pRead4Delay, mDLDelayBufferQ[0]->BufLen4Delay);
+ } else {
+ droplength -= mDLDelayBufferQ[0]->BufLen4Delay;
+ mDLDelayBufQLenTotal -= mDLDelayBufferQ[0]->BufLen4Delay;
+ free(mDLDelayBufferQ[0]->pBufBase);
+ delete mDLDelayBufferQ[0];
+ mDLDelayBufferQ.removeAt(0);
+ }
+ }
+
+ }
+ } else { //add DL zero data at the beginning
+ BufferInfo *newInBuffer = new BufferInfo;
+ struct timespec tstamp;
+ uint32_t BufLength = diffBufLength;
+ newInBuffer->pBufBase = (short *) malloc(BufLength);
+ ASSERT(newInBuffer->pBufBase != NULL);
+ ALOGD("%s, data is ready but need adjust", __FUNCTION__);
+ //memset(newInBuffer->pBufBase, 0, BufLength);
+ memset(newInBuffer->pBufBase, PREPARE_PROCESS_PCM_DATA, BufLength);
+
+ tstamp = GetSystemTime();
+ newInBuffer->BufLen = BufLength;
+ newInBuffer->pRead = newInBuffer->pBufBase;
+ newInBuffer->pWrite = newInBuffer->pBufBase;
+ newInBuffer->time_stamp_queued = tstamp;
+ newInBuffer->time_stamp_estimate = tstamp;
+ memset((void *) & (newInBuffer->time_stamp_process), 0, sizeof(newInBuffer->time_stamp_process));
+
+ //queue to the begging of the downlink input buffer queue, downlink data channel is mono
+ //mDLInBufferQ.add(newInBuffer);
+ mDLInBufferQ.push_front(newInBuffer);
+ //ALOGD("PrepareProcessData, size %d, %p",mDLInBufferQ.size(), mDLInBufferQ[0]->pBufBase);
+ //mDLInBufferQ.insertVectorAt(newInBuffer,0);
+ mDLInBufQLenTotal += BufLength;
+ // ALOGD("CompensateBuffer, mDLInBufQLenTotal=%d, size=%d",mDLInBufQLenTotal,mDLInBufferQ.size());
+
+
+ newInBuffer->BufLen4Delay = BufLength;
+ newInBuffer->pRead4Delay = newInBuffer->pBufBase;
+ newInBuffer->pWrite4Delay = newInBuffer->pBufBase;
+ //mDLDelayBufferQ.add(newInBuffer);
+ mDLDelayBufferQ.push_front(newInBuffer);
+ mDLDelayBufQLenTotal += BufLength;
+ diffBufLength = 0;
+ }
+ }
+#endif
+ ALOGD("%s, finish, mDLInBufferQ.size = %zu, mDLInBufQLenTotal=%d, mULInBufferQ.size = %zu, mULInBufQLenTotal=%d", __FUNCTION__, mDLInBufferQ.size(), mDLInBufQLenTotal, mULInBufferQ.size(),
+ mULInBufQLenTotal); //going to start process
+ ALOGD("%s, finish, mDLInBufferQ[0]->pRead=%p , mDLInBufferQ[0]->BufLen=%d, sec = %ld, nsec = %ld"
+ , __FUNCTION__, mDLInBufferQ[0]->pRead, mDLInBufferQ[0]->BufLen, mDLInBufferQ[0]->time_stamp_estimate.tv_sec, mDLInBufferQ[0]->time_stamp_estimate.tv_nsec);
+
+ ALOGD("%s, finish, mULInBufferQ[0]->pRead=%p , mULInBufferQ[0]->BufLen=%d, sec = %ld, nsec = %ld"
+ , __FUNCTION__, mULInBufferQ[0]->pRead, mULInBufferQ[0]->BufLen, mULInBufferQ[0]->time_stamp_estimate.tv_sec, mULInBufferQ[0]->time_stamp_estimate.tv_nsec);
+
+ mPrepareProcessDataReady = true;
+ bRet = true;
+
+ if (mNeedJitterBuffer && (mJitterSampleCount != 0)) { //the first DL buffer, add the jitter buffer at the first downlink buffer queue and downlink delay buffer queue
+ mNeedJitterBuffer = false;
+ BufferInfo *newJitterBuffer = new BufferInfo;
+ newJitterBuffer->pBufBase = (short *) malloc(mJitterSampleCount * sizeof(short)); //one channel, 16bits
+ ASSERT(newJitterBuffer->pBufBase != NULL);
+ newJitterBuffer->BufLen = mJitterSampleCount * sizeof(short);
+ newJitterBuffer->pRead = newJitterBuffer->pBufBase;
+ newJitterBuffer->pWrite = newJitterBuffer->pBufBase;
+ newJitterBuffer->BufLen4Delay = mJitterSampleCount * sizeof(short);
+ newJitterBuffer->pRead4Delay = newJitterBuffer->pBufBase;
+ newJitterBuffer->pWrite4Delay = newJitterBuffer->pBufBase;
+ memset(newJitterBuffer->pBufBase, 0, newJitterBuffer->BufLen);
+ //newJitterBuffer->time_stamp_queued = tstamp;
+ memset((void *) & (newJitterBuffer->time_stamp_process), 0, sizeof(newJitterBuffer->time_stamp_process));
+ mDLInBufferQ.push_front(newJitterBuffer);
+ mDLInBufQLenTotal += newJitterBuffer->BufLen;
+
+ mDLDelayBufferQ.push_front(newJitterBuffer);
+ mDLDelayBufQLenTotal += newJitterBuffer->BufLen;
+ ALOGD("add jitter buffer,newDelayBuffer->BufLen=%d, size=%zu, mJitterSampleCount=%d, pBufBase=%p", newJitterBuffer->BufLen, mDLInBufferQ.size(), mJitterSampleCount, newJitterBuffer->pBufBase);
+ }
+
+ if (mNeedDelayLatency && (mLatencySampleCount != 0)) { //the first DL buffer, add the delay time buffer as first delay buffer queue
+ //mNeedDelayLatency = false;
+ ALOGD("%s, adjust downlink data mLatencyDir=%d,mLatencySampleCount=%d", __FUNCTION__, mLatencyDir, mLatencySampleCount);
+ if (mLatencyDir == true) {
+ BufferInfo *newDelayBuffer = new BufferInfo;
+ newDelayBuffer->pBufBase = (short *) malloc(mLatencySampleCount * sizeof(short)); //one channel, 16bits
+ ASSERT(newDelayBuffer->pBufBase != NULL);
+ newDelayBuffer->BufLen = mLatencySampleCount * sizeof(short);
+ newDelayBuffer->pRead = newDelayBuffer->pBufBase;
+ newDelayBuffer->pWrite = newDelayBuffer->pBufBase;
+ newDelayBuffer->BufLen4Delay = mLatencySampleCount * sizeof(short);
+ newDelayBuffer->pRead4Delay = newDelayBuffer->pBufBase;
+ newDelayBuffer->pWrite4Delay = newDelayBuffer->pBufBase;
+ memset(newDelayBuffer->pBufBase, 0, newDelayBuffer->BufLen);
+ //newDelayBuffer->time_stamp_queued = tstamp;
+ //newDelayBuffer->time_stamp_process = {0};
+ memset((void *) & (newDelayBuffer->time_stamp_process), 0, sizeof(newDelayBuffer->time_stamp_process));
+ mDLDelayBufferQ.push_front(newDelayBuffer);
+ mDLDelayBufQLenTotal += newDelayBuffer->BufLen;
+ ALOGD("add delay latency buffer, newDelayBuffer->BufLen=%d, size=%zu, mLatencySampleCount=%d, pBufBase=%p", newDelayBuffer->BufLen, mDLDelayBufferQ.size(), mLatencySampleCount,
+ newDelayBuffer->pBufBase);
+ } else {
+ uint32_t diffLatencyBufLength = mLatencySampleCount * sizeof(short);
+ while (diffLatencyBufLength > 0) {
+ if (mDLInBufferQ.isEmpty() || mDLDelayBufferQ.isEmpty()) {
+ ALOGW("adjust downlink data no mDLInBufferQ data");
+ break;
+ }
+ if ((diffLatencyBufLength > (uint32_t)mDLInBufQLenTotal) || (diffLatencyBufLength > (uint32_t)mDLDelayBufQLenTotal)) {
+ //time diff more than DL preQ data
+ ALOGW("adjust downlink data something wrong happened?");
+ diffLatencyBufLength = mDLInBufQLenTotal;
+ //break;
+ }
+ ALOGD("adjust downlink data drop DL data diffBufLength=%d, mDLInBufferQ.size()=%zu, mDLInBufferQ[0]->BufLen=%d!!!", diffBufLength, mDLInBufferQ.size(), mDLInBufferQ[0]->BufLen);
+ if (diffLatencyBufLength >= (uint32_t)mDLInBufferQ[0]->BufLen) {
+ //drop DL data
+ uint32_t droplength = mDLInBufferQ[0]->BufLen;
+ diffLatencyBufLength -= mDLInBufferQ[0]->BufLen;
+ mDLInBufQLenTotal -= mDLInBufferQ[0]->BufLen;
+ mDLInBufferQ.removeAt(0);
+
+ //drop DL delay data
+ while (droplength > 0) {
+ ALOGD("adjust downlink data drop DL Delay data droplength=%d, mDLDelayBufferQ.size()=%zu, mDLDelayBufferQ[0]->BufLen4Delay=%d!!!", droplength, mDLDelayBufferQ.size(), mDLDelayBufferQ[0]->BufLen4Delay);
+ if (droplength < (uint32_t)mDLDelayBufferQ[0]->BufLen4Delay) {
+ ALOGD("adjust downlink data mDLDelayBufferQ[0]->pRead=%p", mDLDelayBufferQ[0]->pRead);
+ mDLDelayBufferQ[0]->BufLen4Delay -= droplength;
+ mDLDelayBufQLenTotal -= droplength;
+ mDLDelayBufferQ[0]->pRead4Delay = mDLDelayBufferQ[0]->pRead4Delay + droplength / 2;
+ droplength = 0;
+ ALOGD("adjust downlink data after mDLDelayBufferQ[0]->pRead=%p, mDLDelayBufferQ[0]->BufLen=%d", mDLDelayBufferQ[0]->pRead4Delay, mDLDelayBufferQ[0]->BufLen4Delay);
+ } else {
+ droplength -= mDLDelayBufferQ[0]->BufLen4Delay;
+ mDLDelayBufQLenTotal -= mDLDelayBufferQ[0]->BufLen4Delay;
+ free(mDLDelayBufferQ[0]->pBufBase);
+ delete mDLDelayBufferQ[0];
+ mDLDelayBufferQ.removeAt(0);
+ }
+ }
+ } else {
+
+ //drop DL data
+ ALOGD("adjust downlink data mDLInBufferQ[0]->pRead=%p , mDLInBufferQ[0]->BufLen=%d, sec %ld, nsec %ld", mDLInBufferQ[0]->pRead, mDLInBufferQ[0]->BufLen, mDLInBufferQ[0]->time_stamp_estimate.tv_sec,
+ mDLInBufferQ[0]->time_stamp_estimate.tv_nsec);
+ uint32_t droplength = diffLatencyBufLength;
+ mDLInBufferQ[0]->BufLen -= diffLatencyBufLength; //record the buffer you consumed
+ mDLInBufQLenTotal -= diffLatencyBufLength;
+ mDLInBufferQ[0]->pRead = mDLInBufferQ[0]->pRead + diffLatencyBufLength / 2;
+
+ //unsigned long long updateDLnsecdiff = (diffBufLength/2)*1000000000/mVoIPSampleRate;
+
+ uint32_t adjustsample = diffLatencyBufLength / 2;
+ unsigned long long updateDLnsecdiff = 0;
+ updateDLnsecdiff = (adjustsample * (unsigned long long)1000000) / 16;
+
+ mDLInBufferQ[0]->time_stamp_estimate.tv_sec = mDLInBufferQ[0]->time_stamp_estimate.tv_sec + (mDLInBufferQ[0]->time_stamp_estimate.tv_nsec + updateDLnsecdiff) / 1000000000;
+ mDLInBufferQ[0]->time_stamp_estimate.tv_nsec = (mDLInBufferQ[0]->time_stamp_estimate.tv_nsec + updateDLnsecdiff) % 1000000000;
+
+ ALOGD("adjust downlink data after mDLInBufferQ[0]->pRead=%p, mDLInBufferQ[0]->BufLen=%d, updatensecdiff=%lld, sec=%ld, nsec=%ld", mDLInBufferQ[0]->pRead, mDLInBufferQ[0]->BufLen, updateDLnsecdiff,
+ mDLInBufferQ[0]->time_stamp_estimate.tv_sec, mDLInBufferQ[0]->time_stamp_estimate.tv_nsec);
+ diffLatencyBufLength = 0;
+
+ //drop DL delay data
+ while (droplength > 0) {
+ ALOGD("adjust downlink data drop DL Delay data droplength=%d, mDLDelayBufferQ.size()=%zu, mDLDelayBufferQ[0]->BufLen4Delay=%d!!!", droplength, mDLDelayBufferQ.size(), mDLDelayBufferQ[0]->BufLen4Delay);
+ if (droplength < (uint32_t)mDLDelayBufferQ[0]->BufLen4Delay) {
+ ALOGD("adjust downlink data mDLDelayBufferQ[0]->pRead=%p", mDLDelayBufferQ[0]->pRead4Delay);
+ mDLDelayBufferQ[0]->BufLen4Delay -= droplength;
+ mDLDelayBufQLenTotal -= droplength;
+ mDLDelayBufferQ[0]->pRead4Delay = mDLDelayBufferQ[0]->pRead4Delay + droplength / 2;
+ droplength = 0;
+ ALOGD("adjust downlink data after mDLDelayBufferQ[0]->pRead=%p, mDLDelayBufferQ[0]->BufLen=%d", mDLDelayBufferQ[0]->pRead4Delay, mDLDelayBufferQ[0]->BufLen4Delay);
+ } else {
+ droplength -= mDLDelayBufferQ[0]->BufLen4Delay;
+ mDLDelayBufQLenTotal -= mDLDelayBufferQ[0]->BufLen4Delay;
+ free(mDLDelayBufferQ[0]->pBufBase);
+ delete mDLDelayBufferQ[0];
+ mDLDelayBufferQ.removeAt(0);
+ }
+ }
+
+ }
+ }
+ }
+ }
+
+#if 0
+ for (int i; i < mDLDelayBufferQ.size(); i++) {
+ ALOGD("PrepareProcessData mDLDelayBufferQ i=%d, length=%d, %p", i, mDLDelayBufferQ[i]->BufLen, mDLDelayBufferQ[i]->pBufBase);
+ }
+#endif
+ }
+ return bRet;
+}
+
+int SPELayer::Process_Record(short *inBuf, int inBufLength) {
+ int retSize = inBufLength;
+ //pthread_mutex_lock(&mBufMutex );
+ //ALOGD("Process_Record, SPERecBufSize=%d,inBufLength=%d,mULInBufQLenTotal=%d, Insize=%d,Outsize=%d",SPERecBufSize,inBufLength,mULInBufQLenTotal,mULInBufferQ.size(),mULOutBufferQ.size());
+ if ((mULInBufQLenTotal < mSPEProcessBufSize) && (mULOutBufferQ.size() == 0)) { //not enough UL buffer for process, and no processed uplink output buffer
+ ALOGD("%s,going memset 0 inBuf=%p,inBufLength=%d", __FUNCTION__, inBuf, inBufLength);
+ memset(inBuf, 0, inBufLength); //clear the buffer data as zero
+ //AL_UNLOCK(mBufMutex);
+ retSize = 0;
+ return retSize; //return the processed buffer size
+ }
+
+ // ALOGD("SPELayer::Process, enough mULInBufQLenTotal buffer,size=%d",mULInBufferQ.size());
+ //process input data in the buffer queue
+ while (mULInBufQLenTotal >= mSPEProcessBufSize) {
+ int tmpSPEProcessBufSize = mSPEProcessBufSize;
+ int indexIn = 0;
+ int tempULIncopysize = mULInBufferQ[0]->BufLen >> 2;
+
+ // ALOGD("SPELayer::Process, mULInBufQLenTotal=%d, SPERecBufSize=%d,tempULIncopysize=%d",mULInBufQLenTotal,mSPEProcessBufSize,tempULIncopysize);
+ //fill in the data to the process buffer
+ while (tmpSPEProcessBufSize) {
+ if (mULInBufferQ.isEmpty()) {
+ ALOGD("%s, uplink input buffer queue is empty, something wrong!!", __FUNCTION__);
+ mError = true;
+ break;
+ }
+
+ // ALOGD("SPELayer indexIn=%d, tmpSPERecBufSize=%d, mULInBufQLenTotal=%d,mULInBufferQ[0]->pRead=%p,mULInBufferQ[0]->pBufBase=%p,mULInBufferQ[0]->BufLen=%d,tempULIncopysize=%d",indexIn,tmpSPERecBufSize,mULInBufQLenTotal,mULInBufferQ[0]->pRead,mULInBufferQ[0]->pBufBase,mULInBufferQ[0]->BufLen,tempULIncopysize);
+ if (tempULIncopysize > 0) { //get the buffer data from the first uplink input buffer queue
+ *(mpSPEBufferUL1 + indexIn) = *(mULInBufferQ[0]->pRead); //left channel
+ *(mpSPEBufferUL2 + indexIn) = *(mULInBufferQ[0]->pRead + 1); //right channel
+ //ALOGD("%d,%d",*(mULInBufferQ[0]->pRead),*(mULInBufferQ[0]->pRead +1));
+ mULInBufferQ[0]->pRead += 2;
+ tempULIncopysize--;
+ indexIn++;
+ tmpSPEProcessBufSize -= 4;
+ mULInBufQLenTotal -= 4; //int and short transform
+ mULInBufferQ[0]->BufLen -= 4; //record the buffer you consumed
+ } else { //consume all the data in first queue buffer
+ free(mULInBufferQ[0]->pBufBase);
+ delete mULInBufferQ[0];
+ mULInBufferQ.removeAt(0);
+ tempULIncopysize = mULInBufferQ[0]->BufLen >> 2;
+ // ALOGD("UL in buffer consume finish, next BufferBase=%p",mULInBufferQ[0]->pBufBase);
+ }
+ }
+
+ if (mError) {
+ ALOGD("%s, error!!", __FUNCTION__);
+ break;
+ }
+
+ //process the fill in buffer
+ mSphEnhOps.ENH_API_Process(&mSph_Enh_ctrl);
+
+ Dump_EPL(&mSph_Enh_ctrl.EPL_buffer, EPLBufSize * sizeof(short));
+ EPLTransVMDump();
+
+ BufferInfo *newOutBuffer = new BufferInfo;
+
+ newOutBuffer->pBufBase = (short *) malloc(mSPEProcessBufSize);
+ ASSERT(newOutBuffer->pBufBase != NULL);
+ newOutBuffer->BufLen = mSPEProcessBufSize;
+
+ newOutBuffer->pRead = newOutBuffer->pBufBase;
+ newOutBuffer->pWrite = newOutBuffer->pBufBase;
+ // ALOGD("newOutBuffer->pBufBase=%p,newOutBuffer->pRead=%p,newOutBuffer->pWrite=%p,newOutBuffer->BufLen=%d",newOutBuffer->pBufBase,newOutBuffer->pRead,newOutBuffer->pWrite,newOutBuffer->BufLen);
+
+ int indexOut = 0;
+ int copysize = newOutBuffer->BufLen >> 2;
+ while (copysize) {
+ // ALOGD("newOutBuffer->pWrite=%p, indexOut=%d,copysizetest=%d",newOutBuffer->pWrite,indexOut,copysizetest);
+ *(newOutBuffer->pWrite) = *(mpSPEBufferUL1 + indexOut); //left channel
+ *(newOutBuffer->pWrite + 1) = *(mpSPEBufferUL2 + indexOut); //right channel
+ newOutBuffer->pWrite += 2;
+ indexOut++;
+ copysize--;
+ }
+
+ Dump_PCM_Process(UPLINK, newOutBuffer->pBufBase, newOutBuffer->BufLen);
+
+ mULOutBufferQ.add(newOutBuffer);
+ mULOutBufQLenTotal += newOutBuffer->BufLen;
+
+ // ALOGD("mULOutBufQLenTotal=%d, indexOut=%d,newOutBuffer->pWrite=%p, mULOutBufferQsize=%d",mULOutBufQLenTotal,indexOut,newOutBuffer->pWrite,mULOutBufferQ.size());
+ }
+
+
+ //process the processed output buffer queue
+
+ // ALOGD("mULOutBufferQ=%d, mULOutBufQLenTotal=%d",mULOutBufferQ.size(),mULOutBufQLenTotal);
+ if (mULOutBufferQ.isEmpty()) {
+ ALOGD("%s, not enought UL output buffer", __FUNCTION__);
+ memset(inBuf, 0, inBufLength); //return in same input buffer address
+ //AL_UNLOCK(mBufMutex);
+ retSize = 0;
+ return retSize; //return the processed buffer size
+ }
+
+ int tmpInBufLength = inBufLength;
+ if (mULOutBufQLenTotal < inBufLength) {
+ tmpInBufLength = mULOutBufQLenTotal;
+ }
+ retSize = tmpInBufLength;
+ int count = 0;
+ int tempULCopy = mULOutBufferQ[0]->BufLen >> 2;
+ while (tmpInBufLength) {
+ if (mULOutBufferQ.isEmpty()) {
+ ALOGD("%s, uplink Output buffer queue is empty, something wrong!!", __FUNCTION__);
+ mError = true;
+ break;
+ }
+
+ // ALOGD("mULOutBufferQ.size = %d,tempULCopy=%d",mULOutBufferQ.size(),tempULCopy);
+
+ if (tempULCopy > 0) { //get the buffer data from the first uplink input buffer queue
+ // ALOGD("mULOutBufferQ[0]->pRead = %p,mULOutBufferQ[0]->pBufBase=%p,mULOutBufferQ[0]->BufLen=%d",mULOutBufferQ[0]->pRead,mULOutBufferQ[0]->pBufBase,mULOutBufferQ[0]->BufLen);
+ // ALOGD("tmpInBufLength=%d,count=%d,mULOutBufQLenTotal=%d,tempULCopy=%d",tmpInBufLength,count,mULOutBufQLenTotal,tempULCopy);
+ *(inBuf + count) = *(mULOutBufferQ[0]->pRead);
+ *(inBuf + count + 1) = *(mULOutBufferQ[0]->pRead + 1);
+ mULOutBufferQ[0]->pRead += 2;
+ tmpInBufLength -= 4; //int and short transform
+ tempULCopy--;
+ count += 2;
+ mULOutBufQLenTotal -= 4; //int and short transform
+ mULOutBufferQ[0]->BufLen -= 4;
+ } else { //consume all the data in first queue buffer
+ free(mULOutBufferQ[0]->pBufBase);
+ delete mULOutBufferQ[0];
+ mULOutBufferQ.removeAt(0);
+ tempULCopy = mULOutBufferQ[0]->BufLen >> 2;
+ // ALOGD("SPELayer::uplink Output buffer consumed");
+ }
+ }
+ //AL_UNLOCK(mBufMutex);
+ return retSize;
+}
+
+int SPELayer::Process_VoIP(short *inBuf, int inBufLength) {
+ int retSize = inBufLength;
+ // ALOGD("SPELayer::process VoIP");
+ //pthread_mutex_lock(&mBufMutex );
+ // ALOGD("SPELayer::Process, SPERecBufSize=%d,inBufLength=%d,mULInBufQLenTotal=%d, Insize=%d,Outsize=%d",SPERecBufSize,inBufLength,mULInBufQLenTotal,mULInBufferQ.size(),mULOutBufferQ.size());
+
+ if (mULInBufQLenTotal < mSPEProcessBufSize) { //not enough UL input buffer for process
+ int tmpInBufLength = inBufLength;
+
+ if (mULOutBufferQ.isEmpty() || mULOutBufQLenTotal < inBufLength) { //TODO:fixme, return data we have?
+ ALOGD("not enough UL output buffer, inBuf=%p,inBufLength=%d", inBuf, inBufLength);
+ memset(inBuf, 0, inBufLength); //reset data
+ //AL_UNLOCK(mBufMutex);
+ //return true;
+ retSize = 0;
+ return retSize; //return the processed buffer size
+ }
+
+
+ int count = 0;
+ int tempULCopy = mULOutBufferQ[0]->BufLen >> 2;
+ while (tmpInBufLength) {
+ if (mULOutBufferQ.isEmpty()) {
+ ALOGD("%s(), Output buffer queue is empty, return size mULOutBufQLenTotal", __FUNCTION__);
+ break;
+ }
+
+ // ALOGD("mDLOutBufferQ.size = %d,tempDLCopy=%d",mDLOutBufferQ.size(),tempDLCopy);
+
+ if (tempULCopy > 0) { //get the buffer data from the first downlink input buffer queue
+ // ALOGD("mULOutBufferQ[0]->pRead = %p,mULOutBufferQ[0]->pBufBase=%p,mULOutBufferQ[0]->BufLen=%d",mULOutBufferQ[0]->pRead,mULOutBufferQ[0]->pBufBase,mULOutBufferQ[0]->BufLen);
+ // ALOGD("tmpInBufLength=%d,count=%d,mULOutBufQLenTotal=%d,tempULCopy=%d",tmpInBufLength,count,mULOutBufQLenTotal,tempULCopy);
+ *(inBuf + count) = *(mULOutBufferQ[0]->pRead);
+ *(inBuf + count + 1) = *(mULOutBufferQ[0]->pRead + 1);
+ mULOutBufferQ[0]->pRead += 2;
+ tmpInBufLength -= 4; //int and short transform
+ tempULCopy--;
+ count += 2;
+ mULOutBufQLenTotal -= 4; //int and short transform
+ mULOutBufferQ[0]->BufLen -= 4;
+ } else { //consume all the data in first queue buffer
+ free(mULOutBufferQ[0]->pBufBase);
+ delete mULOutBufferQ[0];
+ mULOutBufferQ.removeAt(0);
+ //need check if still have ULOutbuffer
+ if (!mULOutBufferQ.isEmpty()) {
+ ALOGD("%s, mULOutBufferQ not empty, get next one, size=%zu", __FUNCTION__, mULOutBufferQ.size());
+ tempULCopy = mULOutBufferQ[0]->BufLen >> 2;
+ } else {
+ ALOGD("%s, mULOutBufferQ is empty!!! size=%zu", __FUNCTION__, mULOutBufferQ.size());
+ }
+ // ALOGD("SPELayer::uplink Output buffer consumed a");
+ }
+ }
+ ALOGD("%s, has UL Output buffer but not enough UL Input buffer, size=%zu, mULOutBufQLenTotal=%d", __FUNCTION__, mULOutBufferQ.size(), mULOutBufQLenTotal);
+ //AL_UNLOCK(mBufMutex);
+ //AL_UNLOCK(mBufMutex);
+ //return true;
+ return retSize;
+ }
+
+ //fix me!!: process when UL data is enough, DL data need to compensated as zero
+ //processing if have enough input UL data (UL is stereo, DL is mono data)
+ if (mULInBufQLenTotal >= mSPEProcessBufSize) { //&&(mDLInBufQLenTotal>= mSPEProcessBufSize/2))
+ while (mULInBufQLenTotal >= mSPEProcessBufSize) { //&&(mDLInBufQLenTotal>= mSPEProcessBufSize/2)) //TODO:fixme!!! has problem
+ if (mDLInBufQLenTotal < mSPEProcessBufSize / 2) { //not enough downlink data to process, wait for a while
+ if (mULOutBufQLenTotal >= inBufLength) {
+ if (EPLDebugEnable == true) {
+ ALOGD("Process_VoIP have enough uplink processed data, skip this time");
+ }
+ break;
+ }
+ //WaitforDownlinkData();
+ }
+
+ if (PrepareProcessData()) { //sync ok, could start process
+ if (mDLInBufQLenTotal < mSPEProcessBufSize / 2) { //not enough downlink data to process, wait for a while
+ if (WaitforDownlinkData()) { //got new DL data queue
+ if (mDLInBufQLenTotal < mSPEProcessBufSize / 2) { //but still not enough data to process
+ if (EPLDebugEnable == true) {
+ ALOGD("got new DL buffer, but still not enough data to process");
+ }
+ continue;
+ }
+ } else { //no new DL data queue
+ ALOGD("no new DL buffer queue, process directly");
+ }
+ } else { //has enough downlink data to process, but still check if there has downlink buffer queue wait
+ if (mNewReferenceBufferComes) { //if there is new DL buffer comes, let it add the queue first (To not block the downlink process)
+ InsertDownlinkData();
+ }
+ }
+ } else { //no sync yet, no need to check or wait for downlink data
+ if (mNewReferenceBufferComes) { //if there is new DL buffer comes, let it add the queue first (To not block the downlink process)
+ ALOGD("also check if new downlink data comes even the sync is not ready");
+ InsertDownlinkData();
+ }
+ }
+
+ //fill in the data to process buffer
+ int tmpSPEProcessBufSize = mSPEProcessBufSize;
+ int indexIn = 0;
+ int ULIncopysize = mULInBufferQ[0]->BufLen >> 2;
+
+ struct timespec tstamp_process;
+ struct timespec DLtstamp_compen;
+
+ if (mDLInBufferQ.isEmpty()) { //there is no DL data before process, compensate time use the uplink time, else use the DL previous time
+ DLtstamp_compen = mULInBufferQ[0]->time_stamp_estimate;
+ }
+ if (EPLDebugEnable == true) {
+ //ALOGD("%s, mULInBufQLenTotal=%d, mDLInBufQLenTotal=%d, SPERecBufSize=%d,ULIncopysize=%d", __FUNCTION__, mULInBufQLenTotal, mDLInBufQLenTotal, mSPEProcessBufSize, ULIncopysize);
+ ALOGD("%s, mULInBufQLenTotal=%d, mDLInBufQLenTotal=%d, SPERecBufSize=%d,ULIncopysize=%d, mULOutBufQLenTotal=%d, mULOutBufferQ.size=%zu, bypass process",
+ __FUNCTION__, mULInBufQLenTotal, mDLInBufQLenTotal, mSPEProcessBufSize, ULIncopysize, mULOutBufQLenTotal, mULOutBufferQ.size());
+ }
+ //if(!mDLDelayBufferQ.isEmpty())
+ //ALOGD("SPELayer::Process_VoIP, mDLDelayBufferQ size=%d,mDLDelayBufQLenTotal=%d, SPERecBufSize=%d, %p",mDLDelayBufferQ.size(),mDLDelayBufQLenTotal,mSPEProcessBufSize,mDLDelayBufferQ[0]->pBufBase);
+ //if(!mDLInBufferQ.isEmpty())
+ //ALOGD("SPELayer::Process_VoIP, mDLInBufferQ size=%d,mDLInBufQLenTotal=%d,ULIncopysize=%d, %p",mDLInBufferQ.size(),mDLInBufQLenTotal,ULIncopysize,mDLInBufferQ[0]->pBufBase);
+
+ while (tmpSPEProcessBufSize) {
+ if (mULInBufferQ.isEmpty()) { //||mDLInBufferQ.isEmpty()||mDLDelayBufferQ.isEmpty())
+ ALOGD("%s,input buffer queue is empty, something wrong!!", __FUNCTION__);
+ mError = true;
+ break;
+ }
+
+ tstamp_process = GetSystemTime();
+
+ // ALOGD("SPELayer indexIn=%d, tmpSPERecBufSize=%d, mULInBufQLenTotal=%d,mULInBufferQ[0]->pRead=%p,mULInBufferQ[0]->pBufBase=%p,mULInBufferQ[0]->BufLen=%d,ULIncopysize=%d",indexIn,tmpSPERecBufSize,mULInBufQLenTotal,mULInBufferQ[0]->pRead,mULInBufferQ[0]->pBufBase,mULInBufferQ[0]->BufLen,ULIncopysize);
+ if (ULIncopysize > 0) { //get the buffer data from the first uplink input buffer queue
+ //fill in uplink data
+ *(mpSPEBufferUL1 + indexIn) = *(mULInBufferQ[0]->pRead);
+ *(mpSPEBufferUL2 + indexIn) = *(mULInBufferQ[0]->pRead + 1);
+ mULInBufferQ[0]->pRead += 2;
+ mULInBufQLenTotal -= 4; //int and short transform
+ mULInBufferQ[0]->BufLen -= 4; //record the buffer you consumed
+
+ mULInBufferQ[0]->time_stamp_process = tstamp_process;
+
+
+#if 1 //INTR
+ //update estimate time, when use the corresponding time
+ mULInBufferQ[0]->time_stamp_estimate.tv_sec = mULInBufferQ[0]->time_stamp_estimate.tv_sec + (mULInBufferQ[0]->time_stamp_estimate.tv_nsec + mNsecPerSample) / 1000000000;
+ mULInBufferQ[0]->time_stamp_estimate.tv_nsec = (mULInBufferQ[0]->time_stamp_estimate.tv_nsec + mNsecPerSample) % 1000000000;
+#endif
+ //fill in downlink data
+ if (mDLInBufferQ.isEmpty()) {
+ ALOGD("no DL buffer, need compensate 1, tmpSPEProcessBufSize=%d", tmpSPEProcessBufSize);
+ CompensateBuffer(tmpSPEProcessBufSize / 2, DLtstamp_compen);
+ }
+ if (mDLInBufferQ[0]->BufLen <= 0) { //run out of DL queue0 buffer
+ //not to free the buffer here due to the data still queue in the DLDelay buffer
+ //free(mDLInBufferQ[0]->pBufBase); //just remove the queue but not delete buffer since it also queue in the delay queue
+ //delete mDLInBufferQ[0];
+ mDLInBufferQ.removeAt(0);
+ // ALOGD("get next DLInBufferQ, size=%d, mDLInBufQLenTotal=%d",mDLInBufferQ.size(),mDLInBufQLenTotal);
+ if (mDLInBufferQ.isEmpty()) {
+ ALOGD("no DL buffer, need compensate, tmpSPEProcessBufSize=%d", tmpSPEProcessBufSize);
+#if 1//def DOWNLINK_MONO
+ CompensateBuffer(tmpSPEProcessBufSize / 2, DLtstamp_compen);
+#else
+ CompensateBuffer(tmpSPEProcessBufSize);
+#endif
+ }
+ // ALOGD("DL in buffer consume finish, next BufferBase=%p",mDLInBufferQ[0]->pBufBase);
+ }
+
+ mDLInBufferQ[0]->time_stamp_process = tstamp_process;
+#if 1//def DOWNLINK_MONO
+ //*(mpSPEBufferDL + indexIn) = (*(mDLInBufferQ[0]->pRead)>>1) + (*(mDLInBufferQ[0]->pRead+1)>>1); //only mono data
+ *(mpSPEBufferDL + indexIn) = *(mDLInBufferQ[0]->pRead); //already mono data
+ mDLInBufferQ[0]->pRead++;
+ mDLInBufQLenTotal -= 2; //int and short transform
+ mDLInBufferQ[0]->BufLen -= 2; //record the buffer you consumed
+
+
+ mDLInBufferQ[0]->time_stamp_estimate.tv_sec = mDLInBufferQ[0]->time_stamp_estimate.tv_sec + (mDLInBufferQ[0]->time_stamp_estimate.tv_nsec + mNsecPerSample) / 1000000000;
+ mDLInBufferQ[0]->time_stamp_estimate.tv_nsec = (mDLInBufferQ[0]->time_stamp_estimate.tv_nsec + mNsecPerSample) % 1000000000;
+ DLtstamp_compen = mDLInBufferQ[0]->time_stamp_estimate;
+
+ //check to remove the first DL buffer to avoid compare the wrong estimate time next time if the buffer is compensated buffer
+ if (mDLInBufferQ[0]->BufLen <= 0) { //run out of DL queue0 buffer
+ //not to free the buffer here due to the data still queue in the DLDelay buffer
+ mDLInBufferQ.removeAt(0);
+ }
+#else
+ *(mpSPEBufferDL + indexIn) = (*(mDLInBufferQ[0]->pRead) >> 1) + (*(mDLInBufferQ[0]->pRead + 1) >> 1); //only mono data
+ mDLInBufferQ[0]->pRead += 2;
+ mDLInBufQLenTotal -= 4; //int and short transform
+ mDLInBufferQ[0]->BufLen -= 4; //record the buffer you consumed
+#endif
+
+ //fill in delay latency data
+ if (mDLDelayBufferQ[0]->BufLen4Delay <= 0) { //run out of DL delay queue0 buffer
+ //ALOGD("DL delay consume");
+ free(mDLDelayBufferQ[0]->pBufBase);
+ delete mDLDelayBufferQ[0];
+ mDLDelayBufferQ.removeAt(0);
+ if (mDLDelayBufferQ.isEmpty()) {
+ ALOGD("no DL delay buffer, should already compensate something wrong");
+ mError = true;
+ break;
+ }
+ // ALOGD("DL delay in buffer consume finish, next BufferBase=%p, size=%d",mDLDelayBufferQ[0]->pBufBase,mDLDelayBufferQ.size());
+ }
+ mDLDelayBufferQ[0]->time_stamp_process = tstamp_process;
+#if 1//def DOWNLINK_MONO
+ //*(mpSPEBufferDLDelay + indexIn) = (*(mDLDelayBufferQ[0]->pRead4Delay)>>1) + (*(mDLDelayBufferQ[0]->pRead4Delay+1)>>1); //only mono data
+ *(mpSPEBufferDLDelay + indexIn) = *(mDLDelayBufferQ[0]->pRead4Delay); //already mono data
+ mDLDelayBufferQ[0]->pRead4Delay++;
+ mDLDelayBufQLenTotal -= 2; //int and short transform
+ mDLDelayBufferQ[0]->BufLen4Delay -= 2; //record the buffer you consumed
+ //ALOGD("%d,%d",*(mULInBufferQ[0]->pRead),*(mULInBufferQ[0]->pRead +1));
+#else
+ *(mpSPEBufferDLDelay + indexIn) = (*(mDLDelayBufferQ[0]->pRead4Delay) >> 1) + (*(mDLDelayBufferQ[0]->pRead4Delay + 1) >> 1); //only mono data
+ mDLDelayBufferQ[0]->pRead4Delay += 2;
+ mDLDelayBufQLenTotal -= 4; //int and short transform
+ mDLDelayBufferQ[0]->BufLen4Delay -= 4; //record the buffer you consumed
+#endif
+
+ if (mDLDelayBufferQ[0]->BufLen4Delay <= 0) { //run out of DL delay queue0 buffer
+ free(mDLDelayBufferQ[0]->pBufBase);
+ delete mDLDelayBufferQ[0];
+ mDLDelayBufferQ.removeAt(0);
+ }
+
+ ULIncopysize--;
+ indexIn++;
+ tmpSPEProcessBufSize -= 4;
+
+ } else { //consume all the data in first queue buffer
+ free(mULInBufferQ[0]->pBufBase);
+ delete mULInBufferQ[0];
+ mULInBufferQ.removeAt(0);
+ ULIncopysize = mULInBufferQ[0]->BufLen >> 2;
+ //ALOGD("UL in buffer consume finish, next BufferBase=%p, size=%d,mULInBufQLenTotal=%d",mULInBufferQ[0]->pBufBase,mULInBufferQ.size(),mULInBufQLenTotal);
+ }
+ }
+
+ if (mError) {
+ ALOGE("error happened!!");
+ break;
+ }
+
+ //after fill buffer, process
+ mSphEnhOps.ENH_API_Process(&mSph_Enh_ctrl);
+
+ Dump_EPL(&mSph_Enh_ctrl.EPL_buffer, EPLBufSize * sizeof(short));
+ EPLTransVMDump();
+
+ //record to the outputbuffer queue, no need processed downlink data
+
+ //BufferInfo *newDLOutBuffer = new BufferInfo;
+ BufferInfo *newULOutBuffer = new BufferInfo;
+
+ //newDLOutBuffer->pBufBase = (short*) malloc(mSPEProcessBufSize/2);
+ //newDLOutBuffer->BufLen= mSPEProcessBufSize/2;
+
+ //newDLOutBuffer->pRead = newDLOutBuffer->pBufBase;
+ //newDLOutBuffer->pWrite= newDLOutBuffer->pBufBase;
+
+ newULOutBuffer->pBufBase = (short *) malloc(mSPEProcessBufSize);
+ ASSERT(newULOutBuffer->pBufBase != NULL);
+ newULOutBuffer->BufLen = mSPEProcessBufSize;
+
+ newULOutBuffer->pRead = newULOutBuffer->pBufBase;
+ newULOutBuffer->pWrite = newULOutBuffer->pBufBase;
+ // ALOGD("newDLOutBuffer->pBufBase=%p,newDLOutBuffer->pRead=%p,newDLOutBuffer->pWrite=%p,newDLOutBuffer->BufLen=%d",newDLOutBuffer->pBufBase,newDLOutBuffer->pRead,newDLOutBuffer->pWrite,newDLOutBuffer->BufLen);
+ int indexOut = 0;
+
+ int copysizetest = newULOutBuffer->BufLen >> 2;
+ while (copysizetest) {
+ //ALOGD("newOutBuffer->pWrite=%p, indexOut=%d,copysizetest=%d",newOutBuffer->pWrite,indexOut,copysizetest);
+ //*(newDLOutBuffer->pWrite) = *(mpSPEBufferFE + indexOut);
+ //*(newDLOutBuffer->pWrite+1) = *(mpSPEBufferFE + indexOut);
+
+ *(newULOutBuffer->pWrite) = *(mpSPEBufferNE + indexOut);
+ *(newULOutBuffer->pWrite + 1) = *(mpSPEBufferNE + indexOut);
+
+ // ALOGD("indexOut=%d,mpSPEBufferFE =%d, mpSPEBufferNE=%d",indexOut,*(mpSPEBufferFE + indexOut),*(mpSPEBufferNE + indexOut));
+ //newDLOutBuffer->pWrite+=2;
+ newULOutBuffer->pWrite += 2;
+ indexOut++;
+ copysizetest--;
+ }
+
+ //mDLOutBufferQ.add(newDLOutBuffer);
+ //mDLOutBufQLenTotal += newDLOutBuffer->BufLen;
+ // ALOGD("queue to DLOut mDLOutBufQLenTotal=%d, size=%d",mDLOutBufQLenTotal,mDLOutBufferQ.size());
+ //Dump_PCM_Process(DOWNLINK,newDLOutBuffer->pBufBase,newDLOutBuffer->BufLen);
+ mULOutBufferQ.add(newULOutBuffer);
+ mULOutBufQLenTotal += newULOutBuffer->BufLen;
+ // Dump_PCM_Process(UPLINK,newULOutBuffer->pBufBase,newULOutBuffer->BufLen);
+ }
+ // ALOGD("return SPELayer::Process, mDLInBufferQ size=%d,mDLInBufQLenTotal=%d,mDLInBufferQ[0]->BufLen=%d",mDLInBufferQ.size(),mDLInBufQLenTotal,mDLInBufferQ[0]->BufLen);
+
+ } else { //not enough UL data, not process
+ ALOGD("not enough uplink data, not process");
+ }
+
+ //process the uplink output processed buffer queue
+ memset(inBuf, 0, inBufLength); //clean the buffer will be used
+#if 1
+ if (mULOutBufferQ.isEmpty()) //fixme, return data we have?
+#else
+ if (mULOutBufferQ.isEmpty() || mULOutBufQLenTotal < inBufLength) //fixme, return data we have?
+#endif
+ {
+ ALOGD("SPELayer not enought UL output buffer return size");
+ //AL_UNLOCK(mBufMutex);
+ //return true;
+ retSize = 0;
+ return retSize; //return the processed buffer size
+ } else {
+ int tmpInBufLength = inBufLength;
+ if (mULOutBufQLenTotal < inBufLength) {
+ ALOGD("Process_VoIP mULOutBufQLenTotal<inBufLength");
+ tmpInBufLength = mULOutBufQLenTotal;
+ retSize = mULOutBufQLenTotal;
+ }
+ int count = 0;
+ int tempULCopy = mULOutBufferQ[0]->BufLen >> 2;
+ while (tmpInBufLength) {
+ if (mULOutBufferQ.isEmpty()) {
+ ALOGD("Process_VoIP run out of output buffer queue");
+ break;
+ }
+
+ // ALOGD("mULOutBufferQ.size = %d,tempULCopy=%d",mULOutBufferQ.size(),tempULCopy);
+
+ if (tempULCopy > 0) { //get the buffer data from the first uplink input buffer queue
+ // ALOGD("mULOutBufferQ[0]->pRead = %p,mULOutBufferQ[0]->pBufBase=%p,mULOutBufferQ[0]->BufLen=%d",mULOutBufferQ[0]->pRead,mULOutBufferQ[0]->pBufBase,mULOutBufferQ[0]->BufLen);
+ // ALOGD("tmpInBufLength=%d,count=%d,mULOutBufQLenTotal=%d,tempULCopy=%d",tmpInBufLength,count,mULOutBufQLenTotal,tempULCopy);
+ *(inBuf + count) = *(mULOutBufferQ[0]->pRead);
+ *(inBuf + count + 1) = *(mULOutBufferQ[0]->pRead + 1);
+ mULOutBufferQ[0]->pRead += 2;
+ tmpInBufLength -= 4; //int and short transform
+ tempULCopy--;
+ count += 2;
+ mULOutBufQLenTotal -= 4; //int and short transform
+ mULOutBufferQ[0]->BufLen -= 4;
+ } else { //consume all the data in first queue buffer
+ free(mULOutBufferQ[0]->pBufBase);
+ delete mULOutBufferQ[0];
+ mULOutBufferQ.removeAt(0);
+ if (!mULOutBufferQ.isEmpty()) {
+ //ALOGD("Process_VoIP mULOutBufferQ not empty, get next one 2, size=%d",mULOutBufferQ.size());
+ tempULCopy = mULOutBufferQ[0]->BufLen >> 2;
+ } else {
+ ALOGD("Process_VoIP mULOutBufferQ empty no more data 2, size=%zu", mULOutBufferQ.size());
+ }
+ // ALOGD("SPELayer::uplink Output buffer consumed");
+ }
+ }
+ }
+
+ //AL_UNLOCK(mBufMutex);
+ //return true;
+ return retSize;
+}
+
+//normal record + VoIP, new interface
+int SPELayer::Process(InBufferInfo *InBufinfo) {
+ if (mError == true) {
+ ReStart();
+ mError = false;
+ }
+ Mutex::Autolock lock(mLock);
+ //ALOGD("SPELayer::Process going to take mBufMutex new interface");
+ mBufMutexWantLock.lock();
+ AL_LOCK(mBufMutex);
+ mBufMutexWantLock.unlock();
+ if (mState == SPE_STATE_IDLE) {
+ ALOGD("%s, wrong state, mState=%d,mMode=%d", __FUNCTION__, mState, mMode);
+ AL_UNLOCK(mBufMutex);
+ return false;
+ }
+ // if(mMode == SPE_MODE_REC)
+ {
+ if ((mULInBufferQ.size() > 20) || (mULOutBufferQ.size() > 20)) {
+ ALOGD("no service? mULInBufferQ.size=%zu, mULOutBufferQ.size=%zu", mULInBufferQ.size(), mULOutBufferQ.size());
+ }
+ }
+ mState = SPE_STATE_RUNNING;
+
+ AddtoInputBuffer(UPLINK, InBufinfo);
+ //AddUplinkBuffer(InBufinfo);
+
+ int inBufLength = InBufinfo->BufLen;
+ short *inBuf = InBufinfo->pBufBase;
+ int retSize = inBufLength;
+
+ //process the input buffer queue
+ if (mMode == SPE_MODE_REC) { //record
+ mVoIPRunningbefore = false;
+ retSize = Process_Record(inBuf, inBufLength);
+ } else { //VoIP
+ mVoIPRunningbefore = true;
+ Process_VoIP(inBuf, inBufLength);
+ }
+
+ Dump_PCM_Out(UPLINK, inBuf, retSize);
+
+ if (mPrepareProcessDataReady && (mDLInBufQLenTotal > (inBufLength * 10))) { //if there has too many echoref data, it means the uplink data may not get continuously. Might have buffer overflow in kernel. (uplink data is stereo\echoref data is mono)
+ //need to resync
+ ReSync();
+ ALOGD("%s, uplink data might uncontinuous, resync", __FUNCTION__);
+ }
+
+ AL_UNLOCK(mBufMutex);
+ //ALOGD("%s, inBufLength=%d,retSize=%d", __FUNCTION__, inBufLength, retSize);
+ return retSize;
+
+}
+
+bool SPELayer::Stop() {
+ ALOGD("%s", __FUNCTION__);
+ Mutex::Autolock lock(mLock);
+ AL_LOCK(mBufMutex);
+ if (mState == SPE_STATE_IDLE) {
+ ALOGD("not start before");
+ AL_UNLOCK(mBufMutex);
+ return false;
+ }
+ mState = SPE_STATE_CLEANING;
+ Clear();
+ AL_UNLOCK(mBufMutex);
+ return true;
+}
+
+
+void SPELayer::ReStart() {
+ ALOGD("%s, State=%d, mode=%d", __FUNCTION__, mState, mMode);
+ Stop();
+ Start(mMode);
+}
+
+void SPELayer::Clear() {
+ ALOGD("%s", __FUNCTION__);
+ //pthread_mutex_lock(&mBufMutex );
+ if (mSphCtrlBuffer) {
+ ALOGD("free mSphCtrlBuffer %p", mSphCtrlBuffer);
+ mSphEnhOps.ENH_API_Free(&mSph_Enh_ctrl);
+ free(mSphCtrlBuffer);
+ mSphCtrlBuffer = NULL;
+ ALOGD("~free mSphCtrlBuffer");
+ }
+
+ mpSPEBufferUL1 = NULL;
+ mpSPEBufferUL2 = NULL;
+ mpSPEBufferDL = NULL;
+ mpSPEBufferDLDelay = NULL;
+
+ mNeedDelayLatency = false;
+ mNeedJitterBuffer = false;
+ mCompensatedBufferSize = 0;
+
+#if 0
+ //clear the buffer queue
+
+ ALOGD("SPELayer::mULOutBufferQ size=%d,mULInBufferQ.size=%d,mDLOutBufferQ.size()=%d,mDLInBufferQ.size()=%d,mDLDelayBufferQ.size()=%d", mULOutBufferQ.size(), mULInBufferQ.size(), mDLOutBufferQ.size(),
+ mDLInBufferQ.size(), mDLDelayBufferQ.size());
+ if (mULOutBufferQ.size() != 0) {
+ while (mULOutBufferQ.size()) {
+ free(mULOutBufferQ[0]->pBufBase);
+ delete mULOutBufferQ[0];
+ mULOutBufferQ.removeAt(0);
+ }
+ mULOutBufferQ.clear();
+ }
+ if (mULInBufferQ.size() != 0) {
+ while (mULInBufferQ.size()) {
+ free(mULInBufferQ[0]->pBufBase);
+ delete mULInBufferQ[0];
+ mULInBufferQ.removeAt(0);
+ }
+ mULInBufferQ.clear();
+ }
+
+ if (mDLOutBufferQ.size() != 0) {
+ while (mDLOutBufferQ.size()) {
+ free(mDLOutBufferQ[0]->pBufBase);
+ delete mDLOutBufferQ[0];
+ mDLOutBufferQ.removeAt(0);
+ }
+ mDLOutBufferQ.clear();
+ }
+ if (mDLInBufferQ.size() != 0) {
+ while (mDLInBufferQ.size()) {
+ if (mDLInBufferQ[0]->pBufBase) {
+ ALOGD("mDLInBufferQ::pBufBase=%d", mDLInBufferQ[0]->pBufBase);
+ // free(mDLInBufferQ[0]->pBufBase);
+ ALOGD("mDLInBufferQ::free");
+ // delete mDLInBufferQ[0];
+ ALOGD("mDLInBufferQ::delete");
+ mDLInBufferQ.removeAt(0);
+ ALOGD("mDLInBufferQ::done, free at DLDelay buffer");
+ }
+ }
+ mDLInBufferQ.clear();
+ }
+
+ if (mDLDelayBufferQ.size() != 0) {
+ while (mDLDelayBufferQ.size()) {
+ if (mDLDelayBufferQ[0]->pBufBase) {
+ ALOGD("mDLDelayBufferQ::pBufBase=%d", mDLDelayBufferQ[0]->pBufBase);
+ free(mDLDelayBufferQ[0]->pBufBase);
+ ALOGD("mDLDelayBufferQ::free");
+ delete mDLDelayBufferQ[0];
+ ALOGD("mDLDelayBufferQ::delete");
+ mDLDelayBufferQ.removeAt(0);
+ ALOGD("mDLDelayBufferQ::done");
+ }
+
+ }
+ mDLDelayBufferQ.clear();
+ }
+
+ mULInBufQLenTotal = 0;
+ mDLInBufQLenTotal = 0;
+ mULOutBufQLenTotal = 0;
+ mDLOutBufQLenTotal = 0;
+ mDLDelayBufQLenTotal = 0;
+ mCompensatedBufferSize = 0;
+#endif
+ mState = SPE_STATE_IDLE;
+
+ ALOGD("~Clear");
+ //AL_UNLOCK(mBufMutex);
+}
+
+bool SPELayer::Standby() {
+ ALOGD("%s+", __FUNCTION__);
+ bool bRet = true;
+
+ Mutex::Autolock lock(mLock);
+ AL_LOCK(mBufMutex);
+
+ mState = SPE_STATE_CLEANING;
+ Clear();
+
+ mMode = SPE_MODE_NONE;
+ mRoute = ROUTE_NONE;
+
+ mError = false;
+
+ FlushBufferQ();
+
+ mFirstVoIPUplink = true;
+ mFirstVoIPDownlink = true;
+ mDLNewStart = false;
+ mPrepareProcessDataReady = false;
+ mDLPreQLimit = true;
+
+ mVoIPRunningbefore = false;
+ DLdataPrepareCount = 0;
+ mOutputStreamRunning = false;
+
+ mLatencyDir = true;
+ mNeedJitterBuffer = false;
+ mNormalModeVoIP = false;
+ mPreULBufLen = 0;
+ mPreDLBufLen = 0;
+
+ memset(&mUplinkIntrStartTime, 0, sizeof(timespec));
+ memset(&mPreUplinkEstTime, 0, sizeof(timespec));
+
+ // memset(&mDownlinkIntrStartTime, 0, sizeof(timespec));
+ // memset(&mPreDownlinkEstTime, 0, sizeof(timespec));
+ // memset(&mPreDownlinkQueueTime, 0, sizeof(timespec));
+
+ AL_UNLOCK(mBufMutex);
+ ALOGD("%s-", __FUNCTION__);
+ return bRet;
+}
+
+
+void SPELayer::ReSync() {
+ if (mPrepareProcessDataReady) {
+ ALOGD("%s", __FUNCTION__);
+ //ASSERT(0);
+ mPrepareProcessDataReady = false;
+ mCompensatedBufferSize = 0;
+ }
+}
+
+void SPELayer::dump() {
+ ALOGD("%s, State=%d, mode=%d", __FUNCTION__, mState, mMode);
+ //dump normal record parameters
+ ALOGD("Record:Samplerate = %d, FrameRate=%d,App_table=%x, Fea_Cfg_table=%x", mRecordSampleRate, mRecordFrameRate, mRecordApp_table, mRecordFea_Cfg_table);
+ ALOGD("Record:EnhanceParas");
+ for (int i = 0; i < (EnhanceParasNum / 7); i++) {
+ ALOGD("[index %d] %d,%d,%d,%d,%d,%d,%d", i, mRecordEnhanceParas[i * 7], mRecordEnhanceParas[i * 7 + 1], mRecordEnhanceParas[i * 7 + 2],
+ mRecordEnhanceParas[i * 7 + 3], mRecordEnhanceParas[i * 7 + 4], mRecordEnhanceParas[i * 7 + 5], mRecordEnhanceParas[i * 7 + 6]);
+ }
+
+ /* ALOGD("Record:DMNRCalData");
+ for(int i=0; i<DMNRCalDataNum; i++)
+ ALOGD("%d",mRecordDMNRCalData[i]);
+ ALOGD("Record:CompenFilter");
+ for(int i=0; i<CompenFilterNum; i++)
+ ALOGD("%d",mRecordCompenFilter[i]);
+
+
+ //dump VoIP parameters
+ ALOGD("VoIP:Samplerate = %d, FrameRate=%d,PGAGain=%d, App_table=%x, Fea_Cfg_table=%x",mVoIPSampleRate,mVoIPFrameRate,mVoIPPGAGain,mVoIPApp_table,mVoIPFea_Cfg_table);
+ ALOGD("VoIP:EnhanceParas");
+ for(int i=0; i<EnhanceParasNum; i++)
+ ALOGD("%d",mVoIPEnhanceParas[i]);
+ ALOGD("VoIP:DMNRCalData");
+ for(int i=0; i<DMNRCalDataNum; i++)
+ ALOGD("%d",mVoIPDMNRCalData[i]);
+ ALOGD("VoIP:CompenFilter");
+ for(int i=0; i<CompenFilterNum; i++)
+ ALOGD("%d",mVoIPCompenFilter[i]);
+ */
+ //dump using parameters
+ ALOGD("Using:Samplerate = %d, FrameRate=%d,MIC_DG=%d, App_table=%x, Fea_Cfg_table=%x, MMI_table=%x, Device_mode=%x, MMI_MIC_GAIN=%d",
+ mSph_Enh_ctrl.sample_rate, mSph_Enh_ctrl.frame_rate, mSph_Enh_ctrl.MIC_DG, mSph_Enh_ctrl.App_table, mSph_Enh_ctrl.Fea_Cfg_table, mSph_Enh_ctrl.MMI_ctrl,
+ mSph_Enh_ctrl.Device_mode, mSph_Enh_ctrl.MMI_MIC_GAIN);
+ ALOGD("Using:EnhanceParas");
+ for (int i = 0; i < (EnhanceParasNum / 7); i++)
+ ALOGD("[index %d] %d,%d,%d,%d,%d,%d,%d", i, mSph_Enh_ctrl.enhance_pars[i * 7], mSph_Enh_ctrl.enhance_pars[i * 7 + 1], mSph_Enh_ctrl.enhance_pars[i * 7 + 2]
+ , mSph_Enh_ctrl.enhance_pars[i * 7 + 3], mSph_Enh_ctrl.enhance_pars[i * 7 + 4], mSph_Enh_ctrl.enhance_pars[i * 7 + 5], mSph_Enh_ctrl.enhance_pars[i * 7 + 6]);
+
+ ALOGD("Using:DMNRCalData");
+ for (int i = 0; i < (DMNRCalDataNum / 19); i++)
+ ALOGD("[index %d] %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+ i, mSph_Enh_ctrl.DMNR_cal_data[i * 19], mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 1], mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 2]
+ , mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 3], mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 4], mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 5], mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 6]
+ , mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 7], mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 8], mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 9], mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 10]
+ , mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 11], mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 12], mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 13], mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 14]
+ , mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 15], mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 16], mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 17], mSph_Enh_ctrl.DMNR_cal_data[i * 19 + 18]);
+
+ /* ALOGD("Using:CompenFilter");
+ for(int i=0; i<CompenFilterNum; i++)
+ ALOGD("%d",mSph_Enh_ctrl.Compen_filter[i]);
+ */
+}
+
+static int checkAndCreateDirectory(const char *pC) {
+ char tmp[PATH_MAX];
+ int i = 0;
+
+ while (*pC) {
+ tmp[i] = *pC;
+
+ if (*pC == '/' && i) {
+ tmp[i] = '\0';
+ if (access(tmp, F_OK) != 0) {
+ if (mkdir(tmp, 0770) == -1) {
+ ALOGE("AudioDumpPCM: mkdir error! %s\n", (char *)strerror(errno));
+ return -1;
+ }
+ }
+ tmp[i] = '/';
+ }
+ i++;
+ pC++;
+ }
+ return 0;
+
+}
+
+bool SPELayer::HasBufferDump() {
+ DumpMutexLock();
+ bool bret = true;
+ if (mDumpDLInBufferQ.size() == 0 && mDumpDLOutBufferQ.size() == 0 && mDumpULInBufferQ.size() == 0 && mDumpULOutBufferQ.size() == 0
+ && mDumpEPLBufferQ.size() == 0) {
+ bret = false;
+ }
+
+ DumpMutexUnlock();
+ return bret;
+}
+
+void SPELayer::DumpBufferClear(void) {
+ DumpMutexLock();
+ ALOGD("DumpBufferClear, %zu %zu %zu %zu %zu", mDumpDLInBufferQ.size(), mDumpDLOutBufferQ.size(), mDumpULInBufferQ.size(), mDumpULOutBufferQ.size(), mDumpEPLBufferQ.size());
+ if (mDumpDLInBufferQ.size() != 0) {
+ while (mDumpDLInBufferQ.size()) {
+ free(mDumpDLInBufferQ[0]->pBufBase);
+ delete mDumpDLInBufferQ[0];
+ mDumpDLInBufferQ.removeAt(0);
+ }
+ mDumpDLInBufferQ.clear();
+ }
+
+ if (mDumpDLOutBufferQ.size() != 0) {
+ while (mDumpDLOutBufferQ.size()) {
+ free(mDumpDLOutBufferQ[0]->pBufBase);
+ delete mDumpDLOutBufferQ[0];
+ mDumpDLOutBufferQ.removeAt(0);
+ }
+ mDumpDLOutBufferQ.clear();
+ }
+
+ if (mDumpULInBufferQ.size() != 0) {
+ while (mDumpULInBufferQ.size()) {
+ free(mDumpULInBufferQ[0]->pBufBase);
+ delete mDumpULInBufferQ[0];
+ mDumpULInBufferQ.removeAt(0);
+ }
+ mDumpULInBufferQ.clear();
+ }
+
+ if (mDumpULOutBufferQ.size() != 0) {
+ while (mDumpULOutBufferQ.size()) {
+ free(mDumpULOutBufferQ[0]->pBufBase);
+ delete mDumpULOutBufferQ[0];
+ mDumpULOutBufferQ.removeAt(0);
+ }
+ mDumpULOutBufferQ.clear();
+ }
+
+ if (mDumpEPLBufferQ.size() != 0) {
+ while (mDumpEPLBufferQ.size()) {
+ free(mDumpEPLBufferQ[0]->pBufBase);
+ delete mDumpEPLBufferQ[0];
+ mDumpEPLBufferQ.removeAt(0);
+ }
+ mDumpEPLBufferQ.clear();
+ }
+ DumpMutexUnlock();
+ ALOGD("DumpBufferClear---");
+}
+
+void *DumpThread(void *arg) {
+ SPELayer *pSPEL = (SPELayer *)arg;
+ ALOGD("DumpThread");
+ struct timespec timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 10 * 1000000;
+ AL_LOCK(pSPEL->mDumpExitMutex);
+
+ while (1) {
+ if (pSPEL->hDumpThread == 0) {
+ ALOGD("DumpThread hDumpThread null");
+ //pSPEL->DumpBufferClear();
+ break;
+#if 0
+ if (!pSPEL->HasBufferDump()) {
+ pSPEL->DumpMutexLock();
+ pSPEL->mDumpDLInBufferQ.clear();
+ pSPEL->mDumpDLOutBufferQ.clear();
+ pSPEL->mDumpULInBufferQ.clear();
+ pSPEL->mDumpULOutBufferQ.clear();
+ pSPEL->mDumpEPLBufferQ.clear();
+ pSPEL->DumpMutexUnlock();
+ ALOGD("DumpThread exit");
+ break;
+ } else {
+ ALOGD("DumpThread still has buffer need consume");
+ }
+#endif
+ }
+ if (!pSPEL->HasBufferDump()) {
+ AL_UNLOCK(pSPEL->mDumpExitMutex);
+ AL_SIGNAL(pSPEL->mDumpExitMutex);
+ usleep(3 * 1000);
+ AL_LOCK(pSPEL->mDumpExitMutex);
+ continue;
+ }
+ //ALOGD( "DumpThread,mDumpULInBufferQ=%d, mDumpULOutBufferQ=%d, mDumpEPLBufferQ=%d",pSPEL->mDumpULInBufferQ.size(),pSPEL->mDumpULOutBufferQ.size(),pSPEL->mDumpEPLBufferQ.size());
+ if (pSPEL->mDumpDLInBufferQ.size() > 0) {
+ fwrite(pSPEL->mDumpDLInBufferQ[0]->pBufBase, pSPEL->mDumpDLInBufferQ[0]->BufLen, 1, pSPEL->mfpInDL);
+ pSPEL->DumpMutexLock();
+ if (pSPEL->hDumpThread != 0) {
+ free(pSPEL->mDumpDLInBufferQ[0]->pBufBase);
+ delete pSPEL->mDumpDLInBufferQ[0];
+ pSPEL->mDumpDLInBufferQ.removeAt(0);
+ }
+ pSPEL->DumpMutexUnlock();
+ }
+
+ if (pSPEL->mDumpDLOutBufferQ.size() > 0) {
+ fwrite(pSPEL->mDumpDLOutBufferQ[0]->pBufBase, pSPEL->mDumpDLOutBufferQ[0]->BufLen, 1, pSPEL->mfpOutDL);
+ pSPEL->DumpMutexLock();
+ if (pSPEL->hDumpThread != 0) {
+ free(pSPEL->mDumpDLOutBufferQ[0]->pBufBase);
+ delete pSPEL->mDumpDLOutBufferQ[0];
+ pSPEL->mDumpDLOutBufferQ.removeAt(0);
+ }
+ pSPEL->DumpMutexUnlock();
+ }
+
+ if (pSPEL->mDumpULInBufferQ.size() > 0) {
+ fwrite(pSPEL->mDumpULInBufferQ[0]->pBufBase, pSPEL->mDumpULInBufferQ[0]->BufLen, 1, pSPEL->mfpInUL);
+ pSPEL->DumpMutexLock();
+ if (pSPEL->hDumpThread != 0) {
+ free(pSPEL->mDumpULInBufferQ[0]->pBufBase);
+ delete pSPEL->mDumpULInBufferQ[0];
+ pSPEL->mDumpULInBufferQ.removeAt(0);
+ }
+ pSPEL->DumpMutexUnlock();
+ }
+
+ if (pSPEL->mDumpULOutBufferQ.size() > 0) {
+ fwrite(pSPEL->mDumpULOutBufferQ[0]->pBufBase, pSPEL->mDumpULOutBufferQ[0]->BufLen, 1, pSPEL->mfpOutUL);
+ pSPEL->DumpMutexLock();
+ if (pSPEL->hDumpThread != 0) {
+ free(pSPEL->mDumpULOutBufferQ[0]->pBufBase);
+ delete pSPEL->mDumpULOutBufferQ[0];
+ pSPEL->mDumpULOutBufferQ.removeAt(0);
+ }
+ pSPEL->DumpMutexUnlock();
+ }
+
+ if (pSPEL->mDumpEPLBufferQ.size() > 0) {
+ fwrite(pSPEL->mDumpEPLBufferQ[0]->pBufBase, pSPEL->mDumpEPLBufferQ[0]->BufLen, 1, pSPEL->mfpEPL);
+ pSPEL->DumpMutexLock();
+ // ALOGD("DumpThread %p, %p",pSPEL->mDumpEPLBufferQ[0],pSPEL->mDumpEPLBufferQ[0]->pBufBase);
+ if (pSPEL->hDumpThread != 0) {
+ free(pSPEL->mDumpEPLBufferQ[0]->pBufBase);
+ delete pSPEL->mDumpEPLBufferQ[0];
+ pSPEL->mDumpEPLBufferQ.removeAt(0);
+ }
+ pSPEL->DumpMutexUnlock();
+ }
+ }
+ AL_UNLOCK(pSPEL->mDumpExitMutex);
+ AL_SIGNAL(pSPEL->mDumpExitMutex);
+ ALOGD("DumpThread exit!!");
+ pthread_exit(NULL);
+ return 0;
+}
+
+bool SPELayer::CreateDumpThread() {
+#if defined(PC_EMULATION)
+ hDumpThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)DumpThread, this, 0, 0);
+ if (hDumpThread == 0) { return false; }
+ return true;
+#else
+ //create PCM data dump thread here
+ int ret;
+ ret = pthread_create(&hDumpThread, NULL, DumpThread, (void *)this);
+ if (ret != 0) { return false; }
+
+ ALOGD("-CreateDumpThread \n");
+ return true;
+#endif
+
+}
+
+void SPELayer::Dump_Enalbe_Check(void) {
+ int ret;
+ char Buf[10];
+ snprintf(Buf, sizeof(Buf), "%d.pcm", DumpFileNum);
+ char value[PROPERTY_VALUE_MAX];
+ char value1[PROPERTY_VALUE_MAX];
+
+ //Dump_PCM_In check
+ property_get("vendor.SPEIn.pcm.dump", value, "0");
+ int bflag = atoi(value);
+ if (bflag) {
+ if (hDumpThread == 0) {
+ CreateDumpThread();
+ }
+
+ //uplink
+ String8 DumpFileNameUpIn;
+ DumpFileNameUpIn.appendFormat("%s%s%s", audio_dump_path, "SPEIn_Uplink", Buf);
+ ret = checkAndCreateDirectory(DumpFileNameUpIn);
+ if (ret < 0) {
+ ALOGE("SPELayer::Dump_PCM_In UPLINK checkAndCreateDirectory() fail!!!");
+ } else {
+ if (mfpInUL == NULL) {
+ mfpInUL = fopen(DumpFileNameUpIn, "ab+");
+ if (mfpInUL == NULL) {
+ ALOGD("open SPEIn_Uplink.pcm fail");
+ } else {
+ ALOGD("open SPEIn_Uplink.pcm");
+ }
+ }
+ }
+
+ //downlink
+ String8 DumpFileNameDownIn;
+ DumpFileNameDownIn.appendFormat("%s%s%s", audio_dump_path, "SPEIn_Downlink", Buf);
+ ret = checkAndCreateDirectory(DumpFileNameDownIn);
+ if (ret < 0) {
+ ALOGE("SPELayer::Dump_PCM_In DOWNLINK checkAndCreateDirectory() fail!!!");
+ } else {
+ if (mfpInDL == NULL) {
+ mfpInDL = fopen(DumpFileNameDownIn, "ab+");
+ if (mfpInDL == NULL) {
+ ALOGD("open SPEIn_Downlink.pcm fail");
+ } else {
+ ALOGD("open SPEIn_Downlink.pcm");
+ }
+ }
+ }
+ }
+
+ //Dump_PCM_Process check
+ property_get("vendor.SPE.pcm.dump", value, "0");
+ bflag = atoi(value);
+ if (bflag) {
+ //if(hDumpThread == NULL)
+ //CreateDumpThread();
+
+ //uplink
+ String8 DumpFileNameUpPro;
+ DumpFileNameUpPro.appendFormat("%s%s%s", audio_dump_path, "SPE_Uplink", Buf);
+ ret = checkAndCreateDirectory(DumpFileNameUpPro);
+ if (ret < 0) {
+ ALOGE("SPELayer::Dump_PCM_Process UPLINK checkAndCreateDirectory() fail!!!");
+ } else {
+ if (mfpProcessedUL == NULL) {
+ mfpProcessedUL = fopen(DumpFileNameUpPro, "ab+");
+ if (mfpProcessedUL == NULL) {
+ ALOGD("open SPE_Uplink.pcm fail");
+ } else {
+ ALOGD("open SPE_Uplink.pcm");
+ }
+ }
+ }
+
+ //downlink
+ String8 DumpFileNameDownPro;
+ DumpFileNameDownPro.appendFormat("%s%s%s", audio_dump_path, "SPE_Downlink", Buf);
+ ret = checkAndCreateDirectory(DumpFileNameDownPro);
+ if (ret < 0) {
+ ALOGE("SPELayer::Dump_PCM_Process DOWNLINK checkAndCreateDirectory() fail!!!");
+ } else {
+ if (mfpProcessedDL == NULL) {
+ mfpProcessedDL = fopen(DumpFileNameDownPro, "ab+");
+ if (mfpProcessedDL == NULL) {
+ ALOGD("open SPE_Downlink.pcm fail");
+ } else {
+ ALOGD("open SPE_Downlink.pcm");
+ }
+ }
+ }
+ }
+
+ //Dump_PCM_Out check
+ property_get("vendor.SPEOut.pcm.dump", value, "0");
+ bflag = atoi(value);
+ if (bflag) {
+ if (hDumpThread == 0) {
+ CreateDumpThread();
+ }
+
+ //uplink
+ String8 DumpFileNameUpOut;
+ DumpFileNameUpOut.appendFormat("%s%s%s", audio_dump_path, "SPEOut_Uplink", Buf);
+ ret = checkAndCreateDirectory(DumpFileNameUpOut);
+ if (ret < 0) {
+ ALOGE("SPELayer::Dump_PCM_Out UPLINK checkAndCreateDirectory() fail!!!");
+ } else {
+ if (mfpOutUL == NULL) {
+ mfpOutUL = fopen(DumpFileNameUpOut, "ab+");
+ if (mfpOutUL == NULL) {
+ ALOGD("open SPEOut_Uplink.pcm fail");
+ } else {
+ ALOGD("open SPEOut_Uplink.pcm");
+ }
+ }
+ }
+
+ //downlink
+ String8 DumpFileNameDownOut;
+ DumpFileNameDownOut.appendFormat("%s%s%s", audio_dump_path, "SPEOut_Downlink", Buf);
+ ret = checkAndCreateDirectory(DumpFileNameDownOut);
+ if (ret < 0) {
+ ALOGE("SPELayer::Dump_PCM_Out DOWNLINK checkAndCreateDirectory() fail!!!");
+ } else {
+ if (mfpOutDL == NULL) {
+ mfpOutDL = fopen(DumpFileNameDownOut, "ab+");
+ if (mfpOutDL == NULL) {
+ ALOGD("open SPEOut_Downlink.pcm fail");
+ } else {
+ ALOGD("open SPEOut_Downlink.pcm");
+ }
+ }
+ }
+ }
+
+ //Dump_EPL check
+ property_get("vendor.SPE_EPL", value, "0");
+ property_get("vendor.streamin.epl.dump", value1, "0");
+ bflag = atoi(value);
+ int bflag1 = atoi(value1);
+ if (bflag || bflag1) {
+ EPLDebugEnable = true;
+ if (hDumpThread == 0) {
+ CreateDumpThread();
+ }
+
+ snprintf(Buf, sizeof(Buf), "%d.EPL", DumpFileNum);
+ String8 DumpFileNameEPL;
+ DumpFileNameEPL.appendFormat("%s%s%s", audio_dump_path, "SPE_EPL", Buf);
+
+ ALOGD("Dump_EPL DumpFileNameEPL = %s", DumpFileNameEPL.string());
+
+ ret = checkAndCreateDirectory(DumpFileNameEPL);
+ if (ret < 0) {
+ ALOGE("SPELayer::Dump_EPL checkAndCreateDirectory() fail!!!");
+ } else {
+ if (mfpEPL == NULL) {
+ mfpEPL = fopen(DumpFileNameEPL, "ab+");
+ if (mfpEPL == NULL) {
+ ALOGD("open SPE_EPL.EPL fail");
+ } else {
+ ALOGD("open SPE_EPL.EPL");
+ }
+ }
+ }
+ } else {
+ EPLDebugEnable = false;
+ }
+}
+
+void SPELayer::Dump_PCM_In(SPE_DATA_DIRECTION dir, void *buffer, int bytes) {
+ if (hDumpThread == 0) {
+ return;
+ }
+ if (dir == UPLINK) {
+ if (mfpInUL != NULL) {
+ BufferInfo *newInBuffer = new BufferInfo;
+ newInBuffer->pBufBase = (short *) malloc(bytes);
+ ASSERT(newInBuffer->pBufBase != NULL);
+ memcpy(newInBuffer->pBufBase, buffer, bytes);
+
+ newInBuffer->BufLen = bytes;
+ newInBuffer->pRead = newInBuffer->pBufBase;
+ newInBuffer->pWrite = newInBuffer->pBufBase;
+ DumpMutexLock();
+ mDumpULInBufferQ.add(newInBuffer);
+ DumpMutexUnlock();
+ }
+ } else {
+ if (mfpInDL != NULL) {
+ BufferInfo *newInBuffer = new BufferInfo;
+ newInBuffer->pBufBase = (short *) malloc(bytes);
+ ASSERT(newInBuffer->pBufBase != NULL);
+ memcpy(newInBuffer->pBufBase, buffer, bytes);
+
+ newInBuffer->BufLen = bytes;
+ newInBuffer->pRead = newInBuffer->pBufBase;
+ newInBuffer->pWrite = newInBuffer->pBufBase;
+ DumpMutexLock();
+ mDumpDLInBufferQ.add(newInBuffer);
+ DumpMutexUnlock();
+ }
+ }
+
+}
+
+void SPELayer::Dump_PCM_Process(SPE_DATA_DIRECTION dir, void *buffer, int bytes) {
+ if (dir == UPLINK) {
+ if (mfpProcessedUL != NULL) {
+ fwrite(buffer, bytes, 1, mfpProcessedUL);
+ }
+ } else {
+ if (mfpProcessedDL != NULL) {
+ fwrite(buffer, bytes, 1, mfpProcessedDL);
+ }
+ }
+}
+
+void SPELayer::Dump_PCM_Out(SPE_DATA_DIRECTION dir, void *buffer, int bytes) {
+ if (hDumpThread == 0) {
+ return;
+ }
+ if (dir == UPLINK) {
+ if (mfpOutUL != NULL) {
+ BufferInfo *newInBuffer = new BufferInfo;
+ newInBuffer->pBufBase = (short *) malloc(bytes);
+ ASSERT(newInBuffer->pBufBase != NULL);
+ memcpy(newInBuffer->pBufBase, buffer, bytes);
+
+ newInBuffer->BufLen = bytes;
+ newInBuffer->pRead = newInBuffer->pBufBase;
+ newInBuffer->pWrite = newInBuffer->pBufBase;
+ DumpMutexLock();
+ mDumpULOutBufferQ.add(newInBuffer);
+ DumpMutexUnlock();
+ }
+ } else {
+ if (mfpOutDL != NULL) {
+ BufferInfo *newInBuffer = new BufferInfo;
+ newInBuffer->pBufBase = (short *) malloc(bytes);
+ ASSERT(newInBuffer->pBufBase != NULL);
+ memcpy(newInBuffer->pBufBase, buffer, bytes);
+
+ newInBuffer->BufLen = bytes;
+ newInBuffer->pRead = newInBuffer->pBufBase;
+ newInBuffer->pWrite = newInBuffer->pBufBase;
+ DumpMutexLock();
+ mDumpDLOutBufferQ.add(newInBuffer);
+ DumpMutexUnlock();
+ }
+ }
+}
+
+void SPELayer::Dump_EPL(void *buffer, int bytes) {
+ if (hDumpThread == 0) {
+ return;
+ }
+ if (mfpEPL != NULL) {
+ BufferInfo *newInBuffer = new BufferInfo;
+ newInBuffer->pBufBase = (short *) malloc(bytes);
+ ASSERT(newInBuffer->pBufBase != NULL);
+ memcpy(newInBuffer->pBufBase, buffer, bytes);
+
+ newInBuffer->BufLen = bytes;
+ newInBuffer->pRead = newInBuffer->pBufBase;
+ newInBuffer->pWrite = newInBuffer->pBufBase;
+ DumpMutexLock();
+ // ALOGD("Dump_EPL %p, %p",newInBuffer,newInBuffer->pBufBase);
+ mDumpEPLBufferQ.add(newInBuffer);
+ DumpMutexUnlock();
+ }
+}
+
+void SPELayer::EPLTransVMDump() {
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("vendor.APVM.dump", value, "0");
+ int bflag = atoi(value);
+ if (bflag || mVMDumpEnable) {
+ int ret;
+ String8 filename;
+ filename.appendFormat("%s%s", audio_dump_path, "SPE.VM");
+ if (bflag) {
+ audio_strncpy(mVMDumpFileName, filename.string(), VM_DUMP_FILE_NAME_SIZE);
+ }
+ if (mVMDumpFileName[0] == '\0') {
+ ALOGE("no mVMDumpFileName name?");
+ }
+
+ ret = checkAndCreateDirectory(mVMDumpFileName);
+ if (ret < 0) {
+ ALOGE("EPLTransVMDump checkAndCreateDirectory() fail!!!");
+ } else {
+ if (mfpVM == NULL && mVMDumpFileName[0] != '\0') {
+ mfpVM = fopen(mVMDumpFileName, "ab+");
+ }
+ }
+
+ if (mfpVM != NULL) {
+ if (mSph_Enh_ctrl.sample_rate == 48000) {
+ /* memcpy(mVM, mSph_Enh_ctrl.EPL_buffer, RecBufSize48K20ms*2*sizeof(short));
+ mVM[MaxVMSize-2] = mSph_Enh_ctrl.EPL_buffer[VMAGC1];
+ mVM[MaxVMSize-1] = mSph_Enh_ctrl.EPL_buffer[VMAGC2];
+ */
+ ALOGD("EPLTransVMDump 48k write to /data/vendor/audiohal/");
+ for (int i = 0; i < MaxVMSize; i++) {
+ if (i == (MaxVMSize - 2)) {
+ mVM[i] = mSph_Enh_ctrl.EPL_buffer[VMAGC1];
+ } else if (i == (MaxVMSize - 1)) {
+ mVM[i] = mSph_Enh_ctrl.EPL_buffer[VMAGC2];
+ } else {
+ mVM[i] = mSph_Enh_ctrl.EPL_buffer[i];
+ }
+ }
+ // ALOGE("EPLTransVMDump write to /data/vendor/audiohal");
+ fwrite(mVM, MaxVMSize * sizeof(short), 1, mfpVM);
+ } else { //suppose only 16K
+ /* memcpy(mVM, &mSph_Enh_ctrl.EPL_buffer[160*4], 320*2*sizeof(short));
+ mVM[640] = mSph_Enh_ctrl.EPL_buffer[VMAGC1];
+ mVM[641] = mSph_Enh_ctrl.EPL_buffer[VMAGC2];
+ */
+ ALOGD("EPLTransVMDump 16k write to /data/vendor/audiohal");
+ for (int i = 0; i < 642; i++) { //320*2+2
+ if (i == 640) {
+ mVM[i] = mSph_Enh_ctrl.EPL_buffer[VMAGC1];
+ } else if (i == 641) {
+ mVM[i] = mSph_Enh_ctrl.EPL_buffer[VMAGC2];
+ } else {
+ mVM[i] = mSph_Enh_ctrl.EPL_buffer[640 + i];
+ }
+ }
+ fwrite(mVM, 642 * sizeof(short), 1, mfpVM);
+ }
+ } else {
+ ALOGD("open vendor.APVM.dump fail");
+ }
+ }
+}
+
+void SPELayer::SetVMDumpEnable(bool bEnable) {
+ ALOGD("%s(), %d", __FUNCTION__, bEnable);
+ mVMDumpEnable = bEnable;
+}
+
+void SPELayer::SetVMDumpFileName(const char *VMFileName) {
+ ALOGD("%s()+, VMFileName=%s", __FUNCTION__, VMFileName);
+ audio_strncpy(mVMDumpFileName, VMFileName, VM_DUMP_FILE_NAME_SIZE);
+ ALOGD("%s()-, VMFileName=%s, mVMDumpFileName=%s", __FUNCTION__, VMFileName, mVMDumpFileName);
+}
+
+// ----------------------------------------------------------------------------
+}
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioSpeechEnhanceInfo.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioSpeechEnhanceInfo.cpp
new file mode 100644
index 0000000..2f609d1
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioSpeechEnhanceInfo.cpp
@@ -0,0 +1,372 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioSpeechEnhanceInfo.h"
+#include <utils/Log.h>
+#include <utils/String16.h>
+#include "AudioUtility.h"
+#include <cutils/properties.h>
+#include "AudioALSAStreamManager.h"
+//#include <AudioLock.h>
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioSpeechEnhanceInfo"
+static const char* PROPERTY_KEY_VOIP_SPH_ENH_MASKS = "persist.vendor.audiohal.voip.sph_enh_mask";
+
+
+namespace android {
+AudioSpeechEnhanceInfo *AudioSpeechEnhanceInfo::mAudioSpeechEnhanceInfo = NULL;
+
+AudioSpeechEnhanceInfo *AudioSpeechEnhanceInfo::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mAudioSpeechEnhanceInfo == NULL) {
+ ALOGD("%s()", __FUNCTION__);
+ mAudioSpeechEnhanceInfo = new AudioSpeechEnhanceInfo();
+ }
+ ASSERT(mAudioSpeechEnhanceInfo != NULL);
+ return mAudioSpeechEnhanceInfo;
+}
+
+AudioSpeechEnhanceInfo::AudioSpeechEnhanceInfo() {
+ ALOGD("%s()", __FUNCTION__);
+ mBesRecScene = -1;
+
+ //for tuning purpose
+ mBesRecTuningEnable = false;
+ mAPDMNRTuningEnable = false;
+ mAPTuningMode = TUNING_MODE_NONE;
+
+ mForceMagiASR = false;
+ mForceAECRec = false;
+
+ mHiFiRecordEnable = false;
+
+ // default value (all enhancement on)
+ char property_default_value[PROPERTY_VALUE_MAX];
+ sprintf(property_default_value, "0x%x", VOIP_SPH_ENH_DYNAMIC_MASK_ALL);
+
+ // get voip sph_enh_mask_struct from property
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_VOIP_SPH_ENH_MASKS, property_value, property_default_value);
+
+ // parse mask info from property_value
+ sscanf(property_value, "0x%x", &mVoIPSpeechEnhancementMask.dynamic_func);
+
+#ifndef MTK_AURISYS_FRAMEWORK_SUPPORT
+ memset((void *)&mPreLoadBesRecordSceneTable, 0, sizeof(mPreLoadBesRecordSceneTable));
+ memset((void *)&mPreLoadBesRecordParam, 0, sizeof(mPreLoadBesRecordParam));
+ memset((void *)&mPreLoadVOIPParam, 0, sizeof(mPreLoadVOIPParam));
+ memset((void *)&mPreLoadDMNRParam, 0, sizeof(mPreLoadDMNRParam));
+#endif
+
+ memset(mVMFileName, 0, VM_FILE_NAME_LEN_MAX);
+
+ mAudioCustParamClient = NULL;
+ mAudioCustParamClient = AudioCustParamClient::GetInstance();
+ ALOGD("%s(), mAudioCustParamClient(%p)", __FUNCTION__, mAudioCustParamClient);
+
+#ifndef MTK_AURISYS_FRAMEWORK_SUPPORT
+ PreLoadBesRecordParams();
+#endif
+
+ //debug purpose++
+ mDebugflag = false;
+ char debug_value[PROPERTY_VALUE_MAX];
+ property_get(streaminlog_propty, debug_value, "0");
+ int bflag = atoi(debug_value);
+ if (bflag) {
+ mDebugflag = true;
+ }
+ //debug purpose--
+}
+
+AudioSpeechEnhanceInfo::~AudioSpeechEnhanceInfo() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+//----------------for HD Record Preprocess +++ -------------------------
+void AudioSpeechEnhanceInfo::SetBesRecScene(int32_t BesRecScene) {
+ AL_AUTOLOCK(mLock);
+ ALOGV("%s() %d", __FUNCTION__, BesRecScene);
+ mBesRecScene = BesRecScene;
+}
+
+int32_t AudioSpeechEnhanceInfo::GetBesRecScene() {
+ AL_AUTOLOCK(mLock);
+ ALOGD("%s() %d", __FUNCTION__, mBesRecScene);
+ return mBesRecScene;
+}
+
+void AudioSpeechEnhanceInfo::ResetBesRecScene() {
+ AL_AUTOLOCK(mLock);
+ ALOGV("%s()", __FUNCTION__);
+ mBesRecScene = -1;
+}
+
+//----------------for HD Record Preprocess --- -----------------------------
+
+//----------------Get MMI info for AP Speech Enhancement --------------------------------
+void AudioSpeechEnhanceInfo::UpdateDynamicSpeechEnhancementMask(const voip_sph_enh_mask_struct_t &mask) {
+ uint32_t feature_support = mAudioCustParamClient->QueryFeatureSupportInfo();
+
+ ALOGD("%s(), mask = %x, feature_support=%x, %x", __FUNCTION__, mask.dynamic_func, feature_support, (feature_support & (SUPPORT_DMNR_3_0 | SUPPORT_VOIP_ENHANCE)));
+
+ if (feature_support & (SUPPORT_DMNR_3_0 | SUPPORT_VOIP_ENHANCE)) {
+
+ char property_value[PROPERTY_VALUE_MAX];
+ sprintf(property_value, "0x%x", mask.dynamic_func);
+ property_set(PROPERTY_KEY_VOIP_SPH_ENH_MASKS, property_value);
+
+ mVoIPSpeechEnhancementMask = mask;
+ AudioALSAStreamManager::getInstance()->UpdateDynamicFunctionMask();
+ } else {
+ ALOGD("%s(), not support", __FUNCTION__);
+ }
+
+}
+
+status_t AudioSpeechEnhanceInfo::SetDynamicVoIPSpeechEnhancementMask(const voip_sph_enh_dynamic_mask_t dynamic_mask_type, const bool new_flag_on) {
+ //Mutex::Autolock lock(mHDRInfoLock);
+ uint32_t feature_support = mAudioCustParamClient->QueryFeatureSupportInfo();
+
+ ALOGD("%s(), feature_support=%x, %x", __FUNCTION__, feature_support, (feature_support & (SUPPORT_DMNR_3_0 | SUPPORT_VOIP_ENHANCE)));
+
+ if (feature_support & (SUPPORT_DMNR_3_0 | SUPPORT_VOIP_ENHANCE)) {
+ voip_sph_enh_mask_struct_t mask = GetDynamicVoIPSpeechEnhancementMask();
+
+ ALOGW("%s(), dynamic_mask_type(%x), %x",
+ __FUNCTION__, dynamic_mask_type, mask.dynamic_func);
+ const bool current_flag_on = ((mask.dynamic_func & dynamic_mask_type) > 0);
+ if (new_flag_on == current_flag_on) {
+ ALOGW("%s(), dynamic_mask_type(%x), new_flag_on(%d) == current_flag_on(%d), return",
+ __FUNCTION__, dynamic_mask_type, new_flag_on, current_flag_on);
+ return NO_ERROR;
+ }
+
+ if (new_flag_on == false) {
+ mask.dynamic_func &= (~dynamic_mask_type);
+ } else {
+ mask.dynamic_func |= dynamic_mask_type;
+ }
+
+ UpdateDynamicSpeechEnhancementMask(mask);
+ } else {
+ ALOGW("%s(), not support", __FUNCTION__);
+ }
+
+ return NO_ERROR;
+}
+
+//----------------Audio tunning +++ --------------------------------
+//----------------for BesRec tunning --------------------------------
+void AudioSpeechEnhanceInfo::SetBesRecTuningEnable(bool bEnable) {
+ ALOGV("%s()+", __FUNCTION__);
+ AL_AUTOLOCK(mLock);
+ mBesRecTuningEnable = bEnable;
+ ALOGV("%s()- %d", __FUNCTION__, bEnable);
+}
+
+bool AudioSpeechEnhanceInfo::IsBesRecTuningEnable(void) {
+ ALOGV("%s()+", __FUNCTION__);
+ AL_AUTOLOCK(mLock);
+ ALOGD("%s()- %d", __FUNCTION__, mBesRecTuningEnable);
+ return mBesRecTuningEnable;
+}
+
+status_t AudioSpeechEnhanceInfo::SetBesRecVMFileName(const char *fileName) {
+ ALOGD("%s()+", __FUNCTION__);
+ AL_AUTOLOCK(mLock);
+ if (fileName != NULL && strlen(fileName) < 128 - 1) {
+ ALOGV("%s(), file name:%s", __FUNCTION__, fileName);
+ audio_strncpy(mVMFileName, fileName, VM_FILE_NAME_LEN_MAX);
+ } else {
+ ALOGV("%s(), input file name NULL or too long!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+}
+void AudioSpeechEnhanceInfo::GetBesRecVMFileName(char *VMFileName, size_t string_size) {
+ ALOGV("%s()+", __FUNCTION__);
+ AL_AUTOLOCK(mLock);
+ audio_strncpy(VMFileName, mVMFileName, string_size);
+ ALOGV("%s(), mVMFileName=%s, VMFileName=%s", __FUNCTION__, mVMFileName, VMFileName);
+}
+
+//----------------for AP DMNR tunning +++ --------------------------------
+void AudioSpeechEnhanceInfo::SetAPDMNRTuningEnable(bool bEnable) {
+ if ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_DUAL_MIC) > 0) {
+ AL_AUTOLOCK(mLock);
+ ALOGV("%s(), %d", __FUNCTION__, bEnable);
+ mAPDMNRTuningEnable = bEnable;
+ } else {
+ ALOGV("%s(), no Dual MIC, not set", __FUNCTION__);
+ }
+}
+
+bool AudioSpeechEnhanceInfo::IsAPDMNRTuningEnable(void) {
+ if ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_DUAL_MIC) > 0) {
+ ALOGV("%s()+", __FUNCTION__);
+ AL_AUTOLOCK(mLock);
+ ALOGD("%s(), %d", __FUNCTION__, mAPDMNRTuningEnable);
+ return mAPDMNRTuningEnable;
+ } else {
+ return false;
+ }
+}
+
+bool AudioSpeechEnhanceInfo::SetAPTuningMode(const TOOL_TUNING_MODE mode) {
+ bool bRet = false;
+ //for different MIC gain
+ ALOGV("%s(), SetAPTuningMode mAPDMNRTuningEnable=%d, mode=%d", __FUNCTION__, mAPDMNRTuningEnable, mode);
+ if (mAPDMNRTuningEnable) {
+ mAPTuningMode = mode;
+ bRet = true;
+ }
+ return bRet;
+}
+
+int AudioSpeechEnhanceInfo::GetAPTuningMode() {
+ ALOGD("%s(), mAPTuningMode=%d", __FUNCTION__, mAPTuningMode);
+
+ return mAPTuningMode;
+}
+
+//----------------Audio tunning --- --------------------------------
+
+//Engineer mode enable MagiASR+++
+bool AudioSpeechEnhanceInfo::SetForceMagiASR(bool enable) {
+ ALOGV("%s, %d", __FUNCTION__, enable);
+ mForceMagiASR = enable;
+ return true;
+}
+
+status_t AudioSpeechEnhanceInfo::GetForceMagiASRState() {
+ status_t ret = 0;
+ uint32_t feature_support = mAudioCustParamClient->QueryFeatureSupportInfo();
+
+ ALOGD("%s(), feature_support=%x, %x, mForceMagiASR=%d", __FUNCTION__, feature_support, (feature_support & SUPPORT_ASR), mForceMagiASR);
+
+ if (feature_support & SUPPORT_ASR) {
+ if (mForceMagiASR) {
+ ret = 1;
+ } else {
+ ret = -1;
+ }
+ } else {
+ ret = 0;
+ }
+
+ return ret;
+}
+
+//Engineer mode MagiASR---
+
+//Engineer mode enable AECRecord+
+bool AudioSpeechEnhanceInfo::SetForceAECRec(bool enable) {
+ ALOGV("%s, %d", __FUNCTION__, enable);
+ mForceAECRec = enable;
+ return true;
+}
+
+bool AudioSpeechEnhanceInfo::GetForceAECRecState() {
+ status_t ret = false;
+
+ ALOGD("%s(), mForceAECRec=%d", __FUNCTION__, mForceAECRec);
+
+ if (mForceAECRec) {
+ ret = true;
+ }
+ return ret;
+}
+//Engineer mode enable AECRecord-
+
+#ifndef MTK_AURISYS_FRAMEWORK_SUPPORT
+//BesRecord+++
+//preload BesRecord parames to avoid record loading fail when storage full
+void AudioSpeechEnhanceInfo::PreLoadBesRecordParams(void) {
+ ALOGD("%s+", __FUNCTION__);
+ AL_AUTOLOCK(mLock);
+ //for NVRAM create file first to reserve the memory
+ // get scene table
+ if (mAudioCustParamClient->GetHdRecordSceneTableFromNV(&mPreLoadBesRecordSceneTable) == 0) {
+ ALOGD("GetHdRecordSceneTableFromNV fail");
+ }
+
+ // get hd rec param
+ if (mAudioCustParamClient->GetHdRecordParamFromNV(&mPreLoadBesRecordParam) == 0) {
+ ALOGD("GetHdRecordParamFromNV fail");
+ }
+
+ //get VoIP param
+ if (mAudioCustParamClient->GetAudioVoIPParamFromNV(&mPreLoadVOIPParam) == 0) {
+ ALOGD("GetAudioVoIPParamFromNV fail");
+ }
+
+ //get DMNR param
+ if ((mAudioCustParamClient->QueryFeatureSupportInfo()& SUPPORT_DUAL_MIC) > 0) {
+ if (mAudioCustParamClient->GetDualMicSpeechParamFromNVRam(&mPreLoadDMNRParam) == 0) {
+ ALOGD("GetDualMicSpeechParamFromNVRam fail");
+ }
+ }
+ ALOGD("%s-", __FUNCTION__);
+}
+
+void AudioSpeechEnhanceInfo::UpdateBesRecordParams(void) {
+ ALOGD("%s+", __FUNCTION__);
+ PreLoadBesRecordParams();
+ ALOGD("%s-", __FUNCTION__);
+}
+
+void AudioSpeechEnhanceInfo::GetPreLoadBesRecordSceneTable(AUDIO_HD_RECORD_SCENE_TABLE_STRUCT *pPara) {
+ ALOGD("%s+", __FUNCTION__);
+ AL_AUTOLOCK(mLock);
+ memcpy((void *)pPara, &mPreLoadBesRecordSceneTable, sizeof(mPreLoadBesRecordSceneTable));
+ ALOGD("%s-", __FUNCTION__);
+}
+void AudioSpeechEnhanceInfo::GetPreLoadBesRecordParam(AUDIO_HD_RECORD_PARAM_STRUCT *pPara) {
+ ALOGD("%s+", __FUNCTION__);
+ AL_AUTOLOCK(mLock);
+ memcpy((void *)pPara, &mPreLoadBesRecordParam, sizeof(mPreLoadBesRecordParam));
+ ALOGD("%s-", __FUNCTION__);
+}
+void AudioSpeechEnhanceInfo::GetPreLoadAudioVoIPParam(AUDIO_VOIP_PARAM_STRUCT *pPara) {
+ ALOGD("%s+", __FUNCTION__);
+ AL_AUTOLOCK(mLock);
+ memcpy((void *)pPara, &mPreLoadVOIPParam, sizeof(mPreLoadVOIPParam));
+ ALOGD("%s-", __FUNCTION__);
+}
+void AudioSpeechEnhanceInfo::GetPreLoadDualMicSpeechParam(AUDIO_CUSTOM_EXTRA_PARAM_STRUCT *pSphParamDualMic) {
+ ALOGD("%s+", __FUNCTION__);
+ AL_AUTOLOCK(mLock);
+ memcpy((void *)pSphParamDualMic, &mPreLoadDMNRParam, sizeof(mPreLoadDMNRParam));
+ ALOGD("%s-", __FUNCTION__);
+}
+
+//BesRecord---
+#endif
+
+//Hifi Record +++
+void AudioSpeechEnhanceInfo::SetHifiRecord(bool bEnable) {
+ ALOGV("%s+, bEnable=%d", __FUNCTION__, bEnable);
+ AL_AUTOLOCK(mLock);
+ mHiFiRecordEnable = bEnable;
+ ALOGV("%s, mHiFiRecordEnable=%d", __FUNCTION__, mHiFiRecordEnable);
+}
+
+bool AudioSpeechEnhanceInfo::GetHifiRecord(void) {
+ AL_AUTOLOCK(mLock);
+ ALOGD("%s, mHiFiRecordEnable=%d", __FUNCTION__, mHiFiRecordEnable);
+ return mHiFiRecordEnable;
+}
+//Hifi Record ---
+
+//debug purpose
+bool AudioSpeechEnhanceInfo::GetDebugStatus(void) {
+ ALOGV("%s, mDebugflag=%d", __FUNCTION__, mDebugflag);
+ return mDebugflag;
+}
+
+}
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioUSBPhoneCallController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioUSBPhoneCallController.cpp
new file mode 100644
index 0000000..73ac6a8
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioUSBPhoneCallController.cpp
@@ -0,0 +1,2660 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioUSBPhoneCallController.h"
+
+#include <audio_utils/format.h>
+//#include <hardware/audio_alsaops.h> will have build error...
+#include <tinyalsa/asoundlib.h>
+#include <math.h>
+#include <sys/resource.h>
+#include <dlfcn.h>
+#include <fstream>
+
+#include <vendor/mediatek/hardware/power/2.0/IPower.h>
+#include <vendor/mediatek/hardware/power/2.0/types.h>
+using namespace vendor::mediatek::hardware::power::V2_0;
+
+#ifdef HAVE_AEE_FEATURE
+#include <aee.h>
+#endif
+
+#include "SpeechDriverFactory.h"
+#include "AudioALSADriverUtility.h"
+#include "AudioALSADeviceConfigManager.h"
+#include "AudioALSADeviceParser.h"
+#include "AudioVolumeFactory.h"
+#include "AudioALSAHardwareResourceManager.h"
+#include "AudioUtility.h"
+
+#include "AudioParamParser.h"
+
+#include "MtkAudioComponent.h"
+
+#include "SpeechDriverFactory.h"
+#include <SpeechUtility.h>
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioUSBPhoneCallController"
+
+// pcm dump
+#define USB_SPH_DUMP_FILE_PREFIX "/data/vendor/audiohal/audio_dump/usbsph.pcm"
+#define USB_SPH_DUMP_DL2HAL_NAME "dl2hal"
+#define USB_SPH_DUMP_DL_PROPERTY "vendor.usbsph.dl.pcm.dump"
+#define USB_SPH_DUMP_UL_PROPERTY "vendor.usbsph.ul.pcm.dump"
+#define USB_SPH_DUMP_HAL2USB_NAME "hal2usb"
+#define USB_SPH_DUMP_USB2HAL_NAME "usb2hal"
+#define USB_SPH_DUMP_HAL2UL_NAME "hal2ul"
+
+// sgen
+#define USB_SPH_DL_SGEN_TYPE_PROPERTY "vendor.usbsph.dl.sgen.type"
+#define USB_SPH_UL_SGEN_TYPE_PROPERTY "vendor.usbsph.ul.sgen.type"
+
+// lpbk
+#define USB_SPH_LPBK_TYPE_PROPERTY "vendor.usbsph.lpbk.type"
+#define USB_SPH_LPBK_PULSE_THRES_PROPERTY "vendor.usbsph.lpbk.pulse.thres"
+
+// rate
+#define USB_SPH_DL_RATE_PROPERTY "vendor.usbsph.dl.rate"
+#define USB_SPH_UL_RATE_PROPERTY "vendor.usbsph.ul.rate"
+
+// debug
+#define USB_SPH_DEBUG "vendor.usbsph.debug"
+
+static const char *PROPERTY_KEY_MIC_MUTE_ON = "vendor.audiohal.recovery.mic_mute_on";
+
+enum USB_DBG_TYPE {
+ USB_DBG_ASSERT_AT_STOP_DL = 0x1 << 0,
+ USB_DBG_BUFFER_LEVEL = 0x1 << 1,
+ USB_DBG_ECHO_REF_ALIGN = 0x1 << 2,
+ USB_DBG_USE_DL_ONLY = 0x1 << 3,
+ USB_DBG_USB_UL_ADDITIONAL_DATA_TEST = 0x1 << 4,
+ USB_DBG_ECHO_USE_SW = 0x1 << 5, // deprecated
+ USB_DBG_DL_TIME_PROFILE = 0x1 << 6,
+ USB_DBG_UL_TIME_PROFILE = 0x1 << 7,
+ USB_DBG_DL_DISABLE_THROTTLE = 0x1 << 8,
+ USB_DBG_UL_DISABLE_THROTTLE = 0x1 << 9,
+ USB_DBG_ASSERT_AT_STOP_UL = 0x1 << 10,
+ USB_DBG_ALL = 0xFFFFFFFF,
+};
+
+enum SGEN_TYPE {
+ SPH_DL_SGEN_OFF = 0,
+ SPH_DL_AFE_HW_SGEN,
+ SPH_DL_SW_SGEN,
+ SPH_DL_AFE_HW_SGEN_AMP_ONE_FOURTH,
+ SPH_UL_SGEN_OFF = 0,
+ SPH_UL_AFE_HW_SGEN,
+ SPH_UL_SW_SGEN,
+};
+
+enum USB_LPBK_TYPE {
+ USB_LPBK_DISABLE,
+ USB_LPBK_NORMAL, // work best with direct loopback on usb headset
+ USB_LPBK_PERIODIC_PULSE, // just send pulse periodically
+};
+
+enum USB_ECHO_REF_STATE {
+ USB_ECHO_REF_RESET,
+ USB_ECHO_REF_SETTLING,
+ USB_ECHO_REF_RUNNING,
+ USB_ECHO_REF_INPUT_CHANGE,
+};
+
+enum USB_THROTTLE_STATE {
+ USB_THROTTLE_INIT,
+ USB_THROTTLE_STEADY,
+ USB_THROTTLE_INCREASE, // increase the data generated by src
+ USB_THROTTLE_DECREASE, // decrease the data generated by src
+ USB_THROTTLE_RESET,
+};
+
+static const uint16_t table_1k_tone_16000_hz[] = {
+ 0x0000, 0x30FC, 0x5A82, 0x7641,
+ 0x7FFF, 0x7641, 0x5A82, 0x30FB,
+ 0x0001, 0xCF05, 0xA57E, 0x89C0,
+ 0x8001, 0x89BF, 0xA57E, 0xCF05
+};
+static const uint32_t kNumElmSinewaveTable = sizeof(table_1k_tone_16000_hz) / sizeof((table_1k_tone_16000_hz)[0]);
+
+// usb sph parameters
+#define USB_SPH_LATENCY_MS 5
+
+#define USB_SPH_DL_CHANNEL 2
+#define USB_SPH_DL_2_HAL_PERIOD_CNT 4
+#define USB_SPH_DL_2_HAL_FMT PCM_FORMAT_S16_LE
+
+#define USB_SPH_UL_CHANNEL USB_SPH_DL_CHANNEL
+#define USB_SPH_UL_2_HAL_PERIOD_CNT USB_SPH_DL_2_HAL_PERIOD_CNT
+#define USB_SPH_UL_2_HAL_FMT USB_SPH_DL_2_HAL_FMT
+
+#define USB_SPH_PRIMARY_IN_DEVICE AUDIO_DEVICE_IN_BUILTIN_MIC
+
+#define USB_SPH_FIRST_READ_PERIOD 2
+#define USB_SPH_LATENCY_LOG_RATIO 1.1f
+
+// usb echo ref
+#define USB_SPH_ECHO_REF_PERIOD_US (USB_SPH_LATENCY_MS * 1000)
+#define USB_SPH_ECHO_FIRST_WRITE_US 1000
+
+#define USB_SPH_ECHO_LOCK_TIMEOUT_MS 20000
+
+#define USB_SPH_PARAM_AUDIOTYPE_NAME "USBCall"
+#define USB_SPH_DEVICE_PARAM_AUDIOTYPE_NAME "USBDevice"
+
+// usb lpbk
+#define USB_SPH_LPBK_PULSE_THRES_DEFAULT 0x6fff
+
+#define USB_SPH_INVALID_AVAIL 0xffff // hardcode
+
+// throttle
+#define USB_SPH_THROTTLE_KICK_IN_DIFF_MS 1
+#define USB_SPH_THROTTLE_KICK_IN_COUNT 3
+#define USB_SPH_THROTTLE_STEADY_DIFF_US 300
+#define USB_SPH_THROTTLE_MS_CHANGE_PER_SECOND 1
+#define USB_SPH_THROTTLE_SPEED_UP_COUNT 3
+
+// direction
+enum {
+ SPH_DL = 0,
+ SPH_UL = 1,
+};
+
+#define calc_time_diff(x,y) ((x.tv_sec - y.tv_sec )+ (double)( x.tv_nsec - y.tv_nsec ) / (double)1000000000)
+
+namespace android {
+// callback function
+void usbXmlChangedCallback(AppHandle *_appHandle, const char *_audioTypeName) {
+ // reload XML file
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return;
+ }
+
+ if (appOps->appHandleReloadAudioType(_appHandle, _audioTypeName) == APP_ERROR) {
+ ALOGE("%s(), Reload xml fail!(audioType = %s)", __FUNCTION__, _audioTypeName);
+ } else {
+ AudioUSBPhoneCallController::getInstance()->updateXmlParam(_audioTypeName);
+ }
+}
+
+AudioUSBPhoneCallController *AudioUSBPhoneCallController::mUSBPhoneCallController = NULL;
+struct mixer *AudioUSBPhoneCallController::mMixer = NULL;
+
+AudioUSBPhoneCallController *AudioUSBPhoneCallController::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (!mUSBPhoneCallController) {
+ mUSBPhoneCallController = new AudioUSBPhoneCallController();
+ }
+
+ return mUSBPhoneCallController;
+}
+
+AudioUSBPhoneCallController::AudioUSBPhoneCallController() :
+ mEnable(false),
+ mAudioHWReady(false),
+ mSpeechRate(16000),
+ mModemIndex(MODEM_1),
+ mUSBOutConnected(false),
+ mUSBInConnected(false),
+ mEnableWithUSBInConnected(false),
+ mPcmMicOut(NULL),
+ mPcmMicIn(NULL),
+ mPcmEchoRefOut(NULL),
+ mPcmEchoRefIn(NULL),
+ mPcmEchoRefDebugOut(NULL),
+ mPcmEchoRefDebugOut2(NULL),
+ mSphDLThread(0),
+ mSphULThread(0),
+ mLpbkType(0),
+ mLpbkStart(false),
+ mLpbkTime(0),
+ mLpbkPulseThres(USB_SPH_LPBK_PULSE_THRES_DEFAULT),
+ mDebugType(0),
+ mEchoRefState(USB_ECHO_REF_RESET),
+ mPowerHalHandle(-1) {
+ memset(&mUSBOutStream, 0, sizeof(struct USBStream));
+ mUSBOutStream.direction = SPH_DL;
+ profile_init(&mUSBOutStream.profile, PCM_OUT);
+
+ memset(&mUSBInStream, 0, sizeof(struct USBStream));
+ mUSBInStream.direction = SPH_UL;
+ profile_init(&mUSBInStream.profile, PCM_IN);
+
+ mLpbkTimePart[0] = mLpbkTimePart[1] = mLpbkTimePart[2] = mLpbkTimePart[3] = 0;
+ memset(&mLpbkNewTime, 0, sizeof(struct timespec));
+ memset(&mLpbkOldTime, 0, sizeof(struct timespec));
+ memset(&mLpbkStartTime, 0, sizeof(struct timespec));
+
+ if (mMixer == NULL) {
+ mMixer = AudioALSADriverUtility::getInstance()->getMixer();
+ ASSERT(mMixer != NULL);
+ }
+
+ memset(&mParam, 0, sizeof(struct USBCallParam));
+ /* XML changed callback process */
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ } else {
+ appOps->appHandleRegXmlChangedCb(appOps->appHandleGetInstance(), usbXmlChangedCallback);
+ }
+ loadUSBCallParam();
+ loadUSBDeviceParam();
+}
+
+AudioUSBPhoneCallController::~AudioUSBPhoneCallController() {
+ try {
+ deinitPerfService();
+ } catch (const std::__1::system_error &e) {
+ ALOGE("%s(), caught system_error", __FUNCTION__);
+ } catch (...) {
+ ALOGE("%s(), caught other exception", __FUNCTION__);
+ }
+}
+
+int AudioUSBPhoneCallController::enable(unsigned int speechRate) {
+ mModemIndex = SpeechDriverFactory::GetInstance()->GetActiveModemIndex();
+
+ ALOGD("+%s(), mEnable %d, md %d, rate %u, mUSBInConnected %d", __FUNCTION__, mEnable, mModemIndex, speechRate, mUSBInConnected);
+
+ AL_AUTOLOCK(mLock);
+
+ initPerfService();
+
+ if (mEnable) {
+ ALOGW("%s(), already enabled, mEnable %d", __FUNCTION__, mEnable);
+ return INVALID_OPERATION;
+ }
+
+ enablePerfCpuScn();
+
+ // set enable flag
+ mEnable = true;
+ mEnableWithUSBInConnected = mDebugType & USB_DBG_USE_DL_ONLY ? false : mUSBInConnected;
+ // set speech rate
+ mSpeechRate = speechRate;
+ mUSBOutStream.speechRate = mSpeechRate;
+ mUSBInStream.speechRate = mSpeechRate;
+
+ // set debug info
+ char value[PROPERTY_VALUE_MAX];
+ property_get(USB_SPH_DEBUG, value, "0");
+ mDebugType = atoi(value);
+ if (mDebugType == 0) {
+ setDebugInfo(false, USB_DBG_ALL);
+ } else {
+ setDebugInfo(true, mDebugType);
+ }
+
+#if !defined(MTK_AUDIO_KS)
+ // set modem
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "USB_Modem_Select"), mModemIndex == MODEM_1 ? "md1" : "md2")) {
+ ALOGE("Error: USB_Modem_Select invalid value");
+ }
+ // set uplink device
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "USB_Voice_UL_Select"), mEnableWithUSBInConnected ? "usb" : "primary")) {
+ ALOGE("Error: USB_Voice_UL_Select invalid value");
+ }
+#endif
+ // start speech downlink thread, modem dl -> afe -> hal -> usb downlink
+ int ret = pthread_create(&mSphDLThread, NULL, AudioUSBPhoneCallController::speechDLThread, this);
+ if (ret) {
+ ALOGE("%s() create mSphDLThread fail, ret = %d!!", __FUNCTION__, ret);
+ ASSERT(0);
+ }
+ ret = pthread_setname_np(mSphDLThread, "usb_call_dl");
+ if (ret) {
+ ALOGW("%s(), set mSphDLThread name fail", __FUNCTION__);
+ }
+
+ // start speech uplink thread
+ if (mEnableWithUSBInConnected) {
+ int ret = pthread_create(&mSphULThread, NULL, AudioUSBPhoneCallController::speechULThread, this);
+ if (ret) {
+ ALOGE("%s() create mSphULThread fail, ret = %d!!", __FUNCTION__, ret);
+ ASSERT(0);
+ }
+ ret = pthread_setname_np(mSphULThread, "usb_call_ul");
+ if (ret) {
+ ALOGW("%s(), set mSphULThread name fail", __FUNCTION__);
+ }
+ }
+
+ // wait for hardware setup finish
+ int sleepTotal_us = 0;
+ while (!mAudioHWReady) {
+ usleep(500);
+ if (sleepTotal_us >= 3 * 1000 * 1000) {
+ ALOGE("%s(), timeout > 3 sec, mAudioHWReady %d", __FUNCTION__, mAudioHWReady);
+ ASSERT(0);
+ break;
+ }
+ sleepTotal_us += 500;
+ }
+
+ // use phone mic if usb mic not connected
+ if (!mEnableWithUSBInConnected) {
+#if defined(MTK_AUDIO_KS)
+ speechULPhoneMicPath(true);
+#else
+ AudioALSAHardwareResourceManager::getInstance()->startInputDevice(USB_SPH_PRIMARY_IN_DEVICE);
+#endif
+ }
+
+ ALOGD("-%s()", __FUNCTION__);
+ return 0;
+}
+
+int AudioUSBPhoneCallController::disable() {
+ ALOGD("+%s(), mEnable %d, mEnableWithUSBInConnected %d", __FUNCTION__, mEnable, mEnableWithUSBInConnected);
+
+ AL_AUTOLOCK(mLock);
+
+ if (!mEnable) {
+ ALOGW("%s(), already disabled, mEnable %d", __FUNCTION__, mEnable);
+ return INVALID_OPERATION;
+ }
+
+ int ret;
+ void *retval;
+
+ // stop phone mic if using primary device
+ if (!mEnableWithUSBInConnected) {
+#if defined(MTK_AUDIO_KS)
+ speechULPhoneMicPath(false);
+#else
+ AudioALSAHardwareResourceManager::getInstance()->stopInputDevice(USB_SPH_PRIMARY_IN_DEVICE);
+#endif
+ }
+
+ // set disable flag
+ mEnable = false;
+
+ // pthread_join
+ ret = pthread_join(mSphDLThread, &retval);
+ if (ret) {
+ ALOGE("%s(), mSphDLThread pthread_join fail, ret = %d", __FUNCTION__, ret);
+ ASSERT(0);
+ }
+
+ if (mEnableWithUSBInConnected) {
+ ret = pthread_join(mSphULThread, &retval);
+ if (ret) {
+ ALOGE("%s(), mSphULThread pthread_join fail, ret = %d", __FUNCTION__, ret);
+ ASSERT(0);
+ }
+ mEnableWithUSBInConnected = false;
+ }
+
+ disablePerfCpuScn();
+
+ ALOGD("-%s()", __FUNCTION__);
+ return 0;
+}
+
+bool AudioUSBPhoneCallController::isEnable() {
+ return mEnable;
+}
+
+bool AudioUSBPhoneCallController::isForceUSBCall() {
+ // set debug info
+ char value[PROPERTY_VALUE_MAX];
+ property_get(USB_SPH_DEBUG, value, "0");
+ mDebugType = atoi(value);
+ if (mDebugType & USB_DBG_ECHO_REF_ALIGN) {
+ ALOGW("%s(), force use USB phone call", __FUNCTION__);
+ return true;
+ }
+
+ return false;
+}
+
+bool AudioUSBPhoneCallController::isUsingUSBIn() {
+ AL_AUTOLOCK(mLock);
+
+ return mEnableWithUSBInConnected;
+}
+
+int AudioUSBPhoneCallController::setUSBOutConnectionState(audio_devices_t devices, bool connect, int card, int device) {
+ ALOGD("%s(), devices 0x%x, connect %d, mUSBOutConnected %d, card %d, device %d",
+ __FUNCTION__, devices, connect, mUSBOutConnected, card, device);
+
+ if (audio_is_usb_out_device(devices)) {
+ mUSBOutConnected = connect;
+
+ if (connect) {
+ ASSERT(card >= 0 && device >= 0);
+ mUSBOutStream.profile.card = card;
+ mUSBOutStream.profile.device = device;
+ getDeviceId(&mUSBOutStream);
+ getDeviceParam(&mUSBOutStream);
+ }
+ }
+
+ return 0;
+}
+
+int AudioUSBPhoneCallController::setUSBInConnectionState(audio_devices_t devices, bool connect, int card, int device) {
+ ALOGD("%s(), devices 0x%x, connect %d, mUSBInConnected %d, card %d, device %d",
+ __FUNCTION__, devices, connect, mUSBInConnected, card, device);
+
+ if (audio_is_usb_in_device(devices)) {
+ if (connect) {
+ ASSERT(card >= 0 && device >= 0);
+ mUSBInStream.profile.card = card;
+ mUSBInStream.profile.device = device;
+ getDeviceId(&mUSBInStream);
+ getDeviceParam(&mUSBInStream);
+ }
+ } else if (devices == AUDIO_DEVICE_IN_BUS) {
+ AL_LOCK_MS(mLock, MAX_AUDIO_LOCK_TIMEOUT_MS);
+ bool usbInConnectedAfterEnable = !mUSBInConnected && connect && mEnable;
+ mUSBInConnected = mDebugType & USB_DBG_USE_DL_ONLY ? false : connect;
+
+ if (usbInConnectedAfterEnable && ((mDebugType & USB_DBG_USE_DL_ONLY) == 0)) {
+ // Get current active speech driver
+ SpeechDriverInterface *pSpeechDriver = SpeechDriverFactory::GetInstance()->GetSpeechDriver();
+
+ // Mute during device change.
+ pSpeechDriver->SetDownlinkMute(true);
+ pSpeechDriver->SetUplinkMute(true);
+ // Clean Side Tone Filter gain
+ pSpeechDriver->SetSidetoneGain(0);
+
+ int ret = pthread_create(&mSphULThread, NULL, AudioUSBPhoneCallController::speechULThread, this);
+ if (ret) {
+ ALOGE("%s() create mSphULThread fail, ret = %d!!", __FUNCTION__, ret);
+ ASSERT(0);
+ }
+ ret = pthread_setname_np(mSphULThread, "usb_call_ul");
+ if (ret) {
+ ALOGW("%s(), set mSphULThread name fail", __FUNCTION__);
+ }
+
+ // set uplink device from usb
+#if defined(MTK_AUDIO_KS)
+ speechULPhoneMicPath(false);
+#else
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "USB_Voice_UL_Select"), "usb")) {
+ ALOGE("Error: USB_Voice_UL_Select invalid value");
+ }
+
+ AudioALSAHardwareResourceManager::getInstance()->stopInputDevice(USB_SPH_PRIMARY_IN_DEVICE);
+#endif
+ mEnableWithUSBInConnected = true;
+
+ AL_LOCK_MS(mEchoRefStateLock, USB_SPH_ECHO_LOCK_TIMEOUT_MS);
+ mEchoRefState = USB_ECHO_REF_INPUT_CHANGE;
+ AL_UNLOCK(mEchoRefStateLock);
+
+ // update speech mode
+ pSpeechDriver->SetSpeechMode(AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_OUT_USB_DEVICE);
+ // Need recover mute state
+ pSpeechDriver->SetUplinkMute(get_uint32_from_mixctrl(PROPERTY_KEY_MIC_MUTE_ON));
+ pSpeechDriver->SetDownlinkMute(false);
+ }
+
+ AL_UNLOCK(mLock);
+
+ if (usbInConnectedAfterEnable && ((mDebugType & USB_DBG_USE_DL_ONLY) == 0)) {
+ // need reset volume when input device is changed during usb call
+ AudioVolumeInterface *volumeController = AudioVolumeFactory::CreateAudioVolumeController();
+ volumeController->setVoiceVolume(volumeController->getVoiceVolume(), AUDIO_MODE_IN_CALL, AUDIO_DEVICE_OUT_USB_DEVICE);
+ }
+ }
+
+ return 0;
+}
+
+unsigned int AudioUSBPhoneCallController::getSpeechRate() {
+ return mSpeechRate;
+}
+
+audio_devices_t AudioUSBPhoneCallController::getUSBCallInDevice() {
+ AL_AUTOLOCK(mLock);
+
+ return mUSBInConnected ? AUDIO_DEVICE_IN_USB_DEVICE : USB_SPH_PRIMARY_IN_DEVICE;
+}
+
+std::string AudioUSBPhoneCallController::getUSBIdSpeechDL() {
+ return mUSBOutStream.deviceId;
+}
+
+std::string AudioUSBPhoneCallController::getUSBIdSpeechUL() {
+ return mUSBInStream.deviceId;
+}
+
+void *AudioUSBPhoneCallController::speechDLThread(void *arg) {
+ AudioUSBPhoneCallController *controller = static_cast<AudioUSBPhoneCallController *>(arg);
+ int ret = 0;
+ bool usbReady = true;
+
+ audio_sched_setschedule(0, SCHED_RR, sched_get_priority_min(SCHED_RR));
+
+ ALOGD("+%s(), pid: %d, tid: %d, priority %d",
+ __FUNCTION__, getpid(), gettid(), getpriority(PRIO_PROCESS, gettid()));
+
+ // setup config for playback to usb output
+ alsa_device_proxy *proxy = &controller->mUSBOutStream.proxy;
+ ret = prepareUSBStream(&controller->mUSBOutStream);
+ if (ret) {
+ // error handle, this should not happen
+ ALOGE("%s(), error, ret %d, USB Not Ready, ignore usb write!!", __FUNCTION__, ret);
+ usbReady = false;
+ }
+
+ FILE *pcmHAL2USBDumpFile = pcmDumpOpen(USB_SPH_DUMP_HAL2USB_NAME, USB_SPH_DUMP_DL_PROPERTY);
+
+ // setup config for capturing modem downlink data
+ struct pcm *pcmUL = NULL;
+ struct pcm_config *pcmULConfig = &controller->mUSBOutStream.pcmConfigHAL2AFE;
+
+ getSpeech2HALPcmConfig(&controller->mUSBOutStream);
+
+#if defined(MTK_AUDIO_KS)
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmCapture2);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmCapture2);
+ controller->mUSBOutStream.apTurnOnSequence = (controller->mModemIndex == MODEM_1) ? AUDIO_CTL_MD1_TO_CAPTURE2 : AUDIO_CTL_MD2_TO_CAPTURE2;
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(controller->mUSBOutStream.apTurnOnSequence.c_str());
+#else
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceUSB);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVoiceUSB);
+#endif
+
+ pcmUL = pcm_open(cardIdx, pcmIdx, PCM_IN | PCM_MONOTONIC, pcmULConfig);
+ ASSERT(pcmUL != NULL && pcm_is_ready(pcmUL));
+ ret = pcm_prepare(pcmUL);
+ if (ret) {
+ ALOGE("%s(), pcm_prepare(pcmUL) fail, ret %d", __FUNCTION__, ret);
+ }
+ controller->mUSBOutStream.pcmHAL2AFE = pcmUL;
+ controller->mAudioHWReady = true;
+
+ FILE *pcmDL2HALDumpFile = pcmDumpOpen(USB_SPH_DUMP_DL2HAL_NAME, USB_SPH_DUMP_DL_PROPERTY);
+
+ // prepare rate, format, channel conversion
+ initBliSrc(&controller->mUSBOutStream);
+ initBitConverter(&controller->mUSBOutStream);
+ initDataPending(&controller->mUSBOutStream);
+
+ // prepare echo ref
+ AL_LOCK(controller->mEchoRefStateLock);
+ controller->mEchoRefState = USB_ECHO_REF_RESET;
+ AL_UNLOCK(controller->mEchoRefStateLock);
+
+#if defined(MTK_AUDIO_KS)
+ controller->setEchoRefPath(true, 1);
+
+ if (controller->mDebugType & USB_DBG_ECHO_REF_ALIGN) {
+ controller->setEchoRefDebugPath(true);
+ }
+#else
+ pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceUSBEchoRef);
+ cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVoiceUSBEchoRef);
+
+ if (controller->mDebugType & USB_DBG_ECHO_REF_ALIGN) {
+ AudioALSAHardwareResourceManager::getInstance()->startOutputDevice(AUDIO_DEVICE_OUT_WIRED_HEADSET, controller->getSpeechRate());
+ }
+
+ // hw echo ref solution need prepare just for setting codec rate
+ AudioALSAHardwareResourceManager::getInstance()->setCodecSampleRate(controller->getSpeechRate());
+#endif
+ struct timespec echoNewTime, echoOldTime;
+
+ // check if use sgen
+ char value[PROPERTY_VALUE_MAX];
+ property_get(USB_SPH_DL_SGEN_TYPE_PROPERTY, value, "0");
+ int sgenType = atoi(value);
+ if (sgenType == SPH_DL_AFE_HW_SGEN || sgenType == SPH_DL_AFE_HW_SGEN_AMP_ONE_FOURTH) {
+ if (controller->mModemIndex == MODEM_1) {
+ AudioALSAHardwareResourceManager::getInstance()->setSgenMode(SGEN_MODE_I14);
+ } else {
+ AudioALSAHardwareResourceManager::getInstance()->setSgenMode(SGEN_MODE_I09);
+ }
+ AudioALSAHardwareResourceManager::getInstance()->setSgenSampleRate(SGEN_MODE_SAMPLERATE_16000HZ);
+
+ if (sgenType == SPH_DL_AFE_HW_SGEN_AMP_ONE_FOURTH) {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(controller->mMixer, "Audio_SineGen_Amplitude"), "1/4")) {
+ ALOGE("%s(), set Audio_SineGen_Amplitude fail", __FUNCTION__);
+ }
+ } else {
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(controller->mMixer, "Audio_SineGen_Amplitude"), "1")) {
+ ALOGE("%s(), set Audio_SineGen_Amplitude fail", __FUNCTION__);
+ }
+ }
+ }
+
+ // start transfer data
+ unsigned int readSize = getPeriodByte(pcmULConfig);
+
+ // let playback buffer data level remain at around (period size * USB_SPH_FIRST_READ_PERIOD), 5 * 2 = 10ms
+ unsigned int firstReadSize = readSize * USB_SPH_FIRST_READ_PERIOD;
+ unsigned int normalReadSize = readSize;
+ bool firstRead = true;
+
+ char readBuffer[firstReadSize];
+ ALOGD("%s(), readSize = %d, usbReady %d", __FUNCTION__, readSize, usbReady);
+
+ // time check
+ unsigned int writeTimes = 0;
+ struct timespec mNewTime, mOldTime;
+ double latency[4];
+ clock_gettime(CLOCK_REALTIME, &mNewTime);
+ mOldTime = mNewTime;
+
+ // throttle init
+ controller->mUSBOutStream.throttleState = USB_THROTTLE_INIT;
+
+ while (controller->isEnable()) {
+ if (firstRead) {
+ readSize = firstReadSize;
+ firstRead = false;
+ } else {
+ readSize = normalReadSize;
+ }
+
+ ret = pcm_read(pcmUL, readBuffer, readSize);
+ if (ret) {
+ ALOGE("%s(), pcm_read() error, ret = %d", __FUNCTION__, ret);
+ }
+
+ // dl 2 hal read time
+ clock_gettime(CLOCK_REALTIME, &mNewTime);
+ latency[0] = calc_time_diff(mNewTime, mOldTime);
+ mOldTime = mNewTime;
+
+ pcmDumpWriteData(pcmDL2HALDumpFile, readBuffer, readSize);
+
+ // lpbk test
+ controller->getLpbkTime(0, readBuffer, readSize,
+ pcmULConfig->channels, pcmULConfig->rate,
+ (pcm_format_to_bits(pcmULConfig->format) / 8));
+
+ // replace read buffer with sgen
+ if (sgenType == SPH_DL_SW_SGEN) {
+ uint16_t *tmpBuffer = (uint16_t *)readBuffer;
+ for (unsigned int i = 0; i < readSize / sizeof(uint16_t); i = i + 2) {
+ *(tmpBuffer + i) = table_1k_tone_16000_hz[(i / 2) % kNumElmSinewaveTable];
+ *(tmpBuffer + i + 1) = table_1k_tone_16000_hz[(i / 2) % kNumElmSinewaveTable];
+ }
+ }
+
+ // ignore write to usb, if not ready
+ if (!usbReady) {
+ continue;
+ }
+
+ // src
+ void *pBufferAfterBliSrc = NULL;
+ uint32_t bytesAfterBliSrc = 0;
+ doBliSrc(&controller->mUSBOutStream,
+ readBuffer, readSize,
+ &pBufferAfterBliSrc, &bytesAfterBliSrc);
+
+ // bit conversion
+ void *pBufferAfterBitConvertion = NULL;
+ uint32_t bytesAfterBitConvertion = 0;
+ doBitConversion(&controller->mUSBOutStream,
+ pBufferAfterBliSrc, bytesAfterBliSrc,
+ &pBufferAfterBitConvertion, &bytesAfterBitConvertion);
+
+ // let output size equal one period size
+ void *pBufferAfterPending = NULL;
+ uint32_t bytesAfterPending = 0;
+ doDataPending(&controller->mUSBOutStream,
+ pBufferAfterBitConvertion, bytesAfterBitConvertion,
+ &pBufferAfterPending, &bytesAfterPending);
+
+ // processing time
+ clock_gettime(CLOCK_REALTIME, &mNewTime);
+ latency[1] = calc_time_diff(mNewTime, mOldTime);
+ mOldTime = mNewTime;
+
+ // lpbk test
+ controller->getLpbkTime(1, pBufferAfterPending, bytesAfterPending,
+ proxy->alsa_config.channels, proxy->alsa_config.rate,
+ (pcm_format_to_bits(proxy->alsa_config.format) / 8));
+
+ if (bytesAfterPending != 0) {
+ pcmDumpWriteData(pcmHAL2USBDumpFile, pBufferAfterPending, bytesAfterPending);
+
+ // write to usb playback
+ ret = proxy_write(proxy, pBufferAfterPending, bytesAfterPending);
+ if (ret) {
+ ALOGW("%s(), proxy_write failed, ret %d, fail due to %s", __FUNCTION__, ret, pcm_get_error(proxy->pcm));
+ if (ret == -EPIPE) {
+ if (controller->mDebugType & USB_DBG_ASSERT_AT_STOP_DL) {
+#ifdef HAVE_AEE_FEATURE
+ aee_system_exception(LOG_TAG, NULL, DB_OPT_FTRACE,
+ " %s, %uL, %s(), underrun", strrchr(__FILE__, '/') + 1, __LINE__, __FUNCTION__);
+#endif
+ }
+
+ firstRead = true;
+ resetBliSrcBuffer(&controller->mUSBOutStream);
+ ret = pcm_stop(pcmUL);
+ if (ret) {
+ ALOGE("%s(), pcm_stop() error, ret = %d, fail due to %s", __FUNCTION__, ret, pcm_get_error(proxy->pcm));
+ }
+
+ controller->mUSBOutStream.throttleState = USB_THROTTLE_RESET;
+ }
+ }
+ }
+
+ // throttle Control
+ if ((controller->mDebugType & USB_DBG_DL_DISABLE_THROTTLE) == 0) {
+ throttleControl(&controller->mUSBOutStream);
+ }
+
+ // write to usb time
+ clock_gettime(CLOCK_REALTIME, &mNewTime);
+ latency[2] = calc_time_diff(mNewTime, mOldTime);
+ mOldTime = mNewTime;
+
+ // write to echoref
+ AL_LOCK_MS(controller->mEchoRefStateLock, USB_SPH_ECHO_LOCK_TIMEOUT_MS);
+
+ if (controller->mEchoRefState == USB_ECHO_REF_RESET ||
+ controller->mEchoRefState == USB_ECHO_REF_INPUT_CHANGE) {
+ // hardware solution
+ controller->mEchoRefState = USB_ECHO_REF_RUNNING;
+ controller->setEchoRefPath(true, 2);
+ }
+
+ AL_UNLOCK(controller->mEchoRefStateLock);
+
+ // write to echoref time
+ clock_gettime(CLOCK_REALTIME, &mNewTime);
+ latency[3] = calc_time_diff(mNewTime, mOldTime);
+ mOldTime = mNewTime;
+ writeTimes++;
+
+ if ((latency[0] + latency[1] + latency[2]) * 1000 >= 2 * controller->mUSBOutStream.latency ||
+ latency[0] * 1000 > controller->mUSBOutStream.latency * USB_SPH_LATENCY_LOG_RATIO ||
+ latency[2] * 1000 > controller->mUSBOutStream.latency * USB_SPH_LATENCY_LOG_RATIO ||
+ latency[3] * 1000 > 1 ||
+ controller->mDebugType & USB_DBG_DL_TIME_PROFILE) {
+ if (controller->mDebugType & USB_DBG_BUFFER_LEVEL) {
+ ALOGD("%s(), time, read %1.6lf, process %1.6lf, write %1.6lf, echo %1.6lf, writeTimes %d, bytesAfterPending %u, avail r %u, w %u",
+ __FUNCTION__, latency[0], latency[1], latency[2], latency[3], writeTimes, bytesAfterPending,
+ getPcmAvail(pcmUL), getPcmAvail(proxy->pcm));
+ } else {
+ ALOGD("%s(), time, read %1.6lf, process %1.6lf, write %1.6lf, echo %1.6lf, writeTimes %d, bytesAfterPending %u",
+ __FUNCTION__, latency[0], latency[1], latency[2], latency[3], writeTimes, bytesAfterPending);
+ }
+ }
+ }
+
+ if (sgenType == SPH_DL_AFE_HW_SGEN) {
+ AudioALSAHardwareResourceManager::getInstance()->setSgenMode(SGEN_MODE_DISABLE);
+ }
+
+ if (controller->mDebugType & USB_DBG_ECHO_REF_ALIGN) {
+#if defined(MTK_AUDIO_KS)
+ controller->setEchoRefDebugPath(false);
+#else
+ AudioALSAHardwareResourceManager::getInstance()->stopOutputDevice();
+#endif
+ }
+
+ setDebugInfo(false, USB_DBG_ALL);
+
+ //
+ deinitBliSrc(&controller->mUSBOutStream);
+ deinitBitConverter(&controller->mUSBOutStream);
+ deinitDataPending(&controller->mUSBOutStream);
+
+ // close echo ref
+ controller->setEchoRefPath(false, 0);
+
+ // close usb
+ pcmDumpClose(pcmHAL2USBDumpFile);
+ proxy_close(proxy);
+
+ // close audio hw
+ pcmDumpClose(pcmDL2HALDumpFile);
+
+ pcm_stop(pcmUL);
+ pcm_close(pcmUL);
+ controller->mUSBOutStream.pcmHAL2AFE = NULL;
+ controller->mAudioHWReady = false;
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(controller->mUSBOutStream.apTurnOnSequence.c_str());
+#endif
+
+ ALOGD("-%s(), pid: %d, tid: %d, scheduler %d", __FUNCTION__, getpid(), gettid(), sched_getscheduler(0));
+ return NULL;
+}
+
+int AudioUSBPhoneCallController::getSpeech2HALPcmConfig(struct USBStream *stream) {
+ struct pcm_config *config = &stream->pcmConfigHAL2AFE;
+ int dir = stream->direction;
+ memset(config, 0, sizeof(struct pcm_config));
+
+ config->channels = (dir == SPH_DL) ? USB_SPH_DL_CHANNEL : USB_SPH_UL_CHANNEL;
+ config->period_count = (dir == SPH_DL) ? USB_SPH_DL_2_HAL_PERIOD_CNT : USB_SPH_UL_2_HAL_PERIOD_CNT;
+ config->format = (dir == SPH_DL) ? USB_SPH_DL_2_HAL_FMT : USB_SPH_UL_2_HAL_FMT;
+ config->rate = stream->speechRate;
+
+ // check if latency is limited by usb latency
+ stream->latency = USB_SPH_LATENCY_MS; // desire
+ if ((float)stream->latency != ceil(stream->usbLatency)) {
+ stream->latency = ceil(stream->usbLatency);
+ ALOGW("%s(), dir %d, latency limited by usb latency %f", __FUNCTION__, dir, stream->usbLatency);
+ }
+
+ config->period_size = (config->rate * stream->latency) / 1000;
+
+ config->start_threshold = 0;
+ config->stop_threshold = 0;
+ config->silence_threshold = 0;
+ config->silence_size = 0;
+
+ // decrease cold latency for pcm_write
+ if (dir == SPH_UL) {
+ config->start_threshold = config->period_size;
+ }
+
+ ALOGD("%s(), dir %d, format %d, channels %d, rate %d, period_size %d, period_count %d, start_thres %d, latency %d",
+ __FUNCTION__, dir, config->format, config->channels, config->rate,
+ config->period_size, config->period_count, config->start_threshold, stream->latency);
+
+ return 0;
+}
+
+unsigned int AudioUSBPhoneCallController::getPeriodByte(const struct pcm_config *config) {
+ return config->period_size * config->channels * (pcm_format_to_bits(config->format) / 8);
+}
+
+int AudioUSBPhoneCallController::prepareUSBStream(struct USBStream *stream) {
+ int dir = stream->direction;
+ alsa_device_profile *profile = &stream->profile;
+ alsa_device_proxy *proxy = &stream->proxy;
+ struct pcm_config proxy_config;
+ memset(&proxy_config, 0, sizeof(proxy_config));
+
+ profile_read_device_info(profile);
+ char *rateList = profile_get_sample_rate_strs(profile);
+ char *formatList = profile_get_format_strs(profile);
+ char *channelList = profile_get_channel_count_strs(profile);
+
+ ALOGD("%s(), usb dir %d, %s", __FUNCTION__, dir, rateList);
+ ALOGD("%s(), usb dir %d, %s", __FUNCTION__, dir, formatList);
+ ALOGD("%s(), usb dir %d, %s, channe count: min %u, max %u", __FUNCTION__, dir, channelList,
+ profile->min_channel_count, profile->max_channel_count);
+ ALOGD("%s(), usb dir %d, min period size %d", __FUNCTION__, dir, profile->min_period_size);
+
+ free(rateList);
+ free(formatList);
+ free(channelList);
+
+ /* use speech rate/format/channel if valid, or choose default value here */
+ /* Rate */
+ char value[PROPERTY_VALUE_MAX];
+ property_get(dir == SPH_DL ? USB_SPH_DL_RATE_PROPERTY : USB_SPH_UL_RATE_PROPERTY, value, "0");
+ unsigned int force_rate = atoi(value);
+
+ if (profile_is_sample_rate_valid(profile, force_rate)) {
+ proxy_config.rate = force_rate;
+ } else if (profile_is_sample_rate_valid(profile, stream->speechRate)) {
+ proxy_config.rate = stream->speechRate;
+ } else if (profile_is_sample_rate_valid(profile, 48000)) { // we prefer 8k base rate, and low freq for performance
+ proxy_config.rate = 48000;
+ } else if (profile_is_sample_rate_valid(profile, 32000)) {
+ proxy_config.rate = 32000;
+ } else if (profile_is_sample_rate_valid(profile, 24000)) {
+ proxy_config.rate = 24000;
+ } else {
+ proxy_config.rate = profile_get_default_sample_rate(profile);
+ }
+
+ /* Format */
+ enum pcm_format fmt = dir == SPH_DL ? USB_SPH_DL_2_HAL_FMT : USB_SPH_UL_2_HAL_FMT;
+ if (profile_is_format_valid(profile, fmt)) {
+ proxy_config.format = fmt;
+ } else {
+ proxy_config.format = profile_get_default_format(profile);
+ }
+
+ /* Channels */
+ unsigned int ch_count = dir == SPH_DL ? USB_SPH_DL_CHANNEL : USB_SPH_UL_CHANNEL;
+ if (profile_is_channel_count_valid(profile, ch_count)) {
+ proxy_config.channels = ch_count;
+ } else {
+ proxy_config.channels = profile_get_default_channel_count(profile);
+ }
+
+ // prepare proxy
+ ALOGD("%s(), proxy_config.rate %d, proxy_config.format %d, proxy_config.channels %d",
+ __FUNCTION__, proxy_config.rate, proxy_config.format, proxy_config.channels);
+ proxy_prepare(proxy, profile, &proxy_config);
+
+ // set period size / count
+ proxy->alsa_config.period_count = dir == SPH_DL ? USB_SPH_DL_2_HAL_PERIOD_CNT : USB_SPH_UL_2_HAL_PERIOD_CNT;
+
+ proxy->alsa_config.period_size = (proxy->alsa_config.rate * USB_SPH_LATENCY_MS) / 1000; // desire
+ if (proxy->alsa_config.period_size < profile->min_period_size) {
+ proxy->alsa_config.period_size = profile->min_period_size;
+ }
+
+ // decrease cold latency for pcm_write
+ if (dir == SPH_DL) {
+ proxy->alsa_config.start_threshold = proxy->alsa_config.period_size;
+ }
+
+ ALOGD("%s(), proxy rate %d, format %d, channels %d, period_count %d, period_size %d, start_thres %d",
+ __FUNCTION__, proxy->alsa_config.rate, proxy->alsa_config.format, proxy->alsa_config.channels,
+ proxy->alsa_config.period_count, proxy->alsa_config.period_size, proxy->alsa_config.start_threshold);
+
+ // open proxy
+ int ret = 0;
+ if (dir == SPH_UL) {
+ ret = proxy_open(proxy);
+ } else {
+ proxy->pcm = pcm_open(profile->card, profile->device,
+ profile->direction | PCM_MONOTONIC | PCM_NORESTART, &proxy->alsa_config);
+ if (proxy->pcm == NULL) {
+ ret = -ENOMEM;
+ }
+
+ if (!pcm_is_ready(proxy->pcm)) {
+ ALOGE(" proxy_open() pcm_open() failed: %s", pcm_get_error(proxy->pcm));
+ pcm_close(proxy->pcm);
+ proxy->pcm = NULL;
+ ret = -ENOMEM;
+ }
+
+ }
+
+ if (ret == 0) {
+ ret = pcm_prepare(proxy->pcm);
+ if (ret) {
+ ALOGE("%s(), pcm_prepare(proxy->pcm) fail, ret %d", __FUNCTION__, ret);
+ }
+ }
+
+ // calculate usb latency
+ stream->usbLatency = (proxy->alsa_config.period_size * 1000.0f) / proxy->alsa_config.rate;
+
+ ALOGD("%s(), after proxy_open, proxy rate %d, format %d, channels %d, period_count %d, period_size %d, start_thres %d, latency %f",
+ __FUNCTION__, proxy->alsa_config.rate, proxy->alsa_config.format, proxy->alsa_config.channels,
+ proxy->alsa_config.period_count, proxy->alsa_config.period_size, proxy->alsa_config.start_threshold, stream->usbLatency);
+
+ return ret;
+}
+
+void *AudioUSBPhoneCallController::speechULThread(void *arg) {
+ AudioUSBPhoneCallController *controller = static_cast<AudioUSBPhoneCallController *>(arg);
+ int ret = 0;
+ bool usbReady = true;
+
+ audio_sched_setschedule(0, SCHED_RR, sched_get_priority_min(SCHED_RR));
+
+ ALOGD("+%s(), pid: %d, tid: %d, priority %d",
+ __FUNCTION__, getpid(), gettid(), getpriority(PRIO_PROCESS, gettid()));
+
+ // setup config for capture from usb input
+ alsa_device_proxy *proxy = &controller->mUSBInStream.proxy;
+ ret = prepareUSBStream(&controller->mUSBInStream);
+ if (ret) {
+ // error handle, this should not happen
+ ALOGE("%s(), error, ret %d, USB Not Ready, ignore usb read!!", __FUNCTION__, ret);
+ usbReady = false;
+ return NULL;
+ }
+
+ FILE *pcmUSB2HALDumpFile = pcmDumpOpen(USB_SPH_DUMP_USB2HAL_NAME, USB_SPH_DUMP_UL_PROPERTY);
+
+ // setup config for capturing modem downlink data
+ struct pcm *pcmDL = NULL;
+ struct pcm_config *pcmDLConfig = &controller->mUSBInStream.pcmConfigHAL2AFE;
+
+ getSpeech2HALPcmConfig(&controller->mUSBInStream);
+
+#if defined(MTK_AUDIO_KS)
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmPlayback2);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmPlayback2);
+ controller->mUSBInStream.apTurnOnSequence = (controller->mModemIndex == MODEM_1) ? AUDIO_CTL_PLAYBACK2_TO_MD1 : AUDIO_CTL_PLAYBACK2_TO_MD2;
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(controller->mUSBInStream.apTurnOnSequence.c_str());
+#else
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceUSB);
+ int cardIdx = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVoiceUSB);
+#endif
+
+ pcmDL = pcm_open(cardIdx, pcmIdx, PCM_OUT | PCM_MONOTONIC | PCM_NORESTART, pcmDLConfig);
+ ASSERT(pcmDL != NULL && pcm_is_ready(pcmDL));
+ ret = pcm_prepare(pcmDL);
+ if (ret) {
+ ALOGE("%s(), pcm_prepare(pcmDL) fail, ret %d", __FUNCTION__, ret);
+ }
+
+ controller->mUSBInStream.pcmHAL2AFE = pcmDL;
+
+ FILE *pcmHAL2ULDumpFile = pcmDumpOpen(USB_SPH_DUMP_HAL2UL_NAME, USB_SPH_DUMP_UL_PROPERTY);
+
+ // prepare rate, format, channel conversion
+ initBliSrc(&controller->mUSBInStream);
+ initBitConverter(&controller->mUSBInStream);
+ initDataPending(&controller->mUSBInStream);
+
+ // check if use sgen
+ char value[PROPERTY_VALUE_MAX];
+ property_get(USB_SPH_UL_SGEN_TYPE_PROPERTY, value, "0");
+ int sgenType = atoi(value);
+ if (sgenType == SPH_UL_AFE_HW_SGEN) {
+ AudioALSAHardwareResourceManager::getInstance()->setSgenMode(SGEN_MODE_I07_I08);
+ }
+
+ // check if test lpbk
+ property_get(USB_SPH_LPBK_TYPE_PROPERTY, value, "0");
+ controller->mLpbkType = atoi(value);
+ controller->mLpbkStart = false;
+ controller->mLpbkTime = 0;
+ controller->mLpbkTimePart[0] = controller->mLpbkTimePart[1] = 0;
+ controller->mLpbkTimePart[2] = controller->mLpbkTimePart[3] = 0;
+ if (controller->mLpbkType) {
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(AUDIO_CTL_USB_CALL_DEBUG_LOOPBACK);
+#else
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(controller->mMixer, "USB_Voice_Loopback_Switch"), "On")) {
+ ALOGE("Error: USB_Voice_Loopback_Switch invalid value");
+ }
+#endif
+ property_get(USB_SPH_LPBK_PULSE_THRES_PROPERTY, value, "0");
+ controller->mLpbkPulseThres = atoi(value);
+ if (controller->mLpbkPulseThres == 0) {
+ controller->mLpbkPulseThres = USB_SPH_LPBK_PULSE_THRES_DEFAULT;
+ }
+ }
+
+ // start transfer data
+ unsigned int readSize = getPeriodByte(&controller->mUSBInStream.proxy.alsa_config);
+
+ // let playback buffer data level remain at around (period size * USB_SPH_FIRST_READ_PERIOD), 5 * 2 = 10ms
+ unsigned int firstReadSize = readSize * USB_SPH_FIRST_READ_PERIOD;
+ unsigned int normalReadSize = readSize;
+ bool firstRead = true;
+
+ char readBuffer[firstReadSize];
+ ALOGD("%s(), readSize = %d, sgenType %d, usbReady %d, mLpbkType %d, pulseThres 0x%x",
+ __FUNCTION__, readSize, sgenType, usbReady, controller->mLpbkType, controller->mLpbkPulseThres);
+
+ // time check
+ unsigned int writeTimes = 0;
+ struct timespec mNewTime, mOldTime;
+ double latency[3];
+ clock_gettime(CLOCK_REALTIME, &mNewTime);
+ mOldTime = mNewTime;
+ controller->mLpbkOldTime = mNewTime;
+
+ // for USB_DBG_USB_UL_ADDITIONAL_DATA_TEST
+ unsigned int totalReadSize = 0;
+ struct timespec dbgStartTime = mOldTime;
+
+ // throttle init
+ controller->mUSBInStream.throttleState = USB_THROTTLE_INIT;
+
+ while (controller->isEnable()) {
+ if (firstRead) {
+ readSize = firstReadSize;
+ firstRead = false;
+ } else {
+ readSize = normalReadSize;
+ }
+
+ // read from usb input
+ if (usbReady) {
+ ret = proxy_read(proxy, readBuffer, readSize);
+ if (ret) {
+ ALOGW("%s(), proxy_read failed, ret %d, fail due to %s, fill mute data", __FUNCTION__, ret, pcm_get_error(proxy->pcm));
+ memset(readBuffer, 0, readSize);
+
+ firstRead = true;
+ resetBliSrcBuffer(&controller->mUSBInStream);
+ ret = pcm_stop(proxy->pcm);
+ if (ret) {
+ ALOGE("%s(), pcm_stop() error, ret = %d, fail due to %s", __FUNCTION__, ret, pcm_get_error(proxy->pcm));
+ }
+
+ if (controller->mDebugType & USB_DBG_ECHO_USE_SW) {
+ AL_LOCK_MS(controller->mEchoRefStateLock, USB_SPH_ECHO_LOCK_TIMEOUT_MS);
+ controller->mEchoRefState = USB_ECHO_REF_RESET;
+ AL_UNLOCK(controller->mEchoRefStateLock);
+ }
+
+ controller->mUSBInStream.throttleState = USB_THROTTLE_RESET;
+ }
+ pcmDumpWriteData(pcmUSB2HALDumpFile, readBuffer, readSize);
+ }
+
+ // usb read time
+ clock_gettime(CLOCK_REALTIME, &mNewTime);
+ latency[0] = calc_time_diff(mNewTime, mOldTime);
+ mOldTime = mNewTime;
+
+ if (controller->mDebugType & USB_DBG_USB_UL_ADDITIONAL_DATA_TEST) {
+ double totalTime = calc_time_diff(mNewTime, dbgStartTime);
+ totalReadSize += readSize;
+
+ ALOGD("%s(), kc, time, total read time %1.6lf, totalReadSize %u, avail r %u",
+ __FUNCTION__, totalTime, totalReadSize, getPcmAvail(proxy->pcm));
+ continue;
+ }
+
+ // lpbk test
+ controller->getLpbkTime(2, readBuffer, readSize,
+ proxy->alsa_config.channels, proxy->alsa_config.rate,
+ (pcm_format_to_bits(proxy->alsa_config.format) / 8));
+
+ // bit conversion
+ void *pBufferAfterBitConvertion = NULL;
+ uint32_t bytesAfterBitConvertion = 0;
+ doBitConversion(&controller->mUSBInStream,
+ readBuffer, readSize,
+ &pBufferAfterBitConvertion, &bytesAfterBitConvertion);
+
+ // src
+ void *pBufferAfterBliSrc = NULL;
+ uint32_t bytesAfterBliSrc = 0;
+ doBliSrc(&controller->mUSBInStream,
+ pBufferAfterBitConvertion, bytesAfterBitConvertion,
+ &pBufferAfterBliSrc, &bytesAfterBliSrc);
+
+ // let output size equal one period size
+ void *pBufferAfterPending = NULL;
+ uint32_t bytesAfterPending = 0;
+ doDataPending(&controller->mUSBInStream,
+ pBufferAfterBliSrc, bytesAfterBliSrc,
+ &pBufferAfterPending, &bytesAfterPending);
+
+ void *writeBuffer = pBufferAfterPending;
+ unsigned int writeSize = bytesAfterPending;
+
+ // lpbk test
+ if (controller->mLpbkType) {
+ if (controller->mLpbkStart && controller->mLpbkType == USB_LPBK_NORMAL) {
+ if (controller->getLpbkTime(3, writeBuffer, writeSize,
+ pcmDLConfig->channels, pcmDLConfig->rate,
+ (pcm_format_to_bits(pcmDLConfig->format) / 8))) {
+ ALOGD("%s(), lpbk time total = %1.6f, part, [0] = %1.6f, [1] = %1.6f, [2] = %1.6f, [3] = %1.6f",
+ __FUNCTION__, controller->mLpbkTimePart[3],
+ controller->mLpbkTimePart[0],
+ controller->mLpbkTimePart[1] - controller->mLpbkTimePart[0],
+ controller->mLpbkTimePart[2] - controller->mLpbkTimePart[1],
+ controller->mLpbkTimePart[3] - controller->mLpbkTimePart[2]);
+
+ controller->mLpbkStart = false;
+ }
+ } else if (controller->mLpbkStart &&
+ controller->mLpbkType == USB_LPBK_PERIODIC_PULSE &&
+ controller->mLpbkTime > 0.5f) {
+ controller->mLpbkStart = false;
+ controller->mLpbkTime = 0;
+ } else {
+ clock_gettime(CLOCK_REALTIME, &controller->mLpbkNewTime);
+ controller->mLpbkTime += calc_time_diff(controller->mLpbkNewTime, controller->mLpbkOldTime);
+ controller->mLpbkOldTime = controller->mLpbkNewTime;
+ }
+
+ memset(writeBuffer, 0, writeSize);
+
+ // check every 100ms
+ if (!controller->mLpbkStart && controller->mLpbkTime > 0.1f) {
+ controller->mLpbkStart = true;
+ controller->mLpbkTime = 0;
+ controller->mLpbkTimePart[0] = controller->mLpbkTimePart[1] = 0;
+ controller->mLpbkTimePart[2] = controller->mLpbkTimePart[3] = 0;
+
+ // send pulse
+ unsigned short *tmpBuffer = (unsigned short *)writeBuffer;
+ *tmpBuffer = 0x7fff;
+ *(tmpBuffer + 1) = 0x7fff;
+
+ clock_gettime(CLOCK_REALTIME, &controller->mLpbkOldTime);
+ controller->mLpbkStartTime = controller->mLpbkOldTime;
+ }
+ }
+
+ // replace read buffer with sgen
+ if (!usbReady || sgenType == SPH_UL_SW_SGEN) {
+ uint16_t *tmpBuffer = (uint16_t *)writeBuffer;
+ for (unsigned int i = 0; i < writeSize / 2; i = i + 2) {
+ *(tmpBuffer + i) = table_1k_tone_16000_hz[(i / 2) % kNumElmSinewaveTable];
+ *(tmpBuffer + i + 1) = table_1k_tone_16000_hz[(i / 2) % kNumElmSinewaveTable];
+ }
+ }
+
+ // dump
+ pcmDumpWriteData(pcmHAL2ULDumpFile, writeBuffer, writeSize);
+
+ // processing time
+ clock_gettime(CLOCK_REALTIME, &mNewTime);
+ latency[1] = calc_time_diff(mNewTime, mOldTime);
+ mOldTime = mNewTime;
+
+ // write to AFE
+ ret = pcm_write(pcmDL, writeBuffer, writeSize);
+ if (ret) {
+ ALOGE("%s(), pcm_write() error, ret = %d", __FUNCTION__, ret);
+ if (ret == -EPIPE) {
+ if (controller->mDebugType & USB_DBG_ASSERT_AT_STOP_UL) {
+#ifdef HAVE_AEE_FEATURE
+ aee_system_exception(LOG_TAG, NULL, DB_OPT_FTRACE,
+ " %s, %uL, %s(), underrun", strrchr(__FILE__, '/') + 1, __LINE__, __FUNCTION__);
+#endif
+ }
+
+ firstRead = true;
+ resetBliSrcBuffer(&controller->mUSBInStream);
+ ret = pcm_stop(proxy->pcm);
+ if (ret) {
+ ALOGE("%s(), pcm_stop() error, ret = %d, fail due to %s", __FUNCTION__, ret, pcm_get_error(proxy->pcm));
+ }
+
+ controller->mUSBInStream.throttleState = USB_THROTTLE_RESET;
+ }
+ }
+
+ // throttle Control
+ if ((controller->mDebugType & USB_DBG_UL_DISABLE_THROTTLE) == 0) {
+ throttleControl(&controller->mUSBInStream);
+ }
+
+ // hal 2 ul time
+ clock_gettime(CLOCK_REALTIME, &mNewTime);
+ latency[2] = calc_time_diff(mNewTime, mOldTime);
+ mOldTime = mNewTime;
+ writeTimes++;
+
+ if ((latency[0] + latency[1] + latency[2]) * 1000 >= 2 * controller->mUSBInStream.latency ||
+ latency[0] * 1000 > controller->mUSBInStream.latency * USB_SPH_LATENCY_LOG_RATIO ||
+ latency[2] * 1000 > controller->mUSBInStream.latency * USB_SPH_LATENCY_LOG_RATIO ||
+ controller->mDebugType & USB_DBG_UL_TIME_PROFILE) {
+ if (controller->mDebugType & USB_DBG_BUFFER_LEVEL) {
+ ALOGD("%s(), time, read %1.6lf, process %1.6lf, write %1.6lf, writeTimes %d, writeSize %u, avail r %u, w %u",
+ __FUNCTION__, latency[0], latency[1], latency[2], writeTimes, writeSize,
+ getPcmAvail(proxy->pcm), getPcmAvail(pcmDL));
+ } else {
+ ALOGD("%s(), time, read %1.6lf, process %1.6lf, write %1.6lf, writeTimes %d, writeSize %u",
+ __FUNCTION__, latency[0], latency[1], latency[2], writeTimes, writeSize);
+ }
+ }
+ }
+
+ setDebugInfo(false, USB_DBG_ALL);
+
+ if (controller->mLpbkType) {
+ controller->mLpbkStart = false;
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(AUDIO_CTL_USB_CALL_DEBUG_LOOPBACK);
+#else
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(controller->mMixer, "USB_Voice_Loopback_Switch"), "Off")) {
+ ALOGE("Error: USB_Voice_Loopback_Switch invalid value");
+ }
+#endif
+ }
+
+ if (sgenType == SPH_UL_AFE_HW_SGEN) {
+ AudioALSAHardwareResourceManager::getInstance()->setSgenMode(SGEN_MODE_DISABLE);
+ }
+
+ //
+ deinitBliSrc(&controller->mUSBInStream);
+ deinitBitConverter(&controller->mUSBInStream);
+ deinitDataPending(&controller->mUSBInStream);
+
+ // close usb
+ pcmDumpClose(pcmUSB2HALDumpFile);
+ proxy_close(proxy);
+
+ // close audio hw
+ pcmDumpClose(pcmHAL2ULDumpFile);
+
+ pcm_stop(pcmDL);
+ pcm_close(pcmDL);
+ controller->mUSBInStream.pcmHAL2AFE = NULL;
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(controller->mUSBInStream.apTurnOnSequence.c_str());
+#endif
+
+ ALOGD("-%s(), pid: %d, tid: %d, scheduler %d", __FUNCTION__, getpid(), gettid(), sched_getscheduler(0));
+ return NULL;
+}
+
+int AudioUSBPhoneCallController::speechULPhoneMicPath(bool enable) {
+ ALOGD("%s(), enable %d", __FUNCTION__, enable);
+
+#if defined(MTK_AUDIO_KS)
+ String8 apTurnOnSequence = String8(mModemIndex == MODEM_1 ? AUDIO_CTL_ADDA_UL_TO_MD1 : AUDIO_CTL_ADDA_UL_TO_MD2);
+
+ if (enable) {
+ struct pcm_config config;
+ memset(&config, 0, sizeof(config));
+ config.channels = 2;
+ config.rate = mSpeechRate;
+ config.period_size = 1024;
+ config.period_count = 2;
+ config.format = USB_SPH_DL_2_HAL_FMT;
+ config.stop_threshold = ~(0U);
+
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(apTurnOnSequence);
+
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessSpeech);
+ int cardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmHostlessSpeech);
+
+ ASSERT(mPcmMicOut == NULL && mPcmMicIn == NULL);
+ mPcmMicIn = pcm_open(cardIndex, pcmIdx, PCM_IN, &config);
+ mPcmMicOut = pcm_open(cardIndex, pcmIdx, PCM_OUT, &config);
+ ASSERT(mPcmMicOut != NULL && mPcmMicIn != NULL);
+
+ AudioALSAHardwareResourceManager::getInstance()->startInputDevice(USB_SPH_PRIMARY_IN_DEVICE);
+
+ if (mPcmMicIn == NULL || pcm_is_ready(mPcmMicIn) == false) {
+ ALOGE("%s(), Unable to open mPcmMicIn device %u (%s)", __FUNCTION__, pcmIdx, pcm_get_error(mPcmMicIn));
+ } else {
+ if (pcm_start(mPcmMicIn)) {
+ ALOGE("%s(), pcm_start mPcmMicIn %p fail due to %s", __FUNCTION__, mPcmMicIn, pcm_get_error(mPcmMicIn));
+ }
+ }
+
+ if (mPcmMicOut == NULL || pcm_is_ready(mPcmMicOut) == false) {
+ ALOGE("%s(), Unable to open mPcmMicOut device %u (%s)", __FUNCTION__, pcmIdx, pcm_get_error(mPcmMicOut));
+ } else {
+ if (pcm_start(mPcmMicOut)) {
+ ALOGE("%s(), pcm_start mPcmMicOut %p fail due to %s", __FUNCTION__, mPcmMicOut, pcm_get_error(mPcmMicOut));
+ }
+ }
+ } else {
+ if (mPcmMicIn != NULL) {
+ pcm_stop(mPcmMicIn);
+ pcm_close(mPcmMicIn);
+ mPcmMicIn = NULL;
+ }
+
+ if (mPcmMicOut != NULL) {
+ pcm_stop(mPcmMicOut);
+ pcm_close(mPcmMicOut);
+ mPcmMicOut = NULL;
+ }
+
+ AudioALSAHardwareResourceManager::getInstance()->stopInputDevice(USB_SPH_PRIMARY_IN_DEVICE);
+
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(apTurnOnSequence);
+ }
+#endif
+ return 0;
+}
+
+int AudioUSBPhoneCallController::setEchoRefPath(bool enable, int stage) {
+ ALOGD("%s(), enable %d, stage %d", __FUNCTION__, enable, stage);
+
+#if defined(MTK_AUDIO_KS)
+ String8 echoRefOutSequence = String8(mModemIndex == MODEM_1 ? AUDIO_CTL_PLAYBACK1_TO_MD1_CH4 : AUDIO_CTL_PLAYBACK1_TO_MD2_CH4);
+ String8 echoRefInSequence = String8(mModemIndex == MODEM_1 ? AUDIO_CTL_MD1_TO_CAPTURE_MONO_1 : AUDIO_CTL_MD2_TO_CAPTURE_MONO_1);
+
+ if (enable) {
+ unsigned int delayUs = getEchoCurrentDelayUs();
+
+ struct pcm_config config;
+ memset(&config, 0, sizeof(config));
+ config.channels = 2;
+ config.rate = mSpeechRate;
+ config.format = USB_SPH_DL_2_HAL_FMT;
+ config.period_count = 2;
+
+ // calculate period size for delay
+ unsigned int formatSize = pcm_format_to_bits(config.format) / 8;
+ // calculate buffer size and make it align
+ unsigned long long bufferSize = (((unsigned long long)delayUs * config.rate) / 1000000) / config.period_count;
+ bufferSize = wordSizeAlign(bufferSize * config.period_count * config.channels * formatSize);
+
+ config.period_size = ((bufferSize / config.period_count) / config.channels) / formatSize;
+
+ if (stage == 1) {
+ // stage 1, outside of while loop, since this may consume many time
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(echoRefOutSequence);
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(echoRefInSequence);
+
+ int pcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmPlayback1);
+ int pcmInIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmCaptureMono1);
+ int cardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmPlayback1);
+
+ /* usb use dram */
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "primary_play_scenario"), 0, 1)) {
+ ALOGW("%s(), primary_play_scenario enable fail", __FUNCTION__);
+ }
+
+ ASSERT(mPcmEchoRefOut == NULL && mPcmEchoRefIn == NULL);
+ mPcmEchoRefIn = pcm_open(cardIndex, pcmInIdx, PCM_IN, &config);
+ mPcmEchoRefOut = pcm_open(cardIndex, pcmOutIdx, PCM_OUT, &config);
+ ASSERT(mPcmEchoRefOut != NULL && mPcmEchoRefIn != NULL);
+
+ int ret = pcm_prepare(mPcmEchoRefOut);
+ if (ret) {
+ ALOGE("%s(), pcm_prepare(mPcmEchoRefOut) fail, ret %d", __FUNCTION__, ret);
+ }
+ } else if (stage == 2) {
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "usb_call_echo_ref"), 0, bufferSize)) {
+ ALOGE("Error: usb_call_echo_ref invalid value");
+ }
+ }
+ } else {
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "usb_call_echo_ref"), 0, 0)) {
+ ALOGE("Error: usb_call_echo_ref invalid value");
+ }
+
+ if (mPcmEchoRefIn != NULL) {
+ pcm_close(mPcmEchoRefIn);
+ mPcmEchoRefIn = NULL;
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(echoRefInSequence);
+ }
+
+ if (mPcmEchoRefOut != NULL) {
+ pcm_close(mPcmEchoRefOut);
+ mPcmEchoRefOut = NULL;
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(echoRefOutSequence);
+ }
+
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "primary_play_scenario"), 0, 0)) {
+ ALOGW("%s(), primary_play_scenario disable fail", __FUNCTION__);
+ }
+ }
+#else
+ if (enable) {
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "USB_Voice_Echo_Ref"), 0, 0)) {
+ ALOGW("%s(), reset USB_Voice_Echo_Ref fail", __FUNCTION__);
+ }
+ // enable echo ref with delay
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "USB_Voice_Echo_Ref"), 0, getEchoCurrentDelayUs())) {
+ ALOGW("%s(), reset USB_Voice_Echo_Ref %u fail", __FUNCTION__, getEchoCurrentDelayUs());
+ }
+ } else {
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "USB_Voice_Echo_Ref"), 0, 0)) {
+ ALOGW("%s(), disable USB_Voice_Echo_Ref fail", __FUNCTION__);
+ }
+ }
+#endif
+ return 0;
+}
+
+int AudioUSBPhoneCallController::setEchoRefDebugPath(bool enable) {
+ ALOGD("%s(), enable %d", __FUNCTION__, enable);
+#if defined(MTK_AUDIO_KS)
+ String8 apTurnOnSequence = String8(AUDIO_CTL_USB_ECHO_REF_DEBUG);
+
+ if (enable) {
+ struct pcm_config config;
+ memset(&config, 0, sizeof(config));
+ config.channels = 2;
+ config.rate = mSpeechRate;
+ config.period_size = 1024;
+ config.period_count = 2;
+ config.format = USB_SPH_DL_2_HAL_FMT;
+ config.stop_threshold = ~(0U);
+
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(apTurnOnSequence);
+
+ int pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessADDADLI2SOut);
+ int cardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmHostlessADDADLI2SOut);
+
+ ASSERT(mPcmEchoRefDebugOut == NULL);
+ mPcmEchoRefDebugOut = pcm_open(cardIndex, pcmIdx, PCM_OUT, &config);
+ ASSERT(mPcmEchoRefDebugOut != NULL);
+
+ if (mPcmEchoRefDebugOut == NULL || pcm_is_ready(mPcmEchoRefDebugOut) == false) {
+ ALOGE("%s(), Unable to open mPcmEchoRefDebugOut device %u (%s)",
+ __FUNCTION__, pcmIdx, pcm_get_error(mPcmEchoRefDebugOut));
+ } else {
+ if (pcm_start(mPcmEchoRefDebugOut)) {
+ ALOGE("%s(), pcm_start mPcmEchoRefDebugOut %p fail due to %s",
+ __FUNCTION__, mPcmEchoRefDebugOut, pcm_get_error(mPcmEchoRefDebugOut));
+ }
+ }
+
+ /* adda ul -> adda dl */
+ pcmIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessLpbk);
+ cardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmHostlessLpbk);
+
+ ASSERT(mPcmEchoRefDebugOut2 == NULL);
+ mPcmEchoRefDebugOut2 = pcm_open(cardIndex, pcmIdx, PCM_OUT, &config);
+ ASSERT(mPcmEchoRefDebugOut2 != NULL);
+
+ if (mPcmEchoRefDebugOut2 == NULL || pcm_is_ready(mPcmEchoRefDebugOut2) == false) {
+ ALOGE("%s(), Unable to open mPcmEchoRefDebugOut2 device %u (%s)",
+ __FUNCTION__, pcmIdx, pcm_get_error(mPcmEchoRefDebugOut2));
+ } else {
+ if (pcm_start(mPcmEchoRefDebugOut2)) {
+ ALOGE("%s(), pcm_start mPcmEchoRefDebugOut2 %p fail due to %s",
+ __FUNCTION__, mPcmEchoRefDebugOut2, pcm_get_error(mPcmEchoRefDebugOut2));
+ }
+ }
+
+ AudioALSAHardwareResourceManager::getInstance()->startOutputDevice(AUDIO_DEVICE_OUT_WIRED_HEADSET, getSpeechRate());
+ } else {
+ AudioALSAHardwareResourceManager::getInstance()->stopOutputDevice();
+
+ if (mPcmEchoRefDebugOut != NULL) {
+ pcm_stop(mPcmEchoRefDebugOut);
+ pcm_close(mPcmEchoRefDebugOut);
+ mPcmEchoRefDebugOut = NULL;
+ }
+
+ if (mPcmEchoRefDebugOut2 != NULL) {
+ pcm_stop(mPcmEchoRefDebugOut2);
+ pcm_close(mPcmEchoRefDebugOut2);
+ mPcmEchoRefDebugOut2 = NULL;
+ }
+
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(apTurnOnSequence);
+ }
+#endif
+ return 0;
+}
+
+// dump file
+FILE *AudioUSBPhoneCallController::pcmDumpOpen(const char *name, const char *property) {
+ static unsigned int dumpFileCount = 0;
+
+ ALOGV("%s()", __FUNCTION__);
+ FILE *file = NULL;
+ char dumpFileName[128];
+ sprintf(dumpFileName, "%s.%s.%u.pid%d.tid%d.pcm", USB_SPH_DUMP_FILE_PREFIX, name, dumpFileCount, getpid(), gettid());
+
+ file = NULL;
+ file = AudioOpendumpPCMFile(dumpFileName, property);
+
+ if (file != NULL) {
+ ALOGD("%s DumpFileName = %s", __FUNCTION__, dumpFileName);
+
+ dumpFileCount++;
+ dumpFileCount %= MAX_DUMP_NUM;
+ }
+
+ return file;
+}
+
+void AudioUSBPhoneCallController::pcmDumpClose(FILE *file) {
+ ALOGV("%s()", __FUNCTION__);
+ if (file) {
+ AudioCloseDumpPCMFile(file);
+ ALOGD("%s(), close it", __FUNCTION__);
+ }
+}
+
+void AudioUSBPhoneCallController::pcmDumpWriteData(FILE *file, const void *buffer, size_t bytes) {
+ if (file) {
+ AudioDumpPCMData((void *)buffer, bytes, file);
+ }
+}
+
+static const uint32_t kBliSrcOutputBufferSize = 0x10000; // 64k
+status_t AudioUSBPhoneCallController::initBliSrc(struct USBStream *stream) {
+ alsa_device_proxy *proxy = &stream->proxy;
+ unsigned int sourceRate, targetRate;
+ unsigned int sourceChannels, targetChannels;
+ audio_format_t format;
+ if (stream->direction == SPH_DL) {
+ sourceRate = stream->pcmConfigHAL2AFE.rate;
+ sourceChannels = stream->pcmConfigHAL2AFE.channels;
+ format = audio_format_from_pcm_format(stream->pcmConfigHAL2AFE.format);
+
+ targetRate = proxy_get_sample_rate(proxy);
+ targetChannels = proxy_get_channel_count(proxy);
+ } else {
+ sourceRate = proxy_get_sample_rate(proxy);
+ sourceChannels = proxy_get_channel_count(proxy);
+ // usb format may not suport by blisrc, will apply bit convert first for SPH_UL
+ format = audio_format_from_pcm_format(USB_SPH_UL_2_HAL_FMT);
+
+ targetRate = stream->pcmConfigHAL2AFE.rate;
+ targetChannels = stream->pcmConfigHAL2AFE.channels;
+ }
+
+ // always create src for throttle control
+ // if (sourceRate != targetRate || sourceChannels != targetChannels)
+ // {
+ ALOGD("%s(), dir %d, sample_rate: %d => %d, num_channels: %d => %d, mStreamAttributeSource->audio_format: 0x%x",
+ __FUNCTION__, stream->direction, sourceRate, targetRate, sourceChannels, targetChannels, format);
+
+ SRC_PCM_FORMAT src_pcm_format = SRC_IN_Q1P15_OUT_Q1P15;
+ if (format == AUDIO_FORMAT_PCM_32_BIT) {
+ src_pcm_format = SRC_IN_Q1P31_OUT_Q1P31;
+ } else if (format == AUDIO_FORMAT_PCM_16_BIT) {
+ src_pcm_format = SRC_IN_Q1P15_OUT_Q1P15;
+ } else {
+ ALOGE("%s(), not support mStreamAttributeSource->audio_format(0x%x) SRC!!", __FUNCTION__, format);
+ ASSERT(0);
+ }
+
+ stream->blisrc = newMtkAudioSrc(sourceRate, sourceChannels,
+ targetRate, targetChannels,
+ src_pcm_format);
+ ASSERT(stream->blisrc != NULL);
+ stream->blisrc->open();
+
+ stream->blisrcOutBuffer = new char[kBliSrcOutputBufferSize];
+ ASSERT(stream->blisrcOutBuffer != NULL);
+ // }
+
+ return NO_ERROR;
+}
+
+status_t AudioUSBPhoneCallController::deinitBliSrc(struct USBStream *stream) {
+ // deinit BLI SRC if need
+ if (stream->blisrc != NULL) {
+ stream->blisrc->close();
+ delete stream->blisrc;
+ stream->blisrc = NULL;
+ }
+
+ if (stream->blisrcOutBuffer != NULL) {
+ delete[] stream->blisrcOutBuffer;
+ stream->blisrcOutBuffer = NULL;
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioUSBPhoneCallController::doBliSrc(struct USBStream *stream, void *pInBuffer, uint32_t inBytes,
+ void **ppOutBuffer, uint32_t *pOutBytes) {
+ if (stream->blisrc == NULL) { // No need SRC
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ } else {
+ char *p_read = (char *)pInBuffer;
+ uint32_t num_raw_data_left = inBytes;
+ uint32_t num_converted_data = kBliSrcOutputBufferSize; // max convert num_free_space
+
+ uint32_t consumed = num_raw_data_left;
+ stream->blisrc->process((int16_t *)p_read, &num_raw_data_left,
+ (int16_t *)stream->blisrcOutBuffer, &num_converted_data);
+ consumed -= num_raw_data_left;
+ p_read += consumed;
+
+ ALOGV("%s(), num_raw_data_left = %u, num_converted_data = %u",
+ __FUNCTION__, num_raw_data_left, num_converted_data);
+
+ if (num_raw_data_left > 0) {
+ ALOGW("%s(), num_raw_data_left(%u) > 0", __FUNCTION__, num_raw_data_left);
+ ASSERT(num_raw_data_left == 0);
+ }
+
+ *ppOutBuffer = stream->blisrcOutBuffer;
+ *pOutBytes = num_converted_data;
+ }
+
+ ASSERT(*ppOutBuffer != NULL && *pOutBytes != 0);
+ return NO_ERROR;
+}
+
+status_t AudioUSBPhoneCallController::resetBliSrcBuffer(struct USBStream *stream) {
+ if (stream->blisrc) {
+ stream->blisrc->resetBuffer();
+ }
+
+ return NO_ERROR;
+}
+
+unsigned int AudioUSBPhoneCallController::getBitConvertDstBufferSize(audio_format_t dstFmt,
+ audio_format_t srcFmt,
+ unsigned int srcBufSizeByte) {
+ size_t dstFmtByte = audio_bytes_per_sample(dstFmt);
+ size_t srcFmtByte = audio_bytes_per_sample(srcFmt);
+
+ if (dstFmtByte == 0) {
+ ALOGE("%s(), invalid dstFmt %d, dstFmtByte = %zu", __FUNCTION__, dstFmt, dstFmtByte);
+ ASSERT(0);
+ dstFmtByte = audio_bytes_per_sample(AUDIO_FORMAT_PCM_16_BIT);
+ }
+
+ if (srcFmtByte == 0) {
+ ALOGE("%s(), invalid srcFmt %d, srcFmtByte = %zu", __FUNCTION__, srcFmt, srcFmtByte);
+ ASSERT(0);
+ srcFmtByte = audio_bytes_per_sample(AUDIO_FORMAT_PCM_16_BIT);
+ }
+
+ return (srcBufSizeByte * dstFmtByte) / srcFmtByte;
+}
+
+static const uint32_t kMaxBitConvertBufferSize = 0x10000; // 64k
+status_t AudioUSBPhoneCallController::initBitConverter(struct USBStream *stream) {
+
+ if (stream->direction == SPH_DL) {
+ stream->dstFmt = audio_format_from_pcm_format(proxy_get_format(&stream->proxy));
+ stream->srcFmt = audio_format_from_pcm_format(stream->pcmConfigHAL2AFE.format);
+ } else {
+ stream->dstFmt = audio_format_from_pcm_format(stream->pcmConfigHAL2AFE.format);
+ stream->srcFmt = audio_format_from_pcm_format(proxy_get_format(&stream->proxy));
+ }
+
+ // init bit converter if need
+ if (stream->srcFmt != stream->dstFmt) {
+ ALOGD("%s(), format: 0x%x => 0x%x", __FUNCTION__, stream->srcFmt, stream->dstFmt);
+ stream->bitConvertBuffer = new char[kMaxBitConvertBufferSize];
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioUSBPhoneCallController::deinitBitConverter(struct USBStream *stream) {
+ // deinit bit converter if need
+ if (stream->bitConvertBuffer != NULL) {
+ delete[] stream->bitConvertBuffer;
+ stream->bitConvertBuffer = NULL;
+ }
+
+ return NO_ERROR;
+}
+
+
+status_t AudioUSBPhoneCallController::doBitConversion(struct USBStream *stream,
+ void *pInBuffer, uint32_t inBytes,
+ void **ppOutBuffer, uint32_t *pOutBytes) {
+ if (stream->bitConvertBuffer != NULL) {
+ audio_format_t dstFmt = stream->dstFmt;
+ audio_format_t srcFmt = stream->srcFmt;
+ unsigned int srcSizeBytes = inBytes;
+
+ size_t srcFmtByte = audio_bytes_per_sample(srcFmt);
+ if (srcFmtByte == 0) {
+ ALOGE("%s(), invalid srcFmt %d, srcFmtByte = %zu", __FUNCTION__, srcFmt, srcFmtByte);
+ ASSERT(0);
+ srcFmtByte = audio_bytes_per_sample(AUDIO_FORMAT_PCM_16_BIT);
+ }
+ unsigned int srcNumSample = srcSizeBytes / srcFmtByte;
+ void *srcBuffer = pInBuffer;
+ unsigned int bitConvertBufferSizeByte = getBitConvertDstBufferSize(dstFmt, srcFmt, srcSizeBytes);
+
+ ALOGV("%s(), bit convert, format: 0x%x => 0x%x, srcNumSample %d, src size %d, dst size %d",
+ __FUNCTION__, srcFmt, dstFmt, srcNumSample, srcSizeBytes, bitConvertBufferSizeByte);
+ memcpy_by_audio_format(stream->bitConvertBuffer,
+ dstFmt,
+ srcBuffer,
+ srcFmt,
+ srcNumSample);
+
+
+ *pOutBytes = bitConvertBufferSizeByte;
+ *ppOutBuffer = stream->bitConvertBuffer;
+ } else {
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ }
+
+ ASSERT(*ppOutBuffer != NULL && *pOutBytes != 0);
+ return NO_ERROR;
+}
+
+// data pending
+
+// TODO: kc: use 8 will, audio playback will have issue
+static const unsigned int kDataAlignedSize = 16; /* sram (device memory) need 8 byte algin for arm64*/
+status_t AudioUSBPhoneCallController::initDataPending(struct USBStream *stream) {
+ if (stream->blisrc != NULL) {
+ unsigned int rate;
+ unsigned int ch;
+ unsigned int fmt_max_bytes = 4;
+ unsigned int max_write_ms = USB_SPH_LATENCY_MS * USB_SPH_FIRST_READ_PERIOD * 2; // 2 for safety, data after src may increase
+
+ if (stream->direction == SPH_DL) {
+ alsa_device_proxy *proxy = &stream->proxy;
+ rate = proxy_get_sample_rate(proxy);
+ ch = proxy_get_channel_count(proxy);
+ } else {
+ rate = stream->pcmConfigHAL2AFE.rate;
+ ch = stream->pcmConfigHAL2AFE.channels;
+ }
+
+ stream->dataPendingOutBufSize = (max_write_ms * rate * 0.001 * ch * fmt_max_bytes) + kDataAlignedSize;
+
+ stream->dataPendingOutBuffer = new char[stream->dataPendingOutBufSize];
+ stream->dataPendingTempBuffer = new char[kDataAlignedSize];
+ ASSERT(stream->dataPendingOutBuffer != NULL);
+
+ ALOGD("%s(), PendingOutBufSize %u, PendingOutBuffer %p, PendingTempBuffer %p",
+ __FUNCTION__,
+ stream->dataPendingOutBufSize,
+ stream->dataPendingOutBuffer,
+ stream->dataPendingTempBuffer);
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioUSBPhoneCallController::deinitDataPending(struct USBStream *stream) {
+ ALOGD("%s()", __FUNCTION__);
+ if (stream->dataPendingOutBuffer != NULL) {
+ delete[] stream->dataPendingOutBuffer;
+ stream->dataPendingOutBuffer = NULL;
+ }
+ if (stream->dataPendingTempBuffer != NULL) {
+ delete[] stream->dataPendingTempBuffer;
+ stream->dataPendingTempBuffer = NULL;
+ }
+ stream->dataPendingOutBufSize = 0;
+ stream->dataPendingRemainBufSize = 0;
+ return NO_ERROR;
+
+}
+
+// let output size equal one period size
+status_t AudioUSBPhoneCallController::doDataPending(struct USBStream *stream,
+ void *pInBuffer, uint32_t inBytes,
+ void **ppOutBuffer, uint32_t *pOutBytes) {
+ char *DataPointer = (char *)stream->dataPendingOutBuffer;
+ char *DatainputPointer = (char *)pInBuffer;
+ uint32 TotalBufferSize = inBytes + stream->dataPendingRemainBufSize;
+ uint32 tempRemind = TotalBufferSize % kDataAlignedSize;
+ uint32 TotalOutputSize = TotalBufferSize - tempRemind;
+ uint32 TotalOutputCount = TotalOutputSize;
+ if (stream->dataPendingOutBuffer != NULL) { // do data pending
+ //ALOGD("inBytes = %d mdataPendingRemindBufferSize = %d TotalOutputSize = %d",inBytes,mdataPendingRemindBufferSize,TotalOutputSize);
+ if (stream->dataPendingRemainBufSize != 0) { // deal previous remaind buffer
+ memcpy((void *)DataPointer, (void *)stream->dataPendingTempBuffer, stream->dataPendingRemainBufSize);
+ DataPointer += stream->dataPendingRemainBufSize;
+ TotalOutputCount -= stream->dataPendingRemainBufSize;
+ }
+
+ //deal with input buffer
+ memcpy((void *)DataPointer, pInBuffer, TotalOutputCount);
+ DataPointer += TotalOutputCount;
+ DatainputPointer += TotalOutputCount;
+ TotalOutputCount = 0;
+
+ // update pointer and data count
+ *ppOutBuffer = stream->dataPendingOutBuffer;
+ *pOutBytes = TotalOutputSize;
+
+ //ALOGD("tempRemind = %d pOutBytes = %d",tempRemind,*pOutBytes);
+
+ // deal with remind buffer
+ memcpy((void *)stream->dataPendingTempBuffer, (void *)DatainputPointer, tempRemind);
+ stream->dataPendingRemainBufSize = tempRemind;
+ } else {
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ }
+
+ ASSERT(*ppOutBuffer != NULL && *pOutBytes != 0);
+ return NO_ERROR;
+}
+
+unsigned int AudioUSBPhoneCallController::getStreamWriteRate(struct USBStream *stream) {
+ return stream->direction == SPH_DL ? stream->proxy.alsa_config.rate : stream->pcmConfigHAL2AFE.rate;
+}
+
+unsigned int AudioUSBPhoneCallController::getStreamReadRate(struct USBStream *stream) {
+ return stream->direction == SPH_DL ? stream->pcmConfigHAL2AFE.rate : stream->proxy.alsa_config.rate;
+}
+
+status_t AudioUSBPhoneCallController::throttleInit(struct USBStream *stream) {
+ struct pcm *pcm = stream->direction == SPH_DL ? stream->proxy.pcm : stream->pcmHAL2AFE;
+
+ stream->throttleState = USB_THROTTLE_STEADY;
+
+ if (pcm != NULL) {
+ stream->throttleTargetAvail = getPcmAvail(pcm);
+ if (stream->throttleTargetAvail == USB_SPH_INVALID_AVAIL) {
+ stream->throttleState = USB_THROTTLE_INIT;
+ }
+ } else {
+ ALOGW("%s(), dir %d, pcm == NULL", __FUNCTION__, stream->direction);
+ stream->throttleState = USB_THROTTLE_INIT;
+ }
+
+ unsigned int writeRate = getStreamWriteRate(stream);
+ stream->throttleKickInAvailDiff = USB_SPH_THROTTLE_KICK_IN_DIFF_MS * writeRate / 1000;
+ stream->throttleSteadyAvailDiff = USB_SPH_THROTTLE_STEADY_DIFF_US * writeRate / 1000000;
+ stream->throttleKickInCount = 0;
+
+ throttleResetCurrentRate(stream);
+
+ ALOGD("%s(), dir %d, state %d, TargetAvail %u, KickInAvailDiff %u, current in rate %u",
+ __FUNCTION__,
+ stream->direction,
+ stream->throttleState,
+ stream->throttleTargetAvail,
+ stream->throttleKickInAvailDiff,
+ stream->throttleCurrentInRate);
+
+ return NO_ERROR;
+}
+
+status_t AudioUSBPhoneCallController::throttleReset(struct USBStream *stream) {
+ throttleResetCurrentRate(stream);
+
+ resetBliSrcBuffer(stream);
+
+ stream->throttleState = USB_THROTTLE_INIT;
+
+ return NO_ERROR;
+}
+
+status_t AudioUSBPhoneCallController::throttleSetSrcInRate(struct USBStream *stream, unsigned int rate) {
+ stream->throttleCurrentInRate = rate;
+ stream->blisrc->setParameter(SRC_PAR_SET_INPUT_SAMPLE_RATE, (void *)((long)rate));
+ return NO_ERROR;
+}
+
+status_t AudioUSBPhoneCallController::throttleResetCurrentRate(struct USBStream *stream) {
+ throttleSetSrcInRate(stream, getStreamReadRate(stream));
+ return NO_ERROR;
+}
+
+status_t AudioUSBPhoneCallController::throttleSetCompensateInRate(struct USBStream *stream,
+ unsigned int changeMsPerSecond,
+ int state) {
+ float rateFactor = state == USB_THROTTLE_INCREASE ? (1 - 0.001f * changeMsPerSecond) : (1 + 0.001f * changeMsPerSecond);
+
+ throttleSetSrcInRate(stream, getStreamReadRate(stream) * rateFactor);
+
+ ALOGV("%s(), dir %d, current in rate %u, state %d, changeMsPerSecond %u",
+ __FUNCTION__,
+ stream->direction,
+ stream->throttleCurrentInRate,
+ state,
+ changeMsPerSecond);
+
+ return NO_ERROR;
+}
+
+status_t AudioUSBPhoneCallController::throttleControl(struct USBStream *stream) {
+ if (stream->throttleState == USB_THROTTLE_INIT) {
+ throttleInit(stream);
+ } else if (stream->throttleState == USB_THROTTLE_RESET) {
+ throttleReset(stream);
+ } else {
+ struct pcm *pcm = stream->direction == SPH_DL ? stream->proxy.pcm : stream->pcmHAL2AFE;
+ unsigned int curAvail;
+
+ if (pcm != NULL) {
+ curAvail = getPcmAvail(pcm);
+ if (curAvail == USB_SPH_INVALID_AVAIL) {
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ ALOGW("%s(), dir %d, pcm == NULL", __FUNCTION__, stream->direction);
+ return UNKNOWN_ERROR;
+ }
+
+ if (curAvail > stream->throttleTargetAvail &&
+ curAvail >= stream->throttleTargetAvail + stream->throttleKickInAvailDiff) {
+ // try increase data in write buffer
+ if (stream->throttleState == USB_THROTTLE_INCREASE) {
+ // already in increase state, check if SRC compensation is fast enough
+ if (curAvail - stream->throttleTargetAvail > stream->throttleOrigAvailDiff) {
+ stream->throttleSpeedUpCount++;
+
+ if (stream->throttleSpeedUpCount >= USB_SPH_THROTTLE_SPEED_UP_COUNT) {
+ stream->throttleSpeedUpFactor++;
+ ALOGW("%s(), increase, dir %d, compensation not fast enough, increase factor by %d, cur %u, orig diff %u avail",
+ __FUNCTION__, stream->direction, stream->throttleSpeedUpFactor,
+ curAvail, stream->throttleOrigAvailDiff);
+
+ throttleSetCompensateInRate(stream,
+ USB_SPH_THROTTLE_MS_CHANGE_PER_SECOND * stream->throttleSpeedUpFactor,
+ USB_THROTTLE_INCREASE);
+ stream->throttleSpeedUpCount = 0;
+ stream->throttleOrigAvailDiff = curAvail - stream->throttleTargetAvail;
+ }
+ } else {
+ stream->throttleSpeedUpCount = 0;
+ }
+ } else {
+ stream->throttleKickInCount++;
+ if (stream->throttleKickInCount >= USB_SPH_THROTTLE_KICK_IN_COUNT) {
+ if (stream->throttleState != USB_THROTTLE_STEADY) {
+ ALOGW("%s(), increase, dir %d, shouldn't be in this state %d",
+ __FUNCTION__, stream->direction, stream->throttleState);
+ }
+
+ stream->throttleState = USB_THROTTLE_INCREASE;
+
+ stream->throttleSpeedUpFactor = 1;
+ stream->throttleSpeedUpCount = 0;
+ stream->throttleKickInCount = 0;
+ stream->throttleOrigAvailDiff = curAvail - stream->throttleTargetAvail;
+
+ throttleSetCompensateInRate(stream,
+ USB_SPH_THROTTLE_MS_CHANGE_PER_SECOND * stream->throttleSpeedUpFactor,
+ USB_THROTTLE_INCREASE);
+
+ ALOGD("%s(), increase, dir %d, factor %d, cur %u, orig diff %u avail",
+ __FUNCTION__, stream->direction, stream->throttleSpeedUpFactor,
+ curAvail, stream->throttleOrigAvailDiff);
+ }
+ }
+ } else if (curAvail < stream->throttleTargetAvail &&
+ curAvail + stream->throttleKickInAvailDiff <= stream->throttleTargetAvail) {
+ // try decrease data in write buffer
+ if (stream->throttleState == USB_THROTTLE_DECREASE) {
+ // already in decrease state, check if SRC compensation is fast enough
+ if (stream->throttleTargetAvail - curAvail > stream->throttleOrigAvailDiff) {
+ if (stream->throttleSpeedUpCount >= USB_SPH_THROTTLE_SPEED_UP_COUNT) {
+ stream->throttleSpeedUpFactor++;
+ ALOGW("%s(), decrease, dir %d, compensation not fast enough, increase factor by %d, cur %u, orig diff %u avail",
+ __FUNCTION__, stream->direction, stream->throttleSpeedUpFactor,
+ curAvail, stream->throttleOrigAvailDiff);
+
+ throttleSetCompensateInRate(stream,
+ USB_SPH_THROTTLE_MS_CHANGE_PER_SECOND * stream->throttleSpeedUpFactor,
+ USB_THROTTLE_DECREASE);
+ stream->throttleSpeedUpCount = 0;
+ stream->throttleOrigAvailDiff = stream->throttleTargetAvail - curAvail;
+ }
+ } else {
+ stream->throttleSpeedUpCount = 0;
+ }
+ } else {
+ stream->throttleKickInCount++;
+ if (stream->throttleKickInCount >= USB_SPH_THROTTLE_KICK_IN_COUNT) {
+
+ if (stream->throttleState != USB_THROTTLE_STEADY) {
+ ALOGW("%s(), decrease, dir %d, shouldn't be in this state %d",
+ __FUNCTION__, stream->direction, stream->throttleState);
+ }
+
+ stream->throttleState = USB_THROTTLE_DECREASE;
+
+ stream->throttleSpeedUpFactor = 1;
+ stream->throttleSpeedUpCount = 0;
+ stream->throttleKickInCount = 0;
+ stream->throttleOrigAvailDiff = stream->throttleTargetAvail - curAvail;
+
+ throttleSetCompensateInRate(stream,
+ USB_SPH_THROTTLE_MS_CHANGE_PER_SECOND * stream->throttleSpeedUpFactor,
+ USB_THROTTLE_DECREASE);
+
+ ALOGD("%s(), decrease, dir %d, factor %d, cur %u, orig diff %u avail",
+ __FUNCTION__, stream->direction, stream->throttleSpeedUpFactor,
+ curAvail, stream->throttleOrigAvailDiff);
+ }
+ }
+ } else {
+ stream->throttleKickInCount = 0;
+
+ // back to steady state
+ if (stream->throttleState == USB_THROTTLE_INCREASE ||
+ stream->throttleState == USB_THROTTLE_DECREASE) {
+ if ((curAvail > stream->throttleTargetAvail &&
+ curAvail <= stream->throttleTargetAvail + stream->throttleSteadyAvailDiff) ||
+ (curAvail < stream->throttleTargetAvail &&
+ curAvail + stream->throttleSteadyAvailDiff >= stream->throttleTargetAvail)) {
+ stream->throttleState = USB_THROTTLE_STEADY;
+ throttleResetCurrentRate(stream);
+ ALOGD("%s(), dir %d, back to steady state", __FUNCTION__, stream->direction);
+ }
+ } else if (stream->throttleState != USB_THROTTLE_STEADY) {
+ ALOGW("%s(), steady, shouldn't be in this state %d", __FUNCTION__, stream->throttleState);
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
+bool AudioUSBPhoneCallController::getLpbkTime(unsigned int idx, void *buffer, unsigned int bufferSize,
+ unsigned int channel, unsigned int rate, size_t format_size) {
+ // lpbk test
+ if (mLpbkStart) {
+ clock_gettime(CLOCK_REALTIME, &mLpbkNewTime);
+ float time = calc_time_diff(mLpbkNewTime, mLpbkStartTime);
+
+ // check for pulse
+ // TODO: handle other format
+ short *tmpBuffer = (short *)buffer;
+ unsigned int i;
+ bool pulseExist = false;
+ for (i = 0; i < bufferSize / format_size; i = i + channel) {
+ if (*(tmpBuffer + i) > mLpbkPulseThres) {
+ pulseExist = true;
+ break;
+ }
+ }
+
+ if (pulseExist) {
+ mLpbkTimePart[idx] += time + ((float)i / channel) / rate;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+unsigned int AudioUSBPhoneCallController::getPcmAvail(struct pcm *pcm) {
+ struct timespec timeStamp;
+ unsigned int avail;
+ if (pcm_get_htimestamp(pcm, &avail, &timeStamp) != 0) {
+ ALOGE("%s(), pcm_get_htimestamp fail %s\n", __FUNCTION__, pcm_get_error(pcm));
+ avail = USB_SPH_INVALID_AVAIL;
+ }
+ return avail;
+}
+
+void AudioUSBPhoneCallController::setDebugInfo(bool enable, int dbgType) {
+ int previousDebugEnable = mixer_ctl_get_value(mixer_get_ctl_by_name(mMixer, "USB_Voice_Debug"), 0);
+ int debugEnable = 0;
+
+ if (enable) {
+ debugEnable = dbgType | previousDebugEnable;
+ } else {
+ debugEnable = (~dbgType) & previousDebugEnable;
+ }
+
+
+ ALOGD("%s(), enable %d, dbgType 0x%x, previousDebugEnable 0x%x, debugEnable 0x%x",
+ __FUNCTION__, enable, dbgType, previousDebugEnable, debugEnable);
+
+ if (mixer_ctl_set_value(mixer_get_ctl_by_name(mMixer, "USB_Voice_Debug"), 0, debugEnable)) {
+ ALOGW("%s(), set USB_Voice_Debug %d fail", __FUNCTION__, debugEnable);
+ }
+}
+
+void AudioUSBPhoneCallController::updateXmlParam(const char *_audioTypeName) {
+ ALOGD("%s(), audioType = %s", __FUNCTION__, _audioTypeName);
+
+ if (strcmp(_audioTypeName, USB_SPH_PARAM_AUDIOTYPE_NAME) == 0) {
+ loadUSBCallParam();
+ } else if (strcmp(_audioTypeName, USB_SPH_DEVICE_PARAM_AUDIOTYPE_NAME) == 0) {
+ loadUSBDeviceParam();
+ }
+}
+
+template<class T>
+status_t getParam(AppOps *appOps, ParamUnit *_paramUnit, T *_param, const char *_paramName) {
+ Param *param;
+ param = appOps->paramUnitGetParamByName(_paramUnit, _paramName);
+ if (!param) {
+ ALOGE("error: get param fail, param_name = %s", _paramName);
+ return BAD_VALUE;
+ } else {
+ *_param = *(T *)param->data;
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioUSBPhoneCallController::loadUSBCallParam() {
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(false);
+ return UNKNOWN_ERROR;
+ }
+
+ ALOGD("+%s()", __FUNCTION__);
+
+ // define xml names
+ char audioTypeName[] = USB_SPH_PARAM_AUDIOTYPE_NAME;
+
+ // extract parameters from xml
+ AudioType *audioType;
+ audioType = appOps->appHandleGetAudioTypeByName(appOps->appHandleGetInstance(), audioTypeName);
+ if (!audioType) {
+ ALOGE("%s(), get audioType fail, audioTypeName = %s", __FUNCTION__, audioTypeName);
+ return BAD_VALUE;
+ }
+
+ std::string paramCommonPath = "USBCallParam,Common";
+
+ const char *platformChar = appOps->appHandleGetFeatureOptionValue(appOps->appHandleGetInstance(), "MTK_PLATFORM");
+ std::string paramPath = "USBCallParam,";
+ if (platformChar) {
+ paramPath += std::string(platformChar);
+ }
+
+ ParamUnit *paramUnit;
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramPath.c_str());
+ if (!paramUnit) {
+ ALOGW("%s(), get paramUnit fail, paramPath = %s, use common", __FUNCTION__, paramPath.c_str());
+
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramCommonPath.c_str());
+ if (!paramUnit) {
+ ALOGE("%s(), get paramUnit fail, paramCommonPath = %s", __FUNCTION__, paramCommonPath.c_str());
+ return BAD_VALUE;
+ }
+ }
+
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ // spec
+ getParam<int>(appOps, paramUnit, &mParam.speechDlUlLatencyUs, "speech_dl_ul_latency_us");
+ getParam<int>(appOps, paramUnit, &mParam.speechDlLatencyUs, "speech_dl_latency_us");
+ getParam<int>(appOps, paramUnit, &mParam.speechUlLatencyUs, "speech_ul_latency_us");
+ getParam<int>(appOps, paramUnit, &mParam.echoSettlingTimeMs, "echo_settling_time_ms");
+ getParam<int>(appOps, paramUnit, &mParam.echoAheadMicDataUs, "echo_ahead_mic_data_us");
+
+
+ ALOGD("-%s(), mParam.speechDlUlLatencyUs = %d, mParam.speechDlLatencyUs = %d, mParam.speechUlLatencyUs = %d, "
+ "mParam.echoSettlingTimeMs = %d, mParam.echoAheadMicDataUs = %d",
+ __FUNCTION__, mParam.speechDlUlLatencyUs, mParam.speechDlLatencyUs, mParam.speechUlLatencyUs,
+ mParam.echoSettlingTimeMs, mParam.echoAheadMicDataUs);
+
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ return NO_ERROR;
+}
+
+status_t AudioUSBPhoneCallController::loadUSBDeviceParam() {
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(false);
+ return UNKNOWN_ERROR;
+ }
+
+ ALOGD("%s()", __FUNCTION__);
+
+ // define xml names
+ char audioTypeName[] = USB_SPH_DEVICE_PARAM_AUDIOTYPE_NAME;
+
+ // extract parameters from xml
+ AudioType *audioType;
+ audioType = appOps->appHandleGetAudioTypeByName(appOps->appHandleGetInstance(), audioTypeName);
+ if (!audioType) {
+ ALOGE("%s(), get audioType fail, audioTypeName = %s", __FUNCTION__, audioTypeName);
+ return BAD_VALUE;
+ }
+
+ std::string categoryTypeName = "Device";
+ CategoryType *categoryType = appOps->audioTypeGetCategoryTypeByName(audioType, categoryTypeName.c_str());
+ if (!audioType) {
+ ALOGE("%s(), get categoryType fail, categoryTypeName = %s", __FUNCTION__, categoryTypeName.c_str());
+ return BAD_VALUE;
+ }
+
+ // Read lock
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+
+ size_t categoryNum = appOps->categoryTypeGetNumOfCategory(categoryType);
+ mParam.deviceParam.resize(categoryNum);
+
+ mParam.maxCaptureLatencyUs = 0;
+ for (size_t i = 0; i < categoryNum; i++) {
+ Category *category = appOps->categoryTypeGetCategoryByIndex(categoryType, i);
+ mParam.deviceParam[i].id = category->name;
+
+ std::string paramPath = categoryTypeName + "," + category->name;
+
+ ParamUnit *paramUnit;
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, paramPath.c_str());
+ if (!paramUnit) {
+ ALOGE("%s(), get paramUnit fail, paramPath = %s", __FUNCTION__, paramPath.c_str());
+ return BAD_VALUE;
+ }
+
+ // spec
+ getParam<int>(appOps, paramUnit, &mParam.deviceParam[i].playbackLatencyUs, "playback_latency_us");
+ getParam<int>(appOps, paramUnit, &mParam.deviceParam[i].captureLatencyUs, "capture_latency_us");
+
+ if (mParam.deviceParam[i].captureLatencyUs > mParam.maxCaptureLatencyUs) {
+ mParam.maxCaptureLatencyUs = mParam.deviceParam[i].captureLatencyUs;
+ }
+
+ ALOGD("%s(), i %zu, device id %s, playbackLatencyUs %d, captureLatencyUs %d",
+ __FUNCTION__, i, mParam.deviceParam[i].id.c_str(),
+ mParam.deviceParam[i].playbackLatencyUs, mParam.deviceParam[i].captureLatencyUs);
+ }
+
+ ALOGV("%s(), mParam.maxCaptureLatencyUs %d", __FUNCTION__, mParam.maxCaptureLatencyUs);
+
+ // Unlock
+ appOps->audioTypeUnlock(audioType);
+
+ return NO_ERROR;
+}
+
+status_t AudioUSBPhoneCallController::getDeviceId(struct USBStream *stream) {
+ if (!profile_is_initialized(&stream->profile)) {
+ ALOGE("%s(), dir %d not initialized", __FUNCTION__, stream->direction);
+ ASSERT(0);
+ stream->deviceId.clear();
+ return BAD_VALUE;
+ }
+
+ // get device id
+#define DEVICE_ID_SIZE 32
+ char deviceId[DEVICE_ID_SIZE] = "default";
+ std::string usbidPath = "proc/asound/card";
+ usbidPath += std::to_string(stream->profile.card);
+ usbidPath += "/usbid";
+
+ std::ifstream is(usbidPath.c_str(), std::ifstream::in);
+ if (is) {
+ is >> deviceId;
+ is.close();
+ } else {
+ ALOGE("%s(), open path %s failed, use default", __FUNCTION__, usbidPath.c_str());
+ /*
+ FILE *file = NULL;
+ file = fopen(usbidPath.c_str(), "r");
+ if (file)
+ {
+ ALOGD("file open success");
+ while (!feof(file))
+ {
+ fgets(deviceId, DEVICE_ID_SIZE, file);
+ }
+ ALOGD("reach EOF");
+ }
+ else
+ {
+ ALOGD("file open fail");
+ }
+
+ if(file)
+ fclose(file);
+ */
+ }
+
+ stream->deviceId = deviceId;
+
+ return NO_ERROR;
+}
+
+status_t AudioUSBPhoneCallController::getDeviceParam(struct USBStream *stream) {
+ int dir = stream->direction;
+ if (stream->deviceId.empty()) {
+ ALOGE("%s(), dir %d, deviceId empty", __FUNCTION__, dir);
+ ASSERT(0);
+ return BAD_VALUE;
+ }
+
+ size_t defaultIdx = 9999;
+
+ for (size_t i = 0; i < mParam.deviceParam.size(); i++) {
+ if (mParam.deviceParam[i].id.compare(std::string(stream->deviceId, 0, mParam.deviceParam[i].id.size())) == 0) {
+ ALOGD("%s(), dir %d, param found for deviceId %s", __FUNCTION__, dir, stream->deviceId.c_str());
+ stream->deviceParamIdx = i;
+ return NO_ERROR;
+ }
+
+ if (mParam.deviceParam[i].id.compare("default") == 0) {
+ defaultIdx = i;
+ }
+ }
+
+ if (defaultIdx >= mParam.deviceParam.size()) {
+ ALOGE("%s(), dir %d, invalid defaultIdx %zu", __FUNCTION__, dir, defaultIdx);
+ ASSERT(0);
+ return BAD_VALUE;
+ }
+
+ ALOGD("%s(), dir %d, use default param for deviceId %s", __FUNCTION__, dir, stream->deviceId.c_str());
+ stream->deviceParamIdx = defaultIdx;
+ return NO_ERROR;
+}
+
+unsigned int AudioUSBPhoneCallController::getEchoMaxDelayUs() {
+ const struct USBDeviceParam *playDeviceParam = mUSBOutStream.deviceParamIdx < mParam.deviceParam.size() ?
+ &mParam.deviceParam[mUSBOutStream.deviceParamIdx] : NULL;
+
+ unsigned int maxLatencyUs = mParam.speechDlUlLatencyUs +
+ (playDeviceParam ? playDeviceParam->playbackLatencyUs : 0) +
+ mParam.maxCaptureLatencyUs -
+ mParam.echoAheadMicDataUs; // AEC algorithm prefer echo data is 6~10ms ahead of speech uplink data
+
+ return maxLatencyUs;
+}
+
+unsigned int AudioUSBPhoneCallController::getEchoCurrentDelayUs() {
+ const struct USBDeviceParam *playDeviceParam = mUSBOutStream.deviceParamIdx < mParam.deviceParam.size() ?
+ &mParam.deviceParam[mUSBOutStream.deviceParamIdx] : NULL;
+
+ if (mEnableWithUSBInConnected) {
+ const struct USBDeviceParam *capDeviceParam = mUSBInStream.deviceParamIdx < mParam.deviceParam.size() ?
+ &mParam.deviceParam[mUSBInStream.deviceParamIdx] : NULL;
+
+ return mParam.speechDlUlLatencyUs +
+ (playDeviceParam ? playDeviceParam->playbackLatencyUs : 0) +
+ (capDeviceParam ? capDeviceParam->captureLatencyUs : 0) -
+ mParam.echoAheadMicDataUs;
+ } else {
+ return mParam.speechDlLatencyUs +
+ (playDeviceParam ? playDeviceParam->playbackLatencyUs : 0) -
+ mParam.echoAheadMicDataUs;
+
+ }
+}
+
+// perf service function
+int AudioUSBPhoneCallController::initPerfService() {
+ if (mPowerHalHandle >= 0) {
+ return 0;
+ }
+
+ android::sp<IPower> powerHal = IPower::getService();
+
+ if (powerHal != NULL) {
+ mPowerHalHandle = powerHal->scnReg();
+ if (mPowerHalHandle >= 0) {
+ powerHal->scnConfig(mPowerHalHandle, MtkPowerCmd::CMD_SET_CLUSTER_CPU_CORE_MIN, 0, 4, 0, 0);
+ powerHal->scnConfig(mPowerHalHandle, MtkPowerCmd::CMD_SET_SCREEN_OFF_STATE, (int32_t)MtkScreenState::SCREEN_OFF_ENABLE, 0, 0, 0);
+ } else {
+ ALOGE("%s(), mPowerHalHandle %d", __FUNCTION__, mPowerHalHandle);
+ }
+ } else {
+ ALOGE("%s(), powerHal == NULL", __FUNCTION__);
+ }
+
+ return 0;
+}
+
+void AudioUSBPhoneCallController::deinitPerfService() {
+ android::sp<IPower> powerHal = IPower::getService();
+
+ if (powerHal != NULL) {
+ powerHal->scnUnreg(mPowerHalHandle);
+ mPowerHalHandle = -1;
+ } else {
+ ALOGE("%s(), powerHal == NULL", __FUNCTION__);
+ }
+}
+
+void AudioUSBPhoneCallController::enablePerfCpuScn() {
+ android::sp<IPower> powerHal = IPower::getService();
+
+ if (powerHal != NULL) {
+ powerHal->scnEnable(mPowerHalHandle, 0);
+ } else {
+ ALOGE("%s(), powerHal == NULL", __FUNCTION__);
+ }
+}
+
+void AudioUSBPhoneCallController::disablePerfCpuScn() {
+ android::sp<IPower> powerHal = IPower::getService();
+
+ if (powerHal != NULL) {
+ powerHal->scnDisable(mPowerHalHandle);
+ } else {
+ ALOGE("%s(), powerHal == NULL", __FUNCTION__);
+ }
+}
+
+}
+
+/*
+// data pending
+status_t AudioUSBPhoneCallController::initDataPending(struct USBStream *stream)
+{
+ if (stream->direction == SPH_DL)
+ {
+ stream->dataPendingDesireOutBufSize = getPeriodByte(&stream->proxy.alsa_config);
+ }
+ else
+ {
+ stream->dataPendingDesireOutBufSize = getPeriodByte(&stream->pcmConfigHAL2AFE);
+ }
+ stream->dataPendingOutBufSize = stream->dataPendingDesireOutBufSize * 2; // sometimes we need write 2 period at a time, read data > write data
+ stream->dataPendingOutRemainBufSize = stream->dataPendingDesireOutBufSize;
+ stream->dataPendingTempBufSize = stream->dataPendingDesireOutBufSize * 2;
+ stream->dataPendingRemainBufSize = 0;
+
+ if(stream->blisrc != NULL)
+ {
+ ALOGD("%s(), dataPendingDesireOutBufSize %d", __FUNCTION__, stream->dataPendingDesireOutBufSize);
+
+ stream->dataPendingOutBuffer= new char[stream->dataPendingOutBufSize];
+ stream->dataPendingTempBuffer = new char[stream->dataPendingTempBufSize];
+ ASSERT(stream->dataPendingOutBuffer != NULL && stream->dataPendingTempBuffer != NULL);
+ }
+ return NO_ERROR;
+}
+
+status_t AudioUSBPhoneCallController::deinitDataPending(struct USBStream *stream)
+{
+ ALOGD("%s()", __FUNCTION__);
+ if(stream->dataPendingOutBuffer != NULL)
+ {
+ delete[] stream->dataPendingOutBuffer;
+ stream->dataPendingOutBuffer = NULL;
+ }
+ if(stream->dataPendingTempBuffer != NULL)
+ {
+ delete[] stream->dataPendingTempBuffer ;
+ stream->dataPendingTempBuffer = NULL;
+ }
+ stream->dataPendingDesireOutBufSize = 0;
+ stream->dataPendingOutRemainBufSize = 0;
+ stream->dataPendingTempBufSize = 0;
+ stream->dataPendingOutBufSize = 0;
+ stream->dataPendingRemainBufSize = 0;
+ return NO_ERROR;
+}
+
+// let output size equal one period size
+status_t AudioUSBPhoneCallController::doDataPending(struct USBStream *stream,
+ void *pInBuffer, uint32_t inBytes,
+ void **ppOutBuffer, uint32_t *pOutBytes)
+{
+ char *dataInputPointer = (char *)pInBuffer;
+
+ uint32 remainOutBufSize = stream->dataPendingOutRemainBufSize;
+ char *dataPointer = (char *)stream->dataPendingOutBuffer + (stream->dataPendingDesireOutBufSize - remainOutBufSize);
+
+ if (stream->dataPendingOutBuffer != NULL) // do data pending
+ {
+ ALOGV("%s(), dir %d, inBytes = %d, dataPendingOutRemainBufSize = %d, dataPendingRemainBufSize = %d",
+ __FUNCTION__, stream->direction, inBytes,
+ stream->dataPendingOutRemainBufSize, stream->dataPendingRemainBufSize);
+
+ if (stream->dataPendingRemainBufSize != 0) // deal previous remain buffer
+ {
+ unsigned int copy_size = stream->dataPendingRemainBufSize;
+ if (copy_size > remainOutBufSize)
+ {
+ copy_size = remainOutBufSize;
+ }
+
+ memcpy((void*)dataPointer, (void*)stream->dataPendingTempBuffer, copy_size);
+ dataPointer += copy_size;
+ remainOutBufSize -= copy_size;
+ stream->dataPendingRemainBufSize -= copy_size;
+
+ // move remain data to the start of stream->dataPendingTempBuffer
+ if (stream->dataPendingRemainBufSize != 0)
+ {
+ memmove((void*)stream->dataPendingTempBuffer,
+ (void*)stream->dataPendingTempBuffer + copy_size,
+ stream->dataPendingRemainBufSize);
+ }
+ }
+
+ // deal with input buffer
+ if (inBytes > remainOutBufSize)
+ {
+ memcpy((void*)dataPointer, pInBuffer, remainOutBufSize);
+ dataPointer += remainOutBufSize;
+ dataInputPointer += remainOutBufSize;
+
+ uint32 inRemain = inBytes - remainOutBufSize;
+ remainOutBufSize = 0;
+
+ ALOGV("%s(), dir %d, inRemain = %d", __FUNCTION__, stream->direction, inRemain);
+
+ // deal with remain buffer
+ if (stream->dataPendingRemainBufSize + inRemain > stream->dataPendingTempBufSize)
+ {
+ // error handle
+ ALOGE("%s(), dir %d, data lost, dataPendingRemainBufSize = %d, inRemain = %d",
+ __FUNCTION__, stream->direction, stream->dataPendingRemainBufSize, inRemain);
+ ASSERT(stream->dataPendingRemainBufSize + inRemain <= stream->dataPendingTempBufSize);
+ inRemain = stream->dataPendingTempBufSize - stream->dataPendingRemainBufSize;
+ }
+
+ memcpy((void*)stream->dataPendingTempBuffer + stream->dataPendingRemainBufSize,
+ (void*)dataInputPointer, inRemain);
+ stream->dataPendingRemainBufSize += inRemain;
+ }
+ else
+ {
+ memcpy((void*)dataPointer, pInBuffer, inBytes);
+ dataPointer += inBytes;
+ remainOutBufSize -= inBytes;
+ }
+
+ // update pointer and data count
+ *ppOutBuffer = stream->dataPendingOutBuffer;
+ if (remainOutBufSize == 0)
+ {
+ *pOutBytes = stream->dataPendingDesireOutBufSize;
+
+ // remain buffer still has a full period data
+ if (stream->dataPendingRemainBufSize >= stream->dataPendingDesireOutBufSize)
+ {
+ unsigned int copy_size = stream->dataPendingDesireOutBufSize;
+ memcpy((void*)dataPointer,
+ (void*)stream->dataPendingTempBuffer,
+ copy_size);
+
+ dataPointer += copy_size;
+ stream->dataPendingRemainBufSize -= copy_size;
+
+ // move remain data to the start of stream->dataPendingTempBuffer
+ if (stream->dataPendingRemainBufSize != 0)
+ {
+ memmove((void*)stream->dataPendingTempBuffer,
+ (void*)stream->dataPendingTempBuffer + copy_size,
+ stream->dataPendingRemainBufSize);
+ }
+
+ *pOutBytes += copy_size;
+ }
+ }
+ else // not enough one period
+ {
+ *pOutBytes = 0;
+ }
+
+ stream->dataPendingOutRemainBufSize = (remainOutBufSize == 0) ? stream->dataPendingDesireOutBufSize : remainOutBufSize;
+
+ ALOGV("%s(), dir %d, remainOutBufSize = %d pOutBytes = %d",
+ __FUNCTION__, stream->direction, stream->dataPendingOutRemainBufSize, *pOutBytes);
+ }
+ else
+ {
+ *ppOutBuffer = pInBuffer;
+ *pOutBytes = inBytes;
+ }
+
+ ASSERT(*ppOutBuffer != NULL);
+ if (*pOutBytes > stream->dataPendingOutBufSize)
+ {
+ ALOGE("%s(), dir %d, *pOutBytes %u", __FUNCTION__, stream->direction, *pOutBytes);
+ ASSERT(*pOutBytes <= stream->dataPendingOutBufSize);
+ *pOutBytes = stream->dataPendingOutBufSize;
+ }
+ return NO_ERROR;
+}
+*/
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioVUnlockDL.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioVUnlockDL.cpp
new file mode 100644
index 0000000..7a50508
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioVUnlockDL.cpp
@@ -0,0 +1,1351 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*****************************************************************************
+* C O M P I L E R F L A G S
+******************************************************************************
+*/
+
+#define LOG_TAG "AudioVoiceUIDL"
+//#define DUMP_VPW_StreamIn_DATA
+//#define forUT
+//#define ENABLE_LOG_VPWStreamIn
+#ifdef ENABLE_LOG_VPWStreamIn
+#undef ALOGV
+#define ALOGV(...) ALOGD(__VA_ARGS__)
+#endif
+
+/*****************************************************************************
+* E X T E R N A L R E F E R E N C E S
+******************************************************************************
+*/
+#define MTK_LOG_ENABLE 1
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sched.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/threads.h>
+
+
+#include <cutils/properties.h>
+
+
+#include "AudioType.h"
+#include "audio_custom_exp.h"
+#include "AudioVUnlockDL.h"
+#include <log/log.h>
+#include <cutils/ashmem.h>
+
+#define RTPM_PRIO_AUDIO_I2S 90
+
+/*****************************************************************************
+* D A T A T Y P E S
+******************************************************************************
+*/
+
+/*****************************************************************************
+* C O N S T A N T S
+******************************************************************************
+*/
+
+/*****************************************************************************
+* C L A S S D E F I N I T I O N
+******************************************************************************
+*/
+namespace android {
+
+static pthread_mutex_t mVUnlockReadMutex;
+#ifdef forUT
+static pthread_mutex_t mVUnlockWriteMutex;
+#endif
+AudioVUnlockDL *UniqueVUnlockDLInstance = NULL;
+
+static long long getTimeMs() {
+ struct timeval t1;
+ long long ms;
+
+ gettimeofday(&t1, NULL);
+ ms = t1.tv_sec * 1000LL + t1.tv_usec / 1000;
+
+ return ms;
+}
+#if 0
+class VUnlockSharedBuffer : public BnMemory {
+public:
+ VUnlockSharedBuffer() {
+ ALOGV("+VUnlockSharedBuffer");
+ sp<MemoryHeapBase> heap = new MemoryHeapBase(1024, 0, "VUnlockSharedBuffer");
+ if (heap != NULL) {
+ mMemory = new MemoryBase(heap, 0, 1024);
+ int32 *data = (int32_t *)mMemory->pointer();
+ if (data != NULL) {
+ *data = 0;
+ }
+ }
+ ALOGV("-VUnlockSharedBuffer");
+ }
+ virtual ~VUnlockSharedBuffer() {
+ mMemory = NULL;
+ }
+ static void instantiate() {
+ ALOGV("+VUnlockSharedBuffer::instantiate");
+ defaultServiceManager()->addService(String16("VUnlock_SHARED_BUFFER_SERVICE"), new VUnlockSharedBuffer());
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+ ALOGV("-VUnlockSharedBuffer::instantiate");
+ }
+ virtual sp<IMemory> getMemory() {
+ return mMemory;
+ }
+private:
+ sp<MemoryBase> mMemory;
+
+};
+#endif
+AudioVUnlockRingBuf::AudioVUnlockRingBuf() {
+ int ret = 0;
+
+ ret = pthread_mutex_init(&mBufMutex, NULL);
+ if (ret != 0) {
+ ALOGI("Failed to initialize AudioVUnlockRingBuf mBufMutex!");
+ }
+
+ ret = pthread_cond_init(&mBuf_Cond, NULL);
+ if (ret != 0) {
+ ALOGI("Failed to initialize AudioVUnlockRingBuf mBuf_Cond!");
+ }
+
+ //mbufAddr = new char[VOICE_UNLOCK_RING_BUFFER_SIZE];
+ memset(mbufAddr, 0, VOICE_UNLOCK_RING_BUFFER_SIZE);
+ mbuf.pBufBase = mbufAddr;
+ mbuf.pRead = mbufAddr;
+ mbuf.pWrite = mbufAddr;
+ mbuf.pBufEnd = mbufAddr + VOICE_UNLOCK_RING_BUFFER_SIZE;
+ mbuf.bufLen = VOICE_UNLOCK_RING_BUFFER_SIZE;
+ mbuf.buffull = false;
+}
+AudioVUnlockRingBuf::~AudioVUnlockRingBuf() {
+}
+uint32_t AudioVUnlockRingBuf:: WriteAdvance(void *buf, uint32_t datasz) {
+ int32_t leftspace;
+ uint32_t datawritten = 0;
+ pthread_mutex_lock(&mBufMutex);
+ //SXLOGD("[WriteAdvance],start mbuf.pWrite %x, mbuf.pRead %x ", mbuf.pWrite,mbuf.pRead);
+ if (mbuf.pWrite == mbuf.pRead) {
+ if (!mbuf.buffull) {
+ leftspace = mbuf.bufLen;
+ } else {
+ leftspace = 0;
+ }
+ } else {
+ leftspace = (mbuf.pRead - mbuf.pWrite);
+ if (leftspace < 0) {
+ leftspace = mbuf.bufLen + leftspace;
+ }
+ }
+ datasz = ((uint32_t)leftspace) < datasz ? ((uint32_t)leftspace) : datasz;
+ if ((mbuf.pWrite + datasz) < mbuf.pBufEnd) {
+ memcpy(mbuf.pWrite, buf, datasz);
+ datawritten += datasz;
+ mbuf.pWrite += datasz;
+ } else {
+ memcpy(mbuf.pWrite, buf, (mbuf.pBufEnd - mbuf.pWrite));
+ memcpy(mbuf.pBufBase, (char *)buf + (mbuf.pBufEnd - mbuf.pWrite), datasz - (mbuf.pBufEnd - mbuf.pWrite));
+ datawritten += datasz;
+ mbuf.pWrite = mbuf.pBufBase + (datasz - (mbuf.pBufEnd - mbuf.pWrite)) ;
+ }
+ if ((mbuf.pWrite == mbuf.pRead) && datawritten != 0) {
+ mbuf.buffull = 1;
+ }
+
+ //SXLOGD("[WriteAdvance] Write offset = %d" ,mbuf.pWrite -mbuf.pBufBase );
+ //SXLOGD("[WriteAdvance] read offset = %d" ,mbuf.pRead -mbuf.pBufBase );
+ pthread_mutex_unlock(&mBufMutex);
+ return datawritten;
+}
+
+int32_t AudioVUnlockRingBuf:: Write(void *buf, uint32_t datasz) {
+ uint32_t leftsz = datasz;
+ char *bufptr = (char *)buf;
+ uint32_t loopCount = 0;
+ int32_t writeAmount = 0;
+ if (buf == NULL) {
+ return -1;
+ }
+ while (leftsz > 0) {
+ int32_t datawritten;
+ datawritten = WriteAdvance(bufptr, leftsz);
+ leftsz -= datawritten;
+ bufptr += datawritten;
+ writeAmount += datawritten;
+ if (leftsz != 0) {
+ // sleep 5ms
+ usleep(1 * 1000);
+ }
+
+ loopCount ++;
+ if (loopCount == 5 && leftsz != 0) {
+ ALOGD("[AudioVUnlockRingBuf:: Write] Drop Stream out data! data droped %d , write %d", leftsz, writeAmount);
+ break;
+ }
+ }
+
+ //SXLOGD("[AudioVUnlockRingBuf:: Write] loopCount %d, %d", loopCount, writeAmount);
+ return writeAmount;
+}
+
+uint32_t AudioVUnlockRingBuf:: AdvanceReadPointer(uint32_t datasz) {
+ pthread_mutex_lock(&mBufMutex);
+
+ if ((mbuf.pRead + datasz) < mbuf.pBufEnd) {
+ mbuf.pRead += datasz;
+ } else {
+ mbuf.pRead = mbuf.pBufBase + (datasz - (mbuf.pBufEnd - mbuf.pRead)) ;
+ }
+ if (mbuf.pRead == mbuf.pWrite && datasz != 0) {
+ mbuf.buffull = 0;
+ }
+
+ //SXLOGD("[AdvanceReadPointer] Write offset = %d" ,mbuf.pWrite -mbuf.pBufBase );
+ //SXLOGD("[AdvanceReadPointer] read offset = %d" ,mbuf.pRead -mbuf.pBufBase );
+ pthread_mutex_unlock(&mBufMutex);
+ return 0;
+}
+
+uint32_t AudioVUnlockRingBuf:: ReadWithoutAdvance(void *buf, uint32_t datasz) {
+ int32_t leftdata;
+ uint32_t dataread = 0;
+ if (buf == NULL || datasz == 0) {
+ return 0;
+ }
+ pthread_mutex_lock(&mBufMutex);
+ if (mbuf.pWrite == mbuf.pRead) {
+ if (!mbuf.buffull) {
+ leftdata = 0;
+ } else {
+ leftdata = mbuf.bufLen;
+ }
+ } else {
+ leftdata = (mbuf.pWrite - mbuf.pRead);
+ if (leftdata < 0) {
+ leftdata = mbuf.bufLen + leftdata;
+ }
+ }
+
+ datasz = ((uint32_t)leftdata) < datasz ? ((uint32_t)leftdata) : datasz;
+
+ if ((mbuf.pRead + datasz) < mbuf.pBufEnd) {
+ memcpy(buf, mbuf.pRead, datasz);
+ dataread += datasz;
+ } else {
+ memcpy(buf, mbuf.pRead, (mbuf.pBufEnd - mbuf.pRead));
+ memcpy((char *)buf + (mbuf.pBufEnd - mbuf.pRead), mbuf.pBufBase, datasz - (mbuf.pBufEnd - mbuf.pRead));
+ dataread += datasz;
+ }
+
+ //SXLOGD("[ReadWithoutAdvance] write offset = %d" ,mbuf.pWrite -mbuf.pBufBase );
+ //SXLOGD("[ReadWithoutAdvance] read offset = %d" ,mbuf.pRead -mbuf.pBufBase );
+ pthread_mutex_unlock(&mBufMutex);
+ return dataread;
+}
+
+uint32_t AudioVUnlockRingBuf:: ReadAdvance(void *buf, uint32_t datasz) {
+ int32_t leftdata;
+ uint32_t dataread = 0;
+ pthread_mutex_lock(&mBufMutex);
+ if (mbuf.pWrite == mbuf.pRead) {
+ if (!mbuf.buffull) {
+ leftdata = 0;
+ } else {
+ leftdata = mbuf.bufLen;
+ }
+ } else {
+ leftdata = (mbuf.pWrite - mbuf.pRead);
+ if (leftdata < 0) {
+ leftdata = mbuf.bufLen + leftdata;
+ }
+ }
+
+ datasz = ((uint32_t)leftdata) < datasz ? ((uint32_t)leftdata) : datasz;
+ if ((mbuf.pRead + datasz) < mbuf.pBufEnd) {
+ memcpy(buf, mbuf.pRead, datasz);
+ dataread += datasz;
+ mbuf.pRead += datasz;
+ } else {
+ memcpy(buf, mbuf.pRead, (mbuf.pBufEnd - mbuf.pRead));
+ memcpy((char *)buf + (mbuf.pBufEnd - mbuf.pRead), mbuf.pBufBase, datasz - (mbuf.pBufEnd - mbuf.pRead));
+ dataread += datasz;
+ mbuf.pRead = mbuf.pBufBase + (datasz - (mbuf.pBufEnd - mbuf.pRead)) ;
+ }
+ if ((mbuf.pRead == mbuf.pWrite) && dataread != 0) {
+ mbuf.buffull = 0;
+ }
+
+ //SXLOGD("[ReadAdvance] write offset = %d" ,mbuf.pWrite -mbuf.pBufBase );
+ //SXLOGD("[ReadAdvance] read offset = %d" ,mbuf.pRead -mbuf.pBufBase );
+ pthread_mutex_unlock(&mBufMutex);
+ return dataread;
+}
+
+int32_t AudioVUnlockRingBuf:: Read(void *buf, uint32_t datasz) {
+ uint32_t leftsz = datasz;
+ char *bufptr = (char *) buf;
+ uint32_t loopCount = 0;
+ int32_t ret = 0;
+ int32_t readAmount = 0;
+ if (buf == NULL) {
+ return -1;
+ }
+
+ while (leftsz > 0) {
+ uint32_t dataread;
+ dataread = ReadAdvance(bufptr, leftsz);
+ leftsz -= dataread;
+ bufptr += dataread;
+ readAmount += dataread;
+ if (leftsz) {
+ //sleep 5ms
+ usleep(5 * 1000);
+ }
+ loopCount ++;
+ if (loopCount == 10 && leftsz != 0) {
+ int32_t ret = -1;
+ break;
+ }
+ ret = readAmount;
+ }
+ return ret;
+}
+uint32_t AudioVUnlockRingBuf:: GetBuflength(void) {
+ return mbuf.bufLen;
+}
+
+uint32_t AudioVUnlockRingBuf:: GetBufDataSz(void) {
+ int32_t leftdata = 0;
+ pthread_mutex_lock(&mBufMutex);
+
+ //SXLOGD("[GetBufDataSz], mbuf.pWrite %x, mbuf.pRead %x ", mbuf.pWrite,mbuf.pRead);
+ if (mbuf.pWrite == mbuf.pRead) {
+ if (!mbuf.buffull) {
+ leftdata = 0;
+ } else {
+ leftdata = mbuf.bufLen;
+ }
+ } else {
+ leftdata = (mbuf.pWrite - mbuf.pRead);
+ //SXLOGD("[GetBufDataSz], leftdata %d ",leftdata);
+ if (leftdata < 0) {
+ leftdata += mbuf.bufLen ;
+ }
+ }
+ pthread_mutex_unlock(&mBufMutex);
+ return (uint32_t)leftdata;
+}
+uint32_t AudioVUnlockRingBuf:: WaitBufData(void) {
+ int32_t leftdata = 0;
+ pthread_mutex_lock(&mBufMutex);
+ if (mbuf.pWrite == mbuf.pRead) {
+ if (!mbuf.buffull) {
+ leftdata = 0;
+ } else {
+ leftdata = mbuf.bufLen;
+ }
+ } else {
+ leftdata = (mbuf.pWrite - mbuf.pRead);
+ if (leftdata < 0) {
+ leftdata = mbuf.bufLen + leftdata;
+ }
+ }
+ /*change conditiont to leftdata <=2, since SRC won't work if leftdata <=2*/
+ //if(leftdata == 0) // wait till buffer filled
+ if (leftdata <= 0) { // wait till buffer has 92 ms data.
+ ALOGV("[WaitBufData]Buffer empty , wait %d", leftdata);
+ pthread_cond_wait(&mBuf_Cond, &mBufMutex);
+ }
+ pthread_mutex_unlock(&mBufMutex);
+ return (uint32_t)leftdata;
+}
+
+uint32_t AudioVUnlockRingBuf:: SignalBufData(void) {
+ int32_t leftdata = 0;
+ //pthread_mutex_lock( &mBufMutex);SignalBufData
+ pthread_cond_broadcast(&mBuf_Cond);
+ //SXLOGV("[SignalBufData] SignalBufData, mBuf_Cond %d", mBuf_Cond.value);
+ //pthread_mutex_unlock( &mBufMutex);
+ return (uint32_t)leftdata;
+}
+
+uint32_t AudioVUnlockRingBuf:: GetBufSpace(void) {
+ uint32_t leftspace = 0;
+
+ pthread_mutex_lock(&mBufMutex);
+ if (mbuf.pWrite == mbuf.pRead) {
+ if (!mbuf.buffull) {
+ leftspace = mbuf.bufLen;
+ } else {
+ leftspace = 0;
+ }
+ } else if (mbuf.pWrite > mbuf.pRead) {
+ leftspace = mbuf.bufLen - (mbuf.pWrite - mbuf.pRead);
+ } else {
+ leftspace = mbuf.pRead - mbuf.pWrite;
+ }
+
+ pthread_mutex_unlock(&mBufMutex);
+ return leftspace;
+}
+uint32_t AudioVUnlockRingBuf:: ResetBuf() {
+
+ pthread_mutex_lock(&mBufMutex);
+ memset(mbufAddr, 0, mbuf.bufLen);
+ mbuf.pBufBase = mbufAddr;
+ mbuf.pRead = mbufAddr;
+ mbuf.pWrite = mbufAddr;
+ mbuf.buffull = false;
+ pthread_mutex_unlock(&mBufMutex);
+ return 0;
+}
+
+//#define WRITEOVER
+void *ReadRoutine(void *hdl __unused) {
+ pthread_detach(pthread_self());
+
+ AudioVUnlockRingBuf *ringBuf_in;
+ AudioVUnlockRingBuf *ringBuf_out;
+ int32_t readAmount;
+ int32_t rwfailcount = 0;
+ AudioVUnlockDL *VInstance = AudioVUnlockDL::getInstance();
+ char *tempbuffer = new char[VOICE_UNLOCK_RING_BUFFER_SIZE];
+ char *tempSRCbuffer = new char[6000];
+ uint32_t dataread = 0;
+ int32_t datawritten = 0;
+ ALOGV(" [ReadRoutine] start");
+ // defaut setting of thread init
+ pthread_mutex_lock(&mVUnlockReadMutex);
+ VInstance->mReadThreadExit = false;
+ VInstance->mReadThreadActive = true;
+ pthread_mutex_unlock(&mVUnlockReadMutex);
+
+ ringBuf_in = (AudioVUnlockRingBuf *) & (VInstance->mRingBufIn);
+ ringBuf_out = (AudioVUnlockRingBuf *) & (VInstance->mRingBufOut);
+
+ if (VInstance == NULL || ringBuf_in == NULL || ringBuf_out == NULL) {
+ ALOGD(" [ReadRoutine] Buffer NULL, Exit");
+ pthread_mutex_lock(&mVUnlockReadMutex);
+ VInstance->mReadThreadExit = true;
+ VInstance->mReadThreadActive = false;
+ pthread_mutex_unlock(&mVUnlockReadMutex);
+ }
+
+#ifdef MTK_AUDIO_ADJUST_PRIORITY
+ int result = -1;
+ // if set priority false , force to set priority
+ if (result == -1) {
+ struct sched_param sched_p;
+ sched_getparam(0, &sched_p);
+ sched_p.sched_priority = RTPM_PRIO_AUDIO_I2S;
+ if (0 != sched_setscheduler(0, SCHED_RR, &sched_p)) {
+ ALOGI("[%s] failed, errno: %d", __func__, errno);
+ } else {
+ sched_p.sched_priority = RTPM_PRIO_AUDIO_I2S;
+ sched_getparam(0, &sched_p);
+ ALOGV("sched_setscheduler ok, priority: %d", sched_p.sched_priority);
+ }
+ }
+#endif
+
+ while (!VInstance->mReadThreadExit) {
+ // Clear DL time if remaining data is pushed.
+ if (VInstance->mDLtime.tv_nsec != 0 && VInstance->mNewDLtime.tv_sec != 0) {
+ if (VInstance->mInRemaining == 0 && VInstance->mOutRemaining == 0) {
+ VInstance->mDLtime.tv_sec = 0;
+ VInstance->mDLtime.tv_nsec = 0;
+ //SXLOGV("[ReadRoutine] All Data from last playback pushed");
+ }
+ }
+ // switch DL time to new DL time
+ if (VInstance->mDLtime.tv_sec == 0 && VInstance->mNewDLtime.tv_sec != 0) {
+ VInstance->mDLtime.tv_sec = VInstance->mNewDLtime.tv_sec ;
+ VInstance->mDLtime.tv_nsec = VInstance->mNewDLtime.tv_nsec;
+ VInstance->mNewDLtime.tv_sec = 0;
+ VInstance->mNewDLtime.tv_nsec = 0;
+ ALOGV("[ReadRoutine] switch to new DL time %ld %ld", VInstance->mDLtime.tv_sec, VInstance->mDLtime.tv_nsec);
+ }
+
+ uint32_t readsz = ringBuf_in->GetBufDataSz();
+ dataread = ringBuf_in->ReadWithoutAdvance(tempbuffer, readsz);
+ if (VInstance->mInRemaining != 0) {
+ dataread = dataread > VInstance->mInRemaining ? VInstance->mInRemaining : dataread;
+ }
+ if (dataread <= 0 || VInstance->mDLtime.tv_sec == 0) { // do not read data if mDLtime is ready.
+ if (VInstance->StreamOutStandBy() && ringBuf_out->GetBufDataSz() == 0) {
+ //SXLOGV("[ReadRoutine] Standby, and all data from last playback is pushed");
+ VInstance->mDLtime.tv_sec = 0;
+ VInstance->mDLtime.tv_nsec = 0;
+ }
+ //SXLOGV("[ReadRoutine] No data from stream out, sleep");
+ usleep(30 * 1000);
+ } else {
+ //do SRC
+ uint32_t dataproduced = ringBuf_out->GetBufSpace();
+ dataproduced = dataproduced > 6000 ? 6000 : dataproduced;
+ int32_t dataConsumed = VInstance->DoSRC((uint8_t *) tempbuffer, &dataread, (uint8_t *) tempSRCbuffer, &dataproduced);
+
+#ifdef DUMP_VPW_StreamIn_DATA
+ //VInstance->DumpData(tempSRCbuffer, dataproduced);
+ if (VInstance->mOutFile_1 != NULL) {
+ VInstance->mOutFile_1 = fopen("/data/vendor/audiohal/audio_dump/VPW_SRC.pcm", "ab+");
+ fwrite(tempSRCbuffer, sizeof(char), dataproduced, VInstance->mOutFile_1);
+ fclose(VInstance->mOutFile_1);
+ }
+#endif
+ if (dataConsumed > 0) {
+ datawritten = ringBuf_out->Write(tempSRCbuffer, dataproduced);
+ ALOGV("[ReadRoutine] write to ring out, datawritten %d", datawritten);
+ } else {
+ datawritten = 0;
+ }
+ if (datawritten <= 0) { // write fail
+ rwfailcount++;
+ if (rwfailcount > 100) {
+ ALOGV("[ReadRoutine] Fail, write fail");
+ break;
+ }
+ ALOGV("[ReadRoutine] No space to write, sleep");
+ usleep(10 * 1000); //10ms
+ } else { //advance read pointer according to data actually write to output buffer
+ ringBuf_in->AdvanceReadPointer((uint32_t)dataConsumed);
+ if (VInstance->mInRemaining != 0) {
+ ALOGV("[ReadRoutine] last playback in buffer remaining %d", VInstance->mInRemaining);
+ VInstance->mInRemaining -= dataConsumed;
+ VInstance->mOutRemaining += datawritten;
+ }
+ ringBuf_out->SignalBufData();
+ ALOGV("[ReadRoutine] advance Read poniter %d ", (uint32_t)dataConsumed);
+ rwfailcount = 0;
+ }
+ }
+ }
+ delete[] tempbuffer;
+ delete[] tempSRCbuffer;
+ ALOGV("[ReadRoutine] exit ");
+
+ VInstance->ClearState(VPWStreamIn_READ_START);
+
+ ALOGV("stop and signal ReadRefFromRing to stop");
+ ringBuf_out->SignalBufData();
+
+ int cnt_val = 50;
+ while ((VInstance->mReadFunctionActive == true) && (cnt_val > 0)) {
+ ALOGD("[ReadRoutine]Signal ReadRefFromRing to stop and wait (%d) ", cnt_val);
+ cnt_val--;
+ ringBuf_out->SignalBufData();
+ usleep(1000 * 10);
+ }
+
+ pthread_mutex_lock(&mVUnlockReadMutex);
+ VInstance->mReadThreadExit = true;
+ VInstance->mReadThreadActive = false;
+ pthread_mutex_unlock(&mVUnlockReadMutex);
+
+ pthread_exit(NULL);
+}
+
+AudioVUnlockDL::AudioVUnlockDL() {
+ int32_t ret;
+ ret = pthread_mutex_init(&mVUnlockReadMutex, NULL);
+ if (ret != 0) {
+ ALOGI("Failed to initialize AudioVUnlockDL mMutex!");
+ }
+
+ ret = pthread_mutex_init(&mSRCMutex, NULL);
+ if (ret != 0) {
+ ALOGI("Failed to initialize AudioVUnlockDL mSRCMutex!");
+ }
+
+ mWriteThreadExit = false;
+ mWriteThreadActive = false;
+ mWriteThread = 0;
+ mReadThreadExit = true;
+ mReadThreadActive = false;
+ mReadFunctionActive = false;
+ mOutFile = 0;
+ mOutFile_1 = NULL;
+ mOutFile_2 = NULL;
+ mDLtime.tv_sec = 0;
+ mDLtime.tv_nsec = 0;
+ mNewDLtime.tv_nsec = 0;
+ mNewDLtime.tv_sec = 0;
+ mStandbyTime.tv_sec = 0;
+ mStandbyTime.tv_nsec = 0;
+ mGetTime = true;
+ mInRemaining = 0;
+ mOutRemaining = 0;
+ mInChannel = 2;
+ mOutputSampleRate = VPW_OUTPUT_SAMPLERATE;
+ mInputSampleRate = 44100;
+ mpSrcHdl = NULL;
+ mSrcBufLen = 0;
+ mReadThread = 0;
+ mState = VPWStreamIn_CREATED;
+ mInputStandby = true;
+ mOutChannel = 0;
+ mStreamOutLatency = 92;
+ mSampleCount_Dump = 0;
+ mULtime.tv_sec = 0;
+ mULtime.tv_nsec = 0;
+ mNeedBlock = false;
+ mFormat = 0;
+ mTempBuf = NULL;
+ mTempBufsz = 0;
+}
+
+
+AudioVUnlockDL::~AudioVUnlockDL() {
+ /* if (mRingBufIn!=NULL)
+ {
+ delete mRingBufIn;
+ }
+ if (mRingBufOut != NULL)
+ {
+ delete mRingBufOut;
+ } */
+ if (mpSrcHdl != NULL) {
+ mpSrcHdl->close();
+ deleteMtkAudioSrc(mpSrcHdl);
+ mpSrcHdl = NULL;
+ }
+ if (mTempBuf != NULL) {
+ delete [] mTempBuf;
+ }
+}
+
+int32_t AudioVUnlockDL::SetUplinkStartTime(struct timespec uplinkStartTime) {
+ mULtime = uplinkStartTime;
+ ALOGD("[SetUplinkStartTime] mULtime sec %ld nsec %ld", mULtime.tv_sec, mULtime.tv_nsec);
+ return 0;
+
+}
+int32_t AudioVUnlockDL::SetUplinkStartTime(struct timespec uplinkStartTime __unused, int clear) {
+ if ((mULtime.tv_sec == 0 && mULtime.tv_nsec == 0) && clear == 0) {
+ clock_gettime(CLOCK_MONOTONIC, &mULtime);
+#if 1
+ mULtime.tv_nsec = mULtime.tv_nsec - (int64_t)50 * 1000 * 1000;
+ if (mULtime.tv_nsec >= 1000000000) {
+ mULtime.tv_sec += 1;
+ mULtime.tv_nsec -= 1000000000;
+ }
+#endif
+ //mULtime = uplinkStartTime;
+ ALOGD("[SetUplinkStartTime] mULtime sec %ld nsec %ld", mULtime.tv_sec, mULtime.tv_nsec);
+ } else if (clear == 1) {
+ mULtime.tv_sec = 0;
+ mULtime.tv_nsec = 0;
+ ALOGD("[SetUplinkStartTime] mULtime sec %ld nsec %ld", mULtime.tv_sec, mULtime.tv_nsec);
+ }
+ return 0;
+}
+int32_t AudioVUnlockDL:: GetSRCInputParameter(
+ uint32_t inSR, /* Input, input sampling rate of the conversion */
+ uint32_t inChannel, /* Input, input channel number of the conversion */
+ audio_format_t format
+) {
+
+ ALOGD("[GetSRCInputParameter] mOutputSampleRate %d, mInputSampleRate %d, mInChannel %d, mOutChannel, %d format %d", (int)mOutputSampleRate, (int)inSR, (int)inChannel, (int)mOutChannel, format);
+ if (format != AUDIO_FORMAT_PCM_16_BIT &&
+ format != AUDIO_FORMAT_PCM_32_BIT &&
+ format != AUDIO_FORMAT_PCM_8_24_BIT) {
+ return -1;
+ }
+ mFormat = format;
+ pthread_mutex_lock(&mSRCMutex);
+ if (mInputSampleRate != inSR || mInChannel != inChannel) {
+ mInputSampleRate = inSR;
+ mInChannel = inChannel;
+ if (mpSrcHdl != NULL) {
+ mpSrcHdl->close();
+ deleteMtkAudioSrc(mpSrcHdl);
+ mpSrcHdl = NULL;
+ }
+ }
+ if (mpSrcHdl == NULL && mOutputSampleRate != 0 && mOutChannel != 0 && mInputSampleRate != 0 && mInChannel != 0) {
+ mpSrcHdl = newMtkAudioSrc(mInputSampleRate, mInChannel, mOutputSampleRate, mOutChannel, SRC_IN_Q1P15_OUT_Q1P15);
+ mpSrcHdl->open();
+
+ }
+ if (!mpSrcHdl) {
+ ALOGD("[GetSRCInputParameter] create SRC handle fail");
+ pthread_mutex_unlock(&mSRCMutex);
+ return -1;
+ }
+ pthread_mutex_unlock(&mSRCMutex);
+ return 0;
+}
+
+int32_t AudioVUnlockDL:: SetSRC(
+ uint32_t outSR, /* Input, output sampling rate of the conversion */
+ uint32_t outChannel /* Input, output channel number of the conversion */
+) {
+ if (outSR == 0 || ((outChannel != 1) && (outChannel != 2))) {
+ return -1;
+ }
+ ALOGD("[SetSRC] mOutputSampleRate %d, mInputSampleRate %d, mInChannel %d, mOutChannel, %d ", (int)outSR, (int)mInputSampleRate, (int)mInChannel, (int)outChannel);
+ pthread_mutex_lock(&mSRCMutex);
+ // check if setting change.
+ if (mOutputSampleRate != outSR || mOutChannel != outChannel) {
+ mOutputSampleRate = outSR;
+ mOutChannel = outChannel;
+ if (mpSrcHdl != NULL) {
+ mpSrcHdl->close();
+ deleteMtkAudioSrc(mpSrcHdl);
+ mpSrcHdl = NULL;
+ }
+ }
+
+ //set blisrc
+
+ if (mpSrcHdl == NULL && mOutputSampleRate != 0 && mOutChannel != 0 && mInputSampleRate != 0 && mInChannel != 0) {
+ mpSrcHdl = newMtkAudioSrc(mInputSampleRate, mInChannel, outSR, outChannel, SRC_IN_Q1P15_OUT_Q1P15);
+ mpSrcHdl->open();
+
+ }
+
+ if (!mpSrcHdl) {
+ ALOGD("[SetSRC] create SRC handle fail");
+ pthread_mutex_unlock(&mSRCMutex);
+ return -1;
+ }
+
+ pthread_mutex_unlock(&mSRCMutex);
+ return 0;
+}
+int32_t AudioVUnlockDL:: DoSRC(uint8_t *inbuf, uint32_t *datasz, uint8_t *outbuf, uint32_t *outlength) {
+ uint8_t *inPtr = inbuf ;
+ uint8_t *outPtr = outbuf;
+ uint32_t outbuflen = *outlength;
+ uint32_t dataProduce = 0;
+ uint32_t count = 40;
+ uint32_t dataconsumed = 0;
+ pthread_mutex_lock(&mSRCMutex);
+ if (mpSrcHdl == NULL) {
+ ALOGD("[DoSRC] SRC not created");
+ pthread_mutex_unlock(&mSRCMutex);
+ return -1;
+ }
+
+ while (count) {
+ ALOGV("count %d ,inPtr %p, inbuf %p, datasz %d, outPtr %p, outbuf %p, outlength %d ", count, inPtr, inbuf, *datasz, outPtr, outbuf, *outlength);
+ int consumed_this_time = *datasz;
+ mpSrcHdl->process((int16_t *)inPtr, datasz, (int16_t *)outPtr, outlength);
+ consumed_this_time -= *datasz;
+
+ dataconsumed += consumed_this_time;
+ ALOGV("after count %d , datasz %d, outlength%d ", count, *datasz, *outlength);
+ dataProduce += *outlength;
+ if (*datasz == 0 || *outlength == 0) {
+ break;
+ } else {
+ inPtr = inbuf + dataconsumed;
+ outPtr = outbuf + dataProduce;
+ }
+ // left space in output buffer
+ *outlength = outbuflen - dataProduce;
+ if (*outlength == 0) {
+ break;
+ }
+ count --;
+ }
+
+ pthread_mutex_unlock(&mSRCMutex);
+ /*if(count == 0 && *datasz !=0 && *outlength != 0)
+ {
+ ALOGD("[DoSRC] do not finish SRC *datasz %d, &outlength %d", *datasz,*outlength );
+ //return -1;
+ }*/
+ *outlength = dataProduce;
+ return dataconsumed;
+}
+int32_t AudioVUnlockDL::GetFirstDLTime() {
+ if (!StateInputStart()) {
+ //SXLOGV("[WriteStreamOutToRing] AudioVUnlockDL is not initialized");
+ return -1;
+ }
+
+ if (mGetTime == true) {
+ clock_gettime(CLOCK_MONOTONIC, &mNewDLtime);
+
+ ALOGD("[GetFirstDLTime] DL time %ld, %ld", mNewDLtime.tv_sec, mNewDLtime.tv_nsec);
+ mGetTime = false;
+ if (mDLtime.tv_sec != 0) {
+ mInRemaining = mRingBufIn.GetBufDataSz();
+ mOutRemaining = mRingBufOut.GetBufDataSz();
+ ALOGD("[GetFirstDLTime] input buf never cleared IN remaining %d, Out remaining %d", mInRemaining, mOutRemaining);
+ }
+ }
+ return 0;
+}
+
+int32_t AudioVUnlockDL::SetDownlinkStartTime(int remainMs) {
+ int timeOffset = remainMs < 15 ? 0 : (remainMs - 15);
+
+ if (!StateInputStart()) {
+ return -1;
+ }
+
+ if (mGetTime == true && mInputStandby == false) {
+ clock_gettime(CLOCK_MONOTONIC, &mNewDLtime);
+ //mNewDLtime.tv_nsec = mNewDLtime.tv_nsec + (int64_t)mStreamOutLatency * 1000 * 1000 / 2 - 20000000;
+ mNewDLtime.tv_nsec = mNewDLtime.tv_nsec + (int64_t)timeOffset * 1000 * 1000;
+ if (mNewDLtime.tv_nsec >= 1000000000) {
+ mNewDLtime.tv_sec += 1;
+ mNewDLtime.tv_nsec -= 1000000000;
+ }
+
+ ALOGD("[SetDownlinkStartTime] get DL time: mNewDLtime.tv_sec %ld, mNewDLtime.tv_nsec %ld, remainMs %d", mNewDLtime.tv_sec, mNewDLtime.tv_nsec, remainMs);
+ mGetTime = false;
+ if (mDLtime.tv_sec != 0) {
+ mInRemaining = mRingBufIn.GetBufDataSz();
+ mOutRemaining = mRingBufOut.GetBufDataSz();
+ ALOGD("[SetDownlinkStartTime] input buf never cleared IN remaining %d, Out remaining %d", mInRemaining, mOutRemaining);
+ }
+ }
+
+ return 0;
+}
+
+int32_t AudioVUnlockDL::WriteStreamOutToRing(const void *buf, uint32_t datasz) {
+ int32_t datawritten = 0;
+ //SXLOGD("[WriteStreamOutToRing] start datasz %d", datasz);
+ if (/*mRingBufIn == NULL ||*/ !StateInputStart()) {
+ //SXLOGV("[WriteStreamOutToRing] AudioVUnlockDL is not initialized");
+ return -1;
+ }
+
+ if (buf == NULL || datasz == 0) {
+ ALOGD("[WriteStreamOutToRing] input buf and datasz null");
+ return -1;
+ }
+
+ if (mFormat != AUDIO_FORMAT_PCM_16_BIT) {
+ int32_t shift = 8;
+ if (mFormat == AUDIO_FORMAT_PCM_8_24_BIT) {
+ shift = 8;
+ } else if (mFormat == AUDIO_FORMAT_PCM_32_BIT) {
+ shift = 16;
+ }
+
+ int32_t *pInPtr = (int32_t *)buf;
+ int16_t *pOutPtr = (int16_t *)buf;
+ int32_t framecount = datasz >> 2;
+ int32_t temp;
+
+ while (framecount) {
+ temp = (*pInPtr) >> shift;
+ //ALOGD("temp 0x%x",(((unsigned short*) &temp)[0]) );
+ *pOutPtr = (((unsigned short *) &temp)[0]) ;
+
+ pOutPtr ++;
+ pInPtr ++;
+ framecount--;
+ };
+
+ datasz = datasz >> 1;
+ datawritten = mRingBufIn.Write((void *)buf, datasz);
+ } else {
+
+ datawritten = mRingBufIn.Write((void *)buf, datasz);
+ }
+
+#ifdef DUMP_VPW_StreamIn_DATA
+ if (mOutFile != NULL) {
+ //SXLOGD("[WriteStreamOutToRing] Dump file");
+ fwrite(buf, sizeof(char), datawritten, mOutFile);
+ fclose(mOutFile);
+ //VInstance->mSampleCount_Dump += datawritten>>1;
+ }
+#endif
+ ALOGV("[WriteStreamOutToRing] datawritten %d", datawritten);
+ return datawritten;
+}
+void AudioVUnlockDL::SetInputStandBy(bool val) {
+ mInputStandby = val;
+ if (val) {
+ ALOGV("[SetInputStandBy] val %d", val);
+ int cnt_val = 30;
+ mRingBufOut.SignalBufData();
+ while ((mReadFunctionActive == true) && (cnt_val > 0) && (mNeedBlock == false)) {
+ mRingBufOut.SignalBufData();
+ ALOGD("[SetInputStandBy] wait ReadRefFromRing to exit (%d) ", cnt_val);
+ cnt_val--;
+ usleep(1000 * 3);
+ }
+ ALOGD("[SetInputStandBy] ReadRefFromRing to exit? (%d) ", mReadFunctionActive);
+ mGetTime = true;
+ } else {
+ ALOGV("[SetInputStandBy] val %d", val);
+ }
+}
+bool AudioVUnlockDL::StreamOutStandBy() {
+ return mInputStandby ;
+}
+
+int32_t AudioVUnlockDL::DumpData(void *buf __unused, uint32_t datasz __unused) {
+#ifdef DUMP_VPW_StreamIn_DATA
+ if (mOutFile != NULL) {
+ //SXLOGD("[DumpData] Dump file");
+ mOutFile = fopen("/data/vendor/audiohal/audio_dump/VPW_In.pcm", "ab+");
+ fwrite(buf, sizeof(char), datasz, mOutFile);
+ fclose(mOutFile);
+ //VInstance->mSampleCount_Dump += datawritten>>1;
+ }
+#endif
+ return 0;
+}
+
+int32_t AudioVUnlockDL::ReadRefFromRing(void *buf, uint32_t datasz, void *DLtime) {
+ uint32_t dataread = 0;
+ uint32_t dataAvailable;
+ //uint8_t* tempbuf ;
+ uint32_t finaldataout = 0;
+ uint32_t dataproduced = datasz;
+ uint32_t leftInRing = 0;
+ int32_t dataConsumed = 0;
+ uint8_t *bufptr = (uint8_t *)buf;
+ int count = 10;
+ struct timespec *timeptr;
+ //SXLOGV("[ReadRefFromRing] start ");
+ if (/*mRingBufIn == NULL ||*/ !StateInputStart()) {
+ ALOGD("[ReadRefFromRing] AudioVUnlockDL is not initialized");
+ return -1;
+ }
+
+ if (buf == NULL || datasz == 0 || DLtime == NULL) {
+ ALOGD("[ReadRefFromRing] buf and datasz null");
+ return -1;
+ }
+ //timeptr = (struct timespec*) DLtime
+ //*timeptr = mDLtime;
+
+ mReadFunctionActive = true;
+ struct timespec *ptr;
+ if (mNeedBlock == true) {
+ ALOGV("[ReadRefFromRing] mNeedBlock %d ", mNeedBlock);
+ mRingBufOut.WaitBufData();
+ mNeedBlock = false;
+ }
+
+ if (mOutRemaining != 0) {
+ datasz = mOutRemaining > datasz ? datasz : mOutRemaining;
+ dataproduced = datasz ;
+ }
+ while (count) {
+ //check how much data to be read, if no data then wait
+ if (!mInputStandby && StateInputStart()) {
+ ALOGV("[ReadRefFromRing] mNeedBlock %d ", mNeedBlock);
+ mRingBufOut.WaitBufData();
+ }
+ ptr = (struct timespec *) static_cast< void *>(DLtime);
+ *ptr = mDLtime;
+ //SXLOGV("[ReadRefFromRing] mDLtime.tv_sec %d, mDLtime.tv_nsec %d",mDLtime.tv_sec,mDLtime.tv_nsec );
+ dataread = mRingBufOut.ReadAdvance(bufptr, dataproduced);
+ if (mOutRemaining != 0) {
+ mOutRemaining -= dataread;
+ ALOGV("[ReadRefFromRing] last playback remaining %d", mOutRemaining);
+ }
+ bufptr += dataread;
+ finaldataout += dataread;
+ dataproduced = datasz - finaldataout;
+ if (dataproduced == 0) {
+ ALOGV("[ReadRefFromRing] output buffer filled. break");
+ break;
+ }
+ if (mInputStandby) {
+ if ((mRingBufOut.GetBufDataSz() != 0) && count == 1) {
+ count ++;
+ ALOGI("[ReadRefFromRing] Playback in standby mode, but ringbuf still has data, mRingBufOut.GetBufDataSz() %d, mRingBufIn.GetBufDataSz() %d", mRingBufOut.GetBufDataSz(), mRingBufIn.GetBufDataSz());
+ }
+ }
+ count --;
+ }
+#ifdef DUMP_VPW_StreamIn_DATA
+ if (mOutFile_2 != NULL) {
+
+ mOutFile_2 = fopen("/data/vendor/audiohal/audio_dump/VPW_Out.pcm", "ab+");
+ fwrite(buf, sizeof(char), finaldataout, mOutFile_2);
+ fclose(mOutFile_2);
+ }
+#endif
+ if (finaldataout != datasz) {
+ mNeedBlock = true;
+ }
+
+ ALOGV("[ReadRefFromRing] end finaldataout %d time %ld", finaldataout, mDLtime.tv_sec);
+
+ mReadFunctionActive = false;
+ return finaldataout;
+}
+bool AudioVUnlockDL::startInput() {
+ ALOGV("...[startInput]...");
+
+ int ret = 0;
+ if (StateInputStart()) {
+ ALOGV("[startInput] already start thread");
+ return true;
+ }
+
+ ALOGV("[startInput] +create AudioVUnlockDL ReadRoutine thread");
+ ret = pthread_create(&mReadThread, NULL, ReadRoutine, this);
+ ALOGV("[startInput] -create AudioVUnlockDL ReadRoutine thread");
+ int cnt_val = 10;
+ while ((mReadThreadActive != true) && (cnt_val > 0)) {
+ ALOGV("[startInput] wait thread to exit (%d) ", cnt_val);
+ cnt_val--;
+ usleep(1000 * 10);
+ }
+
+ mOutRemaining = 0;
+ mInRemaining = 0;
+ mRingBufIn.ResetBuf();
+ mRingBufOut.ResetBuf();
+ if (ret == 0)
+ {SetState(VPWStreamIn_READ_START);}
+ //clock_gettime(CLOCK_MONOTONIC, &mDLtime);
+ //SXLOGD("[GetDownlinkSystemTime] mDLtime sec %ld nsec %ld", mDLtime.tv_sec, mDLtime.tv_nsec);
+
+#ifdef DUMP_VPW_StreamIn_DATA
+ if (mOutFile == NULL) {
+ mOutFile = fopen("/data/vendor/audiohal/audio_dump/VPW_In.pcm", "ab+");
+ }
+ if (mOutFile == NULL) {
+ ALOGV("Fail to Open File %x ", mOutFile);
+ }
+
+ if (mOutFile_1 == NULL) {
+ mOutFile_1 = fopen("/data/vendor/audiohal/audio_dump/VPW_SRC.pcm", "ab+");
+ }
+ if (mOutFile_1 == NULL) {
+ ALOGV("Fail to Open File %x ", mOutFile_1);
+ }
+
+ if (mOutFile_2 == NULL) {
+ mOutFile_2 = fopen("/data/vendor/audiohal/audio_dump/VPW_Out.pcm", "ab+");
+ }
+ if (mOutFile_2 == NULL) {
+ ALOGV("Fail to Open File %x ", mOutFile_2);
+ }
+ mSampleCount_Dump = 0;
+#endif
+ return true;
+}
+
+bool AudioVUnlockDL::stopInput() {
+ ALOGD("...[stopInput]...");
+ int ret = 0;
+ int index = 0;
+
+ if (!StateInputStart()) {
+ ALOGD("[stopInput] mState != VPWStreamIn_READ_START mState = %d", mState);
+ return false;
+ }
+
+ pthread_mutex_lock(&mVUnlockReadMutex);
+ mReadThreadExit = true;
+ pthread_mutex_unlock(&mVUnlockReadMutex);
+ int cnt_val = 50;
+
+ while ((mReadThreadActive == true) && (cnt_val > 0)) {
+ ALOGD("[stopInput] wait thread to exit (%d) ", cnt_val);
+ cnt_val--;
+ usleep(1000 * 50);
+ }
+ mULtime.tv_sec = 0;
+ mULtime.tv_nsec = 0;
+ mDLtime.tv_sec = 0;
+ mDLtime.tv_nsec = 0;
+
+ if (cnt_val <= 0) {
+ ALOGD("[stopInput] mReadThreadActive:%d, cnt_val:%d ", mReadThreadActive, cnt_val);
+ }
+#ifdef DUMP_VPW_StreamIn_DATA
+ if (mOutFile != NULL) {
+ ALOGD("[stopInput] Close dump file");
+ fclose(mOutFile);
+ mOutFile = NULL;
+ }
+
+ if (mOutFile_1 != NULL) {
+ ALOGD("[stopInput] Close dump file");
+ fclose(mOutFile_1);
+ mOutFile_1 = NULL;
+ }
+
+ if (mOutFile_2 != NULL) {
+ ALOGD("[stopInput] Close dump file");
+ fclose(mOutFile_2);
+ mOutFile_2 = NULL;
+ }
+#endif
+
+
+ if (mReadThreadActive) {
+ ALOGD("[stopInput] mReadThreadActive is false, stop fail");
+ return false;
+ }
+
+
+ mOutRemaining = 0;
+ mInRemaining = 0;
+
+ // stop read in from Stream out
+ //delete ring buffer
+ ClearState(VPWStreamIn_READ_START);
+ mGetTime = true;
+
+ return true;
+}
+void AudioVUnlockDL::GetStreamOutLatency(int32_t latency) {
+ mStreamOutLatency = latency;
+}
+int32_t AudioVUnlockDL::GetVoiceUnlockULTime(void *ULtime) {
+ struct timespec *ptr;
+ if (ULtime == NULL) {
+ return -1;
+ }
+ ptr = (struct timespec *) static_cast<void *>(ULtime);
+ *ptr = mULtime ;
+ ALOGD("ULtime->tv_sec %ld, ULtime->tv_nsec %ld", ptr->tv_sec, ptr->tv_nsec);
+ return 0;
+}
+
+int32_t AudioVUnlockDL::GetLatency() {
+ int32_t latency = 0;
+#if 0
+ uint32_t Inlatency = 0;
+ uint32_t Outlatency = 0;
+
+ if (/*mRingBufOut == NULL || mRingBufIn == NULL ||*/ !StateInputStart()) {
+ ALOGD("[WriteStreamOutToRing] AudioVUnlockDL is not initialized");
+ return -1;
+ }
+ Inlatency = mRingBufIn.GetBufDataSz();
+ ALOGD("[GetLatency] mRingBufIn buffer data %d bytes", Inlatency);
+ Outlatency = mRingBufOut.GetBufDataSz();
+
+ ALOGD("[GetLatency] mRingBufOut data %d bytes", Outlatency);
+ if (mInputSampleRate != 0 && mInChannel != 0) {
+ Inlatency = Inlatency * 1000 / (mInputSampleRate * mInChannel) / 2;
+ }
+
+ if (mOutputSampleRate != 0 && mOutChannel != 0) {
+ Outlatency = Outlatency * 1000 / (mOutputSampleRate * mOutChannel) / 2;
+ }
+#endif
+ return latency;
+}
+void AudioVUnlockDL::ClearState(uint32_t state) {
+ ALOGD("clear AudioVUnlockDL state = %d", state);
+ mState &= (~state);
+ ALOGD("clear AudioVUnlockDL mState = %d", mState);
+}
+
+void AudioVUnlockDL::SetState(uint32_t state) {
+ ALOGD("Set AudioVUnlockDL state = %d", state);
+ mState |= state;
+ ALOGD("Set AudioVUnlockDL mState = %d", mState);
+}
+int32_t AudioVUnlockDL::GetState(void) {
+ return mState;
+}
+bool AudioVUnlockDL::StateInputStart(void) {
+ return mState & VPWStreamIn_READ_START;
+}
+
+void AudioVUnlockDL:: freeInstance() {
+ ALOGV("+delete UniqueVUnlockDLInstance");
+ if (UniqueVUnlockDLInstance != NULL) {
+ delete UniqueVUnlockDLInstance;
+ }
+
+ UniqueVUnlockDLInstance = NULL;
+ return;
+}
+
+AudioVUnlockDL *AudioVUnlockDL::getInstance() {
+ //SXLOGV("+new Voice unlock DL instance fd, size, flag");
+ if (UniqueVUnlockDLInstance == NULL) {
+
+ UniqueVUnlockDLInstance = new AudioVUnlockDL();
+
+ }
+ return UniqueVUnlockDLInstance;
+}
+#if 0//def forUT
+#ifdef MTK_BASIC_PACKAGE
+bool AudioVUnlockDL::StateStartwrite(void) {
+ return false;
+}
+
+bool AudioVUnlockDL::startWrite(void) {
+ return false;
+}
+
+bool AudioVUnlockDL::stopWrite() {
+ return false;
+}
+#else
+void *WriteRoutine(void *hdl) {
+ AudioVUnlockDL *VInstance = AudioVUnlockDL::getInstance();
+ int result = -1;
+ int32_t buflen = 640;
+ char *buf = new char[640];
+ pthread_mutex_lock(&mVUnlockWriteMutex);
+ VInstance->mWriteThreadExit = false;
+ VInstance->mWriteThreadActive = true;
+ pthread_mutex_unlock(&mVUnlockWriteMutex);
+ FILE *OutFile = NULL;
+ OutFile = fopen("/system/VPW.pcm", "wb");
+ if (OutFile == NULL) {
+ ALOGD("Fail to Open File %x ", OutFile);
+ }
+
+#ifdef MTK_AUDIO_ADJUST_PRIORITY
+ // if set prority false , force to set priority
+ if (result == -1) {
+ struct sched_param sched_p;
+ sched_getparam(0, &sched_p);
+ sched_p.sched_priority = RTPM_PRIO_AUDIO_I2S;
+ if (0 != sched_setscheduler(0, SCHED_RR, &sched_p)) {
+ ALOGI("[%s] failed, errno: %d", __func__, errno);
+ } else {
+ sched_p.sched_priority = RTPM_PRIO_AUDIO_I2S;
+ sched_getparam(0, &sched_p);
+ ALOGD("sched_setscheduler ok, priority: %d", sched_p.sched_priority);
+ }
+ }
+#endif
+
+ //VInstance ->SetSRC(16000,1);
+ //VInstance -> startInput();
+
+ if (AudioSystem::getVoiceUnlockDLInstance()) {
+ ALOGD(" get Voice Unlock Instance ok");
+ }
+ int latency = AudioSystem::GetVoiceUnlockDLLatency();
+ ALOGD(" get Voice Unlock latency %d", latency);
+ AudioSystem::SetVoiceUnlockSRC(16000, 1);
+ AudioSystem::startVoiceUnlockDL();
+ while (!VInstance->mWriteThreadExit) {
+ int32_t dataSRC;
+ int32_t latency;
+ ALOGD(" [write routine] ReadRefFromRing ");
+ struct timespec DLtime;
+ struct timespec ULtime;
+ dataSRC = AudioSystem::ReadRefFromRing(buf, buflen, (void *)&DLtime);
+ ALOGD(" [write routine] DL time %d %d dataSRC %d", DLtime.tv_sec, DLtime.tv_nsec, dataSRC);
+
+ AudioSystem::GetVoiceUnlockULTime((void *)&ULtime);
+ ALOGD("[write routine] UL time %d %d ", ULtime.tv_sec, ULtime.tv_nsec);
+
+ latency = AudioSystem::GetVoiceUnlockDLLatency();
+ ALOGD(" get Voice Unlock latency %d", latency);
+ if (dataSRC > 0) {
+#ifdef DUMP_VPW_StreamIn_DATA
+ if (OutFile != NULL) {
+ ALOGV("[DumpData] Dump file");
+ fwrite(buf, sizeof(char), dataSRC, OutFile);
+ }
+#endif
+ } else if (dataSRC == -1) {
+ ALOGD("[write routine] dataSRC %d, exit", dataSRC);
+ break;
+ }
+ //latency = VInstance->GetLatency();
+ //SXLOGD("[write routine] latency %d ms", latency);
+ ALOGD("[write routine] dataSRC %d, sleep", dataSRC);
+ usleep(10 * 1000);
+ }
+
+ pthread_mutex_lock(&mVUnlockWriteMutex);
+ VInstance->mWriteThreadExit = true;
+ VInstance->mWriteThreadActive = false;
+ pthread_mutex_unlock(&mVUnlockWriteMutex);
+ ALOGD("[WriteRoutine] exit ");
+ VInstance->ClearState(VPWStreamIn_WRITE_START);
+
+ AudioSystem::freeVoiceUnlockDLInstance();
+ if (OutFile != NULL) {
+ ALOGD("[stopInput] Close dump file");
+ fclose(OutFile);
+ OutFile = NULL;
+ }
+ return 0;
+}
+bool AudioVUnlockDL::StateStartwrite(void) {
+ return mState & VPWStreamIn_WRITE_START;
+}
+
+bool AudioVUnlockDL::startWrite() {
+ ALOGD("...[startwrite]...");
+
+ int ret = 0;
+ if (StateStartwrite()) {
+ return true;
+ }
+
+ ALOGD("[startwrite] +create AudioVUnlockDL WriteRoutine thread");
+ ret = pthread_create(&mWriteThread, NULL, WriteRoutine, this);
+ ALOGD("[startwrite] -create AudioVUnlockDL WriteRoutine thread");
+ if (ret == 0)
+ {SetState(VPWStreamIn_WRITE_START);}
+
+ return true;
+}
+
+bool AudioVUnlockDL::stopWrite() {
+ ALOGD("...[stopWrite]...");
+ int ret = 0;
+ int index = 0;
+
+ if (!StateStartwrite()) {
+ ALOGD("[stopWrite] mState != VPWStreamIn_READ_START mState = %d", mState);
+ return false;
+ }
+ AudioSystem::stopVoiceUnlockDL();
+
+ pthread_mutex_lock(&mVUnlockWriteMutex);
+ mWriteThreadExit = true;
+ pthread_mutex_unlock(&mVUnlockWriteMutex);
+
+ int cnt_val = 50;
+
+ while ((mWriteThreadActive == true) && (cnt_val > 0)) {
+ ALOGD("[stopWrite] wait thread to exit (%d) ", cnt_val);
+ cnt_val--;
+ usleep(1000 * 50);
+ }
+
+ if (cnt_val <= 0) {
+ ALOGD("[stopWrite] mWriteThreadActive:%d, cnt_val:%d ", mWriteThreadActive, cnt_val);
+ }
+
+
+ if (mReadThreadActive) {
+ ALOGD("[stopWrite] mWriteThreadActive is false, stop fail");
+ return false;
+ }
+ // stop read in from Stream out
+ //delete ring buffer
+ ClearState(VPWStreamIn_WRITE_START);
+
+ return true;
+}
+#endif
+#endif
+
+}
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioVolumeFactory.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioVolumeFactory.cpp
new file mode 100644
index 0000000..12a1293
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/AudioVolumeFactory.cpp
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioVolumeFactory.h"
+
+AudioVolumeInterface *AudioVolumeFactory::CreateAudioVolumeController() {
+ // here can create diffeerent volumecontroller base on differemt platform or policy
+ AudioVolumeInterface *mInstance = NULL;
+#ifdef MTK_AUDIO_GAIN_TABLE
+ mInstance = android::AudioMTKGainController::getInstance();
+#else
+ mInstance = android::AudioALSAVolumeController::getInstance();
+#endif
+ return mInstance;
+}
+
+void DestroyAudioVolumeController() {
+ //here to destroy
+}
\ No newline at end of file
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/LoopbackManager.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/LoopbackManager.cpp
new file mode 100644
index 0000000..b0f5023
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/LoopbackManager.cpp
@@ -0,0 +1,447 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "LoopbackManager"
+#include "LoopbackManager.h"
+
+#include <hardware_legacy/power.h>
+
+//#include <DfoDefines.h>
+
+#include "AudioALSAStreamManager.h"
+
+#include "AudioALSALoopbackController.h"
+#include "AudioALSASpeechLoopbackController.h"
+
+#include <SpeechEnhancementController.h>
+#include <SpeechDriverFactory.h>
+
+#include "AudioALSAHardwareResourceManager.h"
+
+#include "AudioVolumeFactory.h"
+
+#if defined(MTK_NEW_VOL_CONTROL)
+#include "AudioGainTableParamParser.h"
+#endif
+
+namespace android {
+static const char LOOPBACK_WAKELOCK_NAME[] = "LOOPBACK_WAKELOCK_NAME";
+
+static const float kVoiceVolumeForLoopback = 1.0f; // max
+static const float kMasterVolumeForLoopback = 1.0f; // max
+
+
+LoopbackManager *LoopbackManager::mLoopbackManager = NULL;
+LoopbackManager *LoopbackManager::GetInstance() {
+ if (mLoopbackManager == NULL) {
+ mLoopbackManager = new LoopbackManager();
+ }
+ ASSERT(mLoopbackManager != NULL);
+ return mLoopbackManager;
+}
+
+LoopbackManager::LoopbackManager() :
+ mLoopbackType(NO_LOOPBACK),
+ mAudioALSAVolumeController(AudioVolumeFactory::CreateAudioVolumeController()),
+ mInputDeviceCopy(AUDIO_DEVICE_IN_BUILTIN_MIC),
+ mOutputDeviceCopy(AUDIO_DEVICE_OUT_SPEAKER),
+ mVoiceVolumeCopy(1.0f),
+ mMasterVolumeCopy(1.0f),
+ mWorkingModemIndex(MODEM_1),
+ mBtHeadsetNrecOnCopy(true),
+ mLpbkRestoreVoiceVolume(false),
+ mLpbkRestoreMasterVolume(false) {
+
+ char isMD1Supported[PROPERTY_VALUE_MAX];
+ property_get("ro.boot.opt_md1_support", isMD1Supported, "0"); //"0": default not support
+
+ int i4MD1Supported = atoi(isMD1Supported);
+ mWorkingModemIndex = MODEM_1;
+ memset(&mMaskCopy, 0, sizeof(mMaskCopy));
+ ALOGD("%s(), isMD1Supported = %s, mWorkingModemIndex=%d", __FUNCTION__, isMD1Supported, mWorkingModemIndex);
+
+}
+
+LoopbackManager::~LoopbackManager() {
+
+}
+
+loopback_t LoopbackManager::GetLoopbackType() {
+ ALOGV("%s(), mLoopbackType = %d", __FUNCTION__, mLoopbackType);
+ return mLoopbackType;
+}
+
+status_t LoopbackManager::SetLoopbackOn(loopback_t loopback_type, loopback_output_device_t loopback_output_device) {
+ ALOGD("+%s(), loopback_type = %d, loopback_output_device = %d", __FUNCTION__, loopback_type, loopback_output_device);
+
+ Mutex::Autolock _l(mLock);
+
+ if (mLoopbackType != NO_LOOPBACK) { // check no loobpack function on
+ ALOGD("-%s() : Please Turn off Loopback Type %d First!!", __FUNCTION__, mLoopbackType);
+ return ALREADY_EXISTS;
+ } else if (CheckLoopbackTypeIsValid(loopback_type) != NO_ERROR) { // to avoid using undefined loopback type & ref/dual mic in single mic project
+ ALOGW("-%s(): No such Loopback type %d", __FUNCTION__, loopback_type);
+ return BAD_TYPE;
+ }
+
+
+ // suspend & standby all input/output streams
+ // if ((loopback_type != AP_BT_LOOPBACK_NO_CODEC) && (loopback_type != AP_BT_LOOPBACK))
+ // AP_BT_LOOPBACK_NO_CODEC no need to standby
+ if (loopback_type != AP_BT_LOOPBACK_NO_CODEC) {
+ AudioALSAStreamManager::getInstance()->setAllStreamsSuspend(true);
+ AudioALSAStreamManager::getInstance()->standbyAllStreams();
+ }
+
+ // copy current device // TODO(Harvey): recover device
+ //mInputDeviceCopy = (audio_devices_t)pAudioResourceManager->getUlInputDevice();
+ //mOutputDeviceCopy = (audio_devices_t)pAudioResourceManager->getDlOutputDevice();
+
+ // get loopback device
+ audio_devices_t input_device = GetInputDeviceByLoopbackType(loopback_type);
+ audio_devices_t output_device = GetOutputDeviceByLoopbackType(loopback_type, loopback_output_device);
+
+ // set specific mic type
+ if (loopback_type == AP_MAIN_MIC_AFE_LOOPBACK || loopback_type == MD_MAIN_MIC_ACOUSTIC_LOOPBACK) {
+ AudioALSAHardwareResourceManager::getInstance()->setBuiltInMicSpecificType(BUILTIN_MIC_MIC1_ONLY);
+ } else if (loopback_type == AP_REF_MIC_AFE_LOOPBACK || loopback_type == MD_REF_MIC_ACOUSTIC_LOOPBACK) {
+ AudioALSAHardwareResourceManager::getInstance()->setBuiltInMicSpecificType(BUILTIN_MIC_MIC2_ONLY);
+ } else if (loopback_type == AP_3RD_MIC_AFE_LOOPBACK || loopback_type == MD_3RD_MIC_ACOUSTIC_LOOPBACK) {
+ AudioALSAHardwareResourceManager::getInstance()->setBuiltInMicSpecificType(BUILTIN_MIC_MIC3_ONLY);
+ }
+
+
+ // check modem status
+ if (CheckIsModemLoopback(loopback_type) == true) {
+ SpeechDriverInterface *pSpeechDriver = SpeechDriverFactory::GetInstance()->GetSpeechDriverByIndex(mWorkingModemIndex);
+ if (pSpeechDriver->CheckModemIsReady() == false) { // modem is sleep...
+ for (int modem_index = MODEM_1; modem_index < NUM_MODEM; modem_index++) { // get working modem index
+ pSpeechDriver = SpeechDriverFactory::GetInstance()->GetSpeechDriverByIndex((modem_index_t)modem_index);
+ if (pSpeechDriver != NULL && pSpeechDriver->CheckModemIsReady() == true) {
+ mWorkingModemIndex = (modem_index_t)modem_index;
+ SpeechDriverFactory::GetInstance()->SetActiveModemIndex(mWorkingModemIndex);
+ break;
+ }
+ }
+ }
+ }
+
+ // to avoid BT test being interferenced by modem side speech enhancement
+ mBtHeadsetNrecOnCopy = SpeechEnhancementController::GetInstance()->GetBtHeadsetNrecOn();
+ if (loopback_type == MD_BT_LOOPBACK || loopback_type == MD_BT_LOOPBACK_NO_CODEC) {
+ SpeechEnhancementController::GetInstance()->SetBtHeadsetNrecOnToAllModem(false);
+ }
+
+ // to turn on/off DMNR
+ if (loopback_type == MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITHOUT_DMNR ||
+ loopback_type == MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITH_DMNR) {
+ mMaskCopy = SpeechEnhancementController::GetInstance()->GetSpeechEnhancementMask(); // copy DMNR mask
+ sph_enh_mask_struct_t mask = mMaskCopy;
+ if (loopback_type == MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITHOUT_DMNR) {
+ mask.dynamic_func &= (~SPH_ENH_DYNAMIC_MASK_DMNR);
+ } else if (loopback_type == MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITH_DMNR) {
+ mask.dynamic_func |= SPH_ENH_DYNAMIC_MASK_DMNR;
+ }
+ SpeechDriverFactory::GetInstance()->GetSpeechDriverByIndex(mWorkingModemIndex)->SetSpeechEnhancementMask(mask);
+ }
+
+ // save opened loobpack type
+ mLoopbackType = loopback_type;
+
+ // BT CVSD
+ if (loopback_type == AP_BT_LOOPBACK) {
+ AudioALSALoopbackController::getInstance()->SetApBTCodec(true);
+ AudioALSALoopbackController::getInstance()->OpenAudioLoopbackControlFlow(input_device, output_device);
+ } else if (loopback_type == AP_BT_LOOPBACK_NO_CODEC) {
+ AudioALSALoopbackController::getInstance()->SetApBTCodec(false);
+ AudioALSALoopbackController::getInstance()->OpenAudioLoopbackControlFlow(input_device, output_device);
+ } else if (loopback_type == MD_BT_LOOPBACK) {
+ AudioALSASpeechLoopbackController::getInstance()->SetModemBTCodec(true);
+ AudioALSASpeechLoopbackController::getInstance()->OpenModemLoopbackControlFlow(input_device, output_device);
+ } else if (loopback_type == MD_BT_LOOPBACK_NO_CODEC) {
+ AudioALSASpeechLoopbackController::getInstance()->SetModemBTCodec(false);
+ AudioALSASpeechLoopbackController::getInstance()->OpenModemLoopbackControlFlow(input_device, output_device);
+ } else {
+ // Enable loopback function
+ switch (loopback_type) {
+ case AP_MAIN_MIC_AFE_LOOPBACK:
+ case AP_HEADSET_MIC_AFE_LOOPBACK:
+ case AP_REF_MIC_AFE_LOOPBACK:
+ case AP_3RD_MIC_AFE_LOOPBACK:
+ //case AP_BT_LOOPBACK:
+ //case AP_BT_LOOPBACK_NO_CODEC:
+ {
+ AudioALSALoopbackController::getInstance()->open(output_device, input_device);
+ break;
+ }
+ case MD_MAIN_MIC_ACOUSTIC_LOOPBACK:
+ case MD_HEADSET_MIC_ACOUSTIC_LOOPBACK:
+ case MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITHOUT_DMNR:
+ case MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITH_DMNR:
+ case MD_REF_MIC_ACOUSTIC_LOOPBACK:
+ case MD_3RD_MIC_ACOUSTIC_LOOPBACK:
+ //case MD_BT_LOOPBACK:
+ //case MD_BT_LOOPBACK_NO_CODEC:
+ {
+#if (!defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)) && defined(MTK_AUDIO_SPH_LPBK_PARAM)
+ AudioALSAStreamManager::getInstance()->UpdateSpeechLpbkParams();
+#endif
+ AudioALSASpeechLoopbackController::getInstance()->open(output_device, input_device);
+ break;
+ }
+ default: {
+ ALOGW("%s(): Loopback type %d not implemented!!", __FUNCTION__, loopback_type);
+ ASSERT(0);
+ }
+ }
+ }
+ /*
+ // only use L ch data, so mute R ch. (Disconnect ADC_I2S_IN_R -> MODEM_PCM_TX_R)
+ if (loopback_type == MD_MAIN_MIC_ACOUSTIC_LOOPBACK ||
+ loopback_type == MD_REF_MIC_ACOUSTIC_LOOPBACK)
+ {
+ AudioDigitalControlFactory::CreateAudioDigitalControl()->SetinputConnection(
+ AudioDigitalType::DisConnect,
+ AudioDigitalType::I04,
+ (mWorkingModemIndex == MODEM_1) ? AudioDigitalType::O18 : AudioDigitalType::O08);
+ }
+ */
+
+ // acquire wake lock
+ int ret = acquire_wake_lock(PARTIAL_WAKE_LOCK, LOOPBACK_WAKELOCK_NAME);
+ ALOGD("%s(), acquire_wake_lock:%s, return %d.", __FUNCTION__, LOOPBACK_WAKELOCK_NAME, ret);
+ // Volume
+ if ((loopback_type != AP_BT_LOOPBACK) && (loopback_type != AP_BT_LOOPBACK_NO_CODEC) && (loopback_type != MD_BT_LOOPBACK) && (loopback_type != MD_BT_LOOPBACK_NO_CODEC)) {
+ if (CheckIsModemLoopback(loopback_type) == true) {
+ mVoiceVolumeCopy = mAudioALSAVolumeController->getVoiceVolume();
+#if defined(MTK_NEW_VOL_CONTROL)
+ mAudioALSAVolumeController->setAnalogVolume(AUDIO_STREAM_VOICE_CALL, output_device, GAIN_MAX_SPEECH_VOL_INDEX, AUDIO_MODE_IN_CALL);
+#else
+ mAudioALSAVolumeController->setVoiceVolume(kVoiceVolumeForLoopback, AUDIO_MODE_IN_CALL, output_device);
+#endif
+ } else {
+ mMasterVolumeCopy = mAudioALSAVolumeController->getMasterVolume();
+#if defined(MTK_NEW_VOL_CONTROL)
+ mAudioALSAVolumeController->setAnalogVolume(AUDIO_STREAM_MUSIC, output_device, GAIN_MAX_VOL_INDEX, AUDIO_MODE_NORMAL);
+#else
+ mAudioALSAVolumeController->setMasterVolume(kMasterVolumeForLoopback, AUDIO_MODE_NORMAL, output_device);
+#endif
+ }
+ }
+
+ ALOGD("-%s(), loopback_type = %d, loopback_output_device = %d", __FUNCTION__, loopback_type, loopback_output_device);
+ return NO_ERROR;
+}
+
+status_t LoopbackManager::SetLoopbackOff() {
+ Mutex::Autolock _l(mLock);
+
+ ALOGD("+%s(), mLoopbackType = %d", __FUNCTION__, mLoopbackType);
+ if (mLoopbackType == NO_LOOPBACK) { // check loobpack do exist to be turned off
+ ALOGD("-%s() : No looback to be closed", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ // Disable Loopback function
+
+ // BT CVSD
+ if ((mLoopbackType == AP_BT_LOOPBACK) || (mLoopbackType == AP_BT_LOOPBACK_NO_CODEC)) {
+ AudioALSALoopbackController::getInstance()->CloseAudioLoopbackControlFlow();
+ } else if ((mLoopbackType == MD_BT_LOOPBACK) || (mLoopbackType == MD_BT_LOOPBACK_NO_CODEC)) {
+ AudioALSASpeechLoopbackController::getInstance()->CloseModemLoopbackControlFlow();
+ } else {
+ switch (mLoopbackType) {
+ case AP_MAIN_MIC_AFE_LOOPBACK:
+ case AP_HEADSET_MIC_AFE_LOOPBACK:
+ case AP_REF_MIC_AFE_LOOPBACK:
+ case AP_3RD_MIC_AFE_LOOPBACK:
+ //case AP_BT_LOOPBACK:
+ //case AP_BT_LOOPBACK_NO_CODEC:
+ {
+ AudioALSALoopbackController::getInstance()->close();
+ break;
+ }
+ case MD_MAIN_MIC_ACOUSTIC_LOOPBACK:
+ case MD_HEADSET_MIC_ACOUSTIC_LOOPBACK:
+ case MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITHOUT_DMNR:
+ case MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITH_DMNR:
+ case MD_REF_MIC_ACOUSTIC_LOOPBACK:
+ case MD_3RD_MIC_ACOUSTIC_LOOPBACK:
+ //case MD_BT_LOOPBACK:
+ //case MD_BT_LOOPBACK_NO_CODEC:
+ {
+ AudioALSASpeechLoopbackController::getInstance()->close();
+#if !defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)&&defined(MTK_AUDIO_SPH_LPBK_PARAM)
+ AudioALSAStreamManager::getInstance()->updateSpeechNVRAMParam(0);
+#endif
+ break;
+ }
+ default: {
+ ALOGW("%s(): Loopback type %d not implemented!!", __FUNCTION__, mLoopbackType);
+ ASSERT(0);
+ }
+ }
+ }
+
+ // recover DMNR
+ if (mLoopbackType == MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITHOUT_DMNR ||
+ mLoopbackType == MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITH_DMNR) {
+ SpeechDriverFactory::GetInstance()->GetSpeechDriverByIndex(mWorkingModemIndex)->SetSpeechEnhancementMask(mMaskCopy);
+ }
+
+ // recover modem side speech enhancement
+ if (mLoopbackType == MD_BT_LOOPBACK || mLoopbackType == MD_BT_LOOPBACK_NO_CODEC) {
+ SpeechEnhancementController::GetInstance()->SetBtHeadsetNrecOnToAllModem(mBtHeadsetNrecOnCopy);
+ }
+
+ // recover device
+ //pAudioResourceManager->setDlOutputDevice(mOutputDeviceCopy);
+ //pAudioResourceManager->setUlInputDevice(mInputDeviceCopy);
+
+ // recover specific mic type
+ if (mLoopbackType == AP_MAIN_MIC_AFE_LOOPBACK || mLoopbackType == MD_MAIN_MIC_ACOUSTIC_LOOPBACK ||
+ mLoopbackType == AP_REF_MIC_AFE_LOOPBACK || mLoopbackType == MD_REF_MIC_ACOUSTIC_LOOPBACK ||
+ mLoopbackType == AP_3RD_MIC_AFE_LOOPBACK || mLoopbackType == MD_3RD_MIC_ACOUSTIC_LOOPBACK) {
+ AudioALSAHardwareResourceManager::getInstance()->setBuiltInMicSpecificType(BUILTIN_MIC_DEFAULT);
+ }
+
+
+ // recover volume
+ if ((mLoopbackType != AP_BT_LOOPBACK) && (mLoopbackType != AP_BT_LOOPBACK_NO_CODEC) && (mLoopbackType != MD_BT_LOOPBACK) && (mLoopbackType != MD_BT_LOOPBACK_NO_CODEC)) {
+ if (CheckIsModemLoopback(mLoopbackType) == true) {
+ mAudioALSAVolumeController->setVoiceVolume(mVoiceVolumeCopy, AUDIO_MODE_IN_CALL, mOutputDeviceCopy);
+ } else {
+ mAudioALSAVolumeController->setMasterVolume(mMasterVolumeCopy, AUDIO_MODE_NORMAL, mOutputDeviceCopy);
+ }
+ }
+
+ // release wake lock
+ int ret = release_wake_lock(LOOPBACK_WAKELOCK_NAME);
+ ALOGD("%s(), release_wake_lock:%s return %d.", __FUNCTION__, LOOPBACK_WAKELOCK_NAME, ret);
+
+ // unsuspend all input/output streams
+ if (mLoopbackType != AP_BT_LOOPBACK_NO_CODEC) {
+ AudioALSAStreamManager::getInstance()->setAllStreamsSuspend(false);
+ }
+
+ // clean
+ mLoopbackType = NO_LOOPBACK;
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t LoopbackManager::CheckLoopbackTypeIsValid(loopback_t loopback_type) {
+ status_t retval;
+
+ switch (loopback_type) {
+ case AP_MAIN_MIC_AFE_LOOPBACK:
+ case AP_HEADSET_MIC_AFE_LOOPBACK:
+ case AP_3RD_MIC_AFE_LOOPBACK:
+ case MD_MAIN_MIC_ACOUSTIC_LOOPBACK:
+ case MD_HEADSET_MIC_ACOUSTIC_LOOPBACK:
+ case MD_3RD_MIC_ACOUSTIC_LOOPBACK:
+ case AP_BT_LOOPBACK:
+ case MD_BT_LOOPBACK:
+ case AP_BT_LOOPBACK_NO_CODEC:
+ case MD_BT_LOOPBACK_NO_CODEC:
+ retval = NO_ERROR;
+ break;
+ case AP_REF_MIC_AFE_LOOPBACK:
+ case MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITHOUT_DMNR:
+ case MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITH_DMNR:
+ case MD_REF_MIC_ACOUSTIC_LOOPBACK:
+ if (AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport() >= 2) {
+ retval = NO_ERROR;
+ } else {
+ retval = BAD_TYPE;
+ }
+ break;
+ default:
+ retval = BAD_TYPE;
+ break;
+ }
+
+ return retval;
+}
+
+
+audio_devices_t LoopbackManager::GetInputDeviceByLoopbackType(loopback_t loopback_type) {
+ audio_devices_t input_device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+
+ switch (loopback_type) {
+ case AP_MAIN_MIC_AFE_LOOPBACK:
+ case MD_MAIN_MIC_ACOUSTIC_LOOPBACK:
+ case MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITHOUT_DMNR:
+ case MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITH_DMNR:
+ case AP_REF_MIC_AFE_LOOPBACK:
+ case MD_REF_MIC_ACOUSTIC_LOOPBACK:
+ case AP_3RD_MIC_AFE_LOOPBACK:
+ case MD_3RD_MIC_ACOUSTIC_LOOPBACK: {
+ input_device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ break;
+ }
+ case AP_HEADSET_MIC_AFE_LOOPBACK:
+ case MD_HEADSET_MIC_ACOUSTIC_LOOPBACK: {
+ input_device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ break;
+ }
+ case AP_BT_LOOPBACK:
+ case MD_BT_LOOPBACK:
+ case AP_BT_LOOPBACK_NO_CODEC:
+ case MD_BT_LOOPBACK_NO_CODEC: {
+ input_device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ break;
+ }
+ default: {
+ ALOGW("%s(): Loopback type %d not implemented!!", __FUNCTION__, loopback_type);
+ ASSERT(0);
+ }
+ }
+
+ return input_device;
+}
+
+audio_devices_t LoopbackManager::GetOutputDeviceByLoopbackType(loopback_t loopback_type, loopback_output_device_t loopback_output_device) {
+ // BT Loopback only use BT headset
+ if (loopback_type == AP_BT_LOOPBACK ||
+ loopback_type == MD_BT_LOOPBACK ||
+ loopback_type == AP_BT_LOOPBACK_NO_CODEC ||
+ loopback_type == MD_BT_LOOPBACK_NO_CODEC) { // BT
+ return AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ }
+
+ // Get Output Devices By LoopbackType
+ audio_devices_t output_device;
+
+ switch (loopback_output_device) {
+ case LOOPBACK_OUTPUT_RECEIVER: {
+ output_device = AUDIO_DEVICE_OUT_EARPIECE;
+ break;
+ }
+ case LOOPBACK_OUTPUT_EARPHONE: {
+ if (loopback_type == AP_HEADSET_MIC_AFE_LOOPBACK ||
+ loopback_type == MD_HEADSET_MIC_ACOUSTIC_LOOPBACK) {
+ output_device = AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ } else {
+ output_device = AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ }
+ break;
+ }
+ case LOOPBACK_OUTPUT_SPEAKER: {
+ output_device = AUDIO_DEVICE_OUT_SPEAKER;
+ break;
+ }
+ default: {
+ output_device = AUDIO_DEVICE_OUT_EARPIECE;
+ break;
+ }
+ }
+
+ return output_device;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/SpeechDataProcessingHandler.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/SpeechDataProcessingHandler.cpp
new file mode 100644
index 0000000..5edafc8
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/SpeechDataProcessingHandler.cpp
@@ -0,0 +1,616 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "SpeechDataProcessingHandler.h"
+
+#include <sys/prctl.h>
+#include "AudioALSACaptureDataProviderVoiceDL.h"
+#include "AudioALSACaptureDataProviderVoiceUL.h"
+#include "AudioALSACaptureDataProviderVoiceMix.h"
+#include "AudioType.h"
+#include "SpeechDriverFactory.h"
+#include "SpeechMessengerInterface.h"
+#include "SpeechType.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "SpeechDataProcessingHandler"
+
+#define SINE_WAVE_ENABLED 0
+
+namespace android {
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+
+static const uint32_t kPcmRingBufferSize = 0x1000; // 4k, used for DL/UL
+
+static const uint32_t kTargetSampleRate = 16000;
+
+static const audio_format_t kTargetBitFormat = AUDIO_FORMAT_PCM_16_BIT;
+
+static const uint32_t kTargetULChannelNumber = 1;
+
+static const uint32_t kTargetDLChannelNumber = 1;
+
+
+/*==============================================================================
+ * Utils
+ *============================================================================*/
+
+// 166Hz for 8kHz
+#define TBL_SZ_48KHz_1K 48
+
+const uint16_t tone1k_48kHz[TBL_SZ_48KHz_1K] = {
+ 0xFFFA, 0x075B, 0x0E9C, 0x159C, 0x1C3D, 0x2263, 0x27F3, 0x2CD4,
+ 0x30F0, 0x3435, 0x3697, 0x3808, 0x3885, 0x380A, 0x3699, 0x3439,
+ 0x30F5, 0x2CDB, 0x27FB, 0x226C, 0x1C47, 0x15A7, 0x0EA7, 0x0766,
+ 0x0006, 0xF8A5, 0xF165, 0xEA63, 0xE3C2, 0xDD9C, 0xD80C, 0xD32C,
+ 0xCF11, 0xCBCB, 0xC969, 0xC7F8, 0xC77A, 0xC7F7, 0xC967, 0xCBC6,
+ 0xCF0B, 0xD326, 0xD804, 0xDD94, 0xE3BA, 0xEA5A, 0xF15A, 0xF89A
+};
+
+void dumpRingBuf(const char *str, RingBuf *buf) {
+ int count = RingBuf_getDataCount(buf);
+ ALOGD("%s(), Dump %s ,base: 0x%p, len: %d, read: 0x%p, write: 0x%p, data_count: %d\n", __FUNCTION__, str, buf->pBufBase, buf->bufLen, buf->pRead, buf->pWrite, count);
+ ALOGD(" [0] 0x%c [1] 0x%c [2] 0x%c [3] 0x%c... [%d] 0x%c [%d] 0x%c\n", buf->pBufBase[0], buf->pBufBase[1], buf->pBufBase[2], buf->pBufBase[3], count - 2, buf->pBufBase[count - 2], count - 1, buf->pBufBase[count - 1]);
+}
+
+void dumpLinearBuf(const char *str, const char *buf, int from, int to) {
+ ALOGD("%s(),Dump %s buffer(%p)\n", __FUNCTION__, str, buf);
+ for (int i = from; i <= to; i++) {
+ ALOGD("%s(), [%d] %c\n", __FUNCTION__, i, buf[i]);
+ }
+}
+
+void setupLinearBufWithSineWave(char *buf, uint32_t size) {
+ ALOGD("%s(), buf = %p, size = %d\n", __FUNCTION__, buf, size);
+ char *p = buf;
+ static uint32_t index_of_table = 0;
+ uint32_t table_bytes = TBL_SZ_48KHz_1K * sizeof(uint16_t);
+
+ if (index_of_table != 0) {
+ memcpy(p, &((char *)tone1k_48kHz)[index_of_table], table_bytes - index_of_table);
+ size -= table_bytes - index_of_table;
+ p += table_bytes - index_of_table;
+ index_of_table = 0;
+ }
+
+ while (size >= table_bytes) {
+ memcpy(p, tone1k_48kHz, table_bytes);
+ size -= table_bytes;
+ p += table_bytes;
+ }
+
+ if (size > 0) {
+ memcpy(p, tone1k_48kHz, size);
+ index_of_table += size;
+ }
+}
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+SpeechDataProcessingHandler *SpeechDataProcessingHandler::mSpeechDataProcessingHandler = NULL;
+AudioLock speechDataProcessingHandlerLock;
+
+SpeechDataProcessingHandler *SpeechDataProcessingHandler::getInstance() {
+ AL_AUTOLOCK(speechDataProcessingHandlerLock);
+
+ if (mSpeechDataProcessingHandler == NULL) {
+ mSpeechDataProcessingHandler = new SpeechDataProcessingHandler();
+ }
+ ASSERT(mSpeechDataProcessingHandler != NULL);
+ return mSpeechDataProcessingHandler;
+}
+
+void SpeechDataProcessingHandler::destoryInstanceSafely() {
+ ALOGD("+%s()\n", __FUNCTION__);
+
+ AL_AUTOLOCK(speechDataProcessingHandlerLock);
+ if (!AudioALSACaptureDataProviderVoiceDL::hasInstance()
+ && !AudioALSACaptureDataProviderVoiceUL::hasInstance()
+ && !AudioALSACaptureDataProviderVoiceMix::hasInstance()) {
+ delete mSpeechDataProcessingHandler;
+ mSpeechDataProcessingHandler = NULL;
+ }
+ ALOGD("-%s()\n", __FUNCTION__);
+}
+
+SpeechDataProcessingHandler::SpeechDataProcessingHandler() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ // Init thread resources
+ mStopThreadFlag = false;
+ mBliSrcUL = NULL;
+ mBliSrcDL = NULL;
+ mSrcSampleRateUL = 0;
+ mSrcSampleRateDL = 0;
+ mSpeechRecordOn = false;
+
+ int ret;
+
+ ret = pthread_cond_init(&mSpeechDataNotifyEvent, NULL);
+ if (ret != 0) {
+ ALOGE("mSpeechDataNotifyEvent create fail!!!");
+ }
+
+ ret = pthread_mutex_init(&mSpeechDataNotifyMutex, NULL);
+ if (ret != 0) {
+ ALOGE("nSpeechDataNotifyMutex create fail!!!");
+ }
+
+ ret = pthread_create(&mSpeechDataProcessingThread, NULL, SpeechDataProcessingHandler::threadLoop, (void *)this);
+ if (ret != 0) {
+ ALOGE("mSpeechDataProcessingThread create fail!!!");
+ } else {
+ ALOGD("mSpeechDataProcessingThread = %lu created", mSpeechDataProcessingThread);
+ }
+
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+SpeechDataProcessingHandler::~SpeechDataProcessingHandler() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ if (mBliSrcDL != NULL) {
+ mBliSrcDL->close();
+ deleteMtkAudioSrc(mBliSrcDL);
+ mBliSrcDL = NULL;
+ mSrcSampleRateDL = 0;
+ }
+
+ if (mBliSrcUL != NULL) {
+ mBliSrcUL->close();
+ deleteMtkAudioSrc(mBliSrcUL);
+ mBliSrcUL = NULL;
+ mSrcSampleRateUL = 0;
+ }
+
+ mStopThreadFlag = true;
+ pthread_cond_signal(&mSpeechDataNotifyEvent);
+ pthread_join(mSpeechDataProcessingThread, NULL);
+ mSpeechDataProcessingThread = (pthread_t)NULL;
+
+ pthread_cond_destroy(&mSpeechDataNotifyEvent);
+ pthread_mutex_destroy(&mSpeechDataNotifyMutex);
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+void SpeechDataProcessingHandler::getStreamAttributeSource(Caller caller, stream_attribute_t *streamAttributeSource) {
+ if (streamAttributeSource != NULL) {
+ SpeechDriverInterface *pSpeechDriver = SpeechDriverFactory::GetInstance()->GetSpeechDriver();
+ streamAttributeSource->audio_format = kTargetBitFormat;
+ streamAttributeSource->sample_rate = kTargetSampleRate;
+
+ switch (caller) {
+ case VOICE_UL_CALLER:
+ streamAttributeSource->audio_channel_mask = AUDIO_CHANNEL_IN_VOICE_UPLINK;
+ streamAttributeSource->num_channels = 1;
+ break;
+ case VOICE_DL_CALLER:
+ streamAttributeSource->audio_channel_mask = AUDIO_CHANNEL_IN_VOICE_DNLINK;
+ streamAttributeSource->num_channels = 1;
+ break;
+ case VOICE_MIX_CALLER:
+ streamAttributeSource->audio_channel_mask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK;
+ streamAttributeSource->num_channels = 2;
+ break;
+ }
+
+ // Reset frames readed counter
+ streamAttributeSource->Time_Info.total_frames_readed = 0;
+ }
+}
+static int mUserCounter = 0;
+status_t SpeechDataProcessingHandler::recordOn(RecordType type __unused) {
+ ALOGD("+%s()\n", __FUNCTION__);
+ AL_AUTOLOCK(speechDataProcessingHandlerLock);
+#if 0
+ if (mSpeechRecordOn == false) {
+ SpeechDriverFactory::GetInstance()->GetSpeechDriver()->recordOn(type);
+ mSpeechRecordOn = true;
+ ALOGD("%s(), recordOn(%d)\n", __FUNCTION__, type);
+ } else {
+ bool hasMix = AudioALSACaptureDataProviderVoiceMix::hasInstance();
+ bool hasDL = AudioALSACaptureDataProviderVoiceDL::hasInstance();
+ bool hasUL = AudioALSACaptureDataProviderVoiceUL::hasInstance();
+
+ RecordType recordType = type;
+ if (hasMix || (hasDL && hasUL)) {
+ recordType = RECORD_TYPE_MIX;
+ }
+ SpeechDriverFactory::GetInstance()->GetSpeechDriver()->setPcmRecordType(recordType);
+ ALOGD("%s(), recordOn(%d) -> setPcmRecordType(%d)\n", __FUNCTION__, type, recordType);
+ }
+#else
+ mUserCounter++;
+ SpcRecordTypeStruct typeRecord;
+ typeRecord.direction = RECORD_TYPE_MIX;
+#ifdef MTK_PHONE_CALL_RECORD_VOICE_ONLY
+ typeRecord.dlPosition = RECORD_POS_DL_AFTER_ENH;
+#else
+ typeRecord.dlPosition = RECORD_POS_DL_END;
+#endif
+ if (mUserCounter == 1) {
+ SpeechDriverFactory::GetInstance()->GetSpeechDriver()->recordOn(typeRecord);
+ ALOGD("%s(), First user, record on. dlPosition: %d\n", __FUNCTION__, typeRecord.dlPosition);
+ } else {
+ ALOGD("%s(), Record already on. user = %d\n", __FUNCTION__, mUserCounter);
+ }
+#endif
+ ALOGD("-%s()\n", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t SpeechDataProcessingHandler::recordOff(RecordType type __unused) {
+ ALOGD("+%s()\n", __FUNCTION__);
+ AL_AUTOLOCK(speechDataProcessingHandlerLock);
+#if 0
+ bool hasMix = AudioALSACaptureDataProviderVoiceMix::hasInstance();
+ bool hasDL = AudioALSACaptureDataProviderVoiceDL::hasInstance();
+ bool hasUL = AudioALSACaptureDataProviderVoiceUL::hasInstance();
+ bool onlyOneProvider = (hasMix && !hasDL && !hasUL) || (!hasMix && hasDL && !hasUL) || (!hasMix && !hasDL && hasUL);
+
+ if (onlyOneProvider) {
+ ALOGD("%s(), Last record type, recordOff(%d)\n", __FUNCTION__, type);
+ mSpeechRecordOn = false;
+ return SpeechDriverFactory::GetInstance()->GetSpeechDriver()->recordOff(type);
+ } else {
+ switch (type) {
+ case RECORD_TYPE_DL:
+ if (!hasMix && hasDL && hasUL) {
+ ALOGD("%s(), recordOff(%d) -> setPcmRecordType(RECORD_TYPE_UL)\n", __FUNCTION__, type);
+ return SpeechDriverFactory::GetInstance()->GetSpeechDriver()->setPcmRecordType(RECORD_TYPE_UL);
+ }
+ break;
+ case RECORD_TYPE_UL:
+ if (!hasMix && hasDL && hasUL) {
+ ALOGD("%s(), recordOff(%d) -> setPcmRecordType(RECORD_TYPE_DL)\n", __FUNCTION__, type);
+ return SpeechDriverFactory::GetInstance()->GetSpeechDriver()->setPcmRecordType(RECORD_TYPE_DL);
+ }
+ break;
+ case RECORD_TYPE_MIX:
+ if (hasDL) {
+ ALOGD("%s(), recordOff(%d) -> setPcmRecordType(RECORD_TYPE_DL)\n", __FUNCTION__, type);
+ return SpeechDriverFactory::GetInstance()->GetSpeechDriver()->setPcmRecordType(RECORD_TYPE_DL);
+ } else if (hasUL) {
+ ALOGD("%s(), recordOff(%d) -> setPcmRecordType(RECORD_TYPE_UL)\n", __FUNCTION__, type);
+ return SpeechDriverFactory::GetInstance()->GetSpeechDriver()->setPcmRecordType(RECORD_TYPE_UL);
+ }
+ break;
+ }
+ }
+ ALOGD("-%s(), recordOff(%d), do nothing. (UL:%d DL:%d MIX:%d)\n", __FUNCTION__, type, hasUL, hasDL, hasMix);
+#else
+ mUserCounter--;
+ SpcRecordTypeStruct typeRecord;
+ typeRecord.direction = RECORD_TYPE_MIX;
+#ifdef MTK_PHONE_CALL_RECORD_VOICE_ONLY
+ typeRecord.dlPosition = RECORD_POS_DL_AFTER_ENH;
+#else
+ typeRecord.dlPosition = RECORD_POS_DL_END;
+#endif
+ if (mUserCounter == 0) {
+ SpeechDriverFactory::GetInstance()->GetSpeechDriver()->recordOff(typeRecord);
+ ALOGD("%s(), No user, record off!\n", __FUNCTION__);
+ } else {
+ ALOGD("%s(), Record is still using. user = %d\n", __FUNCTION__, mUserCounter);
+ }
+ ALOGD("-%s()\n", __FUNCTION__);
+#endif
+ return NO_ERROR;
+}
+
+status_t SpeechDataProcessingHandler::provideModemRecordDataToProvider(RingBuf pcm_read_buf) {
+ ALOGV("%s(), Got speech packet, addr = %p, mSpeechDataList = %p, mSpeechDataNotifyEvent = %p, mSpeechDataNotifyMutex = %p, mStopThreadFlag = %d, this(Handler) = %p\n", __FUNCTION__, pcm_read_buf.pRead, &mSpeechDataList, &mSpeechDataNotifyEvent, &mSpeechDataNotifyMutex, mStopThreadFlag, (void *)this);
+
+ if (mStopThreadFlag == true) {
+ ALOGW("%s(), SpeechDataprocessingHandler is stoping, ignore packet!\n", __FUNCTION__);
+ }
+
+ int speechDataSize = RingBuf_getDataCount(&pcm_read_buf);
+ if (speechDataSize < (int)sizeof(android::spcApRAWPCMBufHdr)) {
+ ALOGW("%s(), no valid struct in pcm buf\n", __FUNCTION__);
+ return NO_ERROR;
+ }
+
+ // Dup ring buf and push it to list
+ RingBuf *ringBuf = new RingBuf;
+ ringBuf->pBufBase = new char[speechDataSize];
+ ringBuf->bufLen = speechDataSize;
+ ringBuf->pRead = ringBuf->pBufBase;
+ ringBuf->pWrite = ringBuf->pBufBase + speechDataSize;
+ RingBuf_copyToLinear(ringBuf->pBufBase, &pcm_read_buf, speechDataSize);
+
+ // Check sync word
+ spcApRAWPCMBufHdrStruct *speechPacketHeader = (spcApRAWPCMBufHdrStruct *)ringBuf->pBufBase;
+ uint16_t syncWord = speechPacketHeader->u16SyncWord;
+ uint16_t pcmLength = speechPacketHeader->u16Length;
+ char *pcmData = ringBuf->pBufBase + sizeof(android::spcApRAWPCMBufHdrStruct);
+
+ // fill pcm data with sine wave
+ if (syncWord != EEMCS_M2A_SHARE_BUFF_HEADER_SYNC) {
+ ALOGE("%s(), Invalid packet found!! (SyncWord: 0x%x, addr = %p)\n", __FUNCTION__, syncWord, &speechPacketHeader->u16SyncWord);
+ delete[] ringBuf->pBufBase;
+ delete ringBuf;
+ return NO_ERROR;
+ }
+
+ pthread_mutex_lock(&mSpeechDataNotifyMutex);
+ mSpeechDataList.push_back(ringBuf);
+ pthread_cond_signal(&mSpeechDataNotifyEvent);
+ pthread_mutex_unlock(&mSpeechDataNotifyMutex);
+
+ return NO_ERROR;
+}
+
+void *SpeechDataProcessingHandler::threadLoop(void *arg) {
+ ALOGD("%s()\n", __FUNCTION__);
+ char *pInputPacketBuf = NULL;
+ int speechDataSize = 0;
+ RingBuf *ringBuf = NULL;
+ SpeechDataProcessingHandler *pHandler = (SpeechDataProcessingHandler *)arg;
+
+ while (!pHandler->mStopThreadFlag) {
+ pInputPacketBuf = NULL;
+ speechDataSize = 0;
+ ringBuf = NULL;
+
+ // Pop speech data from list
+ pthread_mutex_lock(&pHandler->mSpeechDataNotifyMutex);
+ if (pHandler->mSpeechDataList.begin() != pHandler->mSpeechDataList.end()) {
+ ringBuf = *(pHandler->mSpeechDataList.begin());
+ pHandler->mSpeechDataList.erase(pHandler->mSpeechDataList.begin());
+ } else {
+ ALOGV("%s(), wait for new speech data, pHandler = %p, pHandler->mStopThreadFlag = %d\n", __FUNCTION__, pHandler, pHandler->mStopThreadFlag);
+ pthread_cond_wait(&pHandler->mSpeechDataNotifyEvent, &pHandler->mSpeechDataNotifyMutex);
+ }
+ pthread_mutex_unlock(&pHandler->mSpeechDataNotifyMutex);
+
+ // Process speech data
+ if (ringBuf != NULL) {
+ pInputPacketBuf = ringBuf->pBufBase;
+ speechDataSize = ringBuf->bufLen;
+ delete ringBuf;
+
+ if (pInputPacketBuf != NULL) {
+ pHandler->processSpeechPacket(pInputPacketBuf, speechDataSize);
+ delete[] pInputPacketBuf;
+ } else {
+ ALOGW("%s(), pInputPacketBuf is NULL\n", __FUNCTION__);
+ }
+ } else {
+ ALOGV("%s(), ringBuf is NULL\n", __FUNCTION__);
+ }
+ }
+
+ ALOGD("threadLoop exit mSpeechDataProcessingThread = %lu\n", pHandler->mSpeechDataProcessingThread);
+ pthread_exit(NULL);
+ return 0;
+}
+
+status_t SpeechDataProcessingHandler::processSpeechPacket(char *pInputPacketBuf, uint32_t speechDataSize) {
+ ALOGV("+%s(), pInputPacketBuf = %p, speechDataSize = %d\n", __FUNCTION__, pInputPacketBuf, speechDataSize);
+
+ char *pULPcmInputBuf = NULL;
+ uint32_t uULPcmInputBufSize = 0;
+ uint16_t uULFreq = 0;
+ char *pDLPcmInputBuf = NULL;
+ uint32_t uDLPcmInputBufSize = 0;
+ uint16_t uDLFreq = 0;
+ char *ptr = pInputPacketBuf;
+
+ while (ptr < pInputPacketBuf + speechDataSize) {
+ spcApRAWPCMBufHdrStruct *speechPacketHeader = (spcApRAWPCMBufHdrStruct *)ptr;
+ uint16_t syncWord = speechPacketHeader->u16SyncWord;
+ uint16_t rawPcmDir = speechPacketHeader->u16RawPcmDir;
+ uint16_t freq = speechPacketHeader->u16Freq;
+ uint16_t pcmLength = speechPacketHeader->u16Length;
+ uint16_t channel = speechPacketHeader->u16Channel;
+ uint16_t bitFormat = speechPacketHeader->u16BitFormat;
+ char *pcmData = ptr + sizeof(android::spcApRAWPCMBufHdrStruct);
+ ALOGV("%s(), Process speech packet, syncWord = 0x%x, dir = %s, freq = %d, channel = %d, BitFormat = %d, length = %d\n", __FUNCTION__, syncWord, rawPcmDir == 0 ? "UL" : "DL", freq, channel, bitFormat, pcmLength);
+
+ if (syncWord != EEMCS_M2A_SHARE_BUFF_HEADER_SYNC) {
+ ALOGW("%s(), Invalid packet. (syncWord: 0x%x)\n", __FUNCTION__, syncWord);
+ return NO_ERROR;
+ }
+
+ if (bitFormat != kTargetBitFormat) {
+ ALOGW("%s(), Invalid packet. (bit format: %d)\n", __FUNCTION__, bitFormat);
+ return NO_ERROR;
+ }
+
+ if (rawPcmDir == RECORD_TYPE_UL) {
+ ASSERT(pULPcmInputBuf == NULL);
+
+#if SINE_WAVE_ENABLED
+ setupLinearBufWithSineWave(pcmData, pcmLength);
+#endif
+
+ pULPcmInputBuf = pcmData;
+ uULPcmInputBufSize = pcmLength;
+ uULFreq = freq;
+
+ if (uULFreq != mSrcSampleRateUL && uULFreq != kTargetSampleRate) {
+ if (mBliSrcUL != NULL) {
+ deleteMtkAudioSrc(mBliSrcUL);
+ ALOGD("%s(), delete old BliSrcUL (SR:%d -> %d)\n", __FUNCTION__, mSrcSampleRateUL, kTargetSampleRate);
+ }
+
+ mSrcSampleRateUL = uULFreq;
+ mBliSrcUL = newMtkAudioSrc(
+ mSrcSampleRateUL, channel,
+ kTargetSampleRate, kTargetULChannelNumber,
+ SRC_IN_Q1P15_OUT_Q1P15);
+ mBliSrcUL->open();
+ ALOGD("%s(), create BliSrcUL (SR:%d -> %d)\n", __FUNCTION__, mSrcSampleRateUL, kTargetSampleRate);
+ }
+ } else {
+ ASSERT(pDLPcmInputBuf == NULL);
+
+#if SINE_WAVE_ENABLED
+ setupLinearBufWithSineWave(pcmData, pcmLength);
+#endif
+
+ pDLPcmInputBuf = pcmData;
+ uDLPcmInputBufSize = pcmLength;
+ uDLFreq = freq;
+
+ if (uDLFreq != mSrcSampleRateDL && uDLFreq != kTargetSampleRate) {
+ if (mBliSrcDL != NULL) {
+ deleteMtkAudioSrc(mBliSrcDL);
+ ALOGD("%s(), delete old BliSrcDL (SR:%d -> %d)\n", __FUNCTION__, mSrcSampleRateDL, kTargetSampleRate);
+ }
+
+ mSrcSampleRateDL = uDLFreq;
+ mBliSrcDL = newMtkAudioSrc(
+ mSrcSampleRateDL, channel,
+ kTargetSampleRate, kTargetDLChannelNumber,
+ SRC_IN_Q1P15_OUT_Q1P15);
+ mBliSrcDL->open();
+ ALOGD("%s(), create BliSrcDL (SR:%d -> %d)\n", __FUNCTION__, mSrcSampleRateDL, kTargetSampleRate);
+ }
+ }
+
+ // Update ptr
+ ptr += sizeof(android::spcApRAWPCMBufHdrStruct) + pcmLength;
+ // ALOGD("%s(), One packet parsed, header size = %d, pcmLength = %d, ptr = 0x%x\n", __FUNCTION__, sizeof(android::spcApRAWPCMBufHdrStruct), pcmLength, ptr);
+ }
+
+ if (uULPcmInputBufSize != 0) {
+ ALOGV("%s(), UL pcm buf = %p, size = %d\n", __FUNCTION__, pULPcmInputBuf, uULPcmInputBufSize);
+ }
+
+ if (uDLPcmInputBufSize != 0) {
+ ALOGV("%s(), DL pcm buf = %p, size = %d\n", __FUNCTION__, pDLPcmInputBuf, uDLPcmInputBufSize);
+ }
+
+ // 3. ul/dl pcm SRC
+ char *pULSrcOutputBuf = NULL;
+ if (uULFreq != 0 && uULFreq != kTargetSampleRate) {
+ uint32_t uSrcOutputBufSize = uULPcmInputBufSize * kTargetSampleRate / uULFreq;
+ pULSrcOutputBuf = new char[uSrcOutputBufSize];
+
+ char *p_read = pULPcmInputBuf;
+ uint32_t num_raw_data_left = uULPcmInputBufSize;
+ uint32_t num_converted_data = uSrcOutputBufSize;
+
+ ALOGV("%s(), before SRC, num_raw_data_left = %u, num_converted_data = %u",
+ __FUNCTION__, num_raw_data_left, num_converted_data);
+ uint32_t consumed = num_raw_data_left;
+ mBliSrcUL->process((int16_t *)p_read, &num_raw_data_left,
+ (int16_t *)pULSrcOutputBuf, &num_converted_data);
+ consumed -= num_raw_data_left;
+ ALOGV("%s(), after num_raw_data_left = %u, num_converted_data = %u",
+ __FUNCTION__, num_raw_data_left, num_converted_data);
+
+ ASSERT(num_raw_data_left == 0);
+
+ // Update size & pointer
+ uULPcmInputBufSize = num_converted_data;
+ pULPcmInputBuf = pULSrcOutputBuf;
+ }
+
+ char *pDLSrcOutputBuf = NULL;
+ if (uDLFreq != 0 && uDLFreq != kTargetSampleRate) {
+ uint32_t uSrcOutputBufSize = uDLPcmInputBufSize * kTargetSampleRate / uDLFreq;
+ pDLSrcOutputBuf = new char[uSrcOutputBufSize];
+
+ char *p_read = pDLPcmInputBuf;
+ uint32_t num_raw_data_left = uDLPcmInputBufSize;
+ uint32_t num_converted_data = uSrcOutputBufSize;
+
+ ALOGV("%s(), before SRC, num_raw_data_left = %u, num_converted_data = %u",
+ __FUNCTION__, num_raw_data_left, num_converted_data);
+ uint32_t consumed = num_raw_data_left;
+ mBliSrcDL->process((int16_t *)p_read, &num_raw_data_left,
+ (int16_t *)pDLSrcOutputBuf, &num_converted_data);
+ consumed -= num_raw_data_left;
+ ALOGV("%s(), num_raw_data_left = %u, num_converted_data = %u",
+ __FUNCTION__, num_raw_data_left, num_converted_data);
+
+ ASSERT(num_raw_data_left == 0);
+
+ // Update size & pointer
+ uDLPcmInputBufSize = num_converted_data;
+ pDLPcmInputBuf = pDLSrcOutputBuf;
+ }
+
+ if (pULSrcOutputBuf != NULL) {
+ ALOGV("%s(), After SRC, UL buf = %p, size = %d\n", __FUNCTION__, pULPcmInputBuf, uULPcmInputBufSize);
+ }
+
+ if (pDLSrcOutputBuf != NULL) {
+ ALOGV("%s(), After SRC, DL buf = %p, size = %d\n", __FUNCTION__, pDLPcmInputBuf, uDLPcmInputBufSize);
+ }
+
+ // 4. Dispatch UL/DL data to UL/DL/MIX data provider
+ for (int recordType = RECORD_TYPE_UL; recordType <= RECORD_TYPE_MIX; recordType++) {
+ switch (recordType) {
+ case RECORD_TYPE_UL:
+ if (pULPcmInputBuf != NULL && AudioALSACaptureDataProviderVoiceUL::hasInstance()) {
+ RingBuf ringBuf;
+ ringBuf.pBufBase = pULPcmInputBuf;
+ ringBuf.bufLen = uULPcmInputBufSize + 1;
+ ringBuf.pRead = ringBuf.pBufBase;
+ ringBuf.pWrite = ringBuf.pRead + uULPcmInputBufSize;
+ ringBuf.pBufEnd = ringBuf.pBufBase + ringBuf.bufLen;
+
+ AudioALSACaptureDataProviderVoiceUL::getInstance()->provideModemRecordDataToProvider(ringBuf);
+ }
+ break;
+ case RECORD_TYPE_DL:
+ if (pDLPcmInputBuf != NULL && AudioALSACaptureDataProviderVoiceDL::hasInstance()) {
+ RingBuf ringBuf;
+ ringBuf.pBufBase = pDLPcmInputBuf;
+ ringBuf.bufLen = uDLPcmInputBufSize + 1;
+ ringBuf.pRead = ringBuf.pBufBase;
+ ringBuf.pWrite = ringBuf.pBufBase + uDLPcmInputBufSize;
+ ringBuf.pBufEnd = ringBuf.pBufBase + ringBuf.bufLen;
+
+ AudioALSACaptureDataProviderVoiceDL::getInstance()->provideModemRecordDataToProvider(ringBuf);
+ }
+ break;
+ case RECORD_TYPE_MIX:
+ if (pULPcmInputBuf != NULL && pDLPcmInputBuf != NULL && AudioALSACaptureDataProviderVoiceMix::hasInstance()) {
+ // [TODO] only support 16bit now (JH)
+ ASSERT(kTargetBitFormat == AUDIO_FORMAT_PCM_16_BIT);
+ uint32_t bufferSize = (uDLPcmInputBufSize > uULPcmInputBufSize ? uULPcmInputBufSize : uDLPcmInputBufSize) * 2;
+
+ char *pcmMixBuf = new char[bufferSize];
+ uint32_t samples = bufferSize / 2 / 2; /* 2ch / 16bit */
+ for (uint32_t index = 0; index < samples; index++) {
+ ((uint16_t *)pcmMixBuf)[index * 2] = ((uint16_t *)pDLPcmInputBuf)[index];
+ ((uint16_t *)pcmMixBuf)[index * 2 + 1] = ((uint16_t *)pULPcmInputBuf)[index];
+ }
+
+ RingBuf ringBuf;
+ ringBuf.pBufBase = pcmMixBuf;
+ ringBuf.bufLen = bufferSize + 1;
+ ringBuf.pRead = ringBuf.pBufBase;
+ ringBuf.pWrite = ringBuf.pBufBase + bufferSize;
+ ringBuf.pBufEnd = ringBuf.pBufBase + ringBuf.bufLen;
+
+ AudioALSACaptureDataProviderVoiceMix::getInstance()->provideModemRecordDataToProvider(ringBuf);
+ delete[] pcmMixBuf;
+ }
+ break;
+ }
+ }
+
+ if (pULSrcOutputBuf != NULL) {
+ delete[] pULSrcOutputBuf;
+ }
+
+ if (pDLSrcOutputBuf != NULL) {
+ delete[] pDLSrcOutputBuf;
+ }
+
+ return NO_ERROR;
+}
+
+} // end of namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/audio_messenger_ipi.c b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/audio_messenger_ipi.c
new file mode 100644
index 0000000..614acd0
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/audio_messenger_ipi.c
@@ -0,0 +1,732 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <audio_messenger_ipi.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <pthread.h>
+
+#include <audio_log.h>
+#include <audio_lock.h>
+#include <audio_assert.h>
+
+
+#include <audio_task.h>
+#include <audio_controller_msg_id.h>
+
+#ifdef MTK_AUDIODSP_SUPPORT
+#include "AudioAurisysPcmDump.h"
+#include <audio_dsp_service.h>
+#endif
+
+#if defined(MTK_AUDIO_SCP_SUPPORT)
+#include <audio_scp_service.h>
+#endif
+
+#if defined(MTK_AUDIO_DSP_RECOVERY_SUPPORT)
+#include <audio_dsp_controller.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * =============================================================================
+ * LOG
+ * =============================================================================
+ */
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "audio_messenger_ipi"
+
+
+
+/*
+ * =============================================================================
+ * MACRO
+ * =============================================================================
+ */
+
+#define MAX_DSP_DMA_WRITE_SIZE (0x10000)
+
+
+
+/*==============================================================================
+ * ioctl
+ *============================================================================*/
+
+#define AUDIO_IPI_DEVICE_PATH "/dev/audio_ipi"
+#define AUDIO_IPI_IOC_MAGIC 'i'
+
+#define AUDIO_IPI_IOCTL_SEND_MSG_ONLY _IOW(AUDIO_IPI_IOC_MAGIC, 0, unsigned int)
+#define AUDIO_IPI_IOCTL_SEND_PAYLOAD _IOW(AUDIO_IPI_IOC_MAGIC, 1, unsigned int)
+#define AUDIO_IPI_IOCTL_SEND_DRAM _IOW(AUDIO_IPI_IOC_MAGIC, 2, unsigned int)
+
+#define AUDIO_IPI_IOCTL_LOAD_SCENE _IOW(AUDIO_IPI_IOC_MAGIC, 10, unsigned int)
+
+#define AUDIO_IPI_IOCTL_INIT_DSP _IOW(AUDIO_IPI_IOC_MAGIC, 20, unsigned int)
+#define AUDIO_IPI_IOCTL_REG_DMA _IOW(AUDIO_IPI_IOC_MAGIC, 21, unsigned int)
+
+
+
+/*
+ * =============================================================================
+ * struct def
+ * =============================================================================
+ */
+
+struct audio_ipi_reg_dma_t {
+ uint8_t task;
+ uint8_t reg_flag; /* 1: register, 0: unregister */
+ uint16_t __reserved;
+
+ uint32_t a2d_size;
+ uint32_t d2a_size;
+};
+
+struct audio_ipi_dma_client_t {
+ audio_ipi_dma_cbk_t cbk;
+ void *arg;
+};
+
+#ifdef MTK_AUDIODSP_SUPPORT
+struct audio_ipi_reg_feature_t {
+ uint16_t reg_flag;
+ uint16_t feature_id;
+};
+#endif
+
+
+/*
+ * =============================================================================
+ * global var
+ * =============================================================================
+ */
+
+static struct alock_t *g_drv_lock;
+static int g_ipi_drv;
+
+#if defined(MTK_AUDIO_IPI_DMA_SUPPORT)
+static struct alock_t *g_dma_lock;
+
+static pthread_t g_read_ipi_thread_hdl;
+static bool g_read_ipi_thread_enable;
+static uint8_t *g_read_ipi_buf;
+
+static struct audio_ipi_dma_client_t g_ipi_dma_client[TASK_SCENE_SIZE];
+#endif
+
+
+
+/*
+ * =============================================================================
+ * function declaration
+ * =============================================================================
+ */
+
+#if defined(MTK_AUDIO_IPI_DMA_SUPPORT)
+static void *read_ipi_thread(void *arg);
+
+static void process_dma_msg(
+ struct ipi_msg_t *msg,
+ void *buf,
+ uint32_t size,
+ void *arg);
+
+static void audio_ipi_dma_task_controller_reg(bool isRegister);
+#endif
+
+
+
+/*
+ * =============================================================================
+ * init
+ * =============================================================================
+ */
+
+void audio_messenger_ipi_init(void)
+{
+ int ret = 0;
+ int i = 0;
+
+ if (g_drv_lock != NULL) {
+ AUD_LOG_W("%s(), double init, return", __FUNCTION__);
+ return;
+ }
+
+ NEW_ALOCK(g_drv_lock);
+
+ /* open driver */
+ LOCK_ALOCK(g_drv_lock);
+ g_ipi_drv = open(AUDIO_IPI_DEVICE_PATH, O_RDONLY);
+ if (g_ipi_drv < 0) {
+ AUD_LOG_E("%s(), fail to open %s, errno: %d", __FUNCTION__,
+ AUDIO_IPI_DEVICE_PATH, errno);
+ AUD_WARNING("open audio ipi driver fail!!");
+ UNLOCK_ALOCK(g_drv_lock);
+ return;
+ }
+
+#if defined(MTK_AUDIODSP_SUPPORT) || defined(MTK_AUDIO_SCP_SUPPORT)
+ /* init dsp */
+ ret = ioctl(g_ipi_drv, AUDIO_IPI_IOCTL_INIT_DSP, 0);
+ if (ret != 0) {
+ AUD_LOG_E("%s(), ioctl fail! ret = %d, errno: %d", __FUNCTION__, ret, errno);
+ UNLOCK_ALOCK(g_drv_lock);
+ return;
+ }
+#if defined(MTK_AUDIODSP_SUPPORT)
+ audio_dsp_service_init();
+#endif
+
+#if defined(MTK_AUDIO_SCP_SUPPORT)
+ audio_scp_service_init();
+#endif
+
+#endif /* end of MTK_AUDIODSP_SUPPORT || MTK_AUDIO_SCP_SUPPORT */
+
+#ifdef MTK_AUDIO_DSP_RECOVERY_SUPPORT
+ audio_dsp_controller_init();
+#endif
+
+ UNLOCK_ALOCK(g_drv_lock);
+
+
+#if defined(MTK_AUDIO_IPI_DMA_SUPPORT)
+ NEW_ALOCK(g_dma_lock);
+
+ LOCK_ALOCK(g_dma_lock);
+ for (i = 0; i < TASK_SCENE_SIZE; i++) {
+ g_ipi_dma_client[i].cbk = NULL;
+ g_ipi_dma_client[i].arg = NULL;
+ }
+ UNLOCK_ALOCK(g_dma_lock);
+
+ audio_ipi_dma_task_controller_reg(true);
+
+ /* read ipi thread */
+ g_read_ipi_buf = (uint8_t *)malloc(MAX_DSP_DMA_WRITE_SIZE);
+ if (g_read_ipi_buf == NULL) {
+ AUD_LOG_E("%s(), g_read_ipi_buf NULL", __FUNCTION__);
+ return;
+ }
+ g_read_ipi_thread_enable = true;
+ g_read_ipi_thread_hdl = 0;
+ ret = pthread_create(&g_read_ipi_thread_hdl, NULL,
+ read_ipi_thread,
+ NULL);
+ AUD_ASSERT(ret == 0);
+#endif
+}
+
+
+void audio_messenger_ipi_deinit(void)
+{
+#if defined(MTK_AUDIO_IPI_DMA_SUPPORT)
+ /* dma */
+ audio_ipi_dma_task_controller_reg(false);
+
+ /* read ipi thread */
+ g_read_ipi_thread_enable = false;
+ pthread_join(g_read_ipi_thread_hdl, NULL);
+
+ if (g_read_ipi_buf != NULL) {
+ free(g_read_ipi_buf);
+ g_read_ipi_buf = NULL;
+ }
+
+ FREE_ALOCK(g_dma_lock);
+#endif
+
+
+ /* close driver */
+ LOCK_ALOCK(g_drv_lock);
+
+ if (g_ipi_drv >= 0) {
+ close(g_ipi_drv);
+ g_ipi_drv = -1;
+ }
+
+ UNLOCK_ALOCK(g_drv_lock);
+
+ FREE_ALOCK(g_drv_lock);
+
+#ifdef MTK_AUDIODSP_SUPPORT
+ audio_dsp_service_deinit();
+#endif
+
+#ifdef MTK_AUDIO_SCP_SUPPORT
+ audio_scp_service_deinit();
+#endif
+
+#ifdef MTK_AUDIO_DSP_RECOVERY_SUPPORT
+ audio_dsp_controller_deinit();
+#endif
+}
+
+
+
+/*
+ * =============================================================================
+ * ipi msg
+ * =============================================================================
+ */
+
+static uint32_t get_message_buf_size(const struct ipi_msg_t *ipi_msg)
+{
+ if (ipi_msg->data_type == AUDIO_IPI_MSG_ONLY) {
+ return IPI_MSG_HEADER_SIZE;
+ } else if (ipi_msg->data_type == AUDIO_IPI_PAYLOAD) {
+ return (IPI_MSG_HEADER_SIZE + ipi_msg->payload_size);
+ } else if (ipi_msg->data_type == AUDIO_IPI_DMA) {
+ return (IPI_MSG_HEADER_SIZE + IPI_MSG_DMA_INFO_SIZE);
+ } else {
+ return 0;
+ }
+}
+
+
+static int check_msg_format(const struct ipi_msg_t *p_ipi_msg, uint32_t len)
+{
+ if (p_ipi_msg->magic != IPI_MSG_MAGIC_NUMBER) {
+ AUD_LOG_W("%s(), magic 0x%x error!!",
+ __func__, p_ipi_msg->magic);
+ return -1;
+ }
+
+ if (p_ipi_msg->task_scene >= TASK_SCENE_SIZE) {
+ AUD_LOG_W("%s(), task_scene %d error!!",
+ __func__, p_ipi_msg->task_scene);
+ return -1;
+ }
+
+ if (p_ipi_msg->source_layer >= AUDIO_IPI_LAYER_FROM_SIZE) {
+ AUD_LOG_W("%s(), source_layer %d error!!",
+ __func__, p_ipi_msg->source_layer);
+ return -1;
+ }
+
+ if (p_ipi_msg->target_layer >= AUDIO_IPI_LAYER_TO_SIZE) {
+ AUD_LOG_W("%s(), target_layer %d error!!",
+ __func__, p_ipi_msg->target_layer);
+ return -1;
+ }
+
+ if (p_ipi_msg->data_type >= AUDIO_IPI_TYPE_SIZE) {
+ AUD_LOG_W("%s(), data_type %d error!!",
+ __func__, p_ipi_msg->data_type);
+ return -1;
+ }
+
+ if (p_ipi_msg->ack_type > AUDIO_IPI_MSG_DIRECT_SEND &&
+ p_ipi_msg->ack_type != AUDIO_IPI_MSG_CANCELED) {
+ AUD_LOG_W("%s(), ack_type %d error!!",
+ __func__, p_ipi_msg->ack_type);
+ return -1;
+ }
+
+ if (get_message_buf_size(p_ipi_msg) != len) {
+ AUD_LOG_W("%s(), len 0x%x error!!", __func__, len);
+ return -1;
+ }
+
+ if (p_ipi_msg->data_type == AUDIO_IPI_PAYLOAD) {
+ if (p_ipi_msg->payload_size == 0 ||
+ p_ipi_msg->payload_size > MAX_IPI_MSG_PAYLOAD_SIZE) {
+ AUD_LOG_W("%s(), payload_size %u error!!",
+ __func__, p_ipi_msg->payload_size);
+ return -1;
+ }
+ }
+
+ if (p_ipi_msg->data_type == AUDIO_IPI_DMA) {
+ if (p_ipi_msg->dma_info.hal_buf.addr == NULL) {
+ AUD_LOG_W("%s(), dma addr null!!", __func__);
+ return -1;
+ }
+ if (p_ipi_msg->dma_info.hal_buf.data_size == 0) {
+ AUD_LOG_W("%s(), dma data_size %u error!!",
+ __func__, p_ipi_msg->dma_info.hal_buf.data_size);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+int audio_send_ipi_msg(
+ struct ipi_msg_t *p_ipi_msg,
+ uint8_t task_scene, /* task_scene_t */
+ uint8_t target_layer, /* audio_ipi_msg_target_layer_t */
+ uint8_t data_type, /* audio_ipi_msg_data_t */
+ uint8_t ack_type, /* audio_ipi_msg_ack_t */
+ uint16_t msg_id,
+ uint32_t param1, /* data_size for payload & dma */
+ uint32_t param2,
+ void *data_buffer) /* buffer for payload & dma */
+{
+ struct ipi_msg_dma_info_t *dma_info = NULL;
+ uint32_t ipi_msg_len = 0;
+
+ int ret = 0;
+
+
+ memset(p_ipi_msg, 0, MAX_IPI_MSG_BUF_SIZE);
+
+ p_ipi_msg->magic = IPI_MSG_MAGIC_NUMBER;
+ p_ipi_msg->task_scene = task_scene;
+ p_ipi_msg->source_layer = AUDIO_IPI_LAYER_FROM_HAL;
+ p_ipi_msg->target_layer = target_layer;
+ p_ipi_msg->data_type = data_type;
+ p_ipi_msg->ack_type = ack_type;
+ p_ipi_msg->msg_id = msg_id;
+ p_ipi_msg->param1 = param1;
+ p_ipi_msg->param2 = param2;
+
+ if (p_ipi_msg->data_type == AUDIO_IPI_PAYLOAD) {
+ if (data_buffer == NULL) {
+ AUD_LOG_W("payload data_buffer NULL, return");
+ return -1;
+ }
+ if (p_ipi_msg->payload_size > MAX_IPI_MSG_PAYLOAD_SIZE) {
+ AUD_LOG_W("payload_size %u error!!",
+ p_ipi_msg->payload_size);
+ return -1;
+ }
+ memcpy(p_ipi_msg->payload, data_buffer, p_ipi_msg->param1);
+ } else if (p_ipi_msg->data_type == AUDIO_IPI_DMA) {
+ if (data_buffer == NULL) {
+ AUD_LOG_W("dma data_buffer NULL, return");
+ return -1;
+ }
+ p_ipi_msg->dma_addr = (char *)data_buffer;
+
+ if (param1 > 0) {
+ dma_info = &p_ipi_msg->dma_info;
+ dma_info->data_size = 0;
+
+ dma_info->hal_buf.data_size = param1;
+ dma_info->hal_buf.memory_size = param2; /* not 0: write back */
+ dma_info->hal_buf.addr = data_buffer;
+ }
+ }
+
+#ifdef MTK_AUDIO_DSP_RECOVERY_SUPPORT
+ if (is_audio_dsp_ready(task_scene) == false) {
+ DUMP_IPI_MSG("dsp not ready", p_ipi_msg);
+ return 0;
+ }
+#endif
+
+ DUMP_IPI_MSG("hal send", p_ipi_msg);
+
+ ipi_msg_len = get_message_buf_size(p_ipi_msg);
+ if (check_msg_format(p_ipi_msg, ipi_msg_len) != 0) {
+ AUD_LOG_W("%s(), drop msg due to ipi fmt err", __FUNCTION__);
+ return -1;
+ }
+
+
+ LOCK_ALOCK(g_drv_lock);
+
+ if (g_ipi_drv < 0) {
+ AUD_LOG_W("%s(), g_ipi_drv = %d, return", __FUNCTION__, g_ipi_drv);
+ UNLOCK_ALOCK(g_drv_lock);
+ return -1;
+ }
+
+ switch (p_ipi_msg->data_type) {
+ case AUDIO_IPI_MSG_ONLY:
+ ret = ioctl(g_ipi_drv, AUDIO_IPI_IOCTL_SEND_MSG_ONLY, p_ipi_msg);
+ break;
+ case AUDIO_IPI_PAYLOAD:
+ ret = ioctl(g_ipi_drv, AUDIO_IPI_IOCTL_SEND_PAYLOAD, p_ipi_msg);
+ break;
+ case AUDIO_IPI_DMA:
+ ret = ioctl(g_ipi_drv, AUDIO_IPI_IOCTL_SEND_DRAM, p_ipi_msg);
+ break;
+ default:
+ AUD_LOG_W("%s() type %d not support!!",
+ __FUNCTION__, p_ipi_msg->data_type);
+ }
+ if (ret != 0) {
+ AUD_LOG_E("%s() ioctl fail! ret = %d, errno: %d", __FUNCTION__, ret, errno);
+ }
+
+ UNLOCK_ALOCK(g_drv_lock);
+
+ return ret;
+}
+
+
+
+/*
+ * =============================================================================
+ * Audio IPI DMA
+ * =============================================================================
+ */
+
+#if defined(MTK_AUDIO_IPI_DMA_SUPPORT)
+static void audio_ipi_dma_task_controller_reg(bool isRegister) {
+
+ if (isRegister) {
+#if defined(MTK_TINYSYS_SCP_SUPPORT)
+ audio_ipi_dma_cbk_register(
+ TASK_SCENE_AUDIO_CONTROLLER_CM4,
+ 0x20000,
+ 0x48000,
+ process_dma_msg,
+ NULL);
+#endif
+#if defined(MTK_AUDIODSP_SUPPORT)
+ audio_ipi_dma_cbk_register(
+ TASK_SCENE_AUDIO_CONTROLLER_HIFI3,
+ 0x20000,
+ 0x48000,
+ process_dma_msg,
+ NULL);
+#endif
+ } else {
+#if defined(MTK_TINYSYS_SCP_SUPPORT)
+ audio_ipi_dma_cbk_deregister(TASK_SCENE_AUDIO_CONTROLLER_CM4);
+#endif
+#if defined(MTK_AUDIODSP_SUPPORT)
+ audio_ipi_dma_cbk_deregister(TASK_SCENE_AUDIO_CONTROLLER_HIFI3);
+#endif
+ }
+}
+
+
+void audio_ipi_dma_cbk_register(
+ const uint8_t task_scene,
+ const uint32_t a2dSize,
+ const uint32_t d2aSize,
+ audio_ipi_dma_cbk_t cbk,
+ void *arg)
+{
+ struct audio_ipi_reg_dma_t dma_reg;
+ int ret = 0;
+
+
+ AUD_LOG_D("%s(), task %d, sz %u/%u, cbk %p, arg %p", __FUNCTION__,
+ task_scene, a2dSize, d2aSize, cbk, arg);
+
+ if (task_scene >= TASK_SCENE_SIZE) {
+ return;
+ }
+ if (a2dSize == 0 && d2aSize == 0) {
+ return;
+ }
+ if (cbk == NULL) {
+ return;
+ }
+
+ LOCK_ALOCK(g_dma_lock);
+
+ if (g_ipi_dma_client[task_scene].cbk != NULL) {
+ AUD_LOG_W("%s(), task %d cbk exist!!", __FUNCTION__, task_scene);
+ UNLOCK_ALOCK(g_dma_lock);
+ return;
+ }
+ g_ipi_dma_client[task_scene].cbk = cbk;
+ g_ipi_dma_client[task_scene].arg = arg;
+
+ UNLOCK_ALOCK(g_dma_lock);
+
+
+ /* alloc region */
+ dma_reg.task = task_scene;
+ dma_reg.reg_flag = 1;
+ dma_reg.a2d_size = a2dSize;
+ dma_reg.d2a_size = d2aSize;
+
+
+ LOCK_ALOCK(g_drv_lock);
+ if (g_ipi_drv < 0) {
+ AUD_LOG_E("%s(), driver %s file node %d!!", __FUNCTION__,
+ AUDIO_IPI_DEVICE_PATH, g_ipi_drv);
+ UNLOCK_ALOCK(g_drv_lock);
+ return;
+ }
+
+ ret = ioctl(g_ipi_drv, AUDIO_IPI_IOCTL_REG_DMA, &dma_reg);
+ if (ret != 0) {
+ AUD_LOG_E("%s() ioctl fail! ret = %d, errno: %d", __FUNCTION__, ret, errno);
+ }
+ UNLOCK_ALOCK(g_drv_lock);
+}
+
+
+void audio_ipi_dma_cbk_deregister(const uint8_t task_scene)
+{
+ struct audio_ipi_reg_dma_t dma_reg;
+ int ret = 0;
+
+
+
+ AUD_LOG_D("%s(), task %d", __FUNCTION__, task_scene);
+
+ if (task_scene >= TASK_SCENE_SIZE) {
+ return;
+ }
+
+ LOCK_ALOCK(g_dma_lock);
+
+ if (g_ipi_dma_client[task_scene].cbk == NULL) {
+ AUD_LOG_W("%s(), task %d cbk null!!", __FUNCTION__, task_scene);
+ UNLOCK_ALOCK(g_dma_lock);
+ return;
+ }
+ g_ipi_dma_client[task_scene].cbk = NULL;
+ g_ipi_dma_client[task_scene].arg = NULL;
+
+ UNLOCK_ALOCK(g_dma_lock);
+
+
+ /* free region */
+ dma_reg.task = task_scene;
+ dma_reg.reg_flag = 0;
+ dma_reg.a2d_size = 0;
+ dma_reg.d2a_size = 0;
+
+ LOCK_ALOCK(g_drv_lock);
+ if (g_ipi_drv < 0) {
+ AUD_LOG_E("%s(), driver %s file node %d!!", __FUNCTION__,
+ AUDIO_IPI_DEVICE_PATH, g_ipi_drv);
+ UNLOCK_ALOCK(g_drv_lock);
+ return;
+ }
+
+ ret = ioctl(g_ipi_drv, AUDIO_IPI_IOCTL_REG_DMA, &dma_reg);
+ if (ret != 0) {
+ AUD_LOG_E("%s() ioctl fail! ret = %d, errno: %d", __FUNCTION__, ret, errno);
+ }
+
+ UNLOCK_ALOCK(g_drv_lock);
+
+}
+
+
+void *read_ipi_thread(void *arg __unused)
+{
+ struct ipi_msg_t *msg = NULL;
+ uint8_t *data_buf = NULL;
+
+ int msg_size = 0;
+ int data_size = 0;
+ int length_read = 0;
+
+ int ret = 0;
+ int i = 0;
+
+ msg_size = sizeof(struct ipi_msg_t);
+
+ while (g_read_ipi_thread_enable) {
+ /* read */
+ length_read = read(g_ipi_drv, g_read_ipi_buf, MAX_DSP_DMA_WRITE_SIZE);
+ if (length_read <= msg_size || length_read > MAX_DSP_DMA_WRITE_SIZE) {
+ AUD_LOG_W("%s(), read dsp fail!! length_read: %d, errno: %d",
+ __FUNCTION__, (int32_t)length_read, errno);
+ usleep(500 * 1000);
+ continue;
+ }
+
+ /* parse msg */
+ msg = (struct ipi_msg_t *)g_read_ipi_buf;
+ if (msg->magic != IPI_MSG_MAGIC_NUMBER) {
+ AUD_LOG_W("%s(), msg msgic 0x%x fail!!", __FUNCTION__, msg->magic);
+ usleep(500 * 1000);
+ continue;
+ }
+
+ /* data buf */
+ data_size = length_read - msg_size;
+ data_buf = g_read_ipi_buf + msg_size;
+ if (msg->task_scene < TASK_SCENE_SIZE) {
+ if (g_ipi_dma_client[msg->task_scene].cbk != NULL) {
+ g_ipi_dma_client[msg->task_scene].cbk(
+ msg,
+ data_buf,
+ data_size,
+ g_ipi_dma_client[msg->task_scene].arg);
+ }
+ }
+ }
+
+ pthread_exit(NULL);
+ return NULL;
+}
+
+
+static void process_dma_msg(
+ struct ipi_msg_t *msg,
+ void *buf,
+ uint32_t size,
+ void *arg __unused)
+{
+ AUD_LOG_V("%s(), msg_%p, buf %p, size %u", __FUNCTION__, msg, buf, size);
+ switch (msg->msg_id) {
+#if defined(MTK_AUDIODSP_SUPPORT)
+ case AUD_CTL_MSG_D2A_AURISYS_DUMP:
+ process_aurisys_dsp_dump(msg, buf, size);
+ break;
+#endif
+ default:
+ DUMP_IPI_MSG("dma", msg);
+ (void)buf;
+ (void)size;
+ break;
+ }
+}
+#endif /* end of MTK_AUDIO_IPI_DMA_SUPPORT */
+
+
+/*
+ * =============================================================================
+ * OpenDSP ioctl (TODO: refine)
+ * =============================================================================
+ */
+
+void audio_load_task_scene(const uint8_t task_scene)
+{
+ int ret = 0;
+
+ LOCK_ALOCK(g_drv_lock);
+ if (g_ipi_drv < 0) {
+ AUD_LOG_E("%s(), driver %s file node %d!!", __FUNCTION__,
+ AUDIO_IPI_DEVICE_PATH, g_ipi_drv);
+ UNLOCK_ALOCK(g_drv_lock);
+ return;
+ }
+
+ ret = ioctl(g_ipi_drv, AUDIO_IPI_IOCTL_LOAD_SCENE, task_scene);
+ if (ret != 0) {
+ AUD_LOG_E("%s() ioctl fail! ret = %d, errno: %d", __FUNCTION__, ret, errno);
+ }
+
+ UNLOCK_ALOCK(g_drv_lock);
+}
+
+
+
+
+
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/mlds_api.c b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/mlds_api.c
new file mode 100644
index 0000000..0f4744d
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/aud_drv/mlds_api.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include "mlds_api.h"
+
+
+typedef struct {
+ uint32_t param1;
+ uint32_t param2;
+} my_private_enh_param_t;
+
+typedef struct {
+ mlds_task_config_t task_config;
+ uint32_t tmp_buf_size;
+ uint32_t my_private_var;
+} my_private_handler_t;
+
+
+lib_status_t mlds_query_working_buf_size(
+ const mlds_task_config_t *p_mlds_task_config,
+ uint32_t *p_working_buf_size) {
+ /* calculate working buffer working_buf_size by task_config */
+ printf("%s(), p_mlds_task_config->task_scene = %u\n",
+ __func__, p_mlds_task_config->task_scene);
+ printf("%s(), p_mlds_task_config->frame_size_ms = %u\n",
+ __func__, p_mlds_task_config->frame_size_ms);
+
+ printf("%s(), p_mlds_task_config->stream_uplink.device = %u\n",
+ __func__, p_mlds_task_config->stream_uplink.device);
+
+ printf("%s(), p_mlds_task_config->stream_uplink.sample_rate_in = %lu\n",
+ __func__, p_mlds_task_config->stream_uplink.sample_rate_in);
+ printf("%s(), p_mlds_task_config->stream_uplink.sample_rate_out = %lu\n",
+ __func__, p_mlds_task_config->stream_uplink.sample_rate_out);
+
+ printf("%s(), p_mlds_task_config->stream_uplink.bit_format_in = %d\n",
+ __func__, p_mlds_task_config->stream_uplink.bit_format_in);
+ printf("%s(), p_mlds_task_config->stream_uplink.bit_format_out = %d\n",
+ __func__, p_mlds_task_config->stream_uplink.bit_format_out);
+
+ printf("%s(), p_mlds_task_config->stream_uplink.num_channels_in = %d\n",
+ __func__, p_mlds_task_config->stream_uplink.num_channels_in);
+ printf("%s(), p_mlds_task_config->stream_uplink.num_channels_out = %d\n",
+ __func__, p_mlds_task_config->stream_uplink.num_channels_out);
+
+
+ printf("%s(), p_mlds_task_config->stream_downlink.device = %d\n",
+ __func__, p_mlds_task_config->stream_downlink.device);
+
+ printf("%s(), p_mlds_task_config->stream_downlink.sample_rate_in = %lu\n",
+ __func__, p_mlds_task_config->stream_downlink.sample_rate_in);
+ printf("%s(), p_mlds_task_config->stream_downlink.sample_rate_out = %lu\n",
+ __func__, p_mlds_task_config->stream_downlink.sample_rate_out);
+
+ printf("%s(), p_mlds_task_config->stream_downlink.bit_format_in = %d\n",
+ __func__, p_mlds_task_config->stream_downlink.bit_format_in);
+ printf("%s(), p_mlds_task_config->stream_downlink.bit_format_out = %d\n",
+ __func__, p_mlds_task_config->stream_downlink.bit_format_out);
+
+ printf("%s(), p_mlds_task_config->stream_downlink.num_channels_in = %d\n",
+ __func__, p_mlds_task_config->stream_downlink.num_channels_in);
+ printf("%s(), p_mlds_task_config->stream_downlink.num_channels_out = %d\n",
+ __func__, p_mlds_task_config->stream_downlink.num_channels_out);
+
+ *p_working_buf_size = sizeof(my_private_handler_t);
+
+ printf("%s(), working_buf_size = %lu\n", __func__, *p_working_buf_size);
+ return LIB_OK;
+}
+
+
+lib_status_t mlds_create_handler(
+ const mlds_task_config_t *p_mlds_task_config,
+ const uint32_t param_buf_size,
+ void *p_param_buf,
+ const uint32_t working_buf_size,
+ void *p_working_buf,
+ void **pp_handler) {
+ printf("%s()\n", __func__);
+
+ /* init handler by task_config */
+ *pp_handler = p_working_buf;
+
+ my_private_handler_t *my_private_handler = (my_private_handler_t *)*pp_handler;
+
+ memcpy(&my_private_handler->task_config, p_mlds_task_config,
+ sizeof(mlds_task_config_t));
+ my_private_handler->tmp_buf_size = 640;
+ my_private_handler->my_private_var = 0x5566;
+
+ return LIB_OK;
+}
+
+
+lib_status_t mlds_process_ul_buf(
+ void *p_ul_buf_in,
+ void *p_ul_buf_out,
+ void *p_aec_buf_in,
+ const uint32_t delay_ms,
+ void *p_handler,
+ void *arg) {
+ my_private_handler_t *my_private_handler = (my_private_handler_t *)p_handler;
+
+ memcpy(p_ul_buf_out, p_ul_buf_in, my_private_handler->tmp_buf_size);
+ return LIB_OK;
+}
+
+
+lib_status_t mlds_process_dl_buf(
+ void *p_dl_buf_in,
+ void *p_dl_buf_out,
+ void *p_handler,
+ void *arg) {
+ my_private_handler_t *my_private_handler = (my_private_handler_t *)p_handler;
+
+ memcpy(p_dl_buf_out, p_dl_buf_in, my_private_handler->tmp_buf_size);
+ return LIB_OK;
+}
+
+
+lib_status_t mlds_destroy_handler(void *p_handler) {
+ printf("%s(), p_handler = %p\n", __func__, p_handler);
+ return LIB_OK;
+}
+
+
+lib_status_t mlds_update_device(
+ const mlds_task_config_t *p_mlds_task_config,
+ const uint32_t param_buf_size,
+ void *p_param_buf,
+ void *p_handler) {
+ my_private_handler_t *my_private_handler = (my_private_handler_t *)p_handler;
+
+ printf("%s(), my_private_handler->my_private_var = 0x%lx\n", __func__,
+ my_private_handler->my_private_var);
+
+ task_device_in_t device_in_old =
+ my_private_handler->task_config.stream_uplink.device;
+ task_device_in_t device_in_new =
+ p_mlds_task_config->stream_uplink.device;
+
+ task_device_out_t device_out_old =
+ my_private_handler->task_config.stream_uplink.device;
+ task_device_out_t device_out_new =
+ p_mlds_task_config->stream_uplink.device;
+
+ printf("%s(), input device: 0x%x => 0x%x\n", __func__, device_in_old,
+ device_in_new);
+ printf("%s(), output device: 0x%x => 0x%x\n", __func__, device_out_old,
+ device_out_new);
+
+ return LIB_OK;
+}
+
+
+lib_status_t mlds_update_param(
+ const mlds_task_config_t *p_mlds_task_config,
+ const uint32_t param_buf_size,
+ void *p_param_buf,
+ void *p_handler) {
+ my_private_handler_t *my_private_handler = (my_private_handler_t *)p_handler;
+
+ printf("%s(), my_private_handler->my_private_var = 0x%lx\n", __func__,
+ my_private_handler->my_private_var);
+
+ /* pick up new param and update handler */
+
+ return LIB_OK;
+}
+
+
+lib_status_t mlds_query_param_buf_size(
+ const mlds_task_config_t *p_mlds_task_config,
+ const char *platform_name,
+ const char *param_file_path,
+ const int enhancement_mode,
+ uint32_t *p_param_buf_size) {
+ *p_param_buf_size = sizeof(my_private_enh_param_t);
+ printf("%s(), get param buf size %lu for speech mode %d from file %s\n",
+ __func__, *p_param_buf_size, enhancement_mode, param_file_path);
+
+ return LIB_OK;
+}
+
+
+lib_status_t mlds_parsing_param_file(
+ const mlds_task_config_t *p_mlds_task_config,
+ const char *platform_name,
+ const char *param_file_path,
+ const int enhancement_mode,
+ const uint32_t param_buf_size,
+ void *p_param_buf) {
+ my_private_enh_param_t *p_my_private_enh_param = NULL;
+
+ printf("%s(), parsing file %s...\n", __func__, param_file_path);
+
+ p_my_private_enh_param = (my_private_enh_param_t *)p_param_buf;
+
+ p_my_private_enh_param->param1 = 0x12; // should get param from param_file_path
+ p_my_private_enh_param->param2 = 0x34; // should get param from param_file_path
+
+ return LIB_OK;
+}
+
+
+lib_status_t mlds_set_addr_value(
+ uint32_t addr,
+ uint32_t value,
+ void *p_handler) {
+ //my_private_handler_t *my_private_handler = (my_private_handler_t *)p_handler;
+ printf("%s(), set value %lu at addr %p\n", __func__, value, (void *)addr);
+ return LIB_OK;
+}
+
+
+lib_status_t mlds_get_addr_value(
+ uint32_t addr,
+ uint32_t *p_value,
+ void *p_handler) {
+ //my_private_handler_t *my_private_handler = (my_private_handler_t *)p_handler;
+ *p_value = 0x1234; // should get param from handler
+
+ printf("%s(), value %lu at addr %p\n", __func__, *p_value, (void *)addr);
+ return LIB_OK;
+}
+
+
+lib_status_t mlds_set_ul_digital_gain(
+ const int16_t ul_analog_gain_ref_only,
+ const int16_t ul_digital_gain,
+ void *p_handler) {
+ printf("%s(), ul_digital_gain = %d\n", __func__, ul_digital_gain);
+ return LIB_OK;
+}
+
+
+lib_status_t mlds_set_dl_digital_gain(
+ const int16_t dl_analog_gain_ref_only,
+ const int16_t dl_digital_gain,
+ void *p_handler) {
+ printf("%s(), dl_digital_gain = %d\n", __func__, dl_digital_gain);
+ return LIB_OK;
+}
+
+
+lib_status_t mlds_set_ul_mute(uint8_t b_mute_on, void *p_handler) {
+ printf("%s(), b_mute_on = %d\n", __func__, b_mute_on);
+ return LIB_OK;
+}
+
+
+lib_status_t mlds_set_dl_mute(uint8_t b_mute_on, void *p_handler) {
+ printf("%s(), b_mute_on = %d\n", __func__, b_mute_on);
+ return LIB_OK;
+}
+
+
+lib_status_t mlds_set_ul_enhance(uint8_t b_enhance_on, void *p_handler) {
+ printf("%s(), b_enhance_on = %d\n", __func__, b_enhance_on);
+ return LIB_OK;
+}
+
+
+lib_status_t mlds_set_dl_enhance(uint8_t b_enhance_on, void *p_handler) {
+ printf("%s(), b_enhance_on = %d\n", __func__, b_enhance_on);
+ return LIB_OK;
+}
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAANCController.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAANCController.h
new file mode 100644
index 0000000..b8316d2
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAANCController.h
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_ALSA_AUDIO_ANC_CONTROLLER_H
+#define ANDROID_ALSA_AUDIO_ANC_CONTROLLER_H
+
+#include "AudioType.h"
+#include <AudioLock.h>
+
+#include <tinyalsa/asoundlib.h>
+
+#define AUD_DRV_ANC_IOC_MAGIC 'C'
+//ANC Controlaa
+#define SET_ANC_CONTROL _IOW(AUD_DRV_ANC_IOC_MAGIC, 0x1, int)
+#define SET_ANC_PARAMETER _IOW(AUD_DRV_ANC_IOC_MAGIC, 0x2, int)
+#define GET_ANC_PARAMETER _IOW(AUD_DRV_ANC_IOC_MAGIC, 0x3, int)
+
+#define MAX_TABS 68
+#define PROPERTY_ANC_SWITCH "persist.vendor.audiohal.anc_switch"
+namespace android {
+
+static char const *const kANCDevName = "/dev/ancservice";
+
+class AudioALSAHardwareResourceManager;
+//class AudioMTKGainController;
+
+class AudioALSAANCController {
+public:
+ virtual ~AudioALSAANCController();
+
+ static AudioALSAANCController *getInstance();
+
+ virtual void download_binary();
+ virtual void load_coef_l();
+ virtual void upload_coef_l();
+
+ virtual bool getANCEnable();
+ virtual bool setANCSwitch(bool bSwitch);
+ virtual bool getANCSwitch();
+ virtual bool setFivePole(bool isFivePole);
+ virtual bool getFivePole();
+
+ virtual bool setReceiverEnabled(bool bEnabled);
+ virtual bool setSpeakerEnabled(bool bEnabled);
+ virtual bool setHeadphoneSpeakerEnabled(bool bEnabled);
+
+ int setCMD(int cmd);
+
+protected:
+ AudioALSAANCController();
+
+ AudioALSAHardwareResourceManager *mHardwareResourceManager;
+ //AudioMTKGainController *mAudioMTKGainController;
+ //AudioALSAVolumeController *mAudioALSAVolumeController;
+
+
+ AudioLock mLock; // TODO(Harvey): could remove it later...
+
+ bool mEnable;
+ bool mSwitch;
+ bool mIsFivePole;
+ //Mutex mMutex;
+ int mFd;
+
+ struct pcm_config mConfig;
+ struct pcm *mPcm;
+
+private:
+ static AudioALSAANCController *mAudioALSAANCController; // singleton
+ int anc_coef[MAX_TABS];
+
+ void setHWEnable(bool enable);
+
+ void setANCEnable(bool enable);
+ void setANCEnable_l(bool enable);
+
+ bool RefreshEnabledDecision_l();
+
+ //ALSA relate control
+ struct mixer *mMixer;
+
+ bool mSpeakerEnabled;
+ bool mReceiverEnabled;
+ bool mHeadphoneSpeakerEnabled;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_ALSA_AUDIO_ANC_CONTROLLER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataClient.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataClient.h
new file mode 100644
index 0000000..59266a1
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataClient.h
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_CLIENT_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_CLIENT_H
+
+#include "IAudioALSACaptureDataClient.h"
+
+#include "AudioType.h"
+#include <AudioLock.h>
+#include "AudioUtility.h"
+#include "AudioTypeExt.h"
+
+//BesRecord process +++
+#include "AudioSpeechEnhLayer.h"
+//#include "AudioALSAVolumeController.h"
+#include "AudioVolumeInterface.h"
+#include "AudioSpeechEnhanceInfo.h"
+
+//BesRecord process ---
+
+//Android Native Preprocess effect +++
+#include "AudioPreProcess.h"
+//Android Native Preprocess effect ---
+#include "MtkAudioComponent.h"
+
+namespace android {
+
+class AudioALSACaptureDataProviderBase;
+class AudioALSACaptureDataProviderEchoRef;
+
+/// Observer pattern: Observer
+class AudioALSACaptureDataClient : public IAudioALSACaptureDataClient {
+public:
+ AudioALSACaptureDataClient(AudioALSACaptureDataProviderBase *pCaptureDataProvider, stream_attribute_t *stream_attribute_target);
+ virtual ~AudioALSACaptureDataClient();
+
+
+ /**
+ * set client index
+ */
+ inline void *getIdentity() const { return (void *)this; }
+
+ /**
+ * set/get raw frame count from hardware
+ */
+ inline void setRawStartFrameCount(int64_t frameCount) { mRawStartFrameCount = frameCount; }
+ virtual inline int64_t getRawStartFrameCount() { return mRawStartFrameCount; }
+
+ /**
+ * get / process / offer data
+ */
+ virtual uint32_t copyCaptureDataToClient(RingBuf pcm_read_buf); // called by capture data provider
+
+
+ /**
+ * read data from audio hardware
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes); // called by capture handler
+
+ //EchoRef+++
+ /**
+ * get / process / offer data
+ */
+ virtual uint32_t copyEchoRefCaptureDataToClient(RingBuf pcm_read_buf); // called by capture data provider
+
+ void AddEchoRefDataProvider(AudioALSACaptureDataProviderBase *pCaptureDataProvider, stream_attribute_t *stream_attribute_target);
+ //EchoRef---
+
+ /**
+ * Update BesRecord Parameters
+ */
+ status_t UpdateBesRecParam();
+
+ /**
+ * check if the attached client has low latency requirement
+ */
+ bool IsLowLatencyCapture(void);
+
+ /**
+ * Query captured frames & time stamp
+ */
+ int getCapturePosition(int64_t *frames, int64_t *time);
+
+ const stream_attribute_t *getStreamAttributeSource() { return mStreamAttributeSource; }
+
+ /**
+ * sync pcm start
+ */
+ bool isNeedSyncPcmStart() { return IsVoIPEnable(); }
+
+private:
+ AudioALSACaptureDataClient() {}
+ AudioALSACaptureDataProviderBase *mCaptureDataProvider;
+ int64_t mRawStartFrameCount;
+
+ bool IsNeedApplyVolume();
+ status_t ApplyVolume(void *Buffer, uint32_t BufferSize);
+
+ enum channel_remix_operation {
+ CHANNEL_REMIX_NOP = 0,
+ CHANNEL_STEREO_CROSSMIX_L2R,
+ CHANNEL_STEREO_CROSSMIX_R2L,
+ CHANNEL_STEREO_DOWNMIX,
+ CHANNEL_STEREO_DOWNMIX_L_ONLY,
+ CHANNEL_STEREO_DOWNMIX_R_ONLY,
+ CHANNEL_MONO_TO_STEREO,
+ };
+
+
+ AudioLock mLock;
+
+ /**
+ * Speech EnhanceInfo Instance
+ */
+ AudioSpeechEnhanceInfo *mAudioSpeechEnhanceInfoInstance;
+
+ /**
+ * attribute
+ */
+ const stream_attribute_t *mStreamAttributeSource; // from audio hw
+ stream_attribute_t *mStreamAttributeTarget; // to stream in
+
+
+ /**
+ * local ring buffer
+ */
+ RingBuf mRawDataBuf;
+ RingBuf mSrcDataBuf;
+ RingBuf mProcessedDataBuf;
+
+
+ /**
+ * Bli SRC
+ */
+ MtkAudioSrcBase *mBliSrc;
+
+ bool mMicMute;
+ bool mMuteTransition;
+
+ uint32_t TransferFormat(char *linear_buffer, audio_format_t src_format, audio_format_t des_format, uint32_t bytes);
+
+ //BesRecord Move to here for temp
+ SPELayer *mSPELayer;
+
+ //#ifdef MTK_AUDIO_HD_REC_SUPPORT
+ //BesRecord process +++
+ //Load BesRecord parameters from NVRam
+ void LoadBesRecordParams(void);
+ int CheckBesRecordMode(void);
+ void ConfigBesRecordParams(void);
+ void StartBesRecord(void);
+ void StopBesRecord(void);
+ uint32_t BesRecordPreprocess(void *buffer, uint32_t bytes);
+ int GetBesRecordRoutePath(void);
+ int SetCaptureGain(void);
+ bool CheckBesRecordBypass(void);
+ bool CheckNeedBesRecordSRC(void);
+ bool IsVoIPEnable(void);
+ bool IsNeedChannelRemix() { return (mChannelRemixOp != CHANNEL_REMIX_NOP); }
+ void CheckChannelRemixOp(void);
+ ssize_t ApplyChannelRemix(short *buffer, size_t bytes);
+ ssize_t ApplyChannelRemixWithRingBuf(RingBuf *srcBuffer, RingBuf *dstBuffer);
+ void CheckBesRecordStereoModeEnable(void);
+
+ timespec GetCaptureTimeStamp(void);
+ timespec GetEchoRefTimeStamp(void);
+
+ bool CheckDynamicSpeechEnhancementMaskOnOff(const voip_sph_enh_dynamic_mask_t dynamic_mask_type);
+ void SetDMNREnable(DMNR_TYPE type, bool enable);
+ void CheckDynamicSpeechMask(void);
+ void UpdateDynamicFunction(void);
+
+#if ((!defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)) || (MTK_AUDIO_TUNING_TOOL_V2_PHASE == 1))
+ AUDIO_HD_RECORD_SCENE_TABLE_STRUCT mBesRecordSceneTable;
+ AUDIO_HD_RECORD_PARAM_STRUCT mBesRecordParam;
+ AUDIO_VOIP_PARAM_STRUCT mVOIPParam;
+ AUDIO_CUSTOM_EXTRA_PARAM_STRUCT mDMNRParam;
+
+ int mBesRecordModeIndex;
+ int mBesRecordSceneIndex;
+#endif
+
+ AudioVolumeInterface *mAudioALSAVolumeController;
+ bool mBesRecordStereoMode;
+ bool mBypassBesRecord;
+ bool mNeedBesRecordSRC;
+ uint32_t dropBesRecordDataSize;
+
+ SPE_MODE mSpeechProcessMode;
+ voip_sph_enh_mask_struct_t mVoIPSpeechEnhancementMask;
+ uint32_t mChannelRemixOp;
+ //Audio tuning tool
+ bool mBesRecTuningEnable;
+ char m_strTuningFileName[VM_FILE_NAME_LEN_MAX];
+ /**
+ * Bli SRC
+ */
+ MtkAudioSrcBase *mBliSrcHandler1;
+ MtkAudioSrcBase *mBliSrcHandler2;
+ int mBesRecSRCSizeFactor;
+ int mBesRecSRCSizeFactor2;
+ //BesRecord process ---
+ //#endif
+
+ //Android Native Preprocess effect +++
+ AudioPreProcess *mAudioPreProcessEffect;
+ uint32_t NativePreprocess(void *buffer, uint32_t bytes);
+ void CheckNativeEffect(void);
+ //Android Native Preprocess effect ---
+
+ //EchoRef+++
+ AudioALSACaptureDataProviderBase *mCaptureDataProviderEchoRef;
+ /**
+ * attribute
+ */
+ const stream_attribute_t *mStreamAttributeSourceEchoRef; // from audio hw, need the same as DL1 stream out used
+ stream_attribute_t *mStreamAttributeTargetEchoRef; // to stream in
+
+ /**
+ * local ring buffer
+ */
+ RingBuf mEchoRefRawDataBuf;
+ RingBuf mEchoRefSrcDataBuf;
+
+ /**
+ * Bli SRC
+ */
+ MtkAudioSrcBase *mBliSrcEchoRef;
+ MtkAudioSrcBase *mBliSrcEchoRefBesRecord;
+ //EchoRef---
+
+ /**
+ VOIP Latency
+ */
+ bool mFirstSRC;
+ bool mFirstEchoSRC;
+ uint32_t mDropMs;
+ uint32_t getLatencyTime();
+
+ /**
+ * AudioCustParamClient
+ */
+ AudioCustParamClient *mAudioCustParamClient;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_CLIENT_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataClientAurisysNormal.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataClientAurisysNormal.h
new file mode 100644
index 0000000..58932c0
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataClientAurisysNormal.h
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_CLIENT_AURISYS_NORMAL_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_CLIENT_AURISYS_NORMAL_H
+
+#include "IAudioALSACaptureDataClient.h"
+
+#include <pthread.h>
+
+
+#include "AudioType.h"
+#include "AudioUtility.h"
+
+#include <audio_ringbuf.h>
+
+#include <AudioLock.h>
+
+
+// Aurisys Framework
+struct aurisys_lib_manager_t;
+struct aurisys_lib_manager_config_t;
+struct audio_pool_buf_t;
+struct data_buf_t;
+
+
+class AudioVolumeInterface;
+
+namespace android {
+
+class AudioALSACaptureDataProviderBase;
+class AudioALSACaptureDataProviderEchoRef;
+
+//Android Native Preprocess effect +++
+class AudioPreProcess;
+//Android Native Preprocess effect ---
+
+
+/// Observer pattern: Observer
+class AudioALSACaptureDataClientAurisysNormal : public IAudioALSACaptureDataClient {
+public:
+ AudioALSACaptureDataClientAurisysNormal(
+ AudioALSACaptureDataProviderBase *pCaptureDataProvider,
+ stream_attribute_t *stream_attribute_target,
+ AudioALSACaptureDataProviderBase *pCaptureDataProviderEchoRef);
+
+ virtual ~AudioALSACaptureDataClientAurisysNormal();
+
+
+ /**
+ * set client index
+ */
+ inline void *getIdentity() const { return (void *)this; }
+
+ /**
+ * set/get raw frame count from hardware
+ */
+ inline void setRawStartFrameCount(int64_t frameCount) { mRawStartFrameCount = frameCount; }
+ virtual inline int64_t getRawStartFrameCount() { return mRawStartFrameCount; }
+
+ /**
+ * let provider copy raw data to client
+ */
+ virtual uint32_t copyCaptureDataToClient(RingBuf pcm_read_buf); // called by capture data provider
+
+
+ /**
+ * let handler read processed data from client
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes); // called by capture handler
+
+
+ /**
+ * check if the attached client has low latency requirement
+ */
+ bool IsLowLatencyCapture(void);
+
+
+ /**
+ * Query captured frames & time stamp
+ */
+ int getCapturePosition(int64_t *frames, int64_t *time);
+
+
+ /**
+ * EchoRef
+ */
+ void AddEchoRefDataProvider(AudioALSACaptureDataProviderBase *pCaptureDataProvider, stream_attribute_t *stream_attribute_target);
+ uint32_t copyEchoRefCaptureDataToClient(RingBuf pcm_read_buf);
+
+
+ /**
+ * Update BesRecord Parameters
+ */
+ status_t UpdateBesRecParam() { return INVALID_OPERATION; } /* TODO: remove it */
+
+
+ /**
+ * Attribute
+ */
+ const stream_attribute_t *getStreamAttributeSource() { return mStreamAttributeSource; }
+
+
+ /**
+ * sync pcm start
+ */
+ bool isNeedSyncPcmStart() { return IsAECEnable(); }
+
+
+ /**
+ * StreamIn reopen
+ */
+ virtual bool getStreamInReopen() { return mStreamInReopen; }
+ virtual void setStreamInReopen(bool state) { mStreamInReopen = state; }
+
+
+private:
+ AudioALSACaptureDataClientAurisysNormal() {}
+
+
+ /**
+ * stream attribute
+ */
+ const stream_attribute_t *mStreamAttributeSource; // from audio hw
+ stream_attribute_t *mStreamAttributeTarget; // to stream in
+ bool IsVoIPEnable(void) { return mStreamAttributeTarget->mVoIPEnable; }
+
+
+ /**
+ * for data provider
+ */
+ AudioALSACaptureDataProviderBase *mCaptureDataProvider;
+ bool getPcmStatus(void);
+ int64_t mRawStartFrameCount;
+
+
+ /**
+ * for StreamIn reopen
+ */
+ void handleLockTimeout();
+
+
+ /**
+ * gain control
+ */
+ bool IsNeedApplyVolume();
+ status_t ApplyVolume(void *Buffer, uint32_t BufferSize);
+ bool mMicMute;
+ bool mMuteTransition;
+ AudioVolumeInterface *mAudioALSAVolumeController;
+
+
+ /**
+ * process raw data to processed data
+ */
+ bool mEnable;
+
+ bool mStreamInReopen;
+
+ static void *processThread(void *arg);
+ pthread_t hProcessThread;
+ bool mProcessThreadLaunched;
+
+ uint32_t mLatency;
+
+ audio_ringbuf_t mRawDataBuf;
+ AudioLock mRawDataBufLock;
+ struct timespec mRawDataBufTimeStamp;
+ uint32_t mRawDataPeriodBufSize;
+
+ audio_ringbuf_t mProcessedDataBuf;
+ AudioLock mProcessedDataBufLock;
+ uint32_t mProcessedDataPeriodBufSize;
+
+ /**
+ * EchoRef
+ */
+ bool IsAECEnable(void) { return (mCaptureDataProviderEchoRef != NULL); }
+ void syncEchoRefData(const uint8_t data_buf_type, audio_ringbuf_t *rb_data); /* data_buf_type_t */
+
+ AudioALSACaptureDataProviderBase *mCaptureDataProviderEchoRef;
+ const stream_attribute_t *mStreamAttributeSourceEchoRef; // from audio hw, need the same as DL1 stream out used
+
+ audio_ringbuf_t mEchoRefDataBuf;
+ struct timespec mEchoRefDataBufTimeStamp;
+ uint32_t mEchoRefDataPeriodBufSize;
+
+ bool mIsEchoRefDataSync;
+
+
+ /**
+ * Aurisys Framework
+ */
+ void CreateAurisysLibManager();
+ void InitArsiTaskConfig(struct aurisys_lib_manager_config_t *pManagerConfig);
+ void InitBufferConfig(struct aurisys_lib_manager_t *manager);
+ void DestroyAurisysLibManager();
+
+ struct aurisys_lib_manager_t *mAurisysLibManager;
+ struct aurisys_lib_manager_config_t *mManagerConfig;
+ uint32_t mAurisysScenario;
+
+ audio_pool_buf_t *mAudioPoolBufUlIn;
+ audio_pool_buf_t *mAudioPoolBufUlOut;
+ audio_pool_buf_t *mAudioPoolBufUlAec;
+ audio_pool_buf_t *mAudioPoolBufDlIn;
+ audio_pool_buf_t *mAudioPoolBufDlOut;
+ struct data_buf_t *mLinearOut;
+
+
+ /**
+ * Depop
+ */
+ uint32_t mDropPopSize;
+
+
+ //Android Native Preprocess effect +++
+ AudioPreProcess *mAudioPreProcessEffect;
+ uint32_t NativePreprocess(void *buffer, uint32_t bytes);
+ void CheckNativeEffect(void);
+ //Android Native Preprocess effect ---
+
+
+
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_CLIENT_AURISYS_NORMAL_H
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataClientDsp.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataClientDsp.h
new file mode 100644
index 0000000..cb080ae
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataClientDsp.h
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_CLIENT_DSP_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_CLIENT_DSP_H
+
+#include "IAudioALSACaptureDataClient.h"
+
+#include <pthread.h>
+
+
+#include "AudioType.h"
+#include "AudioUtility.h"
+
+#include <audio_ringbuf.h>
+
+#include <AudioLock.h>
+
+
+
+namespace android {
+
+class AudioALSACaptureDataProviderBase;
+class MtkAudioSrcBase;
+class MtkAudioBitConverterBase;
+
+/* TODO: base class */
+class AudioALSACaptureDataClientDsp : public IAudioALSACaptureDataClient {
+public:
+ AudioALSACaptureDataClientDsp(
+ AudioALSACaptureDataProviderBase *pCaptureDataProvider,
+ stream_attribute_t *stream_attribute_target);
+
+ virtual ~AudioALSACaptureDataClientDsp();
+
+
+ /**
+ * set client index
+ */
+ inline void *getIdentity() const { return (void *)this; }
+
+ /**
+ * set/get raw frame count from hardware
+ */
+ inline void setRawStartFrameCount(int64_t frameCount) { mRawStartFrameCount = frameCount; }
+ virtual inline int64_t getRawStartFrameCount() { return mRawStartFrameCount; }
+
+ /**
+ * let provider copy raw data to client
+ */
+ virtual uint32_t copyCaptureDataToClient(RingBuf pcm_read_buf); // called by capture data provider
+
+
+ /**
+ * let handler read processed data from client
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes); // called by capture handler
+
+
+ /**
+ * check if the attached client has low latency requirement
+ */
+ bool IsLowLatencyCapture(void);
+
+
+ /**
+ * Query captured frames & time stamp
+ */
+ int getCapturePosition(int64_t *frames, int64_t *time);
+
+
+ /**
+ * EchoRef
+ */
+ void AddEchoRefDataProvider(AudioALSACaptureDataProviderBase *pCaptureDataProvider, stream_attribute_t *stream_attribute_target);
+ uint32_t copyEchoRefCaptureDataToClient(RingBuf pcm_read_buf);
+
+
+ /**
+ * Update BesRecord Parameters
+ */
+ status_t UpdateBesRecParam() { return INVALID_OPERATION; } /* TODO: remove it */
+
+
+ /**
+ * Attribute
+ */
+ const stream_attribute_t *getStreamAttributeSource() { return mStreamAttributeSource; }
+
+
+
+private:
+ AudioALSACaptureDataClientDsp() {}
+
+
+ /**
+ * stream attribute
+ */
+ const stream_attribute_t *mStreamAttributeSource; // from audio hw
+ stream_attribute_t *mStreamAttributeTarget; // to stream in
+ stream_attribute_t mStreamAttributeTargetDSP; // to stream DSP
+
+ bool isVoIPEnable(void) { return mStreamAttributeTarget->mVoIPEnable; }
+
+ /**
+ * for data provider
+ */
+ AudioALSACaptureDataProviderBase *mCaptureDataProvider;
+ int64_t mRawStartFrameCount;
+
+ /**
+ * gain control
+ */
+ bool IsNeedApplyVolume();
+ status_t ApplyVolume(void *Buffer, uint32_t BufferSize);
+ bool mMicMute;
+ bool mMuteTransition;
+
+ void configDSPAttribute();
+
+ /**
+ * process raw data to processed data
+ */
+ bool mEnable;
+
+ static void *processThread(void *arg);
+ pthread_t hProcessThread;
+
+ audio_ringbuf_t mRawDataBuf;
+ char *mRawDataBufLinear;
+ AudioLock mRawDataBufLock;
+
+ audio_ringbuf_t mProcessedDataBuf;
+ AudioLock mProcessedDataBufLock;
+
+
+ /**
+ * Bli SRC
+ */
+ status_t initBliSrc();
+ status_t deinitBliSrc();
+ status_t doBliSrc(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes);
+ MtkAudioSrcBase *mBliSrc;
+ char *mBliSrcOutputBuffer;
+
+
+ /**
+ * Bit Converter
+ */
+ status_t initBitConverter();
+ status_t deinitBitConverter();
+ status_t doBitConversion(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes);
+
+ MtkAudioBitConverterBase *mBitConverter;
+ char *mBitConverterOutputBuffer;
+
+ /**
+ * Depop
+ */
+ uint32_t mDropPopSize;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_CLIENT_SYNC_IO_H
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataClientSyncIO.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataClientSyncIO.h
new file mode 100644
index 0000000..d41bf6e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataClientSyncIO.h
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_CLIENT_SYNC_IO_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_CLIENT_SYNC_IO_H
+
+#include "IAudioALSACaptureDataClient.h"
+
+#include <pthread.h>
+
+
+#include "AudioType.h"
+#include "AudioUtility.h"
+
+#include <audio_ringbuf.h>
+
+#include <AudioLock.h>
+
+
+
+namespace android {
+
+class AudioALSACaptureDataProviderBase;
+class MtkAudioSrcBase;
+class MtkAudioBitConverterBase;
+
+/* TODO: base class */
+class AudioALSACaptureDataClientSyncIO : public IAudioALSACaptureDataClient {
+public:
+ AudioALSACaptureDataClientSyncIO(
+ AudioALSACaptureDataProviderBase *pCaptureDataProvider,
+ stream_attribute_t *stream_attribute_target);
+
+ virtual ~AudioALSACaptureDataClientSyncIO();
+
+
+ /**
+ * set client index
+ */
+ inline void *getIdentity() const { return (void *)this; }
+
+ /**
+ * set/get raw frame count from hardware
+ */
+ inline void setRawStartFrameCount(int64_t frameCount) { mRawStartFrameCount = frameCount; }
+ virtual inline int64_t getRawStartFrameCount() { return mRawStartFrameCount; }
+
+ /**
+ * let provider copy raw data to client
+ */
+ virtual uint32_t copyCaptureDataToClient(RingBuf pcm_read_buf); // called by capture data provider
+
+
+ /**
+ * let handler read processed data from client
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes); // called by capture handler
+
+
+ /**
+ * check if the attached client has low latency requirement
+ */
+ bool IsLowLatencyCapture(void);
+
+
+ /**
+ * Query captured frames & time stamp
+ */
+ int getCapturePosition(int64_t *frames, int64_t *time);
+
+
+ /**
+ * EchoRef
+ */
+ void AddEchoRefDataProvider(AudioALSACaptureDataProviderBase *pCaptureDataProvider, stream_attribute_t *stream_attribute_target);
+ uint32_t copyEchoRefCaptureDataToClient(RingBuf pcm_read_buf);
+
+
+ /**
+ * Update BesRecord Parameters
+ */
+ status_t UpdateBesRecParam() { return INVALID_OPERATION; } /* TODO: remove it */
+
+
+ /**
+ * Attribute
+ */
+ const stream_attribute_t *getStreamAttributeSource() { return mStreamAttributeSource; }
+
+
+
+private:
+ AudioALSACaptureDataClientSyncIO() {}
+
+
+ /**
+ * stream attribute
+ */
+ const stream_attribute_t *mStreamAttributeSource; // from audio hw
+ stream_attribute_t *mStreamAttributeTarget; // to stream in
+
+
+ /**
+ * for data provider
+ */
+ AudioALSACaptureDataProviderBase *mCaptureDataProvider;
+ int64_t mRawStartFrameCount;
+
+
+ /**
+ * gain control
+ */
+ bool IsNeedApplyVolume();
+ status_t ApplyVolume(void *Buffer, uint32_t BufferSize);
+ bool mMicMute;
+ bool mMuteTransition;
+
+
+ /**
+ * process raw data to processed data
+ */
+ bool mEnable;
+
+ static void *processThread(void *arg);
+ pthread_t hProcessThread;
+
+ audio_ringbuf_t mRawDataBuf;
+ char *mRawDataBufLinear;
+ AudioLock mRawDataBufLock;
+
+ audio_ringbuf_t mProcessedDataBuf;
+ AudioLock mProcessedDataBufLock;
+
+
+ /**
+ * Bli SRC
+ */
+ status_t initBliSrc();
+ status_t deinitBliSrc();
+ status_t doBliSrc(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes);
+ MtkAudioSrcBase *mBliSrc;
+ char *mBliSrcOutputBuffer;
+
+
+ /**
+ * Bit Converter
+ */
+ status_t initBitConverter();
+ status_t deinitBitConverter();
+ status_t doBitConversion(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes);
+
+ MtkAudioBitConverterBase *mBitConverter;
+ char *mBitConverterOutputBuffer;
+
+ /**
+ * Depop
+ */
+ uint32_t mDropPopSize;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_CLIENT_SYNC_IO_H
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderAAudio.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderAAudio.h
new file mode 100644
index 0000000..f89cea7
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderAAudio.h
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_AAUDIO_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_AAUDIO_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+namespace android {
+
+class AudioALSACaptureDataProviderAAudio : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderAAudio();
+
+ static AudioALSACaptureDataProviderAAudio *getInstance();
+ static void freeInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+ /**
+ * AAudio MMAP
+ */
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t createMmapBuffer(int32_t min_size_frames,
+ struct audio_mmap_buffer_info *info);
+ virtual status_t getMmapPosition(struct audio_mmap_position *position);
+
+
+protected:
+ AudioALSACaptureDataProviderAAudio();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderAAudio *mAudioALSACaptureDataProviderAAudio;
+ struct mixer *mMixer;
+
+
+ /**
+ * AAudio MMAP
+ */
+ int64_t mTime_nanoseconds;
+ int32_t mPosition_frames;
+ int32_t mMin_size_frames;
+ struct timespec mCreateMmapTime;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_AAUDIO_H
\ No newline at end of file
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderANC.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderANC.h
new file mode 100644
index 0000000..c7aa2e4
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderANC.h
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ANC_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ANC_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+namespace android {
+
+class AudioALSACaptureDataProviderANC : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderANC();
+
+ static AudioALSACaptureDataProviderANC *getInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+
+
+protected:
+ AudioALSACaptureDataProviderANC();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderANC *mAudioALSACaptureDataProviderANC;
+
+
+ /**
+ * pcm read thread
+ */
+ static void *readThread(void *arg);
+ pthread_t hReadThread;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ANC_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderBTCVSD.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderBTCVSD.h
new file mode 100644
index 0000000..c7b2a1e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderBTCVSD.h
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_BT_CVSD_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_BT_CVSD_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+namespace android {
+
+class WCNChipController;
+class AudioBTCVSDControl;
+
+class AudioALSACaptureDataProviderBTCVSD : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderBTCVSD();
+
+ static AudioALSACaptureDataProviderBTCVSD *getInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+
+
+protected:
+ AudioALSACaptureDataProviderBTCVSD();
+
+
+ uint32_t readDataFromBTCVSD(void *linear_buffer, bool *isMuteData, struct timespec *bufferTimeStamp);
+
+ /**
+ * Bli SRC
+ */
+ status_t initBliSrc();
+ status_t deinitBliSrc();
+ status_t doBliSrc(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes);
+
+ /**
+ * Timestamp related
+ */
+ status_t getKernelTimeStamp(struct timespec *captureStartTime);
+
+ struct timespec getCurrentTimeStamp();
+
+ status_t updateStartTimeStamp(struct timespec timeStamp);
+
+ status_t updateCaptureTimeStampByStartTime(uint32_t bufferSize);
+
+ bool isBufferTimeStampMatchEstimated(struct timespec timeStamp);
+
+ uint32_t getLatencyTime();
+
+ struct timespec mCaptureStartTime;
+
+ struct timespec mEstimatedBufferTimeStamp;
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderBTCVSD *mAudioALSACaptureDataProviderBTCVSD;
+
+ WCNChipController *mWCNChipController;
+ AudioBTCVSDControl *mAudioBTCVSDControl;
+ struct mixer *mMixer;
+ bool mBTIrqReceived;
+
+ /**
+ * pcm read thread
+ */
+ static void *readThread(void *arg);
+ pthread_t hReadThread;
+
+ uint32_t mReadBufferSize;
+
+ MtkAudioSrcBase *mBliSrc;
+ char *mBliSrcOutputBuffer;
+
+ int mFd2;
+
+ struct timespec mNewtime, mOldtime, mOldCVSDReadTime;
+ double mTimerec[5];
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_BT_CVSD_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderBTSCO.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderBTSCO.h
new file mode 100644
index 0000000..a808695
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderBTSCO.h
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_BT_SCO_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_BT_SCO_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+namespace android {
+
+class WCNChipController;
+
+class AudioALSACaptureDataProviderBTSCO : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderBTSCO();
+
+ static AudioALSACaptureDataProviderBTSCO *getInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+
+protected:
+ AudioALSACaptureDataProviderBTSCO();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderBTSCO *mAudioALSACaptureDataProviderBTSCO;
+
+ WCNChipController *mWCNChipController;
+
+ /**
+ * pcm read thread
+ */
+ static void *readThread(void *arg);
+ pthread_t hReadThread;
+
+ struct timespec mNewtime, mOldtime; //for calculate latency
+ double timerec[3]; //0=>threadloop, 1=>kernel delay, 2=>process delay
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_BT_SCO_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderBase.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderBase.h
new file mode 100644
index 0000000..43df0e3
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderBase.h
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_BASE_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_BASE_H
+
+#include <utils/KeyedVector.h>
+
+#include <tinyalsa/asoundlib.h>
+
+#include <pthread.h>
+
+
+#include "AudioType.h"
+#include <AudioLock.h>
+#include "AudioUtility.h"
+#include "AudioALSADeviceParser.h"
+
+#ifdef MTK_AUDIO_SCP_SUPPORT
+struct ipi_msg_t;
+#endif
+
+#ifdef MTK_AUDIODSP_SUPPORT
+#include "AudioDspType.h"
+#endif
+
+typedef int (*audio_pcm_read_wrapper_fp_t)(struct pcm *pcm, void *data, unsigned int count);
+
+namespace android {
+
+class IAudioALSACaptureDataClient;
+class AudioALSAHardwareResourceManager;
+class AudioMessengerIPI;
+
+/// Observer pattern: Subject
+class AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderBase();
+
+ /**
+ * attach/detach client to capture data provider
+ */
+ void attach(IAudioALSACaptureDataClient *pCaptureDataClient);
+ void detach(IAudioALSACaptureDataClient *pCaptureDataClient);
+
+ void configStreamAttribute(const stream_attribute_t *attribute);
+ const stream_attribute_t *getStreamAttributeSource() { return &mStreamAttributeSource; }
+ stream_attribute_t getStreamAttributeTargetDSP() { return mStreamAttributeTargetDSP; }
+
+ bool isEnable() { return mEnable; }
+
+ int getCapturePosition(int64_t *frames, int64_t *time);
+
+ capture_provider_t getCaptureDataProviderType() { return mCaptureDataProviderType; }
+
+ virtual uint32_t getLatencyTime() { return mlatency; }
+
+ virtual bool getReadThreadReady() { return mReadThreadReady; }
+ void signalPcmStart();
+ status_t writeData(const char *echoRefData, uint32_t dataSize, struct timespec *timestamp);
+
+ virtual status_t getPcmStatus();
+
+ /**
+ * AAudio MMAP
+ */
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t createMmapBuffer(int32_t min_size_frames,
+ struct audio_mmap_buffer_info *info);
+ virtual status_t getMmapPosition(struct audio_mmap_position *position);
+
+
+protected:
+ AudioALSACaptureDataProviderBase();
+ AudioMessengerIPI *mAudioMessengerIPI;
+ AudioALSAHardwareResourceManager *mHardwareResourceManager;
+
+ /**
+ * pcm driver open/close
+ */
+ status_t openPcmDriver(const unsigned int device); // TODO(Harvey): Query device by string
+ status_t openPcmDriverWithFlag(const unsigned int device, unsigned int flag);
+ status_t closePcmDriver();
+
+ /**
+ * provide captrue data to all attached clients
+ */
+ void provideCaptureDataToAllClients(const uint32_t open_index);
+
+
+ //echoref+++
+ /**
+ * provide captrue data to all attached clients
+ */
+ void provideEchoRefCaptureDataToAllClients(const uint32_t open_index);
+ //echoref---
+
+
+ /**
+ * pcm write function
+ */
+ int pcmRead(struct pcm *mpcm, void *data, unsigned int count);
+
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ virtual status_t open() = 0;
+ virtual status_t close() = 0;
+
+ /**
+ * open/close pmic interface when attach & detach
+ */
+ void enablePmicInputDevice(bool enable);
+
+ /**
+ * pcm read time stamp
+ */
+ status_t GetCaptureTimeStamp(time_info_struct_t *Time_Info, unsigned int read_size);
+
+ int64_t mCaptureFramesReaded;
+ timespec mCaptureTimeStamp;
+
+ /**
+ * check if any attached clients has low latency requirement
+ */
+ bool HasLowLatencyCapture(void);
+
+ /**
+ * Set the thread priority
+ */
+ void setThreadPriority(void);
+
+ /**
+ * enable state
+ */
+ bool mEnable;
+ static status_t mPcmStatus;
+
+ /**
+ * Provider Index
+ */
+ uint32_t mOpenIndex;
+
+
+ /**
+ * latency time
+ */
+ uint32_t mlatency;
+
+
+ /**
+ * lock
+ */
+ AudioLock mTimeStampLock; // Protect timestamp
+
+ /**
+ * client vector
+ */
+ KeyedVector<void *, IAudioALSACaptureDataClient *> mCaptureDataClientVector;
+
+ /**
+ * local ring buffer
+ */
+ RingBuf mPcmReadBuf;
+
+
+ /**
+ * tinyalsa pcm interface
+ */
+ struct pcm_config mConfig;
+ struct pcm *mPcm;
+ String8 mApTurnOnSequence;
+ bool isNeedSyncPcmStart();
+ void waitPcmStart();
+
+
+ /**
+ * pcm start
+ */
+ AudioLock mStartLock; // first
+ bool mStart;
+ bool mReadThreadReady;
+
+
+ /**
+ * pcm read attribute
+ */
+ stream_attribute_t mStreamAttributeSource;
+ stream_attribute_t mStreamAttributeTargetDSP;
+
+ capture_provider_t mCaptureDataProviderType;
+
+ unsigned int mPcmflag;
+ audio_pcm_read_wrapper_fp_t audio_pcm_read_wrapper_fp;
+
+ void OpenPCMDump(const char *class_name);
+ void ClosePCMDump(void);
+ void WritePcmDumpData(void);
+ String8 mDumpFileName;
+ FILE *mPCMDumpFile;
+ FILE *mPCMDumpFile4ch;
+
+#ifdef MTK_AUDIODSP_SUPPORT
+ void OpenPCMDumpDsp(const char *class_name);
+ void ClosePCMDumpDsp(void);
+ void WritePcmDumpDataDsp(void);
+ String8 mDumpFileNameDsp;
+ FILE *mPCMDumpFileDsp;
+ FILE *pcmin_dump_array[DEBUG_PCMDUMP_NUM];
+ static uint32_t mDumpFileNumDsp;
+
+ /* dsp pcm dump */
+ void get_task_pcmdump_info(int task_id, int param1, void **pcm_dump);
+ void set_task_pcmdump_info(int task_id, int param1, void *pcm_dump);
+ void processDmaMsg(struct ipi_msg_t *msg,
+ void *buf,
+ uint32_t size);
+ static void processDmaMsgWrapper(struct ipi_msg_t *msg,
+ void *buf,
+ uint32_t size,
+ void *arg);
+#endif
+
+private:
+ /**
+ * lock
+ */
+ AudioLock mEnableLock; // first
+ AudioLock mClientLock; // second
+
+ static int mDumpFileNum;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_BASE_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderDsp.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderDsp.h
new file mode 100644
index 0000000..cde2e3e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderDsp.h
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_DSP_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_DSP_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+#include "AudioDspType.h"
+
+struct aurisys_dsp_config_t;
+struct aurisys_lib_manager_t;
+class AudioVolumeInterface;
+
+namespace android {
+
+class AudioALSACaptureDataProviderDsp : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderDsp();
+
+ static AudioALSACaptureDataProviderDsp *getInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+
+
+protected:
+ AudioALSACaptureDataProviderDsp();
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderDsp *mAudioALSACaptureDataProviderDsp;
+ struct mixer *mMixer;
+
+ int setAfeDspShareMem(bool condition);
+ int setDspRuntimeEn(bool condition);
+ status_t openDspHwPcm();
+ status_t closeDspHwPcm();
+ status_t openDspHwRefPcm();
+ status_t closeDspHwRefPcm();
+ struct pcm *mDspHwPcm;
+ struct pcm *mDspHwRefPcm;
+ /**
+ * pcm read thread
+ */
+ static void *readThread(void *arg);
+ pthread_t hReadThread;
+
+ uint32_t mCaptureDropSize;
+
+ struct timespec mNewtime, mOldtime; //for calculate latency
+ double timerec[3]; //0=>threadloop, 1=>kernel delay, 2=>process delay
+ void adjustSpike();
+
+ struct pcm_config mDsphwConfig;
+ struct pcm_config mDsphwRefConfig;
+
+ struct aurisys_lib_manager_t *mAurisysLibManager;
+ struct aurisys_dsp_config_t *mAurisysDspConfig;
+ String8 mDspRefTurnOnSequence;
+
+ /* Volume Controller */
+ AudioVolumeInterface *mAudioALSAVolumeController;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_DSP_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderEchoRef.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderEchoRef.h
new file mode 100644
index 0000000..2893129
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderEchoRef.h
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ECHOREF_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ECHOREF_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+namespace android {
+
+class AudioALSACaptureDataProviderEchoRef : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderEchoRef();
+
+ static AudioALSACaptureDataProviderEchoRef *getInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+
+protected:
+ AudioALSACaptureDataProviderEchoRef();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderEchoRef *mAudioALSACaptureDataProviderEchoRef;
+ struct mixer *mMixer;
+
+ /**
+ * pcm read thread
+ */
+ static void *readThread(void *arg);
+ pthread_t hReadThread;
+
+ struct timespec mNewtime, mOldtime; //for calculate latency
+ double timerec[3]; //0=>threadloop, 1=>kernel delay, 2=>process delay
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ECHOREF_H
\ No newline at end of file
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderEchoRefBTCVSD.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderEchoRefBTCVSD.h
new file mode 100644
index 0000000..e869c03
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderEchoRefBTCVSD.h
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ECHOREF__BTCVSD_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ECHOREF__BTCVSD_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+#include <AudioLock.h>
+#include <pthread.h>
+
+namespace android {
+
+class WCNChipController;
+
+class AudioALSACaptureDataProviderEchoRefBTCVSD : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderEchoRefBTCVSD();
+
+ static AudioALSACaptureDataProviderEchoRefBTCVSD *getInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+ /**
+ * PlaybackHandler use this API to provide echo ref data
+ */
+ status_t writeData(const char *echoRefData, uint32_t dataSize, struct timespec *timestamp);
+
+protected:
+ AudioALSACaptureDataProviderEchoRefBTCVSD();
+
+
+
+private:
+ /**
+ * For echo ref SW implementation
+ */
+ RingBuf mDataRingBuf;
+ AudioLock mDataBufLock;
+ struct timespec mCaptureStartTime;
+ struct timespec mEstimateTimeStamp;
+ uint32_t mTotalCaptureBufSize;
+
+ void initDataRingBuf(uint32_t size);
+ void deinitDataRingBuf();
+ status_t readData(char *buffer, uint32_t size);
+ void signalDataWaiting();
+ status_t GetCaptureTimeStampByStartTime(time_info_struct_t *Time_Info);
+ void updateStartTimeStamp(struct timespec *timeStamp);
+ void updateTotalCaptureBufSize(uint32_t captureSize);
+ void resetTimeStampInfo();
+ uint32_t compensateSilenceData(uint32_t msec, RingBuf *ringBuf);
+
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderEchoRefBTCVSD *mAudioALSACaptureDataProviderEchoRefBTCVSD;
+
+ WCNChipController *mWCNChipController;
+
+ /**
+ * pcm read thread
+ */
+ static void *readThread(void *arg);
+ pthread_t hReadThread;
+
+ struct timespec mNewtime, mOldtime; //for calculate latency
+ double timerec[3]; //0=>threadloop, 1=>kernel delay, 2=>process delay
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ECHOREF__BTCVSD_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderEchoRefBTSCO.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderEchoRefBTSCO.h
new file mode 100644
index 0000000..51ca125
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderEchoRefBTSCO.h
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ECHOREF__BTSCO_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ECHOREF__BTSCO_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+namespace android {
+
+class WCNChipController;
+
+class AudioALSACaptureDataProviderEchoRefBTSCO : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderEchoRefBTSCO();
+
+ static AudioALSACaptureDataProviderEchoRefBTSCO *getInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+
+
+protected:
+ AudioALSACaptureDataProviderEchoRefBTSCO();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderEchoRefBTSCO *mAudioALSACaptureDataProviderEchoRefBTSCO;
+
+ WCNChipController *mWCNChipController;
+
+ /**
+ * pcm read thread
+ */
+ static void *readThread(void *arg);
+ pthread_t hReadThread;
+
+ struct timespec mNewtime, mOldtime; //for calculate latency
+ double timerec[3]; //0=>threadloop, 1=>kernel delay, 2=>process delay
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ECHOREF__BTSCO_H
\ No newline at end of file
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderEchoRefExt.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderEchoRefExt.h
new file mode 100644
index 0000000..f7550d1
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderEchoRefExt.h
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ECHOREF_EXT_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ECHOREF_EXT_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+namespace android {
+class AudioSmartPaController;
+class AudioALSACaptureDataProviderEchoRefExt : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderEchoRefExt();
+
+ static AudioALSACaptureDataProviderEchoRefExt *getInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+
+protected:
+ AudioALSACaptureDataProviderEchoRefExt();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderEchoRefExt *mAudioALSACaptureDataProviderEchoRefExt;
+
+ struct mixer *mMixer;
+ AudioSmartPaController *mSmartPaController;
+
+ /**
+ * pcm read thread
+ */
+ static void *readThread(void *arg);
+ pthread_t hReadThread;
+
+ struct timespec mNewtime, mOldtime; //for calculate latency
+ double timerec[3]; //0=>threadloop, 1=>kernel delay, 2=>process delay
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ECHOREF_EXT_H
\ No newline at end of file
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderEchoRefUsb.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderEchoRefUsb.h
new file mode 100644
index 0000000..cde330e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderEchoRefUsb.h
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ECHOREF__USB_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ECHOREF__USB_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+#include "AudioALSAPlaybackHandlerUsb.h"
+
+#include <AudioLock.h>
+
+namespace android {
+class IAudioALSACaptureDataClient;
+class AudioALSACaptureDataProviderEchoRefUsb : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderEchoRefUsb();
+
+ static AudioALSACaptureDataProviderEchoRefUsb *getInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+ virtual void initEchoRefInfo(stream_attribute_t stream_attribute_source_usb);
+
+ /**
+ * PlaybackHandler use this API to provide echo ref data
+ */
+ status_t writeData(const char *echoRefData, uint32_t dataSize, struct timespec *timestamp);
+protected:
+ AudioALSACaptureDataProviderEchoRefUsb();
+
+
+
+private:
+
+ /**
+ * For echo ref SW implementation
+ */
+ RingBuf mDataRingBuf;
+ AudioLock mDataBufLock;
+ struct timespec mCaptureStartTime;
+ struct timespec mEstimateTimeStamp;
+ uint32_t mTotalCaptureBufSize;
+ AudioALSAPlaybackHandlerUsb *mPlaybackHandlerUsb;
+
+ void initDataRingBuf(uint32_t size);
+ void deinitDataRingBuf();
+ status_t readData(char *buffer, uint32_t size);
+ void signalDataWaiting();
+ status_t GetCaptureTimeStampByStartTime(time_info_struct_t *Time_Info);
+ void updateStartTimeStamp(struct timespec *timeStamp);
+ void updateTotalCaptureBufSize(uint32_t captureSize);
+ void resetTimeStampInfo();
+ uint32_t compensateSilenceData(uint32_t msec, RingBuf *ringBuf);
+
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderEchoRefUsb *mAudioALSACaptureDataProviderEchoRefUsb;
+
+
+ /**
+ * pcm read thread
+ */
+ static void *readThread(void *arg);
+ pthread_t hReadThread;
+
+ struct timespec mNewtime, mOldtime; //for calculate latency
+ double timerec[3]; //0=>threadloop, 1=>kernel delay, 2=>process delay
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_ECHOREF__BTCVSD_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderFMRadio.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderFMRadio.h
new file mode 100644
index 0000000..71d20c0
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderFMRadio.h
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_FM_FADIO_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_FM_FADIO_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+namespace android {
+
+class AudioALSACaptureDataProviderFMRadio : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderFMRadio();
+
+ static AudioALSACaptureDataProviderFMRadio *getInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+
+
+protected:
+ AudioALSACaptureDataProviderFMRadio();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderFMRadio *mAudioALSACaptureDataProviderFMRadio;
+
+
+ /**
+ * pcm read thread
+ */
+ static void *readThread(void *arg);
+ pthread_t hReadThread;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_FM_FADIO_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderModemDai.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderModemDai.h
new file mode 100644
index 0000000..2eba4f4
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderModemDai.h
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_MODEM_DAI_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_MODEM_DAI_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+namespace android {
+
+class AudioALSACaptureDataProviderModemDai : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderModemDai();
+
+ static AudioALSACaptureDataProviderModemDai *getInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+
+protected:
+ AudioALSACaptureDataProviderModemDai();
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderModemDai *mAudioALSACaptureDataProviderModemDai;
+
+ /**
+ * pcm read thread
+ */
+ static void *readThread(void *arg);
+ pthread_t hReadThread;
+
+ /*
+ * moddai interface control
+ */
+ static const uint32_t kModDaiReadBufferSize = 640;
+ static const uint32_t kModDaiReadPeriodSize = 160;
+ static const uint32_t kModDaiReadBufferCount = 12;
+ static const uint32_t kModDaiChanel = 1;
+ static const uint32_t kModDaiSampleRate = 16000;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_MODEM_DAI_H
\ No newline at end of file
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderNormal.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderNormal.h
new file mode 100644
index 0000000..f9aa61d
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderNormal.h
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_NORMAL_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_NORMAL_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+namespace android {
+
+class AudioALSACaptureDataProviderNormal : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderNormal();
+
+ static AudioALSACaptureDataProviderNormal *getInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+
+
+protected:
+ AudioALSACaptureDataProviderNormal();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderNormal *mAudioALSACaptureDataProviderNormal;
+ struct mixer *mMixer;
+
+ /**
+ * pcm read thread
+ */
+ static void *readThread(void *arg);
+ pthread_t hReadThread;
+
+ uint32_t mCaptureDropSize;
+
+ struct timespec mNewtime, mOldtime; //for calculate latency
+ double timerec[3]; //0=>threadloop, 1=>kernel delay, 2=>process delay
+ void adjustSpike();
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_NORMAL_H
\ No newline at end of file
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderTDM.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderTDM.h
new file mode 100644
index 0000000..bd81e33
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderTDM.h
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_TDM_RECORD_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_TDM_RECORD_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+namespace android {
+
+class AudioALSACaptureDataProviderTDM : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderTDM();
+
+ static AudioALSACaptureDataProviderTDM *getInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+
+
+protected:
+ AudioALSACaptureDataProviderTDM();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderTDM *mAudioALSACaptureDataProviderTDM;
+
+
+ /**
+ * pcm read thread
+ */
+ static void *readThread(void *arg);
+ pthread_t hReadThread;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_TDM_RECORD_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderUsb.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderUsb.h
new file mode 100644
index 0000000..b1eba1f
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderUsb.h
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_USB_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_USB_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+extern "C" {
+ //#include <tinyalsa/asoundlib.h>
+#include "alsa_device_profile.h"
+#include "alsa_device_proxy.h"
+#include "alsa_logging.h"
+#include <audio_utils/channels.h>
+}
+namespace android {
+class IAudioALSACaptureDataClient;
+
+class AudioALSACaptureDataProviderUsb : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderUsb();
+
+ static AudioALSACaptureDataProviderUsb *getInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+
+ virtual status_t open();
+ virtual status_t close();
+ virtual void initUsbInfo(stream_attribute_t stream_attribute_source_usb, alsa_device_proxy *proxy, size_t buffer_size, bool enable);
+ virtual bool isNeedEchoRefData();
+
+protected:
+ AudioALSACaptureDataProviderUsb();
+
+ status_t updateStartTimeStamp(struct timespec timeStamp);
+
+ status_t updateCaptureTimeStampByStartTime(uint32_t bufferSize);
+
+ struct timespec mCaptureStartTime;
+
+ struct timespec mEstimatedBufferTimeStamp;
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderUsb *mAudioALSACaptureDataProviderUsb;
+
+
+ /**
+ * pcm read thread
+ */
+ static void *readThread(void *arg);
+ pthread_t hReadThread;
+
+ struct timespec mNewtime, mOldtime; //for calculate latency
+ double timerec[3]; //0=>threadloop, 1=>kernel delay, 2=>process delay
+
+};
+
+}
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_NORMAL_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderVOW.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderVOW.h
new file mode 100644
index 0000000..7efdb63
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderVOW.h
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_VOW_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_VOW_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+#include <linux/vow.h>
+
+namespace android {
+
+class AudioALSACaptureDataProviderVOW : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderVOW();
+
+ static AudioALSACaptureDataProviderVOW *getInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+
+
+protected:
+ AudioALSACaptureDataProviderVOW();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderVOW *mAudioALSACaptureDataProviderVOW;
+
+
+ /**
+ * pcm read thread
+ */
+ static void *readThread(void *arg);
+ pthread_t hReadThread;
+
+ int mFd;
+ vow_model_info_t vow_info_buf;
+ void WriteVOWPcmData(void);
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_VOW_H
\ No newline at end of file
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderVoice.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderVoice.h
new file mode 100644
index 0000000..14b6588
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderVoice.h
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_VOICE_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_VOICE_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+namespace android {
+
+class AudioALSACaptureDataProviderVoice : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderVoice();
+
+ static AudioALSACaptureDataProviderVoice *getInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+ /**
+ * provide modem record data to capture data provider
+ */
+ status_t provideModemRecordDataToProvider(RingBuf modem_record_buf);
+
+
+protected:
+ AudioALSACaptureDataProviderVoice();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderVoice *mAudioALSACaptureDataProviderVoice;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_VOICE_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderVoiceDL.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderVoiceDL.h
new file mode 100644
index 0000000..d0fc5a8
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderVoiceDL.h
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_VOICE_DL_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_VOICE_DL_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+namespace android {
+
+class AudioALSACaptureDataProviderVoiceDL : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderVoiceDL();
+
+ static AudioALSACaptureDataProviderVoiceDL *getInstance();
+
+ static bool hasInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+ /**
+ * provide modem record data to capture data provider
+ */
+ status_t provideModemRecordDataToProvider(RingBuf modem_record_buf);
+
+
+protected:
+ AudioALSACaptureDataProviderVoiceDL();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderVoiceDL *mAudioALSACaptureDataProviderVoiceDL;
+
+ /**
+ * Period buffer related
+ */
+ RingBuf mRawDataRingBuf;
+ uint32_t mPeriodBufferSize;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_VOICE_DL_H
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderVoiceMix.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderVoiceMix.h
new file mode 100644
index 0000000..dce3b3d
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderVoiceMix.h
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_VOICE_MIX_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_VOICE_MIX_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+
+namespace android {
+
+class AudioALSACaptureDataProviderVoiceMix : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderVoiceMix();
+
+ static AudioALSACaptureDataProviderVoiceMix *getInstance();
+
+ static bool hasInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+ /**
+ * provide modem record data to capture data provider
+ */
+ status_t provideModemRecordDataToProvider(RingBuf modem_record_buf);
+
+
+protected:
+ AudioALSACaptureDataProviderVoiceMix();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderVoiceMix *mAudioALSACaptureDataProviderVoiceMix;
+
+ /**
+ * Period buffer related
+ */
+ RingBuf mRawDataRingBuf;
+ uint32_t mPeriodBufferSize;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_VOICE_MIX_H
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderVoiceUL.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderVoiceUL.h
new file mode 100644
index 0000000..a6520f1
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureDataProviderVoiceUL.h
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_VOICE_UL_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_VOICE_UL_H
+
+#include "AudioALSACaptureDataProviderBase.h"
+namespace android {
+class AudioALSACaptureDataProviderVoiceUL : public AudioALSACaptureDataProviderBase {
+public:
+ virtual ~AudioALSACaptureDataProviderVoiceUL();
+
+ static AudioALSACaptureDataProviderVoiceUL *getInstance();
+
+ static bool hasInstance();
+
+ /**
+ * open/close pcm interface when 1st attach & the last detach
+ */
+ status_t open();
+ status_t close();
+
+ /**
+ * provide modem record data to capture data provider
+ */
+ status_t provideModemRecordDataToProvider(RingBuf modem_record_buf);
+
+
+protected:
+ AudioALSACaptureDataProviderVoiceUL();
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACaptureDataProviderVoiceUL *mAudioALSACaptureDataProviderVoiceUL;
+
+ /**
+ * Period buffer related
+ */
+ RingBuf mRawDataRingBuf;
+ uint32_t mPeriodBufferSize;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_DATA_PROVIDER_VOICE_UL_H
\ No newline at end of file
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerAAudio.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerAAudio.h
new file mode 100644
index 0000000..b6e0c38
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerAAudio.h
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_AAUDIO_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_AAUDIO_H
+
+#include "AudioALSACaptureHandlerBase.h"
+
+namespace android {
+class AudioALSACaptureHandlerAAudio : public AudioALSACaptureHandlerBase {
+public:
+ AudioALSACaptureHandlerAAudio(stream_attribute_t *stream_attribute_target);
+ virtual ~AudioALSACaptureHandlerAAudio();
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t input_device);
+
+
+ /**
+ * read data from audio hardware
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes);
+
+ /**
+ * AAudio MMAP
+ */
+ class AudioALSACaptureDataProviderAAudio *mDataProvider;
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t createMmapBuffer(int32_t min_size_frames,
+ struct audio_mmap_buffer_info *info);
+ virtual status_t getMmapPosition(struct audio_mmap_position *position);
+
+protected:
+ /**
+ * init audio hardware
+ */
+ virtual status_t init();
+
+
+
+private:
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_AAUDIO_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerAEC.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerAEC.h
new file mode 100644
index 0000000..c7d3aeb
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerAEC.h
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_AEC_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_AEC_H
+
+#include "AudioALSACaptureHandlerBase.h"
+
+namespace android {
+class AudioALSACaptureHandlerAEC : public AudioALSACaptureHandlerBase {
+public:
+ AudioALSACaptureHandlerAEC(stream_attribute_t *stream_attribute_target);
+ virtual ~AudioALSACaptureHandlerAEC();
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t input_device);
+
+
+ /**
+ * read data from audio hardware
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes);
+
+
+ /**
+ * Update BesRecord Parameters
+ */
+ virtual status_t UpdateBesRecParam();
+
+protected:
+ /**
+ * init audio hardware
+ */
+ virtual status_t init();
+
+
+
+private:
+
+ stream_attribute_t mStreamAttributeTargetEchoRef; // to stream in EchoRef
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_AEC_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerANC.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerANC.h
new file mode 100644
index 0000000..84f4517
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerANC.h
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_ANC_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_ANC_H
+
+#include "AudioALSACaptureHandlerBase.h"
+
+namespace android {
+
+class AudioALSACaptureHandlerANC : public AudioALSACaptureHandlerBase {
+public:
+ AudioALSACaptureHandlerANC(stream_attribute_t *stream_attribute_target);
+ virtual ~AudioALSACaptureHandlerANC();
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t input_device);
+
+
+ /**
+ * read data from audio hardware
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes);
+
+
+
+protected:
+ /**
+ * init audio hardware
+ */
+ virtual status_t init();
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_ANC_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerBT.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerBT.h
new file mode 100644
index 0000000..a869676
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerBT.h
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_BT_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_BT_H
+
+#include "AudioALSACaptureHandlerBase.h"
+
+namespace android {
+
+// BT SCO (Synchronous Connection Oriented link)
+class AudioALSACaptureHandlerBT : public AudioALSACaptureHandlerBase {
+public:
+ AudioALSACaptureHandlerBT(stream_attribute_t *stream_attribute_target);
+ virtual ~AudioALSACaptureHandlerBT();
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t input_device);
+
+
+ /**
+ * read data from audio hardware
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes);
+
+
+
+protected:
+ /**
+ * init audio hardware
+ */
+ virtual status_t init();
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_BT_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerBase.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerBase.h
new file mode 100644
index 0000000..750cbf8
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerBase.h
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_BASE_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_BASE_H
+
+#include "AudioType.h"
+
+namespace android {
+
+class AudioALSADataProcessor;
+
+class AudioALSAHardwareResourceManager;
+class IAudioALSACaptureDataClient;
+
+class AudioALSACaptureHandlerBase {
+public:
+ AudioALSACaptureHandlerBase(stream_attribute_t *stream_attribute_target);
+ virtual ~AudioALSACaptureHandlerBase();
+
+
+ /**
+ * set handler index
+ */
+ inline void setIdentity(const uint32_t identity) { mIdentity = identity; }
+ inline uint32_t getIdentity() const { return mIdentity; }
+
+ /**
+ * get raw frame count from hardware
+ */
+ int64_t getRawStartFrameCount();
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open() = 0;
+ virtual status_t close() = 0;
+ virtual status_t routing(const audio_devices_t input_device) = 0;
+
+
+ /**
+ * read data from audio hardware
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes) = 0;
+
+ /**
+ * Update BesRecord Parameters
+ */
+ virtual status_t UpdateBesRecParam();
+
+ /**
+ * Query if the capture handler can run in Call Mode
+ */
+ virtual bool isSupportConcurrencyInCall();
+
+ capture_handler_t getCaptureHandlerType();
+
+ virtual status_t setLowLatencyMode(bool mode, size_t kernel_buffer_size, size_t reduce_size, bool bforce = false);
+
+ int getCapturePosition(int64_t *frames, int64_t *time);
+
+ bool getStreamInReopen();
+ void setStreamInReopen(bool state);
+
+
+ /**
+ * AAudio MMAP
+ */
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t createMmapBuffer(int32_t min_size_frames,
+ struct audio_mmap_buffer_info *info);
+ virtual status_t getMmapPosition(struct audio_mmap_position *position);
+
+
+protected:
+ /**
+ * init audio hardware
+ */
+ virtual status_t init();
+
+ AudioALSAHardwareResourceManager *mHardwareResourceManager;
+ IAudioALSACaptureDataClient *mCaptureDataClient;
+
+ stream_attribute_t *mStreamAttributeTarget; // to stream in
+ bool mSupportConcurrencyInCall;
+
+ capture_handler_t mCaptureHandlerType;
+
+private:
+ AudioALSADataProcessor *mDataProcessor;
+
+ uint32_t mIdentity; // key for mCaptureHandlerVector
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_BASE_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerDsp.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerDsp.h
new file mode 100644
index 0000000..2c5f074
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerDsp.h
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_DSP_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_DSP_H
+
+#include "AudioALSACaptureHandlerBase.h"
+
+namespace android {
+class AudioALSACaptureHandlerDsp : public AudioALSACaptureHandlerBase {
+public:
+ AudioALSACaptureHandlerDsp(stream_attribute_t *stream_attribute_target);
+ virtual ~AudioALSACaptureHandlerDsp();
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t input_device);
+
+
+ /**
+ * read data from audio hardware
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes);
+
+protected:
+ /**
+ * init audio hardware
+ */
+ virtual status_t init();
+
+
+
+private:
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_DSP_H
\ No newline at end of file
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerFMRadio.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerFMRadio.h
new file mode 100644
index 0000000..4085e92
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerFMRadio.h
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_FM_RADIO_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_FM_RADIO_H
+
+#include "AudioALSACaptureHandlerBase.h"
+
+namespace android {
+
+class AudioALSACaptureHandlerFMRadio : public AudioALSACaptureHandlerBase {
+public:
+ AudioALSACaptureHandlerFMRadio(stream_attribute_t *stream_attribute_target);
+ virtual ~AudioALSACaptureHandlerFMRadio();
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t input_device);
+
+
+ /**
+ * read data from audio hardware
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes);
+
+
+
+protected:
+ /**
+ * init audio hardware
+ */
+ virtual status_t init();
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_FM_RADIO_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerModemDai.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerModemDai.h
new file mode 100644
index 0000000..b6af1af
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerModemDai.h
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_MODEM_DAI_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_MODEM_DAI_H
+
+#include "AudioALSACaptureHandlerBase.h"
+
+namespace android {
+
+class AudioALSACaptureHandlerModemDai : public AudioALSACaptureHandlerBase {
+public:
+ AudioALSACaptureHandlerModemDai(stream_attribute_t *stream_attribute_target);
+ virtual ~AudioALSACaptureHandlerModemDai();
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t input_device);
+
+
+ /**
+ * read data from audio hardware
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes);
+
+protected:
+ /**
+ * init audio hardware
+ */
+ virtual status_t init();
+private:
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_MODEM_DAI_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerNormal.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerNormal.h
new file mode 100644
index 0000000..c296ad0
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerNormal.h
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_NORMAL_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_NORMAL_H
+
+#include "AudioALSACaptureHandlerBase.h"
+
+namespace android {
+class AudioALSACaptureHandlerNormal : public AudioALSACaptureHandlerBase {
+public:
+ AudioALSACaptureHandlerNormal(stream_attribute_t *stream_attribute_target);
+ virtual ~AudioALSACaptureHandlerNormal();
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t input_device);
+
+
+ /**
+ * read data from audio hardware
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes);
+
+protected:
+ /**
+ * init audio hardware
+ */
+ virtual status_t init();
+
+
+
+private:
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_NORMAL_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerSyncIO.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerSyncIO.h
new file mode 100644
index 0000000..3bfe7de
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerSyncIO.h
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_SYNCIO_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_SYNCIO_H
+
+#include "AudioALSACaptureHandlerBase.h"
+
+namespace android {
+class AudioALSACaptureHandlerSyncIO : public AudioALSACaptureHandlerBase {
+public:
+ AudioALSACaptureHandlerSyncIO(stream_attribute_t *stream_attribute_target);
+ virtual ~AudioALSACaptureHandlerSyncIO();
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t input_device);
+
+
+ /**
+ * read data from audio hardware
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes);
+
+protected:
+ /**
+ * init audio hardware
+ */
+ virtual status_t init();
+
+
+
+private:
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_SYNCIO_H
\ No newline at end of file
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerTDM.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerTDM.h
new file mode 100644
index 0000000..f679463
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerTDM.h
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_TDM_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_TDM_H
+
+#include "AudioALSACaptureHandlerBase.h"
+
+namespace android {
+class AudioALSACaptureHandlerTDM : public AudioALSACaptureHandlerBase {
+public:
+ AudioALSACaptureHandlerTDM(stream_attribute_t *stream_attribute_target);
+ virtual ~AudioALSACaptureHandlerTDM();
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t input_device);
+
+
+ /**
+ * read data from audio hardware
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes);
+
+protected:
+ /**
+ * init audio hardware
+ */
+ virtual status_t init();
+
+
+
+private:
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_NORMAL_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerVOW.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerVOW.h
new file mode 100644
index 0000000..6f1e49a
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerVOW.h
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_VOW_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_VOW_H
+
+#include "AudioALSACaptureHandlerBase.h"
+
+namespace android {
+
+class AudioALSACaptureHandlerVOW : public AudioALSACaptureHandlerBase {
+public:
+ AudioALSACaptureHandlerVOW(stream_attribute_t *stream_attribute_target);
+ virtual ~AudioALSACaptureHandlerVOW();
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t input_device);
+
+
+ /**
+ * read data from audio hardware
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes);
+
+
+
+protected:
+ /**
+ * init audio hardware
+ */
+ virtual status_t init();
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_VOW_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerVoice.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerVoice.h
new file mode 100644
index 0000000..ec5c36a
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACaptureHandlerVoice.h
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_VOICE_H
+#define ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_VOICE_H
+
+#include "AudioALSACaptureHandlerBase.h"
+
+namespace android {
+
+class AudioALSACaptureHandlerVoice : public AudioALSACaptureHandlerBase {
+public:
+ AudioALSACaptureHandlerVoice(stream_attribute_t *stream_attribute_target);
+ virtual ~AudioALSACaptureHandlerVoice();
+
+ /**
+ * open/close speech driver
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t input_device);
+
+
+ /**
+ * read data from speech driver
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes);
+
+
+protected:
+ /**
+ * init audio speech driver
+ */
+ virtual status_t init();
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CAPTURE_HANDLER_VOICE_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceBase.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceBase.h
new file mode 100644
index 0000000..dec8718
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceBase.h
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CODEC_DEVICE_BASE_H
+#define ANDROID_AUDIO_ALSA_CODEC_DEVICE_BASE_H
+
+#include <tinyalsa/asoundlib.h>
+
+#include "AudioType.h"
+
+namespace android {
+
+class DeviceCtlDescriptor;
+class AudioALSACodecDeviceBase {
+public:
+ virtual ~AudioALSACodecDeviceBase();
+
+ static AudioALSACodecDeviceBase *createCodecOutputDevices();
+
+
+ /**
+ * open/close codec driver
+ */
+ virtual status_t open() = 0;
+ virtual status_t close() = 0;
+
+
+
+protected:
+ AudioALSACodecDeviceBase();
+
+
+ /**
+ * mixer controller
+ */
+ static struct mixer *mMixer;
+
+
+ /**
+ * open count, used to decide open/close codec driver or not
+ */
+ uint32_t mClientCount;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CODEC_DEVICE_BASE_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutEarphonePMIC.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutEarphonePMIC.h
new file mode 100644
index 0000000..1ae025e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutEarphonePMIC.h
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_EARPHONE_PMIC_H
+#define ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_EARPHONE_PMIC_H
+
+#include "AudioType.h"
+#include "AudioALSACodecDeviceBase.h"
+#include "AudioCustParamClient.h"
+
+
+namespace android {
+
+class AudioALSACodecDeviceOutEarphonePMIC : public AudioALSACodecDeviceBase {
+public:
+ virtual ~AudioALSACodecDeviceOutEarphonePMIC();
+
+ static AudioALSACodecDeviceOutEarphonePMIC *getInstance();
+
+
+ /**
+ * open/close codec driver
+ */
+ status_t open();
+ status_t close();
+ status_t DeviceDoDcCalibrate();
+
+
+protected:
+ AudioALSACodecDeviceOutEarphonePMIC();
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACodecDeviceOutEarphonePMIC *mAudioALSACodecDeviceOutEarphonePMIC;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_EARPHONE_PMIC_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutExtSpeakerAmp.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutExtSpeakerAmp.h
new file mode 100644
index 0000000..0bdce14
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutExtSpeakerAmp.h
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_EXT_SPEAKER_AMP_H
+#define ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_EXT_SPEAKER_AMP_H
+
+#include "AudioType.h"
+
+#include "AudioALSACodecDeviceBase.h"
+
+
+namespace android {
+
+class AudioALSACodecDeviceOutExtSpeakerAmp : public AudioALSACodecDeviceBase {
+public:
+ virtual ~AudioALSACodecDeviceOutExtSpeakerAmp();
+
+ static AudioALSACodecDeviceOutExtSpeakerAmp *getInstance();
+
+
+ /**
+ * open/close codec driver
+ */
+ status_t open();
+ status_t close();
+
+
+
+protected:
+ AudioALSACodecDeviceOutExtSpeakerAmp();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACodecDeviceOutExtSpeakerAmp *mAudioALSACodecDeviceOutExtSpeakerAmp;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_EXT_SPEAKER_AMP_H
\ No newline at end of file
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutHeadphone.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutHeadphone.h
new file mode 100644
index 0000000..dac404a
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutHeadphone.h
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_HEADPHONE_H
+#define ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_HEADPHONE_H
+
+#include "AudioType.h"
+#include "AudioALSACodecDeviceBase.h"
+#include "AudioCustParam.h"
+#include "AudioALSADeviceParser.h"
+#include <tinyalsa/asoundlib.h>
+
+namespace android {
+
+class AudioALSACodecDeviceOutHeadphone : public AudioALSACodecDeviceBase {
+public:
+ virtual ~AudioALSACodecDeviceOutHeadphone();
+
+ static AudioALSACodecDeviceOutHeadphone *getInstance();
+
+ int mCount;
+ int hifi_enable;
+ struct pcm_config mHpPcmConfig;
+ struct pcm *mHpPcmOut;
+
+ /**
+ * open/close codec driver
+ */
+ status_t open();
+ status_t open(int SampleRate);
+ status_t close();
+ status_t setHeadphoneState(int enable);
+ status_t getHeadphoneState();
+
+protected:
+ AudioALSACodecDeviceOutHeadphone();
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACodecDeviceOutHeadphone *mAudioALSACodecDeviceOutHeadphone;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_HEADPHONE_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutReceiverPMIC.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutReceiverPMIC.h
new file mode 100644
index 0000000..887347c
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutReceiverPMIC.h
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_RECEIVER_PMIC_H
+#define ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_RECEIVER_PMIC_H
+
+#include "AudioType.h"
+
+#include "AudioALSACodecDeviceBase.h"
+
+
+namespace android {
+
+class AudioALSACodecDeviceOutReceiverPMIC : public AudioALSACodecDeviceBase {
+public:
+ virtual ~AudioALSACodecDeviceOutReceiverPMIC();
+
+ static AudioALSACodecDeviceOutReceiverPMIC *getInstance();
+
+
+ /**
+ * open/close codec driver
+ */
+ status_t open();
+ status_t close();
+
+
+
+protected:
+ AudioALSACodecDeviceOutReceiverPMIC();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACodecDeviceOutReceiverPMIC *mAudioALSACodecDeviceOutReceiverPMIC;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_RECEIVER_PMIC_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutReceiverSpeakerSwitch.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutReceiverSpeakerSwitch.h
new file mode 100644
index 0000000..74fa359
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutReceiverSpeakerSwitch.h
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_RECEIVER_SPEAKER_SWITCH_H
+#define ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_RECEIVER_SPEAKER_SWITCH_H
+
+#include "AudioType.h"
+
+#include "AudioALSACodecDeviceBase.h"
+
+
+namespace android {
+
+class AudioALSACodecDeviceOutReceiverSpeakerSwitch : public AudioALSACodecDeviceBase {
+public:
+ virtual ~AudioALSACodecDeviceOutReceiverSpeakerSwitch();
+
+ static AudioALSACodecDeviceOutReceiverSpeakerSwitch *getInstance();
+
+
+ /**
+ * open/close codec driver
+ */
+ status_t open();
+ status_t close();
+
+
+
+protected:
+ AudioALSACodecDeviceOutReceiverSpeakerSwitch();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACodecDeviceOutReceiverSpeakerSwitch *mAudioALSACodecDeviceOutReceiverSpeakerSwitch;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_EXT_SPEAKER_AMP_H
\ No newline at end of file
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutSpeakerEarphonePMIC.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutSpeakerEarphonePMIC.h
new file mode 100644
index 0000000..51efd28
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutSpeakerEarphonePMIC.h
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_SPEAKER_EARPHONE_PMIC_H
+#define ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_SPEAKER_EARPHONE_PMIC_H
+
+#include "AudioType.h"
+
+#include "AudioALSACodecDeviceBase.h"
+
+
+namespace android {
+
+class AudioALSACodecDeviceOutSpeakerEarphonePMIC : public AudioALSACodecDeviceBase {
+public:
+ virtual ~AudioALSACodecDeviceOutSpeakerEarphonePMIC();
+
+ static AudioALSACodecDeviceOutSpeakerEarphonePMIC *getInstance();
+
+
+ /**
+ * open/close codec driver
+ */
+ status_t open();
+ status_t close();
+ status_t DeviceDoDcCalibrate();
+
+
+protected:
+ AudioALSACodecDeviceOutSpeakerEarphonePMIC();
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACodecDeviceOutSpeakerEarphonePMIC *mAudioALSACodecDeviceOutSpeakerEarphonePMIC;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_SPEAKER_EARPHONE_PMIC_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutSpeakerNXP.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutSpeakerNXP.h
new file mode 100644
index 0000000..1b3663c
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutSpeakerNXP.h
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_SPEAKER_NXP_H
+#define ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_SPEAKER_NXP_H
+
+#include "AudioType.h"
+
+#include "AudioALSACodecDeviceBase.h"
+#include "SpeechType.h"
+#include "SpeechDriverFactory.h"
+
+
+namespace android {
+
+class AudioALSACodecDeviceOutSpeakerNXP : public AudioALSACodecDeviceBase {
+public:
+ virtual ~AudioALSACodecDeviceOutSpeakerNXP();
+
+ static AudioALSACodecDeviceOutSpeakerNXP *getInstance();
+
+
+ /**
+ * open/close codec driver
+ */
+ status_t open();
+ status_t open(const uint32_t SampleRate);
+ status_t close();
+
+
+
+protected:
+ AudioALSACodecDeviceOutSpeakerNXP();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACodecDeviceOutSpeakerNXP *mAudioALSACodecDeviceOutSpeakerNXP;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_SPEAKER_NXP_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutSpeakerPMIC.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutSpeakerPMIC.h
new file mode 100644
index 0000000..3927cc3
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSACodecDeviceOutSpeakerPMIC.h
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_SPEAKER_PMIC_H
+#define ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_SPEAKER_PMIC_H
+
+#include "AudioType.h"
+
+#include "AudioALSACodecDeviceBase.h"
+
+
+namespace android {
+
+class AudioALSACodecDeviceOutSpeakerPMIC : public AudioALSACodecDeviceBase {
+public:
+ virtual ~AudioALSACodecDeviceOutSpeakerPMIC();
+
+ static AudioALSACodecDeviceOutSpeakerPMIC *getInstance();
+
+
+ /**
+ * open/close codec driver
+ */
+ status_t open();
+ status_t close();
+
+
+
+protected:
+ AudioALSACodecDeviceOutSpeakerPMIC();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSACodecDeviceOutSpeakerPMIC *mAudioALSACodecDeviceOutSpeakerPMIC;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_CODEC_DEVICE_OUT_SPEAKER_PMIC_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSADataProcessor.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSADataProcessor.h
new file mode 100644
index 0000000..ec9550f
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSADataProcessor.h
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_DATA_PROCESSOR_H
+#define ANDROID_AUDIO_ALSA_DATA_PROCESSOR_H
+
+#include "AudioType.h"
+
+namespace android {
+
+class AudioALSADataProcessor {
+public:
+ virtual ~AudioALSADataProcessor();
+
+ static AudioALSADataProcessor *getInstance();
+
+
+
+protected:
+ AudioALSADataProcessor();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSADataProcessor *mAudioALSADataProcessor;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_DATA_PROCESSOR_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSADeviceConfigManager.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSADeviceConfigManager.h
new file mode 100644
index 0000000..f445854
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSADeviceConfigManager.h
@@ -0,0 +1,328 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_MTK_DEVICE_CONFIG_MANAGER_H
+#define ANDROID_AUDIO_MTK_DEVICE_CONFIG_MANAGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Mutex.h>
+#include <utils/String8.h>
+#include "AudioType.h"
+#include <utils/Log.h>
+#include <cutils/properties.h>
+#include <sys/types.h>
+#include <cutils/config_utils.h>
+#include <cutils/misc.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <tinyxml.h>
+
+#define AUDIO_DEVICE_TURNON "turnon"
+#define AUDIO_DEVICE_TURNOFF "turnoff"
+#define AUDIO_DEVICE_SETTING "setting"
+
+#define AUDIO_DEVICE_HEADPHONE "headphone_output"
+#if defined(MTK_HIFIAUDIO_SUPPORT)
+#define AUDIO_DEVICE_HIFI_DAC "hifi_dac_output"
+#endif
+#define AUDIO_DEVICE_SPEAKER "speaker_output"
+#define AUDIO_DEVICE_2IN1_SPEAKER "two_in_one_speaker_output"
+#define AUDIO_DEVICE_RECEIVER "receiver_output"
+#define AUDIO_DEVICE_EARPHONE_SPEAKER "headphoneSpeaker_output"
+#define AUDIO_DEVICE_EXT_SPEAKER "ext_speaker_output"
+
+#define AUDIO_DEVICE_MAXIM_SPEAKER "maxim_speaker_output"
+#define AUDIO_DEVICE_MAXIM_EARPHONE_SPEAKER "maxim_headphoneSpeaker_output"
+
+#define AUDIO_LOOPBACK_USE_SINGLE_MIC_L_CH "loopback_use_single_mic_l_ch"
+#define AUDIO_LOOPBACK_USE_SINGLE_MIC_R_CH "loopback_use_single_mic_r_ch"
+
+#define AUDIO_DEVICE_BUILTIN_MIC_MIC1 "builtin_Mic_Mic1"
+#define AUDIO_DEVICE_BUILTIN_MIC_MIC2 "builtin_Mic_Mic2"
+#define AUDIO_DEVICE_BUILTIN_MIC_MIC3 "builtin_Mic_Mic3"
+#define AUDIO_DEVICE_BUILTIN_MIC_MIC4 "builtin_Mic_Mic4"
+#define AUDIO_DEVICE_BUILTIN_MIC_MIC5 "builtin_Mic_Mic5"
+#define AUDIO_DEVICE_BUILTIN_MIC_VOW_MIC "builtin_Mic_Vow_Mic"
+#define AUDIO_DEVICE_BUILTIN_MIC_VOW_DUAL_MIC "builtin_Mic_Vow_DualMic"
+
+#define AUDIO_DEVICE_BUILTIN_MIC_MIC1_INVERSE "builtin_Mic_Mic1_Inverse"
+#define AUDIO_DEVICE_BUILTIN_MIC_MIC2_INVERSE "builtin_Mic_Mic2_Inverse"
+#define AUDIO_DEVICE_BUILTIN_MIC_MIC3_INVERSE "builtin_Mic_Mic3_Inverse"
+
+
+#define AUDIO_DEVICE_BUILTIN_SINGLE_MIC "builtin_Mic_SingleMic"
+#define AUDIO_DEVICE_BUILTIN_DUAL_MIC "builtin_Mic_DualMic"
+#define AUDIO_DEVICE_BUILTIN_TRIPLE_MIC "builtin_Mic_TripleMic"
+#define AUDIO_DEVICE_BUILTIN_BACK_MIC "builtin_Mic_BackMic"
+#define AUDIO_DEVICE_BUILTIN_BACK_MIC_INVERSE "builtin_Mic_BackMic_Inverse"
+
+#define AUDIO_DEVICE_HEADSET_MIC "headset_mic_input"
+#define AUDIO_DEVICE_SIDETONE "sidetone_switch"
+#define AUDIO_DEVICE_HEADSET_VOW_MIC "headset_vow_input"
+
+
+#define AUDIOMIC1_TYPE_ACCMODE "Mic1TypeACCMode"
+#define AUDIOMIC1_TYPE_DCCMODE "Mic1TypeDCCMode"
+#define AUDIOMIC1_TYPE_DMICMODE "Mic1TypeDMICMode"
+#define AUDIOMIC1_TYPE_DCCECMDIFFMODE "Mic1TypeDCCECMDIFFMode"
+#define AUDIOMIC1_TYPE_DCCECMSINGLEMODE "Mic1TypeDCCECMSINGLEMode"
+
+#define AUDIOMIC2_TYPE_ACCMODE "Mic2TypeACCMode"
+#define AUDIOMIC2_TYPE_DCCMODE "Mic2TypeDCCMode"
+#define AUDIOMIC2_TYPE_DMICMODE "Mic2TypeDMICMode"
+#define AUDIOMIC2_TYPE_DCCECMDIFFMODE "Mic2TypeDCCECMDIFFMode"
+#define AUDIOMIC2_TYPE_DCCECMSINGLEMODE "Mic2TypeDCCECMSINGLEMode"
+
+#define AUDIOMIC3_TYPE_ACCMODE "Mic3TypeACCMode"
+#define AUDIOMIC3_TYPE_DCCMODE "Mic3TypeDCCMode"
+#define AUDIOMIC3_TYPE_DMICMODE "Mic3TypeDMICMode"
+#define AUDIOMIC3_TYPE_DCCECMDIFFMODE "Mic3TypeDCCECMDIFFMode"
+#define AUDIOMIC3_TYPE_DCCECMSINGLEMODE "Mic3TypeDCCECMSINGLEMode"
+
+#define AUDIOMIC4_TYPE_ACCMODE "Mic4TypeACCMode"
+#define AUDIOMIC4_TYPE_DCCMODE "Mic4TypeDCCMode"
+#define AUDIOMIC4_TYPE_DMICMODE "Mic4TypeDMICMode"
+#define AUDIOMIC4_TYPE_DCCECMDIFFMODE "Mic4TypeDCCECMDIFFMode"
+#define AUDIOMIC4_TYPE_DCCECMSINGLEMODE "Mic4TypeDCCECMSINGLEMode"
+
+#define VOWMIC1_TYPE_ACCMODE "Mic1TypeVOWACCMode"
+#define VOWMIC1_TYPE_DCCMODE "Mic1TypeVOWDCCMode"
+#define VOWMIC1_TYPE_DMICMODE "Mic1TypeVOWDMICMode"
+#define VOWMIC1_TYPE_DMICLPMODE "Mic1TypeVOWDMICLPMode"
+#define VOWMIC1_TYPE_DCCECMDIFFMODE "Mic1TypeVOWDCCECMDIFFMode"
+#define VOWMIC1_TYPE_DCCECMSINGLEMODE "Mic1TypeVOWDCCECMSINGLEMode"
+
+#define VOWMIC2_TYPE_ACCMODE "Mic2TypeVOWACCMode"
+#define VOWMIC2_TYPE_DCCMODE "Mic2TypeVOWDCCMode"
+#define VOWMIC2_TYPE_DCCECMDIFFMODE "Mic2TypeVOWDCCECMDIFFMode"
+#define VOWMIC2_TYPE_DCCECMSINGLEMODE "Mic2TypeVOWDCCECMSINGLEMode"
+
+#define VOWMIC3_TYPE_ACCMODE "Mic3TypeVOWACCMode"
+#define VOWMIC3_TYPE_DCCMODE "Mic3TypeVOWDCCMode"
+#define VOWMIC3_TYPE_DMICMODE "Mic3TypeVOWDMICMode"
+#define VOWMIC3_TYPE_DMICLPMODE "Mic3TypeVOWDMICLPMode"
+#define VOWMIC3_TYPE_DCCECMDIFFMODE "Mic3TypeVOWDCCECMDIFFMode"
+#define VOWMIC3_TYPE_DCCECMSINGLEMODE "Mic3TypeVOWDCCECMSINGLEMode"
+
+#define AUDIO_MIC_INVERSE "Mic_Setting_Inverse"
+#define AUDIO_MIC_NOINVERSE "Mic_Setting_NoInverse"
+
+#if defined(MTK_AUDIO_KS)
+// playback
+#define AUDIO_CTL_PLAYBACK1_TO_ADDA_DL "PLAYBACK1_TO_ADDA_DL"
+#define AUDIO_CTL_PLAYBACK1_TO_I2S "PLAYBACK1_TO_"
+
+#define AUDIO_CTL_PLAYBACK2_TO_ADDA_DL "PLAYBACK2_TO_ADDA_DL"
+#define AUDIO_CTL_PLAYBACK2_TO_I2S "PLAYBACK2_TO_"
+
+#define AUDIO_CTL_PLAYBACK3_TO_ADDA_DL "PLAYBACK3_TO_ADDA_DL"
+#define AUDIO_CTL_PLAYBACK3_TO_I2S "PLAYBACK3_TO_"
+
+#define AUDIO_CTL_PLAYBACK4_TO_ADDA_DL "PLAYBACK4_TO_ADDA_DL"
+#define AUDIO_CTL_PLAYBACK4_TO_I2S "PLAYBACK4_TO_"
+
+#define AUDIO_CTL_PLAYBACK5_TO_ADDA_DL "PLAYBACK5_TO_ADDA_DL"
+#define AUDIO_CTL_PLAYBACK5_TO_I2S "PLAYBACK5_TO_"
+
+#define AUDIO_CTL_PLAYBACK6_TO_ADDA_DL "PLAYBACK6_TO_ADDA_DL"
+#define AUDIO_CTL_PLAYBACK6_TO_I2S "PLAYBACK6_TO_"
+
+#define AUDIO_CTL_PLAYBACK12_TO_ADDA_DL "PLAYBACK12_TO_ADDA_DL"
+#define AUDIO_CTL_PLAYBACK12_TO_I2S "PLAYBACK12_TO_"
+
+#define AUDIO_CTL_PLAYBACK1_TO_MD1_CH4 "PLAYBACK1_TO_MD1_CH4"
+#define AUDIO_CTL_PLAYBACK1_TO_MD2_CH4 "PLAYBACK1_TO_MD2_CH4"
+#define AUDIO_CTL_PLAYBACK2_TO_MD1 "PLAYBACK2_TO_MD1"
+#define AUDIO_CTL_PLAYBACK2_TO_MD2 "PLAYBACK2_TO_MD2"
+// capture
+#define AUDIO_CTL_ADDA_TO_CAPTURE1 "ADDA_TO_CAPTURE1"
+#define AUDIO_CTL_ADDA_TO_CAPTURE1_4CH "ADDA_TO_CAPTURE1_4CH"
+#define AUDIO_CTL_ADDA_TO_CAPTURE7 "ADDA_TO_CAPTURE7"
+#define AUDIO_CTL_DL_MEMIF_TO_CAPTURE2 "DL_MEMIF_TO_CAPTURE2"
+#define AUDIO_CTL_DL_MEMIF_TO_CAPTURE2_SPEAKER_HIFI3 "DL_MEMIF_TO_CAPTURE2_SPEAKER_HIFI3"
+#define AUDIO_CTL_DL_PLAYBACK_TO_CAPTURE2_NON_SPEAKER_HIFI3 "DL_PLAYBACK_TO_CAPTURE2_NON_SPEAKER_HIFI3"
+#define AUDIO_CTL_DL_MEMIF_TO_CAPTURE4 "DL_MEMIF_TO_CAPTURE4"
+#define AUDIO_CTL_DL_MEMIF_TO_CAPTURE4_SPEAKER_HIFI3 "DL_MEMIF_TO_CAPTURE4_SPEAKER_HIFI3"
+#define AUDIO_CTL_DL_MEMIF_TO_CAPTURE4_NON_SPEAKER_HIFI3 "DL_MEMIF_TO_CAPTURE4_NON_SPEAKER_HIFI3"
+#define AUDIO_CTL_I2S0_TO_CAPTURE2 "I2S0_TO_CAPTURE2"
+#define AUDIO_CTL_I2S2_TO_CAPTURE2 "I2S2_TO_CAPTURE2"
+#define AUDIO_CTL_MD1_TO_CAPTURE2 "MD1_TO_CAPTURE2"
+#define AUDIO_CTL_MD2_TO_CAPTURE2 "MD2_TO_CAPTURE2"
+#define AUDIO_CTL_CONNSYS_TO_CAPTURE3 "CONNSYS_TO_CAPTURE3"
+#define AUDIO_CTL_MD1_TO_CAPTURE_MONO_1 "MD1_TO_CAPTURE_MONO_1"
+#define AUDIO_CTL_MD2_TO_CAPTURE_MONO_1 "MD2_TO_CAPTURE_MONO_1"
+#define AUDIO_CTL_PLAYBACK1_TO_CAPTURE6 "PLAYBACK1_TO_CAPTURE6"
+#define AUDIO_CTL_PLAYBACK2_TO_CAPTURE6 "PLAYBACK2_TO_CAPTURE6"
+#define AUDIO_CTL_PLAYBACK12_TO_CAPTURE6 "PLAYBACK12_TO_CAPTURE6"
+#define AUDIO_CTL_PLAYBACK3_TO_CAPTURE6 "PLAYBACK3_TO_CAPTURE6"
+#define AUDIO_CTL_PLAYBACK4_TO_CAPTURE6 "PLAYBACK4_TO_CAPTURE6"
+#define AUDIO_CTL_PLAYBACK6_TO_CAPTURE6 "PLAYBACK6_TO_CAPTURE6"
+#define AUDIO_CTL_I2S_TO_CAPTURE4 "_TO_CAPTURE4"
+
+// hostless
+#define AUDIO_CTL_ADDA_UL_TO_ADDA_DL "ADDA_UL_TO_ADDA_DL"
+#define AUDIO_CTL_ADDA_UL_TO_I2S "ADDA_UL_TO_"
+
+#define AUDIO_CTL_CONNSYS_TO_ADDA_DL "CONNSYS_TO_ADDA_DL"
+#define AUDIO_CTL_CONNSYS_TO_I2S "CONNSYS_TO_"
+
+#define AUDIO_CTL_MRG_TO_ADDA_DL "MRG_TO_ADDA_DL"
+#define AUDIO_CTL_MRG_TO_I2S "MRG_TO_"
+
+#define AUDIO_CTL_MD1_TO_ADDA_DL "MD1_TO_ADDA_DL"
+#define AUDIO_CTL_MD1_TO_I2S "MD1_TO_"
+
+#define AUDIO_CTL_MD2_TO_ADDA_DL "MD2_TO_ADDA_DL"
+#define AUDIO_CTL_MD2_TO_I2S "MD2_TO_"
+
+// DSP DL
+#define AUDIO_CTL_PLAYBACK1_TO_DSP "PLAYBACK1_TO_DSPDL"
+#define AUDIO_CTL_PLAYBACK2_TO_DSP "PLAYBACK2_TO_DSPDL"
+#define AUDIO_CTL_PLAYBACK3_TO_DSP "PLAYBACK3_TO_DSPDL"
+#define AUDIO_CTL_PLAYBACK4_TO_DSP "PLAYBACK4_TO_DSPDL"
+#define AUDIO_CTL_PLAYBACK6_TO_DSP "PLAYBACK6_TO_DSPDL"
+#define AUDIO_CTL_PLAYBACK12_TO_DSP "PLAYBACK12_TO_DSPDL"
+
+
+#define AUDIO_CTL_ADDA_UL_TO_MD1 "ADDA_UL_TO_MD1"
+#define AUDIO_CTL_ADDA_UL_TO_MD2 "ADDA_UL_TO_MD2"
+#define AUDIO_CTL_HP_IMPEDANCE "HP_IMPEDANCE"
+#define AUDIO_CTL_SPK_INIT "SPK_INIT"
+#define AUDIO_CTL_MD1_ECHO_REF_I2S0_ON "MD1_ECHO_REF_I2S0_ON"
+#define AUDIO_CTL_MD1_ECHO_REF_I2S0_OFF "MD1_ECHO_REF_I2S0_OFF"
+#define AUDIO_CTL_MD1_ECHO_REF_I2S2_ON "MD1_ECHO_REF_I2S2_ON"
+#define AUDIO_CTL_MD1_ECHO_REF_I2S2_OFF "MD1_ECHO_REF_I2S2_OFF"
+#define AUDIO_CTL_MD2_ECHO_REF_I2S0_ON "MD2_ECHO_REF_I2S0_ON"
+#define AUDIO_CTL_MD2_ECHO_REF_I2S0_OFF "MD2_ECHO_REF_I2S0_OFF"
+#define AUDIO_CTL_MD2_ECHO_REF_I2S2_ON "MD2_ECHO_REF_I2S2_ON"
+#define AUDIO_CTL_MD2_ECHO_REF_I2S2_OFF "MD2_ECHO_REF_I2S2_OFF"
+#define AUDIO_CTL_VOW_BARGE_IN_ECHO "VOW_BARGE_IN_ECHO"
+#define AUDIO_CTL_VOW_BARGE_IN_ECHO_SPEAKER_HIFI3 "VOW_BARGE_IN_ECHO_SPEAKER_HIFI3"
+#define AUDIO_CTL_VOW_BARGE_IN_ECHO_DSP_SMARTPA "VOW_BARGE_IN_ECHO_DSP_SMARTPA"
+// usb call
+#define AUDIO_CTL_USB_ECHO_REF_DEBUG "USB_ECHO_REF_DEBUG"
+#define AUDIO_CTL_USB_CALL_DEBUG_LOOPBACK "USB_CALL_DEBUG_LOOPBACK"
+// i2s
+#define AUDIO_CTL_I2S0_HD_ON "I2S0_HD_ON"
+#define AUDIO_CTL_I2S0_HD_OFF "I2S0_HD_OFF"
+#define AUDIO_CTL_I2S1_HD_ON "I2S1_HD_ON"
+#define AUDIO_CTL_I2S1_HD_OFF "I2S1_HD_OFF"
+#define AUDIO_CTL_I2S2_HD_ON "I2S2_HD_ON"
+#define AUDIO_CTL_I2S2_HD_OFF "I2S2_HD_OFF"
+#define AUDIO_CTL_I2S3_HD_ON "I2S3_HD_ON"
+#define AUDIO_CTL_I2S3_HD_OFF "I2S3_HD_OFF"
+#define AUDIO_CTL_I2S5_HD_ON "I2S5_HD_ON"
+#define AUDIO_CTL_I2S5_HD_OFF "I2S5_HD_OFF"
+// device
+#define AUDIO_CTL_BUILT_IN_MIC "builtin_Mic"
+#define AUDIO_CTL_HEADSET_MIC "headset_mic_input"
+
+#define AUDIO_CTL_SINGLE_MIC "SingleMic"
+#define AUDIO_CTL_DUAL_MIC "DualMic"
+#define AUDIO_CTL_THREE_MIC "ThreeMic"
+#define AUDIO_CTL_MIC1 "Mic1"
+#define AUDIO_CTL_MIC2 "Mic2"
+#define AUDIO_CTL_MIC3 "Mic3"
+#define AUDIO_CTL_BACK_MIC "BackMic"
+#define AUDIO_CTL_BACK_MIC_3 "BackMic_3"
+
+#define AUDIO_CTL_MIC_INVERSE "Inverse"
+
+// reset
+#define AUDIO_CTL_RESET_DEVICE "reset_device_setting"
+#endif
+
+namespace android {
+
+class DeviceCtlDescriptor {
+public:
+ DeviceCtlDescriptor();
+ String8 mDevicename;
+ Vector<String8> mDeviceCltonVector;
+ Vector<String8> mDeviceCltoffVector;
+ Vector<String8> mDeviceCltsettingVector;
+ int DeviceStatusCounter;
+};
+
+class DeviceCtlControlSeq {
+public:
+ Vector<String8> mDeviceCltNameVector;
+ Vector<String8> mDeviceCltValueVector;
+};
+
+class AudioALSADeviceConfigManager {
+public:
+ static AudioALSADeviceConfigManager *getInstance();
+
+ /**
+ * LoadAudioConfig file
+ */
+ status_t LoadAudioConfig(const char *path);
+
+ /**
+ * config file related function
+ */
+ bool SupportConfigFile(void);
+
+
+ /**
+ * check device path exist
+ */
+ bool CheckDeviceExist(const char *path) ;
+
+ /**
+ * dump for all config file content
+ */
+ void dump(void);
+
+ /**
+ * set mixer ctl by type
+ */
+ int setMixerByteCtl(struct mixer_ctl *ctl, char **values, unsigned int numValues);
+ int setMixerCtlValue(String8 cltName, String8 cltNalue);
+ int setMixerCtl(String8 cltName, String8 cltNalue);
+
+ /**
+ * apply turn on / off sequence by string
+ */
+ status_t ApplyDeviceTurnonSequenceByName(const char *DeviceName) ;
+ status_t ApplyDeviceTurnoffSequenceByName(const char *DeviceName) ;
+
+ /**
+ * apply setting sequence
+ */
+ status_t ApplyDeviceSettingByName(const char *DeviceName) ;
+
+private:
+ static AudioALSADeviceConfigManager *UniqueAlsaDeviceConfigParserInstance;
+ AudioALSADeviceConfigManager();
+
+ /**
+ * load config file
+ */
+ status_t GetVersion(TiXmlElement *root);
+ status_t ParseInitSequence(TiXmlElement *root);
+ status_t ParseDeviceSequence(TiXmlElement *root);
+ /**
+ * query for device
+ */
+ DeviceCtlDescriptor *GetDeviceDescriptorbyname(const char *devicename);
+
+ Vector<DeviceCtlDescriptor *> mDeviceVector;
+ DeviceCtlControlSeq mDeviceCtlSeq;
+ String8 VersionControl;
+ bool mConfigsupport;
+ bool mInit;
+
+ /**
+ * mixer controller
+ */
+ struct mixer *mMixer;
+ /*
+ * flag of dynamic enable verbose/debug log
+ */
+ int mLogEnable;
+};
+
+}
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSADeviceParser.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSADeviceParser.h
new file mode 100644
index 0000000..67c3038
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSADeviceParser.h
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_MTK_DEVICE_PARSER_H
+#define ANDROID_AUDIO_MTK_DEVICE_PARSER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Mutex.h>
+#include <utils/String8.h>
+#include <utils/KeyedVector.h>
+#include <tinyalsa/asoundlib.h>
+#include "AudioALSADeviceString.h"
+#include "AudioType.h"
+
+namespace android {
+
+class AudioPcmDeviceparam {
+public:
+ AudioPcmDeviceparam() :
+ mBufferBytes(0),
+ mRateMax(0),
+ mRateMin(0),
+ mChannelMax(0),
+ mChannelMin(0),
+ mSampleBitMax(0),
+ mSampleBitMin(0),
+ mPreriodSizeMax(0),
+ mPreriodSizeMin(0),
+ mPreriodCountMax(0),
+ mPreriodCountMin(0) {
+ };
+ unsigned int mBufferBytes;
+ unsigned int mRateMax;
+ unsigned int mRateMin;
+ unsigned int mChannelMax;
+ unsigned int mChannelMin;
+ unsigned int mSampleBitMax;
+ unsigned int mSampleBitMin;
+ unsigned int mPreriodSizeMax;
+ unsigned int mPreriodSizeMin;
+ unsigned int mPreriodCountMax;
+ unsigned int mPreriodCountMin;
+};
+
+class AudioDeviceDescriptor {
+public:
+ AudioDeviceDescriptor() :
+ mCardindex(0),
+ mPcmindex(0),
+ mplayback(0),
+ mRecord(0) {
+ };
+ String8 mStreamName;
+ String8 mCodecName;
+ unsigned int mCardindex;
+ unsigned int mPcmindex;
+ unsigned int mplayback;
+ unsigned int mRecord;
+ AudioPcmDeviceparam mPlayparam;
+ AudioPcmDeviceparam mRecordparam;
+};
+
+class AudioALSADeviceParser {
+public:
+ unsigned int GetPcmIndexByString(String8 stringpair);
+ unsigned int GetCardIndexByString(String8 stringpair);
+ unsigned int GetPcmBufferSize(unsigned int pcmindex, unsigned int direction);
+ static AudioALSADeviceParser *getInstance();
+ void dump();
+
+ unsigned int GetCardIndex() {return mCardIndex;}
+private:
+ static AudioALSADeviceParser *UniqueAlsaDeviceInstance;
+ AudioALSADeviceParser();
+ void GetAllPcmAttribute(void);
+ void GetAllCompressAttribute(void);
+ void AddPcmString(char *InputBuffer);
+ status_t QueryPcmDriverCapability();
+ status_t GetPcmDriverparameters(AudioPcmDeviceparam *PcmDeviceparam, struct pcm_params *params);
+ void SetPcmCapability(AudioDeviceDescriptor *Descriptor, char *Buffer);
+ void getCardName();
+ void ParseCardIndex();
+ /**
+ * Audio Pcm vector
+ */
+ Vector <AudioDeviceDescriptor *> mAudioDeviceVector;
+ Vector <AudioDeviceDescriptor *> mAudioComprDevVector;
+ String8 mCardName;
+ unsigned int mCardIndex;
+
+ /*
+ * flag of dynamic enable verbose/debug log
+ */
+ int mLogEnable;
+};
+
+}
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSADriverUtility.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSADriverUtility.h
new file mode 100644
index 0000000..dcd40b4
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSADriverUtility.h
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_DRIVER_UTILITY_H
+#define ANDROID_AUDIO_ALSA_DRIVER_UTILITY_H
+
+#include <tinyalsa/asoundlib.h>
+#include <AudioLock.h>
+
+namespace android {
+
+class AudioALSADriverUtility {
+public:
+ virtual ~AudioALSADriverUtility();
+
+ static AudioALSADriverUtility *getInstance();
+
+ struct mixer *getMixer() const { return mMixer; }
+
+ int GetPropertyValue(const char *ProPerty_Key);
+
+ int setPropertyValue(const char *ProPerty_Key, int value);
+
+ inline AudioLock *getStreamSramDramLock() { return &mStreamSramDramLock; }
+
+ struct mixer_ctl *getMixerCtrlByName(struct mixer *mixer, const char *name);
+
+ int mixerCtrlGetValue(struct mixer_ctl *ctl, unsigned int id);
+
+ int mixerCtrlSetValue(struct mixer_ctl *ctl, unsigned int id, int value);
+
+private:
+ AudioALSADriverUtility();
+
+
+ /**
+ * singleton pattern
+ */
+ static AudioALSADriverUtility *mAudioALSADriverUtility;
+
+
+ /**
+ * singleton pattern
+ */
+ struct mixer *mMixer;
+
+ /**
+ * Lock for pcm open & close
+ */
+ AudioLock mStreamSramDramLock; // protect stream in/out sram/dram allocation mechanism
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_DRIVER_UTILITY_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAFMController.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAFMController.h
new file mode 100644
index 0000000..890e544
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAFMController.h
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_ALSA_AUDIO_FM_CONTROLLER_H
+#define ANDROID_ALSA_AUDIO_FM_CONTROLLER_H
+
+#include "AudioType.h"
+#include <AudioLock.h>
+#include "AudioVolumeInterface.h"
+
+#include <tinyalsa/asoundlib.h>
+
+
+namespace android {
+
+// FMAudioPlayer.cpp also need this structure!!
+typedef struct _AUDIO_DEVICE_CHANGE_CALLBACK_STRUCT {
+ void (*callback)(void *data);
+} AUDIO_DEVICE_CHANGE_CALLBACK_STRUCT;
+
+
+class AudioALSAHardwareResourceManager;
+class AudioALSAVolumeController;
+
+
+class AudioALSAFMController {
+public:
+ virtual ~AudioALSAFMController();
+
+ static AudioALSAFMController *getInstance();
+
+ virtual bool getFmEnable();
+ virtual status_t setFmEnable(const bool enable, const audio_devices_t output_device, bool bForceControl = false, bool bForce2DirectConn = false, bool bNeedSyncVolume = false); // TODO(Harvey)
+
+ virtual uint32_t getFmUplinkSamplingRate() const;
+ virtual uint32_t getFmDownlinkSamplingRate() const;
+
+ virtual status_t routing(const audio_devices_t pre_device, const audio_devices_t new_device);
+
+ virtual status_t setFmVolume(const float fm_volume);
+
+ virtual bool getFmChipPowerInfo();
+ virtual void setFmDeviceCallback(const AUDIO_DEVICE_CHANGE_CALLBACK_STRUCT *callback_data);
+
+ virtual void setUseFmDirectConnectionMode(const bool use_direct_mode) { mUseFmDirectConnectionMode = use_direct_mode; }
+
+ virtual bool checkFmNeedUseDirectConnectionMode();
+ virtual float getFmVolume();
+protected:
+ AudioALSAFMController();
+
+ virtual status_t setFmDirectConnection_l(const bool enable, const bool bforce, audio_devices_t output_device);
+
+ void (*mFmDeviceCallback)(void *data);
+ virtual status_t doDeviceChangeCallback();
+ bool isPreferredSampleRate(uint32_t rate) const;
+ virtual status_t setFmVolume_l(const float fm_volume);
+
+ AudioALSAHardwareResourceManager *mHardwareResourceManager;
+ AudioVolumeInterface *mAudioALSAVolumeController;
+
+
+ AudioLock mLock; // TODO(Harvey): could remove it later...
+
+ bool mFmEnable;
+ bool mIsFmDirectConnectionMode;
+ bool mUseFmDirectConnectionMode;
+
+ float mFmVolume;
+
+ struct pcm *mPcm;
+ struct pcm *mPcmUL;
+ String8 mApTurnOnSequence;
+ String8 mApTurnOnSequence2;
+
+ audio_devices_t mOuput_device;
+ bool mHyBridNLERegister;
+ struct pcm_config mConfig;
+
+private:
+ static AudioALSAFMController *mAudioALSAFMController; // singleton
+ /*
+ * flag of dynamic enable verbose/debug log
+ */
+ int mLogEnable;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_ALSA_AUDIO_FM_CONTROLLER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAGainController.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAGainController.h
new file mode 100644
index 0000000..77755ca
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAGainController.h
@@ -0,0 +1,284 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_VOLUME_CONTROLLER_H
+#define ANDROID_AUDIO_ALSA_VOLUME_CONTROLLER_H
+
+#include "AudioVolumeInterface.h"
+#include "AudioType.h"
+#include <utils/Log.h>
+#include <utils/String16.h>
+#include <cutils/properties.h>
+#include <utils/threads.h>
+
+#include <tinyalsa/asoundlib.h>
+
+#include "audio_custom_exp.h"
+
+#include "AudioGainTableParamParser.h"
+
+namespace android {
+/****************************************************
+* Define Volume Range of sound & Voice.
+*****************************************************/
+
+#define VOICE_VOLUME_MAX (160) // outside
+#define VOICE_ONEDB_STEP (4) // outside
+#define UPLINK_GAIN_MAX (252) // param tuner
+#define UPLINK_ONEDB_STEP (4) // param tuner
+
+//#define AUDIO_SYSTEM_UL_GAIN_MAX (45)
+//#define MAX_PGA_GAIN_RANGE (30) // gain controller
+//#define AUDIO_UL_PGA_STEP (6) // gain controller
+#define AMP_CONTROL_POINT (5) // not used
+
+typedef enum {
+ EarPiece_SideTone_Gain = 0,
+ Headset_SideTone_Gain,
+ LoudSpk_SideTone_Gain,
+ HAC_SideTone_gain,
+ Num_Side_Tone_Gain
+} SIDETOEN_GAIN_MODE;
+
+// these is used by legacy AudioALSAParamTuner, should be removed.
+typedef enum {
+ Audio_Earpiece = 0,
+ Audio_Headset,
+ Audio_Headphone,
+ Audio_Speaker,
+ Audio_DualMode_Earpiece,
+ Audio_DualMode_Headset,
+ Audio_DualMode_Headphone,
+ Audio_DualMode_speaker,
+ Ringtone_Earpiece,
+ Ringtone_Headset,
+ Ringtone_Headphone,
+ Ringtone_Speaker,
+ Sipcall_Earpiece,
+ Sipcall_Headset,
+ Sipcall_Headphone,
+ Sipcall_Speaker,
+ Num_of_Audio_gain
+} AUDIO_GAIN_MODE;
+
+typedef enum {
+ DRC_VERSION_1 = 0,
+ DRC_VERSION_2 = 1,
+} DRC_VERSION;
+
+struct HWStreamInfo {
+ int stream;
+ int devices;
+ int index;
+ audio_mode_t mode;
+};
+struct HWvolume {
+ int audioBuffer;
+ int voiceBuffer;
+ int speaker;
+ int dLDegardeGain;
+ int micGain;
+ int swAgc;
+ int sideTone;
+};
+struct HwCaptureInfo {
+ audio_mode_t mode;
+ audio_source_t source;
+ audio_devices_t input_device;
+ audio_devices_t output_devices;
+};
+
+//class AudioAMPControlInterface;
+class AudioALSAStreamManager;
+class AudioALSAHardwareResourceManager;
+class AudioSpeechEnhanceInfo;
+
+class AudioMTKGainController : public AudioVolumeInterface {
+public:
+ static AudioMTKGainController *getInstance();
+ ~AudioMTKGainController();
+ /**
+ * check to see if the audio hardware interface has been initialized.
+ */
+ virtual status_t setMasterVolume(float v, audio_mode_t mode, uint32_t devices);
+ virtual float getMasterVolume();
+ virtual status_t setVoiceVolume(float v, audio_mode_t mode, uint32_t devices);
+ virtual float getVoiceVolume(void);
+ virtual status_t setVoiceVolume(int MapVolume, uint32_t device);
+ virtual status_t ApplyVoiceGain(int degradeDb, audio_mode_t mode, uint32_t device);
+ virtual status_t setVoiceVolume(int index, int devices, audio_mode_t mode);
+ virtual status_t ApplyMicGain(GAIN_MIC_MODE _micMode, GAIN_DEVICE _gainDevice, audio_mode_t _mode);
+
+ // should depend on different usage , FM ,MATV and output device to setline in gain
+ virtual status_t ApplyMicGain(uint32_t MicType, int mode);
+ virtual status_t setFmVolume(const float fm_volume);
+public:
+ virtual status_t setAnalogVolume(int stream, int devices, int index, audio_mode_t mode);
+ virtual status_t speechNetworkChange(unsigned int info);
+ virtual bool isNbSpeechBand(void);
+ virtual status_t setBtVolumeCapability(bool support);
+public:
+ virtual status_t initCheck();
+ virtual status_t initVolumeController();
+ // here only valid stream can be set .
+ virtual status_t setStreamVolume(int stream, float v);
+ virtual status_t setStreamMute(int stream, bool mute);
+ virtual float getStreamVolume(int stream);
+ virtual status_t SetLineInPlaybackGain(int type);
+ virtual status_t SetLineInRecordingGain(int type);
+ virtual status_t SetSideTone(uint32_t Mode, uint32_t devices);
+ virtual uint32_t GetSideToneGain(uint32_t device);
+ virtual status_t SetMicGain(uint32_t Mode, uint32_t devices);
+ virtual status_t SetULTotalGain(uint32_t Mode, unsigned char Volume);
+ virtual uint8_t GetULTotalGain() {return mULTotalGain;}
+ virtual status_t SetDigitalHwGain(uint32_t Mode, uint32_t Gain, uint32_t routes);
+ virtual short GetSWMICGain();
+ virtual void ApplyMdDlGain(int Gain);
+ virtual void ApplyMdDlEhn1Gain(int32_t Gain);
+ virtual void ApplyMdUlGain(int Gain);
+ virtual uint16_t MappingToDigitalGain(unsigned char Gain);
+ virtual uint16_t MappingToPGAGain(unsigned char Gain);
+ virtual status_t ApplySideTone(uint32_t Mode);
+ // alsa driver set pga gain function
+ virtual void SetReceiverGain(int DrgradeDb);
+ virtual void SetHeadPhoneRGain(int DrgradeDb);
+ virtual void SetHeadPhoneLGain(int DrgradeDb);
+ virtual void SetSpeakerGain(int DegradedBGain);
+ virtual void SetLinoutLGain(int DegradedBGain);
+ virtual void SetLinoutRGain(int DegradedBGain);
+ virtual void SetAdcPga1(int DrgradeDb);
+ virtual void SetAdcPga2(int DrgradeDb);
+ virtual int ApplyAudioGainTuning(int Gain, uint32_t mode, uint32_t device);
+ virtual status_t SetMicGainTuning(uint32_t Mode, uint32_t gain);
+ status_t SetMicGainTuning(GAIN_MIC_MODE micMode, GAIN_DEVICE gainDevice, uint32_t gainDecimal);
+ unsigned short getMicGainDecimal(GAIN_MIC_MODE micMode, GAIN_DEVICE gainDevice);
+ virtual status_t SetCaptureGain(audio_mode_t mode, audio_source_t source, audio_devices_t input_device, audio_devices_t output_devices);
+ virtual uint32_t GetOffloadGain(float vol_f);
+public:
+ static int logToLinear(float volume);
+ static float linearToLog(int volume);
+ bool GetHeadPhoneImpedance(void);
+ void setANCEnable(bool _enable);
+
+ // return 0~255
+ int GetDigitalLinearGain(int _volIdx, audio_devices_t _device, audio_stream_type_t _streamType);
+ // return 0.0~1.0
+ float GetDigitalLogGain(int _volIdx, audio_devices_t _device, audio_stream_type_t _streamType);
+
+ void updateXmlParam(const char *_audioTypeName);
+#ifdef MTK_AUDIO_SW_DRE
+public:
+ void registerPlaybackHandler(uint32_t _identity);
+ void removePlaybackHandler(uint32_t _identity);
+ void requestMute(uint32_t _identity, bool _mute);
+
+ void setFmEnable(bool _enable);
+ bool isOtherModuleWorking();
+
+ void updateSWDREState(bool _numChanged, bool _muteChanged);
+ void SWDRERampToMute();
+ void SWDRERampToNormal();
+private:
+ AudioLock mSWDRELock;
+ KeyedVector<uint32_t, bool> mMutedHandlerVector;
+
+ bool mSWDREMute;
+ bool mHasMuteHandler;
+ size_t mNumHandler;
+ bool mFmEnable;
+#endif
+private:
+ static AudioMTKGainController *UniqueVolumeInstance;
+ AudioMTKGainController();
+ AudioMTKGainController(const AudioMTKGainController &); // intentionally undefined
+ AudioMTKGainController &operator=(const AudioMTKGainController &); // intentionally undefined
+ status_t setNormalVolume(int stream, int index, int devices, audio_mode_t mode);
+private:
+ bool isInVoiceCall(audio_mode_t mode);
+ bool isInVoipCall(audio_mode_t mode);
+ bool isInCall(audio_mode_t mode);
+ GAIN_DEVICE getGainDevice(audio_devices_t devices);
+ GAIN_DEVICE getGainDeviceForTty(void);
+ GAIN_MIC_MODE getGainMicMode(audio_source_t _source, audio_mode_t _mode);
+ uint32_t getSideToneGainType(uint32_t devices);
+ // BUFFER_TYPE getBufferType(int device,audio_mode_t mode);
+ uint16_t updateSidetone(int dlPGAGain, int sidetone, uint8_t ulGain);
+ status_t setAnalogVolume_l(int stream, int devices, int index, audio_mode_t mode);
+ // cal and set and set analog gainQuant
+ void ApplyAudioGain(int Gain, audio_mode_t mode, GAIN_DEVICE gainDevice);
+ void setAudioBufferGain(int gain);
+ void setVoiceBufferGain(int gain);
+ void setSpeakerGain(int gain);
+ void setAMPGain(void *points, int num, int device);
+ void ApplyMicGainByDevice(uint32_t device, audio_mode_t mode);
+ void ApplyMicGainForTty(audio_mode_t mode);
+ //bool Get_FMPower_info(void);
+
+ int GetReceiverGain(void);
+ int GetHeadphoneRGain(void);
+ int GetHeadphoneLGain(void);
+ int GetSPKGain(void);
+
+ int tuneGainForMasterVolume(int gain, audio_mode_t mode, GAIN_DEVICE gainDevice);
+ int tuneGainForHpImpedance(int gain, GAIN_DEVICE gainDevice);
+
+ uint32_t getHpImpedanceIdx(int32_t impedance);
+ int getHpImpedanceCompesateValue(void);
+ uint32_t mHpImpedanceIdx;
+
+ bool isValidStreamType(audio_stream_type_t _streamType);
+ bool isValidVolIdx(int _idx, audio_mode_t _mode);
+
+ bool isHeadsetCategory(enum GAIN_DEVICE _gainDevice);
+ bool isEarpieceCategory(enum GAIN_DEVICE _gainDevice);
+ bool isSpeakerCategory(enum GAIN_DEVICE _gainDevice);
+ bool isDmicDevice(enum GAIN_DEVICE _gainDevice);
+
+public:
+ status_t getSceneGainTableParameter(GainTableForScene *_gainTableForScene);
+ status_t getNonSceneGainTableParameter(GainTableForNonScene *_gainTableForNonScene);
+ int getSceneCount();
+ int getSceneIndex(const char *scene);
+ int getCurrentSceneIndex();
+ void setScene(const char *scene);
+ int16_t getVoiceDlAnalogGain(int index, int device, audio_mode_t mode);
+ uint16_t getVoiceUlAnalogGain(uint32_t device, audio_mode_t mode);
+ int setSpeakerType(int type);
+
+private:
+ status_t allocateGainTable();
+ status_t freeGainTable();
+
+private:
+ GainTableParam mGainTable;
+ GainTableSpec *mSpec;
+ // AUDIO_BT_GAIN_STRUCT mCustomVolume_BT;
+ AudioALSAHardwareResourceManager *mHardwareResourceManager;
+ // AudioAMPControlInterface * mAmpControl;
+ float mVoiceVolume;
+ float mMasterVolume;
+ //int mFmVolume;
+ //int mFmChipVolume;
+ bool mInitDone;
+ GAIN_SPEECH_BAND mBand;
+ GAIN_SPEECH_NETWORK mNetwork;
+ HWvolume mHwVolume;
+ HWStreamInfo mHwStream;
+ HwCaptureInfo mHwCaptureInfo;
+ Mutex mLock;
+ bool mSupportBtVol;
+
+ struct mixer *mMixer;
+
+ AudioSpeechEnhanceInfo *mAudioSpeechEnhanceInfoInstance;
+ uint8_t mULTotalGain;
+
+ bool mANCEnable;
+
+ std::vector<std::string> mSceneList;
+ int mSceneIndex;
+ int mSpkType;
+};
+
+}
+
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAHardware.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAHardware.h
new file mode 100644
index 0000000..b4aa090
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAHardware.h
@@ -0,0 +1,296 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_MTK_HARDWARE_H
+#define ANDROID_AUDIO_MTK_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Mutex.h>
+#include <utils/String8.h>
+
+#include <hardware/AudioCustomVolume.h>
+
+
+#include "AudioType.h"
+#include "AudioSpeechEnhanceInfo.h"
+#include <hardware_legacy/AudioMTKHardwareInterface.h>
+#include <hardware/AudioCustomVolume.h>
+#include "AudioVolumeInterface.h"
+#include "AudioCustParamClient.h"
+
+#include "AudioTypeExt.h"
+
+#ifdef MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT
+#include "AudioParamParser.h"
+#endif
+
+#include <hardware/audio_mtk.h>
+#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioOffload.h>
+
+namespace android {
+
+class AudioALSAStreamManager;
+class AudioALSAVolumeController;
+class AudioALSAParamTuner;
+class AudioALSASpeechPhoneCallController;
+class AudioALSADeviceParser;
+class AudioALSAANCController;
+class AudioParameterChangedHidlCallback;
+class AudioMessengerIPI;
+
+class AudioALSAHardware : public AudioMTKHardwareInterface {
+public:
+ AudioALSAHardware();
+ virtual ~AudioALSAHardware();
+
+ /**
+ * check to see if the audio hardware interface has been initialized.
+ * return status based on values defined in include/utils/Errors.h
+ */
+ virtual status_t initCheck();
+
+ /** set the audio volume of a voice call. Range is between 0.0 and 1.0 */
+ virtual status_t setVoiceVolume(float volume);
+
+ /**
+ * set the audio volume for all audio activities other than voice call.
+ * Range between 0.0 and 1.0. If any value other than NO_ERROR is returned,
+ * the software mixer will emulate this capability.
+ */
+ virtual status_t setMasterVolume(float volume);
+
+ /**
+ * Get the current master volume value for the HAL, if the HAL supports
+ * master volume control. AudioFlinger will query this value from the
+ * primary audio HAL when the service starts and use the value for setting
+ * the initial master volume across all HALs.
+ */
+ virtual status_t getMasterVolume(float *volume);
+
+ /**
+ * setMode is called when the audio mode changes. NORMAL mode is for
+ * standard audio playback, RINGTONE when a ringtone is playing, and IN_CALL
+ * when a call is in progress.
+ */
+ virtual status_t setMode(int mode);
+
+ // mic mute
+ virtual status_t setMicMute(bool state);
+ virtual status_t getMicMute(bool *state);
+
+#ifdef MTK_HIFIAUDIO_SUPPORT
+ // hifi audio
+ virtual status_t setHiFiStateToXML(bool value);
+ virtual int getHiFiStateFromXML();
+#endif
+
+ // set/get global audio parameters
+ virtual status_t setParameters(const String8 &keyValuePairs);
+ virtual String8 getParameters(const String8 &keys);
+
+ // Returns audio input buffer size according to parameters passed or 0 if one of the
+ // parameters is not supported
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+
+ /** This method creates and opens the audio hardware output stream */
+ virtual AudioMTKStreamOutInterface *openOutputStream(
+ uint32_t devices,
+ int *format = 0,
+ uint32_t *channels = 0,
+ uint32_t *sampleRate = 0,
+ status_t *status = 0);
+ virtual AudioMTKStreamOutInterface *openOutputStreamWithFlags(uint32_t devices,
+ audio_output_flags_t flags = (audio_output_flags_t)0,
+ int *format = 0,
+ uint32_t *channels = 0,
+ uint32_t *sampleRate = 0,
+ status_t *status = 0);
+ virtual void closeOutputStream(AudioMTKStreamOutInterface *out);
+
+ /** This method creates and opens the audio hardware input stream */
+ virtual AudioMTKStreamInInterface *openInputStream(
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
+ status_t *status,
+ audio_in_acoustics_t acoustics);
+
+ virtual AudioMTKStreamInInterface *openInputStreamWithFlags(
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
+ status_t *status,
+ audio_in_acoustics_t acoustics,
+ audio_input_flags_t flags = (audio_input_flags_t)0);
+
+ virtual void closeInputStream(AudioMTKStreamInInterface *in);
+
+ /**
+ * Called by the framework to read available microphones characteristics.
+ *
+ * \param[in] dev the hw_device object.
+ * \param[out] mic_array Pointer to first element on array with microphone info
+ * \param[out] mic_count When called, this holds the value of the max number of elements
+ * allowed in the mic_array. The actual number of elements written
+ * is returned here.
+ * if mic_count is passed as zero, mic_array will not be populated,
+ * and mic_count will return the actual number of microphones in the
+ * system.
+ *
+ * \return 0 if the microphone array is successfully filled.
+ * -ENOSYS if there is an error filling the data
+ */
+ virtual int getMicrophones(struct audio_microphone_characteristic_t *mic_array, size_t *mic_count);
+
+ /**This method dumps the state of the audio hardware */
+ virtual status_t dumpState(int fd, const Vector<String16> &args);
+ //#ifdef MTK_AUDIO
+ // TDM loopback I0I1 record
+ virtual status_t SetTDMrecordEnable(uint32_t sampleRate);
+ virtual status_t SetTDMrecordDisable(void);
+ virtual status_t setTDMRecord(int samplerate);
+
+
+ // add EM parameter or general purpose commands
+
+ virtual status_t SetEMParameter(void *ptr, int len) ;
+ virtual status_t GetEMParameter(void *ptr, int len) ;
+ virtual status_t SetAudioCommand(int par1, int par2);
+ virtual status_t GetAudioCommand(int par1);
+ virtual status_t SetAudioData(int par1, size_t len, void *ptr);
+ virtual status_t GetAudioData(int par1, size_t len, void *ptr);
+ virtual String8 GetAudioEncodedBuffer(int TypeAudioData, size_t ByteAudioData);
+
+ // ACF Preview parameter
+ virtual status_t SetACFPreviewParameter(void *ptr, int len);
+ virtual status_t SetHCFPreviewParameter(void *ptr, int len);
+
+#ifdef MTK_SPEAKER_MONITOR_SPEECH_SUPPORT
+ status_t CheckDisableSpeechStream(audio_mode_t new_mode);
+ status_t CheckEnableSpeechStream(audio_mode_t mode, status_t status_change);
+#endif
+
+ // for PCMxWay Interface API
+ virtual int xWayPlay_Start(int sample_rate);
+ virtual int xWayPlay_Stop(void);
+ virtual int xWayPlay_Write(void *buffer, int size_bytes);
+ virtual int xWayPlay_GetFreeBufferCount(void);
+ virtual int xWayRec_Start(int sample_rate);
+ virtual int xWayRec_Stop(void);
+ virtual int xWayRec_Read(void *buffer, int size_bytes);
+
+ // Voice Unlock
+ int ReadRefFromRing(void *buf, uint32_t datasz, void *DLtime);
+ int GetVoiceUnlockULTime(void *DLtime);
+ int SetVoiceUnlockSRC(uint32_t outSR, uint32_t outChannel);
+ bool startVoiceUnlockDL();
+ bool stopVoiceUnlockDL();
+ void freeVoiceUnlockDLInstance();
+ int GetVoiceUnlockDLLatency();
+ bool getVoiceUnlockDLInstance();
+ status_t GetAudioCommonData(int par1, size_t len, void *ptr);
+ status_t SetAudioCommonData(int par1, size_t len, void *ptr);
+ void setScreenState(bool mode);
+ void setBluetoothAudioOffloadParam(const sp<::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost>& hostIf,
+ const ::android::hardware::bluetooth::a2dp::V1_0::CodecConfiguration& codecConfig,
+ bool on);
+ void setA2dpSuspendStatus(int status);
+
+ //#endif
+ // update speech fir
+ bool UpdateOutputFIR(int mode, int index);
+
+ virtual status_t setMasterMute(bool muted);
+
+ virtual int createAudioPatch(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);
+
+ virtual int releaseAudioPatch(audio_patch_handle_t handle);
+
+ virtual int getAudioPort(struct audio_port *port);
+
+ virtual int setAudioPortConfig(const struct audio_port_config *config);
+ class AudioHalPatch {
+ public:
+ AudioHalPatch(audio_patch_handle_t newHalHandle) :
+ num_sources(0),
+ num_sinks(0),
+ mHalHandle(newHalHandle) {
+ memset((void *)sources, 0x00, sizeof(struct audio_port_config)*AUDIO_PATCH_PORTS_MAX);
+ memset((void *)sinks, 0x00, sizeof(struct audio_port_config)*AUDIO_PATCH_PORTS_MAX);
+ }
+
+ unsigned int num_sources; /* number of sources in following array */
+ struct audio_port_config sources[AUDIO_PATCH_PORTS_MAX];
+ unsigned int num_sinks; /* number of sinks in following array */
+ struct audio_port_config sinks[AUDIO_PATCH_PORTS_MAX];
+ audio_patch_handle_t mHalHandle;
+ };
+
+ virtual status_t GetAudioCustomVol(AUDIO_CUSTOM_VOLUME_STRUCT *pAudioCustomVol, int dStructLen);
+ static AudioALSAHardware *GetInstance();
+ virtual int setupParametersCallback(device_parameters_callback_t callback, void *cookie);
+ static int setParametersByCallback(const String8 &keyValuePairs);
+ virtual int setAudioParameterChangedCallback(device_audio_parameter_changed_callback_t callback, void *cookie);
+ virtual int clearAudioParameterChangedCallback(void *cookie);
+protected:
+ virtual status_t dump(int fd, const Vector<String16> &args);
+
+ AudioMessengerIPI *mAudioMessengerIPI;
+ AudioALSAStreamManager *mStreamManager;
+ AudioSpeechEnhanceInfo *mAudioSpeechEnhanceInfoInstance;
+ AudioVolumeInterface *mAudioALSAVolumeController;
+ AudioALSAParamTuner *mAudioALSAParamTunerInstance;
+ AudioALSASpeechPhoneCallController *mSpeechPhoneCallController;
+ AudioALSADeviceParser *mAudioAlsaDeviceInstance;
+ AudioALSAANCController *mANCController;
+
+private:
+ static AudioALSAHardware *mAudioALSAHardware; // singleton
+ bool mFmTxEnable;
+ bool mUseTuningVolume;
+ AUDIO_CUSTOM_VOLUME_STRUCT VolCache;
+ volatile int32_t mNextUniqueId;
+ bool mUseAudioPatchForFm;
+ SortedVector <AudioHalPatch *> mAudioHalPatchVector;
+ float MappingFMVolofOutputDev(int Gain, audio_devices_t eOutput);
+ //KeyedVector<audio_patch_handle_t, AudioHalPatch *> mAudioHalPatchVector;
+ int valAudioCmd;
+ char *pAudioBuffer;
+
+ // for bybpass audio hw
+ bool mAudioHWBypass;
+ static device_parameters_callback_t mHwParametersCbk;
+ static void *mHwParametersCbkCookie;
+
+ /**
+ * AudioCustParamClient
+ */
+ AudioCustParamClient *mAudioCustParamClient;
+
+ /**
+ * For AudioParameterChanged hidl callback
+ */
+ AudioLock mAudioParameterChangedHidlCallbackListLock;
+ Vector<AudioParameterChangedHidlCallback *> mAudioParameterChangedHidlCallbackList;
+ void onAudioParameterChangedCallback(const char *audioType);
+#ifdef MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT
+ static void onXmlChangedCallback(AppHandle *appHandle, const char *audioType);
+#endif
+
+ ::android::hardware::bluetooth::a2dp::V1_0::CodecConfiguration mBluetoothAudioOffloadCodecConfig;
+ /*
+ * flag of dynamic enable verbose/debug log
+ */
+ int mLogEnable;
+ bool mAudioHalBtscoWB;
+};
+
+}
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAHardwareResourceManager.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAHardwareResourceManager.h
new file mode 100644
index 0000000..9f0db0c
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAHardwareResourceManager.h
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_HARDWARE_RESOURCE_MANAGER_H
+#define ANDROID_AUDIO_ALSA_HARDWARE_RESOURCE_MANAGER_H
+#include "AudioTypeExt.h"
+
+#include <tinyalsa/asoundlib.h>
+
+#include "AudioType.h"
+#include <AudioLock.h>
+#include "AudioUtility.h"
+
+namespace android {
+
+typedef enum {
+ AUDIO_SPEAKER_MODE_D = 0,
+ AUDIO_SPEAKER_MODE_AB = 1,
+
+} AUDIO_SPEAKER_MODE;
+
+enum builtin_mic_specific_type {
+ BUILTIN_MIC_DEFAULT,
+ BUILTIN_MIC_MIC1_ONLY,
+ BUILTIN_MIC_MIC2_ONLY,
+ BUILTIN_MIC_MIC3_ONLY,
+ BUILTIN_MIC_MIC4_ONLY,
+ BUILTIN_MIC_MIC5_ONLY,
+};
+
+enum DeviceStatus {
+ DEVICE_STATUS_ON,
+ DEVICE_STATUS_OFF,
+};
+
+typedef bool (*SpeakerStatusChangeCb)(const DeviceStatus);
+
+class AudioALSADeviceConfigManager;
+class AudioSmartPaController;
+class AudioALSAHardwareResourceManager {
+public:
+ virtual ~AudioALSAHardwareResourceManager();
+ static AudioALSAHardwareResourceManager *getInstance();
+ virtual status_t ResetDevice(void);
+
+ /**
+ * output devices
+ */
+ virtual status_t setOutputDevice(const audio_devices_t new_devices, const uint32_t sample_rate);
+ virtual status_t startOutputDevice(const audio_devices_t new_devices, const uint32_t SampleRate);
+ virtual status_t stopOutputDevice();
+ virtual status_t changeOutputDevice(const audio_devices_t new_devices);
+ virtual bool isSharedOutDevice(audio_devices_t devices);
+ virtual audio_devices_t getOutputDevice();
+
+ /**
+ * output devices - Before using them, we should keep the mlock
+ */
+ virtual status_t startOutputDevice_l(const audio_devices_t new_devices, const uint32_t SampleRate);
+ virtual status_t stopOutputDevice_l();
+ virtual status_t changeOutputDevice_l(const audio_devices_t new_devices, const uint32_t SampleRate);
+
+ /**
+ * input devices
+ */
+ virtual status_t setInputDevice(const audio_devices_t new_device);
+ virtual status_t startInputDevice(const audio_devices_t new_device);
+ virtual status_t stopInputDevice(const audio_devices_t stop_device);
+ virtual status_t changeInputDevice(const audio_devices_t new_device);
+ virtual audio_devices_t getInputDevice();
+
+
+ /**
+ * HW Gain2
+ */
+ virtual status_t setHWGain2DigitalGain(const uint32_t gain);
+
+
+ /**
+ * Interrupt Rate
+ */
+ virtual status_t setInterruptRate(const audio_output_flags_t flag, const uint32_t rate);
+ virtual status_t setInterruptRate2(const uint32_t rate);
+ virtual status_t setULInterruptRate(const uint32_t rate);
+
+
+ /**
+ * sgen
+ */
+ virtual status_t setSgenMode(const sgen_mode_t sgen_mode);
+ virtual status_t setSgenSampleRate(const sgen_mode_samplerate_t sample_rate);
+ virtual status_t setSgenMute(int channel, bool mute);
+ virtual status_t setSgenFreqDiv(int channel, int freqDiv);
+ virtual status_t openAddaOutput(const uint32_t sample_rate);
+ virtual status_t closeAddaOutput();
+
+ /**
+ * sidetone
+ */
+ virtual status_t EnableSideToneFilter(const bool enable);
+ /**
+ * Current Sensing
+ */
+ virtual status_t setSPKCurrentSensor(bool bSwitch);
+
+ virtual status_t setSPKCurrentSensorPeakDetectorReset(bool bSwitch);
+
+ /**
+ * Get Phone MIC Mode by HW config
+ */
+ virtual uint32_t updatePhoneMicMode();
+ virtual uint32_t getPhoneMicMode(void) { return mPhoneMicMode; }
+ virtual uint32_t getHeadsetMicMode(void) { return mHeadsetMicMode; }
+
+ /**
+ * MIC inverse
+ */
+ virtual status_t setMicInverse(bool bMicInverse);
+ virtual bool getMicInverse(void);
+
+ virtual void setMIC1Mode(bool isHeadsetMic);
+ virtual void setMIC2Mode(bool isHeadsetMic);
+ virtual void setMIC3Mode(bool isHeadsetMic);
+
+ /**
+ * acquire pmic clk
+ */
+ virtual void EnableAudBufClk(bool bEanble);
+
+ /**
+ * Headphone Change information
+ */
+ virtual void setHeadPhoneChange(bool bchange) { mHeadchange = bchange; }
+ virtual bool getHeadPhoneChange(void) { return mHeadchange ; }
+
+ /**
+ * Headphone Change information
+ */
+ virtual void setNumOfHeadsetPole(int pole) { mNumHSPole = pole; }
+ virtual int getNumOfHeadsetPole(void) { return mNumHSPole; }
+
+ /**
+ * debug dump register & DAC I2S Sgen
+ */
+ virtual void setAudioDebug(const bool enable);
+
+ /**
+ * build in mic specific type
+ */
+ void setBuiltInMicSpecificType(const builtin_mic_specific_type type) { mBuiltInMicSpecificType = type; }
+
+ int getNumPhoneMicSupport(void) { return mNumPhoneMicSupport; }
+ void HpImpeDanceDetect(void);
+ void setDPDModule(bool enable);
+ void setHeadphoneLowPowerMode(bool enable);
+
+ int setNonSmartPAType();
+ int getNonSmartPAType();
+ bool setSpeakerStatusChangeCb(const SpeakerStatusChangeCb cb);
+
+
+ status_t EnableLowLatencyDebug(uint32_t bFlag) {
+ ALOGD("+%s() flag %d, Audio_LowLatency_Debug", __FUNCTION__, bFlag);
+
+ struct mixer_ctl *ctl = mixer_get_ctl_by_name(mMixer, "Audio_LowLatency_Debug");
+ if (ctl == NULL) {
+ ALOGD("+%s() don't support Audio_LowLatency_Debug", __FUNCTION__);
+ return NO_ERROR;
+ }
+
+ int retval = mixer_ctl_set_value(ctl, 0, bFlag);
+ ALOGD("+%s() retval %d", __FUNCTION__, retval);
+
+ return NO_ERROR;
+ }
+
+ // Latency unit : 0.1ms
+ void setA2dpDeviceLatency(int latency) { mA2dpDeviceLatency = latency / 10; }
+ int getA2dpDeviceLatency() { return mA2dpDeviceLatency; }
+ void resetA2dpDeviceLatency(void);
+
+ // BT FW latency
+ void setA2dpFwLatency(int latency) { mA2dpFwLatency = latency; }
+ int getA2dpFwLatency() { return mA2dpFwLatency; }
+ void resetA2dpFwLatency() { mA2dpFwLatency = 0; }
+
+ int getA2dpLatency() { return mA2dpFwLatency + mA2dpDeviceLatency; }
+
+#if defined(MTK_HIFIAUDIO_SUPPORT)
+ void setHiFiStatus(const bool enable) { mHiFiState = enable; }
+ bool getHiFiStatus() { return mHiFiState; }
+ //int setHiFiDACStatus(bool enable);
+ bool GetHiFiDACStateProperty();
+#endif
+
+ void setCodecSampleRate(const uint32_t sample_rate);
+
+ status_t AssignDRAM(uint32_t memoryInterface) {
+ struct mixer_ctl *ctl = mixer_get_ctl_by_name(mMixer, "Audio_Assign_DRAM");
+ if (ctl == NULL) {
+ ALOGD("-%s() don't support Audio_Assign_DRAM", __FUNCTION__);
+ return NO_ERROR;
+ }
+
+ int retval = mixer_ctl_set_value(ctl, 0, memoryInterface);
+ ALOGV("-%s() retval %d", __FUNCTION__, retval);
+
+ return NO_ERROR;
+ }
+
+
+protected:
+ AudioALSAHardwareResourceManager();
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSAHardwareResourceManager *mAudioALSAHardwareResourceManager;
+
+ /**
+ * low level for device open close
+ */
+ virtual status_t OpenReceiverPath(const uint32_t SampleRate);
+ virtual status_t CloseReceiverPath();
+ virtual status_t OpenHeadphonePath(const uint32_t SampleRate);
+ virtual status_t CloseHeadphonePath();
+ virtual status_t OpenSpeakerPath(const uint32_t SampleRate);
+ virtual status_t CloseSpeakerPath();
+ virtual status_t OpenHeadphoneSpeakerPath(const uint32_t SampleRate);
+ virtual status_t CloseHeadphoneSpeakerPath();
+ virtual status_t OpenBuiltInMicPath();
+ virtual status_t CloseBuiltInMicPath();
+ virtual status_t OpenBackMicPath();
+ virtual status_t CloseBackMicPath();
+ virtual status_t OpenWiredHeadsetMicPath();
+ virtual status_t CloseWiredHeadsetMicPath();
+
+ status_t setMicType(void);
+ status_t SetExtDacGpioEnable(bool bEnable);
+ bool GetExtDacPropertyEnable(void);
+
+ bool notifyOutputDeviceStatusChange(const audio_devices_t device, const DeviceStatus status);
+ AudioLock mLock;
+ AudioLock mLockin;
+
+ struct mixer *mMixer;
+ struct pcm *mPcmDL;
+ AudioALSADeviceConfigManager *mDeviceConfigManager;
+
+ audio_devices_t mOutputDevices;
+ audio_devices_t mInputDevice;
+
+ uint32_t mOutputDeviceSampleRate;
+ uint32_t mInputDeviceSampleRate;
+
+ bool mIsChangingInputDevice;
+
+ int32_t mStartOutputDevicesCount;
+ int32_t mStartInputDeviceCount;
+ String8 mStartInputDeviceSeqeunce;
+ SpeakerStatusChangeCb mSpeakerStatusChangeCb;
+
+ int mNumPhoneMicSupport;
+ bool mMicInverse;
+ builtin_mic_specific_type mBuiltInMicSpecificType;
+#if defined(MTK_HIFIAUDIO_SUPPORT)
+ AudioLock mHiFiLock;
+ bool mHiFiState;
+ int mHiFiDACStatusCount;
+#endif
+
+ int mNumHSPole;
+ bool mHeadchange;
+ uint32_t mPhoneMicMode;
+ uint32_t mHeadsetMicMode;
+ struct pcm_config mHpImpedanceConfig;
+ struct pcm *mHpImpeDancePcm;
+
+ AudioSmartPaController *mSmartPaController;
+
+ struct pcm_config mSpkPcmConfig;
+ struct pcm *mSpkPcmOut;
+
+ int mA2dpDeviceLatency;
+ int mA2dpFwLatency;
+
+ /*
+ * flag of dynamic enable verbose/debug log
+ */
+ int mLogEnable;
+
+ int nonSmartPAType;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_HARDWARE_RESOURCE_MANAGER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSALoopbackController.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSALoopbackController.h
new file mode 100644
index 0000000..ce49dbb
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSALoopbackController.h
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_LOOPBACK_CONTROLLER_H
+#define ANDROID_AUDIO_ALSA_LOOPBACK_CONTROLLER_H
+
+#include <tinyalsa/asoundlib.h> // TODO(Harvey): move it
+
+#include "AudioType.h"
+#include <AudioLock.h>
+#include "AudioUtility.h"
+
+
+namespace android {
+
+class AudioALSAHardwareResourceManager;
+
+class AudioALSALoopbackController {
+public:
+ virtual ~AudioALSALoopbackController();
+
+ static AudioALSALoopbackController *getInstance();
+
+ virtual status_t open(const audio_devices_t output_devices, const audio_devices_t input_device);
+ virtual status_t close();
+ virtual status_t SetApBTCodec(bool enable_codec);
+ virtual bool IsAPBTLoopbackWithCodec(void);
+ virtual status_t OpenAudioLoopbackControlFlow(const audio_devices_t input_device, const audio_devices_t output_device);
+ virtual status_t CloseAudioLoopbackControlFlow(void);
+ //#if defined(BTCVSD_LOOPBACK_WITH_CODEC)
+#if 1 //0902
+ class AudioMTKLoopbackThread : public Thread {
+ public:
+ AudioMTKLoopbackThread();
+ virtual ~AudioMTKLoopbackThread();
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+ private:
+ String8 mName;
+ virtual bool threadLoop();
+ };
+#endif
+
+protected:
+ AudioALSALoopbackController();
+
+ void setLoopbackUseLCh(bool enable);
+
+ AudioALSAHardwareResourceManager *mHardwareResourceManager;
+
+ AudioLock mLock;
+
+ struct pcm_config mConfig;
+
+ struct pcm *mPcmDL;
+ struct pcm *mPcmUL;
+ String8 mApTurnOnSequence;
+ String8 mApTurnOnSequence2;
+
+ struct mixer *mMixer;
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSALoopbackController *mAudioALSALoopbackController;
+
+ int mFd2;
+ bool mBtLoopbackWithCodec;
+ bool mBtLoopbackWithoutCodec;
+ //#if defined(BTCVSD_LOOPBACK_WITH_CODEC)
+#if 1 //0902
+ sp<AudioMTKLoopbackThread> mBTCVSDLoopbackThread;
+#endif
+ //for BT SW BT CVSD loopback test
+ bool mUseBtCodec;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_LOOPBACK_CONTROLLER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSANLEController.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSANLEController.h
new file mode 100644
index 0000000..f78a42d
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSANLEController.h
@@ -0,0 +1,360 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_NLE_CONTROLLER_H
+#define ANDROID_AUDIO_ALSA_NLE_CONTROLLER_H
+
+#include "AudioType.h"
+#include "AudioUtility.h"
+#include <AudioLock.h>
+#include <tinyalsa/asoundlib.h>
+#include "AudioALSAPlaybackHandlerBase.h"
+#ifdef MTK_HYBRID_NLE_SUPPORT
+//#undef MTK_HYBRID_NLE_SUPPORT
+#endif
+
+namespace android {
+
+class AudioALSAPlaybackHandlerBase;
+
+#define NLE_SUPPORT_CH_NUMBER_MAX (2)
+#define NLE_SUPPORT_SAMPLING_RATE_MAX (192000)
+#define NLE_SUPPORT_PREVIEW_MS_MIN (25) // ms
+#define NLE_SUPPORT_HARDWARE_NUM (1)
+#define NLE_SKIP_FRAME_COUNT (0)
+#define NLE_24BIT_NAGATIVE_MAX (8388608)
+#define NLE_24BIT_POSITIVE_MAX (8388607)
+#define NLE_16BIT_NAGATIVE_MAX (32768)
+#define NLE_16BIT_POSITIVE_MAX (32767)
+#define NLE_GAIN_UNININIAL_VALUE (10000)
+// #define NLE_HW_QUEUE_EXTRA_FRAMECOUNT (16) //extra check SPL
+// #define NLE_HW_QUEUE_SKIP_ZCE_FRAMECOUNT (NLE_HW_QUEUE_EXTRA_FRAMECOUNT+16) // reduce check ZCE
+#define NLE_HW_QUEUE_EXTRA_FRAMECOUNT_MS (4) //extra check SPL
+#define NLE_HW_QUEUE_SKIP_ZCE_FRAMECOUNT_MS (NLE_HW_QUEUE_EXTRA_FRAMECOUNT_MS+2) // reduce check ZCE
+#define NLE_HW_QUEUE_BUFFER_BEFORE_DAC_FRAMECOUNT (16)
+#define NLE_WAIT_NLE_BYPASS_MAX_MS (21 + NLE_HW_QUEUE_SKIP_ZCE_FRAMECOUNT_MS - NLE_HW_QUEUE_EXTRA_FRAMECOUNT_MS)
+#define NLE_GAIN_STEP_MAX_DB (2) // greater than 0, don't 0
+
+#define NLE_AFE_RGS_NLE_R_CFG0 (0)
+#define NLE_AFE_RGS_NLE_R_CFG1 (1)
+#define NLE_AFE_RGS_NLE_R_CFG2 (2)
+#define NLE_AFE_RGS_NLE_R_CFG3 (3)
+
+#define NLE_AFE_RGS_NLE_L_CFG0 (4)
+#define NLE_AFE_RGS_NLE_L_CFG1 (5)
+#define NLE_AFE_RGS_NLE_L_CFG2 (6)
+#define NLE_AFE_RGS_NLE_L_CFG3 (7)
+#define NLE_AFE_RGS_NLE_MAX (8)
+
+
+#define NLE_AFE_DL_NLE_R_CFG0 (0)
+#define NLE_AFE_DL_NLE_R_CFG1 (1)
+#define NLE_AFE_DL_NLE_R_CFG2 (2)
+#define NLE_AFE_DL_NLE_R_CFG3 (3)
+
+#define NLE_AFE_DL_NLE_L_CFG0 (4)
+#define NLE_AFE_DL_NLE_L_CFG1 (5)
+#define NLE_AFE_DL_NLE_L_CFG2 (6)
+#define NLE_AFE_DL_NLE_L_CFG3 (7)
+#define NLE_AFE_DL_NLE_MAX (8)
+
+
+
+#define nle_r_clip_overflow_mask (1<<15)
+#define nle_r_clip_overflow_len (1)
+#define nle_r_gain_dig_cur_mask (1<<8)
+#define nle_r_gain_dig_cur_len (6)
+#define nle_r_anc_mask_mask (1<<7)
+#define nle_r_anc_mask_len (1)
+#define nle_r_gain_ana_cur_mask (1<<0)
+#define nle_r_gain_ana_cur_len (6)
+
+#define nle_r_gain_dig_tar_cur_mask (1<<8)
+#define nle_r_gain_dig_tar_cur_len (6)
+#define nle_r_gain_ana_tar_cur_mask (1<<0)
+#define nle_r_gain_ana_tar_cur_len (6)
+
+#define nle_r_state_cur_mask (1<<12)
+#define nle_r_state_cur_len (3)
+#define nle_r_gain_step_cur_mask (1<<8)
+#define nle_r_gain_step_cur_len (4)
+#define nle_r_toggle_num_cur_mask (1<<0)
+#define nle_r_toggle_num_cur_len (6)
+
+#define nle_r_dig_gain_targeted_mask (1<<15)
+#define nle_r_dig_gain_targeted_len (1)
+#define nle_r_dig_gain_increase_mask (1<<14)
+#define nle_r_dig_gain_increase_len (1
+#define nle_r_dig_gain_decrease_mask (1<<13)
+#define nle_r_dig_gain_decrease_len (1)
+#define nle_r_ana_gain_targeted_mask (1<<12)
+#define nle_r_ana_gain_targeted_len (1)
+#define nle_r_ana_gain_increase_mask (1<<11)
+#define nle_r_ana_gain_increase_len (1)
+#define nle_r_ana_gain_decrease_mask (1<<10)
+#define nle_r_ana_gain_decrease_len (1)
+#define nle_r_time_counter_cur_mask (1<<0)
+#define nle_r_time_counter_cur_len (9)
+
+#define nle_l_clip_overflow_mask (1<<15)
+#define nle_l_clip_overflow_len (1)
+#define nle_l_gain_dig_cur_mask (1<<8)
+#define nle_l_gain_dig_cur_len (6)
+#define nle_l_anc_mask_mask (1<<7)
+#define nle_l_anc_mask_len (1)
+#define nle_l_gain_ana_cur_mask (1<<0)
+#define nle_l_gain_ana_cur_len (6)
+
+#define nle_l_gain_dig_tar_cur_mask (1<<8)
+#define nle_l_gain_dig_tar_cur_len (6)
+#define nle_l_gain_ana_tar_cur_mask (1<<0)
+#define nle_l_gain_ana_tar_cur_len (6)
+
+#define nle_l_state_cur_mask (1<<12)
+#define nle_l_state_cur_len (3)
+#define nle_l_gain_step_cur_mask (1<<8)
+#define nle_l_gain_step_cur_len (4)
+#define nle_l_toggle_num_cur_mask (1<<0)
+#define nle_l_toggle_num_cur_len (6)
+
+#define nle_l_dig_gain_targeted_mask (1<<15)
+#define nle_l_dig_gain_targeted_len (1)
+#define nle_l_dig_gain_increase_mask (1<<14)
+#define nle_l_dig_gain_increase_len (1
+#define nle_l_dig_gain_decrease_mask (1<<13)
+#define nle_l_dig_gain_decrease_len (1)
+#define nle_l_ana_gain_targeted_mask (1<<12)
+#define nle_l_ana_gain_targeted_len (1)
+#define nle_l_ana_gain_increase_mask (1<<11)
+#define nle_l_ana_gain_increase_len (1)
+#define nle_l_ana_gain_decrease_mask (1<<10)
+#define nle_l_ana_gain_decrease_len (1)
+#define nle_l_time_counter_cur_mask (1<<0)
+#define nle_l_time_counter_cur_len (9)
+
+#define DIG_GAIN_TARGETED (0)
+#define DIG_GAIN_INCREASE (1)
+#define DIG_GAIN_DECREASE (2)
+#define ANA_GAIN_TARGETED (3)
+#define ANA_GAIN_INCREASE (4)
+#define ANA_GAIN_DECREASE (5)
+#define TIME_COUNTER_CUR_MSB (6)
+#define TIME_COUNTER_CUR_LSB (7)
+
+#define DIG_GAIN_CUR (8)
+#define ANA_GAIN_CUR (9)
+
+
+
+typedef enum {
+ AUDIO_NLE_STATE_NONE,
+ AUDIO_NLE_STATE_INITIALIZED,
+ AUDIO_NLE_STATE_FIRST_WRITE,
+ AUDIO_NLE_STATE_RUNNING,
+} audio_nle_state;
+
+#if 0
+typedef enum {
+ AUDIO_NLE_CHANNEL_L,
+ AUDIO_NLE_CHANNEL_R,
+} audio_nle_channel;
+
+typedef struct {
+ int32_t mLGainNle;
+ int32_t mLGainHP;
+ int32_t mLDbpPerStep;
+ int32_t mLStepPerZC;
+
+ int32_t mRGainNle;
+ int32_t mRGainHP;
+ int32_t mRDbpPerStep;
+ int32_t mRStepPerZC;
+} HwParam_t;
+
+class AudioALSANLEController {
+public:
+ AudioALSANLEController(const stream_attribute_t *pStream_Attribute_Source); //Input attribute for NLE, however it is the same attribute for writing to HW
+ ~AudioALSANLEController();
+ status_t init(playback_handler_t ePlaybackHandlerType); // allocate memory/resource if success
+ status_t deinit(void); // deallocate memory/resource if success
+ size_t process(void *buffer, size_t Byte, time_info_struct_t *pHWBuffer_Time_Info); // return the size of data which write to NLE SW module
+private:
+
+ status_t checkValidForInit(playback_handler_t ePlaybackHandlerType);
+ status_t allocateResource(void);
+ status_t freeResource(void);
+ size_t writeToEachChannel(void *buffer, size_t Byte);
+ status_t gainAllocatePlan(float Spl, size_t ZeroCnt, audio_nle_channel eChannel);
+ status_t checkAndSetGain(size_t zuframecount);
+ status_t getMaxSPLandZeroCnt(RingBuf *pRingBuf, size_t zuframecount, float *pSPL_Db, size_t *pZeroCnt, uint32_t maxValidValue);
+ status_t applySetting2Hw(HwParam_t *pHwParam);
+ stream_attribute_t mStreamAttribute;
+ playback_handler_t mAattachPlaybackHandlerType;
+ audio_nle_state mState;
+ size_t mBytePerSample;
+ size_t mMinPreviewByte;
+ size_t mHwBufTotalFrame;
+ RingBuf mLBuf;
+ RingBuf mRBuf;
+ AudioLock mLock;
+ static uint32_t mUseHWNum;
+ size_t mUsedFrameCount;
+ size_t mMinPreviewFrameCount;
+ HwParam_t mCurHwParam;
+ HwParam_t mPrevHwParam;
+ struct mixer *mMixer;
+};
+#endif
+typedef enum {
+ AUDIO_NLE_CHANNEL_L = 0,
+ AUDIO_NLE_CHANNEL_R,
+} audio_nle_channel;
+
+typedef struct {
+ int32_t mGainNle;
+ int32_t mGainHP;
+ int32_t mDbpPerStep;
+ int32_t mStepPerZC;
+} NleHwParam_t;
+
+typedef struct {
+ NleHwParam_t stCur;
+ NleHwParam_t stPrev;
+ int32_t mMaxSPL_Db;
+ uint32_t mMaxValue;
+ size_t mZeroEventCount;
+ size_t mLookUpFrameCount;
+ audio_nle_channel mChannel;
+} NleHwInfo_t;
+
+typedef enum {
+ AUDIO_HYBRID_NLE_MNG_STATE_DISABLE = 0, // NLE HW module disable
+ AUDIO_HYBRID_NLE_MNG_STATE_BYBASS, // NLE HW module bypass signal, always keep digital gain at 0 dB
+ AUDIO_HYBRID_NLE_MNG_STATE_RUNNING, // NLE HW module run with normal mode
+} audio_hybridnlemng_status;
+
+typedef enum {
+ AUDIO_STREAM_HW_FM = 1 << 0,
+ AUDIO_STREAM_OTHER = 1 << 1,
+} audio_stream_hw_path;
+
+typedef enum {
+ NLE_ADJUST_GAIN_NORMAL = 0,
+ NLE_ADJUST_GAIN_RAMP_TO_BYPASS,
+ NLE_ADJUST_GAIN_MAX,
+} audio_hybrid_adjust_mode;
+
+class AudioALSANLECtrl {
+public:
+ AudioALSANLECtrl(playback_handler_t ePlaybackHandlerType, const stream_attribute_t *pStream_Attribute_Source); //Input attribute for NLE, however it is the same attribute for writing to HW
+ ~AudioALSANLECtrl();
+ status_t init(AudioALSAPlaybackHandlerBase *pPlaybackHandler); // allocate memory/resource if success
+ status_t deinit(void); // deallocate memory/resource if success
+ size_t process(void *buffer, size_t Byte); // return the size of data which write to NLE SW module
+ status_t getMaxSPLandZeroCnt(NleHwInfo_t *pNleHwInfo, RingBuf *pRingBuf, size_t zuframecount, float *pSPL_Db, size_t *pZeroCnt, uint32_t maxValidValue);
+ status_t setMaxSPLintoSpecificPos(size_t zuOffsetForTail);
+ RingBuf mLBuf;
+ RingBuf mRBuf;
+ size_t mMinPreviewFrameCount;
+ size_t mCheckHwExtraFrameCnt;
+ size_t mSkipHwZCEFrameCnt;
+ size_t mPlaybackedFrameCnt;
+ size_t mRamp2ZeroFrameCnt;
+ size_t mBytePerSample;
+ AudioALSAPlaybackHandlerBase *mAudioALSAPlaybackHandlerBase;
+private:
+ status_t checkValidForInit(playback_handler_t ePlaybackHandlerType);
+ status_t allocateResource(void);
+ status_t freeResource(void);
+ size_t writeToEachChannel(void *buffer, size_t Byte);
+ stream_attribute_t mStreamAttribute;
+ playback_handler_t mAattachPlaybackHandlerType;
+ audio_nle_state mState;
+ size_t mMinPreviewByte;
+ size_t mHwBufTotalFrame;
+ AudioLock mLock;
+};
+
+class AudioALSAHyBridNLEManager {
+public:
+ AudioALSAHyBridNLEManager();
+ static AudioALSAHyBridNLEManager *getInstance();
+ // hpMaxGainDb: 12~-32 Db or -128 = muted
+ status_t setNleHwConfigByIndex(size_t hpMaxGainIdx);
+ status_t getNleHwConfigByDb(int *hpMaxGainDb);
+ status_t getNleHwConfigByIndex(size_t *hpMaxGainIdx);
+ audio_hybridnlemng_status getStatus(void);
+ status_t initPlayBackHandler(playback_handler_t ePlaybackHandlerType, stream_attribute_t *pStreamAttribute, AudioALSAPlaybackHandlerBase *pPlaybackHandler);
+ status_t deinitPlayBackHandler(playback_handler_t ePlaybackHandlerType);
+ status_t process(playback_handler_t ePlaybackHandlerType, void *buffer, size_t Byte);
+ status_t addHwPathStream(audio_stream_hw_path eHwPath);
+ status_t removeHwPathStream(audio_stream_hw_path eHwPath);
+ status_t setAudioMode(audio_mode_t eMode);
+ status_t setBypassNLE(bool bBypass);
+ bool getBypassNLE(void);
+ status_t setEnableNLE(bool bEnable);
+ status_t setNleEopDb(int eopGainDb); //Gain change
+ int getNleEopDb(void);
+ status_t dump(void);
+ static uint32_t getSupportRunNLEHandler(void);
+ static status_t setSupportRunNLEHandler(playback_handler_t eHandler);
+private:
+ status_t setNleHwConfigByDb(int hpMaxGainDb, int eopGainDb); //Gain change
+ status_t updateCurStatus(void);
+ status_t enableNleHw(void);
+ status_t disableNleHw(void);
+ status_t ramp2DigitalGainZero(void);
+ bool checkIfGainTargeted(void);
+ status_t waitForBypass(audio_hybridnlemng_status ePrevStatus, audio_hybridnlemng_status eCurStatus);
+ status_t doAdjustGainProcess(AudioALSANLECtrl *pCurNLECtrl, size_t zuCheckOffsetFrameCnt, audio_hybrid_adjust_mode eAdjustMode);
+ status_t gainAllocatePlan(float Spl, size_t ZeroCnt, size_t Zuframecount, NleHwInfo_t *pNleHwInfo);
+ status_t checkAndSetGain(size_t zuframecount, AudioALSANLECtrl *pNleCtrl, NleHwInfo_t *pNleHwInfo, RingBuf *pRingBuf);
+ status_t applyGain2Hw(NleHwInfo_t *pNleHwInfo);
+ status_t resetDefaultGain(NleHwInfo_t *pNleHwInfo);
+ status_t getGstepAndGnum(int32_t SPL_diff, size_t ZeroCnt, int32_t *pdGstep, int32_t *pdGnum);
+ AudioLock mLock;
+ static AudioALSAHyBridNLEManager *mAudioALSAHyBridNREManager; // singleton
+ status_t getDbFromAnalogIdx(size_t AnalogIdx, int8_t *pDb);
+ status_t getAnalogIdx(int8_t Db, size_t *pAnalogIdx);
+ status_t getDbFromDigitalIdx(size_t DigitalIdx, int8_t *pDb);
+ status_t getDigitalIdx(int8_t Db, size_t *pDigitalIdx);
+ void showRegInfo(void);
+ int32_t mGainHP_Db_Max;
+ int32_t mGainHP_Db_Min;
+ int32_t mGainNLE_Db_Max;
+ int32_t mGainNLE_Db_Min;
+ int32_t mGainEop_Db;
+ int32_t mGainSop_Db;
+ audio_hybridnlemng_status mStatus;
+ playback_handler_t mActivePBHandler;
+ uint32_t mActivePBHandlerBitwise;
+ uint32_t mInitPBHandlerBitwise;
+ NleHwInfo_t mLNleHwInfo;
+ NleHwInfo_t mRNleHwInfo;
+ audio_mode_t mMode;
+ AudioALSANLECtrl *mNleCtrlOfPlaybackHandler[PLAYBACK_HANDLER_MAX];
+ uint32_t mNleCtrlOfPlaybackHandlerCounter;
+ uint32_t mHwPathStreamCounter;
+ bool mBypassNLE; // Mean fix digital gain to 0, and fix analog gain to User gain
+ bool mNleSwitch; // Turn on/off NLE Hw module, before turn off make sure fix digital gain to 0, and fix analog gain to User gain
+ struct mixer *mMixer;
+ int8_t mHwAnalogGainMaxDb;
+ int8_t mHwAnalogGainMinDb;
+ size_t mHwAnalogGainMinValue;
+ int8_t mHwAnalogGainMuteDb;
+ size_t mHwAnalogGainMuteValue;
+ int8_t mHwDigitalGainMaxDb;
+ size_t mHwDigitalGainMaxValue;
+ int8_t mHwDigitalgGainMinDb;
+ uint8_t mHwAnalogDelayTick;
+ bool mHwSupport;
+ bool mSetEopByProp;
+ bool mForceTurnOffNLE;
+ uint32_t mMax24BitValidValue;
+ uint32_t mMax16BitValidValue;
+ static uint32_t mSupportRunNLEHandlerBitwise;
+ // uint32_t mNLE_AFE_RGS_NLE[NLE_AFE_RGS_NLE_MAX];
+ // uint32_t mNLE_AFE_DL_NLE[NLE_AFE_DL_NLE_MAX];
+};
+
+}
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAParamTuner.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAParamTuner.h
new file mode 100644
index 0000000..75b862b
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAParamTuner.h
@@ -0,0 +1,331 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*******************************************************************************
+ *
+ * Filename:
+ * ---------
+ * AudioParamTuning.h
+ *
+ * Project:
+ * --------
+ * Android
+ *
+ * Description:
+ * ------------
+ * This file implements the method for handling param tuning.
+ *
+ * Author:
+ * -------
+ * Donglei Ji (mtk80823)
+ *******************************************************************************/
+
+#ifndef _AUDIO_ALSA_PARAM_TUNER_H_
+#define _AUDIO_ALSA_PARAM_TUNER_H_
+
+#include <utils/threads.h>
+
+#include "AudioVolumeInterface.h"
+//#include "AudioALSAVolumeController.h"
+#include "AudioVolumeFactory.h"
+
+#include "AudioALSAHardwareResourceManager.h"
+#include "SpeechDriverFactory.h"
+//#include "AudioDigitalControlInterface.h"
+//#include "AudioAnalogControlInterface.h"
+#include "SpeechPcm2way.h"
+#include "AudioALSASpeechPhoneCallController.h"
+
+#define MAX_VOICE_VOLUME VOICE_VOLUME_MAX
+#define FILE_NAME_LEN_MAX 128
+
+#ifdef DMNR_TUNNING_AT_MODEMSIDE
+#define P2W_RECEIVER_OUT 0
+#define P2W_HEADSET_OUT 1
+#define P2W_NORMAL 0
+#define P2W_RECONLY 1
+#else
+typedef enum {
+ OUTPUT_DEVICE_RECEIVER = 0,
+ OUTPUT_DEVICE_HEADSET,
+ OUTPUT_DEVICE_SPEAKER,
+
+ DMNR_REC_OUTPUT_DEV_NUM
+} DMNR_REC_OUTPUT_DEVICE_TYPE;
+
+typedef enum {
+ RECPLAY_MODE = 0,
+ RECONLY_MODE,
+ RECPLAY_HF_MODE,
+ RECONLY_HF_MODE,
+
+ DMNR_REC_MODE_NUM
+} DMNR_REC_MODE_TYPE;
+#include "AudioALSAStreamManager.h"
+#include "AudioSpeechEnhanceInfo.h"
+#endif
+
+typedef struct {
+ unsigned short cmd_type;
+ unsigned short slected_fir_index;
+ unsigned short dlDigitalGain;
+ unsigned short dlPGA;
+ unsigned short phone_mode;
+ unsigned short wb_mode;
+ char input_file[FILE_NAME_LEN_MAX];
+} AudioTasteTuningStruct;
+
+typedef enum {
+ AUD_TASTE_STOP = 0,
+ AUD_TASTE_START,
+ AUD_TASTE_DLDG_SETTING,
+ AUD_TASTE_DLPGA_SETTING,
+ AUD_TASTE_INDEX_SETTING,
+
+ AUD_TASTE_CMD_NUM
+} AUD_TASTE_CMD_TYPE;
+
+typedef enum {
+ PCM_FORMAT = 0,
+ WAVE_FORMAT,
+
+ UNSUPPORT_FORMAT
+} FILE_FORMAT;
+
+typedef enum {
+ AUD_MIC_GAIN = 0,
+ AUD_RECEIVER_GAIN,
+ AUD_HS_GAIN,
+ AUD_MIC_GAIN_HF,
+
+ AUD_GAIN_TYPE_NUM
+} DMNRGainType;
+
+typedef enum {
+ DUAL_MIC_REC_PLAY_STOP = 0,
+ DUAL_MIC_REC,
+ DUAL_MIC_REC_PLAY,
+ DUAL_MIC_REC_PLAY_HS,
+ DUAL_MIC_REC_HF,
+ DUAL_MIC_REC_PLAY_HF,
+ DUAL_MIC_REC_PLAY_HF_HS,
+ FIR_REC,
+ FIR_REC_STOP,
+
+ DMNR_TUNING_CMD_CNT
+} TuningCmdType;
+
+typedef struct {
+ unsigned int ChunkID;
+ unsigned int ChunkSize;
+ unsigned int Format;
+ unsigned int Subchunk1ID;
+ unsigned int Subchunk1IDSize;
+ unsigned short AudioFormat;
+ unsigned short NumChannels;
+ unsigned int SampleRate;
+ unsigned int ByteRate;
+ unsigned short BlockAlign;
+ unsigned short BitsPerSample;
+ unsigned int SubChunk2ID;
+ unsigned int SubChunk2Size;
+} WAVEHDR;
+
+#if defined(MTK_AUDIO_GAIN_TABLE) && !defined(MTK_NEW_VOL_CONTROL)
+//for UI Disp
+#define MAX_NAME_LEN 16
+#define MAX_SUB_ITEM_NUM 4
+typedef struct _PCDispSubItem {
+ char outputDevice[MAX_NAME_LEN];
+ unsigned short AnalogPoint; // PGA and Ext Amp
+} PCDispSubItem; // size: 18
+typedef struct _PCDispItem {
+ char strType[MAX_NAME_LEN];
+ unsigned short level;
+ unsigned int subItemNum;
+ PCDispSubItem subItem[MAX_SUB_ITEM_NUM]; //3 //3 -> 4
+} PCDispItem; // size: 22 + 18*4 = 94
+
+
+#define MAX_NAME_LEN_MIC 32
+#define MAX_SUB_ITEM_NUM_MIC 32
+typedef struct _PCDispMic {
+ char strType[MAX_NAME_LEN_MIC];
+ unsigned int subItemNum;
+ char subItem[MAX_SUB_ITEM_NUM_MIC][MAX_NAME_LEN_MIC]; //24 -> 32
+} PCDispMic; //size: 1060
+
+#define MAX_GAIN_POINT_NUM 12
+#define MAX_GAIN_STEP 32
+#define MAX_ITEM_NUM 20
+typedef struct _PCDispTotolStru {
+ unsigned int itemNum;
+ PCDispItem DispItem[MAX_ITEM_NUM]; // 16 -> 20
+ PCDispMic DispMic;
+ unsigned short gainRangeNum; // 9->12
+ signed char gainRange[MAX_GAIN_POINT_NUM][MAX_GAIN_STEP]; // 9-> 12
+} PCDispTotolStru;
+
+static char gainRangeCopy[MAX_GAIN_POINT_NUM][MAX_GAIN_STEP] = {
+ { -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ { -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ {0, 45, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ {0, 6, 12, 20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ { -60, -50, -45, -42, -39, -36, -33, -30, -27, -24, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0 },
+ {0, 6, 12, 20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ { -60, -50, -45, -42, -39, -36, -33, -30, -27, -24, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0 },
+ {0, 32, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ {0, 32, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ {6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
+};
+
+static char subItemMic[MAX_SUB_ITEM_NUM_MIC][MAX_NAME_LEN_MIC] = {
+ {"Idle Record Mic"},
+ {"Idel Record Headset"},
+ {"Voice Recognition Mic"}, //
+ {"Voice Recognition Headset"},
+ {"Video Record Mic"},
+ {"Video Record Headset"},
+ {"IncallNB Receiver"},
+ {"IncallNB Headset"},
+ {"IncallNB Speaker"},
+ {"IncallWB Receiver"},
+ {"IncallWB Headset"},
+ {"IncallWB Speaker"},
+ {"VOIP Receiver"},
+ {"VOIP Headset"},
+ {"VOIP Speaker"},
+ {"TTY"},
+ {"Reserved1 Mic"},
+ {"Reserved1 Headset"},
+ {"Reserved2 Mic"},
+ {"Reserved2 Headset"},
+ {""},
+ {""},
+ {""},
+ {""},
+ {""},
+ {""},
+ {""},
+ {""}
+};
+
+#endif
+
+namespace android {
+#define MODE_NUM NUM_OF_VOL_MODE
+
+#if defined(MTK_AUDIO_GAIN_TABLE) && !defined(MTK_NEW_VOL_CONTROL)
+class AudioHWVolumeCapability;
+#endif
+
+class AudioALSAParamTuner {
+public:
+ AudioALSAParamTuner();
+ ~AudioALSAParamTuner();
+
+ static AudioALSAParamTuner *getInstance();
+
+ //for taste tool
+ bool isPlaying();
+ status_t setMode(uint32 mode);
+ uint32 getMode();
+ status_t setPlaybackFileName(const char *fileName);
+ status_t setDLPGA(uint32 gain);
+ void updataOutputFIRCoffes(AudioTasteTuningStruct *pCustParam);
+ status_t enableModemPlaybackVIASPHPROC(bool bEnable, bool bWB = false);
+
+ FILE_FORMAT playbackFileFormat();
+
+ // protect Play PCM With Speech Enhancement buffers
+ pthread_mutex_t mPlayBufMutex;
+ pthread_cond_t mPPSExit_Cond;
+ pthread_mutex_t mPPSMutex;
+ pthread_mutex_t mP2WMutex;
+
+ uint32 mMode;
+ bool m_bPPSThreadExit;
+ bool m_bWBMode;
+ FILE *m_pInputFile;
+
+ // For DMNR Tuning
+ status_t setRecordFileName(const char *fileName);
+ status_t setDMNRGain(unsigned short type, unsigned short value); //for DMNR
+ status_t getDMNRGain(unsigned short type, unsigned short *value); //for DMNR
+#ifdef DMNR_TUNNING_AT_MODEMSIDE
+ status_t enableDMNRModem2Way(bool bEnable, bool bWBMode, unsigned short outputDevice, unsigned short workMode);
+#else
+ AudioALSAStreamManager *getStreamManager() {return mAudioStreamManager;}
+ AudioSpeechEnhanceInfo *getSpeechEnhanceInfoInst() {return mAudioSpeechEnhanceInfoInstance;}
+ int getPlaybackDb() {return mPlaybackDb_index;}
+ status_t setPlaybackVolume(uint32_t mode, uint32_t gain, uint32_t device);
+ status_t enableDMNRAtApSide(bool bEnable, bool bWBMode, unsigned short outputDevice, unsigned short workMode);
+ status_t enableFIRRecord(bool bEnable);
+#endif
+ // for DMNR playback+record thread
+ //rb m_sRecBuf;
+
+ // protect DMNR Playback+record buffers
+ pthread_mutex_t mRecPlayMutex;
+ pthread_mutex_t mRecBufMutex;
+ pthread_cond_t mRecPlayExit_Cond;
+
+ bool m_bRecPlayThreadExit;
+ FILE *m_pOutputFile;
+
+ Play2Way *mPlay2WayInstance;
+ Record2Way *mRec2WayInstance;
+
+ uint32_t mDMNROutputDevice;
+
+#if defined(MTK_AUDIO_GAIN_TABLE) && !defined(MTK_NEW_VOL_CONTROL)
+ status_t getGainInfoForDisp(void *pParam); //gain table
+#ifdef MTK_AUDIO_GAIN_TABLE_BT
+ status_t getBtNrecInfoForDisp(void *pParam); //gain table
+#endif
+#endif
+
+private:
+
+ status_t setSphVolume(uint32 mode, uint32 gain);
+ status_t openModemDualMicCtlFlow(bool bWB, bool bRecPly);
+ status_t closeModemDualMicCtlFlow(bool bRecPly);
+
+ // the uniqe
+ static AudioALSAParamTuner *UniqueTuningInstance;
+
+ SpeechDriverFactory *mSpeechDriverFactory;
+ AudioVolumeInterface *mAudioALSAVolumeController;
+ // AudioAnalogControlInterface *mAudioAnalogInstance;
+ // AudioDigitalControlInterface *mAudioDigitalInstance;
+ AudioALSAHardwareResourceManager *mAudioResourceManager;
+ AudioALSASpeechPhoneCallController *mSphPhonecallCtrl;
+#if defined(MTK_AUDIO_GAIN_TABLE) && !defined(MTK_NEW_VOL_CONTROL)
+ status_t getPCDispItem(void *pParam);
+ status_t getPCDispSubItem(void *pParam, int streamType, int speech = -1);
+ status_t getPCDispMic(void *pParam);
+ AudioHWVolumeCapability *mAudioHWVolumeCapabilityInstance;
+#endif
+ uint32 mSideTone;
+ uint32 mOutputVolume[MODE_NUM];
+ char m_strInputFileName[FILE_NAME_LEN_MAX];
+ bool m_bPlaying;
+ bool mStartRec;
+
+ pthread_t mTasteThreadID;
+
+ bool m_bDMNRPlaying;
+ char m_strOutFileName[FILE_NAME_LEN_MAX]; // for reord
+ unsigned short mDualMicTool_micGain[2]; // 0 for normal mic; 1 for handsfree mic
+ unsigned short mDualMicTool_receiverGain;
+ unsigned short mDualMicTool_headsetGain;
+ pthread_t mRecPlayThreadID;
+#ifndef DMNR_TUNNING_AT_MODEMSIDE
+ AudioALSAStreamManager *mAudioStreamManager;
+ AudioSpeechEnhanceInfo *mAudioSpeechEnhanceInfoInstance;
+ int mPlaybackDb_index;
+#endif
+};
+}
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPcmDataCaptureIn.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPcmDataCaptureIn.h
new file mode 100644
index 0000000..8818cf0
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPcmDataCaptureIn.h
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_PCM_DATA_CAPTURE_IN_H
+#define ANDROID_AUDIO_PCM_DATA_CAPTURE_IN_H
+
+#include "AudioType.h"
+#include <AudioLock.h>
+#include "AudioUtility.h"
+#include <tinyalsa/asoundlib.h>
+
+namespace android {
+
+class AudioALSAPcmDataCaptureIn {
+public:
+ virtual ~AudioALSAPcmDataCaptureIn();
+ static AudioALSAPcmDataCaptureIn *getInstance();
+
+ /**
+ * read data from audio hardware
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes); // called by capture handler
+ virtual status_t Standby();
+ virtual status_t SetPcmConfig(pcm_config mPcmInputConfig);
+ virtual status_t GetPcmConfig(pcm_config *mPcmInputConfig);
+ virtual status_t SetThreadEnable(void);
+ virtual status_t SetThreadDisable(void);
+
+ class AudioPCMInputThread : public Thread {
+ public:
+ AudioPCMInputThread(AudioALSAPcmDataCaptureIn *mAudioALSAPcmDataCaptureIn);
+ virtual ~AudioPCMInputThread();
+
+ // Good place to do one-time initializations
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+
+ status_t SetPcmConfig(pcm_config mPcmInputConfig);
+ status_t GetPcmConfig(pcm_config *mPcmInputConfig);
+
+ status_t SetThreadEnable();
+ status_t SetThreadDisable();
+
+ void OpenPCMDump(const char *class_name);
+ void ClosePCMDump();
+
+ int readIVData(void *buffer, ssize_t bytes);
+ unsigned int FormatTransfer(int SourceFormat, int TargetFormat, void *Buffer, unsigned int mReadBufferSize);
+
+ protected:
+ status_t OpenPcm();
+ status_t ClosePcm();
+ status_t StartPcm();
+ status_t ProcessStateChange();
+ int GetPcmData();
+ status_t AllocateResource(); // allocate buffer
+ status_t ReleaseResource(); // release buffer
+ status_t ResetResource(); // reset read buffer
+ status_t AssignReadSize(); // assign read pcm buffer size
+
+ private:
+ virtual bool threadLoop();
+ AudioALSAPcmDataCaptureIn *mAudioALSAPcmDataCaptureIn;
+ char *mReadBuffer;
+ unsigned int mReadBufferSize;
+ const unsigned int mReadBufferAllocateSize = 64 * 1024;
+ pcm_config mPcmInputConfig;
+ struct pcm *mInputPcm;
+ bool mbRunning;
+ bool mbStatusChange;
+
+ Mutex mLock; // mutex associated with mCond
+ Condition mWaitWorkCV; // condition for status return
+
+ Mutex mRingLock;
+ Condition mRingWaitWorkCV;
+
+ Mutex mPcmLock;
+ Condition mPcmWaitWorkCV;
+
+ /**
+ * local ring buffer
+ */
+ RingBuf mRawDataBuf;
+
+ FILE *mPCMIVDumpFile;
+ int DumpIVFileNum;
+
+ };
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSAPcmDataCaptureIn *mAudioALSAPcmDataCaptureIn;
+ AudioALSAPcmDataCaptureIn();
+
+ sp<AudioPCMInputThread> mAudioPcmInputThread;
+ /**
+ * attribute
+ */
+ stream_attribute_t mStreamAttributeSource; // from audio hw , can set by user
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_PCM_DATA_CAPTURE_IN_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackDataDispatcher.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackDataDispatcher.h
new file mode 100644
index 0000000..0e7829f
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackDataDispatcher.h
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_PLAYBACK_DATA_DISPATCHER_H
+#define ANDROID_AUDIO_ALSA_PLAYBACK_DATA_DISPATCHER_H
+
+#include <tinyalsa/asoundlib.h>
+
+namespace android {
+
+class AudioALSAPlaybackDataDispatcher {
+public:
+ virtual ~AudioALSAPlaybackDataDispatcher();
+
+ static AudioALSAPlaybackDataDispatcher *getInstance();
+
+protected:
+ AudioALSAPlaybackDataDispatcher();
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSAPlaybackDataDispatcher *mAudioALSAPlaybackDataDispatcher;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_PLAYBACK_DATA_DISPATCHER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerAAudio.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerAAudio.h
new file mode 100644
index 0000000..b3b1c7a
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerAAudio.h
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_AAUDIO_H
+#define ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_AAUDIO_H
+
+#include "AudioALSAPlaybackHandlerBase.h"
+
+
+namespace android {
+
+class AudioALSAPlaybackHandlerAAudio : public AudioALSAPlaybackHandlerBase {
+public:
+ AudioALSAPlaybackHandlerAAudio(const stream_attribute_t *stream_attribute_source);
+ virtual ~AudioALSAPlaybackHandlerAAudio();
+
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t output_devices);
+
+
+ /**
+ * write data to audio hardware
+ */
+ virtual ssize_t write(const void *buffer, size_t bytes);
+
+ virtual status_t setFilterMng(AudioMTKFilterManager *pFilterMng);
+
+
+ /**
+ * low latency
+ */
+ virtual status_t setScreenState(bool mode, size_t buffer_size, size_t reduceInterruptSize, bool bforce = false);
+
+
+ /**
+ * AAudio MMAP
+ */
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t createMmapBuffer(int32_t min_size_frames,
+ struct audio_mmap_buffer_info *info);
+ virtual status_t getMmapPosition(struct audio_mmap_position *position);
+
+private:
+
+ /**
+ * AAudio MMAP
+ */
+ int64_t mTime_nanoseconds;
+ int32_t mPosition_frames;
+ int32_t mMin_size_frames;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_AAUDIO_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerBTCVSD.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerBTCVSD.h
new file mode 100644
index 0000000..ea76b3c
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerBTCVSD.h
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_BT_CVSD_H
+#define ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_BT_CVSD_H
+
+#include "AudioALSAPlaybackHandlerBase.h"
+
+namespace android {
+
+class WCNChipController;
+class AudioALSACaptureDataProviderEchoRefBTCVSD;
+class AudioBTCVSDControl;
+
+class AudioALSAPlaybackHandlerBTCVSD : public AudioALSAPlaybackHandlerBase {
+public:
+ AudioALSAPlaybackHandlerBTCVSD(const stream_attribute_t *stream_attribute_source);
+ virtual ~AudioALSAPlaybackHandlerBTCVSD();
+
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t output_devices);
+
+ virtual int getLatency();
+
+ /**
+ * write data to audio hardware
+ */
+ virtual ssize_t write(const void *buffer, size_t bytes);
+
+
+ /**
+ * get hardware buffer info (framecount)
+ */
+ virtual status_t getHardwareBufferInfo(time_info_struct_t *HWBuffer_Time_Info __unused) { return INVALID_OPERATION; }
+
+
+private:
+ /**
+ * For echo ref SW implementation
+ */
+ bool writeEchoRefDataToDataProvider(AudioALSACaptureDataProviderEchoRefBTCVSD *dataProvider, const char *echoRefData, uint32_t dataSize);
+ status_t updateStartTimeStamp();
+
+ stream_attribute_t mStreamAttributeTargetEchoRef; // to echoref
+ struct timespec mEchoRefStartTime;
+ uint32_t mTotalEchoRefBufSize;
+
+ AudioALSACaptureDataProviderEchoRefBTCVSD *mDataProviderEchoRefBTCVSD;
+ WCNChipController *mWCNChipController;
+ AudioBTCVSDControl *mAudioBTCVSDControl;
+ struct mixer *mMixer;
+ bool mInitWrite;
+ unsigned int mWrittenFrame;
+
+ int mFd2;
+
+ struct timespec mNewtime, mOldtime;
+ double latencyTime[4];
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_BT_CVSD_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerBTSCO.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerBTSCO.h
new file mode 100644
index 0000000..9e55867
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerBTSCO.h
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_BT_SCO_H
+#define ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_BT_SCO_H
+
+#include "AudioALSAPlaybackHandlerBase.h"
+
+namespace android {
+
+class WCNChipController;
+
+class AudioALSAPlaybackHandlerBTSCO : public AudioALSAPlaybackHandlerBase {
+public:
+ AudioALSAPlaybackHandlerBTSCO(const stream_attribute_t *stream_attribute_source);
+ virtual ~AudioALSAPlaybackHandlerBTSCO();
+
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t output_devices);
+
+ /**
+ * write data to audio hardware
+ */
+ virtual ssize_t write(const void *buffer, size_t bytes);
+
+
+
+private:
+ WCNChipController *mWCNChipController;
+
+ struct timespec mNewtime, mOldtime;
+ double latencyTime[3];
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_BT_SCO_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerBase.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerBase.h
new file mode 100644
index 0000000..80ac8d7
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerBase.h
@@ -0,0 +1,366 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_BASE_H
+#define ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_BASE_H
+
+#include <tinyalsa/asoundlib.h> // TODO(Harvey): move it
+#include "sound/compress_params.h"
+#include <tinycompress/tinycompress.h>
+#include <sound/asound.h>
+#include "sound/compress_offload.h"
+
+#include "AudioType.h"
+#include "AudioALSADeviceParser.h"
+#include <hardware/audio.h>
+#include "AudioALSANLEController.h"
+#include "MtkAudioComponent.h"
+
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+struct aurisys_lib_manager_t;
+struct aurisys_lib_manager_config_t;
+struct audio_pool_buf_t;
+struct data_buf_t;
+#endif
+
+typedef int (*audio_pcm_write_wrapper_fp_t)(struct pcm *pcm, const void *data, unsigned int count);
+
+
+#ifdef MTK_AUDIO_SCP_SUPPORT
+struct ipi_msg_t;
+#endif
+
+
+namespace android {
+
+class AudioALSADataProcessor;
+
+class AudioALSAHardwareResourceManager;
+
+class AudioMTKFilterManager;
+
+class AudioALSAHyBridNLEManager;
+
+class AudioMessengerIPI;
+
+struct WriteSmoother;
+
+
+
+class AudioALSAPlaybackHandlerBase {
+
+public:
+ virtual ~AudioALSAPlaybackHandlerBase();
+
+
+ /**
+ * set handler index
+ */
+ inline void setIdentity(const uint32_t identity) { mIdentity = identity; }
+ inline uint32_t getIdentity() const { return mIdentity; }
+
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open() = 0;
+ virtual status_t close() = 0;
+ virtual status_t routing(const audio_devices_t output_devices) = 0;
+
+ virtual int pause() { return -ENODATA; }
+ virtual int resume() { return -ENODATA; }
+ virtual int flush() { return 0; }
+ virtual int drain(audio_drain_type_t type __unused) { return 0; }
+ virtual status_t setVolume(uint32_t vol __unused) { return INVALID_OPERATION; }
+
+ virtual int getLatency();
+
+ virtual int setSuspend(bool suspend __unused) { return 0; }
+
+ /**
+ * write data to audio hardware
+ */
+ virtual ssize_t write(const void *buffer, size_t bytes) = 0;
+ virtual int preWriteOperation(const void *buffer, size_t bytes);
+
+ /**
+ * Post processing
+ */
+ virtual status_t setFilterMng(AudioMTKFilterManager *pFilterMng);
+
+
+ /**
+ * low latency
+ */
+ virtual status_t setScreenState(bool mode, size_t buffer_size, size_t reduceInterruptSize, bool bforce = false);
+
+
+ /**
+ * get hardware buffer info (framecount)
+ */
+ virtual status_t getHardwareBufferInfo(time_info_struct_t *HWBuffer_Time_Info);
+
+ virtual status_t get_timeStamp(unsigned long *frames, unsigned int *samplerate);
+
+ virtual status_t updateHardwareBufferInfo(size_t sourceWrittenBytes, uint32_t targetWrittenBytes);
+
+ playback_handler_t getPlaybackHandlerType();
+
+ /**
+ * get stream attribute for kernel buffer
+ */
+ const stream_attribute_t *getStreamAttributeTarget() { return &mStreamAttributeTarget; }
+
+ status_t setComprCallback(stream_callback_t StreamCbk, void *CbkCookie);
+
+ /**
+ * set first write
+ */
+ virtual void setFirstDataWriteFlag(bool bFirstDataWrite) { mFirstDataWrite = bFirstDataWrite; }
+
+ virtual uint64_t getBytesWriteKernel() { return mBytesWriteKernel; }
+
+ virtual void resetBytesWriteKernel() { mBytesWriteKernel = 0; }
+
+ /**
+ * update mode
+ */
+ virtual int updateAudioMode(audio_mode_t mode);
+
+#ifdef MTK_AUDIODSP_SUPPORT
+ /* dsp pcm dump */
+ static void processDmaMsgWrapper(struct ipi_msg_t *msg,
+ void *buf,
+ uint32_t size,
+ void *arg);
+
+ void get_task_pcmdump_info(int task_id, int param1, void **pcm_dump);
+ void set_task_pcmdump_info(int task_id, int param1, void *pcm_dump);
+ int setDspDumpWakelock(bool condition);
+ void processDmaMsg(struct ipi_msg_t *msg,
+ void *buf,
+ uint32_t size);
+#endif
+ /**
+ * update offload routing status
+ */
+ virtual bool setOffloadRoutingFlag(bool enable) { return enable;}
+
+
+ /**
+ * write smoother
+ */
+ virtual void updateSmootherTime(const uint64_t bufferTimeUs);
+
+ /**
+ * AAudio MMAP
+ */
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t createMmapBuffer(int32_t min_size_frames,
+ struct audio_mmap_buffer_info *info);
+ virtual status_t getMmapPosition(struct audio_mmap_position *position);
+
+
+protected:
+ AudioALSAPlaybackHandlerBase(const stream_attribute_t *stream_attribute_source);
+
+ AudioMessengerIPI *mAudioMessengerIPI;
+
+
+ /**
+ * pcm driver open/close
+ */
+ status_t openPcmDriver(const unsigned int device); // TODO(Harvey): Query device by string
+ status_t openPcmDriverWithFlag(const unsigned int device, unsigned int flag);
+ status_t openComprDriver(const unsigned int device);
+
+
+ status_t closePcmDriver();
+ status_t closeComprDriver();
+
+ /**
+ * pcm driver list
+ */
+ status_t ListPcmDriver(const unsigned int card, const unsigned int device);
+
+ /**
+ * pcm write function
+ */
+ status_t pcmWrite(struct pcm *pcm, const void *data, unsigned int count);
+
+ /**
+ * stereo to mono for speaker
+ */
+ status_t doStereoToMonoConversionIfNeed(void *buffer, size_t bytes);
+
+
+ /**
+ * Post processing
+ */
+ status_t initPostProcessing();
+ status_t deinitPostProcessing();
+ status_t doPostProcessing(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes);
+
+ /**
+ * Dc Removal
+ */
+ int32 initDcRemoval();
+ int32 deinitDcRemoval();
+ int32 doDcRemoval(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes);
+
+ /**
+ * Bli SRC
+ */
+ status_t initBliSrc();
+ status_t deinitBliSrc();
+ status_t doBliSrc(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes);
+
+
+ /**
+ * Bit Converter
+ */
+ pcm_format transferAudioFormatToPcmFormat(const audio_format_t audio_format) const;
+ status_t initBitConverter();
+ status_t deinitBitConverter();
+ status_t doBitConversion(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes);
+
+ status_t initDataPending();
+ status_t DeinitDataPending();
+ status_t dodataPending(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes);
+
+
+ /**
+ * NLE processing
+ */
+ status_t initNLEProcessing();
+ status_t deinitNLEProcessing();
+ status_t doNLEProcessing(void *pInBuffer, size_t inBytes);
+ playback_handler_t mPlaybackHandlerType;
+
+ AudioALSAHardwareResourceManager *mHardwareResourceManager;
+
+ const stream_attribute_t *mStreamAttributeSource; // from stream out
+ stream_attribute_t mStreamAttributeTarget; // to audio hw
+ bool IsVoIPEnable(void) { return mStreamAttributeSource->mVoIPEnable; }
+
+ struct pcm_config mConfig; // TODO(Harvey): move it to AudioALSAHardwareResourceManager later
+ struct pcm *mPcm; // TODO(Harvey): move it to AudioALSAHardwareResourceManager & AudioALSAPlaybackDataDispatcher later
+ String8 mApTurnOnSequence;
+ String8 mApTurnOnSequence2;
+ String8 mApTurnOnSequenceDsp;
+ String8 mApTurnOnSequence3;
+
+ struct compr_config mComprConfig;
+ struct compress *mComprStream;
+ stream_callback_t mStreamCbk;
+ void *mCbkCookie;
+
+ /**
+ * Post processing
+ */
+ AudioMTKFilterManager *mAudioFilterManagerHandler;
+ char *mPostProcessingOutputBuffer;
+ uint32_t mPostProcessingOutputBufferSize;
+ bool mFirstDataWrite;
+
+ /**
+ * DcRemoval
+ */
+ MtkAudioDcRemoveBase *mDcRemove;
+ char *mDcRemoveWorkBuffer;
+ uint32_t mDcRemoveBufferSize;
+ /**
+ * Bli SRC
+ */
+ MtkAudioSrcBase *mBliSrc;
+ char *mBliSrcOutputBuffer;
+
+
+ /**
+ * Bit Converter
+ */
+ MtkAudioBitConverterBase *mBitConverter;
+ char *mBitConverterOutputBuffer;
+
+ /**
+ * data Pending
+ */
+ char *mdataPendingOutputBuffer;
+ char *mdataPendingTempBuffer;
+ uint32_t mdataPendingOutputBufferSize;
+ uint32_t mdataPendingRemindBufferSize;
+ uint32_t mDataAlignedSize;
+ bool mDataPendingForceUse;
+ /**
+ * NLE Control
+ */
+ AudioALSAHyBridNLEManager *mNLEMnger;
+ /**
+ * for debug PCM dump
+ */
+ void OpenPCMDump(const char *class_name);
+ void ClosePCMDump(void);
+ void WritePcmDumpData(const void *buffer, ssize_t bytes);
+ FILE *mPCMDumpFile;
+ static uint32_t mDumpFileNum;
+
+#ifdef MTK_AUDIODSP_SUPPORT
+ void OpenPCMDumpDSP(const char *className);
+ void ClosePCMDumpDSP(void);
+ FILE *mPCMDumpFileDSP;
+ static uint32_t mDumpFileNumDSP;
+#endif
+
+ struct mixer *mMixer;
+ uint64_t mBytesWriteKernel;
+ bool mTimeStampValid;
+
+ int mHalQueuedFrame;
+
+
+ /*
+ * =============================================================================
+ * Aurisys Framework 2.0
+ * =============================================================================
+ */
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ void CreateAurisysLibManager();
+ void InitArsiTaskConfig(struct aurisys_lib_manager_config_t *pManagerConfig);
+ void InitBufferConfig(struct aurisys_lib_manager_t *manager);
+ void DestroyAurisysLibManager();
+ uint32_t GetTransferredBufferSize(uint32_t sourceBytes,
+ const stream_attribute_t *source,
+ const stream_attribute_t *target);
+
+ struct aurisys_lib_manager_t *mAurisysLibManager;
+ struct aurisys_lib_manager_config_t *mManagerConfig;
+ uint32_t mAurisysScenario;
+
+ audio_pool_buf_t *mAudioPoolBufUlIn;
+ audio_pool_buf_t *mAudioPoolBufUlOut;
+ audio_pool_buf_t *mAudioPoolBufDlIn;
+ audio_pool_buf_t *mAudioPoolBufDlOut;
+
+ uint32_t mTransferredBufferSize;
+
+ struct data_buf_t *mLinearOut;
+#endif
+
+ bool mIsNeedUpdateLib;
+
+ struct WriteSmoother *mSmoother;
+
+
+
+private:
+ AudioALSADataProcessor *mDataProcessor;
+
+ uint32_t mIdentity; // key for mPlaybackHandlerVector
+ unsigned int mPcmflag;
+ audio_pcm_write_wrapper_fp_t audio_pcm_write_wrapper_fp;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_BASE_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerDsp.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerDsp.h
new file mode 100644
index 0000000..f590dda
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerDsp.h
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_DSP_H
+#define ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_DSP_H
+
+#include "AudioALSAPlaybackHandlerBase.h"
+#include "AudioDspType.h"
+struct aurisys_dsp_config_t;
+
+
+namespace android {
+
+class AudioDspStreamManager;
+
+class AudioALSAPlaybackHandlerDsp : public AudioALSAPlaybackHandlerBase {
+
+public:
+ AudioALSAPlaybackHandlerDsp(const stream_attribute_t *stream_attribute_source);
+ virtual ~AudioALSAPlaybackHandlerDsp();
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+
+ virtual status_t routing(const audio_devices_t output_devices);
+
+ /**
+ * write data to audio hardware
+ */
+ virtual ssize_t write(const void *buffer, size_t bytes);
+ virtual int preWriteOperation(const void *buffer __unused, size_t bytes __unused) { return 0; }
+ virtual int updateAudioMode(audio_mode_t mode __unused) { return 0; }
+ virtual status_t setFilterMng(AudioMTKFilterManager *pFilterMng);
+
+ /**
+ * low latency
+ */
+ virtual status_t setScreenState(bool mode, size_t buffer_size, size_t reduceInterruptSize, bool bforce = false);
+
+ /* dsp pcm API*/
+ status_t openDspHwPcm();
+ status_t openDspPcmDriverWithFlag(const unsigned int device, unsigned int flag);
+ status_t opeDspPcmDriver(const unsigned int device);
+ status_t closeDspPcmDriver();
+
+private:
+ struct timespec mNewtime, mOldtime;
+ bool deviceSupportHifi(audio_devices_t outputdevice);
+ uint32_t chooseTargetSampleRate(uint32_t SampleRate, audio_devices_t outputdevice);
+ uint32_t getLowJitterModeSampleRate(void);
+ int setAfeDspShareMem(unsigned int flag, bool condition);
+ int setStreamState(unsigned int flag, bool condition);
+ int setDspRuntimeEn(bool condition);
+ struct pcm_config mDsphwConfig;
+ AudioDspStreamManager *mDspStreamManager;
+
+ struct pcm *mDspHwPcm;
+ double latencyTime[3];
+ bool mForceMute;
+ int mCurMuteBytes;
+ int mStartMuteBytes;
+ bool mSupportNLE;
+
+
+ uint8_t mTaskScene;
+ struct aurisys_dsp_config_t *mAurisysDspConfig;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_DSP_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerFMTransmitter.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerFMTransmitter.h
new file mode 100644
index 0000000..26c63d2
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerFMTransmitter.h
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_FM_TRANSMITTER_H
+#define ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_FM_TRANSMITTER_H
+
+#include "AudioALSAPlaybackHandlerBase.h"
+
+namespace android {
+
+class WCNChipController;
+
+class AudioALSAPlaybackHandlerFMTransmitter : public AudioALSAPlaybackHandlerBase {
+public:
+ AudioALSAPlaybackHandlerFMTransmitter(const stream_attribute_t *stream_attribute_source);
+ virtual ~AudioALSAPlaybackHandlerFMTransmitter();
+
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t output_devices);
+
+ /**
+ * write data to audio hardware
+ */
+ virtual ssize_t write(const void *buffer, size_t bytes);
+
+
+
+private:
+ WCNChipController *mWCNChipController;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_FM_TRANSMITTER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerFast.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerFast.h
new file mode 100644
index 0000000..8d300a0
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerFast.h
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_FAST_H
+#define ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_FAST_H
+
+#include "AudioALSAPlaybackHandlerBase.h"
+
+namespace android {
+
+class AudioALSAPlaybackHandlerFast : public AudioALSAPlaybackHandlerBase {
+public:
+ AudioALSAPlaybackHandlerFast(const stream_attribute_t *stream_attribute_source);
+ virtual ~AudioALSAPlaybackHandlerFast();
+
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+
+ virtual status_t routing(const audio_devices_t output_devices);
+
+ /**
+ * write data to audio hardware
+ */
+ virtual ssize_t write(const void *buffer, size_t bytes);
+
+ virtual status_t setFilterMng(AudioMTKFilterManager *pFilterMng);
+
+
+ /**
+ * low latency
+ */
+ virtual status_t setScreenState(bool mode, size_t buffer_size, size_t reduceInterruptSize, bool bforce = false);
+
+private:
+ struct timespec mNewtime, mOldtime;
+ bool SetLowJitterMode(bool bEnable, uint32_t SampleRate);
+ uint32_t ChooseTargetSampleRate(uint32_t SampleRate, audio_devices_t outputdevice);
+ bool DeviceSupportHifi(audio_devices_t outputdevice);
+ uint32_t GetLowJitterModeSampleRate(void);
+ double latencyTime[3];
+
+ virtual status_t dataTransferBeforeWrite(void *addr, uint32_t size);
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_FAST_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerMixer.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerMixer.h
new file mode 100644
index 0000000..fac524e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerMixer.h
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_MIXER_H
+#define ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_MIXER_H
+
+#include "AudioALSAPlaybackHandlerBase.h"
+
+namespace android {
+
+class AudioMixerOut;
+class AudioALSAPlaybackHandlerMixer : public AudioALSAPlaybackHandlerBase {
+public:
+ AudioALSAPlaybackHandlerMixer(const stream_attribute_t *stream_attribute_source);
+ virtual ~AudioALSAPlaybackHandlerMixer();
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t output_devices);
+
+ virtual int getLatency();
+
+ virtual int setSuspend(bool suspend);
+
+ /**
+ * write data to audio hardware
+ */
+ virtual ssize_t write(const void *buffer, size_t bytes);
+ virtual int preWriteOperation(const void *buffer __unused, size_t bytes __unused) { return 0; }
+ virtual int updateAudioMode(audio_mode_t mode __unused) { return 0; }
+
+ /**
+ * get hardware buffer info (framecount)
+ */
+ virtual status_t getHardwareBufferInfo(time_info_struct_t *HWBuffer_Time_Info);
+
+ /**
+ * low latency
+ */
+ virtual status_t setScreenState(bool mode, size_t buffer_size, size_t reduceInterruptSize, bool bforce = false);
+
+private:
+ AudioMixerOut *mMixerOut;
+
+ struct timespec mNewtime, mOldtime;
+ double latencyTime[3];
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_MIXER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerNormal.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerNormal.h
new file mode 100644
index 0000000..475bc75
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerNormal.h
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_NORMAL_H
+#define ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_NORMAL_H
+
+#include "AudioALSAPlaybackHandlerBase.h"
+
+
+namespace android {
+
+class AudioALSAPlaybackHandlerNormal : public AudioALSAPlaybackHandlerBase {
+public:
+ AudioALSAPlaybackHandlerNormal(const stream_attribute_t *stream_attribute_source);
+ virtual ~AudioALSAPlaybackHandlerNormal();
+
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t output_devices);
+
+ /**
+ * write data to audio hardware
+ */
+ virtual ssize_t write(const void *buffer, size_t bytes);
+
+ virtual status_t setFilterMng(AudioMTKFilterManager *pFilterMng);
+
+
+ /**
+ * low latency
+ */
+ virtual status_t setScreenState(bool mode, size_t buffer_size, size_t reduceInterruptSize, bool bforce = false);
+
+private:
+ struct timespec mNewtime, mOldtime;
+ bool SetLowJitterMode(bool bEnable, uint32_t SampleRate);
+ uint32_t ChooseTargetSampleRate(uint32_t SampleRate, audio_devices_t outputdevice);
+ bool DeviceSupportHifi(audio_devices_t outputdevice);
+ uint32_t GetLowJitterModeSampleRate(void);
+ uint32_t fillKernelBuffer(const uint32_t targetBufSize);
+#if defined(MTK_HIFIAUDIO_SUPPORT)
+ uint32_t UpdateKernelBufferSize(audio_devices_t outputdevice);
+#endif
+ struct pcm_config mHpImpedanceConfig;
+ struct pcm *mHpImpeDancePcm;
+ double latencyTime[3];
+
+ //#ifdef MTK_AUDIO_SW_DRE
+ bool mForceMute;
+ int mCurMuteBytes;
+ int mStartMuteBytes;
+ char *mAllZeroBlock;
+ //#endif
+
+ bool mSupportNLE;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_NORMAL_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerOffload.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerOffload.h
new file mode 100644
index 0000000..b2530f5
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerOffload.h
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSAPlaybackHandlerBase.h"
+#include "sound/compress_params.h"
+#include <tinycompress/tinycompress.h>
+#include <sound/asound.h>
+#include "sound/compress_offload.h"
+#include <pthread.h>
+#include <cutils/list.h>
+
+
+#ifndef ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_OFFLOAD_H
+#define ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_OFFLOAD_H
+
+
+namespace android {
+#define OFFLOAD_BUFFER_SIZE_PER_ACCESSS (32768)
+
+
+enum {
+ OFFLOAD_ACTION_OPEN = 0,
+ OFFLOAD_ACTION_START = 1,
+ OFFLOAD_ACTION_PAUSE = 2,
+ OFFLOAD_ACTION_RESUME = 3,
+ OFFLOAD_ACTION_STOP = 4,
+ OFFLOAD_ACTION_CLOSE = 5,
+};
+
+
+enum {
+ OFFLOAD_STATE_IDLE,
+ OFFLOAD_STATE_PLAYING,
+ OFFLOAD_STATE_PAUSED,
+ OFFLOAD_STATE_EARLY_DRAIN,
+ OFFLOAD_STATE_DRAINED,
+};
+
+enum {
+ OFFLOAD_WRITE_EMPTY,
+ OFFLOAD_WRITE_REMAIN,
+ OFFLOAD_WRITE_ERROR,
+};
+
+
+enum {
+ OFFLOAD_CMD_WRITE,
+ OFFLOAD_CMD_DRAIN,
+ OFFLOAD_CMD_PAUSE,
+ OFFLOAD_CMD_RESUME,
+ OFFLOAD_CMD_CLOSE,
+ OFFLOAD_CMD_FLUSH,
+};
+
+
+enum {
+ OFFLOAD_MODE_GDMA = 0,
+ OFFLOAD_MODE_SW,
+ OFFLOAD_MODE_DSP,
+};
+
+struct tstamp {
+ unsigned long frames;
+ unsigned int samplerate;
+};
+
+
+struct offload_cmd {
+ struct listnode node;
+ int cmd;
+};
+struct offload_thread_property {
+
+ pthread_mutex_t offload_mutex;
+ pthread_cond_t offload_cond;
+ struct listnode offload_cmd_list;
+ pthread_t offload_pthread;
+};
+
+struct offload_stream_property {
+ int offload_state;
+ unsigned int fragment_size;
+ int num_channels;
+ int sample_rate;
+ int bit_rate;
+ unsigned int offload_gain[2];
+ void *tmpbsBuffer;
+ int remain_write;
+};
+
+struct offload_write_info {
+ void *tmpBuffer;
+ unsigned int bytes;
+};
+
+
+struct offload_buffer {
+ size_t fragment_size;
+ int fragments;
+};
+
+struct offload_codec {
+ __u32 id;
+ __u32 ch_in;
+ __u32 ch_out;
+ __u32 sample_rate;
+ __u32 bit_rate;
+ __u32 rate_control;
+ __u32 profile;
+ __u32 level;
+ __u32 ch_mode;
+ __u32 format;
+ __u32 align;
+ union snd_codec_options options;
+ __u32 reserved[3];
+};
+
+
+struct snd_offload_params {
+ struct offload_buffer buffer;
+ struct offload_codec codec;
+};
+
+
+class AudioALSAPlaybackHandlerOffload : public AudioALSAPlaybackHandlerBase {
+public:
+ AudioALSAPlaybackHandlerOffload(const stream_attribute_t *stream_attribute_source);
+ virtual ~AudioALSAPlaybackHandlerOffload();
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual int pause();
+ virtual int resume();
+ virtual int flush();
+ virtual status_t routing(const audio_devices_t output_devices);
+ virtual status_t setVolume(uint32_t vl);
+
+ /**
+ * write data to audio hardware
+ */
+ virtual ssize_t write(const void *buffer, size_t bytes);
+
+ virtual int drain(audio_drain_type_t type);
+
+
+ virtual status_t setFilterMng(AudioMTKFilterManager *pFilterMng);
+
+ int process_write();
+ int process_writewait();
+ int process_drain();
+
+ void offload_callback(stream_callback_event_t event);
+
+ void offload_initialize();
+ void set_pcmdump(int enable);
+ virtual bool setOffloadRoutingFlag(bool enable);
+ bool getOffloadRoutingFlag();
+ int isformatnotsupport();
+ int setDspRuntimeEn(bool condition);
+
+protected:
+
+private:
+ //void set_codec_samplerate(int pcmindex, int cardindex);
+ int setAfeDspSharemem(bool condition);
+ uint32_t ChooseTargetSampleRate(uint32_t SampleRate);
+ bool SetLowJitterMode(bool bEnable, uint32_t SampleRate);
+ uint32_t GetLowJitterModeSampleRate();
+ audio_format_t mFormat;
+ uint32_t mWriteBsbufSize;
+ bool mReady;
+ //struct pcm_config mOffloadPcmConfig;
+ //struct pcm *mOffloadPcmOut;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_NORMAL_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerSpeakerProtection.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerSpeakerProtection.h
new file mode 100644
index 0000000..a6c9843
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerSpeakerProtection.h
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_SPEAKERPROTECTION_H
+#define ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_SPEAKERPROTECTION_H
+
+#include "AudioALSAPlaybackHandlerBase.h"
+#include "AudioALSAPcmDataCaptureIn.h"
+#define DSM_CHANNELS 1
+//#define DEBUG_LATENCY
+
+typedef struct mlds_task_config_t mlds_task_config_t;
+typedef struct mlds_interface mlds_interface;
+
+namespace android {
+
+//for Maxim
+static void (*DsmConfigure)(int usecase, void *dsm_handler);
+static unsigned int (*DsmSetParams)(void *ipModuleHandler, int iCommandNumber, void *ipParamsBuffer);
+static unsigned int (*DsmGetParams)(void *ipModuleHandler, int iCommandNum, void *opParams);
+
+class AudioALSAPlaybackHandlerSpeakerProtection : public AudioALSAPlaybackHandlerBase {
+public:
+ AudioALSAPlaybackHandlerSpeakerProtection(const stream_attribute_t *stream_attribute_source);
+ virtual ~AudioALSAPlaybackHandlerSpeakerProtection();
+
+ status_t setParameters(const String8 &keyValuePairs);
+ String8 getParameters(const String8 &keys);
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t output_devices);
+
+ /**
+ * write data to audio hardware
+ */
+ virtual ssize_t write(const void *buffer, size_t bytes);
+ virtual status_t setFilterMng(AudioMTKFilterManager *pFilterMng);
+
+ /**
+ * low latency
+ */
+ virtual status_t setScreenState(bool mode, size_t lowLatencyHalBufferSize, size_t reduceInterruptSize, bool bforce = false);
+
+ unsigned int GetSampleSize(unsigned int Format);
+ unsigned int GetFrameSize(unsigned int channels, unsigned int Format);
+
+ // post processing interface
+ virtual status_t SpeakerProtectionInterfaceInit(unsigned int SampleRate, unsigned int chennels, unsigned int Format);
+ virtual status_t SpeakerProtectionInterfaceDeinit();
+ virtual status_t Initmldsconfig(const stream_attribute_t *mStreamAttributeSource, stream_attribute_t *mStreamAttributeTarget);
+ virtual status_t SpeakerBufferInit(void);
+ virtual status_t SpeakerBufferDeInit(void);
+ status_t DoSpeakerProtionInterfaceProcessing(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes);
+ status_t DoSpeakerProctionPacking(int *Dsmtempbuffer, int ValidInputBuffersize);
+ status_t DoSpeakerProctionUnPacking(int *pbuffer, int ValidInputBuffersize);
+ status_t MonoToStereo(int *pbuffer, int ValidInputBuffersize);
+
+ status_t EnableIVTask(pcm_config mPcm_config);
+ status_t DisableIVTask(void);
+ status_t CopyIVbuffer(void *Input, short *Rbuffer, short *Lbuffer, unsigned int samplecount);
+ void OpenPCMIVDump(const char *class_name);
+ void ClosePCMIVDump();
+
+ // using dl to do function open
+ virtual status_t InitmldsInterface();
+
+ FILE *mPCMPlayIVDumpFile;
+ int mDumpPlayIVFileNum;
+
+private:
+#ifdef DEBUG_LATENCY
+ struct timespec mNewtime, mOldtime;
+ double latencyTime[3];
+#endif
+
+ uint32_t ChooseTargetSampleRate(uint32_t SampleRate);
+
+ // for MAXIM porting
+ void *mDsmConfigHandle;
+ void *mDsmInterfaceHandle;
+ void *dsm_handler;
+ void *mMlds_handle;
+ unsigned int mu4DsmMemSize;
+ int mDsmMemSize;
+ int *mDsmMemBuffer;
+ int mDsmBuffer[DSM_CHANNELS * 4 + 1 ];
+ int remaining_bytes;
+ const int mDsmBufferSize = 1024 * 32;
+ unsigned int mDsmSamples;
+ unsigned int mDsmChannels;
+ unsigned int mInputChannels;
+ unsigned int mDsmSampleRate;
+ int *mDsmpcmOut, *mDsmProcessingbuffer;
+ int *mSpeakerChannelProcessingBuffer;
+
+ // mlds interface
+ mlds_task_config_t *mmlds_task_config;
+
+ // IV data Process
+ AudioALSAPcmDataCaptureIn *mAudioAlsaPcmIn;
+ int *mDsmiData, *mDsmvData, *mDsmIvReadData;
+ struct pcm_config mPcmIvConfig;
+
+ //mlds_interface pointer pointer
+ mlds_interface *mMlds_Interace_pointer;
+
+ bool mBypassSpeakerProtection;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_SPEAKERPROTECTION_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerSpeakerProtectionDsp.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerSpeakerProtectionDsp.h
new file mode 100644
index 0000000..167319f
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerSpeakerProtectionDsp.h
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_SPEAKERPROTECTION_DSP_H
+#define ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_SPEAKERPROTECTION_DSP_H
+
+#include "AudioALSAPlaybackHandlerBase.h"
+
+
+namespace android {
+class AudioALSAPlaybackHandlerSpeakerProtectionDsp : public AudioALSAPlaybackHandlerBase {
+public:
+ AudioALSAPlaybackHandlerSpeakerProtectionDsp(const stream_attribute_t *stream_attribute_source);
+ virtual ~AudioALSAPlaybackHandlerSpeakerProtectionDsp();
+
+ status_t setParameters(const String8 &keyValuePairs);
+ String8 getParameters(const String8 &keys);
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t output_devices);
+
+ /**
+ * write data to audio hardware
+ */
+ virtual ssize_t write(const void *buffer, size_t bytes);
+ virtual status_t setFilterMng(AudioMTKFilterManager *pFilterMng);
+
+ /**
+ * low latency
+ */
+ virtual status_t setScreenState(bool mode, size_t buffer_size, size_t reduceInterruptSize, bool bforce = false);
+
+
+ unsigned int GetSampleSize(unsigned int Format);
+ unsigned int GetFrameSize(unsigned int channels, unsigned int Format);
+ int initSmartPaConfig();
+
+ /* scp spk pcm API */
+ status_t openScpSpkPcmDriverWithFlag(const unsigned int device, unsigned int flag);
+ status_t openScpSpkPcmDriver(const unsigned int dlDevice, const unsigned int ivDevice);
+ status_t openScpSpkHwPcm();
+ status_t closeScpSpkHwPcm();
+
+private:
+ struct timespec mNewtime, mOldtime;
+ uint32_t ChooseTargetSampleRate(uint32_t SampleRate, audio_devices_t outputdevice);
+ int setPcmDump(bool benable);
+ double latencyTime[3];
+ struct pcm_config mScpSpkHwOutConfig;
+ struct pcm_config mScpSpkHwInConfig;
+ struct pcm *mScpSpkDlHwPcm;
+ struct pcm *mScpSpkIvHwPcm;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_SPEAKERPROTECTION_DSP_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerSphDL.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerSphDL.h
new file mode 100644
index 0000000..4ccd0f9
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerSphDL.h
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_SPEECH_DL_H
+#define ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_SPEECH_DL_H
+
+#include "AudioALSAPlaybackHandlerBase.h"
+#include "AudioALSAPcmDataCaptureIn.h"
+#define DSM_CHANNELS 1
+
+typedef struct mlds_task_config_t mlds_task_config_t;
+typedef struct mlds_interface mlds_interface;
+
+
+namespace android {
+
+class AudioALSAPlaybackHandlerSphDL : public AudioALSAPlaybackHandlerBase {
+public:
+ AudioALSAPlaybackHandlerSphDL(const stream_attribute_t *stream_attribute_source);
+ virtual ~AudioALSAPlaybackHandlerSphDL();
+
+ status_t setParameters(const String8 &keyValuePairs);
+ String8 getParameters(const String8 &keys);
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t output_devices);
+
+ /**
+ * write data to audio hardware
+ */
+ virtual ssize_t write(const void *buffer, size_t bytes);
+ virtual status_t setFilterMng(AudioMTKFilterManager *pFilterMng);
+
+ /**
+ * low latency
+ */
+ virtual status_t setScreenState(bool mode, size_t lowLatencyHalBufferSize, size_t reduceInterruptSize, bool bforce = false);
+
+ unsigned int GetSampleSize(unsigned int Format);
+ unsigned int GetFrameSize(unsigned int channels, unsigned int Format);
+
+ // post processing interface
+ virtual status_t SpeakerProtectionInterfaceInit(unsigned int SampleRate, unsigned int chennels, unsigned int Format);
+ virtual status_t SpeakerProtectionInterfaceDeinit();
+ virtual status_t Initmldsconfig(const stream_attribute_t *mStreamAttributeSource, stream_attribute_t *mStreamAttributeTarget);
+ virtual status_t SpeakerBufferInit(void);
+ virtual status_t SpeakerBufferDeInit(void);
+ status_t DoSpeakerProtionInterfaceProcessing(void *pInBuffer, uint32_t inBytes, void **ppOutBuffer, uint32_t *pOutBytes);
+ status_t DoSpeakerProctionPacking(int *Dsmtempbuffer, int ValidInputBuffersize);
+ status_t DoSpeakerProctionUnPacking(int *pbuffer, int ValidInputBuffersize);
+ status_t MonoToStereo(int *pbuffer, int ValidInputBuffersize);
+
+ status_t EnableIVTask(pcm_config mPcm_config);
+ status_t DisableIVTask(void);
+ status_t CopyIVbuffer(void *Input, short *Rbuffer, short *Lbuffer, unsigned int samplecount);
+ void OpenPCMIVDump(const char *class_name);
+ void ClosePCMIVDump();
+
+ // using dl to do function open
+ virtual status_t InitmldsInterface();
+
+ FILE *mPCMPlayIVDumpFile;
+ int mDumpPlayIVFileNum;
+
+private:
+ struct timespec mNewtime, mOldtime;
+ uint32_t ChooseTargetSampleRate(uint32_t SampleRate, audio_devices_t outputdevice);
+ double latencyTime[3];
+
+
+ // for MAXIM porting
+ void *dsm_handler;
+ void *mMlds_handle;
+ unsigned int mu4DsmMemSize;
+ int mDsmMemSize;
+ int *mDsmMemBuffer;
+ int mDsmBuffer[DSM_CHANNELS * 4 + 1 ];
+ int remaining_bytes;
+ const int mDsmBufferSize = 1024 * 16;
+ unsigned int mDsmSamples;
+ unsigned int mDsmChannels;
+ unsigned int mInputChannels;
+ unsigned int mDsmSampleRate;
+ int *mDsmpcmIn, *mDsmpcmOut, *mDsmProcessingbuffer;
+ int *mSpeakerChannelProcessingBuffer;
+
+ // mlds interface
+ mlds_task_config_t *mmlds_task_config;
+
+ // IV data Process
+ AudioALSAPcmDataCaptureIn *mAudioAlsaPcmIn;
+ int *mDsmiData, *mDsmvData, *mDsmIvReadData;
+ struct pcm_config mPcmIvConfig;
+
+ //mlds_interface pointer pointer
+ mlds_interface *mMlds_Interace_pointer;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_SPEECH_DL_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerUsb.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerUsb.h
new file mode 100644
index 0000000..f02abe2
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerUsb.h
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_USB_H
+#define ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_USB_H
+
+#include "AudioALSAPlaybackHandlerBase.h"
+#include "AudioUSBPhoneCallController.h"
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+struct aurisys_lib_manager_t;
+struct arsi_task_config_t;
+struct audio_pool_buf_t;
+#endif
+extern "C" {
+ //#include <tinyalsa/asoundlib.h>
+#include "alsa_device_profile.h"
+#include "alsa_device_proxy.h"
+#include "alsa_logging.h"
+#include <audio_utils/channels.h>
+}
+
+namespace android {
+class AudioALSACaptureDataProviderEchoRefUsb;
+
+class AudioALSAPlaybackHandlerUsb : public AudioALSAPlaybackHandlerBase {
+public:
+ AudioALSAPlaybackHandlerUsb(const stream_attribute_t *stream_attribute_source);
+ virtual ~AudioALSAPlaybackHandlerUsb();
+
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t output_devices);
+ virtual void initUsbInfo(stream_attribute_t mStreamAttributeTargetUSB, alsa_device_proxy *proxy, size_t buffer_size);
+
+
+ /**
+ * write data to audio hardware
+ */
+ virtual ssize_t write(const void *buffer, size_t bytes);
+
+ virtual status_t setFilterMng(AudioMTKFilterManager *pFilterMng);
+
+
+ /**
+ * low latency
+ */
+ virtual status_t setScreenState(bool mode, size_t buffer_size, size_t reduceInterruptSize, bool bforce = false);
+
+ const stream_attribute_t getStreamAttributeTargetEchoRef() { return mStreamAttributeTargetEchoRef; }
+private:
+ /**
+ * For echo ref SW implementation
+ */
+ bool writeEchoRefDataToDataProvider(AudioALSACaptureDataProviderEchoRefUsb *dataProvider, const char *echoRefData, uint32_t dataSize);
+ status_t updateStartTimeStamp();
+ status_t loadUSBDeviceParam();
+ status_t getDeviceId(struct USBStream *stream);
+ uint32_t getUSBDeviceLatency(size_t deviceParamIdx);
+ status_t getDeviceParam(struct USBStream *stream);
+
+ stream_attribute_t mStreamAttributeTargetEchoRef; // to echoref
+ struct timespec mEchoRefStartTime;
+ uint32_t mTotalEchoRefBufSize;
+
+ AudioALSACaptureDataProviderEchoRefUsb *mDataProviderEchoRefUsb;
+ struct timespec mNewtime, mOldtime;
+ double latencyTime[3];
+
+ struct USBStream mUSBOutStream;
+ struct USBCallParam mParam;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_USB_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerVoice.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerVoice.h
new file mode 100644
index 0000000..8a0b1b5
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerVoice.h
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_VOICE_H
+#define ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_VOICE_H
+
+#include "AudioALSAPlaybackHandlerBase.h"
+
+namespace android {
+
+class BGSPlayer;
+class BGSPlayBuffer;
+class SpeechDriverInterface;
+
+
+class AudioALSAPlaybackHandlerVoice : public AudioALSAPlaybackHandlerBase {
+public:
+ AudioALSAPlaybackHandlerVoice(const stream_attribute_t *stream_attribute_source);
+ virtual ~AudioALSAPlaybackHandlerVoice();
+
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t output_devices);
+
+ /**
+ * write data to audio hardware
+ */
+ virtual ssize_t write(const void *buffer, size_t bytes);
+
+ uint32_t ChooseTargetSampleRate(uint32_t SampleRate);
+
+
+ /**
+ * get hardware buffer info (framecount)
+ */
+ virtual status_t getHardwareBufferInfo(time_info_struct_t *HWBuffer_Time_Info __unused) { return INVALID_OPERATION; }
+
+
+
+private:
+ SpeechDriverInterface *mSpeechDriver;
+ BGSPlayer *mBGSPlayer;
+ BGSPlayBuffer *mBGSPlayBuffer;
+
+ struct timespec mOpenTime, mCurTime;
+ uint64_t mWriteCnt;
+
+ uint64_t mLatencyUs;
+
+ struct timespec mNewtimeLatency, mOldtimeLatency;
+ uint64_t mLatencyTimeMs[3];
+
+ bool mBypassBgsSleep;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_VOICE_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerVoiceMixer.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerVoiceMixer.h
new file mode 100644
index 0000000..c4d3311
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAPlaybackHandlerVoiceMixer.h
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_VOICEMIXER_H
+#define ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_VOICEMIXER_H
+
+#include "AudioALSAPlaybackHandlerBase.h"
+
+namespace android {
+
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+class VoiceMixerPlayer;
+class VoiceMixerPlayBuffer;
+class SpeechDriverInterface;
+
+
+/*
+ * =============================================================================
+ * class
+ * =============================================================================
+ */
+class AudioALSAPlaybackHandlerVoiceMixer : public AudioALSAPlaybackHandlerBase {
+public:
+ AudioALSAPlaybackHandlerVoiceMixer(const stream_attribute_t *stream_attribute_source);
+ virtual ~AudioALSAPlaybackHandlerVoiceMixer() {}
+
+ /**
+ * open/close audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t output_devices);
+
+ /**
+ * write data to audio hardware
+ */
+ virtual ssize_t write(const void *buffer, size_t bytes);
+
+ virtual status_t setVolume(uint32_t vol __unused) { return NO_ERROR; }
+ /**
+ * get hardware buffer info (framecount)
+ */
+ virtual status_t getHardwareBufferInfo(time_info_struct_t *HWBuffer_Time_Info __unused) {
+ return INVALID_OPERATION;
+ }
+
+ uint32_t chooseTargetSampleRate(uint32_t sampleRate);
+ int configMixType(const uint8_t mixType);
+
+
+private:
+ SpeechDriverInterface *mSpeechDriver;
+ VoiceMixerPlayer *mVoiceMixerPlayer;
+ VoiceMixerPlayBuffer *mVoiceMixerPlayBuffer;
+
+ struct timespec mOpenTime, mCurTime;
+ uint64_t mWriteCnt;
+
+ uint64_t mLatencyUs;
+
+ struct timespec mNewtimeLatency, mOldtimeLatency;
+ uint64_t mLatencyTimeMs[3];
+
+ bool mBypassVoiceMixerSleep;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_PLAYBACK_HANDLER_VOICEMIXER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSASampleRateController.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSASampleRateController.h
new file mode 100644
index 0000000..ba1ba33
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSASampleRateController.h
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_SAMPLE_RATE_CONTROLLER_H
+#define ANDROID_AUDIO_ALSA_SAMPLE_RATE_CONTROLLER_H
+
+#include "AudioType.h"
+#include "AudioAssert.h"
+#include <AudioLock.h>
+
+namespace android {
+
+enum playback_scenario_mask_t {
+ PLAYBACK_SCENARIO_STREAM_OUT = 0,
+ PLAYBACK_SCENARIO_FM,
+ PLAYBACK_SCENARIO_ECHO_REF,
+ PLAYBACK_SCENARIO_ECHO_REF_EXT,
+ PLAYBACK_SCENARIO_VOW_BARGE_IN,
+ PLAYBACK_SCENARIO_COUNT
+};
+
+
+class AudioALSASampleRateController {
+public:
+ virtual ~AudioALSASampleRateController();
+
+ static AudioALSASampleRateController *getInstance();
+
+ virtual status_t setPrimaryStreamOutSampleRate(const uint32_t sample_rate);
+ uint32_t getPrimaryStreamOutSampleRate();
+
+
+ void setScenarioStatus(const playback_scenario_mask_t playback_scenario_mask);
+ void resetScenarioStatus(const playback_scenario_mask_t playback_scenario_mask);
+
+
+
+
+protected:
+ AudioALSASampleRateController();
+ bool hasActiveScenario();
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSASampleRateController *mAudioALSASampleRateController;
+
+ uint32_t mPrimaryStreamOutSampleRate;
+
+ int mScenarioReference[PLAYBACK_SCENARIO_COUNT];
+
+ AudioLock mLock;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_SAMPLE_RATE_CONTROLLER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSASpeechLoopbackController.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSASpeechLoopbackController.h
new file mode 100644
index 0000000..2846f3a
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSASpeechLoopbackController.h
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_SPEECH_LOOPBACK_CONTROLLER_H
+#define ANDROID_AUDIO_ALSA_SPEECH_LOOPBACK_CONTROLLER_H
+
+#include <tinyalsa/asoundlib.h> // TODO(Harvey): move it
+
+#include "AudioType.h"
+#include "SpeechType.h"
+
+#include <AudioLock.h>
+
+
+namespace android {
+
+class AudioALSAHardwareResourceManager;
+class SpeechDriverFactory;
+
+class AudioALSASpeechLoopbackController {
+public:
+ virtual ~AudioALSASpeechLoopbackController();
+
+ static AudioALSASpeechLoopbackController *getInstance();
+
+ virtual status_t open(const audio_devices_t output_devices, const audio_devices_t input_device);
+ virtual status_t close();
+ virtual status_t SetModemBTCodec(bool enable_codec);
+ virtual status_t OpenModemLoopbackControlFlow(const audio_devices_t input_device, const audio_devices_t output_device);
+ virtual status_t CloseModemLoopbackControlFlow(void);
+
+protected:
+ AudioALSASpeechLoopbackController();
+
+ AudioALSAHardwareResourceManager *mHardwareResourceManager;
+
+ SpeechDriverFactory *mSpeechDriverFactory;
+
+
+ AudioLock mLock;
+
+ struct pcm_config mConfig;
+
+ struct pcm *mPcmUL;
+ struct pcm *mPcmDL;
+ String8 mApTurnOnSequence;
+ String8 mApTurnOnSequence2;
+
+private:
+ static AudioALSASpeechLoopbackController *mSpeechLoopbackController; // singleton
+
+ //for BT SW BT CVSD loopback test
+ bool mUseBtCodec;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_SPEECH_LOOPBACK_CONTROLLER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSASpeechStreamController.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSASpeechStreamController.h
new file mode 100644
index 0000000..4b1819e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSASpeechStreamController.h
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_SPEECH_STREAM_CONTROLLER_H
+#define ANDROID_AUDIO_ALSA_SPEECH_STREAM_CONTROLLER_H
+
+#include <utils/threads.h>
+#include "AudioType.h"
+#include <AudioLock.h>
+#include "AudioALSAStreamManager.h"
+
+namespace android {
+class AudioALSAHardwareResourceManager;
+class AudioALSAStreamOut;
+class AudioALSAStreamIn;
+
+class AudioALSASpeechStreamController {
+public:
+ virtual ~AudioALSASpeechStreamController();
+ status_t EnableSpeechStreamThread(bool enable);
+ AudioALSAStreamManager *getStreamManager() {return mAudioMtkStreamManager;}
+ bool IsSpeechStreamThreadEnable(void);
+ pthread_mutex_t mSpeechStreamMutex;
+ pthread_cond_t mSphStream_Cond, mSpkMonitorActivate_Cond;
+ bool m_bThreadExit;
+ bool m_bEnabled;
+ static AudioALSASpeechStreamController *getInstance();
+ audio_devices_t GetStreamOutputDevice(void);
+ status_t SetStreamOutputDevice(audio_devices_t OutputDevices);
+
+protected:
+ AudioALSASpeechStreamController();
+
+ AudioALSAHardwareResourceManager *mHardwareResourceManager;
+
+ AudioLock mLock;
+
+ audio_mode_t mAudioMode;
+
+ audio_devices_t mRoutingForTty;
+
+ struct pcm *mPcmIn;
+ struct pcm *mPcmOut;
+
+private:
+ AudioALSAStreamManager *mAudioMtkStreamManager;
+ pthread_t mSpeechStreamThreadID;
+ static AudioALSASpeechStreamController *UniqueInstance; // singleton
+ static void *SpeechStreamThread(void *arg);
+ audio_devices_t mOutputDevices;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_SPEECH_PHONE_CALL_CONTROLLER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAStreamIn.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAStreamIn.h
new file mode 100644
index 0000000..be601a8
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAStreamIn.h
@@ -0,0 +1,283 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_STREAM_IN_H
+#define ANDROID_AUDIO_ALSA_STREAM_IN_H
+
+#include <utils/Mutex.h>
+
+#include <hardware_legacy/AudioMTKHardwareInterface.h>
+#include <media/AudioParameter.h>
+
+#include "AudioType.h"
+#include <AudioLock.h>
+#include "AudioSpeechEnhanceInfo.h"
+#include "AudioALSACaptureHandlerBase.h"
+
+namespace android {
+
+class AudioALSAStreamManager;
+class AudioALSACaptureHandlerBase;
+
+class AudioALSAStreamIn : public AudioMTKStreamInInterface {
+public:
+ AudioALSAStreamIn();
+ virtual ~AudioALSAStreamIn();
+
+ virtual status_t set(uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate,
+ status_t *status, audio_in_acoustics_t acoustics, uint32_t flags = 0);
+
+ /** return audio sampling rate in hz - eg. 44100 */
+ virtual uint32_t sampleRate() const;
+
+ /** return the input buffer size allowed by audio driver */
+ virtual size_t bufferSize() const;
+
+ /** return input channel mask */
+ virtual uint32_t channels() const;
+
+ /**
+ * return audio format in 8bit or 16bit PCM format -
+ * eg. AUDIO_FORMAT_PCM_16_BIT
+ */
+ virtual int format() const;
+
+ /** set the input gain for the audio driver. This method is for
+ * for future use */
+ virtual status_t setGain(float gain);
+
+ /** read audio buffer in from audio driver */
+ virtual ssize_t read(void *buffer, ssize_t bytes);
+
+ /** dump the state of the audio input device */
+ virtual status_t dump(int fd, const Vector<String16> &args);
+
+ /**
+ * Put the audio hardware input into standby mode. Returns
+ * status based on include/utils/Errors.h
+ */
+ virtual status_t standby(bool halRequest = true);
+ virtual bool getStandby();
+
+ // set/get audio input parameters. The function accepts a list of parameters
+ // key value pairs in the form: key1=value1;key2=value2;...
+ // Some keys are reserved for standard parameters (See AudioParameter class).
+ // If the implementation does not accept a parameter change while the output is
+ // active but the parameter is acceptable otherwise, it must return INVALID_OPERATION.
+ // The audio flinger will put the input in standby and then change the parameter value.
+ virtual status_t setParameters(const String8 &keyValuePairs);
+ virtual String8 getParameters(const String8 &keys);
+
+
+ // Return the amount of input frames lost in the audio driver since the last call of this function.
+ // Audio driver is expected to reset the value to 0 and restart counting upon returning the current value by this function call.
+ // Such loss typically occurs when the user space process is blocked longer than the capacity of audio driver buffers.
+ // Unit: the number of input audio frames
+ virtual unsigned int getInputFramesLost() const;
+ unsigned int getInputFlags() const;
+
+ /**
+ * Return a recent count of the number of audio frames received and
+ * the clock time associated with that frame count.
+ *
+ * frames is the total frame count received. This should be as early in
+ * the capture pipeline as possible. In general,
+ * frames should be non-negative and should not go "backwards".
+ *
+ * time is the clock MONOTONIC time when frames was measured. In general,
+ * time should be a positive quantity and should not go "backwards".
+ *
+ * The status returned is 0 on success, -ENOSYS if the device is not
+ * ready/available, or -EINVAL if the arguments are null or otherwise invalid.
+ */
+ virtual int getCapturePosition(int64_t *frames, int64_t *time);
+
+ /**
+ * Called by the framework to read active microphones
+ *
+ * \param[in] stream the stream object.
+ * \param[out] mic_array Pointer to first element on array with microphone info
+ * \param[out] mic_count When called, this holds the value of the max number of elements
+ * allowed in the mic_array. The actual number of elements written
+ * is returned here.
+ * if mic_count is passed as zero, mic_array will not be populated,
+ * and mic_count will return the actual number of active microphones.
+ *
+ * \return 0 if the microphone array is successfully filled.
+ * -ENOSYS if there is an error filling the data
+ */
+ virtual int getActiveMicrophones(struct audio_microphone_characteristic_t *mic_array, size_t *mic_count);
+
+ /**
+ * Called when the metadata of the stream's sink has been changed.
+ * @param sink_metadata Description of the audio that is recorded by the clients.
+ */
+ virtual void updateSinkMetadata(const struct sink_metadata *sink_metadata);
+
+ virtual status_t addAudioEffect(effect_handle_t effect);
+ virtual status_t removeAudioEffect(effect_handle_t effect);
+
+
+ /**
+ * set stream in index
+ */
+ inline void setIdentity(const uint32_t identity) { mIdentity = identity; }
+ inline uint32_t getIdentity() const { return mIdentity; }
+
+
+ /**
+ * open/close stream in related audio hardware
+ */
+ virtual status_t open();
+ virtual status_t close();
+
+
+ /**
+ * routing
+ */
+ status_t routing(audio_devices_t input_device);
+ status_t setPhonecallRouting(audio_devices_t input_device);
+ bool getDeviceConnectionState(audio_devices_t device);
+ void updateDeviceConnectionState(audio_devices_t device, bool connect);
+
+
+ /**
+ * reopen
+ */
+ void setReopenState(bool state) { mStreamInReopen = state; }
+ bool getReopenState() { return mStreamInReopen; }
+
+
+ /**
+ * suspend/resume
+ */
+ status_t setSuspend(const bool suspend_on);
+
+
+ /**
+ * get stream attribute
+ */
+ virtual const stream_attribute_t *getStreamAttribute() const { return &mStreamAttributeTarget; }
+
+ /**
+ * low latency
+ */
+ status_t setLowLatencyMode(bool mode);
+
+
+ /**
+ * update output routing
+ */
+ status_t updateOutputDeviceInfoForInputStream(audio_devices_t output_devices);
+
+ /**
+ * Set Input mute
+ */
+ void SetInputMute(bool bEnable);
+
+ /**
+ * Update Dynamic function mask
+ */
+ void UpdateDynamicFunctionMask(void);
+
+ /**
+ * Query if the stream in can run in Call Mode
+ */
+ bool isSupportConcurrencyInCall(void);
+
+ AudioALSACaptureHandlerBase *getStreamInCaptureHandler(void);
+
+ capture_handler_t getCaptureHandlerType();
+
+
+ /**
+ * AAudio MMAP
+ */
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t createMmapBuffer(int32_t min_size_frames,
+ struct audio_mmap_buffer_info *info);
+ virtual status_t getMmapPosition(struct audio_mmap_position *position);
+
+
+protected:
+ AudioALSAStreamManager *mStreamManager;
+ AudioALSACaptureHandlerBase *mCaptureHandler;
+
+ /**
+ * low latency
+ */
+ status_t setLowLatencyMode_l() {
+ status_t ret = NO_ERROR;
+ if (NULL != mCaptureHandler) {
+ ret = mCaptureHandler->setLowLatencyMode(mLowLatencyMode, mKernelBuffersize, mReduceBuffersize);
+ }
+ return ret;
+ }
+
+ /**
+ * check open input stream parameters
+ */
+ virtual bool checkOpenStreamFormat(int *format);
+ virtual bool checkOpenStreamChannels(uint32_t *channels);
+ virtual bool checkOpenStreamSampleRate(const audio_devices_t devices, uint32_t *sampleRate);
+
+
+
+private:
+ AudioLock mLock;
+ volatile int32_t mLockCount;
+ volatile int32_t mSuspendLockCount;
+ AudioLock mSuspendLock;
+ AudioLock mStandbyLock;
+
+
+ uint32_t mIdentity; // key for mStreamInVector
+
+ uint32_t mSuspendCount;
+ int64_t mStandbyFrameCount;
+ bool mStandby;
+ stream_attribute_t mStreamAttributeTarget;
+ bool mStreamInReopen;
+ audio_devices_t mNewInputDevice;
+ effect_handle_t mPreProcessEffectBackup[MAX_PREPROCESSORS];
+ int mPreProcessEffectBackupCount;
+ bool mLowLatencyMode;
+ uint32_t mKernelBuffersize;
+ size_t mReduceBuffersize;
+
+ /**
+ * Speech EnhanceInfo Instance
+ */
+ AudioSpeechEnhanceInfo *mAudioSpeechEnhanceInfoInstance;
+
+ void CheckBesRecordInfo();
+
+ /**
+ * for debug PCM dump
+ */
+ void OpenPCMDump(void);
+ void ClosePCMDump(void);
+ void WritePcmDumpData(void *buffer, ssize_t bytes);
+ String8 mDumpFileName;
+ FILE *mPCMDumpFile;
+ static int mDumpFileNum;
+
+ /*
+ * Device Available flag
+ */
+ uint32_t mAvailableInputDevices;
+
+ /*
+ * flag of dynamic enable verbose/debug log
+ */
+ int mLogEnable;
+
+ /**
+ * AAudio MMAP
+ */
+ bool mStart;
+ bool mDestroy;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_STREAM_IN_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAVoiceWakeUpController.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAVoiceWakeUpController.h
new file mode 100644
index 0000000..966d3f4
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioALSAVoiceWakeUpController.h
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_ALSA_AUDIO_VOICE_WAKE_UP_CONTROLLER_H
+#define ANDROID_ALSA_AUDIO_VOICE_WAKE_UP_CONTROLLER_H
+
+#include <tinyalsa/asoundlib.h>
+
+#include "AudioType.h"
+#include "AudioParamParser.h"
+#include <AudioLock.h>
+
+#include "AudioALSACaptureHandlerBase.h"
+#include "AudioALSACaptureHandlerVOW.h"
+
+
+namespace android {
+//class AudioALSACaptureDataProviderBase;
+
+class AudioALSADeviceConfigManager;
+class AudioALSACaptureDataProviderVOW;
+
+class AudioALSAVoiceWakeUpController {
+public:
+ virtual ~AudioALSAVoiceWakeUpController();
+
+ static AudioALSAVoiceWakeUpController *getInstance();
+
+ virtual status_t setVoiceWakeUpEnable(const bool enable);
+ virtual bool getVoiceWakeUpEnable();
+
+ virtual status_t updateDeviceInfoForVoiceWakeUp();
+
+ virtual status_t updateVOWCustParam();
+ virtual bool getVoiceWakeUpStateFromKernel();
+ virtual unsigned int getVOWMicType();
+
+ virtual status_t SeamlessRecordEnable();
+
+ bool updateSpeakerPlaybackStatus(bool isSpeakerPlaying);
+
+protected:
+ AudioALSAVoiceWakeUpController();
+
+ virtual status_t updateParamToKernel();
+ virtual bool setBargeInEnable(const bool enable);
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioALSAVoiceWakeUpController *mAudioALSAVoiceWakeUpController;
+
+ AudioALSACaptureDataProviderVOW *mVOWCaptureDataProvider;
+ AudioALSACaptureHandlerBase *mCaptureHandler;
+ stream_attribute_t *stream_attribute_target;
+ status_t setVoiceWakeUpDebugDumpEnable(const bool enable);
+ bool mDebug_Enable;
+
+ struct mixer *mMixer; // TODO(Harvey): move it to AudioALSAHardwareResourceManager later
+ struct pcm *mPcm;
+
+ AudioLock mLock;
+
+ bool mEnable;
+
+ bool mBargeInEnable;
+ bool mBargeInEnableOngoing;
+ struct pcm *mBargeInPcm;
+ struct pcm *mPcmHostlessUl;
+ struct pcm *mPcmHostlessDl;
+ String8 mBargeInTurnOnSequence;
+
+ bool mIsUseHeadsetMic;
+ AudioALSAHardwareResourceManager *mHardwareResourceManager;
+ bool mIsNeedToUpdateParamToKernel;
+
+
+ uint32_t mHandsetMicMode;
+ uint32_t mHeadsetMicMode;
+ AudioALSADeviceConfigManager *mDeviceConfigManager;
+ AppHandle *mAppHandle;
+
+ static void *dumyReadThread(void *arg);
+ pthread_t hDumyReadThread;
+ bool mDumpReadStart;
+ AudioLock mDebugDumpLock;
+ int mFd_dnn;
+ AudioLock mSeamlessLock;
+ int mFd_vow;
+ bool mIsSpeakerPlaying;
+
+ struct pcm_config mSrcDlConfig;
+ struct pcm_config mSrcUlConfig;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_ALSA_AUDIO_VOICE_WAKE_UP_CONTROLLER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioAMPControlInterface.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioAMPControlInterface.h
new file mode 100644
index 0000000..107022d
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioAMPControlInterface.h
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef __AUDIO_AMP_CONTROL_INTERFACE_H__
+#define __AUDIO_AMP_CONTROL_INTERFACE_H__
+
+namespace android {
+
+enum AUDIO_AMP_CONTROL_COMMAND {
+ AUD_AMP_GET_CTRP_NUM,
+ AUD_AMP_GET_CTRP_BITS,
+ AUD_AMP_GET_CTRP_TABLE,
+ AUD_AMP_GET_REGISTER,
+ AUD_AMP_SET_REGISTER,
+ AUD_AMP_SET_AMPGAIN, // gain is use for low 24bits as external amp , device should base on control point set to AMPLL_CON0_REG
+ AUD_AMP_GET_AMPGAIN,
+ AUD_AMP_SET_MODE,
+ NUM_AUD_AMP_CONTROL_COMMAND
+};
+
+typedef struct {
+ unsigned long int command;
+ unsigned long int param1;
+ unsigned long int param2;
+} AMP_Control;
+
+class AudioAMPControlInterface {
+public:
+ AudioAMPControlInterface() {}
+ virtual ~AudioAMPControlInterface() {}
+ //open/close device
+ virtual bool setSpeaker(bool on) = 0;
+ virtual bool setHeadphone(bool on) = 0;
+ virtual bool setReceiver(bool on) = 0;
+ virtual status_t setVolume(void *points, int num, int device) = 0;
+ //set mode to amp
+ virtual void setMode(audio_mode_t mode) = 0;
+ // for set and get parameters , for command1 and command 2 , use to command
+ // and data is used for comamnd need to carry a lots of command.
+ virtual status_t setParameters(int command1, int command2, unsigned int data) = 0;
+ virtual status_t getParameters(int command1, int command2, void *data) = 0;
+};
+
+class AudioDeviceManger {
+public:
+ static AudioAMPControlInterface *createInstance();
+private:
+ static AudioAMPControlInterface *mInstance;
+};
+
+}
+
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioBTCVSDControl.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioBTCVSDControl.h
new file mode 100644
index 0000000..0e414cb
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioBTCVSDControl.h
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef _AUDIO_BTCVSD_CONTROL_H_
+#define _AUDIO_BTCVSD_CONTROL_H_
+
+#define EXT_MODEM_BT_CVSD
+#define EXTMD_SUPPORT_WB
+
+//#define EXTMD_LOOPBACK_TEST
+
+//#define BTCVSD_LOOPBACK_WITH_CODEC
+
+//#define BTCVSD_ENC_DEC_LOOPBACK //copy TX output buf to RX inbuf directly, without writing to kernel
+//#define BTCVSD_KERNEL_LOOPBACK //enable this option for TXRX loopback in kernel
+
+//#define TXOUT_RXIN_TEST
+//#define BTCVSD_TEST_HW_ONLY
+
+#include "AudioType.h"
+#include "AudioBTCVSDDef.h"
+#include "AudioUtility.h"
+#include <tinyalsa/asoundlib.h>
+#include "WCNChipController.h"
+
+#ifdef EXT_MODEM_BT_CVSD
+//#include "AudioDigitalControlFactory.h"
+//#include "AudioResourceManager.h"
+
+#ifdef EXTMD_LOOPBACK_TEST
+//#include "AudioAnalogControlFactory.h"
+//#include "AudioAfeReg.h"
+//#include "AudioDigitalType.h"
+#endif
+#endif
+#include "MtkAudioComponent.h"
+
+namespace android {
+
+enum BT_SCO_STATE {
+ BT_SCO_TXSTATE_IDLE = 0x0,
+ BT_SCO_TXSTATE_INIT,
+ BT_SCO_TXSTATE_READY,
+ BT_SCO_TXSTATE_RUNNING,
+ BT_SCO_TXSTATE_ENDING,
+ BT_SCO_RXSTATE_IDLE = 0x10,
+ BT_SCO_RXSTATE_INIT,
+ BT_SCO_RXSTATE_READY,
+ BT_SCO_RXSTATE_RUNNING,
+ BT_SCO_RXSTATE_ENDING,
+ BT_SCO_TXSTATE_DIRECT_LOOPBACK
+} ;
+
+#ifdef EXT_MODEM_BT_CVSD
+#define EXTMD_BTSCO_AFE_SAMPLERATE (8000)
+
+enum EXTMD_BTSCO_THREAD_TYPE {
+ ExtMD_BTSCO_UL_READTHREAD = 0x0,
+ ExtMD_BTSCO_UL_WRITETHREAD,
+ ExtMD_BTSCO_DL_READTHREAD,
+ ExtMD_BTSCO_DL_WRITETHREAD,
+} ;
+
+enum EXTMD_BTSCO_DIRECTION {
+ ExtMD_BTSCO_UL = 0x0,
+ ExtMD_BTSCO_DL,
+} ;
+#endif
+
+typedef struct {
+ uint64_t dataCountEquiTime;
+ uint64_t timestampUS;
+} TimeBufferInfo;
+
+struct BtCodecLib {
+ bool ready;
+ void *handle;
+
+ void *(*decInit)(signed char *buffer);
+ void *(*encInit)(signed char *buffer);
+ int (*decProcess)(void *handle, char *inBuf, int *inLen, short *outBuf, int *outLen);
+ int (*encProcess)(void *handle, short *inBuf, int *inLen, char *outBuf, int *outLen);
+ int (*decGetBufferSize)();
+ int (*encGetBufferSize)();
+
+ int (*g711plc_GetMemorySize_v2)();
+ void (*g711plc_construct_v2)(void *lc, unsigned int samplingrate);
+ void (*g711plc_addtohistory_v2)(void *lc, short *s, unsigned int dwBtEv3HalfBad);
+ void (*g711plc_dofe_v2)(void *lc, short *out, unsigned int dwBtEv3HalfBad);
+};
+
+class BT_SCO_TX {
+public:
+ MtkAudioSrcBase *pSRCHandle;
+ void *pEncHandle;
+ void *pHPFHandle;
+ void (*pCallback)(void *pData);
+ void *pUserData;
+ uint8_t PcmBuf_64k[SCO_TX_PCM64K_BUF_SIZE];
+ uint32_t uPcmBuf_w;
+ uint32_t iPacket_w;
+ uint16_t uSampleRate;
+ uint8_t uChannelNumber;
+ bool fEnableFilter;
+ bool fEnablePLC;
+
+} ;
+
+class BT_SCO_RX {
+public:
+ //handle
+ void *pDecHandle;
+ void *pHPFHandle;
+ void *pPLCHandle;
+ MtkAudioSrcBase *pSRCHandle_1;
+ MtkAudioSrcBase *pSRCHandle_2;
+ //callback
+ void (*pCallback)(void *pData);
+ void *pUserData;
+ //temp buffer
+ uint8_t PcmBuf_64k[SCO_RX_PCM64K_BUF_SIZE];
+ uint8_t PcmBuf_8k[SCO_RX_PCM8K_BUF_SIZE];
+#ifdef EXT_MODEM_BT_CVSD
+ uint8_t PcmBuf_8k_accu[BTSCO_CVSD_RX_INBUF_SIZE * 2 * 2];
+#endif
+ uint32_t uPcmBuf_r; //for PcmBuf_8k
+ uint16_t uSampleRate;
+ uint8_t uChannelNumber;
+ bool fEnableSRC2;
+ bool fEnableFilter;
+ bool fEnablePLC;
+ //mSBC
+ uint8_t PacketBuf[SCO_RX_PACKER_BUF_NUM][SCO_RX_PLC_SIZE];
+ uint8_t EntirePacket[MSBC_PACKET_SIZE_BYTE];
+ uint8_t PcmBuf_mSBC[MSBC_PCM_FRAME_BYTE];
+ bool PacketValid[SCO_RX_PACKER_BUF_NUM];
+ uint32_t iPacket_w;
+ uint32_t iPacket_r;
+} ;
+
+class BTSCO_CVSD_Context {
+public:
+
+ BT_SCO_TX *pTX; //btsco.pTx
+ BT_SCO_RX *pRX;
+ uint8_t *pStructMemory;
+ uint8_t *pTXWorkingMemory;
+ uint8_t *pRXWorkingMemory;
+ uint16_t uAudId;
+ BT_SCO_STATE uTXState;
+ BT_SCO_STATE uRXState;
+ bool fIsStructMemoryOnMED;
+ bool fIsWideBand;
+};
+
+
+class AudioBTCVSDControl {
+public:
+
+ enum BT_SCO_MODE {
+ BT_SCO_MODE_CVSD,
+ BT_SCO_MODE_MSBC
+ } ;
+
+ enum BT_SCO_LINK {
+ BT_SCO_LINK_TX_ONLY,
+ BT_SCO_LINK_RX_ONLY,
+ BT_SCO_LINK_BOTH,
+ } ;
+
+ enum BT_SCO_MODULE {
+ BT_SCO_MOD_CVSD_ENCODE,
+ BT_SCO_MOD_CVSD_DECODE,
+ BT_SCO_MOD_FILTER_TX,
+ BT_SCO_MOD_FILTER_RX,
+ BT_SCO_MOD_PLC_NB,
+ BT_SCO_MOD_CVSD_TX_SRC,
+ BT_SCO_MOD_MSBC_TX_SRC,
+ BT_SCO_MOD_MSBC_RX_SRC,
+ BT_SCO_MOD_CVSD_RX_SRC1,
+ BT_SCO_MOD_CVSD_RX_SRC2,
+ BT_SCO_MOD_PCM_RINGBUF_TX,
+ BT_SCO_MOD_PCM_RINGBUF_RX,
+ BT_SCO_MOD_MSBC_DECODE,
+ BT_SCO_MOD_MSBC_ENCODE,
+ BT_SCO_MOD_PLC_WB,
+ } ;
+
+ enum BT_SCO_DIRECT {
+ BT_SCO_DIRECT_BT2ARM,
+ BT_SCO_DIRECT_ARM2BT
+ } ;
+
+ enum BT_SCO_PACKET_LEN {
+ BT_SCO_CVSD_30 = 0,
+ BT_SCO_CVSD_60 = 1,
+ BT_SCO_CVSD_90 = 2,
+ BT_SCO_CVSD_120 = 3,
+ BT_SCO_CVSD_10 = 4,
+ BT_SCO_CVSD_20 = 5,
+ BT_SCO_CVSD_MAX = 6
+ } ;
+
+ static AudioBTCVSDControl *getInstance();
+ static void freeInstance();
+
+ int getFd();
+
+ void BT_SCO_CVSD_Init(void);
+ void BT_SCO_CVSD_DeInit(void);
+ void BT_SCO_SET_TXState(BT_SCO_STATE state);
+ void BT_SCO_SET_RXState(BT_SCO_STATE state);
+ void BT_SCO_RX_Open(void);
+ int BT_SCO_RX_SetHandle(void(*pCallback)(void *pData), void *pData, uint32_t uSampleRate, uint32_t uChannelNumber, uint32_t uEnableFilter);
+ void BT_SCO_RX_Start(void);
+ void BT_SCO_RX_Stop(void);
+ void BT_SCO_RX_Close(void);
+ void BT_SCO_RX_Begin(int mFd2);
+ void BT_SCO_RX_End(int mFd2);
+ void BT_SCO_RX_DestroyModule(void);
+ uint8_t *BT_SCO_RX_GetCVSDTempInBuf(void);
+ void BT_SCO_RX_SetCVSDTempInBuf(uint8_t *addr);
+ uint8_t *BT_SCO_RX_GetCVSDInBuf(void);
+ void BT_SCO_RX_SetCVSDInBuf(uint8_t *addr);
+ uint8_t *BT_SCO_RX_GetCVSDOutBuf(void);
+ uint8_t *BT_SCO_RX_GetCVSDWorkBuf(void);
+ uint8_t *BT_SCO_RX_GetMSBCOutBuf(void);
+ void *BT_SCO_RX_GetTimeBufferInfo(void);
+ void btsco_cvsd_RX_main(void);
+ void btsco_process_RX_CVSD(void *inbuf, uint32_t *insize, void *outbuf, uint32_t *outsize, void *workbuf, const uint32_t workbufsize, uint8_t packetvalid);
+ void btsco_process_TX_CVSD(void *inbuf, uint32_t *insize, void *outbuf, uint32_t *outsize, void *workbuf, const uint32_t workbufsize);
+ void BT_SCO_TX_Open(void);
+ int BT_SCO_TX_SetHandle(void(*pCallback)(void *pData), void *pData, uint32_t uSampleRate, uint32_t uChannelNumber, uint32_t uEnableFilter);
+ void BT_SCO_TX_Start(void);
+ void BT_SCO_TX_Stop(void);
+ void BT_SCO_TX_Close(void);
+ void BT_SCO_TX_Begin(int mFd2, uint32_t uSampleRate, uint32_t uChannelNumber);
+ void BT_SCO_TX_End(int mFd2);
+ void BT_SCO_TX_DestroyModule(void);
+ void BT_SCO_TX_SetCVSDOutBuf(uint8_t *addr);
+ uint8_t *BT_SCO_TX_GetCVSDOutBuf(void);
+ uint8_t *BT_SCO_TX_GetCVSDWorkBuf(void);
+ void *BT_SCO_TX_GetTimeBufferInfo(void);
+
+ void BTCVSD_Init(int mFd2, uint32_t mSourceSampleRate, uint32_t mSourceChannels);
+ void BTCVSD_StandbyProcess(int mFd2);
+#if defined(BTCVSD_ENC_DEC_LOOPBACK)
+ void BTCVSD_Test_UserSpace_TxToRx(uint32_t total_outsize);
+#endif
+#ifdef EXT_MODEM_BT_CVSD
+ void AudioExtMDCVSDCreateThread(void);
+ void AudioExtMDCVSDDeleteThread(void);
+ bool BT_SCO_ExtMDULBufLock(void);
+ bool BT_SCO_ExtMDULBufUnLock(void);
+ bool BT_SCO_ExtMDDLBufLock(void);
+ bool BT_SCO_ExtMDDLBufUnLock(void);
+ void BT_SCO_ExtMDInitBuf(EXTMD_BTSCO_DIRECTION direction);
+ uint32_t BT_SCO_ExtMDGetBufSpace(EXTMD_BTSCO_DIRECTION direction);
+ uint32_t BT_SCO_ExtMDGetBufCount(EXTMD_BTSCO_DIRECTION direction);
+ void BT_SCO_ExtMDWriteDataToRingBuf(uint8_t *buf, uint32_t size, EXTMD_BTSCO_DIRECTION direction);
+ void BT_SCO_ExtMDReadDataFromRingBuf(uint8_t *buf, uint32_t size, EXTMD_BTSCO_DIRECTION direction);
+ uint8_t *BT_SCO_ExtMDGetCVSDAccuOutBuf(void);
+ uint8_t *BT_SCO_ExtMDGetCVSDULWriteTmpBuf(void);
+ uint8_t *BT_SCO_ExtMDGetCVSDULWriteTmpBuf2(void);
+ bool BT_SCO_ExtMDGetBTSCORunning(void);
+ void BT_SCO_ExtMD_ULBuf_Open(void);
+ void BT_SCO_ExtMD_ULBuf_Close(void);
+ void BT_SCO_ExtMD_DLBuf_Open(void);
+ void BT_SCO_ExtMD_DLBuf_Close(void);
+#endif
+ static BTSCO_CVSD_Context *mBTSCOCVSDContext; //btsco
+
+ void btsco_process_RX_MSBC(void *inbuf, uint32_t *insize, void *outbuf, uint32_t *outsize, void *workbuf, uint8_t packetvalid);
+ void btsco_process_TX_MSBC(void *inbuf, uint32_t *insize, void *outbuf, uint32_t *outsize, void *workbuf);
+ void BT_SCO_SetMode(uint32_t mode);
+ bool BT_SCO_isWideBand(void);
+
+private:
+
+ AudioBTCVSDControl();
+ ~AudioBTCVSDControl();
+
+ int initCvsdLib();
+ int initMsbcLib();
+ struct BtCodecLib mCvsdLib;
+ struct BtCodecLib mMsbcLib;
+
+ int mFd2;
+
+ uint32_t BT_SCO_GetMemorySize_4ByteAlign(BT_SCO_MODULE uModule);
+ void BT_SCO_InitialModule(BT_SCO_MODULE uModule, uint8_t *pBuf);
+ static AudioBTCVSDControl *UniqueAudioBTCVSDControl;
+ uint8_t *mBTCVSDRXTempInBuf;
+ uint8_t *mBTCVSDRXInBuf;
+ uint8_t *mBTCVSDTXOutBuf;
+#ifdef EXT_MODEM_BT_CVSD
+ uint8_t *mExtMDbtscoULBuf;
+ uint8_t *mExtMDbtscoULWTmpBuf;
+ uint8_t *mExtMDbtscoULWTmpBuf2;
+ uint8_t *mExtMDbtscoDLBuf;
+ Mutex mLockUL;
+ Mutex mLockDL;
+ RingBuf mULRingBuf;
+ RingBuf mDLRingBuf;
+ //AudioDigitalControlInterface *mAudioDigitalControl;
+#endif
+ FILE *mTXSRCPCMDumpFile;
+ FILE *mBTCVSDRXDumpFile;
+ FILE *mBTCVSDRXInDumpFile;
+
+ uint32_t Audio_IIRHPF_GetBufferSize(void);
+ void *Audio_IIRHPF_Init(void);
+ void Audio_IIRHPF_Process(void);
+ BT_SCO_MODE BTmode;
+ void btsco_AllocMemory_TX_CVSD(void);
+ void btsco_AllocMemory_TX_MSBC(void);
+ void btsco_AllocMemory_RX_CVSD(void);
+ void btsco_AllocMemory_RX_MSBC(void);
+
+#ifdef EXT_MODEM_BT_CVSD
+ class AudioExtMDCVSDThread : public Thread {
+ public:
+ AudioExtMDCVSDThread(EXTMD_BTSCO_THREAD_TYPE Thread_type, char *RingBuffer, uint32_t BufferSize);
+ virtual ~AudioExtMDCVSDThread();
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+ void WritePcmDumpData(uint8_t *buf, uint32_t size);
+ void ClosePcmDumpFile();
+ void ExtMD_btsco_cvsd_UL_Read_main();
+ void ExtMD_btsco_cvsd_UL_Write_main();
+ void ExtMD_btsco_cvsd_DL_Read_main();
+ void ExtMD_btsco_cvsd_DL_Write_main();
+
+ private:
+ int mFd;
+ int mFd2;
+ int mThreadType;
+ String8 mName;
+ virtual bool threadLoop();
+ char *mRingBuffer;
+ uint32_t mBufferSize;
+ //AudioMTKStreamInManager *mManager;
+ //unsigned char tempdata;
+ //uint32_t mRecordDropms;
+
+ bool mAFEDLStarting;
+ bool mAFEULStarting;
+
+ FILE *mPAdcPCMDumpFile;
+ FILE *mPI2SPCMDumpFile;
+ FILE *mExtMDULReadPCMDumpFile;
+ FILE *mExtMDULWritePCMDumpFile;
+ FILE *mExtMDDLReadPCMDumpFile;
+ FILE *mExtMDDLWritePCMDumpFile;
+
+ AudioBTCVSDControl *mAudioBTCVSDControl;
+
+ //AudioDigitalControlInterface *mAudioDigitalControl;
+ //AudioResourceManagerInterface *mAudioResourceManager;
+
+#ifndef EXTMD_SUPPORT_WB
+ MtkAudioSrcBase *pULSRCHandle;
+#endif
+
+#ifdef EXTMD_LOOPBACK_TEST
+ //AudioAnalogControlInterface *mAudioAnalogControl;
+ //AudioAfeReg *mAfeReg;
+#endif
+ };
+
+ bool mExtMDBTSCORunning;
+ // EXTMD_BTSCO_THREAD_TYPE mThreadType;
+
+ sp<AudioExtMDCVSDThread> mExtMDCVSDULThread1;
+ sp<AudioExtMDCVSDThread> mExtMDCVSDULThread2;
+ sp<AudioExtMDCVSDThread> mExtMDCVSDDLThread1;
+ sp<AudioExtMDCVSDThread> mExtMDCVSDDLThread2;
+#endif
+
+ class AudioBTCVSDLoopbackRxThread : public Thread {
+ public:
+ AudioBTCVSDLoopbackRxThread(uint32_t Mem_type, char *mRingBuffer, uint32_t mBufferSize);
+ virtual ~AudioBTCVSDLoopbackRxThread();
+ // Good place to do one-time initializations
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+ void WritePcmDumpData(void *outbuf, uint32_t outsize);
+ void ClosePcmDumpFile();
+ void DropRecordData();
+ void btsco_cvsd_RX_main();
+
+ private:
+ int mFd;
+ int mFd2;
+ int mMemType;
+ String8 mName;
+ virtual bool threadLoop();
+ char *mRingBuffer;
+ uint32_t mBufferSize;
+ unsigned char tempdata;
+ uint32_t mRecordDropms;
+ FILE *mBTCVSDLoopbackDumpFile;
+ AudioBTCVSDControl *mAudioBTCVSDControl;
+ struct pcm *mPcm_LoopbackRx = NULL;
+ struct pcm_config mConfig_LoopbackRx;
+ };
+
+ AudioBTCVSDControl *mAudioBTCVSDControl;
+#if defined(BTCVSD_ENC_DEC_LOOPBACK) || defined(BTCVSD_KERNEL_LOOPBACK)
+ FILE *mCVSDloopbackPCMDumpFile;
+#endif
+ sp<AudioBTCVSDLoopbackRxThread> mBTCVSDRxTestThread;
+};
+}
+
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioBTCVSDDef.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioBTCVSDDef.h
new file mode 100644
index 0000000..ea8af7d
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioBTCVSDDef.h
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef _AUDIO_BTCVSD_DEF_H_
+#define _AUDIO_BTCVSD_DEF_H_
+
+// BT HW Register address
+#if 1 //TODO: !!!!!!!!!!!!!!MUST modify according to 6572/6582 spec!!!!!!!!!!!!!!!!
+//#define BTSRAM_BASE (0xA3000000)
+#define BTPKT_BASE (0x18000000)//(0xA3340000)
+#define BT_SCO_HW_REG_PACKET_R ((volatile kal_uint32*)(BTPKT_BASE+0x0FD0))
+#define BT_SCO_HW_REG_PACKET_W ((volatile kal_uint32*)(BTPKT_BASE+0x0FD4))
+#define BT_SCO_HW_REG_CONTROL ((volatile kal_uint32*)(BTPKT_BASE+0x0FD8))
+
+#define BT_LOOPBACK_CTL ((volatile kal_uint16*)(0x18000000))
+
+//#define BT_POWER_OFF ((volatile kal_uint16*)(0xA0700170))
+//#define BT_POWER_OFF_MASK (0x2)
+#endif
+
+#define BT_SCO_PACKET_120 120
+#define BT_SCO_PACKET_180 180
+
+#define BT_CVSD_TX_NREADY (1<<21)
+#define BT_CVSD_RX_READY (1<<22)
+#define BT_CVSD_TX_UNDERFLOW (1<<23)
+#define BT_CVSD_RX_OVERFLOW (1<<24)
+#define BT_CVSD_INTERRUPT (1<<31)
+
+#define BT_CVSD_CLEAR (BT_CVSD_TX_NREADY | BT_CVSD_RX_READY | BT_CVSD_TX_UNDERFLOW | BT_CVSD_RX_OVERFLOW | BT_CVSD_INTERRUPT)
+
+//TX
+#define SCO_TX_ENCODE_SIZE (60 ) // 60 byte (60*8 samples)
+#define SCO_TX_PACKER_BUF_NUM (8 ) // 8
+#define SCO_TX_PACKET_MASK (0x7 ) //0x7
+#define SCO_TX_PCM64K_BUF_SIZE (SCO_TX_ENCODE_SIZE*2*8 ) // 60 * 2 * 8 byte
+
+//RX
+#define SCO_RX_PLC_SIZE (30 )
+#define SCO_RX_PACKER_BUF_NUM (16 ) //16
+#define SCO_RX_PACKET_MASK (0xF ) //0xF
+#define SCO_RX_PCM64K_BUF_SIZE (SCO_RX_PLC_SIZE*2*8 )
+#define SCO_RX_PCM8K_BUF_SIZE (SCO_RX_PLC_SIZE*2 )
+
+#define BTSCO_CVSD_RX_FRAME SCO_RX_PACKER_BUF_NUM
+
+#define BTSCO_CVSD_RX_INBUF_SIZE (BTSCO_CVSD_RX_FRAME*SCO_RX_PLC_SIZE)
+#define BTSCO_CVSD_PACKET_VALID_SIZE 2
+#define BTSCO_CVSD_RX_TEMPINPUTBUF_SIZE (BTSCO_CVSD_RX_FRAME*(SCO_RX_PLC_SIZE+BTSCO_CVSD_PACKET_VALID_SIZE))
+
+#define BTSCO_CVSD_TX_FRAME SCO_TX_PACKER_BUF_NUM
+#define BTSCO_CVSD_TX_OUTBUF_SIZE (BTSCO_CVSD_TX_FRAME*SCO_TX_ENCODE_SIZE)
+
+
+// mSBC related part
+#define __MSBC_CODEC_SUPPORT__ 1
+
+#define MSBC_BTSTREAM_FRAME_BYTE (57)
+#define MSBC_PACKET_SIZE_BYTE (60)
+#define MSBC_PCM_FRAME_BYTE (240) //120 sample
+
+#define NB_SPEECH_FRAME_SIZE (320) //BYTE
+#define WB_SPEECH_FRAME_SIZE (640) //BYTE
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioBitTrueTest.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioBitTrueTest.h
new file mode 100644
index 0000000..24802c2
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioBitTrueTest.h
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_BIT_TRUE_TEST_H
+#define ANDROID_AUDIO_BIT_TRUE_TEST_H
+
+#include <tinyalsa/asoundlib.h> // TODO(Harvey): move it
+
+#include <pthread.h>
+
+#include "AudioType.h"
+#include <AudioLock.h>
+
+enum {
+ BIT_TRUE_TEST_DISABLE = 0,
+ BIT_TRUE_TEST_DL_UL,
+ BIT_TRUE_TEST_4_PIN_I2S,
+};
+
+namespace android {
+
+class AudioBitTrueTest {
+public:
+ static AudioBitTrueTest *getInstance();
+ ~AudioBitTrueTest();
+
+ int setTestType(int testType);
+ int getTestState();
+private:
+ static AudioBitTrueTest *mAudioBitTrueTest;
+ AudioBitTrueTest();
+ int open(int testType);
+ int close();
+
+ static void *playThread(void *arg);
+ static void *verifyThread(void *arg);
+
+ static FILE *testDumpOpen(const char *name, const char *property);
+ static void testDumpClose(FILE *file);
+ static void testDumpWriteData(FILE *file, const void *buffer, size_t bytes);
+
+ AudioLock mLock;
+
+ int mTestState;
+ bool mPlayReady;
+
+ struct mixer *mMixer;
+
+ pthread_t mPlayThread;
+ pthread_t mVerifyThread;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_BIT_TRUE_TEST_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioDeviceInt.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioDeviceInt.h
new file mode 100644
index 0000000..ca7d0b4
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioDeviceInt.h
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef __AUDIO_DEVICE_INT_H__
+#define __AUDIO_DEVICE_INT_H__
+
+// this is used only in HAL for speech ap speaker protection
+const audio_devices_t AUDIO_DEVICE_IN_SPK_FEED = AUDIO_DEVICE_IN_DEFAULT;
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioExternWrapper.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioExternWrapper.h
new file mode 100644
index 0000000..4d2c696
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioExternWrapper.h
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: MediaTekProprietary
+
+#include "IAudioALSACaptureDataClient.h"
+#include "AudioALSACaptureDataProviderUsb.h"
+#include "AudioALSACaptureDataProviderEchoRefUsb.h"
+#include "AudioALSAPlaybackHandlerUsb.h"
+#include "AudioALSACaptureDataProviderBase.h"
+
+
+
+#include "AudioType.h"
+#include "AudioUtility.h"
+
+
+namespace android {
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+extern "C" IAudioALSACaptureDataClient *createMTKAudioDataClient(AudioALSACaptureDataProviderBase *pCaptureDataProvider, stream_attribute_t *stream_attribute_target, AudioALSACaptureDataProviderBase *pCaptureDataProviderEchoRef);
+#else
+extern "C" IAudioALSACaptureDataClient *createMTKAudioDataClient(AudioALSACaptureDataProviderBase *pCaptureDataProvider, stream_attribute_t *stream_attribute_target);
+#endif
+extern "C" AudioALSACaptureDataProviderUsb *createMTKAudioUSBProvider();
+extern "C" AudioALSACaptureDataProviderEchoRefUsb *createMTKAudioUSBProviderEchoRef();
+extern "C" AudioALSAPlaybackHandlerUsb *createMTKAudioUSBPlaybackHandler(stream_attribute_t *stream_attribute_source);
+
+} // end namespace android
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+typedef android::IAudioALSACaptureDataClient *create_AudioMTKDataClient(android::AudioALSACaptureDataProviderBase *pCaptureDataProvider, stream_attribute_t *stream_attribute_target, android::AudioALSACaptureDataProviderBase *pCaptureDataProviderEchoRef);
+#else
+typedef android::IAudioALSACaptureDataClient *create_AudioMTKDataClient(android::AudioALSACaptureDataProviderBase *pCaptureDataProvider, stream_attribute_t *stream_attribute_target);
+#endif
+
+typedef android::AudioALSACaptureDataProviderUsb *create_AudioMTKUSBProvider();
+typedef android::AudioALSACaptureDataProviderEchoRefUsb *create_AudioMTKUSBProviderEchoRef();
+typedef android::AudioALSAPlaybackHandlerUsb *create_AudioMTKUSBPlaybackHandler(stream_attribute_t *stream_attribute_source);
+
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioFtm.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioFtm.h
new file mode 100644
index 0000000..e5aba95
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioFtm.h
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+/*******************************************************************************
+ *
+ * Filename:
+ * ---------
+ * AudioFtm.h
+ *
+ * Project:
+ * --------
+ * Android Audio Driver
+ *
+ * Description:
+ * ------------
+ * Factory Mode
+ *
+ * Author:
+ * -------
+ * Chipeng Chang (mtk02308)
+ *
+ *------------------------------------------------------------------------------
+ * $Revision: #5 $
+ * $Modtime:$
+ * $Log:$
+ *
+ *
+ *******************************************************************************/
+
+#ifndef ANDROID_AUDIO_FTM_H
+#define ANDROID_AUDIO_FTM_H
+
+/*****************************************************************************
+* C O M P I L E R F L A G S
+******************************************************************************
+*/
+
+/*****************************************************************************
+* E X T E R N A L R E F E R E N C E S
+******************************************************************************
+*/
+#include <stdint.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+#include <tinyalsa/asoundlib.h> // TODO(Harvey): move it
+
+#include "AudioType.h"
+
+#include "AudioFtmBase.h"
+
+/*****************************************************************************
+* C O N S T A N T S
+******************************************************************************
+*/
+
+/*****************************************************************************
+* M A C R O
+******************************************************************************
+*/
+
+/*****************************************************************************
+* R E G I S T E R D E F I N I T I O N
+******************************************************************************
+*/
+
+/*****************************************************************************
+* F U N C T I O N D E F I N I T I O N
+******************************************************************************
+*/
+
+/*****************************************************************************
+* D A T A T Y P E S
+******************************************************************************
+*/
+
+namespace android {
+
+enum audio_mic_mask_t {
+ AUDIO_MIC_MASK_NONE = 1 << 0,
+ AUDIO_MIC_MASK_MIC1 = 1 << 1,
+ AUDIO_MIC_MASK_MIC2 = 1 << 2,
+ AUDIO_MIC_MASK_MIC3 = 1 << 3,
+ AUDIO_MIC_MASK_MIC4 = 1 << 4,
+
+ AUDIO_MIC_MASK_HEADSET_MIC = 1 << 16,
+};
+
+
+/*****************************************************************************
+* C L A S S D E F I N I T I O N
+******************************************************************************
+*/
+
+class AudioALSAStreamManager;
+class AudioALSAStreamOut;
+class AudioALSAStreamIn;
+
+class LoopbackManager;
+
+class AudioALSAHardwareResourceManager;
+
+class AudioFtm : public AudioFtmBase {
+public:
+ virtual ~AudioFtm();
+ static AudioFtm *getInstance();
+
+
+ virtual int SineGenTest(char sinegen_test);
+
+ /// Output device test
+ virtual int RecieverTest(char receiver_test);
+ virtual int LouderSPKTest(char left_channel, char right_channel);
+ virtual int EarphoneTest(char bEnable);
+ virtual int EarphoneTestLR(char bLR);
+
+ /// Input device test
+ virtual int SpecificBuildInMicTest(char type);
+
+ /// Speaker over current test
+ virtual int Audio_READ_SPK_OC_STA(void);
+ virtual int LouderSPKOCTest(char left_channel, char right_channel);
+
+
+ /// Loopback // TODO: Add in platform!!!
+ virtual int PhoneMic_Receiver_Loopback(char echoflag);
+ virtual int PhoneMic_EarphoneLR_Loopback(char echoflag);
+ virtual int PhoneMic_SpkLR_Loopback(char echoflag);
+ virtual int HeadsetMic_EarphoneLR_Loopback(char bEnable, char bHeadsetMic);
+ virtual int HeadsetMic_SpkLR_Loopback(char echoflag);
+ virtual int HeadsetMic_Receiver_Loopback(char bEnable, char bHeadsetMic);
+
+ virtual int PhoneMic_Receiver_Acoustic_Loopback(int Acoustic_Type, int *Acoustic_Status_Flag, int bHeadset_Output);
+
+
+ /// FM / mATV
+ virtual int FMLoopbackTest(char bEnable);
+
+ virtual int Audio_FM_I2S_Play(char bEnable);
+ virtual int Audio_MATV_I2S_Play(int enable_flag);
+ virtual int Audio_FMTX_Play(bool Enable, unsigned int Freq);
+
+ virtual int ATV_AudPlay_On(void);
+ virtual int ATV_AudPlay_Off(void);
+ virtual unsigned int ATV_AudioWrite(void *buffer, unsigned int bytes);
+
+ /// HDMI
+ int HDMI_SineGenPlayback(bool Enable, int Freq);
+
+
+ /// Vibration Speaker // MTK_VIBSPK_SUPPORT??
+ virtual int SetVibSpkCalibrationParam(void *cali_param);
+ virtual uint32_t GetVibSpkCalibrationStatus();
+ virtual void SetVibSpkEnable(bool enable, uint32_t freq);
+ virtual void SetVibSpkRampControl(uint8_t rampcontrol);
+
+ virtual bool ReadAuxadcData(int channel, int *value);
+ virtual void SetStreamOutPostProcessBypass(bool flag);
+
+ // speaker calibration for SmartPa
+ virtual bool SpeakerCalibration(int calibStage);
+
+private:
+ static AudioFtm *mAudioFtm;
+
+ AudioFtm();
+ AudioFtm(const AudioFtm &); // intentionally undefined
+ AudioFtm &operator=(const AudioFtm &); // intentionally undefined
+
+ // SW SineWave for FM Tx and HDMI //[temp]
+ bool WavGen_SW_SineWave(bool Enable, unsigned int Freq, int type);
+ bool WavGen_SWPattern(bool Enable, unsigned int Freq, int type);
+ void WavGen_AudioRead(char *pBuffer, unsigned int bytes);
+
+ static void *FmTx_thread_create(void *arg);
+ static void *HDMI_thread_create(void *arg);
+ void FmTx_thread_digital_out(void);
+ void HDMI_thread_I2SOutput(void);
+
+ pthread_t m_WaveThread;
+ bool mAudioSinWave_thread;
+ unsigned int IdxAudioPattern;
+ unsigned int SizeAudioPattern;
+ unsigned char *mDataTable;
+ char *mDataBuffer;
+
+
+ virtual status_t setMicEnable(const audio_mic_mask_t audio_mic_mask, const bool enable); // [TMP]
+
+
+ AudioALSAStreamManager *mStreamManager;
+ AudioALSAStreamOut *mStreamOut;
+ AudioALSAStreamIn *mStreamIn;
+
+ LoopbackManager *mLoopbackManager;
+
+ AudioALSAHardwareResourceManager *mHardwareResourceManager;
+};
+
+}; // namespace android
+
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioGainTableParam.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioGainTableParam.h
new file mode 100644
index 0000000..19392e5
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioGainTableParam.h
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef _AUDIO_GAIN_TABLE_PARAM_H_
+#define _AUDIO_GAIN_TABLE_PARAM_H_
+
+#include <system/audio.h>
+#include <vector>
+#include <string>
+
+#define PLAY_DIGI_AUDIOTYPE_NAME "PlaybackVolDigi"
+#define PLAY_ANA_AUDIOTYPE_NAME "PlaybackVolAna"
+#define SPEECH_VOL_AUDIOTYPE_NAME "SpeechVol"
+#define REC_VOL_AUDIOTYPE_NAME "RecordVol"
+#define VOIP_VOL_AUDIOTYPE_NAME "VoIPVol"
+#define RINGBACK_VOL_AUDIOTYPE_NAME "RingbackVol"
+#define VOLUME_AUDIOTYPE_NAME "Volume"
+#define GAIN_MAP_AUDIOTYPE_NAME "VolumeGainMap"
+#define GAIN_MAP_UL_AUDIOTYPE_NAME "VolumeGainMapUL"
+#define HP_IMPEDANCE_AUDIOTYPE_NAME "HpImpedance"
+
+// VOLUME INDEX
+#define GAIN_MAX_VOL_INDEX (15) // index will change from 0~18 total 19 step
+#define GAIN_VOL_INDEX_SIZE (GAIN_MAX_VOL_INDEX + 1)
+
+#define GAIN_MAX_SPEECH_VOL_INDEX (7) // for voice stream, policy index range = 0~7, set 7 here.
+
+// STREAM TYPE
+#define GAIN_MIN_STREAM_TYPE (AUDIO_STREAM_VOICE_CALL)
+#define GAIN_MAX_STREAM_TYPE (AUDIO_STREAM_ACCESSIBILITY)
+#define GAIN_STREAM_TYPE_SIZE (GAIN_MAX_STREAM_TYPE + 1)
+
+// SCENE INDEX
+#define GAIN_SCENE_INDEX_DEFAULT (0)
+
+// DEVICE
+#if defined(MTK_YOCTO_AUDIO)
+enum GAIN_DEVICE {
+ GAIN_DEVICE_NONE = -1,
+ GAIN_DEVICE_SPEAKER,
+ GAIN_DEVICE_SPEAKER_TBOX,
+ NUM_GAIN_DEVICE,
+};
+#else
+enum GAIN_DEVICE {
+ GAIN_DEVICE_NONE = -1,
+ GAIN_DEVICE_EARPIECE = 0,
+ GAIN_DEVICE_HEADSET,
+ GAIN_DEVICE_SPEAKER,
+ GAIN_DEVICE_HEADPHONE,
+ GAIN_DEVICE_HSSPK, // headset with speaker
+ GAIN_DEVICE_HEADSET_5POLE,
+ GAIN_DEVICE_HEADSET_5POLE_ANC,
+ GAIN_DEVICE_HAC,
+ GAIN_DEVICE_BT,
+ GAIN_DEVICE_TTY,
+ GAIN_DEVICE_LPBK_RCV,
+ GAIN_DEVICE_LPBK_SPK,
+ GAIN_DEVICE_LPBK_HP,
+ GAIN_DEVICE_USB,
+ GAIN_DEVICE_BT_A2DP,
+ GAIN_DEVICE_BT_A2DP_HP,
+ GAIN_DEVICE_BT_A2DP_SPK,
+ GAIN_DEVICE_RCV_EV,//super volume mode
+ GAIN_DEVICE_SPK_EV,//super volume mode
+ NUM_GAIN_DEVICE,
+};
+#endif
+
+// GAIN_ANA_TYPE
+enum GAIN_ANA_TYPE {
+ GAIN_ANA_NONE = -1,
+ GAIN_ANA_HANDSET = 0, // mtk codec voice buffer
+ GAIN_ANA_HEADPHONE, // mtk codec audio buffer
+ GAIN_ANA_SPEAKER, // mtk codec speaker amp
+ GAIN_ANA_LINEOUT, // mtk codec linout buffer
+ NUM_GAIN_ANA_TYPE
+};
+
+// SPEECH
+enum GAIN_SPEECH_BAND {
+ GAIN_SPEECH_NB,
+ GAIN_SPEECH_WB,
+ GAIN_SPEECH_SWB,
+ NUM_GAIN_SPEECH_BAND
+};
+
+enum GAIN_SPEECH_NETWORK {
+ GAIN_SPEECH_NETWORK_GSM,
+#if !defined(MTK_YOCTO_AUDIO)
+ GAIN_SPEECH_NETWORK_WCDMA,
+ GAIN_SPEECH_NETWORK_VOLTE,
+#endif
+ NUM_GAIN_SPEECH_NETWORK
+};
+
+// MIC
+enum GAIN_MIC_MODE {
+ GAIN_MIC_INVALID = -1,
+ GAIN_MIC_NORMAL = 0,
+ GAIN_MIC_VOICE_CALL,
+ GAIN_MIC_CAMCORDER,
+ GAIN_MIC_VOICE_RECOGNITION,
+ GAIN_MIC_VOICE_COMMUNICATION,
+ GAIN_MIC_VOICE_UNLOCK,
+ GAIN_MIC_CUSTOMIZATION1,
+ GAIN_MIC_CUSTOMIZATION2,
+ GAIN_MIC_CUSTOMIZATION3,
+ GAIN_MIC_UNPROCESSED,
+ NUM_GAIN_MIC_MODE,
+ /* the following is DEPRECATED, DO NOT USE!!! */
+ Idle_Normal_Record, // Record, AUDIO_SOURCE_MIC, Sound recording, rcv (else)
+ Idle_Headset_Record, // Record, AUDIO_SOURCE_MIC, Sound recording, hs (else)
+ Voice_Rec_Mic_Handset, // Record, AUDIO_SOURCE_VOICE_RECOGNITION, Voice recognition & CTS verifier, rcv
+ Voice_Rec_Mic_Headset, // Record, AUDIO_SOURCE_VOICE_RECOGNITION, Voice recognition & CTS verifier, hs
+ Idle_Video_Record_Handset, // Record, AUDIO_SOURCE_CAMCORDER, Camera recording, rcv
+ Idle_Video_Record_Headset, // Record, AUDIO_SOURCE_CAMCORDER, Camera recording, hs
+ Normal_Mic, // Speech, NB, RCV
+ Headset_Mic, // Speech, NB, HS
+ Handfree_Mic, // Speech, NB, SPK
+ Normal_WB_Mic, // Speech, WB, RCV
+ Headset_WB_Mic, // Speech, WB, HS
+ Handfree_WB_Mic, // Speech, WB, SPK
+ VOIP_Normal_Mic, // VoIP, Handset
+ VOIP_Headset_Mic, // VoIP, Headset
+ VOIP_Handfree_Mic, // VoIP, Hands-free
+ TTY_CTM_Mic, // Record,
+ Level_Shift_Buffer_Gain, // Record,
+ Analog_PLay_Gain, // Record,
+ Voice_UnLock_Mic_Handset, // Record, AUDIO_SOURCE_VOICE_UNLOCK, , rcv
+ Voice_UnLock_Mic_Headset, // Record, AUDIO_SOURCE_VOICE_UNLOCK, ,hs
+ Customization1_Mic_Handset, // Record, AUDIO_SOURCE_CUSTOMIZATION1, ASR improvement,rcv
+ Customization1_Mic_Headset, // Record, AUDIO_SOURCE_CUSTOMIZATION1, ASR improvement,hs
+ Customization2_Mic_Handset, // Record, AUDIO_SOURCE_CUSTOMIZATION2, , rcv
+ Customization2_Mic_Headset, // Record, AUDIO_SOURCE_CUSTOMIZATION2, ,hs
+ Customization3_Mic_Handset, // Record, AUDIO_SOURCE_CUSTOMIZATION3, ,rcv
+ Customization3_Mic_Headset, // Record, AUDIO_SOURCE_CUSTOMIZATION3, , hs
+};
+
+struct GainTableUnit {
+ unsigned char digital;
+ unsigned char analog[NUM_GAIN_ANA_TYPE];
+};
+
+struct GainTableSidetoneUnit {
+ unsigned char gain;
+};
+
+struct GainTableMicUnit {
+ unsigned char gain;
+};
+
+struct GainTableRingbackToneUnit {
+ unsigned char digital;
+};
+
+struct GainTableForScene {
+ GainTableUnit streamGain[GAIN_STREAM_TYPE_SIZE][NUM_GAIN_DEVICE][GAIN_VOL_INDEX_SIZE];
+ GainTableMicUnit micGain[NUM_GAIN_MIC_MODE][NUM_GAIN_DEVICE];
+};
+
+struct GainTableForNonScene{
+ GainTableUnit speechGain[NUM_GAIN_SPEECH_BAND][NUM_GAIN_SPEECH_NETWORK][NUM_GAIN_DEVICE][GAIN_VOL_INDEX_SIZE];
+ GainTableSidetoneUnit sidetoneGain[NUM_GAIN_SPEECH_BAND][NUM_GAIN_SPEECH_NETWORK][NUM_GAIN_DEVICE];
+ GainTableMicUnit speechMicGain[NUM_GAIN_SPEECH_BAND][NUM_GAIN_SPEECH_NETWORK][NUM_GAIN_DEVICE];
+ GainTableRingbackToneUnit ringbackToneGain[NUM_GAIN_DEVICE][GAIN_VOL_INDEX_SIZE];
+};
+
+struct GainTableParam {
+ int sceneCount;
+ GainTableForScene *sceneGain;
+ GainTableForNonScene nonSceneGain;
+};
+
+struct GainTableSpec {
+ int keyStepPerDb;
+ float keyDbPerStep;
+ float keyVolumeStep;
+
+ int digiDbMax;
+ int digiDbMin;
+
+ int sidetoneIdxMax;
+ int sidetoneIdxMin;
+
+ int micIdxMax[NUM_GAIN_DEVICE];
+ int micIdxMin[NUM_GAIN_DEVICE];
+ int decRecMax;
+ int decRecStepPerDb;
+
+ unsigned int numAudioBufferGainLevel;
+ std::vector<short> audioBufferGainDb;
+ std::vector<short> audioBufferGainIdx;
+ std::vector<std::string> audioBufferGainString;
+ int audioBufferGainPreferMaxIdx;
+ std::string audioBufLMixerName;
+ std::string audioBufRMixerName;
+
+ unsigned int numVoiceBufferGainLevel;
+ std::vector<short> voiceBufferGainDb;
+ std::vector<short> voiceBufferGainIdx;
+ std::vector<std::string> voiceBufferGainString;
+ int voiceBufferGainPreferMaxIdx;
+ std::string voiceBufMixerName;
+
+ unsigned int numLineoutBufferGainLevel;
+ std::vector<short> lineoutBufferGainDb;
+ std::vector<short> lineoutBufferGainIdx;
+ std::vector<std::string> lineoutBufferGainString;
+ int lineoutBufferGainPreferMaxIdx;
+
+ unsigned int numSpkGainLevel;
+ std::vector<short> spkGainDb;
+ std::vector<short> spkGainIdx;
+ std::vector<std::string> spkGainString;
+
+ std::string spkLMixerName;
+ std::string spkRMixerName;
+ GAIN_ANA_TYPE spkAnaType;
+
+ std::vector<short> swagcGainMap[NUM_GAIN_DEVICE];
+ std::vector<short> swagcGainMapDmic[NUM_GAIN_DEVICE];
+ std::vector<short> ulPgaGainMap[NUM_GAIN_DEVICE];
+ std::vector<std::string> ulPgaGainString;
+ int ulGainOffset;
+ int ulPgaGainMapMax;
+ int ulHwPgaIdxMax;
+ std::string ulPgaLMixerName;
+ std::string ulPgaRMixerName;
+
+ std::vector<short> stfGainMap;
+
+ int hpImpEnable;
+ int hpImpOnBoardResistor;
+ int hpImpDefaultIdx;
+ std::vector<short> hpImpThresholdList;
+ std::vector<short> hpImpCompensateList;
+};
+
+#endif //_AUDIO_GAIN_TABLE_PARAM_H_
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioGainTableParamParser.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioGainTableParamParser.h
new file mode 100644
index 0000000..458133a
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioGainTableParamParser.h
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef _AUDIO_GAIN_TABLE_PARAM_PARSER_H_
+#define _AUDIO_GAIN_TABLE_PARAM_PARSER_H_
+
+/*****************************************************************************
+* E X T E R N A L R E F E R E N C E S
+******************************************************************************
+*/
+
+#include <utils/Errors.h>
+#include <vector>
+
+//extern "C" {
+#include "AudioParamParser.h"
+//}
+
+#include "AudioGainTableParam.h"
+
+namespace android {
+
+class GainTableParamParser {
+public:
+ virtual ~GainTableParamParser();
+ static GainTableParamParser *getInstance();
+
+ status_t loadGainTableParam();
+ status_t loadGainTableSpec();
+ status_t loadGainTableMapDl();
+ status_t loadGainTableMapUl();
+ status_t loadGainTableHpImpedance();
+
+ status_t getGainTableParam(GainTableParam *_gainTable, std::vector<std::string> *sceneList);
+ status_t getGainTableSpec(GainTableSpec **_gainTableSpec);
+
+ status_t updatePlaybackDigitalGain(GainTableParam *_gainTable, std::vector<std::string> *sceneList);
+ status_t updatePlaybackAnalogGain(GainTableParam *_gainTable, std::vector<std::string> *sceneList);
+ status_t updateSpeechVol(GainTableParam *_gainTable);
+ status_t updateRecordVol(GainTableParam *_gainTable, std::vector<std::string> *sceneList);
+ status_t updateVoIPVol(GainTableParam *_gainTable, std::vector<std::string> *sceneList);
+ status_t updateRingbackVol(GainTableParam *_gainTable);
+
+ /*
+ * Utility functions
+ */
+ unsigned int audioBufferGainDb2Idx(int dB);
+ unsigned int voiceBufferGainDb2Idx(int dB);
+ unsigned int lineoutBufferGainDb2Idx(int dB);
+ unsigned int spkGainDb2Idx(int dB);
+ int gainIdx2Db(unsigned int idx, int anaType);
+ GAIN_SPEECH_NETWORK getGainSpeechNetwork(const char *name);
+
+public:
+ status_t getSceneList(std::vector<std::string> *sceneList);
+
+private:
+ status_t clearTableParam(GainTableParam *_gainTable, int sceneCount);
+ status_t getCategoryList(AudioType *audioType, std::vector<std::string> *sceneList);
+ bool isInSceneList(std::vector<std::string> *sceneList, std::string scene);
+
+private:
+ GainTableParamParser();
+
+ template<class T>
+ status_t getParam(ParamUnit *_paramUnit, T *_param, const char *_paramName);
+ status_t getParam(ParamUnit *_paramUnit, std::string *_param, const char *_paramName);
+
+ template<class T>
+ status_t getParamVector(ParamUnit *_paramUnit, std::vector<T> *_param, const char *_paramName);
+ status_t getParamVector(ParamUnit *_paramUnit, std::vector<std::string> *_param, const char *_paramName);
+
+ static GainTableParamParser *mGainTableParamParser;
+ AppHandle *mAppHandle;
+
+ GainTableSpec mSpec;
+
+ // store mapping of DL total gain to seperate digital & analog gain
+ std::vector<short> mMapDlDigital[NUM_GAIN_DEVICE];
+ std::vector<short> mMapDlAnalog[NUM_GAIN_DEVICE];
+ GAIN_ANA_TYPE mMapDlAnalogType[NUM_GAIN_DEVICE];
+}; //GainTableParamParser
+
+}
+
+#endif //_AUDIO_GAIN_TABLE_PARAM_PARSER_H_
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioMessengerIPI.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioMessengerIPI.h
new file mode 100644
index 0000000..d9d444c
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioMessengerIPI.h
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_MESSENGER_IPI_H
+#define ANDROID_MESSENGER_IPI_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <AudioLock.h>
+#include <AudioType.h>
+
+#include <audio_messenger_ipi.h>
+
+unsigned int getDspFeatureID(const uint16_t flag);
+
+
+namespace android {
+
+class AudioMessengerIPI {
+public:
+ virtual ~AudioMessengerIPI();
+ static AudioMessengerIPI *getInstance();
+
+
+ virtual void loadTaskScene(const uint8_t task_scene);
+
+
+ virtual status_t sendIpiMsg(
+ struct ipi_msg_t *p_ipi_msg,
+ uint8_t task_scene, /* task_scene_t */
+ uint8_t target_layer, /* audio_ipi_msg_target_layer_t */
+ uint8_t data_type, /* audio_ipi_msg_data_t */
+ uint8_t ack_type, /* audio_ipi_msg_ack_t */
+ uint16_t msg_id,
+ uint32_t param1, /* data_size for payload & dma */
+ uint32_t param2,
+ void *data_buffer); /* buffer for payload & dma */
+
+
+ virtual void registerDmaCbk(
+ const uint8_t task_scene,
+ const uint32_t a2dSize,
+ const uint32_t d2aSize,
+ audio_ipi_dma_cbk_t cbk,
+ void *arg);
+ virtual void deregisterDmaCbk(const uint8_t task_scene);
+
+
+ virtual void registerAdspFeature(const uint16_t feature_id);
+ virtual void deregisterAdspFeature(const uint16_t feature_id);
+
+
+
+protected:
+ AudioMessengerIPI();
+
+ AudioLock mLock;
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static AudioMessengerIPI *mAudioMessengerIPI;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_MESSENGER_IPI_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioMixerOut.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioMixerOut.h
new file mode 100644
index 0000000..1207f12
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioMixerOut.h
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_MIXER_OUT_H
+#define ANDROID_AUDIO_MIXER_OUT_H
+
+#include <system/audio.h>
+#include <utils/KeyedVector.h>
+#include <pthread.h>
+
+#include "AudioType.h"
+#include "AudioUtility.h"
+#include "AudioLock.h"
+
+namespace android {
+
+enum MIXER_USAGE {
+ MIXER_USAGE_UNKNOWN, // just for error handle
+ MIXER_USAGE_BT,
+ MIXER_USAGE_DEEP_FAST, // temp, pre-design
+ MIXER_USAGE_SMARTPA,
+ MIXER_USAGE_NUM,
+};
+
+class MtkAudioSrcBase;
+class AudioALSAPlaybackHandlerBase;
+class AudioALSAStreamManager;
+
+struct MixerOutClient {
+ const void *id;
+ stream_attribute_t attribute;
+ RingBuf dataBuffer;
+
+ bool suspend;
+
+ AudioLock *dataBufferLock;
+
+ // blisrc
+ MtkAudioSrcBase *blisrc;
+ char *blisrcOutBuffer;
+
+ // bit convert
+ audio_format_t dstFmt;
+ audio_format_t srcFmt;
+ char *bitConvertBuffer;
+
+ // screen state
+ bool screenMode;
+ size_t screenBufferSize;
+ size_t screenReduceInterruptSize;
+ bool screenForce;
+};
+
+typedef KeyedVector<const void *, struct MixerOutClient *> MixerOutClientVector;
+
+struct MixerOutInfo {
+ const void *id;
+ enum MIXER_USAGE usage;
+
+ stream_attribute_t attribute;
+ stream_attribute_t attribute2;
+
+ AudioLock *threadLock;
+ AudioLock *waitSuspendLock;
+ AudioLock *waitOutThreadLock;
+
+ MixerOutClientVector *clients;
+ bool clientAllSuspend;
+
+ // bit convert
+ audio_format_t dstFmt;
+ audio_format_t srcFmt;
+ char *bitConvertBuffer;
+
+ unsigned int readBufferTimeUs;
+ unsigned int minWriteFrameCnt;
+
+ AudioALSAPlaybackHandlerBase *playHandler;
+ AudioALSAPlaybackHandlerBase *playHandler2;
+
+ // screen state
+ bool screenMode;
+ size_t screenBufferSize;
+ size_t screenReduceInterruptSize;
+ bool screenForce;
+};
+
+class AudioMixerOut {
+public:
+ static AudioMixerOut *getInstance(enum MIXER_USAGE usage);
+ ~AudioMixerOut();
+
+ status_t attach(const void *id, const stream_attribute_t *attribute);
+ void detach(const void *id);
+
+ size_t write(const void *id, const void *buffer, size_t bytes);
+ status_t setSuspend(const void *id, bool suspend);
+
+ status_t getHardwareBufferInfo(const void *id, time_info_struct_t *HWBuffer_Time_Info);
+ status_t setScreenState(const void *id, bool mode, size_t bufferSize, size_t reduceInterruptSize, bool force = false);
+
+ int getLatency();
+
+private:
+ static AudioMixerOut *mAudioMixerOut;
+ AudioMixerOut(enum MIXER_USAGE usage);
+
+ status_t createOutThread();
+ void destroyOutThread();
+
+ void deleteClient(struct MixerOutClient *client);
+
+ static status_t setScreenState_l(struct MixerOutInfo *info);
+
+ static void *outThread(void *arg);
+
+ static int destroyPlaybackHandler(AudioALSAPlaybackHandlerBase *playbackHandler,
+ AudioALSAStreamManager *streamManager);
+ static bool clientAllSuspend(const MixerOutClientVector *clients);
+ static int waitSignal(AudioLock *mWaitLock, unsigned int waitTimeUs, const char *dbgString);
+
+ // dump
+ static FILE *mixerOutDumpOpen(const char *name, const char *property);
+ static void mixerOutDumpClose(FILE *file);
+ static void mixerOutDumpWriteData(FILE *file, const void *buffer, size_t bytes);
+
+ // blisrc
+ static status_t initBliSrc(struct MixerOutClient *client, const struct MixerOutInfo *outInfo);
+ static status_t deinitBliSrc(struct MixerOutClient *client);
+ static status_t doBliSrc(struct MixerOutClient *client, void *pInBuffer, uint32_t inBytes,
+ void **ppOutBuffer, uint32_t *pOutBytes);
+
+ // bit convert
+ static unsigned int getBitConvertDstBufferSize(audio_format_t dstFmt,
+ audio_format_t srcFmt,
+ unsigned int srcBufSizeByte);
+ static status_t initBitConverter(struct MixerOutClient *client, audio_format_t dstFmt);
+ static status_t initBitConverter(struct MixerOutInfo *info, audio_format_t srcFmt);
+ template<class T>
+ static status_t initBitConverter(T *client, audio_format_t srcFmt, audio_format_t dstFmt);
+ template<class T>
+ static status_t deinitBitConverter(T *client);
+ template<class T>
+ static status_t doBitConversion(T *client,
+ void *pInBuffer, uint32_t inBytes,
+ void **ppOutBuffer, uint32_t *pOutBytes);
+private:
+ AudioLock mLock;
+ AudioLock mWaitSuspendLock;
+ AudioLock mWaitOutThreadLock;
+ AudioLock mThreadLock;
+
+ enum MIXER_USAGE mUsage;
+ struct MixerOutInfo mOutInfo;
+
+ pthread_t mOutThread;
+
+ /**
+ * client vector
+ */
+ MixerOutClientVector mClients;
+ KeyedVector<const void *, AudioLock *> mClientsLock;
+
+ int mDebugType;
+};
+
+}
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioPreProcess.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioPreProcess.h
new file mode 100644
index 0000000..8e3f4fe
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioPreProcess.h
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef _AUDIO_PRE_PROCESS_H
+#define _AUDIO_PRE_PROCESS_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+
+#include <system/audio.h>
+#include <hardware/audio.h>
+#include "AudioType.h"
+#include "AudioSpeechEnhanceInfo.h"
+
+#include <audio_utils/resampler.h>
+#include <audio_utils/echo_reference.h>
+#include <audio_effects/effect_aec.h>
+
+#include <AudioLock.h>
+
+
+namespace android {
+
+struct effect_info_s {
+ effect_handle_t effect_itfe;
+ size_t num_channel_configs;
+ channel_config_t *channel_configs;
+ bool enable;
+};
+
+class AudioPreProcess {
+public:
+ AudioPreProcess(const stream_attribute_t *streamIn_attribute);
+ ~AudioPreProcess();
+
+ void stop_echo_reference(struct echo_reference_itfe *reference);
+ //tuna: void put_echo_reference(struct echo_reference_itfe *reference);
+
+ struct echo_reference_itfe *start_echo_reference(audio_format_t format, uint32_t channel_count, uint32_t sampling_rate);
+ //tuna: echo_reference_itfe *get_echo_reference(audio_format_t format,uint32_t channel_count,uint32_t sampling_rate);
+ void push_echo_reference(size_t frames);
+ int in_configure_reverse(uint32_t channel_count, uint32_t sampling_rate);
+
+ status_t addAudioEffect(effect_handle_t effect);
+ status_t removeAudioEffect(effect_handle_t effect);
+
+ uint32_t NativePreprocess(void *buffer, uint32_t bytes, const time_info_struct_t *Time_Info);
+ uint32_t WriteEchoRefData(void *buffer, uint32_t bytes, const time_info_struct_t *Time_Info);
+
+ status_t CheckNativeEffect(void);
+
+ int num_preprocessors;
+ bool need_echo_reference;
+ struct effect_info_s preprocessors[MAX_PREPROCESSORS];
+ int16_t *proc_buf_in;
+ int16_t *proc_buf_out;
+ size_t proc_buf_size;
+ size_t proc_buf_frames;
+
+private:
+
+ void add_echo_reference(struct echo_reference_itfe *reference);
+ void clear_echo_reference(struct echo_reference_itfe *reference);
+ void remove_echo_reference(struct echo_reference_itfe *reference);
+ int32_t update_echo_reference(size_t frames);
+ int set_preprocessor_echo_delay(effect_handle_t handle, int32_t delay_us);
+ int set_preprocessor_param(effect_handle_t handle, effect_param_t *param);
+ void get_capture_delay(size_t frames, struct echo_reference_buffer *buffer);
+ void get_echoref_delay(size_t frames, struct echo_reference_buffer *buffer);
+
+
+ bool MutexLock(void);
+ bool MutexUnlock(void);
+
+ int16_t *ref_buf;
+ size_t ref_buf_size;
+ size_t ref_buf_frames;
+ struct echo_reference_itfe *mEcho_Reference;
+
+
+ /**
+ * AudioPreProcess lock
+ */
+ AudioLock mLock;
+ //Mutex mLock;
+
+ int mInChn;
+ uint32_t mInSampleRate;
+ AudioSpeechEnhanceInfo *mAudioSpeechEnhanceInfoInstance;
+ const stream_attribute_t *mStreamInAttribute; // for stream in
+
+ time_info_struct_t mTime_Info;
+ time_info_struct_t mTime_Info_echoref;
+ static const uint32_t mEchoRefChannelCount = 2;
+
+ /*
+ * flag of dynamic enable verbose/debug log
+ */
+ int mLogEnable;
+};
+}
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioSCPPhoneCallController.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioSCPPhoneCallController.h
new file mode 100644
index 0000000..b9146ab
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioSCPPhoneCallController.h
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_SCP_PHONE_CALL_CONTROLLER_H
+#define ANDROID_AUDIO_SCP_PHONE_CALL_CONTROLLER_H
+
+#include <system/audio.h>
+#include <pthread.h>
+#include <vector>
+#include <string>
+
+extern "C" {
+#include <alsa_device_profile.h>
+#include <alsa_device_proxy.h>
+}
+#include <AudioLock.h>
+#include "AudioType.h"
+
+struct mixer;
+struct pcm_config;
+
+namespace android {
+
+class AudioSCPPhoneCallController {
+public:
+ static AudioSCPPhoneCallController *getInstance();
+ ~AudioSCPPhoneCallController();
+
+ int enable(unsigned int speechRate, const audio_devices_t inputDevice);
+ int disable();
+ bool isEnable();
+ bool deviceSupport(const audio_devices_t output_devices);
+ bool isSupportPhonecall(const audio_devices_t output_devices);
+
+ int setUSBOutConnectionState(audio_devices_t devices, bool connect, int card, int device);
+ int setUSBInConnectionState(audio_devices_t devices, bool connect, int card, int device);
+ unsigned int getSpeechRate();
+
+ int closeScpSpkHwPcm();
+ int openScpSpkPcmDriverWithFlag(const unsigned int device,
+ unsigned int flag);
+ int openScpSpkPcmDriver(const unsigned int mdUlDevice,
+ const unsigned int dlDevice,
+ const unsigned int ivDevice);
+ int openScpSpkHwPcm();
+ int speechULPhoneMicPath(bool enable);
+
+private:
+ static AudioSCPPhoneCallController *mSCPPhoneCallController;
+ AudioSCPPhoneCallController();
+
+ unsigned int getPeriodByte(const struct pcm_config *config);
+ unsigned int getPcmAvail(struct pcm *pcm);
+ int initSmartPaConfig();
+
+ // debug
+ static void setSCPDebugInfo(bool enable, int dbgType);
+ int setPcmDump(bool benable);
+
+private:
+ AudioLock mLock;
+ bool mEnable;
+ unsigned int mSpeechRate;
+ int mModemIndex;
+ audio_devices_t mInputDevice;
+ struct pcm_config mConfig;
+ struct pcm_config mScpSpkHwConfig;
+ struct pcm *mPcmMicIn;
+ struct pcm *mPcmMicOut;
+ struct pcm *mScpSpkPcmIn;
+ struct pcm *mScpSpkDlHwPcm;
+ struct pcm *mScpSpkIvHwPcm;
+ struct pcm *mScpSpkMdUlHwPcm;
+ static struct mixer *mMixer;
+ struct timespec mLpbkNewTime, mLpbkOldTime, mLpbkStartTime;
+
+ String8 mApTurnOnSequence;
+ String8 mApTurnOnSequence2;
+};
+
+}
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioSmartPaController.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioSmartPaController.h
new file mode 100644
index 0000000..ca25669
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioSmartPaController.h
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_SMART_PA_CONTROLLER_H
+#define ANDROID_AUDIO_SMART_PA_CONTROLLER_H
+
+#ifdef __cplusplus
+#include <AudioLock.h>
+#include "AudioALSADriverUtility.h"
+
+#if defined(MTK_AUDIO_SMARTPASCP_SUPPORT)
+#include "AudioSmartPaParam.h"
+#endif
+
+#endif
+
+struct SmartPaRuntime {
+ unsigned int sampleRate;
+ int mode;
+ int device;
+};
+
+struct SmartPaAttribute {
+ bool isSmartPAUsed;
+ unsigned int dspType;
+ unsigned int chipDelayUs;
+
+ char spkLibPath[128];
+
+ unsigned int supportedRateList[32];
+ unsigned int supportedRateMax;
+ unsigned int supportedRateMin;
+
+ char codecCtlName[128];
+ int isAlsaCodec;
+ int isApllNeeded;
+ unsigned int i2sSetStage;
+
+ int i2sOutSelect;
+ int i2sInSelect;
+};
+
+struct SmartPa;
+struct SmartPaOps {
+ int (*init)(struct SmartPa *smartPa);
+ int (*speakerOn)(struct SmartPaRuntime *runtime);
+ int (*speakerOff)();
+ int (*deinit)();
+ int (*speakerCalibrate)(int calibStage);
+};
+
+struct SmartPa {
+ struct SmartPaOps ops;
+ struct SmartPaRuntime runtime;
+ struct SmartPaAttribute attribute;
+};
+
+enum spk_enhancement_type {
+ SPK_AP_DSP = 0, /* AP Sw Enhancement*/
+ SPK_ONBOARD_DSP = 1, /* SPK on board Enhancement*/
+ SPK_APSCP_DSP = 2, /* SPK AP SCP Enhancement*/
+};
+
+enum spk_type {
+ SPK_INVALID_TYPE = -1,
+ SPK_NOT_SMARTPA,
+ SPK_RICHTEK_RT5509,
+ SPK_MTK_MT6660,
+ SPK_TYPE_NUM
+};
+
+enum spk_i2s_set_stage {
+ SPK_I2S_NO_NEED = 0x1 << 0,
+ SPK_I2S_AUDIOSERVER_INIT = 0x1 << 1,
+ SPK_I2S_BEFORE_PCM_OPEN = 0x1 << 2,
+ SPK_I2S_BEFORE_SPK_ON = 0x1 << 3,
+};
+
+enum spk_calib_stage_t {
+ SPK_CALIB_STAGE_UNKNOWN = -1,
+ SPK_CALIB_STAGE_INIT,
+ SPK_CALIB_STAGE_CALCULATE_AND_SAVE,
+ SPK_CALIB_STAGE_DEINIT,
+};
+
+#ifdef __cplusplus
+namespace android {
+class String8;
+class AudioSmartPaController {
+ AudioSmartPaController();
+ ~AudioSmartPaController();
+
+ int init();
+ int deinit();
+
+ int initSpkAmpType();
+ int initSmartPaAttribute();
+ int initSmartPaRuntime();
+
+
+ static AudioSmartPaController *mAudioSmartPaController;
+ struct SmartPa mSmartPa;
+
+ struct mixer *mMixer;
+
+ struct pcm *mPcmEcho;
+ struct pcm *mPcmEchoUL;
+
+ void *mLibHandle;
+ int (*mtk_smartpa_init)(struct SmartPa *smartPa);
+ void setSmartPaRuntime(unsigned int device);
+ int transformDeviceIndex(const unsigned int device);
+ bool isCalibrating;
+
+public:
+ static AudioSmartPaController *getInstance();
+
+ int speakerOn(unsigned int sampleRate, unsigned int device);
+ int speakerOff();
+
+ int dspOnBoardSpeakerOn(unsigned int sampleRate);
+ int dspOnBoardSpeakerOff();
+
+ unsigned int getSmartPaDelayUs();
+
+ unsigned int getMaxSupportedRate();
+ unsigned int getMinSupportedRate();
+ bool isRateSupported(unsigned int rate);
+
+ bool isAlsaCodec();
+ bool isHwDspSpkProtect(const int device);
+ bool isSwDspSpkProtect(const int device);
+ bool isApSideSpkProtect();
+ bool isBypassSwDspSpkProtect();
+ unsigned int getSpkProtectType();
+ int getI2sSetStage();
+ bool isInCalibration();
+
+ bool isSmartPAUsed();
+
+ int getI2sOutSelect();
+ int getI2sInSelect();
+ String8 getI2sSequence(const char *sequence, bool input = false);
+ String8 getSphEchoRefSequence(bool enable, int md);
+
+ int setI2sHD(bool enable, int i2sSelect);
+ int setI2sOutHD(bool enable);
+ int setI2sInHD(bool enable);
+
+ bool isSmartPADynamicDetectSupport();
+ int setSmartPaCalibration(int calibStage);
+};
+
+}
+#endif
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioSmartPaParam.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioSmartPaParam.h
new file mode 100644
index 0000000..41398be
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioSmartPaParam.h
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_SMART_PA_PARAM_H
+#define ANDROID_AUDIO_SMART_PA_PARAM_H
+
+#include "AudioLock.h"
+#include "AudioALSADriverUtility.h"
+#include <arsi_type.h>
+
+#define SMARTPA_STR_LENGTH (256)
+
+/* string should comapre with prefix + vendor + suffix*/
+const char smartpa_aurisys_set_param_prefix[] = "AURISYS_SET_PARAM,DSP,PLAYBACK,SMARTPA";
+const char smartpa_aurisys_get_param_prefix[] = "AURISYS_GET_PARAM,DSP,PLAYBACK,SMARTPA";
+
+
+struct SmartPAParamOps {
+ int (*loadParam)(const string_buf_t *product_name,
+ const string_buf_t *param_file_path,
+ const debug_log_fp_t debug_log_fp);
+ int (*queryParamSize)(const arsi_task_config_t *p_arsi_task_config,
+ const arsi_lib_config_t *p_arsi_lib_config,
+ const string_buf_t *product_name,
+ const string_buf_t *param_file_path,
+ const string_buf_t *custom_info,
+ uint32_t *p_param_buf_size,
+ const debug_log_fp_t debug_log_fp);
+ int (*parsingParamFile)(const arsi_task_config_t *p_arsi_task_config,
+ const arsi_lib_config_t *p_arsi_lib_config,
+ const string_buf_t *product_name,
+ const string_buf_t *param_file_path,
+ const string_buf_t *custom_info,
+ data_buf_t *p_param_buf,
+ const debug_log_fp_t debug_log_fp);
+};
+
+struct ipi_msg_t;
+
+namespace android {
+
+class AudioMessengerIPI;
+
+class AudioSmartPaParam {
+
+public:
+ ~AudioSmartPaParam();
+
+ int setParameter(const char *keyValuePair);
+ char *getParameter(const char *key);
+
+
+ /**
+ * get instance's pointer
+ */
+ static AudioSmartPaParam *getInstance(void);
+
+ int setArsiTaskConfig(const arsi_task_config_t * ArsiTaskConfig);
+ int setArsiLibConfig(const arsi_lib_config_t * mArsiLibConfig);
+ int setSmartpaParam();
+ int setParamFilePath(const char *str);
+
+protected:
+
+ AudioSmartPaParam();
+ static void processSmartPaDmaMsg(ipi_msg_t *msg, void *buf, uint32_t size, void *arg);
+
+private:
+ static AudioSmartPaParam *mAudioSmartPaParam;
+ AudioMessengerIPI *mAudioMessengerIPI;
+ void parseSetParameterStr(const char *inputStr, char **outputStr,
+ const int paramindex);
+ bool checkParameter(int ¶mindex, int &direction, const char *keyValuePair);
+ int getsetParameterPrefixlength(int paramindex);
+ int getgetParameterPrefixlength(int paramindex);
+ int setProductName(const char *str);
+ char *getParamFilePath(void);
+ char *getProductName(void);
+ int getDefalutParamFilePath(void);
+ int getDefaultProductName(void);
+
+
+ void initArsiTaskConfig(void);
+ void initArsiLibconfig(void);
+
+ char mSmartParamFilePath[SMARTPA_STR_LENGTH];
+ char mPhoneProductName[SMARTPA_STR_LENGTH];
+
+ arsi_task_config_t *mArsiTaskConfig;
+ arsi_lib_config_t *mArsiLibConfig;
+ data_buf_t *mParamBuf;
+
+ bool mEnableLibLogHAL;
+
+ void *mLibHandle;
+ struct SmartPAParamOps mSmartPAParam;
+ int (*mtk_smartpa_param_init)(struct SmartPAParamOps *mSmartPAParam);
+
+};
+
+}
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioSpeechEnhLayer.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioSpeechEnhLayer.h
new file mode 100644
index 0000000..7b55015
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioSpeechEnhLayer.h
@@ -0,0 +1,417 @@
+// SPDX-License-Identifier: MediaTekProprietary
+
+#ifndef _AUDIO_SPEECH_ENH_LAYER_H
+#define _AUDIO_SPEECH_ENH_LAYER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+#include <system/audio.h>
+#include <hardware/audio.h>
+#include <utils/SortedVector.h>
+#include "AudioType.h"
+#include <AudioLock.h>
+
+extern "C" {
+#include "enh_api.h"
+}
+
+namespace android {
+/*
+typedef unsigned short uWord16;
+typedef signed short Word16;
+typedef signed long Word32;
+typedef unsigned long uWord32;
+
+typedef struct {
+
+ uWord32 enhance_pars[28];
+// uWord32 error_flag;
+ Word32 App_table;
+ Word32 Fea_Cfg_table;
+ Word32 MIC_DG;
+ Word32 sample_rate;
+ Word32 frame_rate;
+ Word32 MMI_ctrl;
+ Word32 RCV_DG; // for VoIP, 0xE3D
+ Word16 DMNR_cal_data[76];
+ Word16 Compen_filter[270];
+// Word16 ne_out[960];
+// Word16 fe_out[960];
+ Word16 PCM_buffer[1920];
+ Word16 EPL_buffer[4160];
+ Word32 Device_mode; //routing path
+ Word32 MMI_MIC_GAIN; //Uplink path total gain
+ Word32 Near_end_vad;
+ Word32 *SCH_mem; // caster to (SCH_mem_struct*) in every alloc function
+} SPH_ENH_ctrl_struct;
+
+*/
+
+#define EnhanceModeParasExtNum 32
+#define EnhanceParasNum (28+EnhanceModeParasExtNum)
+#define DMNRCalDataNum 76
+#define CompenFilterNum 270
+
+#define Rec48KUL2BufStartAddr 960
+#define Rec16KUL2BufStartAddr 320
+
+#define RecBufSize48K20ms 960
+#define RecBufSize48K10ms 480
+#define RecBufSize48K5ms 240
+#define RecBufSize48K3ms 144
+#define RecBufSize48K2ms 96
+#define RecBufSize48K1ms 48
+
+
+
+#define RecBufSize16K20ms 320
+#define RecBufSize16K10ms 160
+#define RecBufSize16K5ms 80
+#define RecBufSize16K3ms 48
+#define RecBufSize16K2ms 32
+#define RecBufSize16K1ms 16
+
+
+
+
+#define EPLBufSize 4800
+#define MaxVMSize 1922 //960*2 +2 for 48K
+#define VMAGC1 3847
+#define VMAGC2 3848
+
+#define VM_DUMP_FILE_NAME_SIZE (128)
+
+
+enum SPE_MMI_CONTROL_TABLE {
+ UL_MUTE = (1 << 0), // Bit 0, UL mute
+ NORMAL_DMNR = (1 << 1), // Bit 1, normal DMNR
+ VCE = (1 << 2), // Bit 2, VCE
+ BWE = (1 << 3), // Bit 3, BWE
+ UL_NR = (1 << 4), // Bit 4, UL NR
+ DL_NR = (1 << 5), // Bit 5, DL NR
+ HANDSFREE_DMNR = (1 << 6), // Bit 6, handsfree mode DMNR
+ HANDSFREE_DMNR_ASR = (1 << 15), // Bit 15, handsfree mode ASR DMNR
+ MMI_CONTROL_MASK_ALL = 0xFFFFFFFF
+};
+
+typedef enum {
+ DMNR_DISABLE = 0,
+ DMNR_NORMAL = 1,
+ DMNR_HANDSFREE
+} DMNR_TYPE;
+
+typedef enum {
+ SPE_MODE_NONE = 0,
+ SPE_MODE_REC = 1,
+ SPE_MODE_VOIP = 2,
+ SPE_MODE_AECREC
+} SPE_MODE;
+
+
+typedef enum {
+ SPE_STATE_IDLE = 0,
+ SPE_STATE_START = 1,
+ SPE_STATE_RUNNING = 2,
+ SPE_STATE_CLEANING
+} SPE_STATE;
+
+
+typedef enum {
+ NB_VOIP = 0x1,
+ WB_VOIP = 0x2,
+ MONO_RECORD = 0x4,
+ STEREO_RECORD = 0x8,
+ SPEECH_RECOGNITION = 0x10,
+ MONO_AEC_RECORD = 0x20,
+ STEREO_AEC_RECORD = 0x40,
+ LOW_LATENCY_RECORD = 0x80
+} SPE_APP_TABLE;
+
+/*
+typedef enum
+{
+ AGC = 0x1,
+ AEC = 0x2,
+ DMNR = 0x4
+} SPE_FEA_TABLE;
+*/
+
+typedef enum {
+ UPLINK = 0,
+ DOWNLINK
+} SPE_DATA_DIRECTION;
+
+typedef enum {
+ ROUTE_NONE = -1,
+ ROUTE_NORMAL = 0,
+ ROUTE_HEADSET = 1,
+ ROUTE_SPEAKER = 2,
+ ROUTE_BT = 3,
+ ROUTE_EARPHONE = 4,
+ ROUTE_BT_NSEC_OFF_PATH = 5,
+ ROUTE_MAX = 6
+} SPE_ROUTE;
+
+typedef struct _SphEnhOps {
+ void *handle;
+ Word32(*ENH_API_Get_Memory)(SPH_ENH_ctrl_struct *Sph_Enh_ctrl);
+ Word16(*ENH_API_Alloc)(SPH_ENH_ctrl_struct *Sph_Enh_ctrl, Word32 *mem_ptr);
+ Word16(*ENH_API_Rst)(SPH_ENH_ctrl_struct *Sph_Enh_ctrl);
+ void (*ENH_API_Process)(SPH_ENH_ctrl_struct *Sph_Enh_ctrl);
+ Word16(*ENH_API_Free)(SPH_ENH_ctrl_struct *Sph_Enh_ctrl);
+ Word16(*ENH_API_Get_Version)(SPH_ENH_ctrl_struct *Sph_Enh_ctrl);
+} SphEnhOps;
+
+struct BufferInfo {
+ short *pBufBase;
+ int BufLen;
+ short *pRead; //short
+ short *pWrite; //short
+ int BufLen4Delay;
+ short *pRead4Delay; //short
+ short *pWrite4Delay; //short
+ bool DLfirstBuf;
+ struct timespec time_stamp_queued; //buffer queue time
+ struct timespec time_stamp_estimate; //estimate buffer consume start time
+ struct timespec time_stamp_process;
+};
+
+
+struct InBufferInfo {
+ short *pBufBase;
+ uint32_t BufLen;
+ struct timespec time_stamp_queued; //buffer queue time
+ bool bHasRemainInfo;
+ struct timespec time_stamp_predict; //predict time output from hardware
+};
+
+struct StreamAttribute {
+ int mSampleRate;
+ int mChannels;
+ int mBufferSize;
+};
+
+class SPELayer {
+public:
+ SPELayer();
+ ~SPELayer();
+
+ ////can remove below parameter setting function+++
+ bool SetEnhPara(SPE_MODE mode, uWord32 *pEnhance_pars);
+ bool SetDMNRPara(SPE_MODE mode, Word16 *pDMNR_cal_data);
+ bool SetCompFilter(SPE_MODE mode, Word16 *pCompen_filter);
+ bool SetMICDigitalGain(SPE_MODE mode, Word32 gain);
+ bool SetUpLinkTotalGain(SPE_MODE mode, uint8_t gain);
+ ////can remove below parameter setting function---
+ bool SetSampleRate(SPE_MODE mode, long sample_rate);
+ bool SetFrameRate(SPE_MODE mode, long frame_rate);
+ bool SetAPPTable(SPE_MODE mode, SPE_APP_TABLE App_table);
+ bool SetFeaCfgTable(SPE_MODE mode, Word32 Fea_Cfg_table);
+ bool SetPlatfromTimeOffset(int ms);
+ bool SetChannel(int channel);
+ // bool SetMode(SPE_MODE mode);
+ bool SetRoute(SPE_ROUTE route);
+ bool GetUPlinkIntrStartTime(void);
+ bool SetUPLinkIntrStartTime(struct timespec UPlinkStartTime);
+ void SetUPLinkDropTime(uint32_t droptime);
+ void SetDownLinkLatencyTime(uint32_t latencytime);
+
+ bool GetDownlinkIntrStartTime(void);
+ bool SetDynamicFuncCtrl(const SPE_MMI_CONTROL_TABLE func, const bool enable);
+
+ bool Start(SPE_MODE mode);
+ int Process(InBufferInfo *InBufinfo);
+ bool Stop();
+ bool Standby();
+
+
+ int GetLatencyTime();
+ SPE_MODE GetMode();
+ SPE_ROUTE GetRoute();
+ long GetSampleRate(SPE_MODE mode);
+ long GetFrameRate(SPE_MODE mode);
+ Word32 GetMICDigitalGain(SPE_MODE mode);
+ Word32 GetAPPTable(SPE_MODE mode);
+ Word32 GetFeaCfgTable(SPE_MODE mode);
+ int GetChannel();
+ bool GetEnhPara(SPE_MODE mode, uWord32 *pEnhance_pars);
+ bool GetDMNRPara(SPE_MODE mode, Word16 *pDMNR_cal_data);
+ bool GetCompFilter(SPE_MODE mode, Word16 *pCompen_filter);
+ bool IsSPERunning();
+ void SetStreamAttribute(bool direct, StreamAttribute SA); //direct=0 =>downlink stream info, direct=1 =>uplink stream info
+
+
+ bool MutexLock(void);
+ bool MutexUnlock(void);
+ bool DumpMutexLock(void);
+ bool DumpMutexUnlock(void);
+ void dump(void);
+
+ void Dump_Enalbe_Check(void);
+ void Dump_PCM_In(SPE_DATA_DIRECTION dir, void *buffer, int bytes);
+ void Dump_PCM_Process(SPE_DATA_DIRECTION dir, void *buffer, int bytes);
+ void Dump_PCM_Out(SPE_DATA_DIRECTION dir, void *buffer, int bytes);
+ void Dump_EPL(void *buffer, int bytes);
+ bool CreateDumpThread();
+ void DumpBufferClear(void);
+ bool HasBufferDump();
+ void EPLTransVMDump();
+ void SetVMDumpEnable(bool bEnable);
+ void SetVMDumpFileName(const char *VMFileName);
+
+ //void WriteReferenceBuffer(short *inBuf, int inBufLength);
+ void WriteReferenceBuffer(struct InBufferInfo *Binfo);
+ void SetOutputStreamRunning(bool bRunning, bool bFromOutputStart = 0);
+ void EnableNormalModeVoIP(bool bSet);
+ void SetEchoRefStartTime(struct timespec EchoRefStartTime);
+
+ Vector<BufferInfo *> mDumpDLInBufferQ, mDumpDLOutBufferQ, mDumpULOutBufferQ, mDumpULInBufferQ, mDumpEPLBufferQ;
+#if defined(PC_EMULATION)
+ HANDLE hDumpThread;
+#else
+ pthread_t hDumpThread;
+#endif
+
+ FILE *mfpInDL;
+ FILE *mfpInUL;
+ FILE *mfpOutDL;
+ FILE *mfpOutUL;
+ FILE *mfpProcessedDL;
+ FILE *mfpProcessedUL;
+ FILE *mfpEPL;
+ FILE *mfpVM;
+ static int DumpFileNum;
+ static bool EPLDebugEnable;
+
+ AudioLock mDumpExitMutex;
+
+private:
+
+ void ReStart();
+ void Clear();
+ //void AddtoInputBuffer(SPE_DATA_DIRECTION dir, short *inBuf, int inBufLength, bool prequeue=0);
+ void AddtoInputBuffer(SPE_DATA_DIRECTION dir, struct InBufferInfo *BInputInfo, bool prequeue = 0);
+ void AddUplinkBuffer(struct InBufferInfo *BInputInfo);
+ void AddDownlinkBuffer(struct InBufferInfo *BInputInfo, bool prequeue = 0);
+ int Process_Record(short *inBuf, int inBufLength);
+ int Process_VoIP(short *inBuf, int inBufLength);
+ void CompensateBuffer(size_t BufLength, struct timespec CompenStartTime);
+
+ bool WaitforDownlinkData(void);
+ bool InsertDownlinkData(void);
+
+ bool PrepareProcessData(void);
+ int GetVoIPJitterTime(void);
+ int GetVoIPLatencyTime(void);
+ void FlushBufferQ(void);
+ void CalPreQNumber(void);
+ void CalPrepareCount(void);
+ void BypassDLBuffer(void);
+ void ReSync(void);
+
+ //inBufLength is time2 buffer's Sample frame count
+ unsigned long long TimeStampDiff(BufferInfo *BufInfo1, BufferInfo *BufInfo2);
+ bool TimeStampCompare(BufferInfo *BufInfo1, BufferInfo *BufInfo2, bool Endtime);
+ bool TimeCompare(struct timespec time1, struct timespec time2);
+ unsigned long long TimeDifference(struct timespec time1, struct timespec time2);
+
+ void DropDownlinkData(uint32_t dropsample);
+
+ SphEnhOps mSphEnhOps;
+ SPE_MODE mMode;
+ SPE_ROUTE mRoute;
+ SPE_STATE mState;
+ Word32 mMMI_ctrl_mask;
+ //Record settings
+ Word32 mRecordSampleRate;
+ Word32 mRecordFrameRate;
+ Word32 mRecordMICDigitalGain; //MIC_DG
+ Word32 mRecordULTotalGain; //uplink total gain
+ uWord32 mRecordEnhanceParas[EnhanceParasNum];
+ Word16 mRecordDMNRCalData[DMNRCalDataNum];
+ Word16 mRecordCompenFilter[CompenFilterNum];
+ Word32 mRecordApp_table;
+ Word32 mRecordFea_Cfg_table;
+
+ //VoIP settings
+ int mLatencyTime;
+ int mPlatformOffsetTime;
+ int mLatencySampleCount;
+ Word32 mVoIPSampleRate;
+ Word32 mVoIPFrameRate;
+ Word32 mVoIPMICDigitalGain; //MIC_DG
+ Word32 mVoIPULTotalGain; //uplink total gain
+ uWord32 mVoIPEnhanceParas[EnhanceParasNum];
+ Word16 mVoIPDMNRCalData[DMNRCalDataNum];
+ Word16 mVoIPCompenFilter[CompenFilterNum];
+ Word32 mVoIPApp_table;
+ Word32 mVoIPFea_Cfg_table;
+ bool mNeedDelayLatency;
+ bool mLatencyDir;
+
+ bool mNeedJitterBuffer;
+ int mJitterBufferTime;
+ int mDefaultJitterBufferTime;
+ int mJitterSampleCount;
+
+ struct timespec mUplinkIntrStartTime;
+ struct timespec mDownlinkIntrStartTime;
+ struct timespec mPreUplinkEstTime;
+ struct timespec mPreDownlinkEstTime;
+ struct timespec mPreDownlinkQueueTime;
+
+ uint32_t mULDropTime;
+ uint32_t mDLLatencyTime;
+ bool mFirstVoIPUplink;
+ bool mFirstVoIPDownlink;
+ int mPreULBufLen;
+ int mPreDLBufLen;
+ bool mDLNewStart;
+ bool mPrepareProcessDataReady;
+ int mDLPreQnum;
+ bool mDLPreQLimit;
+ unsigned long long mNsecPerSample;
+ struct timespec mULIntrDeltaTime;
+
+ SPH_ENH_ctrl_struct mSph_Enh_ctrl;
+ int *mSphCtrlBuffer;
+ int mSPEProcessBufSize;
+ /* BufferInfo *mpSPEBufferUL1;
+ BufferInfo *mpSPEBufferUL2;
+ BufferInfo *mpSPEBufferDL;
+ BufferInfo *mpSPEBufferDLDelay;
+ */
+ short *mpSPEBufferUL1;
+ short *mpSPEBufferUL2;
+ short *mpSPEBufferDL;
+ short *mpSPEBufferDLDelay;
+ short *mpSPEBufferNE;
+ short *mpSPEBufferFE;
+
+ int mULInBufQLenTotal, mDLInBufQLenTotal, mULOutBufQLenTotal, mDLOutBufQLenTotal, mDLDelayBufQLenTotal;
+
+ Vector<BufferInfo *> mDLInBufferQ, mDLOutBufferQ, mULOutBufferQ, mULInBufferQ, mDLDelayBufferQ;
+ //Vector<BufferInfo> mULInBufferQ;
+
+ Mutex mLock, mDumpLock, mBufMutexWantLock;
+ bool mError;
+ bool mVoIPRunningbefore;
+
+ AudioLock mBufMutex;
+
+ bool mOutputStreamRunning;
+ bool mNormalModeVoIP;
+ size_t mCompensatedBufferSize;
+ int DLdataPrepareCount;
+ StreamAttribute mDLStreamAttribute;
+ bool mNewReferenceBufferComes;
+
+ //VM
+ Word16 mVM[MaxVMSize];
+ bool mVMDumpEnable;
+ char mVMDumpFileName[VM_DUMP_FILE_NAME_SIZE];
+};
+}
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioSpeechEnhanceInfo.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioSpeechEnhanceInfo.h
new file mode 100644
index 0000000..4f3cd84
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioSpeechEnhanceInfo.h
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_SPEECH_ENHANCE_INFO_H
+#define AUDIO_SPEECH_ENHANCE_INFO_H
+
+//#include "AudioUtility.h"
+#include <utils/threads.h>
+#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
+#include <utils/TypeHelpers.h>
+#include <utils/Vector.h>
+#include <utils/String16.h>
+
+#include "SpeechType.h"
+#include "AudioType.h"
+#include <AudioLock.h>
+
+#include "AudioCustParamClient.h"
+
+namespace android {
+
+enum TOOL_TUNING_MODE {
+ TUNING_MODE_NONE = 0,
+ NORMAL_MODE_DMNR = 1,
+ HANDSFREE_MODE_DMNR = 2
+};
+
+
+class AudioSpeechEnhanceInfo {
+public:
+
+ static AudioSpeechEnhanceInfo *getInstance();
+ AudioSpeechEnhanceInfo();
+ ~AudioSpeechEnhanceInfo();
+
+ //BesRecord Preprocess +++
+ void SetBesRecScene(int32_t BesRecScene);
+ int32_t GetBesRecScene(void);
+ void ResetBesRecScene(void);
+ //BesRecord Preprocess ---
+
+ //get the MMI switch info
+ void UpdateDynamicSpeechEnhancementMask(const voip_sph_enh_mask_struct_t &mask);
+ status_t SetDynamicVoIPSpeechEnhancementMask(const voip_sph_enh_dynamic_mask_t dynamic_mask_type, const bool new_flag_on);
+ voip_sph_enh_mask_struct_t GetDynamicVoIPSpeechEnhancementMask() const { return mVoIPSpeechEnhancementMask; }
+
+ //Engineer mode enable MagiASR+++
+ status_t GetForceMagiASRState();
+ bool SetForceMagiASR(bool enable);
+ //Engineer mode MagiASR---
+
+ //Engineer mode enable AECRecord+
+ bool GetForceAECRecState();
+ bool SetForceAECRec(bool enable);
+ //Engineer mode enable AECRecord-
+
+ //----------------Audio tunning +++ --------------------------------
+ //----------------for AP DMNR tunning --------------------------------
+ void SetAPDMNRTuningEnable(bool bEnable);
+ bool IsAPDMNRTuningEnable(void);
+ bool SetAPTuningMode(const TOOL_TUNING_MODE mode);
+ int GetAPTuningMode(void);
+ //----------------for HDRec tunning --------------------------------
+ void SetBesRecTuningEnable(bool bEnable);
+ bool IsBesRecTuningEnable(void);
+
+ status_t SetBesRecVMFileName(const char *fileName);
+ void GetBesRecVMFileName(char *VMFileName, size_t string_size);
+ //----------------Audio tunning --- --------------------------------
+#ifndef MTK_AURISYS_FRAMEWORK_SUPPORT
+ void PreLoadBesRecordParams(void);
+ void UpdateBesRecordParams(void);
+ void GetPreLoadBesRecordSceneTable(AUDIO_HD_RECORD_SCENE_TABLE_STRUCT *pPara);
+ void GetPreLoadBesRecordParam(AUDIO_HD_RECORD_PARAM_STRUCT *pPara);
+ void GetPreLoadAudioVoIPParam(AUDIO_VOIP_PARAM_STRUCT *pPara);
+ void GetPreLoadDualMicSpeechParam(AUDIO_CUSTOM_EXTRA_PARAM_STRUCT *pSphParamDualMic);
+#endif
+ //----------------for Hifi Record --- --------------------------------
+ void SetHifiRecord(bool bEnable);
+ bool GetHifiRecord(void);
+
+ //----------------for debug --- --------------------------------
+ bool GetDebugStatus(void);
+
+private:
+
+ /**
+ * singleton pattern
+ */
+ static AudioSpeechEnhanceInfo *mAudioSpeechEnhanceInfo;
+
+ /**
+ * AudioSpeechEnhanceInfo lock
+ */
+ AudioLock mLock;
+
+ //BesRecord Preprocess +++
+ int32_t mBesRecScene;
+
+#ifndef MTK_AURISYS_FRAMEWORK_SUPPORT
+ AUDIO_HD_RECORD_SCENE_TABLE_STRUCT mPreLoadBesRecordSceneTable;
+ AUDIO_HD_RECORD_PARAM_STRUCT mPreLoadBesRecordParam;
+ AUDIO_VOIP_PARAM_STRUCT mPreLoadVOIPParam;
+ AUDIO_CUSTOM_EXTRA_PARAM_STRUCT mPreLoadDMNRParam;
+#endif
+ //BesRecord Preprocess ---
+
+ //for BesRec tuning
+ bool mBesRecTuningEnable;
+ char mVMFileName[VM_FILE_NAME_LEN_MAX];
+ //for AP DMNR tunning
+ bool mAPDMNRTuningEnable;
+ int mAPTuningMode;
+
+ //Tina todo
+ // KeyedVector<AudioALSAStreamIn *, SPELayer *> mSPELayerVector; // vector to save current recording client
+ voip_sph_enh_mask_struct_t mVoIPSpeechEnhancementMask;
+
+ //Engineer mode enable MagiASR+++
+ bool mForceMagiASR;
+ //Engineer mode MagiASR---
+
+ //Engineer mode enable AECRecord+
+ bool mForceAECRec;
+ //Engineer mode enable AECRecord-
+
+ //for Normal record with high sample rate (>48K)
+ bool mHiFiRecordEnable;
+
+ //for debug purpose, temp using
+ bool mDebugflag;
+
+ /**
+ * AudioCustParamClient
+ */
+ AudioCustParamClient *mAudioCustParamClient;
+};
+
+}
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioType.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioType.h
new file mode 100644
index 0000000..b113f41
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioType.h
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef __AUDIO_TYPE_H__
+#define __AUDIO_TYPE_H__
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Vector.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+#include <hardware/audio_effect.h>
+
+#include "AudioAssert.h"
+
+
+#ifndef int32
+typedef signed int int32;
+#endif
+
+#ifndef uint32
+typedef unsigned int uint32;
+#endif
+
+#if defined(ANDROID)
+using android::status_t;
+#endif
+
+#ifndef status_t
+typedef int status_t;
+#endif
+
+#define VM_FILE_NAME_LEN_MAX (128)
+#define SCENE_NAME_LEN_MAX (64)
+
+#define MAX_PREPROCESSORS 3 /* maximum one AGC + one NS + one AEC per input stream */
+#ifndef UPLINK_LOW_LATENCY //no need to drop data
+#define CAPTURE_DROP_MS (120) //drop 120ms record data in carture data normal provider due to hardware pulse
+#else
+#define CAPTURE_DROP_MS (0) //drop 120ms record data in carture data normal provider due to hardware pulse
+#endif
+#define UPLINK_NORMAL_LATENCY_MS (20)
+
+#ifdef UPLINK_LOW_LATENCY_CHIP_MS
+#define UPLINK_LOW_LATENCY_MS (UPLINK_LOW_LATENCY_CHIP_MS) // audio low latency param - record - interrupt rate
+#else
+#define UPLINK_LOW_LATENCY_MS (5) // audio low latency param - record - interrupt rate
+#endif
+
+#define MMAP_DL_PERIOD_SIZE 96
+#define MMAP_UL_PERIOD_SIZE 96
+
+#define MIN_MMAP_PERIOD_COUNT 4
+#define MAX_MMAP_FRAME_COUNT 4096 // max hw buffer size of share mode
+#define MAX_MMAP_HW_BUFFER_SIZE 8192 // max hw buffer size of exclusive mode
+
+
+#ifdef AUDIO_UTIL_PULSE_LEVEL
+#define PULSE_LEVEL (AUDIO_UTIL_PULSE_LEVEL)
+#else
+#define PULSE_LEVEL (800)
+#endif
+
+// when call I2S start , need parameters for I2STYPE
+typedef enum {
+ MATV, //I2S Input For ATV
+ FMRX, //I2S Input For FMRX
+ FMRX_32K, //I2S Input For FMRX_32K
+ FMRX_48K, //I2S Input For FMRX_48K
+ I2S0OUTPUT, // I2S0 output
+ I2S1OUTPUT, // I2S1 output
+ HOA_SAMPLERATE, // use for HQA support
+ NUM_OF_I2S
+} I2STYPE;
+
+#define AUDIO_LOCK_TIMEOUT_VALUE_MS (5000) //The same with ANR
+
+#if 1 //HP switch
+//#define HIFIDAC_SWITCH
+//#define SWITCH_BEFORE_HPAMP
+//#define HIFI_SWITCH_BY_AUDENH
+
+//#define EXTDAC_PMIC_MUTE
+//#define RINGTONE_USE_PMIC
+#endif
+
+// TODO(Harvey): move it to somewhere else
+/**
+ * Playback handler types
+ */
+enum playback_handler_t {
+ PLAYBACK_HANDLER_BASE = -1,
+ PLAYBACK_HANDLER_NORMAL,
+ PLAYBACK_HANDLER_BT_SCO,
+ PLAYBACK_HANDLER_FM_TX,
+ PLAYBACK_HANDLER_HDMI,
+ PLAYBACK_HANDLER_VOICE,
+ PLAYBACK_HANDLER_BT_CVSD,
+ PLAYBACK_HANDLER_OFFLOAD, //doug
+ PLAYBACK_HANDLER_FAST,
+ PLAYBACK_HANDLER_SPEAKERPROTECTION,
+ PLAYBACK_HANDLER_USB,
+ PLAYBACK_HANDLER_DEEP_BUFFER,
+ PLAYBACK_HANDLER_MIXER,
+ PLAYBACK_HANDLER_VOIP,
+ PLAYBACK_HANDLER_MAX,
+};
+
+/**
+ * Capture handler types
+ */
+enum capture_handler_t {
+ CAPTURE_HANDLER_BASE = (1 << 0),
+ CAPTURE_HANDLER_NORMAL = (1 << 1),
+ CAPTURE_HANDLER_VOICE = (1 << 2),
+ CAPTURE_HANDLER_FM_RADIO = (1 << 3),
+ CAPTURE_HANDLER_SPK_FEED = (1 << 4),
+ CAPTURE_HANDLER_ANC = (1 << 5),
+ CAPTURE_HANDLER_BT = (1 << 6),
+ CAPTURE_HANDLER_AEC = (1 << 7),
+ CAPTURE_HANDLER_TDM = (1 << 8),
+ CAPTURE_HANDLER_MODEM_DAI = (1 << 9),
+ CAPTURE_HANDLER_SYNCIO = (1 << 10),
+ CAPTURE_HANDLER_DSP = (1 << 11),
+ CAPTURE_HANDLER_ALL = 0xFFFFFFFF,
+};
+
+
+/**
+ * Capture Data Provider types
+ */
+enum capture_provider_t {
+ CAPTURE_PROVIDER_BASE = -1,
+ CAPTURE_PROVIDER_NORMAL,
+ CAPTURE_PROVIDER_VOICE,
+ CAPTURE_PROVIDER_FM_RADIO,
+ CAPTURE_PROVIDER_SPK_FEED,
+ CAPTURE_PROVIDER_ANC,
+ CAPTURE_PROVIDER_ECHOREF,
+ CAPTURE_PROVIDER_ECHOREF_BTSCO,
+ CAPTURE_PROVIDER_ECHOREF_BTCVSD,
+ CAPTURE_PROVIDER_ECHOREF_EXT,
+ CAPTURE_PROVIDER_TDM_RECORD,
+ CAPTURE_PROVIDER_EXTERNAL,
+ CAPTURE_PROVIDER_BT_SCO,
+ CAPTURE_PROVIDER_BT_CVSD,
+ CAPTURE_PROVIDER_VOW,
+ CAPTURE_PROVIDER_AP_VOICE_DL,
+ CAPTURE_PROVIDER_USB_BASE,
+ CAPTURE_PROVIDER_USB,
+ CAPTURE_PROVIDER_ECHOREF_USB,
+ CAPTURE_PROVIDER_DSP,
+ CAPTURE_PROVIDER_MAX
+};
+
+/**
+ * speech enhancement function dynamic mask
+ * This is the dynamic switch to decided the enhancment output.
+ */
+enum voip_sph_enh_dynamic_mask_t {
+ VOIP_SPH_ENH_DYNAMIC_MASK_DMNR = (1 << 0), // for receiver
+ VOIP_SPH_ENH_DYNAMIC_MASK_VCE = (1 << 1),
+ VOIP_SPH_ENH_DYNAMIC_MASK_BWE = (1 << 2),
+ VOIP_SPH_ENH_DYNAMIC_MASK_LSPK_DMNR = (1 << 5), // for loud speaker
+ VOIP_SPH_ENH_DYNAMIC_MASK_ALL = 0xFFFFFFFF
+};
+
+enum {
+ VOICE_MIXER_TYPE_MIX,
+ VOICE_MIXER_TYPE_REPLACE
+};
+
+typedef struct {
+ uint32_t dynamic_func; // DMNR,VCE,BWE,
+} voip_sph_enh_mask_struct_t;
+
+typedef struct {
+ bool besrecord_enable;
+ int32_t besrecord_scene;
+ bool besrecord_voip_enable;
+ //for VoIP dymanic mask
+ voip_sph_enh_mask_struct_t besrecord_dynamic_mask;
+ //for besrecord tuning
+ bool besrecord_tuningEnable;
+ char besrecord_VMFileName[VM_FILE_NAME_LEN_MAX];
+ bool besrecord_tuning16K;
+ //for engineer mode
+ bool besrecord_ForceMagiASREnable;
+ bool besrecord_ForceAECRecEnable;
+ //for AP DMNR tunning
+ bool besrecord_dmnr_tuningEnable;
+ int32_t besrecord_dmnr_tuningMode;
+ //for temp using
+ bool besrecord_bypass_dualmicprocess;
+} besrecord_info_struct_t;
+
+typedef struct {
+ bool PreProcessEffect_Update;
+ int PreProcessEffect_Count;
+ bool PreProcessEffect_AECOn;
+ effect_handle_t PreProcessEffect_Record[MAX_PREPROCESSORS];
+
+} native_preprocess_info_struct_t;
+
+
+typedef struct {
+ timespec timestamp_get;
+ unsigned int frameInfo_get; //for input: remains data(frame) in kernel buffer. for output: empty data(frame) in kernel buffer size
+ unsigned int buffer_per_time; //for input: frames read per read. For output: kernel buffer size(frame)
+ unsigned int total_frames_readed; //for input: total frames readed
+ unsigned long kernelbuffer_ns; //calculated kernel buffer time
+ int halQueuedFrame;
+} time_info_struct_t;
+
+struct afe_offload_codec_t {
+ unsigned int codec_samplerate;
+ unsigned int codec_bitrate;
+ unsigned int disable_codec;
+};
+
+struct stream_attribute_t {
+ audio_format_t audio_format;
+ int audio_offload_format;
+ audio_channel_mask_t audio_channel_mask;
+ union {
+ audio_output_flags_t mAudioOutputFlags;
+ audio_input_flags_t mAudioInputFlags;
+ };
+
+ afe_offload_codec_t offload_codec_info;
+
+ audio_devices_t output_devices;
+
+ audio_devices_t input_device;
+ audio_source_t input_source;
+
+ uint32_t num_channels;
+ uint32_t sample_rate;
+
+ uint32_t buffer_size;
+ size_t frame_count;
+ uint32_t latency;
+ uint32_t interrupt_samples;
+
+ audio_in_acoustics_t acoustics_mask;
+
+ bool digital_mic_flag;
+
+ bool bBypassPostProcessDL;
+ bool micmute;
+#if defined(MTK_SPEAKER_MONITOR_SPEECH_SUPPORT)
+ bool bFixedRouting;
+ bool bModemDai_Input;
+#endif
+ audio_mode_t audio_mode;
+
+ uint32_t mStreamOutIndex; // AudioALSAStreamOut pass to AudioALSAStreamManager
+
+ char mCustScene[SCENE_NAME_LEN_MAX];
+ besrecord_info_struct_t BesRecord_Info;
+
+ native_preprocess_info_struct_t NativePreprocess_Info;
+ time_info_struct_t Time_Info;
+
+ uint8_t u8BGSDlGain;
+ uint8_t u8BGSUlGain;
+
+ double mInterrupt;
+ bool mVoIPEnable;
+
+ // sync device info with audio policy
+ bool usePolicyDevice;
+ audio_devices_t policyDevice;
+
+ bool mPowerHalEnable; // for PowerHAL debug
+
+ bool isMixerOut;
+
+ unsigned int dspLatency;
+
+ uint8_t mPcmMixTypeDl;
+ uint8_t mPcmMixTypeUl;
+};
+
+
+enum sgen_mode_t {
+ SGEN_MODE_I00_I01 = 0,
+ SGEN_MODE_I02 = 1,
+ SGEN_MODE_I03_I04 = 2,
+ SGEN_MODE_I05_I06 = 3,
+ SGEN_MODE_I07_I08 = 4,
+ SGEN_MODE_I09 = 5,
+ SGEN_MODE_I10_I11 = 6,
+ SGEN_MODE_I12_I13 = 7,
+ SGEN_MODE_I14 = 8,
+ SGEN_MODE_I15_I16 = 9,
+ SGEN_MODE_I17_I18 = 10,
+ SGEN_MODE_I19_I20 = 11,
+ SGEN_MODE_I21_I22 = 12,
+ SGEN_MODE_O00_O01 = 13,
+ SGEN_MODE_O02 = 14,
+ SGEN_MODE_O03_O04 = 15,
+ SGEN_MODE_O05_O06 = 16,
+ SGEN_MODE_O07_O08 = 17,
+ SGEN_MODE_O09_O10 = 18,
+ SGEN_MODE_O11 = 19,
+ SGEN_MODE_O12 = 20,
+ SGEN_MODE_O13_O14 = 21,
+ SGEN_MODE_O15_O16 = 22,
+ SGEN_MODE_O17_O18 = 23,
+ SGEN_MODE_O19_O20 = 24,
+ SGEN_MODE_O21_O22 = 25,
+ SGEN_MODE_O23_O24 = 26,
+ SGEN_MODE_DISABLE = 27,
+ SGEN_MODE_O03 = 28, // sgen to o3 o4, but mute o4
+ SGEN_MODE_O04 = 29, // sgen to o3 o4, but mute o3
+ SGEN_MODE_I25_I26 = 30,
+ SGEN_MODE_O25 = 31,
+ SGEN_MODE_O28_O29 = 32,
+ SGEN_MODE_I23_I24 = 33,
+ SGEN_MODE_O32_O33 = 34,
+ SGEN_MODE_I34_I35 = 35
+};
+
+enum sgen_mode_samplerate_t {
+ SGEN_MODE_SAMPLERATE_8000HZ = 0,
+ SGEN_MODE_SAMPLERATE_11025HZ = 1,
+ SGEN_MODE_SAMPLERATE_12000HZ = 2,
+ SGEN_MODE_SAMPLERATE_16000HZ = 3,
+ SGEN_MODE_SAMPLERATE_22050HZ = 4,
+ SGEN_MODE_SAMPLERATE_24000HZ = 5,
+ SGEN_MODE_SAMPLERATE_32000HZ = 6,
+ SGEN_MODE_SAMPLERATE_44100HZ = 7,
+ SGEN_MODE_SAMPLERATE_48000HZ = 8
+};
+
+typedef enum {
+ AUDIO_MIC_MODE_ACC = 1,
+ AUDIO_MIC_MODE_DCC,
+ AUDIO_MIC_MODE_DMIC,
+ AUDIO_MIC_MODE_DMIC_LP,
+ AUDIO_MIC_MODE_DCCECMDIFF,
+ AUDIO_MIC_MODE_DCCECMSINGLE,
+ AUDIO_MIC_MODE_DMIC_VENDOR01
+} AUDIO_MIC_MODE;
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioTypeExt.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioTypeExt.h
new file mode 100644
index 0000000..d7aca5d
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioTypeExt.h
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef __AUDIO_TYPE_EXT_H__
+#define __AUDIO_TYPE_EXT_H__
+
+#include "AudioType.h"
+
+const audio_source_t AUDIO_SOURCE_VOICE_UNLOCK = (audio_source_t)80;
+const audio_source_t AUDIO_SOURCE_CUSTOMIZATION1 = (audio_source_t)81;
+const audio_source_t AUDIO_SOURCE_CUSTOMIZATION2 = (audio_source_t)82;
+const audio_source_t AUDIO_SOURCE_CUSTOMIZATION3 = (audio_source_t)83;
+const audio_output_flags_t AUDIO_OUTPUT_FLAG_PLAYBACK = (audio_output_flags_t)2048; // 0x800
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioUSBPhoneCallController.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioUSBPhoneCallController.h
new file mode 100644
index 0000000..0198c0c
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioUSBPhoneCallController.h
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_USB_PHONE_CALL_CONTROLLER_H
+#define ANDROID_AUDIO_USB_PHONE_CALL_CONTROLLER_H
+
+#include <system/audio.h>
+#include <pthread.h>
+extern "C" {
+#include <alsa_device_profile.h>
+#include <alsa_device_proxy.h>
+}
+
+#include <vector>
+#include <string>
+
+#include <AudioLock.h>
+#include "AudioType.h"
+
+struct mixer;
+struct pcm_config;
+
+namespace android {
+class MtkAudioSrcBase;
+
+struct USBStream {
+ int direction;
+ unsigned int speechRate;
+ unsigned int latency;
+
+ // usb control
+ std::string deviceId;
+ size_t deviceParamIdx;
+ alsa_device_profile profile;
+ alsa_device_proxy proxy;
+ float usbLatency;
+
+ // hal 2 afe control
+ struct pcm_config pcmConfigHAL2AFE;
+ struct pcm *pcmHAL2AFE;
+ std::string apTurnOnSequence;
+
+ // blisrc
+ MtkAudioSrcBase *blisrc;
+ char *blisrcOutBuffer;
+
+ // bit convert
+ audio_format_t dstFmt;
+ audio_format_t srcFmt;
+ char *bitConvertBuffer;
+
+ // data pending
+ unsigned int dataPendingOutBufSize;
+ char *dataPendingOutBuffer;
+ char *dataPendingTempBuffer;
+ unsigned int dataPendingRemainBufSize;
+ /*
+ unsigned int dataPendingDesireOutBufSize;
+ unsigned int dataPendingOutBufSize;
+ unsigned int dataPendingTempBufSize;
+ unsigned int dataPendingOutRemainBufSize;
+ char *dataPendingOutBuffer;
+ char *dataPendingTempBuffer;
+ unsigned int dataPendingRemainBufSize;
+ */
+
+ // throttle control
+ unsigned int throttleTargetAvail;
+ unsigned int throttleKickInAvailDiff;
+ unsigned int throttleSteadyAvailDiff;
+ unsigned int throttleOrigAvailDiff;
+ unsigned int throttleSpeedUpFactor;
+ unsigned int throttleSpeedUpCount;
+ unsigned int throttleKickInCount;
+ unsigned int throttleCurrentInRate;
+ int throttleState;
+};
+
+struct USBDeviceParam {
+ std::string id;
+ int playbackLatencyUs;
+ int captureLatencyUs;
+};
+
+struct USBCallParam {
+ int speechDlUlLatencyUs; // latency of usb dl + usb ul path
+ int speechDlLatencyUs; // latency of usb dl + audio analog mic path
+ int speechUlLatencyUs; // latency of usb ul + audio analog playback path
+ int echoSettlingTimeMs;
+ int echoAheadMicDataUs;
+
+ std::vector<struct USBDeviceParam> deviceParam;
+ int maxCaptureLatencyUs;
+};
+
+class AudioUSBPhoneCallController {
+public:
+ static AudioUSBPhoneCallController *getInstance();
+ ~AudioUSBPhoneCallController();
+
+ int enable(unsigned int speechRate);
+ int disable();
+ bool isEnable();
+ bool isForceUSBCall();
+ bool isUsingUSBIn();
+
+ int setUSBOutConnectionState(audio_devices_t devices, bool connect, int card, int device);
+ int setUSBInConnectionState(audio_devices_t devices, bool connect, int card, int device);
+
+ unsigned int getSpeechRate();
+ audio_devices_t getUSBCallInDevice();
+
+ std::string getUSBIdSpeechDL();
+ std::string getUSBIdSpeechUL();
+
+ // param
+ void updateXmlParam(const char *_audioTypeName);
+private:
+ static AudioUSBPhoneCallController *mUSBPhoneCallController;
+ AudioUSBPhoneCallController();
+
+ // speech downlink related
+ static void *speechDLThread(void *arg);
+
+ // utility function
+ static int prepareUSBStream(struct USBStream *stream);
+ static int getSpeech2HALPcmConfig(struct USBStream *stream);
+ static unsigned int getPeriodByte(const struct pcm_config *config);
+
+ // speech uplink related
+ static void *speechULThread(void *arg);
+ int speechULPhoneMicPath(bool enable);
+
+ // echo ref
+ int setEchoRefPath(bool enable, int stage);
+ int setEchoRefDebugPath(bool enable);
+
+ // dump
+ static FILE *pcmDumpOpen(const char *name, const char *property);
+ static void pcmDumpClose(FILE *file);
+ static void pcmDumpWriteData(FILE *file, const void *buffer, size_t bytes);
+
+ // blisrc
+ static status_t initBliSrc(struct USBStream *stream);
+ static status_t deinitBliSrc(struct USBStream *stream);
+ static status_t doBliSrc(struct USBStream *stream, void *pInBuffer, uint32_t inBytes,
+ void **ppOutBuffer, uint32_t *pOutBytes);
+ static status_t resetBliSrcBuffer(struct USBStream *stream);
+
+ // bit convert
+ static unsigned int getBitConvertDstBufferSize(audio_format_t dstFmt,
+ audio_format_t srcFmt,
+ unsigned int srcBufSizeByte);
+ static status_t initBitConverter(struct USBStream *stream);
+ static status_t deinitBitConverter(struct USBStream *stream);
+ static status_t doBitConversion(struct USBStream *stream,
+ void *pInBuffer, uint32_t inBytes,
+ void **ppOutBuffer, uint32_t *pOutBytes);
+
+ // data pending
+ static status_t initDataPending(struct USBStream *stream);
+ static status_t deinitDataPending(struct USBStream *stream);
+ static status_t doDataPending(struct USBStream *stream,
+ void *pInBuffer, uint32_t inBytes,
+ void **ppOutBuffer, uint32_t *pOutBytes);
+
+ // throttle
+ static unsigned int getStreamWriteRate(struct USBStream *stream);
+ static unsigned int getStreamReadRate(struct USBStream *stream);
+
+ static status_t throttleInit(struct USBStream *stream);
+ static status_t throttleReset(struct USBStream *stream);
+ static status_t throttleSetSrcInRate(struct USBStream *stream, unsigned int rate);
+ static status_t throttleResetCurrentRate(struct USBStream *stream);
+ static status_t throttleSetCompensateInRate(struct USBStream *stream,
+ unsigned int changeMsPerSecond,
+ int state);
+ static status_t throttleControl(struct USBStream *stream);
+
+ // lpbk test
+ bool getLpbkTime(unsigned int idx, void *buffer, unsigned int bufferSize,
+ unsigned int channel, unsigned int rate, size_t format_size);
+
+ static unsigned int getPcmAvail(struct pcm *pcm);
+
+ // perf service function
+ int initPerfService();
+ void deinitPerfService();
+ void enablePerfCpuScn();
+ void disablePerfCpuScn();
+
+ // debug
+ static void setDebugInfo(bool enable, int dbgType);
+
+ // param
+ status_t loadUSBCallParam();
+ status_t loadUSBDeviceParam();
+
+ status_t getDeviceId(struct USBStream *stream);
+ status_t getDeviceParam(struct USBStream *stream);
+ unsigned int getEchoMaxDelayUs();
+ unsigned int getEchoCurrentDelayUs();
+
+private:
+ AudioLock mLock;
+
+ bool mEnable;
+ bool mAudioHWReady;
+ unsigned int mSpeechRate;
+ int mModemIndex;
+
+ bool mUSBOutConnected;
+ struct USBStream mUSBOutStream;
+
+ bool mUSBInConnected;
+ bool mEnableWithUSBInConnected;
+ struct USBStream mUSBInStream;
+
+ struct pcm *mPcmMicOut;
+ struct pcm *mPcmMicIn;
+
+ struct pcm *mPcmEchoRefOut;
+ struct pcm *mPcmEchoRefIn;
+
+ struct pcm *mPcmEchoRefDebugOut;
+ struct pcm *mPcmEchoRefDebugOut2;
+
+ static struct mixer *mMixer;
+
+ pthread_t mSphDLThread;
+ pthread_t mSphULThread;
+
+ int mLpbkType;
+ bool mLpbkStart;
+ float mLpbkTime, mLpbkTimePart[4];
+ struct timespec mLpbkNewTime, mLpbkOldTime, mLpbkStartTime;
+ int mLpbkPulseThres;
+
+ int mDebugType;
+
+ int mEchoRefState;
+ AudioLock mEchoRefStateLock;
+
+ struct USBCallParam mParam;
+
+ int32_t mPowerHalHandle;
+};
+
+}
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioVUnlockDL.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioVUnlockDL.h
new file mode 100644
index 0000000..69da2f4
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioVUnlockDL.h
@@ -0,0 +1,265 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+/*******************************************************************************
+ *
+ * Filename:
+ * ---------
+ * AudioVPWStreamIn.cpp
+ *
+ * Project:
+ * --------
+ * Android
+ *
+ * Description:
+ * ------------
+ * Stream In Downlink data for voice password (user space)
+ *
+ * Author:
+ * -------
+ *
+ *------------------------------------------------------------------------------
+ * $Revision$
+ * $Modtime:$
+ * $Log:$
+ *
+ * 09 24 2013 donglei.ji
+ * [ALPS01026663] voice ui&unlock feature latency tuning
+ * .
+ *
+ * 10 01 2012 vend_Wendy.lin
+ *
+ *
+ *******************************************************************************/
+
+#ifndef ANDROID_AUDIO_VPWStreamIn_H
+#define ANDROID_AUDIO_VPWStreamIn_H
+
+/*****************************************************************************
+* C O M P I L E R F L A G S
+******************************************************************************
+*/
+
+/*****************************************************************************
+* E X T E R N A L R E F E R E N C E S
+******************************************************************************
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+#include "MtkAudioComponent.h"
+#include "AudioUtility.h"
+
+
+/*****************************************************************************
+* C O N S T A N T S
+******************************************************************************
+*/
+//#define VPW_Buffer_Count (2)
+#define forUT
+//VPW stream In read once size
+#define VOICE_UNLOCK_RING_BUFFER_SIZE (16384*2) //140ms 48k 2ch data length
+// I2S buffer size
+#define VPW_OUTPUT_SAMPLERATE (16000)
+namespace android {
+
+
+/*****************************************************************************
+* D A T A T Y P E S
+******************************************************************************
+
+this enum also defined the capability of I2S , for example , now I2S is support I2S_INPUT ,
+I2S_OUTPUT and I2S1_OUTPUT
+*/
+typedef enum {
+ VPWStreamIn_NONE = 0x0,
+ VPWStreamIn_CREATED = 0x1,
+ VPWStreamIn_READ_START = 0x2,
+ VPWStreamIn_WRITE_START = 0x4,
+} VPWStreamInSTATE;
+
+typedef struct {
+ char *pBufBase;
+ char *pRead;
+ char *pWrite;
+ char *pBufEnd;
+ int bufLen;
+ bool buffull;
+} rb_vpw;
+
+
+
+/*****************************************************************************
+* C L A S S D E F I N I T I O N
+******************************************************************************
+*/
+class AudioVUnlockDL;
+class AudioVUnlockRingBuf;
+
+class AudioVUnlockRingBuf {
+public:
+ AudioVUnlockRingBuf();
+ ~AudioVUnlockRingBuf();
+
+ int32_t Write(void *buf, uint32_t datasz);
+ int32_t Read(void *buf, uint32_t datasz);
+ /* AdvanceReadPointer only advance read pointer, no R/W operation*/
+ uint32_t AdvanceReadPointer(uint32_t datasz);
+ /*ReadWithoutAdvance only read data from buffer without advance read ptr */
+ uint32_t ReadWithoutAdvance(void *buf, uint32_t datasz);
+ uint32_t GetBuflength(void);
+ uint32_t GetBufDataSz(void);
+ uint32_t GetBufSpace(void);
+ /*wait if no data to read*/
+ uint32_t WaitBufData(void);
+ /*signal if data exist for read*/
+ uint32_t SignalBufData(void);
+
+ uint32_t ResetBuf(void);
+
+ uint32_t WriteAdvance(void *buf, uint32_t datasz);
+ uint32_t ReadAdvance(void *buf, uint32_t datasz);
+private:
+
+ rb_vpw mbuf;
+ pthread_mutex_t mBufMutex;
+ pthread_cond_t mBuf_Cond;
+ char mbufAddr[VOICE_UNLOCK_RING_BUFFER_SIZE];
+
+};
+
+
+class AudioVUnlockDL {
+public:
+ AudioVUnlockDL();
+ ~AudioVUnlockDL();
+
+ static AudioVUnlockDL *StreamOutGetInstance();
+ static AudioVUnlockDL *getInstance();
+ /*startInput create a read thread to move data, must be called first before R/W start */
+ bool startInput(void);
+ /* stopInput will terminate the read thread*/
+ bool stopInput(void);
+ /* for stream out to write data to ring buffer*/
+ int32_t WriteStreamOutToRing(const void *buf, uint32_t datasz);
+ /*read reference data from stream ring buffer, if no data in ring buffer, write zeroes to buf.*/
+ int32_t ReadRefFromRing(void *buf, uint32_t datasz, void *DLtime);
+ int32_t GetState(void);
+ void ClearState(uint32_t state);
+ void SetState(uint32_t state);
+ bool StateInputStart(void);
+ static void freeInstance();
+
+ int32_t GetSRCInputParameter(uint32_t inSR, /* Input, input sampling rate of the conversion */
+ uint32_t inChannel, /* Input, input channel number of the conversion */
+ audio_format_t format
+ );
+ int32_t SetSRC(uint32_t outSR, /* Input, output sampling rate of the conversion */
+ uint32_t outChannel /* Input, output channel number of the conversion */);
+ /*DoSRC : return data consumed.*/
+ int32_t DoSRC(uint8_t *inbuf, /* input buffer pointer*/
+ uint32_t *datasz, /* input: data in input buffer, output: data left in input buffer */
+ uint8_t *outbuf, /*output buffer pointer*/
+ uint32_t *outlength); /*input: buffer length of output buffer, output: data produced */
+ /*return latency in ms*/
+ int32_t GetLatency(void);
+ int32_t DumpData(void *buf, uint32_t datasz);
+ void SetInputStandBy(bool val);
+ void GetStreamOutLatency(int32_t latency);
+ bool StreamOutStandBy();
+ int GetShareMemory(int *fd, int *size, uint *flags);
+ int32_t SetUplinkStartTime(struct timespec uplinkStartTime, int clear);
+ int32_t SetUplinkStartTime(struct timespec uplinkStartTime);
+ int32_t SetDownlinkStartTime(int remainMs);
+ int32_t GetVoiceUnlockULTime(void *ULtime);
+ int32_t GetFirstDLTime();
+#ifdef forUT
+ bool StateStartwrite(void);
+ bool startWrite(void);
+
+ bool stopWrite();
+
+
+ bool mWriteThreadExit;
+ bool mWriteThreadActive;
+ pthread_t mWriteThread; // readthread to move data from mRingBufIn to mRingBufOut
+
+
+#endif
+ AudioVUnlockRingBuf mRingBufIn; // input ring buffer
+ AudioVUnlockRingBuf mRingBufOut; //output ring buffer
+ bool mReadThreadExit;
+ bool mReadThreadActive;
+ bool mReadFunctionActive;
+ // for dump file
+ FILE *mOutFile;
+ FILE *mOutFile_1;
+ FILE *mOutFile_2;
+ struct timespec mDLtime;
+ struct timespec mNewDLtime;
+ struct timespec mStandbyTime;
+
+ bool mGetTime;
+ uint32_t mInRemaining;
+ uint32_t mOutRemaining;
+ uint32_t mInChannel; // input channel for SRC
+ uint32_t mOutChannel; // output channel for SRC
+ uint32_t mOutputSampleRate; //output sampling rate for src
+ uint32_t mInputSampleRate; // input sampling rate for src
+private:
+ MtkAudioSrcBase *mpSrcHdl ; //SRC handle
+ uint32_t mSrcBufLen; // SRC working buffer length
+ pthread_t mReadThread; // readthread to move data from mRingBufIn to mRingBufOut
+ int32_t mState;
+ bool mInputStandby; // True : stream out is in standby mode, False: stream out is writing.
+ // for mutiple access to AudioVUnlockDL, need to protect when multiple access.
+ //pthread_mutex_t mVUnlockReadMutex;
+ int32_t mStreamOutLatency;
+ pthread_mutex_t mSRCMutex;
+ uint32_t mSampleCount_Dump;
+ struct timespec mULtime;
+ bool mNeedBlock;
+ uint32_t mFormat;
+ int32_t *mTempBuf;
+ int32_t mTempBufsz;
+};
+
+
+}; // namespace android
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioVolumeFactory.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioVolumeFactory.h
new file mode 100644
index 0000000..1928fd1
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioVolumeFactory.h
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_VOLUME_FACTORY_H
+#define AUDIO_VOLUME_FACTORY_H
+
+#ifdef MTK_AUDIO_GAIN_TABLE
+
+#ifdef MTK_NEW_VOL_CONTROL
+#include "AudioALSAGainController.h"
+#else
+#include "AudioMTKGainController.h"
+#endif
+
+#else
+#include "AudioALSAVolumeController.h"
+#endif
+
+#include "AudioVolumeInterface.h"
+
+class AudioVolumeFactory {
+public:
+ // here to implement create and
+ static AudioVolumeInterface *CreateAudioVolumeController();
+ static void DestroyAudioVolumeController();
+private:
+};
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioVolumeInterface.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioVolumeInterface.h
new file mode 100644
index 0000000..b4a9c6f
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/AudioVolumeInterface.h
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_VOLUME_INTERFACE_H
+#define ANDROID_AUDIO_VOLUME_INTERFACE_H
+
+#include "AudioType.h"
+#include <system/audio.h>
+#include <utils/Errors.h>
+#include <utils/Vector.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+//! A AudioVolumeInterface interface
+/*!
+ this class is hold for volume controlb base on mode and device.
+ need to take care both input and output volume.
+*/
+
+class AudioVolumeInterface {
+public:
+ /**
+ * virtual destrutor
+ */
+ virtual ~AudioVolumeInterface() {};
+
+ /**
+ * check volume control init done.
+ * @return status_t
+ */
+ virtual status_t initCheck() = 0;
+
+ /**
+ * volume controller init funciton
+ * @return status_t
+ */
+ virtual status_t initVolumeController() = 0;
+
+ /**
+ * volume controller setMasterVolume, usually set master volume is by setting analog gain,
+ * @param v
+ * @param mode
+ * @param routes
+ * @return status_t
+ */
+ virtual status_t setMasterVolume(float v, audio_mode_t mode, uint32_t devices) = 0 ;
+
+ /**
+ * volume controller GetMasterVolume
+ * @return mastervolume
+ */
+ virtual float getMasterVolume() = 0 ;
+
+ /**
+ * volume controller setVoiceVolume, usually set voice volume is use by incall mode
+ * @param v
+ * @param mode
+ * @param routes
+ * @return status_t
+ */
+ virtual status_t setVoiceVolume(float v, audio_mode_t mode, uint32_t devices) = 0 ;
+ virtual status_t setVoiceVolume(int MapVolume, uint32_t device) = 0;
+ virtual status_t ApplyVoiceGain(int degradeDb, audio_mode_t mode, uint32_t device) = 0;
+ virtual status_t setVoiceVolume(int index, int devices, audio_mode_t mode) = 0;
+
+ /**
+ * volume controller getVoiceVolume
+ * @return VoiceVolume
+ */
+ virtual float getVoiceVolume(void) = 0;
+
+ /**
+ * volume controller setStreamVolume, this function basicaaly use for FM or MATV
+ * which need set volume by hardware, diogital is set by audiopolicymanager.
+ * @param stream
+ * @param v
+ * @return status_t
+ */
+ virtual status_t setStreamVolume(int stream, float v) = 0 ;
+
+ /**
+ * volume controller setStreamMute
+ * @param stream
+ * @param mute
+ * @return status_t
+ */
+ virtual status_t setStreamMute(int stream, bool mute) = 0 ;
+
+ /**
+ * volume controller getStreamVolume
+ * @param stream
+ * @return status_t
+ */
+ virtual float getStreamVolume(int stream) = 0;
+
+ /**
+ * volume controller setFmVolume
+ * Set FM playback volume
+ * @param volume
+ * @return bool
+ */
+ virtual status_t setFmVolume(const float volume) = 0;
+
+ /**
+ * Audio Tuning tool set playback gain
+ */
+ virtual int ApplyAudioGainTuning(int Gain, uint32_t mode, uint32_t device) = 0;
+
+ /**
+ * volume controller SetSideTone
+ * base on mode gain and route to decide sidetone gain
+ * @param Mode
+ * @param Gain
+ * @param routes
+ * @return status_t
+ */
+ virtual status_t SetSideTone(uint32_t Mode, uint32_t gain) = 0 ;
+
+ /**
+ * volume controller GetSideToneGain
+ * base on output device get sidetone gain
+ * @param device
+ * @return gain
+ */
+ virtual uint32_t GetSideToneGain(uint32_t device) = 0 ;
+
+ /**
+ * volume controller SetMicGain
+ * base on mode gain and route to decide sidetone gain
+ * @param Mode
+ * @param Gain
+ * @param routes
+ * @return status_t
+ */
+ virtual status_t SetMicGain(uint32_t Mode, uint32_t gain) = 0 ;
+
+ /**
+ * volume controller SetULTotalGain
+ * base on mode and gain
+ * @param Mode
+ * @param Gain
+ * @return status_t
+ */
+ virtual status_t SetULTotalGain(uint32_t Mode, unsigned char Volume) = 0 ;
+
+ /**
+ * volume controller ApplyMicGain
+ * base on mode gain and MicType to decide mic gain
+ * @param MicType
+ * @param Mode
+ */
+ virtual status_t ApplyMicGain(uint32_t MicType, int mode) = 0 ;
+
+ /**
+ * volume controller SetCaptureGain
+ * base on mode gain and MicType to decide mic gain
+ * @param Mode
+ * @param Input Source
+ * @param Input device
+ * @param Output devices
+ */
+ virtual status_t SetCaptureGain(audio_mode_t mode, audio_source_t source, audio_devices_t input_device, audio_devices_t output_devices) = 0 ;
+
+ /**
+ * volume controller SetDigitalHwGain
+ * base on mode gain and route to decide sidetone GAIN_MUTE
+ * @param Mode
+ * @param Gain
+ * @param routes
+ * @return status_t
+ */
+ virtual status_t SetDigitalHwGain(uint32_t Mode, uint32_t Gain, uint32_t devices) = 0 ;
+
+ /**
+ * volume controller GetSWMICGain
+ * get MIC software digital gain for HD record library
+ */
+ virtual short GetSWMICGain(void) = 0 ;
+
+ /**
+ * volume controller GetULTotalGain
+ * get MIC software digital gain for BesRecord library
+ */
+ virtual uint8_t GetULTotalGain(void) = 0 ;
+
+
+ /**
+ * volume controller Set modem DL gain
+ * @param Gain
+ * @return status_t
+ */
+ virtual void ApplyMdDlGain(int Gain) = 0 ;
+
+
+ /**
+ * volume controller Set modem DL Ehn gain
+ * @param Gain
+ * @return status_t
+ */
+ virtual void ApplyMdDlEhn1Gain(int Gain) = 0 ;
+
+ /**
+ * volume controller Set modem Ul gain
+ * @param Gain
+ * @return status_t
+ */
+ virtual void ApplyMdUlGain(int Gain) = 0 ;
+
+ /**
+ * volume controller map volume to digital gain
+ * @param Gain
+ * @return digital gain
+ */
+ virtual uint16_t MappingToDigitalGain(unsigned char Gain) = 0 ;
+
+ /**
+ * volume controller map volume to PGA gain
+ * @param Gain
+ * @return PGA gain
+ */
+ virtual uint16_t MappingToPGAGain(unsigned char Gain) = 0 ;
+
+ /**
+ * volume controller SetMicGainTuning
+ * base on mode gain and route to decide sidetone gain
+ * @param Mode
+ * @param Gain
+ * @param routes
+ * @return status_t
+ */
+ virtual status_t SetMicGainTuning(uint32_t Mode, uint32_t gain) = 0 ;
+
+ virtual status_t ApplySideTone(uint32_t Mode) = 0 ;
+ // alsa driver set pga gain function
+ virtual void SetReceiverGain(int DrgradeDb) = 0 ;
+ virtual void SetHeadPhoneRGain(int DrgradeDb) = 0 ;
+ virtual void SetHeadPhoneLGain(int DrgradeDb) = 0 ;
+ virtual void SetLinoutRGain(int DrgradeDb) = 0 ;
+ virtual void SetLinoutLGain(int DrgradeDb) = 0 ;
+ virtual void SetSpeakerGain(int DegradedBGain) = 0 ;
+ virtual uint32_t GetOffloadGain(float vol_f) = 0;
+
+#ifdef MTK_AUDIO_GAIN_TABLE
+ virtual status_t setAnalogVolume(int stream, int device, int index, audio_mode_t mode) = 0;
+ virtual status_t speechNetworkChange(unsigned int info) = 0;
+ virtual bool isNbSpeechBand(void) = 0;
+ virtual status_t setBtVolumeCapability(bool support) = 0;
+ virtual void setAudioBufferGain(int gain) = 0;
+#else
+ virtual void setAudioBufferGain(int gain __unused) {};
+#endif
+
+ virtual int16_t getVoiceDlAnalogGain(int index, int device, audio_mode_t mode) = 0;
+ virtual uint16_t getVoiceUlAnalogGain(uint32_t device, audio_mode_t mode) = 0;
+ virtual int setSpeakerType(int type) = 0;
+};
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/IAudioALSACaptureDataClient.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/IAudioALSACaptureDataClient.h
new file mode 100644
index 0000000..9c43f49
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/IAudioALSACaptureDataClient.h
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_I_AUDIO_ALSA_CAPTURE_DATA_CLIENT_H
+#define ANDROID_I_AUDIO_ALSA_CAPTURE_DATA_CLIENT_H
+
+#include <AudioType.h>
+#include <AudioUtility.h>
+
+
+namespace android {
+
+class AudioALSACaptureDataProviderBase;
+
+/// Observer pattern: Observer
+class IAudioALSACaptureDataClient {
+public:
+ IAudioALSACaptureDataClient(AudioALSACaptureDataProviderBase *pCaptureDataProvider, stream_attribute_t *stream_attribute_target);
+ virtual ~IAudioALSACaptureDataClient() {};
+
+
+ /**
+ * set client index
+ */
+ virtual void *getIdentity() const = 0;
+
+ /**
+ * set/get raw frame count from hardware
+ */
+ virtual void setRawStartFrameCount(int64_t frameCount) = 0;
+ virtual int64_t getRawStartFrameCount() = 0;
+
+ /**
+ * get / process / offer data
+ */
+ virtual uint32_t copyCaptureDataToClient(RingBuf pcm_read_buf) = 0; // called by capture data provider
+
+
+ /**
+ * read data from audio hardware
+ */
+ virtual ssize_t read(void *buffer, ssize_t bytes) = 0; // called by capture handler
+
+ //EchoRef+++
+ /**
+ * get / process / offer data
+ */
+ virtual uint32_t copyEchoRefCaptureDataToClient(RingBuf pcm_read_buf) = 0;// called by capture data provider
+
+ virtual void AddEchoRefDataProvider(AudioALSACaptureDataProviderBase *pCaptureDataProvider, stream_attribute_t *stream_attribute_target);
+ //EchoRef---
+
+ /**
+ * Update BesRecord Parameters
+ */
+ virtual status_t UpdateBesRecParam() = 0;
+
+ /**
+ * check if the attached client has low latency requirement
+ */
+ virtual bool IsLowLatencyCapture(void) = 0;
+
+ /**
+ * Query captured frames & time stamp
+ */
+ virtual int getCapturePosition(int64_t *frames, int64_t *time) = 0;
+
+ virtual const stream_attribute_t *getStreamAttributeSource() = 0;
+
+ /**
+ * sync pcm start
+ */
+ virtual bool isNeedSyncPcmStart() { return false; }
+
+ /**
+ * StreamIn reopen
+ */
+ virtual bool getStreamInReopen() { return false; }
+ virtual void setStreamInReopen(bool state) { (void)state; }
+
+
+protected:
+ IAudioALSACaptureDataClient() {}
+
+
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_I_AUDIO_ALSA_CAPTURE_DATA_CLIENT_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/LoopbackManager.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/LoopbackManager.h
new file mode 100644
index 0000000..4e5719d
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/LoopbackManager.h
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_LOOPBACK_MANAGER_H
+#define ANDROID_LOOPBACK_MANAGER_H
+
+#include <utils/threads.h>
+
+#include "AudioType.h"
+#include <SpeechType.h>
+
+#include "AudioVolumeInterface.h"
+
+namespace android {
+
+// for loopback
+enum loopback_t {
+ NO_LOOPBACK = 0,
+
+ // AFE Loopback
+ AP_MAIN_MIC_AFE_LOOPBACK = 1,
+ AP_HEADSET_MIC_AFE_LOOPBACK = 2,
+ AP_REF_MIC_AFE_LOOPBACK = 3,
+ AP_3RD_MIC_AFE_LOOPBACK = 4,
+
+ // Acoustic Loopback
+ MD_MAIN_MIC_ACOUSTIC_LOOPBACK = 21,
+ MD_HEADSET_MIC_ACOUSTIC_LOOPBACK = 22,
+ MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITHOUT_DMNR = 23,
+ MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITH_DMNR = 24,
+ MD_REF_MIC_ACOUSTIC_LOOPBACK = 25,
+ MD_3RD_MIC_ACOUSTIC_LOOPBACK = 26,
+
+ // BT Loopback with codec
+ AP_BT_LOOPBACK = 30,
+ MD_BT_LOOPBACK = 31,
+
+ // BT Loopback without codec
+ AP_BT_LOOPBACK_NO_CODEC = 32,
+ MD_BT_LOOPBACK_NO_CODEC = 33,
+};
+
+enum loopback_output_device_t {
+ LOOPBACK_OUTPUT_RECEIVER = 1,
+ LOOPBACK_OUTPUT_EARPHONE = 2,
+ LOOPBACK_OUTPUT_SPEAKER = 3,
+};
+
+enum loopback_ipc_status_t {
+ LOOPBACK_STATE_READY = 0,
+ LOOPBACK_STATE_PROC_ON = 1,
+ LOOPBACK_STATE_PROC_OFF = 2,
+};
+
+//class AudioVolumeInterface;
+
+class LoopbackManager {
+public:
+ virtual ~LoopbackManager();
+
+ static LoopbackManager *GetInstance();
+
+ loopback_t GetLoopbackType();
+
+ status_t SetLoopbackOn(loopback_t loopback_type, loopback_output_device_t loopback_output_device);
+ status_t SetLoopbackOff();
+
+ inline bool CheckIsModemLoopback(const loopback_t loopback_type) {
+ if (loopback_type == MD_MAIN_MIC_ACOUSTIC_LOOPBACK ||
+ loopback_type == MD_HEADSET_MIC_ACOUSTIC_LOOPBACK ||
+ loopback_type == MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITHOUT_DMNR ||
+ loopback_type == MD_DUAL_MIC_ACOUSTIC_LOOPBACK_WITH_DMNR ||
+ loopback_type == MD_REF_MIC_ACOUSTIC_LOOPBACK ||
+ loopback_type == MD_3RD_MIC_ACOUSTIC_LOOPBACK ||
+ loopback_type == MD_BT_LOOPBACK ||
+ loopback_type == MD_BT_LOOPBACK_NO_CODEC) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ loopback_t mLoopbackType;
+
+protected:
+ LoopbackManager();
+
+ status_t CheckLoopbackTypeIsValid(loopback_t loopback_type);
+
+ audio_devices_t GetInputDeviceByLoopbackType(loopback_t loopback_type);
+ audio_devices_t GetOutputDeviceByLoopbackType(loopback_t loopback_type, loopback_output_device_t loopback_output_device);
+
+ AudioVolumeInterface *mAudioALSAVolumeController;
+
+ Mutex mLock;
+
+
+ audio_devices_t mInputDeviceCopy;
+ audio_devices_t mOutputDeviceCopy;
+
+ float mVoiceVolumeCopy;
+ float mMasterVolumeCopy;
+
+ sph_enh_mask_struct_t mMaskCopy;
+
+ modem_index_t mWorkingModemIndex;
+
+ bool mBtHeadsetNrecOnCopy;
+ bool mLpbkRestoreVoiceVolume;
+ bool mLpbkRestoreMasterVolume;
+
+private:
+ static LoopbackManager *mLoopbackManager; // singleton
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_LOOPBACK_MANAGER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechDataProcessingHandler.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechDataProcessingHandler.h
new file mode 100644
index 0000000..9fe7f19
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechDataProcessingHandler.h
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_DATA_PROCESSING_HANDLER_H
+#define ANDROID_SPEECH_DATA_PROCESSING_HANDLER_H
+
+#include <utils/threads.h>
+#include <pthread.h>
+#include <utils/List.h>
+
+#include "AudioType.h"
+#include <AudioLock.h>
+#include "AudioUtility.h"
+#include "MtkAudioComponent.h"
+#include "SpeechDriverFactory.h"
+
+namespace android {
+class SpeechDataProcessingHandler {
+public:
+ enum Caller {
+ VOICE_MIX_CALLER,
+ VOICE_UL_CALLER,
+ VOICE_DL_CALLER
+ };
+
+ ~SpeechDataProcessingHandler();
+
+ static SpeechDataProcessingHandler *getInstance();
+
+ static void destoryInstanceSafely();
+
+ /**
+ * provide modem record data to capture data provider
+ */
+ status_t provideModemRecordDataToProvider(RingBuf modem_record_buf);
+
+ /**
+ * Get the stream attr of speech data
+ */
+ void getStreamAttributeSource(Caller caller, stream_attribute_t *streamAttributeSource);
+
+ status_t recordOn(RecordType type);
+
+ status_t recordOff(RecordType type);
+
+private:
+ SpeechDataProcessingHandler();
+
+
+ /**
+ * singleton pattern
+ */
+ static SpeechDataProcessingHandler *mSpeechDataProcessingHandler;
+
+ /**
+ * Bli SRC
+ */
+ MtkAudioSrcBase *mBliSrcUL;
+
+ MtkAudioSrcBase *mBliSrcDL;
+
+ uint32_t mSrcSampleRateUL;
+
+ uint32_t mSrcSampleRateDL;
+
+ /**
+ * Threading resources
+ */
+ pthread_t mSpeechDataProcessingThread;
+
+ pthread_cond_t mSpeechDataNotifyEvent;
+
+ pthread_mutex_t mSpeechDataNotifyMutex;
+
+ bool mStopThreadFlag;
+
+ List<RingBuf *> mSpeechDataList;
+
+ static void *threadLoop(void *arg);
+
+ status_t processSpeechPacket(char *inputPacketBuf, uint32_t speechDataSize);
+
+ /**
+ * Maintain speech driver status
+ */
+ bool mSpeechRecordOn;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_SPEECH_DATA_PROCESSING_HANDLER_H
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechDriverOpenDSP.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechDriverOpenDSP.h
new file mode 100644
index 0000000..95b9612
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechDriverOpenDSP.h
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_DRIVER_OPEN_DSP_H
+#define ANDROID_SPEECH_DRIVER_OPEN_DSP_H
+
+#include "SpeechDriverInterface.h"
+
+#include <AudioLock.h>
+
+struct ipi_msg_t;
+
+struct aurisys_dsp_config_t;
+struct aurisys_lib_manager_t;
+struct arsi_task_config_t;
+
+namespace android {
+
+class AudioMessengerIPI;
+
+class SpeechDriverOpenDSP : public SpeechDriverInterface {
+public:
+ virtual ~SpeechDriverOpenDSP();
+
+
+ /**
+ * get instance's pointer
+ */
+ static SpeechDriverInterface *GetInstance(modem_index_t modem_index);
+
+
+ /**
+ * speech control
+ */
+ virtual status_t SetSpeechMode(const audio_devices_t input_device, const audio_devices_t output_devices);
+ virtual status_t SpeechOn();
+ virtual status_t SpeechOff();
+ virtual status_t VideoTelephonyOn();
+ virtual status_t VideoTelephonyOff();
+ virtual status_t SpeechRouterOn();
+ virtual status_t SpeechRouterOff();
+
+ virtual status_t setMDVolumeIndex(int stream, int device, int index);
+
+ /**
+ * record control
+ */
+ virtual status_t recordOn();
+ virtual status_t recordOff();
+ virtual status_t recordOn(SpcRecordTypeStruct typeRecord);
+ virtual status_t recordOff(SpcRecordTypeStruct typeRecord);
+ virtual status_t setPcmRecordType(SpcRecordTypeStruct typeRecord);
+
+ virtual status_t VoiceMemoRecordOn();
+ virtual status_t VoiceMemoRecordOff();
+
+ virtual uint16_t GetRecordSampleRate() const;
+ virtual uint16_t GetRecordChannelNumber() const;
+
+
+ /**
+ * background sound control
+ */
+ virtual status_t BGSoundOn();
+ virtual status_t BGSoundConfig(uint8_t ul_gain, uint8_t dl_gain);
+ virtual status_t BGSoundOff();
+
+
+ /**
+ * pcm 2 way
+ */
+ virtual status_t PCM2WayOn(const bool wideband_on);
+ virtual status_t PCM2WayOff();
+
+
+ /** voice mixer on/off */
+ virtual status_t pcmMixerOn();
+ virtual status_t pcmMixerOff();
+ virtual status_t pcmMixerConfig(const uint8_t direction, const uint8_t mixType);
+
+
+ /**
+ * tty ctm control
+ */
+ virtual status_t TtyCtmOn();
+ virtual status_t TtyCtmOff();
+ virtual status_t TtyCtmDebugOn(bool tty_debug_flag);
+ virtual int setTtyMode(const TtyModeType ttyMode);
+
+ /**
+ * rtt control
+ */
+ virtual int RttConfig(int rttMode);
+
+ /**
+ * acoustic loopback
+ */
+ virtual status_t SetAcousticLoopback(bool loopback_on);
+ virtual status_t SetAcousticLoopbackBtCodec(bool enable_codec);
+
+ virtual status_t SetAcousticLoopbackDelayFrames(int32_t delay_frames);
+ virtual status_t setLpbkFlag(bool enableLpbk);
+
+ /**
+ * Modem Audio DVT and Debug
+ */
+ virtual status_t SetModemLoopbackPoint(uint16_t loopback_point);
+
+ /**
+ * encryption
+ */
+ virtual status_t SetEncryption(bool encryption_on);
+
+ /**
+ * volume control
+ */
+ virtual status_t SetDownlinkGain(int16_t gain);
+ virtual status_t SetEnh1DownlinkGain(int16_t gain);
+ virtual status_t SetUplinkGain(int16_t gain);
+ virtual status_t SetDownlinkMute(bool mute_on);
+ virtual status_t SetUplinkMute(bool mute_on);
+ virtual status_t SetUplinkSourceMute(bool mute_on);
+ virtual status_t SetSidetoneGain(int16_t gain);
+ virtual status_t SetDownlinkMuteCodec(bool mute_on);
+
+
+ /**
+ * device related config
+ */
+ virtual status_t SetModemSideSamplingRate(uint16_t sample_rate);
+
+
+ /**
+ * speech enhancement control
+ */
+ virtual status_t SetSpeechEnhancement(bool enhance_on);
+ virtual status_t SetSpeechEnhancementMask(const sph_enh_mask_struct_t &mask);
+
+ virtual status_t SetBtHeadsetNrecOn(const bool bt_headset_nrec_on);
+
+
+ /**
+ * speech enhancement parameters setting
+ */
+ virtual status_t GetVibSpkParam(void *eVibSpkParam);
+ virtual status_t SetVibSpkParam(void *eVibSpkParam);
+
+ virtual status_t SetDynamicSpeechParameters(const int type, const void *param_arg);
+
+ /**
+ * check whether modem is ready.
+ */
+ virtual bool CheckModemIsReady();
+
+
+
+protected:
+ SpeechDriverOpenDSP() {}
+ SpeechDriverOpenDSP(modem_index_t modem_index);
+
+ /**
+ * scp phone call on/off
+ */
+ virtual status_t ScpSpeechOn();
+ virtual status_t ScpSpeechOff();
+
+ /**
+ * recover status (speech/record/bgs/vt/p2w/tty)
+ */
+ virtual bool GetScpSideSpeechStatus(const modem_status_mask_t modem_status_mask);
+ virtual void SetScpSideSpeechStatus(const modem_status_mask_t modem_status_mask);
+ virtual void ResetScpSideSpeechStatus(const modem_status_mask_t modem_status_mask);
+ virtual void RecoverModemSideStatusToInitState();
+
+
+ AudioMessengerIPI *mAudioMessengerIPI;
+ SpeechDriverInterface *pSpeechDriverInternal; // adaptor
+
+
+
+ uint32_t mScpSideSpeechStatus; // value |= modem_status_mask_t
+ AudioLock mScpSideSpeechStatusLock;
+
+ uint32_t mModemPcmSampleRate; // AFE pcm config
+ uint32_t mModemDspMaxSampleRate; // FD216 working sample rate
+
+
+
+ /**
+ * lib related
+ */
+ void createDumpFiles();
+ static void processDmaMsg(struct ipi_msg_t *msg, void *buf, uint32_t size, void *arg);
+ bool mEnableDump;
+
+
+ /**
+ * aurisys
+ */
+ struct aurisys_dsp_config_t *mAurisysDspConfig;
+ audio_devices_t mInputDevice;
+ audio_devices_t mOutputDevices;
+
+ struct aurisys_lib_manager_t *mAurisysLibManager;
+
+ void SetArsiTaskConfig(struct arsi_task_config_t *pTaskConfig);
+ void SetArsiAttribute();
+ void CreateAurisysLibManager();
+ void UpdateAurisysConfig();
+ void DestroyAurisysLibManager() ;
+
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ static SpeechDriverOpenDSP *mSpeechDriverOpenDSP;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_SPEECH_DRIVER_OPEN_DSP_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechMessengerCCCI.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechMessengerCCCI.h
new file mode 100644
index 0000000..e0a7dff
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechMessengerCCCI.h
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_MESSENGER_CCCI_H
+#define ANDROID_SPEECH_MESSENGER_CCCI_H
+
+#include <pthread.h>
+
+#include "AudioType.h"
+#include "SpeechType.h"
+#include "AudioUtility.h"
+#include "SpeechMessengerInterface.h"
+
+#include "SpeechBGSPlayer.h"
+#include "SpeechPcm2way.h"
+#define SPEECH_PCM_VM_SUPPORT
+
+namespace android {
+
+class SpeechDriverLAD;
+
+class SpeechMessengerCCCI : public SpeechMessengerInterface {
+public:
+ SpeechMessengerCCCI(modem_index_t modem_index, SpeechDriverLAD *pLad);
+ virtual ~SpeechMessengerCCCI();
+
+ virtual status_t Initial();
+ virtual status_t Deinitial();
+ virtual bool A2MBufLock();
+ virtual void A2MBufUnLock();
+
+ virtual status_t WaitUntilModemReady();
+
+ virtual ccci_buff_t InitCcciMailbox(uint16_t id, uint16_t param_16bit, uint32_t param_32bit);
+ virtual status_t SendMessageInQueue(ccci_buff_t ccci_buff);
+
+ virtual uint16_t GetM2AShareBufSyncWord(const ccci_buff_t &ccci_buff);
+ virtual uint16_t GetM2AShareBufDataType(const ccci_buff_t &ccci_buff);
+ virtual uint16_t GetM2AShareBufDataLength(const ccci_buff_t &ccci_buff);
+
+ /**
+ * get modem side modem function status
+ */
+ virtual bool GetModemSideModemStatus(const modem_status_mask_t modem_status_mask) const;
+
+
+ /**
+ * check whether modem side get all necessary speech enhancement parameters here
+ */
+ virtual bool CheckSpeechParamAckAllArrival();
+
+
+ /**
+ * check whether modem is ready. (if w/o SIM && phone_2 => modem sleep)
+ */
+ virtual bool CheckModemIsReady();
+
+ /**
+ * check whether modem audio is ready from reset.
+ */
+ virtual bool GetMDResetFlag();
+
+ /**
+ * set raw record type.
+ */
+ virtual status_t setPcmRecordType(RecordType typeRecord);
+
+#ifdef USE_CCCI_SHARE_BUFFER
+ virtual void InitA2MRawParaRingBuffer();
+ virtual status_t GetA2MRawParaRingBuffer(uint16_t *offset, uint16_t *avail);
+ virtual status_t AdvanceA2MRawParaRingBuffer(int datalength);
+ virtual status_t WriteA2MRawParaRingBuffer(char *data, int datalength);
+#endif
+
+protected:
+ virtual char GetModemCurrentStatus();
+
+ virtual uint16_t GetMessageID(const ccci_buff_t &ccci_buff);
+ virtual uint16_t GetMessageParam(const ccci_buff_t &ccci_buff);
+
+ virtual uint16_t GetMessageLength(const ccci_buff_t &ccci_buff);
+ virtual uint16_t GetMessageOffset(const ccci_buff_t &ccci_buff);
+ virtual bool CheckOffsetAndLength(const ccci_buff_t &ccci_buff);
+ virtual uint16_t GetPcmFreq(const uint16_t Idx_Freq);
+
+ virtual ccci_message_ack_t JudgeAckOfMsg(const uint16_t message_id);
+
+ virtual bool IsModemFunctionOnOffMessage(const uint16_t message_id);
+
+ virtual status_t SendMessage(const ccci_buff_t &ccci_buff);
+ virtual status_t ReadMessage(ccci_buff_t &ccci_buff);
+ virtual void SendMsgFailErrorHandling(const ccci_buff_t &ccci_buff);
+
+ virtual RingBuf GetM2AUplinkRingBuffer(const ccci_buff_t &ccci_buff);
+ virtual RingBuf GetM2ACtmRingBuffer(const ccci_buff_t &ccci_buff);
+ virtual RingBuf GetM2ARawPcmRingBuffer(const ccci_buff_t &ccci_buff);
+
+ virtual status_t CreateReadingThread();
+ virtual status_t CreateSendSphParaThread();
+
+ static void *CCCIReadThread(void *arg);
+ static void *SendSphParaThread(void *arg);
+
+ // for message queue
+ virtual uint32_t GetQueueCount() const;
+ virtual status_t ConsumeMessageInQueue();
+ virtual bool MDReset_CheckMessageInQueue();
+ virtual void ResetSpeechParamAckCount();
+ virtual void AddSpeechParamAckCount(speech_param_ack_t type);
+
+
+ /**
+ * set/reset AP side modem function status
+ */
+ virtual void SetModemSideModemStatus(const modem_status_mask_t modem_status_mask);
+ virtual void ResetModemSideModemStatus(const modem_status_mask_t modem_status_mask);
+
+ // lock
+ virtual bool SpeechParamLock();
+ virtual void SpeechParamUnLock();
+
+ virtual void GetRFInfo(void);
+ virtual void SetRFInfo(char mRFIdx, uint16_t mRfData);
+ virtual void ResetRFInfo(void);
+
+ modem_index_t mModemIndex;
+ SpeechDriverLAD *mLad;
+ bool CCCIEnable;
+
+ // file handle for CCCI user space interface
+ int32_t fHdlRead;
+ int32_t fHdlWrite;
+
+ ccci_queue_element_t pQueue[CCCI_MAX_QUEUE_NUM];
+ int32_t iQRead;
+ int32_t iQWrite;
+
+ uint32_t mSpeechParamAckCount[NUM_SPEECH_PARAM_ACK_TYPE];
+
+
+ uint32_t mModemSideModemStatus; // value |= modem_status_mask_t
+
+ uint16_t mWaitAckMessageID;
+
+ AudioLock mCCCIMessageQueueMutex;
+ AudioLock mA2MShareBufMutex;
+ AudioLock mSetSpeechParamMutex;
+
+ pthread_t hReadThread;
+ pthread_t hSendSphThread;
+
+ bool mIsModemResetDuringPhoneCall;
+ bool mIsModemReset;
+ bool mIsModemEPOF; // 1=MD power off
+ RecordType mPcmRecordType;
+ uint32_t LastSentMessage;
+ uint32_t LastNeedAckSentMessage;
+ char *mSphCCCITmpBuf;
+ char *mSphPCMBuf;
+ RingBuf pcm_ring_buf;
+ char *mSphPCMBufEnd;
+ /*
+ * flag of dynamic enable verbose/debug log
+ */
+ int mLogEnable;
+
+ SpeechMessengerCCCI() {}
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_SPEECH_MESSAGE_CCCI_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechMessengerECCCI.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechMessengerECCCI.h
new file mode 100644
index 0000000..8a73727
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechMessengerECCCI.h
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_MESSENGER_ECCCI_H
+#define ANDROID_SPEECH_MESSENGER_ECCCI_H
+
+#include <pthread.h>
+
+#include "AudioType.h"
+#include "SpeechType.h"
+#include "AudioUtility.h"
+
+#include "SpeechBGSPlayer.h"
+#include "SpeechPcm2way.h"
+#include "SpeechMessengerInterface.h"
+
+
+namespace android {
+
+class SpeechDriverLAD;
+
+class SpeechMessengerECCCI : public SpeechMessengerInterface {
+public:
+ SpeechMessengerECCCI(modem_index_t modem_index, SpeechDriverLAD *pLad);
+ virtual ~SpeechMessengerECCCI();
+
+ virtual status_t Initial();
+ virtual status_t Deinitial();
+
+ virtual bool A2MBufLock();
+ virtual void A2MBufUnLock();
+
+ virtual status_t WaitUntilModemReady();
+
+ virtual ccci_buff_t InitCcciMailbox(uint16_t id, uint16_t param_16bit, uint32_t param_32bit);
+ virtual status_t SendMessageInQueue(ccci_buff_t ccci_buff);
+
+
+ virtual uint16_t GetM2AShareBufSyncWord(const ccci_buff_t &ccci_buff);
+ virtual uint16_t GetM2AShareBufDataType(const ccci_buff_t &ccci_buff);
+ virtual uint16_t GetM2AShareBufDataLength(const ccci_buff_t &ccci_buff);
+ uint16_t GetM2AUplinkData(const ccci_buff_t &ccci_buff, char *TargetBuf);
+
+ /**
+ * get modem side modem function status
+ */
+ virtual bool GetModemSideModemStatus(const modem_status_mask_t modem_status_mask) const;
+
+
+ /**
+ * check whether modem side get all necessary speech enhancement parameters here
+ */
+ virtual bool CheckSpeechParamAckAllArrival();
+
+
+ /**
+ * check whether modem is ready. (if w/o SIM && phone_2 => modem sleep)
+ */
+ virtual bool CheckModemIsReady();
+
+ /**
+ * check whether modem audio is ready from reset.
+ */
+ virtual bool GetMDResetFlag();
+
+ /**
+ * set raw record type.
+ */
+ virtual status_t setPcmRecordType(SpcRecordTypeStruct typeRecord);
+
+#ifdef USE_CCCI_SHARE_BUFFER
+ virtual void InitA2MRawParaRingBuffer();
+ virtual status_t GetA2MRawParaRingBuffer(uint16_t *offset, uint16_t *avail);
+ virtual status_t AdvanceA2MRawParaRingBuffer(int datalength);
+ virtual status_t WriteA2MRawParaRingBuffer(char *data, int datalength);
+#endif
+
+protected:
+ SpeechMessengerECCCI() {}
+
+ virtual char GetModemCurrentStatus();
+
+ virtual uint16_t GetMessageID(const ccci_buff_t &ccci_buff);
+ virtual uint16_t GetMessageParam(const ccci_buff_t &ccci_buff);
+
+ virtual uint16_t GetMessageLength(const ccci_buff_t &ccci_buff);
+ virtual uint16_t GetMessageOffset(const ccci_buff_t &ccci_buff);
+ virtual bool CheckOffsetAndLength(const ccci_buff_t &ccci_buff);
+ virtual uint16_t GetPcmFreq(const uint16_t Idx_Freq);
+
+ virtual ccci_message_ack_t JudgeAckOfMsg(const uint16_t message_id);
+
+ virtual bool IsModemFunctionOnOffMessage(const uint16_t message_id);
+
+ virtual status_t SendMessage(const ccci_buff_t &ccci_buff);
+ virtual status_t ReadMessage(ccci_buff_t &ccci_buff);
+ virtual void SendMsgFailErrorHandling(const ccci_buff_t &ccci_buff);
+
+ virtual RingBuf GetM2AUplinkRingBuffer(const ccci_buff_t &ccci_buff);
+ virtual RingBuf GetM2ARawPcmRingBuffer(const ccci_buff_t &ccci_buff);
+
+ virtual status_t CreateReadingThread();
+ virtual status_t CreateSendSphParaThread();
+
+ static void *CCCIReadThread(void *arg);
+ static void *SendSphParaThread(void *arg);
+
+
+ // for message queue
+ virtual uint32_t GetQueueCount() const;
+ virtual status_t ConsumeMessageInQueue();
+ virtual bool MDReset_CheckMessageInQueue();
+ virtual void ResetSpeechParamAckCount();
+ virtual void AddSpeechParamAckCount(speech_param_ack_t type);
+
+
+ /**
+ * set/reset AP side modem function status
+ */
+ virtual void SetModemSideModemStatus(const modem_status_mask_t modem_status_mask);
+ virtual void ResetModemSideModemStatus(const modem_status_mask_t modem_status_mask);
+
+ // lock
+ virtual bool SpeechParamLock();
+ virtual void SpeechParamUnLock();
+
+ virtual void GetRFInfo(void);
+ virtual void SetRFInfo(char mRFIdx, uint16_t mRfData);
+ virtual void ResetRFInfo(void);
+ status_t SetNWCodecInfo(const ccci_buff_t &ccci_buff);
+ uint32_t GetMessageReserved(const ccci_buff_t &ccci_buff);
+ bool JudgeLogPrintOfMsg(const uint16_t message_id);
+ modem_index_t mModemIndex;
+ SpeechDriverLAD *mLad;
+ bool CCCIEnable;
+
+ // file handle for ECCCI user space interface
+ int32_t fHdl;
+#ifdef USE_CCCI_SHARE_BUFFER
+ int32_t CCCIBuf_Hdl;
+#endif
+
+ // share buffer base and len
+ uint32_t mA2MShareBufLen;
+ uint32_t mM2AShareBufLen;
+
+ char *mECCCIShareBuf;
+ char *mM2AShareBufRead;
+
+#ifdef USE_CCCI_SHARE_BUFFER
+ char *mA2MParaShareBufBase;
+ char *mA2MParaShareBufEnd;
+ uint32_t mA2MParaShareBufLen;
+ bool mIsA2MParaShareBufEmpty;
+ RingBuf mA2MParaShareBuf;
+#endif
+
+ char *mSphPCMBuf;
+ char *mSphPCMBufEnd;
+ RingBuf pcm_ring_buf;
+
+ ccci_queue_element_t pQueue[CCCI_MAX_QUEUE_NUM];
+ int32_t iQRead;
+ int32_t iQWrite;
+
+ uint32_t mSpeechParamAckCount[NUM_SPEECH_PARAM_ACK_TYPE];
+
+
+ uint32_t mModemSideModemStatus; // value |= modem_status_mask_t
+
+ uint16_t mWaitAckMessageID;
+
+
+ AudioLock mCCCIMessageQueueMutex;
+ AudioLock mA2MShareBufMutex;
+ AudioLock mSetSpeechParamMutex;
+
+ pthread_t hReadThread;
+ pthread_t hSendSphThread;
+
+ bool mIsModemResetDuringPhoneCall;
+ bool mIsModemReset;
+ bool mIsModemEPOF; // 1=MD power off
+ RecordType mPcmRecordType;
+ uint32_t LastSentMessage;
+ uint32_t LastNeedAckSentMessage;
+ /*
+ * flag of dynamic enable verbose/debug log
+ */
+ int mLogEnable;
+
+};
+
+} // end namespace android
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechMessengerEVDO.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechMessengerEVDO.h
new file mode 100644
index 0000000..9da414f
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechMessengerEVDO.h
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_MESSENGER_EVDO_H
+#define ANDROID_SPEECH_MESSENGER_EVDO_H
+
+#include <pthread.h>
+
+#include "AudioType.h"
+#include "SpeechType.h"
+#include "AudioUtility.h"
+
+#include "SpeechBGSPlayer.h"
+#include "SpeechPcm2way.h"
+#include "SpeechMessengerInterface.h"
+
+
+namespace android {
+#define EVDO_MAX_PAYLOAD_SIZE 4000 //A2M/M2A share memory=16k
+/** EVDO buffer structure */
+typedef struct {
+ uint32_t magic;
+ uint32_t message; // message[31:16] = id, message[15:0] = parameters
+ uint32_t channel;
+ uint32_t reserved;
+ uint32_t payload[EVDO_MAX_PAYLOAD_SIZE];
+} evdo_buff_t;
+
+class SpeechDriverLAD;
+
+class SpeechMessengerEVDO : public SpeechMessengerInterface {
+public:
+ SpeechMessengerEVDO(modem_index_t modem_index, SpeechDriverLAD *pLad);
+ virtual ~SpeechMessengerEVDO();
+
+ virtual status_t Initial();
+ virtual status_t Deinitial();
+
+ virtual bool A2MBufLock();
+ virtual void A2MBufUnLock();
+
+ virtual status_t WaitUntilModemReady();
+
+ virtual ccci_buff_t InitCcciMailbox(uint16_t id, uint16_t param_16bit, uint32_t param_32bit);
+ virtual status_t SendMessageInQueue(ccci_buff_t ccci_buff);
+
+
+ virtual uint16_t GetM2AShareBufSyncWord(const ccci_buff_t &ccci_buff);
+ virtual uint16_t GetM2AShareBufDataType(const ccci_buff_t &ccci_buff);
+ virtual uint16_t GetM2AShareBufDataLength(const ccci_buff_t &ccci_buff);
+ uint16_t GetM2AUplinkData(const ccci_buff_t &ccci_buff, char *TargetBuf);
+
+ /**
+ * get modem side modem function status
+ */
+ virtual bool GetModemSideModemStatus(const modem_status_mask_t modem_status_mask) const;
+
+
+ /**
+ * check whether modem side get all necessary speech enhancement parameters here
+ */
+ virtual bool CheckSpeechParamAckAllArrival();
+
+
+ /**
+ * check whether modem is ready. (if w/o SIM && phone_2 => modem sleep)
+ */
+ virtual bool CheckModemIsReady();
+
+ /**
+ * check whether modem audio is ready from reset.
+ */
+ virtual bool GetMDResetFlag();
+
+ /**
+ * set raw record type.
+ */
+ virtual status_t SetPcmRecordType(record_type_t type_record);
+
+#ifdef USE_CCCI_SHARE_BUFFER
+ virtual void InitA2MRawParaRingBuffer();
+ virtual status_t GetA2MRawParaRingBuffer(uint16_t *offset, uint16_t *avail);
+ virtual status_t AdvanceA2MRawParaRingBuffer(int datalength);
+ virtual status_t WriteA2MRawParaRingBuffer(char *data, int datalength);
+#endif
+
+protected:
+ SpeechMessengerEVDO() {}
+
+ virtual char GetModemCurrentStatus();
+
+ virtual uint16_t GetMessageID(const ccci_buff_t &ccci_buff);
+ virtual uint16_t GetMessageParam(const ccci_buff_t &ccci_buff);
+
+ virtual uint16_t GetMessageLength(const ccci_buff_t &ccci_buff);
+ virtual uint16_t GetMessageOffset(const ccci_buff_t &ccci_buff);
+ virtual bool CheckOffsetAndLength(const ccci_buff_t &ccci_buff);
+
+ virtual ccci_message_ack_t JudgeAckOfMsg(const uint16_t message_id);
+
+ virtual bool IsModemFunctionOnOffMessage(const uint16_t message_id);
+
+ virtual status_t SendMessage(const ccci_buff_t &ccci_buff);
+ virtual status_t ReadMessage(ccci_buff_t &ccci_buff);
+ virtual void SendMsgFailErrorHandling(const ccci_buff_t &ccci_buff);
+
+ virtual uint16_t GetPcmFreq(const uint16_t Idx_Freq);
+ virtual RingBuf GetM2AUplinkRingBuffer(const ccci_buff_t &ccci_buff);
+ virtual RingBuf GetM2ARawPcmRingBuffer(const ccci_buff_t &ccci_buff);
+
+ virtual status_t CreateReadingThread();
+ virtual status_t CreateSendSphParaThread();
+
+ static void *EVDOReadThread(void *arg);
+ static void *SendSphParaThread(void *arg);
+ static void *OpenMuxdDeviceThread(void *arg);
+
+
+ // for message queue
+ virtual uint32_t GetQueueCount() const;
+ virtual status_t ConsumeMessageInQueue();
+ virtual bool MDReset_CheckMessageInQueue();
+
+ virtual void ResetSpeechParamAckCount();
+ virtual void AddSpeechParamAckCount(speech_param_ack_t type);
+
+
+ /**
+ * set/reset AP side modem function status
+ */
+ virtual void SetModemSideModemStatus(const modem_status_mask_t modem_status_mask);
+ virtual void ResetModemSideModemStatus(const modem_status_mask_t modem_status_mask);
+
+ // lock
+ virtual bool SpeechParamLock();
+ virtual void SpeechParamUnLock();
+
+
+ /**
+ * set/reset AP side modem function status
+ */
+ virtual void OpenMuxdDeviceUntilReady();
+
+ status_t SetNWCodecInfo(const ccci_buff_t &ccci_buff);
+ bool JudgeLogPrintOfMsg(const uint16_t message_id);
+
+ modem_index_t mModemIndex;
+ SpeechDriverLAD *mLad;
+ bool CCCIEnable;
+
+ // file handle for ECCCI user space interface
+ int32_t fHdl;
+ AudioLock mfHdlLock;
+
+ // share buffer base and len
+ uint32_t mA2MShareBufLen;
+ uint32_t mM2AShareBufLen;
+
+ char *mECCCIShareBuf;
+ char *mM2AShareBufRead;
+ char *mSphPCMBuf;
+ char *mSphPCMBufEnd;
+ RingBuf pcm_ring_buf;
+
+ ccci_queue_element_t pQueue[CCCI_MAX_QUEUE_NUM];
+ int32_t iQRead;
+ int32_t iQWrite;
+
+ uint32_t mSpeechParamAckCount[NUM_SPEECH_PARAM_ACK_TYPE];
+
+
+ uint32_t mModemSideModemStatus; // value |= modem_status_mask_t
+
+ uint16_t mWaitAckMessageID;
+
+
+ AudioLock mCCCIMessageQueueMutex;
+ AudioLock mA2MShareBufMutex;
+ AudioLock mSetSpeechParamMutex;
+
+ pthread_t hReadThread;
+ pthread_t hSendSphThread;
+ pthread_t hOpenMuxdDeviceThread;
+
+ char mModemStatus;
+ AudioLock mGetModemCurrentStatusLock;
+
+ bool mIsModemResetDuringPhoneCall;
+ bool mIsModemReset;
+ bool mIsModemEPOF; // 1=MD power off
+ record_type_t mPcmRecordType;
+ bool mCreatingSphThreadFlag;
+ bool mWaitSphThreadFlag;
+ uint32_t LastSentMessage;
+ uint32_t LastNeedAckSentMessage;
+
+#ifdef USE_CCCI_SHARE_BUFFER
+ int32_t CCCIBuf_Hdl;
+ char *mA2MParaShareBufBase;
+ char *mA2MParaShareBufEnd;
+ uint32_t mA2MParaShareBufLen;
+ bool mIsA2MParaShareBufEmpty;
+ RingBuf mA2MParaShareBuf;
+#endif
+ /*
+ * flag of dynamic enable verbose/debug log
+ */
+ int mLogEnable;
+
+};
+
+} // end namespace android
+
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechParamParser.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechParamParser.h
new file mode 100644
index 0000000..26024f4
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechParamParser.h
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef _SPEECH_PARAM_PARSER_H_
+#define _SPEECH_PARAM_PARSER_H_
+
+/*
+ * =============================================================================
+ * external references
+ * =============================================================================
+ */
+#include "AudioType.h"
+#include "SpeechType.h"
+#include <vector>
+#include "AudioParamParser.h"
+
+namespace android {
+
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+
+struct SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT;
+struct AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT;
+struct SPEECH_PARAM_INFO_STRUCT;
+struct SPEECH_PARAM_SUPPORT_STRUCT;
+struct SPEECH_NETWORK_STRUCT;
+
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+enum speech_type_dynamic_param_t {
+ AUDIO_TYPE_SPEECH = 0,
+ AUDIO_TYPE_SPEECH_DMNR = 1,
+ AUDIO_TYPE_SPEECH_GENERAL = 2,
+ AUDIO_TYPE_SPEECH_MAGICLARITY = 3,
+ AUDIO_TYPE_SPEECH_NETWORK = 4,
+ AUDIO_TYPE_SPEECH_ECHOREF = 5,
+
+
+ NUM_AUDIO_TYPE_SPEECH_TYPE /* the #types of speech_type_dynamic_param_t */
+};
+
+/* XML name */
+const char audioTypeNameList[8][128] = {
+ "Speech",
+ "SpeechDMNR",
+ "SpeechGeneral",
+ "SpeechMagiClarity",
+ "SpeechNetwork",
+ "SpeechEchoRef"
+};
+
+enum tty_param_t {
+ TTY_PARAM_OFF = 0,
+ TTY_PARAM_HCO = 1,
+ TTY_PARAM_VCO = 2
+};
+
+/*
+ * =============================================================================
+ * class
+ * =============================================================================
+ */
+
+class SpeechParamParser {
+public:
+ virtual ~SpeechParamParser();
+ static SpeechParamParser *getInstance();
+ bool GetSpeechParamSupport(const char *paramName);
+ int GetSpeechParamUnit(char *bufParamUnit, int *paramArg);
+ int GetGeneralParamUnit(char *bufParamUnit);
+ int GetDmnrParamUnit(char *bufParamUnit);
+ int GetMagiClarityParamUnit(char *bufParamUnit);
+ int GetEchoRefParamUnit(char *bufParamUnit);
+ status_t SetParamInfo(const String8 &keyParamPairs);
+ int GetBtDelayTime(const char *btDeviceName);
+ bool GetParamStatus(const char *paramName);
+
+protected:
+
+
+private:
+ SpeechParamParser();
+ static SpeechParamParser *UniqueSpeechParamParser;
+ AppHandle *mAppHandle;
+ int getSpeechProfile(const speech_mode_t sphMode, bool btHeadsetNrecOn);
+
+ void init();
+ void initAppParser();
+ status_t getSpeechParamFromAppParser(uint16_t idxSphType,
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT *paramLayerInfo,
+ char *bufParamUnit,
+ uint16_t *sizeByteTotal);
+ uint16_t sizeByteParaData(uint16_t dataType, uint16_t arraySize);
+ status_t speechDataDump(char *bufDump,
+ uint16_t idxSphType,
+ const char *nameParam,
+ const char *speechParamData);
+ status_t setMDParamUnitHdr(speech_type_dynamic_param_t idxAudioType,
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT *paramUnitHdr,
+ uint16_t configValue);
+ uint16_t setMDParamDataHdr(SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT paramUnitHdr,
+ const char *cateBandName,
+ const char *cateNetworkName);
+ int initSpeechNetwork(void);
+
+ SPEECH_PARAM_INFO_STRUCT *mSphParamInfo;
+ SPEECH_NETWORK_STRUCT *mListSpeechNetwork;
+ SPEECH_NETWORK_STRUCT *mNameForEachSpeechNetwork;
+ SPEECH_PARAM_SUPPORT_STRUCT *mSphParamSupport;
+ uint8_t mNumSpeechNetwork, mSpeechParamVerFirst, mSpeechParamVerLast, mNumSpeechParam;
+
+}; //SpeechParamParser
+
+} //namespace android
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechVMRecorder.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechVMRecorder.h
new file mode 100644
index 0000000..2ccf109
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechVMRecorder.h
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_VM_RECORDER_H
+#define ANDROID_SPEECH_VM_RECORDER_H
+
+#if !defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+#include <hardware_legacy/AudioMTKHardwareInterface.h>
+#endif
+
+#include "AudioType.h"
+#include "AudioUtility.h"
+
+#include <AudioLock.h>
+
+namespace android {
+
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+enum SpeechVmType {
+ SPEECH_VM_DISABLE = 0,
+ SPEECH_VM_SPEECH = 1,
+ SPEECH_VM_CTM4WAY = 2,
+ NUM_SPEECH_VM_TYPE
+};
+
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+class AudioCustParamClient;
+
+class SpeechVMRecorder {
+public:
+ virtual ~SpeechVMRecorder();
+ static SpeechVMRecorder *getInstance();
+
+ /**
+ * VM Config
+ */
+#if !defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ int configVm(const AUDIO_CUSTOM_PARAM_STRUCT *sphParamNB);
+#endif
+ int configVm(const uint8_t vmConfig);
+ int configVmEpl(const bool isEpl);
+ SpeechVmType getVmConfig();
+
+ /**
+ * VM for vocie call
+ */
+ status_t open();
+ status_t close();
+ bool getVMRecordStatus() const { return mIsVmEnable; }
+ uint16_t getVmDataFromModem(RingBuf ul_ring_buf);
+
+ /**
+ * CTM Debug for TTY
+ */
+ int startCtmDebug();
+ int stopCtmDebug();
+ void getCtmDebugDataFromModem(RingBuf ul_ring_buf, FILE *pFile);
+ FILE *pCtmDumpFileUlIn;
+ FILE *pCtmDumpFileDlIn;
+ FILE *pCtmDumpFileUlOut;
+ FILE *pCtmDumpFileDlOut;
+
+protected:
+ SpeechVMRecorder();
+
+ FILE *openFile();
+ static void *dumpVMRecordDataThread(void *arg);
+ void triggerSpeechVm();
+
+ bool mIsDumpThreadStart;
+ AudioLock mThreadStartMutex;
+
+ bool mIsVmEnable;
+
+ RingBuf mRingBuf; // Internal Input Buffer for Get VM data
+
+ pthread_t mRecordThread;
+ AudioLock mMutex;
+
+ SpeechVmType mVMConfig;
+ uint32_t mOpenIndex;
+
+
+private:
+ static SpeechVMRecorder *mSpeechVMRecorder; // singleton
+ bool mIsCtmDebugStart;
+}; // end of class SpeechVMRecorder
+
+}; // end of namespace android
+
+#endif // end of ANDROID_SPEECH_VM_RECORDER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechVoiceCustomLogger.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechVoiceCustomLogger.h
new file mode 100644
index 0000000..dfc0cc4
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/SpeechVoiceCustomLogger.h
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_VOICE_CUSTOM_LOGGER_H
+#define ANDROID_SPEECH_VOICE_CUSTOM_LOGGER_H
+#include "AudioUtility.h"
+#include <AudioLock.h>
+
+namespace android {
+
+class SpeechVoiceCustomLogger {
+public:
+ virtual ~SpeechVoiceCustomLogger();
+
+ static SpeechVoiceCustomLogger *GetInstance();
+
+ status_t Open();
+ status_t Close();
+
+ uint16_t CopyBufferToVCL(RingBuf ul_ring_buf);
+ bool UpdateVCLSwitch() ;
+
+ bool GetVCLRecordStatus() const { return mEnable; } // true for open, false for close
+
+
+protected:
+ SpeechVoiceCustomLogger();
+
+ status_t OpenFile();
+ static void *DumpVCLRecordDataThread(void *arg);
+
+ bool mStarting;
+ bool mEnable;
+ bool mVCLEnable;
+
+ RingBuf mRingBuf; // Internal Input Buffer for Get VM data
+ FILE *mDumpFile;
+
+ pthread_t mRecordThread;
+ AudioLock mMutex;
+
+private:
+ static SpeechVoiceCustomLogger *mSpeechVoiceCustomLogger; // singleton
+}; // end of class SpeechVMRecorder
+
+}; // end of namespace android
+
+#endif // end of ANDROID_SPEECH_VM_RECORDER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/audio_a2dp_msg_id.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/audio_a2dp_msg_id.h
new file mode 100644
index 0000000..deaa979
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/audio_a2dp_msg_id.h
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+* Copyright (C) 2016 MediaTek Inc.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+*/
+
+#ifndef AUDIO_A2DP_MSG_ID_H
+#define AUDIO_A2DP_MSG_ID_H
+
+enum ipi_msg_id_a2dp_t {
+
+ AUDIO_DSP_TASK_A2DP_DATAREAD = 0x800,
+ AUDIO_DSP_TASK_DATAPROVIDER_READ,
+ AUDIO_DSP_TASK_A2DP_CODECINFO,
+ AUDIO_DSP_TASK_DATAPROVIDER_SUSPEND,
+ AUDIO_DSP_TASK_A2DP_SUSPEND
+};
+
+#endif // end of AUDIO_A2DP_MSG_ID_H
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/audio_controller_msg_id.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/audio_controller_msg_id.h
new file mode 100644
index 0000000..1a51ad2
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/audio_controller_msg_id.h
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_CONTROLLER_MSG_ID_H
+#define AUDIO_CONTROLLER_MSG_ID_H
+
+#define AUD_CTL_MSG_A2D_BASE (0xAD00)
+#define AUD_CTL_MSG_D2A_BASE (0xDA00)
+#define AUD_CTL_MSG_D2D_BASE (0xDD00)
+
+
+/* NOTE: all ack behaviors are rely on audio_ipi_msg_ack_t */
+enum AUD_CTL_MSG_id_call_t {
+ /* Aurisys control msg, 0xADA- */
+ AUD_CTL_MSG_A2D_AURISYS_CFG = AUD_CTL_MSG_A2D_BASE + 0xA0,
+ AUD_CTL_MSG_A2D_AURISYS_SET_PARAM = AUD_CTL_MSG_A2D_BASE + 0xA1,
+ AUD_CTL_MSG_A2D_AURISYS_GET_PARAM = AUD_CTL_MSG_A2D_BASE + 0xA2,
+ AUD_CTL_MSG_A2D_AURISYS_ENABLE = AUD_CTL_MSG_A2D_BASE + 0xA3,
+
+
+ /* Boot & recovery */
+ AUD_CTL_MSG_A2D_HAL_REBOOT = AUD_CTL_MSG_A2D_BASE + 0xB0,
+
+ /* DMA control msg, 0xADD- */
+ AUD_CTL_MSG_A2D_DMA_INIT = AUD_CTL_MSG_A2D_BASE + 0xD0,
+ AUD_CTL_MSG_A2D_DMA_UPDATE_REGION = AUD_CTL_MSG_A2D_BASE + 0xD1,
+
+
+ /* Aurisys dump msg, 0xDAA- */
+ AUD_CTL_MSG_D2A_AURISYS_DUMP = AUD_CTL_MSG_D2A_BASE + 0xA0,
+
+
+ /* IRQ, DSP to DSP, 0xDDD- */
+ AUD_CTL_MSG_D2D_IRQ = AUD_CTL_MSG_D2D_BASE + 0x00,
+
+
+ /* uint16_t */
+ AUD_CTL_MSG_MAX = 0xFFFF
+};
+
+
+
+#endif /* end of AUDIO_CONTROLLER_MSG_ID_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/audio_messenger_ipi.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/audio_messenger_ipi.h
new file mode 100644
index 0000000..bb32f78
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/audio_messenger_ipi.h
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_MESSENGER_IPI_H
+#define AUDIO_MESSENGER_IPI_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <audio_log.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * =============================================================================
+ * MACRO
+ * =============================================================================
+ */
+
+#define MAX_IPI_MSG_BUF_SIZE (272) /* SHARE_BUF_SIZE - 16 */
+#define IPI_MSG_HEADER_SIZE (16)
+#define MAX_IPI_MSG_PAYLOAD_SIZE (MAX_IPI_MSG_BUF_SIZE - IPI_MSG_HEADER_SIZE)
+
+#define IPI_MSG_MAGIC_NUMBER (0x8888)
+
+
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+
+enum { /* audio_ipi_msg_source_layer_t */
+ AUDIO_IPI_LAYER_FROM_HAL,
+ AUDIO_IPI_LAYER_FROM_KERNEL,
+ AUDIO_IPI_LAYER_FROM_DSP,
+
+ AUDIO_IPI_LAYER_FROM_SIZE,
+ AUDIO_IPI_LAYER_FROM_MAX = 15 /* 4-bit only */
+};
+
+enum { /* audio_ipi_msg_target_layer_t */
+ AUDIO_IPI_LAYER_TO_HAL,
+ AUDIO_IPI_LAYER_TO_KERNEL,
+ AUDIO_IPI_LAYER_TO_DSP,
+
+ AUDIO_IPI_LAYER_TO_SIZE,
+ AUDIO_IPI_LAYER_TO_MAX = 15 /* 4-bit only */
+};
+
+enum { /* audio_ipi_msg_data_t */
+ AUDIO_IPI_MSG_ONLY,
+ AUDIO_IPI_PAYLOAD,
+ AUDIO_IPI_DMA,
+
+ AUDIO_IPI_TYPE_SIZE
+};
+
+enum { /* audio_ipi_msg_ack_t */
+ /* bypass ack, but still send to audio queue */
+ AUDIO_IPI_MSG_BYPASS_ACK = 0,
+
+ /* need ack, and block in audio queue until ack back */
+ AUDIO_IPI_MSG_NEED_ACK = 1,
+ AUDIO_IPI_MSG_ACK_BACK = 2,
+
+ /* bypass audio queue, but still send to ipc queue */
+ AUDIO_IPI_MSG_DIRECT_SEND = 3,
+
+ AUDIO_IPI_MSG_CANCELED = 8
+};
+
+
+/*
+ * =============================================================================
+ * struct definition
+ * =============================================================================
+ */
+
+struct aud_data_t {
+ uint32_t memory_size; /* buffer size (memory) */
+ uint32_t data_size; /* 0 <= data_size <= memory_size */
+ union {
+ void *addr; /* memory address */
+ unsigned long addr_val; /* the value of address */
+
+ uint32_t dummy[2]; /* work between 32/64 bit environment */
+ };
+};
+
+struct ipi_msg_dma_info_t {
+ struct aud_data_t reserve; /* TODO: remove later */
+
+ struct aud_data_t hal_buf; /* source data buffer */
+
+ uint32_t rw_idx; /* region r/w index */
+ uint32_t data_size; /* region data size */
+
+ struct aud_data_t wb_dram; /* allow target to write data back */
+};
+#define IPI_MSG_DMA_INFO_SIZE (sizeof(struct ipi_msg_dma_info_t))
+
+
+struct ipi_msg_t {
+ /* header: 16 bytes */
+ uint16_t magic; /* IPI_MSG_MAGIC_NUMBER */
+ uint8_t task_scene; /* see task_scene_t */
+ uint8_t source_layer: 4; /* see audio_ipi_msg_source_layer_t */
+ uint8_t target_layer: 4; /* see audio_ipi_msg_target_layer_t */
+
+ uint8_t data_type; /* see audio_ipi_msg_data_t */
+ uint8_t ack_type; /* see audio_ipi_msg_ack_t */
+ uint16_t msg_id; /* defined by user */
+
+ union {
+ uint32_t param1;
+ uint32_t payload_size; /* payload */
+ uint32_t scp_ret;
+ };
+
+ uint32_t param2;
+
+ /* data: 256 bytes */
+ union {
+ char payload[MAX_IPI_MSG_PAYLOAD_SIZE]; /* payload only */
+ struct ipi_msg_dma_info_t dma_info; /* dma only */
+ char *dma_addr; /* TODO: remove later */
+ };
+
+};
+
+
+typedef void (*audio_ipi_dma_cbk_t)(
+ struct ipi_msg_t *msg,
+ void *buf,
+ uint32_t size,
+ void *arg);
+
+
+
+/*
+ * =============================================================================
+ * public functions
+ * =============================================================================
+ */
+
+void audio_messenger_ipi_init(void);
+void audio_messenger_ipi_deinit(void);
+
+
+#define DUMP_IPI_MSG(description, p_ipi_msg) \
+ do { \
+ if (description == NULL || (p_ipi_msg) == NULL) \
+ break; \
+ if ((p_ipi_msg)->magic != IPI_MSG_MAGIC_NUMBER) { \
+ AUD_LOG_D("%s, but magic 0x%x fail", \
+ description, (p_ipi_msg)->magic); \
+ break; \
+ } \
+ if ((p_ipi_msg)->data_type == AUDIO_IPI_MSG_ONLY) { \
+ AUD_LOG_D("%s, task: %d, msg_id: 0x%x, ack_type: %d, " \
+ "p1: 0x%x, p2: 0x%x", \
+ description, \
+ (p_ipi_msg)->task_scene, \
+ (p_ipi_msg)->msg_id, \
+ (p_ipi_msg)->ack_type, \
+ (p_ipi_msg)->param1, \
+ (p_ipi_msg)->param2); \
+ } else if ((p_ipi_msg)->data_type == AUDIO_IPI_PAYLOAD) { \
+ AUD_LOG_D("%s, task: %d, msg_id: 0x%x, ack_type: %d, " \
+ "payload_size: 0x%x, p2: 0x%x", \
+ description, \
+ (p_ipi_msg)->task_scene, \
+ (p_ipi_msg)->msg_id, \
+ (p_ipi_msg)->ack_type, \
+ (p_ipi_msg)->payload_size, \
+ (p_ipi_msg)->param2); \
+ } else if ((p_ipi_msg)->data_type == AUDIO_IPI_DMA) { \
+ AUD_LOG_D("%s, task: %d, msg_id: 0x%x, ack_type: %d, " \
+ "p1: 0x%x, p2: 0x%x, dma sz: %u, idx: %u, " \
+ "hal sz: %u", \
+ description, \
+ (p_ipi_msg)->task_scene, \
+ (p_ipi_msg)->msg_id, \
+ (p_ipi_msg)->ack_type, \
+ (p_ipi_msg)->param1, \
+ (p_ipi_msg)->param2, \
+ (p_ipi_msg)->dma_info.data_size, \
+ (p_ipi_msg)->dma_info.rw_idx, \
+ (p_ipi_msg)->dma_info.hal_buf.data_size); \
+ } \
+ } while (0)
+
+
+
+int audio_send_ipi_msg(
+ struct ipi_msg_t *p_ipi_msg,
+ uint8_t task_scene, /* task_scene_t */
+ uint8_t target_layer, /* audio_ipi_msg_target_layer_t */
+ uint8_t data_type, /* audio_ipi_msg_data_t */
+ uint8_t ack_type, /* audio_ipi_msg_ack_t */
+ uint16_t msg_id,
+ uint32_t param1, /* data_size for payload & dma */
+ uint32_t param2,
+ void *data_buffer); /* buffer for payload & dma */
+
+
+
+void audio_ipi_dma_cbk_register(
+ const uint8_t task_scene,
+ const uint32_t a2dSize,
+ const uint32_t d2aSize,
+ audio_ipi_dma_cbk_t cbk,
+ void *arg);
+
+void audio_ipi_dma_cbk_deregister(const uint8_t task_scene);
+
+
+
+void audio_load_task_scene(const uint8_t task_scene);
+
+
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* end of AUDIO_MESSENGER_IPI_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/audio_speech_msg_id.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/audio_speech_msg_id.h
new file mode 100644
index 0000000..b55b6c0
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/audio_speech_msg_id.h
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_SPEECH_MSG_ID_H
+#define AUDIO_SPEECH_MSG_ID_H
+
+#define IPI_MSG_A2D_BASE (0xAD00)
+#define IPI_MSG_D2A_BASE (0xDA00)
+
+#define IPI_MSG_M2D_BASE (0x3D00)
+#define IPI_MSG_D2M_BASE (0xD300)
+
+
+/* NOTE: all ack behaviors are rely on audio_ipi_msg_ack_t */
+enum ipi_msg_id_call_t {
+ /*======================================================================
+ * AP to OpenDSP
+ *====================================================================*/
+ /* volume, 0xAD0- */
+ IPI_MSG_A2D_UL_GAIN = IPI_MSG_A2D_BASE + 0x00,
+ IPI_MSG_A2D_DL_GAIN,
+
+ /* device environment info, 0xAD1- */
+ IPI_MSG_A2D_TASK_CFG = IPI_MSG_A2D_BASE + 0x10,
+ IPI_MSG_A2D_LIB_CFG,
+ IPI_MSG_A2D_SPH_PARAM,
+
+ /* function control, 0xAD2-*/
+ IPI_MSG_A2D_SPH_ON = IPI_MSG_A2D_BASE + 0x20,
+ IPI_MSG_A2D_TTY_ON,
+
+ /* speech enhancement control, 0xAD3-*/
+ IPI_MSG_A2D_UL_MUTE_ON = IPI_MSG_A2D_BASE + 0x30,
+ IPI_MSG_A2D_DL_MUTE_ON,
+ IPI_MSG_A2D_UL_ENHANCE_ON,
+ IPI_MSG_A2D_DL_ENHANCE_ON,
+ IPI_MSG_A2D_BT_NREC_ON,
+
+ /* tuning tool, 0xAD4-*/
+ IPI_MSG_A2D_SET_ADDR_VALUE = IPI_MSG_A2D_BASE + 0x40,
+ IPI_MSG_A2D_GET_ADDR_VALUE,
+ IPI_MSG_A2D_SET_KEY_VALUE,
+ IPI_MSG_A2D_GET_KEY_VALUE,
+
+
+ /* EMI base address, 0x8c070000-*/
+ IPI_MSG_A2D_GET_EMI_ADDRESS = IPI_MSG_A2D_BASE + 0x50,
+
+
+ /* aurisys, 0xAD6- */
+ IPI_MSG_A2D_AURISYS_INIT = IPI_MSG_A2D_BASE + 0x60,
+ IPI_MSG_A2D_AURISYS_DEINIT,
+ IPI_MSG_A2D_AURISYS_ROUTING,
+ IPI_MSG_A2D_AURISYS_PARAM,
+
+
+ /* debug, 0xADA- */
+ IPI_MSG_A2D_PCM_DUMP_ON = IPI_MSG_A2D_BASE + 0xA0,
+ IPI_MSG_A2D_LIB_LOG_ON,
+
+
+ /*======================================================================
+ * OpenDSP to AP
+ *====================================================================*/
+ IPI_MSG_D2A_PCM_DUMP_DATA_NOTIFY = IPI_MSG_D2A_BASE + 0x00,
+
+
+ /*======================================================================
+ * Modem to OpenDSP
+ *====================================================================*/
+ /* call data handshake, 0x3D0- */
+ IPI_MSG_M2D_CALL_DATA_READY = IPI_MSG_M2D_BASE + 0x00,
+
+};
+
+
+
+#endif // end of AUDIO_SPEECH_MSG_ID_H
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/audio_spkprotect_msg_id.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/audio_spkprotect_msg_id.h
new file mode 100644
index 0000000..53b37ae
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/audio_spkprotect_msg_id.h
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+* Copyright (C) 2016 MediaTek Inc.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+*/
+
+#ifndef AUDIO_SPKPROTECT_MSG_ID_H
+#define AUDIO_SPKPROTECT_MSG_ID_H
+
+
+#define SPK_IPI_MSG_A2D_BASE (0x200)
+
+enum {
+ SPK_PROTECT_OPEN = 0x1,
+ SPK_PROTECT_CLOSE,
+ SPK_PROTECT_PREPARE,
+ SPK_PROTECT_PLATMEMPARAM,
+ SPK_PROTECT_DLMEMPARAM,
+ SPK_PROTECT_IVMEMPARAM,
+ SPK_PROTECT_HWPARAM,
+ SPK_PROTECT_DLCOPY,
+ SPK_PROTECT_START,
+ SPK_PROTECT_STOP,
+ SPK_PROTECT_SETPRAM,
+ SPK_PROTECT_NEEDDATA,
+ SPK_PROTTCT_PCMDUMP_ON,
+ SPK_PROTTCT_PCMDUMP_OFF,
+ SPK_PROTECT_PCMDUMP_OK,
+ SPK_PROTECT_IRQDL,
+ SPK_PROTECT_IRQUL,
+ SPK_PROTECT_SPEECH_OPEN = 0x101,
+ SPK_PROTECT_SPEECH_CLOSE,
+ SPK_PROTECT_SPEECH_PREPARE,
+ SPK_PROTECT_SPEECH_MDFEEDBACKPARAM,
+ SPK_PROTECT_SPEECH_DLMEMPARAM,
+ SPK_PROTECT_SPEECH_IVMEMPARAM,
+ SPK_PROTECT_SPEECH_HWPARAM,
+ SPK_PROTECT_SPEECH_DLCOPY,
+ SPK_PROTECT_SPEECH_START,
+ SPK_PROTECT_SPEECH_STOP,
+ SPK_PROTECT_SPEECH_SETPRAM,
+ SPK_PROTECT_SPEECH_NEEDDATA,
+ SPK_PROTECT_SPEECH_IRQDL,
+ SPK_PROTECT_SPEECH_IRQUL,
+ SPK_PROTECT_CONFIGURE,
+ SPK_PROTECT_CALIB,
+ SPK_PROTECT_VAR,
+
+ /* volume */
+ SPK_MSG_A2D_UL_GAIN = SPK_IPI_MSG_A2D_BASE + 0x00,
+ SPK_MSG_A2D_DL_GAIN,
+
+ /* device environment info */
+ SPK_IPI_MSG_A2D_TASK_CFG = SPK_IPI_MSG_A2D_BASE + 0x10,
+ SPK_IPI_MSG_A2D_LIB_CFG,
+ SPK_IPI_MSG_A2D_PARAM,
+
+ /* function control*/
+ SPK_IPI_MSG_A2D_SPH_ON = SPK_IPI_MSG_A2D_BASE + 0x20,
+ SPK_IPI_MSG_A2D_TTY_ON,
+
+ /* speech enhancement control*/
+ SPK_IPI_MSG_A2D_UL_MUTE_ON = SPK_IPI_MSG_A2D_BASE + 0x30,
+ SPK_IPI_MSG_A2D_DL_MUTE_ON,
+ SPK_IPI_MSG_A2D_UL_ENHANCE_ON,
+ SPK_IPI_MSG_A2D_DL_ENHANCE_ON,
+ SPK_IPI_MSG_A2D_BT_NREC_ON,
+
+ /* tuning tool*/
+ SPK_IPI_MSG_A2D_SET_ADDR_VALUE = SPK_IPI_MSG_A2D_BASE + 0x40,
+ SPK_IPI_MSG_A2D_GET_ADDR_VALUE,
+ SPK_IPI_MSG_A2D_SET_KEY_VALUE,
+ SPK_IPI_MSG_A2D_GET_KEY_VALUE,
+
+ /* debug */
+ SPK_IPI_MSG_A2D_PCM_DUMP_ON = SPK_IPI_MSG_A2D_BASE + 0xA0,
+ SPK_IPI_MSG_A2D_LIB_LOG_ON,
+};
+
+#endif /* end of AUDIO_SPKPROTECT_MSG_ID_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/mlds_api.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/mlds_api.h
new file mode 100644
index 0000000..310426b
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/include/mlds_api.h
@@ -0,0 +1,495 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/**
+ ******************************************************************************
+ * @file mlds_api.h
+ * @author MTK audio driver team
+ * @version V0.7
+ * @date 29-June-2015
+ * @brief MLDS, Melodious Sound.
+ * Define audio/speech enhancement APIs for various usages.
+ ******************************************************************************
+ */
+
+#ifndef MTK_MLDS_API_H
+#define MTK_MLDS_API_H
+
+#include <stdint.h>
+
+
+#define MAKE_MLDS_API_VERSION(major, minor) (((uint8_t)(major)) << 8 | ((uint8_t)(minor)))
+#define MLDS_API_VERSION MAKE_MLDS_API_VERSION(0, 7)
+
+
+/*==============================================================================
+ * typedefs
+ *============================================================================*/
+
+typedef enum {
+ LIB_UNSUPPORTED = -1,
+ LIB_OK = 0,
+ LIB_ERROR = 1,
+ LIB_NULL_POINTER = 2,
+} lib_status_t;
+
+
+typedef enum {
+ TASK_SCENE_PHONE_CALL,
+ TASK_SCENE_VOW,
+ TASK_SCENE_PLAYBACK_MP3,
+ TASK_SCENE_RECORD,
+ TASK_SCENE_VOIP,
+ TASK_SCENE_SPEAKER_PROTECTION,
+} task_scene_t;
+
+
+typedef enum {
+ TASK_DEVICE_IN_NONE = 0,
+ TASK_DEVICE_IN_PHONE_MIC = (1 << 0),
+ TASK_DEVICE_IN_HEADSET_MIC = (1 << 1),
+ TASK_DEVICE_IN_BLUETOOTH_MIC = (1 << 2),
+} task_device_in_t;
+
+
+typedef enum {
+ TASK_DEVICE_OUT_NONE = 0,
+ TASK_DEVICE_OUT_RECEIVER = (1 << 0),
+ TASK_DEVICE_OUT_SPEAKER = (1 << 1),
+ TASK_DEVICE_OUT_HEADPHONE = (1 << 2),
+ TASK_DEVICE_OUT_BLUETOOTH = (1 << 3),
+} task_device_out_t;
+
+
+typedef enum {
+ BIT_FORMAT_S16_LE = 0, /* 16-bit signed pcm (2-bytes per channel) */
+ BIT_FORMAT_S24_LE, /* 24-bit signed pcm (4-bytes per channel) */
+ BIT_FORMAT_S32_LE, /* 32-bit signed pcm (4-bytes per channel) */
+} bit_format_t;
+
+
+typedef struct stream_info_t {
+ uint16_t device; /* task_device_in_t OR task_device_out_t */
+ uint16_t device_extra_info; /* reserve */
+ uint32_t sample_rate_in; /* 8000, 16000, 24000, 32000, ... */
+ uint32_t sample_rate_out; /* 8000, 16000, 24000, 32000, ... */
+ uint8_t bit_format_in; /* bit_format_t */
+ uint8_t bit_format_out; /* bit_format_t */
+ uint8_t num_channels_in; /* 1, 2, 3, 4 */
+ uint8_t num_channels_out; /* 1, 2, 3, 4 */
+} stream_info_t;
+
+
+typedef struct mlds_task_config_t {
+ uint16_t api_version; /* ex, 0x0120 => ver 1.32 */
+ uint16_t vendor_id; /* ex, 0x0E8D */
+ uint8_t task_scene; /* task_scene_t */
+ uint16_t frame_size_ms; /* ex, 20ms */
+
+ stream_info_t stream_uplink; /* for record & phone call */
+ stream_info_t stream_downlink; /* for playback & phone call */
+ union {
+ stream_info_t stream_echo_ref; /* for record & phone call */
+ stream_info_t stream_dl_fbk; /* for playback only */
+ };
+} mlds_task_config_t;
+
+typedef struct mlds_interface {
+ lib_status_t (*mlds_query_working_buf_size)(const mlds_task_config_t *p_mlds_task_config, uint32_t *p_working_buf_size);
+ lib_status_t (*mlds_create_handler)(
+ const mlds_task_config_t *p_mlds_task_config,
+ const uint32_t param_buf_size,
+ void *p_param_buf,
+ const uint32_t working_buf_size,
+ void *p_working_buf,
+ void **pp_handler);
+ lib_status_t (*mlds_process_ul_buf)(
+ void *p_ul_buf_in,
+ void *p_ul_buf_out,
+ void *p_aec_buf_in,
+ const uint32_t delay_ms,
+ void *p_handler,
+ void *arg);
+ lib_status_t(* mlds_process_dl_buf)(
+ void *p_dl_buf_in,
+ uint32_t *InSize,
+ void *p_dl_buf_out,
+ uint32_t *OutSize,
+ void *p_ref_buf,
+ uint32_t *RefBufSize,
+ void *p_handler,
+ void *arg);
+ lib_status_t (*mlds_destroy_handler)(void *p_handler);
+ lib_status_t (*mlds_update_device)(
+ const mlds_task_config_t *p_mlds_task_config,
+ const uint32_t param_buf_size,
+ void *p_param_buf,
+ void *p_handler);
+ lib_status_t (*mlds_update_param)(
+ const mlds_task_config_t *p_mlds_task_config,
+ const uint32_t param_buf_size,
+ void *p_param_buf,
+ void *p_handler);
+ lib_status_t (*mlds_query_param_buf_size)(
+ const mlds_task_config_t *p_mlds_task_config,
+ const char *platform_name,
+ const char *param_file_path,
+ const int enhancement_mode,
+ uint32_t *p_param_buf_size);
+ lib_status_t (*mlds_parsing_param_file)(
+ const mlds_task_config_t *p_mlds_task_config,
+ const char *platform_name,
+ const char *param_file_path,
+ const int enhancement_mode,
+ const uint32_t param_buf_size,
+ void *p_param_buf);
+ lib_status_t (*mlds_set_addr_value)(
+ uint32_t addr,
+ uint32_t value,
+ void *p_handler);
+ lib_status_t (*mlds_get_addr_value)(
+ uint32_t addr,
+ uint32_t *p_value,
+ void *p_handler);
+ lib_status_t (*mlds_set_ul_digital_gain)(
+ const int16_t ul_analog_gain_ref_only,
+ const int16_t ul_digital_gain,
+ void *p_handler);
+ lib_status_t (*mlds_set_dl_digital_gain)(
+ const int16_t dl_analog_gain_ref_only,
+ const int16_t dl_digital_gain,
+ void *p_handler);
+ lib_status_t (*mlds_set_ul_mute)(uint8_t b_mute_on, void *p_handler);
+ lib_status_t (*mlds_set_dl_mute)(uint8_t b_mute_on, void *p_handler);
+ lib_status_t (*mlds_set_ul_enhance)(uint8_t b_enhance_on, void *p_handler);
+ lib_status_t (*mlds_set_dl_enhance)(uint8_t b_enhance_on, void *p_handler);
+} mlds_interface;
+
+
+
+/*==============================================================================
+ * APIs
+ *============================================================================*/
+
+/**
+ ******************************************************************************
+ * @brief Query the size of the working buffer
+ *
+ * @param p_mlds_task_config the task configure
+ * @param p_working_buf_size the working buffer size.
+ *
+ * @return lib_status_t
+ ******************************************************************************
+ */
+lib_status_t mlds_query_working_buf_size(
+ const mlds_task_config_t *p_mlds_task_config,
+ uint32_t *p_working_buf_size);
+
+
+/**
+ ******************************************************************************
+ * @brief Create handler and initialize it
+ *
+ * @param p_mlds_task_config the task configure
+ * @param param_buf_size the size of param_buf
+ * @param p_param_buf the enhancement parameters and lib related configure settings
+ * @param working_buf_size the size of working buffer
+ * @param p_working_buf the allocated buffer and the size is from mlds_create_handler()
+ * @param pp_handler the handler of speech enhancement
+ *
+ * @return lib_status_t
+ ******************************************************************************
+ */
+lib_status_t mlds_create_handler(
+ const mlds_task_config_t *p_mlds_task_config,
+ const uint32_t param_buf_size,
+ void *p_param_buf,
+ const uint32_t working_buf_size,
+ void *p_working_buf,
+ void **pp_handler);
+
+
+/**
+ ******************************************************************************
+ * @brief Processing microphone/uplink data
+ *
+ * @param p_ul_buf_in the microphone/uplink data to be Processed
+ * ul_buf_in = ul_buf_mic1(1 frame) + ... + ul_buf_micN (1 frame)
+ * @param p_ul_buf_out the processed microphone/uplink data
+ * @param p_aec_buf_in the AEC reference data
+ * @param delay_ms the delay time(ms) of aec buf
+ * @param p_handler the handler of speech enhancement
+ * @param arg reserved field
+ *
+ * @return lib_status_t
+ ******************************************************************************
+ */
+lib_status_t mlds_process_ul_buf(
+ void *p_ul_buf_in,
+ void *p_ul_buf_out,
+ void *p_aec_buf_in,
+ const uint32_t delay_ms,
+ void *p_handler,
+ void *arg);
+
+
+/**
+ ******************************************************************************
+ * @brief Processing playback/downlink data
+ *
+ * @param p_dl_buf_in the playback/downlink data to be Processed
+ * @InSize Input:Inputsize of p_dl_buf_in / Output:buffersize consume p_dl_buf_in
+ * @param p_dl_buf_out the processed playback/downlink data
+ * @OutSize Input:OutSize of p_dl_buf_out / Output:buffersize consume p_dl_buf_out
+ * @param p_ref_buf the reference buffer
+ * @OutSize Input:OutSize of p_ref_buf / Output:buffersize consume p_ref_buf
+ * @param p_handler the handler of speech enhancement
+ * @param arg reserved field
+ *
+ * @return lib_status_t
+ ******************************************************************************
+ */
+
+lib_status_t mlds_process_dl_buf(
+ void *p_dl_buf_in,
+ uint32_t *InSize,
+ void *p_dl_buf_out,
+ uint32_t *OutSize,
+ void *p_ref_buf,
+ uint32_t *RefBufSize,
+ void *p_handler,
+ void *arg);
+
+
+/**
+ ******************************************************************************
+ * @brief deinitialize handler and destroy it (no need to free the working buffer)
+ *
+ * @param p_handler the handler of speech enhancement
+ *
+ * @return lib_status_t
+ ******************************************************************************
+ */
+lib_status_t mlds_destroy_handler(void *p_handler);
+
+
+/**
+ ******************************************************************************
+ * @brief Update task device info
+ *
+ * @param p_mlds_task_config the task configure
+ * @param param_buf_size the size of param_buf
+ * @param p_param_buf the enhancement parameters and lib related configure settings
+ * @param p_handler the handler of speech enhancement
+ *
+ * @return lib_status_t
+ ******************************************************************************
+ */
+lib_status_t mlds_update_device(
+ const mlds_task_config_t *p_mlds_task_config,
+ const uint32_t param_buf_size,
+ void *p_param_buf,
+ void *p_handler);
+
+
+/**
+ ******************************************************************************
+ * @brief Update speech enhancement parameters
+ *
+ * @param p_mlds_task_config the task configure
+ * @param param_buf_size the size of param_buf
+ * @param p_param_buf the enhancement parameters and lib related configure settings
+ * @param p_handler the handler of speech enhancement
+ *
+ * @return lib_status_t
+ ******************************************************************************
+ */
+lib_status_t mlds_update_param(
+ const mlds_task_config_t *p_mlds_task_config,
+ const uint32_t param_buf_size,
+ void *p_param_buf,
+ void *p_handler);
+
+
+/**
+ ******************************************************************************
+ * @brief Query the buffer size to keep speech enhancement parameters(single mode)
+ * Implemented in HAL, but not OpenDSP.
+ *
+ * @param p_mlds_task_config the task configure
+ * @param platform_name the platform name by "adb shell getprop ro.product.model"
+ * @param param_file_path the speech enhancement param file (fullset)
+ * @param enhancement_mode the speech enhancement mode by apk
+ * @param p_param_buf_size the pointer to a variable to keep the size of param buffer
+ *
+ * @return lib_status_t
+ ******************************************************************************
+ */
+lib_status_t mlds_query_param_buf_size(
+ const mlds_task_config_t *p_mlds_task_config,
+ const char *platform_name,
+ const char *param_file_path,
+ const int enhancement_mode,
+ uint32_t *p_param_buf_size);
+
+
+/**
+ ******************************************************************************
+ * @brief Parsing param file to get param buffer(single mode)
+ * Implemented in HAL, but not OpenDSP.
+ *
+ * @param p_mlds_task_config the task configure
+ * @param platform_name the platform name by "adb shell getprop ro.product.model"
+ * @param param_file_path the speech enhancement param file (fullset)
+ * @param enhancement_mode the speech enhancement mode by apk
+ * @param param_buf_size the size of param buffer
+ * @param p_param_buf the param buffer(single mode)
+ *
+ * @return lib_status_t
+ ******************************************************************************
+ */
+lib_status_t mlds_parsing_param_file(
+ const mlds_task_config_t *p_mlds_task_config,
+ const char *platform_name,
+ const char *param_file_path,
+ const int enhancement_mode,
+ const uint32_t param_buf_size,
+ void *p_param_buf);
+
+
+/**
+ ******************************************************************************
+ * @brief Set value at a specified address
+ *
+ * @param addr the specified address
+ * @param value the value to be setted at the specified address
+ * @param p_handler the handler of speech enhancement
+ *
+ * @return lib_status_t
+ ******************************************************************************
+ */
+lib_status_t mlds_set_addr_value(
+ uint32_t addr,
+ uint32_t value,
+ void *p_handler);
+
+
+/**
+ ******************************************************************************
+ * @brief Get value at a specified address
+ *
+ * @param addr the specified address
+ * @param p_value the pointer to a variable to get the value at the specified address
+ * @param p_handler the handler of speech enhancement
+ *
+ * @return lib_status_t
+ ******************************************************************************
+ */
+lib_status_t mlds_get_addr_value(
+ uint32_t addr,
+ uint32_t *p_value,
+ void *p_handler);
+
+
+/**
+ ******************************************************************************
+ * @brief set uplink digital gain
+ *
+ * @param ul_analog_gain_ref_only uplink PGA gain. For reference only.
+ * The unit is 0.25 dB.
+ * value: 0x0000 => 0.0dB, 0xFFFC = -1.0dB, 0x0020 = +8.0dB
+ * @param ul_digital_gain uplink gain.
+ * The unit is 0.25 dB.
+ * So gain value [0, 120] => 0 to 30dB
+ * @param p_handler the handler of speech enhancement
+ *
+ * @return lib_status_t
+ ******************************************************************************
+ */
+lib_status_t mlds_set_ul_digital_gain(
+ const int16_t ul_analog_gain_ref_only,
+ const int16_t ul_digital_gain,
+ void *p_handler);
+
+
+/**
+ ******************************************************************************
+ * @brief set downlink digital gain
+ *
+ * @param dl_analog_gain_ref_only downlink PGA gain. For reference only.
+ * The unit is 0.25 dB.
+ * value: 0x0000 => 0.0dB, 0xFFFC = -1.0dB, 0x0020 = +8.0dB
+ * @param dl_digital_gain downlink gain.
+ The unit is 0.25 dB.
+ * So gain value [-256, 0] => -64 to 0 dB
+ * @param p_handler the handler of speech enhancement
+ *
+ * @return lib_status_t
+ ******************************************************************************
+ */
+lib_status_t mlds_set_dl_digital_gain(
+ const int16_t dl_analog_gain_ref_only,
+ const int16_t dl_digital_gain,
+ void *p_handler);
+
+
+/**
+ ******************************************************************************
+ * @brief mute/unmute uplink
+ *
+ * @param b_mute_on mute uplink or not.
+ * - true: mute
+ * - false: unmute(default state)
+ * @param p_handler the handler of speech enhancement
+ *
+ * @return lib_status_t
+ ******************************************************************************
+ */
+lib_status_t mlds_set_ul_mute(uint8_t b_mute_on, void *p_handler);
+
+
+/**
+ ******************************************************************************
+ * @brief mute/unmute downlink
+ *
+ * @param b_mute_on mute downlink or not.
+ * - true: mute
+ * - false: unmute(default state)
+ * @param p_handler the handler of speech enhancement
+ *
+ * @return lib_status_t
+ ******************************************************************************
+ */
+lib_status_t mlds_set_dl_mute(uint8_t b_mute_on, void *p_handler);
+
+
+/**
+ ******************************************************************************
+ * @brief enable/disable uplink enhancement function
+ *
+ * @param b_enhance_on enable uplink speech enhancement or not.
+ * true: enable(default state)
+ * false: disable
+ * @param p_handler the handler of speech enhancement
+ *
+ * @return lib_status_t
+ ******************************************************************************
+ */
+lib_status_t mlds_set_ul_enhance(uint8_t b_enhance_on, void *p_handler);
+
+
+/**
+ ******************************************************************************
+ * @brief enable/disable downlink enhancement function
+ *
+ * @param b_enhance_on enable downlink speech enhancement or not.
+ * - true: enable(default state)
+ * - false: disable
+ * @param p_handler the handler of speech enhancement
+ *
+ * @return lib_status_t
+ ******************************************************************************
+ */
+lib_status_t mlds_set_dl_enhance(uint8_t b_enhance_on, void *p_handler);
+
+
+#endif // end of MTK_MLDS_API_H
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/AudioALSASpeechLoopbackController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/AudioALSASpeechLoopbackController.cpp
new file mode 100644
index 0000000..715a0d7
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/AudioALSASpeechLoopbackController.cpp
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioALSASpeechLoopbackController.h"
+
+#include "AudioALSADriverUtility.h"
+#include "AudioALSADeviceParser.h"
+#include "AudioALSAHardwareResourceManager.h"
+#if defined(MTK_AUDIO_KS)
+#include "AudioALSADeviceConfigManager.h"
+#include "AudioSmartPaController.h"
+#endif
+
+#include "SpeechDriverInterface.h"
+#include "SpeechDriverFactory.h"
+#include "SpeechVMRecorder.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSASpeechLoopbackController"
+
+namespace android {
+
+AudioALSASpeechLoopbackController *AudioALSASpeechLoopbackController::mSpeechLoopbackController = NULL;
+AudioALSASpeechLoopbackController *AudioALSASpeechLoopbackController::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mSpeechLoopbackController == NULL) {
+ mSpeechLoopbackController = new AudioALSASpeechLoopbackController();
+ }
+ ASSERT(mSpeechLoopbackController != NULL);
+ return mSpeechLoopbackController;
+}
+
+
+AudioALSASpeechLoopbackController::AudioALSASpeechLoopbackController() :
+ mHardwareResourceManager(AudioALSAHardwareResourceManager::getInstance()),
+ mSpeechDriverFactory(SpeechDriverFactory::GetInstance()),
+ mPcmUL(NULL),
+ mPcmDL(NULL),
+ mUseBtCodec(false) {
+ memset((void *)&mConfig, 0, sizeof(mConfig));
+}
+
+
+AudioALSASpeechLoopbackController::~AudioALSASpeechLoopbackController() {
+
+}
+
+status_t AudioALSASpeechLoopbackController::open(const audio_devices_t output_devices, const audio_devices_t input_device) {
+ ALOGD("+%s(), output_devices = 0x%x, input_device = 0x%x", __FUNCTION__, output_devices, input_device);
+ AL_AUTOLOCK(mLock);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ // get speech driver instance
+ SpeechDriverInterface *pSpeechDriver = mSpeechDriverFactory->GetSpeechDriver();
+
+ // check BT device // TODO(Harvey): BT Loopback?
+#if defined(SPH_SR32K)
+ const uint32_t sample_rate = 32000;
+#elif defined(SPH_SR48K)
+ const uint32_t sample_rate = 48000;
+#else
+ const uint32_t sample_rate = 16000;
+#endif
+ ALOGD("%s(), sample_rate = %d", __FUNCTION__, sample_rate);
+
+
+ //--- here to test pcm interface platform driver_attach
+#ifdef MTK_VOICE_ULTRA
+ if (output_devices == AUDIO_DEVICE_OUT_EARPIECE) {
+ int PcmInIdx, PcmOutIdx, CardIndex;
+ PcmInIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceUltra);
+ PcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceUltra);
+ CardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVoiceUltra);
+ String8 mixer_ctl_name;
+
+ if (mSpeechDriverFactory->GetActiveModemIndex() == MODEM_1) {
+ mixer_ctl_name = "md1";
+ } else {
+ mixer_ctl_name = "md2";
+ }
+
+ ALOGD("%s(), select ultra %s, PcmOutIdx = %d PcmInIdx = %d", __FUNCTION__,
+ mixer_ctl_name.string(), PcmOutIdx, PcmInIdx);
+ if (mixer_ctl_set_enum_by_string(
+ mixer_get_ctl_by_name(AudioALSADriverUtility::getInstance()->getMixer(), "Ultra_Modem_Select")
+ , mixer_ctl_name.string())) {
+ ALOGE("Error: Ultra_Modem_Select invalid value");
+ }
+
+ // ASSERT(mPcmIn == NULL && mPcmOut == NULL); // TODO:
+
+ // use pcm out to set memif, ultrasound, downlink
+ enum pcm_format memifFormat = PCM_FORMAT_S16_LE; // PCM_FORMAT_S32_LE or PCM_FORMAT_S16_LE
+ unsigned int ultraRate = 96000; // 192000 or 96000
+ unsigned int msPerPeriod = 10; // note: max sram is 48k for mt6797
+
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = 1;
+ mConfig.rate = ultraRate;
+ mConfig.period_size = (ultraRate * msPerPeriod) / 1000;
+ mConfig.period_count = 2;
+ mConfig.format = memifFormat;
+
+ mPcmDL = pcm_open(CardIndex, PcmOutIdx, PCM_OUT, &mConfig);
+
+ // use pcm in to set modem, uplink
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = 2;
+ mConfig.rate = sample_rate; // modem rate
+ mConfig.period_size = 1024;
+ mConfig.period_count = 2;
+ mConfig.format = PCM_FORMAT_S16_LE;
+
+ mPcmUL = pcm_open(CardIndex, PcmInIdx, PCM_IN, &mConfig);
+ } else
+#endif
+ {
+ int pcmInIdx, pcmOutIdx, cardIndex;
+
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = 2;
+ mConfig.rate = sample_rate;
+ mConfig.period_size = 1024;
+ mConfig.period_count = 2;
+ mConfig.format = PCM_FORMAT_S16_LE;
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+
+#if defined(MTK_AUDIO_KS)
+ mConfig.stop_threshold = ~(0U);
+ if ((output_devices & AUDIO_DEVICE_OUT_SPEAKER) &&
+ AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence(mSpeechDriverFactory->GetActiveModemIndex() == MODEM_1 ?
+ AUDIO_CTL_MD1_TO_I2S : AUDIO_CTL_MD2_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+
+ if (popcount(output_devices) > 1) {
+ mApTurnOnSequence2 = mSpeechDriverFactory->GetActiveModemIndex() == MODEM_1 ?
+ AUDIO_CTL_MD1_TO_ADDA_DL : AUDIO_CTL_MD2_TO_ADDA_DL;
+ }
+ } else {
+ mApTurnOnSequence = mSpeechDriverFactory->GetActiveModemIndex() == MODEM_1 ?
+ AUDIO_CTL_MD1_TO_ADDA_DL : AUDIO_CTL_MD2_TO_ADDA_DL;
+ }
+
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence2);
+ }
+
+ pcmInIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessSpeech);
+ pcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessSpeech);
+ cardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmHostlessSpeech);
+
+ mHardwareResourceManager->startInputDevice(input_device);
+#else
+ if (mSpeechDriverFactory->GetActiveModemIndex() == MODEM_1) {
+ pcmInIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceMD1);
+ pcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceMD1);
+ cardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVoiceMD1);
+ } else {
+ pcmInIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceMD2);
+ pcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceMD2);
+ cardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVoiceMD2);
+ }
+#endif
+
+ ASSERT(mPcmUL == NULL && mPcmDL == NULL);
+ mPcmUL = pcm_open(cardIndex, pcmInIdx, PCM_IN, &mConfig);
+ mPcmDL = pcm_open(cardIndex, pcmOutIdx, PCM_OUT, &mConfig);
+ ASSERT(mPcmUL != NULL && mPcmDL != NULL);
+ ALOGV("%s(), mPcmUL = %p, mPcmDL = %p", __FUNCTION__, mPcmUL, mPcmDL);
+ }
+ if (pcm_start(mPcmUL)) {
+ ALOGE("%s(), pcm_start UL %p fail due to %s", __FUNCTION__, mPcmUL, pcm_get_error(mPcmUL));
+ }
+
+ if (pcm_start(mPcmDL)) {
+ ALOGE("%s(), pcm_start DL(%p) fail due to %s", __FUNCTION__, mPcmDL, pcm_get_error(mPcmDL));
+ }
+
+#if !defined(MTK_AUDIO_KS)
+ // Set PMIC digital/analog part - uplink has pop, open first
+ mHardwareResourceManager->startInputDevice(input_device);
+#endif
+
+ // Clean Side Tone Filter gain
+ pSpeechDriver->SetSidetoneGain(0);
+
+ // Set MD side sampling rate
+ pSpeechDriver->SetModemSideSamplingRate(sample_rate);
+ pSpeechDriver->setLpbkFlag(true);
+
+ // Set speech mode
+ pSpeechDriver->SetSpeechMode(input_device, output_devices);
+
+ // Loopback on
+ pSpeechDriver->SetAcousticLoopback(true);
+
+ mHardwareResourceManager->startOutputDevice(output_devices, sample_rate);
+
+ // check VM need open
+ SpeechVMRecorder *pSpeechVMRecorder = SpeechVMRecorder::getInstance();
+ if (pSpeechVMRecorder->getVmConfig() == SPEECH_VM_SPEECH) {
+ ALOGD("%s(), Open VM/EPL record", __FUNCTION__);
+ pSpeechVMRecorder->open();
+ }
+
+ ALOGD("-%s(), output_devices = 0x%x, input_device = 0x%x", __FUNCTION__, output_devices, input_device);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSASpeechLoopbackController::close() {
+ ALOGD("+%s()", __FUNCTION__);
+ AL_AUTOLOCK(mLock);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ // check VM need close
+ SpeechVMRecorder *pSpeechVMRecorder = SpeechVMRecorder::getInstance();
+ if (pSpeechVMRecorder->getVMRecordStatus() == true) {
+ ALOGD("%s(), Close VM/EPL record", __FUNCTION__);
+ pSpeechVMRecorder->close();
+ }
+
+ mHardwareResourceManager->stopOutputDevice();
+
+ // Stop MODEM_PCM
+ pcm_stop(mPcmDL);
+ pcm_stop(mPcmUL);
+ pcm_close(mPcmDL);
+ pcm_close(mPcmUL);
+
+ mPcmDL = NULL;
+ mPcmUL = NULL;
+
+ mHardwareResourceManager->stopInputDevice(mHardwareResourceManager->getInputDevice());
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence2);
+ mApTurnOnSequence2.clear();
+ }
+#endif
+
+ // Get current active speech driver
+ SpeechDriverInterface *pSpeechDriver = mSpeechDriverFactory->GetSpeechDriver();
+
+ // Loopback off
+ pSpeechDriver->SetAcousticLoopback(false);
+ pSpeechDriver->setLpbkFlag(false);
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t AudioALSASpeechLoopbackController::SetModemBTCodec(bool enable_codec) {
+ ALOGD("+%s(), enable_codec = %d", __FUNCTION__, enable_codec);
+ mUseBtCodec = enable_codec;
+ return NO_ERROR;
+}
+
+status_t AudioALSASpeechLoopbackController::OpenModemLoopbackControlFlow(const audio_devices_t input_device, const audio_devices_t output_device) {
+ ALOGD("+%s(), output_device = 0x%x, input_device = 0x%x", __FUNCTION__, output_device, input_device);
+ AL_AUTOLOCK(mLock);
+
+ // get speech driver instance
+ SpeechDriverInterface *pSpeechDriver = mSpeechDriverFactory->GetSpeechDriver();
+
+ // check BT device // TODO(Harvey): BT Loopback?
+ const bool bt_device_on = audio_is_bluetooth_sco_device(output_device);
+#if defined(SPH_SR32K)
+ const int sample_rate = (bt_device_on == true) ? 8000 : 32000;
+#elif defined(SPH_SR48K)
+ const int sample_rate = (bt_device_on == true) ? 8000 : 48000;
+#else
+ const int sample_rate = (bt_device_on == true) ? 8000 : 16000;
+#endif
+ ALOGD("%s(), sample_rate = %d", __FUNCTION__, sample_rate);
+
+ // Clean Side Tone Filter gain
+ pSpeechDriver->SetSidetoneGain(0);
+
+ // Set MD side sampling rate
+ pSpeechDriver->SetModemSideSamplingRate(sample_rate);
+
+ // Set speech mode
+ pSpeechDriver->SetSpeechMode(input_device, output_device);
+
+ // BT Loopback on
+ pSpeechDriver->SetAcousticLoopbackBtCodec(mUseBtCodec);
+ pSpeechDriver->SetAcousticLoopback(true);
+
+ ALOGD("-%s(), output_devices = 0x%x, input_device = 0x%x", __FUNCTION__, output_device, input_device);
+ return NO_ERROR;
+}
+
+
+status_t AudioALSASpeechLoopbackController::CloseModemLoopbackControlFlow(void) {
+ AL_AUTOLOCK(mLock);
+ ALOGD("+%s()", __FUNCTION__);
+
+ // Get current active speech driver
+ SpeechDriverInterface *pSpeechDriver = mSpeechDriverFactory->GetSpeechDriver();
+
+ // Loopback off
+ pSpeechDriver->SetAcousticLoopback(false);
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/AudioALSASpeechStreamController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/AudioALSASpeechStreamController.cpp
new file mode 100644
index 0000000..4d3f144
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/AudioALSASpeechStreamController.cpp
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSASpeechStreamController"
+
+#include <unistd.h>
+#include <sched.h>
+#include <sys/prctl.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <cutils/properties.h>
+#include "AudioALSAHardwareResourceManager.h"
+#include "SpeechDriverInterface.h"
+#include "SpeechDriverFactory.h"
+#include "AudioALSAStreamOut.h"
+#include "AudioALSAStreamIn.h"
+#include "AudioALSASpeechStreamController.h"
+#include "AudioALSASpeechStreamController.h"
+#include "AudioALSACaptureHandlerModemDai.h"
+#include "MtkAudioComponent.h"
+#include "AudioDeviceInt.h"
+
+#define FRAME_BLOCK_SIZE 320
+
+namespace android {
+
+/*==============================================================================
+ * Property keys
+ *============================================================================*/
+AudioALSASpeechStreamController *AudioALSASpeechStreamController::UniqueInstance = NULL;
+AudioALSASpeechStreamController *AudioALSASpeechStreamController::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (UniqueInstance == NULL) {
+ UniqueInstance = new AudioALSASpeechStreamController();
+ }
+ ASSERT(UniqueInstance != NULL);
+ return UniqueInstance;
+}
+
+AudioALSASpeechStreamController::AudioALSASpeechStreamController() {
+ int ret;
+ ALOGD("%s()", __FUNCTION__);
+
+ m_bEnabled = false;
+ m_bThreadExit = false;
+ mOutputDevices = AUDIO_DEVICE_NONE;
+ mHardwareResourceManager = NULL;
+ mAudioMode = AUDIO_MODE_NORMAL;
+ mRoutingForTty = 0;
+ mPcmIn = NULL;
+ mPcmOut = NULL;
+ mSpeechStreamThreadID = 0;
+ mAudioMtkStreamManager = AudioALSAStreamManager::getInstance();
+
+ ret = pthread_mutex_init(&mSpeechStreamMutex, NULL);
+ if (ret != 0) {
+ ALOGE("Failed to initialize mSpeechStreamMutex!");
+ }
+
+ ret = pthread_cond_init(&mSphStream_Cond, NULL);
+ if (ret != 0) {
+ ALOGE("Failed to initialize mSphStream_Cond!");
+ }
+}
+
+AudioALSASpeechStreamController::~AudioALSASpeechStreamController() {
+ ALOGD("%s()", __FUNCTION__);
+ pthread_cond_destroy(&mSphStream_Cond);
+}
+
+void *AudioALSASpeechStreamController::SpeechStreamThread(void *arg) {
+ ALOGD("%s() +", __FUNCTION__);
+
+ /*
+ * deivce setting
+ */
+ int Inputformat = AUDIO_FORMAT_PCM_16_BIT;
+ uint32_t Inputdevice = AUDIO_DEVICE_IN_SPK_FEED;
+ uint32_t Inputchannel = AUDIO_CHANNEL_IN_STEREO;
+ uint32_t InputsampleRate = 16000;
+ status_t status = 0;
+
+ /**
+ * Bit Converter
+ */
+ MtkAudioBitConverterBase *mBitConverter = NULL;
+ int *mBitConverterOutputBuffer = NULL;
+ uint32_t bytesAfterpostprocessings = 0;
+ uint32_t bytesBeforepostprocessings = 0;
+
+ /*
+ * StreamIn Read Parameters
+ */
+ const int ReadStreamInLength = (FRAME_BLOCK_SIZE * sizeof(short));
+ int mStreaimInReadBytes = 0;
+ void *pWriteBuffer = NULL;
+ short *ReadStreamInBuffer = NULL;
+
+ AudioMTKStreamInInterface *streamInput = NULL;
+ AudioMTKStreamOutInterface *streamOutput = NULL;
+ AudioALSASpeechStreamController *pSphStrmCtrl = static_cast<AudioALSASpeechStreamController *>(arg);
+
+ if (pSphStrmCtrl == NULL) {
+ ALOGE("SpeechStreamThread pSphStrmCtrl = NULL");
+ return 0;
+ }
+
+ if (mBitConverter == NULL) {
+ mBitConverter = newMtkAudioBitConverter(InputsampleRate, 2, BCV_IN_Q1P15_OUT_Q1P31);
+ ASSERT(mBitConverter != NULL);
+ if (mBitConverter != NULL) {
+ mBitConverter->open();
+ mBitConverter->resetBuffer();
+ }
+ if (mBitConverterOutputBuffer == NULL) {
+ mBitConverterOutputBuffer = new int[FRAME_BLOCK_SIZE];
+ ASSERT(mBitConverterOutputBuffer != NULL);
+ }
+ }
+
+ if (ReadStreamInBuffer == NULL) {
+ ReadStreamInBuffer = new short[FRAME_BLOCK_SIZE];
+ memset(ReadStreamInBuffer, 0, sizeof(short)*FRAME_BLOCK_SIZE);
+ }
+
+ pthread_mutex_lock(&pSphStrmCtrl->mSpeechStreamMutex);
+ pSphStrmCtrl->m_bThreadExit = false;
+
+ /*
+ * Adjust thread priority
+ */
+ prctl(PR_SET_NAME, (unsigned long)"SpeechStreamPlayback", 0, 0, 0);
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_HIGHEST);
+ ALOGD("+%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+
+ /*
+ * ----start the loop --------
+ */
+ streamInput = pSphStrmCtrl->getStreamManager()->openInputStream(Inputdevice, &Inputformat, &Inputchannel, &InputsampleRate, &status, (audio_in_acoustics_t)0);
+ ASSERT(streamInput != NULL);
+
+ /*
+ * output device setting
+ */
+
+ uint32_t OutputDevice = AUDIO_DEVICE_OUT_SPEAKER_SAFE; // need to different fomr normal playback
+ uint32_t Outputchannel = AUDIO_CHANNEL_OUT_STEREO;
+ int Outputformat = AUDIO_FORMAT_PCM_32_BIT;
+ uint32_t sampleRate = 16000;
+ streamOutput = pSphStrmCtrl->getStreamManager()->openOutputStream(OutputDevice, &Outputformat, &Outputchannel, &sampleRate, &status);
+ ASSERT(streamOutput != NULL);
+
+
+ ALOGD("pthread_cond_signal(&pSpkMonitor->mSphStream_Cond)");
+ pthread_cond_signal(&pSphStrmCtrl->mSphStream_Cond);
+ pthread_mutex_unlock(&pSphStrmCtrl->mSpeechStreamMutex);
+ ALOGD("%s() loop start", __FUNCTION__);
+
+ //AudioALSAHardwareResourceManager::getInstance ()->setSgenMode(SGEN_MODE_O12);
+
+ while (pSphStrmCtrl->m_bEnabled && pSphStrmCtrl->m_bThreadExit == false) {
+ if (streamInput != NULL) {
+ mStreaimInReadBytes = streamInput->read(ReadStreamInBuffer, ReadStreamInLength);
+ if (mBitConverter != NULL) {
+ bytesBeforepostprocessings = ReadStreamInLength;
+ bytesAfterpostprocessings = ReadStreamInLength * 2;
+ mBitConverter->process(ReadStreamInBuffer, &bytesBeforepostprocessings, (void *)mBitConverterOutputBuffer, &bytesAfterpostprocessings);
+ pWriteBuffer = (void *)mBitConverterOutputBuffer;
+ }
+
+ if (streamOutput != NULL && pSphStrmCtrl->m_bEnabled == true && pSphStrmCtrl->m_bThreadExit == false) {
+ streamOutput->write(pWriteBuffer, bytesAfterpostprocessings);
+ }
+ }
+ }
+
+ ALOGD("%s() loop end", __FUNCTION__);
+ if (streamOutput != NULL) {
+ streamOutput->standbyStreamOut();
+ pSphStrmCtrl->getStreamManager()->closeOutputStream(streamOutput);
+ streamOutput = NULL;
+ }
+
+ if (streamInput != NULL) {
+ streamInput->standby();
+ pSphStrmCtrl->getStreamManager()->closeInputStream(streamInput);
+ streamInput = NULL;
+ }
+
+ if (ReadStreamInBuffer != NULL) {
+ delete[] ReadStreamInBuffer;
+ ReadStreamInBuffer = NULL;
+ }
+
+ // deinit bit converter if need
+ if (mBitConverter != NULL) {
+ mBitConverter->close();
+ deleteMtkAudioBitConverter(mBitConverter);
+ mBitConverter = NULL;
+ }
+
+ if (mBitConverterOutputBuffer != NULL) {
+ delete[] mBitConverterOutputBuffer;
+ mBitConverterOutputBuffer = NULL;
+ }
+
+ ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+ pthread_mutex_lock(&pSphStrmCtrl->mSpeechStreamMutex);
+ ALOGD("pthread_cond_signal(&pSphStrmCtrl->mSphStream_Cond)");
+ pthread_cond_signal(&pSphStrmCtrl->mSphStream_Cond);
+ pthread_mutex_unlock(&pSphStrmCtrl->mSpeechStreamMutex);
+ pthread_exit(NULL);
+ return 0;
+}
+
+audio_devices_t AudioALSASpeechStreamController::GetStreamOutputDevice(void) {
+ ALOGD("%s mOutputDevices = %d", __FUNCTION__, mOutputDevices);
+ return mOutputDevices;
+}
+
+status_t AudioALSASpeechStreamController::SetStreamOutputDevice(audio_devices_t OutputDevices) {
+ ALOGD("%s(), %d", __FUNCTION__, OutputDevices);
+ mOutputDevices = OutputDevices;
+ return NO_ERROR;
+}
+
+bool AudioALSASpeechStreamController::IsSpeechStreamThreadEnable(void) {
+ ALOGD("%s(), %d", __FUNCTION__, m_bEnabled);
+ return m_bEnabled;
+}
+
+status_t AudioALSASpeechStreamController::EnableSpeechStreamThread(bool enable) {
+ struct timeval now;
+ struct timespec timeout;
+ gettimeofday(&now, NULL);
+ timeout.tv_sec = now.tv_sec + 3;
+ timeout.tv_nsec = now.tv_usec * 1000;
+ int ret;
+ void *status;
+ ALOGD("%s() %d", __FUNCTION__, enable);
+
+ if (enable == true && m_bEnabled == false) {
+ ALOGD("open SpeechStreamThread");
+ pthread_mutex_lock(&mSpeechStreamMutex);
+ ret = pthread_create(&mSpeechStreamThreadID, NULL, AudioALSASpeechStreamController::SpeechStreamThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("EnableSpeechStreamThread pthread_create error!!");
+ }
+
+ ALOGD("+mSphStream_Cond wait");
+ m_bEnabled = true;
+ ret = pthread_cond_timedwait(&mSphStream_Cond, &mSpeechStreamMutex, &timeout);
+ ALOGD("-mSphStream_Cond receive ret=%d", ret);
+ pthread_mutex_unlock(&mSpeechStreamMutex);
+
+ } else if (enable == false && m_bEnabled == true) {
+ ALOGD("close SpeechStreamThread");
+ pthread_mutex_lock(&mSpeechStreamMutex);
+ if (!m_bThreadExit) {
+ m_bThreadExit = true;
+ ALOGD("+mSphStream_Cond wait");
+ ret = pthread_cond_timedwait(&mSphStream_Cond, &mSpeechStreamMutex, &timeout);
+ ALOGD("-mSphStream_Cond receive ret=%d", ret);
+ }
+ m_bEnabled = false;
+ pthread_mutex_unlock(&mSpeechStreamMutex);
+ ALOGD("%s +pthread_join", __FUNCTION__);
+ pthread_join(mSpeechStreamThreadID, &status);
+ ALOGD("%s -pthread_join", __FUNCTION__);
+ }
+ return NO_ERROR;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechDriverLAD.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechDriverLAD.cpp
new file mode 100644
index 0000000..790419c
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechDriverLAD.cpp
@@ -0,0 +1,1641 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <SpeechDriverLAD.h>
+
+#include <SpeechMessengerECCCI.h>
+#include <SpeechMessengerCCCI.h>
+
+#if defined (AUDIO_C2K_SUPPORT)
+#include <SpeechMessengerEVDO.h>
+#endif
+
+#include <CFG_AUDIO_File.h> // alps/vendor/mediatek/proprietary/custom/common/cgen/cfgfileinc/CFG_AUDIO_File.h
+
+#include <SpeechEnhancementController.h>
+#include <SpeechVMRecorder.h>
+
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+#include <AudioParamParser.h>
+#include <SpeechParamParser.h>
+#endif
+
+//#if defined(MTK_VIBSPK_SUPPORT)
+#include <AudioCompFltCustParam.h>
+#include <AudioVIBSPKControl.h>
+//#endif
+#include <AudioALSAStreamManager.h>
+
+#include <AudioLock.h>
+#include <AudioUtility.h>
+#include <AudioSmartPaController.h>
+#include <AudioALSAHardwareResourceManager.h>
+#include <SpeechDriverFactory.h>
+
+//#define SPH_SKIP_A2M_BUFF_MSG
+//Phone Call Test without buffer message transfer
+#define WAIT_VM_RECORD_ON_CNT (20)
+
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+#define MODEM_DYNAMIC_PARAM
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechDriverLAD"
+
+// refer to /alps/vendor/mediatek/proprietary/hardware/ril/libratconfig/ratconfig.c
+#define CDMA "C"
+
+
+namespace android {
+
+/*==============================================================================
+ * Const Value
+ *============================================================================*/
+static const uint16_t kSpeechOnWaitModemAckMaxTimeMs = 0; // 0: dont't wait
+static const uint16_t kSpeechOffWaitModemAckMaxTimeMs = 500;
+
+static const uint32_t kDefaultAcousticLoopbackDelayFrames = 12;
+static const uint32_t kMaxAcousticLoopbackDelayFrames = 64;
+
+/*==============================================================================
+ * Callback Function
+ *============================================================================*/
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+static void callbackAudioXmlChanged(AppHandle *appHandle, const char *audioTypeName) {
+ ALOGD("+%s(), audioType = %s", __FUNCTION__, audioTypeName);
+ bool isSpeechParamChanged = false, onlyUpdatedDuringCall = false;
+ int audioTypeUpdate = 0;
+ // reload XML file
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return;
+ }
+
+ if (appOps->appHandleReloadAudioType(appHandle, audioTypeName) == APP_ERROR) {
+ ALOGE("%s(), Reload xml fail!(audioType = %s)", __FUNCTION__, audioTypeName);
+ } else {
+ if (strcmp(audioTypeName, audioTypeNameList[AUDIO_TYPE_SPEECH]) == 0) {
+ //"Speech"
+ isSpeechParamChanged = true;
+ onlyUpdatedDuringCall = true;
+ audioTypeUpdate = (int) AUDIO_TYPE_SPEECH;
+ } else if (strcmp(audioTypeName, audioTypeNameList[AUDIO_TYPE_SPEECH_DMNR]) == 0) {
+ //"SpeechDMNR"
+ isSpeechParamChanged = true;
+ audioTypeUpdate = (int) AUDIO_TYPE_SPEECH_DMNR;
+ } else if (strcmp(audioTypeName, audioTypeNameList[AUDIO_TYPE_SPEECH_GENERAL]) == 0) {
+ //"SpeechGeneral"
+ isSpeechParamChanged = true;
+ audioTypeUpdate = (int) AUDIO_TYPE_SPEECH_GENERAL;
+ }
+ if (isSpeechParamChanged) {
+ modem_index_t currentMD = SpeechDriverFactory::GetInstance()->GetActiveModemIndex();
+ SpeechDriverLAD::GetInstance(currentMD)->updateParam(audioTypeUpdate);
+ }
+
+ }
+}
+#endif
+
+
+/*==============================================================================
+ * Singleton Pattern
+ *============================================================================*/
+
+SpeechDriverLAD *SpeechDriverLAD::mLad1 = NULL;
+SpeechDriverLAD *SpeechDriverLAD::mLad2 = NULL;
+SpeechDriverLAD *SpeechDriverLAD::mLad3 = NULL;
+
+SpeechDriverLAD *SpeechDriverLAD::GetInstance(modem_index_t modem_index) {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ SpeechDriverLAD *pLad = NULL;
+ ALOGD("%s(), modem_index=%d", __FUNCTION__, modem_index);
+
+ switch (modem_index) {
+ case MODEM_1:
+ if (mLad1 == NULL) {
+ mLad1 = new SpeechDriverLAD(modem_index);
+ }
+ pLad = mLad1;
+ break;
+ case MODEM_2:
+ if (mLad2 == NULL) {
+ mLad2 = new SpeechDriverLAD(modem_index);
+ }
+ pLad = mLad2;
+ break;
+ case MODEM_EXTERNAL:
+ if (mLad3 == NULL) {
+ mLad3 = new SpeechDriverLAD(modem_index);
+ }
+ pLad = mLad3;
+ break;
+ default:
+ ALOGE("%s: no such modem_index %d", __FUNCTION__, modem_index);
+ break;
+ }
+
+ ASSERT(pLad != NULL);
+ return pLad;
+}
+
+/*==============================================================================
+ * Constructor / Destructor / Init / Deinit
+ *============================================================================*/
+
+SpeechDriverLAD::SpeechDriverLAD(modem_index_t modem_index) {
+ ALOGD("%s(), modem_index = %d", __FUNCTION__, modem_index);
+ mModemIndex = modem_index;
+ pCCCI = NULL;
+
+ if (mModemIndex == MODEM_1 || mModemIndex == MODEM_2) {
+ ALOGD("%s(), SpeechMessengerCCCI modem_index = %d", __FUNCTION__, modem_index);
+#if defined(CCCI_FORCE_USE)
+ pCCCI = new SpeechMessengerCCCI(mModemIndex, this);
+#else
+ pCCCI = new SpeechMessengerECCCI(mModemIndex, this);
+#endif
+ } else if (mModemIndex == MODEM_EXTERNAL) {
+#if defined(AUDIO_C2K_SUPPORT)
+ char isC2kSupported[PROPERTY_VALUE_MAX];
+ property_get("ro.boot.opt_ps1_rat", isC2kSupported, "0"); //"0": default not support
+
+ if (strstr(isC2kSupported, CDMA) != NULL) {
+ ALOGD("%s(), isC2kSupported = %s", __FUNCTION__, isC2kSupported);
+
+ pCCCI = new SpeechMessengerEVDO(mModemIndex, this);
+ } else {
+ pCCCI = new SpeechMessengerECCCI(mModemIndex, this);
+
+ }
+#elif !defined(CCCI_FORCE_USE)
+ ALOGE("%s(), AUDIO_C2K_SUPPORT/CCCI_FORCE_USE is not defined!!!", __FUNCTION__);
+ pCCCI = new SpeechMessengerECCCI(mModemIndex, this);
+
+#endif
+ }
+
+ if (pCCCI == NULL) {
+ ALOGE("%s(), pCCCI == NULL!!!", __FUNCTION__);
+ ASSERT(pCCCI != NULL);
+ } else {
+ status_t ret = pCCCI->Initial();
+
+ if (ret == NO_ERROR) {
+ RecoverModemSideStatusToInitState();
+ }
+ }
+ // Speech mode
+ mSpeechMode = SPEECH_MODE_NORMAL;
+
+ // Record capability
+ mRecordSampleRateType = RECORD_SAMPLE_RATE_08K;
+ mRecordChannelType = RECORD_CHANNEL_MONO;
+ mRecordType.direction = RECORD_TYPE_UL;
+ mRecordType.dlPosition= RECORD_POS_DL_END;
+ mVolumeIndex = 0x3;
+
+ mUseBtCodec = 1;
+
+ // BT Headset NREC
+ mBtHeadsetNrecOn = SpeechEnhancementController::GetInstance()->GetBtHeadsetNrecOn();
+
+ // loopback delay frames (1 frame = 20 ms)
+ mAcousticLoopbackDelayFrames = kDefaultAcousticLoopbackDelayFrames;
+ mIsLpbk = false;
+
+ // RTT
+ mRttMode = 0;
+
+#if defined(MODEM_DYNAMIC_PARAM)
+ SpeechParamParser::getInstance();
+#endif
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ AppHandle *mAppHandle;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return;
+ }
+
+ /* Init AppHandle */
+ ALOGD("%s() appHandleGetInstance", __FUNCTION__);
+ mAppHandle = appOps->appHandleGetInstance();
+ ALOGD("%s() appHandleRegXmlChangedCb", __FUNCTION__);
+
+ /* XML changed callback process */
+ appOps->appHandleRegXmlChangedCb(mAppHandle, callbackAudioXmlChanged);
+#endif
+
+}
+
+
+SpeechDriverLAD::~SpeechDriverLAD() {
+ pCCCI->Deinitial();
+ delete pCCCI;
+}
+
+/*==============================================================================
+ * Speech Control
+ *============================================================================*/
+speech_mode_t SpeechDriverLAD::GetSpeechModeByOutputDevice(const audio_devices_t output_device) {
+ speech_mode_t speech_mode = SPEECH_MODE_NORMAL;
+ if (audio_is_bluetooth_sco_device(output_device)) {
+#if !defined(MODEM_DYNAMIC_PARAM)
+ if (mBtHeadsetNrecOn == true) {
+ speech_mode = SPEECH_MODE_BT_EARPHONE;
+ } else {
+ speech_mode = SPEECH_MODE_BT_CARKIT;
+ }
+#else
+ speech_mode = SPEECH_MODE_BT_EARPHONE;
+#endif
+ } else if (output_device == AUDIO_DEVICE_OUT_SPEAKER) {
+ speech_mode = SPEECH_MODE_LOUD_SPEAKER;
+#if defined(MODEM_DYNAMIC_PARAM) && (defined(MTK_INCALL_HANDSFREE_DMNR) || defined(MTK_MAGICONFERENCE_SUPPORT))
+ if (AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport() >= 2 &&
+ SpeechEnhancementController::GetInstance()->GetMagicConferenceCallOn() == true) {
+ speech_mode = SPEECH_MODE_MAGIC_CON_CALL;
+ }
+#endif
+ } else if (output_device == AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+ speech_mode = SPEECH_MODE_EARPHONE;
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ SpeechParamParser::getInstance()->SetParamInfo(String8("ParamHeadsetPole=4;"));
+#endif
+ } else if (output_device == AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+ speech_mode = SPEECH_MODE_EARPHONE;
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ SpeechParamParser::getInstance()->SetParamInfo(String8("ParamHeadsetPole=3;"));
+#endif
+ }
+#if defined(MTK_USB_PHONECALL)
+ else if (output_device == AUDIO_DEVICE_OUT_USB_DEVICE) {
+ speech_mode = SPEECH_MODE_USB_AUDIO;
+ }
+#endif
+ else if (output_device == AUDIO_DEVICE_OUT_EARPIECE) {
+#if defined(MTK_HAC_SUPPORT)
+ if (SpeechEnhancementController::GetInstance()->GetHACOn() == true) {
+ speech_mode = SPEECH_MODE_HAC;
+ } else
+#endif
+ {
+ speech_mode = SPEECH_MODE_NORMAL;
+ }
+ }
+
+ return speech_mode;
+}
+
+status_t SpeechDriverLAD::SetSpeechMode(const audio_devices_t input_device, const audio_devices_t output_device) {
+#if defined(SPH_SKIP_A2M_BUFF_MSG)
+ return NO_ERROR;
+#endif
+ speech_mode_t speech_mode = GetSpeechModeByOutputDevice(output_device);
+ ALOGD("%s(), input_device = 0x%x, output_device = 0x%x, speech_mode = %d", __FUNCTION__, input_device, output_device, speech_mode);
+
+ // AP side have to set speech mode before speech/record/loopback on,
+ // hence we check whether modem side get all necessary speech enhancement parameters here
+ // if not, re-send it !!
+ if (pCCCI->CheckSpeechParamAckAllArrival() == false) {
+ ALOGW("%s(), Do SetAllSpeechEnhancementInfoToModem() done. Start set speech_mode = %d", __FUNCTION__, speech_mode);
+ }
+
+ mSpeechMode = speech_mode;
+
+ // set a unreasonable gain value s.t. the reasonable gain can be set to modem next time
+ mDownlinkGain = kUnreasonableGainValue;
+ mUplinkGain = kUnreasonableGainValue;
+ mSideToneGain = kUnreasonableGainValue;
+
+#if defined(SPH_BT_DELAYTIME_SUPPORT)
+ if (speech_mode == SPEECH_MODE_BT_EARPHONE) {
+ const char *btDeviceName = AudioALSAStreamManager::getInstance()->GetBtHeadsetName();
+ int btDelayMs = SpeechParamParser::getInstance()->GetBtDelayTime(btDeviceName);
+ ALOGD("%s(), btDeviceName = %s, btDelayMs=%d", __FUNCTION__, btDeviceName, btDelayMs);
+ pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SET_BT_DELAY_TIME, (uint16_t)btDelayMs, 0));
+ }
+#endif
+
+#if defined(MODEM_DYNAMIC_PARAM)
+
+#if defined(MTK_AUDIO_SPH_LPBK_PARAM)
+ if (mIsLpbk) {
+ SpeechParamParser::getInstance()->SetParamInfo(String8("ParamSphLpbk=1;"));
+ }
+#endif
+
+ int param_arg[4];
+ param_arg[0] = (int) mSpeechMode;
+ param_arg[1] = mVolumeIndex;
+ param_arg[2] = mBtHeadsetNrecOn;
+ param_arg[3] = 0;//bit 0: customized profile, bit 1: single band, bit 4~7: band number
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH, param_arg);
+
+ return NO_ERROR;
+#else
+
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SET_SPH_MODE, speech_mode, 0));
+#endif
+}
+
+status_t SpeechDriverLAD::setMDVolumeIndex(int stream, int device, int index) {
+ bool bSpeechStatus = GetApSideModemStatus(SPEECH_STATUS_MASK);
+ ALOGD("+%s() stream= %d, device = 0x%x, index =%d, bSpeechStatus=%d", __FUNCTION__, stream, device, index, bSpeechStatus);
+ //Android M Voice volume index: available index 1~7, 0 for mute
+ //Android L Voice volume index: available index 0~6
+ if (index <= 0) {
+ return NO_ERROR;
+ } else {
+ mVolumeIndex = index - 1;
+ }
+ // set a unreasonable gain value s.t. the reasonable gain can be set to modem next time
+#if defined(MODEM_DYNAMIC_PARAM)
+ if (bSpeechStatus) {
+ int param_arg[4];
+ param_arg[0] = (int) mSpeechMode;
+ param_arg[1] = mVolumeIndex;
+ param_arg[2] = mBtHeadsetNrecOn;
+ param_arg[3] = 0;//bit 0: customized profile, bit 1: single band, bit 4~7: band number
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH, param_arg);
+ } else {
+ ALOGD("%s() bSpeechStatus=%d, only update index(%d)", __FUNCTION__, bSpeechStatus, index);
+
+ }
+#endif
+ return NO_ERROR;
+
+}
+
+status_t SpeechDriverLAD::SpeechOn() {
+ ALOGD("%s()", __FUNCTION__);
+ CheckApSideModemStatusAllOffOrDie();
+ SetApSideModemStatus(SPEECH_STATUS_MASK);
+
+ // Check if Modem reset re-send parameter here
+ if (pCCCI->WasModemReset() == true) {
+ ALOGD("%s modem was reset, send speech param now", __FUNCTION__);
+ SetAllSpeechEnhancementInfoToModem();
+ pCCCI->ResetWasModemReset(false);
+ } else {
+#if defined(MODEM_DYNAMIC_PARAM)
+ int param_arg[2];
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH_GENERAL, param_arg);
+#if defined(MTK_SPH_MAGICLARITY_SHAPEFIR_SUPPORT)
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH_MAGICLARITY, param_arg);
+#endif
+
+ if (AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport() >= 2) {
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH_DMNR, param_arg);
+ }
+
+#if defined(MTK_USB_PHONECALL)
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH_ECHOREF, param_arg);
+#endif
+#endif
+
+ }
+ status_t retval = pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SPH_ON, RAT_2G_MODE, 0));
+
+ if (retval == NO_ERROR) { // In queue or had sent to modem side => wait ack
+ WaitUntilSignaledOrTimeout(kSpeechOnWaitModemAckMaxTimeMs);
+ }
+ // Clean gain value and mute status
+ CleanGainValueAndMuteStatus();
+
+ return retval;
+}
+
+status_t SpeechDriverLAD::SpeechOff() {
+ ALOGD("%s()", __FUNCTION__);
+
+ ResetApSideModemStatus(SPEECH_STATUS_MASK);
+ CheckApSideModemStatusAllOffOrDie();
+
+ status_t retval = pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SPH_OFF, 0, 0));
+
+ if (retval == NO_ERROR) { // In queue or had sent to modem side => wait ack
+ WaitUntilSignaledOrTimeout(kSpeechOffWaitModemAckMaxTimeMs);
+ }
+ // mVolumeIndex = 0x3;
+
+ return retval;
+}
+
+status_t SpeechDriverLAD::VideoTelephonyOn() {
+ ALOGD("%s()", __FUNCTION__);
+
+ CheckApSideModemStatusAllOffOrDie();
+ SetApSideModemStatus(VT_STATUS_MASK);
+ // Check if Modem reset re-send parameter here
+ if (pCCCI->WasModemReset() == true) {
+ ALOGD("%s modem was reset, send speech param now", __FUNCTION__);
+ SetAllSpeechEnhancementInfoToModem();
+ pCCCI->ResetWasModemReset(false);
+ } else {
+#if defined(MODEM_DYNAMIC_PARAM)
+ int size_byte;
+ int param_arg[2];
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH_GENERAL, param_arg);
+#if defined(MTK_SPH_MAGICLARITY_SHAPEFIR_SUPPORT)
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH_MAGICLARITY, param_arg);
+#endif
+
+ if (AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport() >= 2) {
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH_DMNR, param_arg);
+ }
+
+#if defined(MTK_USB_PHONECALL)
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH_ECHOREF, param_arg);
+#endif
+#endif
+
+ }
+ status_t retval = pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SPH_ON, RAT_3G324M_MODE, 0));
+
+ if (retval == NO_ERROR) { // In queue or had sent to modem side => wait ack
+ WaitUntilSignaledOrTimeout(kSpeechOnWaitModemAckMaxTimeMs);
+ }
+ // Clean gain value and mute status
+ CleanGainValueAndMuteStatus();
+
+ return retval;
+}
+
+status_t SpeechDriverLAD::VideoTelephonyOff() {
+ ALOGD("%s()", __FUNCTION__);
+
+ ResetApSideModemStatus(VT_STATUS_MASK);
+ CheckApSideModemStatusAllOffOrDie();
+
+ status_t retval = pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SPH_OFF, 0, 0));
+
+ if (retval == NO_ERROR) { // In queue or had sent to modem side => wait ack
+ WaitUntilSignaledOrTimeout(kSpeechOffWaitModemAckMaxTimeMs);
+ }
+
+ return retval;
+}
+
+status_t SpeechDriverLAD::SpeechRouterOn() {
+ ALOGD("%s()", __FUNCTION__);
+
+ CheckApSideModemStatusAllOffOrDie();
+ SetApSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SPH_ROUTER_ON, true, 0));
+}
+
+status_t SpeechDriverLAD::SpeechRouterOff() {
+ ALOGD("%s()", __FUNCTION__);
+
+ ResetApSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+ CheckApSideModemStatusAllOffOrDie();
+
+ // Clean gain value and mute status
+ CleanGainValueAndMuteStatus();
+
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SPH_ROUTER_ON, false, 0));
+}
+
+
+/*==============================================================================
+ * Recording Control
+ *============================================================================*/
+
+status_t SpeechDriverLAD::recordOn() {
+ ALOGD("%s(), sample_rate = %d, channel = %d, MSG_A2M_PCM_REC_ON", __FUNCTION__, mRecordSampleRateType, mRecordChannelType);
+
+ SetApSideModemStatus(RECORD_STATUS_MASK);
+
+ // Note: the record capability is fixed in constructor
+ uint16_t param_16bit = mRecordSampleRateType | (mRecordChannelType << 4);
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_PCM_REC_ON, param_16bit, 0));
+}
+
+status_t SpeechDriverLAD::recordOn(SpcRecordTypeStruct typeRecord) {
+ ALOGD("%s(), sample_rate = %d, channel = %d, typeRecord = %d, MSG_A2M_RECORD_RAW_PCM_ON", __FUNCTION__, mRecordSampleRateType, mRecordChannelType, typeRecord.direction);
+ uint16_t param_16bit;
+
+ SetApSideModemStatus(RAW_RECORD_STATUS_MASK);
+ mRecordType = typeRecord;
+ pCCCI->setPcmRecordType(typeRecord);
+ param_16bit = mRecordSampleRateType | (mRecordChannelType << 4);
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_RECORD_RAW_PCM_ON, param_16bit, 0));
+}
+
+status_t SpeechDriverLAD::recordOff() {
+ ALOGD("%s()", __FUNCTION__);
+
+ ResetApSideModemStatus(RECORD_STATUS_MASK);
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_PCM_REC_OFF, 0, 0));
+}
+
+status_t SpeechDriverLAD::recordOff(SpcRecordTypeStruct typeRecord) {
+ ALOGD("%s(), typeRecord = %d, MSG_A2M_RECORD_RAW_PCM_OFF", __FUNCTION__, typeRecord.direction);
+
+ ResetApSideModemStatus(RAW_RECORD_STATUS_MASK);
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_RECORD_RAW_PCM_OFF, 0, 0));
+}
+
+status_t SpeechDriverLAD::SetPcmRecordType(SpcRecordTypeStruct typeRecord) {
+ ALOGD("%s(), typeRecord = %d", __FUNCTION__, typeRecord.direction);
+ pCCCI->setPcmRecordType(typeRecord);
+ return NO_ERROR;
+}
+
+status_t SpeechDriverLAD::VoiceMemoRecordOn() {
+ ALOGD("%s(), MSG_A2M_VM_REC_ON", __FUNCTION__);
+
+ SetApSideModemStatus(VM_RECORD_STATUS_MASK);
+
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_VM_REC_ON, RECORD_FORMAT_VM, 0));
+}
+
+status_t SpeechDriverLAD::VoiceMemoRecordOff() {
+ ALOGD("%s()", __FUNCTION__);
+ uint8_t i = 0;
+ while ((GetApSideModemStatus(VM_RECORD_STATUS_MASK) != true) && (i < WAIT_VM_RECORD_ON_CNT)) {
+ i++;
+ usleep(5 * 1000);
+ ALOGD("%s() wait %d ms...", __FUNCTION__, (i + 1) * 5);
+ }
+
+ ResetApSideModemStatus(VM_RECORD_STATUS_MASK);
+
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_VM_REC_OFF, 0, 0));
+}
+
+uint16_t SpeechDriverLAD::GetRecordSampleRate() const {
+ // Note: the record capability is fixed in constructor
+
+ uint16_t num_sample_rate;
+
+ switch (mRecordSampleRateType) {
+ case RECORD_SAMPLE_RATE_08K:
+ num_sample_rate = 8000;
+ break;
+ case RECORD_SAMPLE_RATE_16K:
+ num_sample_rate = 16000;
+ break;
+ case RECORD_SAMPLE_RATE_32K:
+ num_sample_rate = 32000;
+ break;
+ case RECORD_SAMPLE_RATE_48K:
+ num_sample_rate = 48000;
+ break;
+ default:
+ num_sample_rate = 8000;
+ break;
+ }
+
+ ALOGD("%s(), num_sample_rate = %u", __FUNCTION__, num_sample_rate);
+ return num_sample_rate;
+}
+
+uint16_t SpeechDriverLAD::GetRecordChannelNumber() const {
+ // Note: the record capability is fixed in constructor
+
+ uint16_t num_channel;
+
+ switch (mRecordChannelType) {
+ case RECORD_CHANNEL_MONO:
+ num_channel = 1;
+ break;
+ case RECORD_CHANNEL_STEREO:
+ num_channel = 2;
+ break;
+ default:
+ num_channel = 1;
+ break;
+ }
+
+ ALOGD("%s(), num_channel = %u", __FUNCTION__, num_channel);
+ return num_channel;
+}
+
+
+/*==============================================================================
+ * Background Sound
+ *============================================================================*/
+
+status_t SpeechDriverLAD::BGSoundOn() {
+ ALOGD("%s()", __FUNCTION__);
+ SetApSideModemStatus(BGS_STATUS_MASK);
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_BGSND_ON, 0, 0));
+}
+
+status_t SpeechDriverLAD::BGSoundConfig(uint8_t ul_gain, uint8_t dl_gain) {
+ ALOGD("%s(), ul_gain = 0x%x, dl_gain = 0x%x", __FUNCTION__, ul_gain, dl_gain);
+ uint16_t param_16bit = (ul_gain << 8) | dl_gain;
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_BGSND_CONFIG, param_16bit, 0));
+}
+
+status_t SpeechDriverLAD::BGSoundOff() {
+ ALOGD("%s()", __FUNCTION__);
+ ResetApSideModemStatus(BGS_STATUS_MASK);
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_BGSND_OFF, 0, 0));
+}
+
+/*==============================================================================
+ * PCM 2 Way
+ *============================================================================*/
+
+status_t SpeechDriverLAD::PCM2WayOn(const bool wideband_on) {
+ mPCM2WayState = (SPC_PNW_MSG_BUFFER_SPK | SPC_PNW_MSG_BUFFER_MIC | (wideband_on << 4));
+ ALOGD("%s(), mPCM2WayState = 0x%x", __FUNCTION__, mPCM2WayState);
+ SetApSideModemStatus(P2W_STATUS_MASK);
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_PNW_ON, mPCM2WayState, 0));
+}
+
+status_t SpeechDriverLAD::PCM2WayOff() {
+ mPCM2WayState = 0;
+ ALOGD("%s(), mPCM2WayState = 0x%x", __FUNCTION__, mPCM2WayState);
+ ResetApSideModemStatus(P2W_STATUS_MASK);
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_PNW_OFF, 0, 0));
+}
+
+
+/*==============================================================================
+ * TTY-CTM Control
+ *============================================================================*/
+status_t SpeechDriverLAD::TtyCtmOn() {
+ ALOGD("%s(), mTtyMode = %d", __FUNCTION__, mTtyMode);
+ status_t retval;
+ const bool uplink_mute_on_copy = mUplinkMuteOn;
+ SetUplinkMute(true);
+ SetApSideModemStatus(TTY_STATUS_MASK);
+ SpeechVMRecorder *pSpeechVMRecorder = SpeechVMRecorder::getInstance();
+ TtyCtmDebugOn(pSpeechVMRecorder->getVmConfig() == SPEECH_VM_CTM4WAY);
+ retval = pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_CTM_ON, mTtyMode, 0));
+ SetUplinkMute(uplink_mute_on_copy);
+ return retval;
+}
+
+status_t SpeechDriverLAD::TtyCtmOff() {
+ ALOGD("%s()", __FUNCTION__);
+ char paramTtyInfo[50] = {0};
+ mTtyMode = AUD_TTY_OFF;
+ ResetApSideModemStatus(TTY_STATUS_MASK);
+ TtyCtmDebugOn(false);
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ snprintf(paramTtyInfo, sizeof(paramTtyInfo), "ParamSphTty=%d;", mTtyMode);
+ SpeechParamParser::getInstance()->SetParamInfo(String8(paramTtyInfo));
+#endif
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_CTM_OFF, 0, 0));
+}
+
+status_t SpeechDriverLAD::TtyCtmDebugOn(bool tty_debug_flag) {
+ ALOGD("%s(), tty_debug_flag = %d", __FUNCTION__, tty_debug_flag);
+ SpeechVMRecorder *pSpeechVMRecorder = SpeechVMRecorder::getInstance();
+ if (tty_debug_flag) {
+ pSpeechVMRecorder->startCtmDebug();
+ } else {
+ pSpeechVMRecorder->stopCtmDebug();
+ }
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_CTM_DUMP_DEBUG_FILE, tty_debug_flag, 0));
+}
+
+int SpeechDriverLAD::setTtyMode(const TtyModeType ttyMode) {
+ ALOGD("%s(), ttyMode = %d, old mTtyMode = %d", __FUNCTION__, ttyMode, mTtyMode);
+
+ if (ttyMode == mTtyMode) { return 0; }
+ mTtyMode = ttyMode;
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ char paramTtyInfo[50] = {0};
+ snprintf(paramTtyInfo, sizeof(paramTtyInfo), "ParamSphTty=%d;", mTtyMode);
+ SpeechParamParser::getInstance()->SetParamInfo(String8(paramTtyInfo));
+#endif
+ return 0;
+}
+
+/*==============================================================================
+ * RTT
+ *============================================================================*/
+int SpeechDriverLAD::RttConfig(int rttMode) {
+ ALOGD("%s(), rttMode = %d, old mRttMode = %d", __FUNCTION__, rttMode, mRttMode);
+ if (rttMode == mRttMode) { return NO_ERROR; }
+ mRttMode = rttMode;
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_RTT_CONFIG, (uint16_t)mRttMode, 0));
+}
+
+/*==============================================================================
+ * Modem Audio DVT and Debug
+ *============================================================================*/
+
+status_t SpeechDriverLAD::SetModemLoopbackPoint(uint16_t loopback_point) {
+ ALOGD("%s(), loopback_point = %d", __FUNCTION__, loopback_point);
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SET_LPBK_POINT_DVT, loopback_point, 0));
+}
+
+/*==============================================================================
+ * Speech Encryption
+ *============================================================================*/
+
+//Speech Encryption Type: 0: disable, 1: Hard bit Encryption, 2: Pcm Data Encryption
+status_t SpeechDriverLAD::SetEncryption(bool encryption_on) {
+#if defined (SPH_SKIP_A2M_BUFF_MSG)
+ return NO_ERROR;
+#endif
+ uint16_t encryptionType = 0;
+
+#if defined(MTK_SPEECH_ENCRYPTION_PCM)
+ encryptionType = (encryption_on == true) ? 2 : 0;
+#else
+ encryptionType = (encryption_on == true) ? 1 : 0;
+#endif
+
+ ALOGD("%s(), encryption_on = %d", __FUNCTION__, encryption_on);
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SPH_ENCRYPTION, encryptionType, 0));
+}
+
+/*==============================================================================
+ * Acoustic Loopback
+ *============================================================================*/
+
+status_t SpeechDriverLAD::SetAcousticLoopback(bool loopback_on) {
+#if defined(SPH_SKIP_A2M_BUFF_MSG)
+ return NO_ERROR;
+#endif
+ ALOGD("%s(), loopback_on = %d, mAcousticLoopbackDelayFrames=%d", __FUNCTION__, loopback_on, mAcousticLoopbackDelayFrames);
+
+ if (loopback_on == true) {
+ CheckApSideModemStatusAllOffOrDie();
+ SetApSideModemStatus(LOOPBACK_STATUS_MASK);
+ // Check if Modem reset re-send parameter here
+ if (pCCCI->WasModemReset() == true) {
+ ALOGD("%s modem was reset, send speech param now", __FUNCTION__);
+ SetAllSpeechEnhancementInfoToModem();
+ pCCCI->ResetWasModemReset(false);
+ } else {
+#if defined(MODEM_DYNAMIC_PARAM)
+ int param_arg[2];
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH_GENERAL, param_arg);
+#if defined(MTK_SPH_MAGICLARITY_SHAPEFIR_SUPPORT)
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH_MAGICLARITY, param_arg);
+#endif
+
+ if (AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport() >= 2) {
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH_DMNR, param_arg);
+ }
+
+#if defined(MTK_USB_PHONECALL)
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH_ECHOREF, param_arg);
+#endif
+#endif
+ }
+ // Clean gain value and mute status
+ CleanGainValueAndMuteStatus();
+
+ } else {
+ ResetApSideModemStatus(LOOPBACK_STATUS_MASK);
+ CheckApSideModemStatusAllOffOrDie();
+
+ mUseBtCodec = 1;
+#if defined(MODEM_DYNAMIC_PARAM)&&defined(MTK_AUDIO_SPH_LPBK_PARAM)
+ SpeechParamParser::getInstance()->SetParamInfo(String8("ParamSphLpbk=0;"));
+#endif
+ }
+
+ const bool use_loopback_delay_control = true;
+ bool disable_btcodec = !mUseBtCodec;
+ int16_t param16 = (use_loopback_delay_control << 2) | (disable_btcodec << 1) | loopback_on;
+ status_t retval = pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SET_ACOUSTIC_LOOPBACK, param16, mAcousticLoopbackDelayFrames));
+
+ if (retval == NO_ERROR) { // In queue or had sent to modem side => wait ack
+ WaitUntilSignaledOrTimeout(loopback_on == true ?
+ kSpeechOnWaitModemAckMaxTimeMs :
+ kSpeechOffWaitModemAckMaxTimeMs);
+ }
+
+ return retval;
+}
+
+status_t SpeechDriverLAD::SetAcousticLoopbackBtCodec(bool enable_codec) {
+ mUseBtCodec = enable_codec;
+ return NO_ERROR;
+}
+
+status_t SpeechDriverLAD::SetAcousticLoopbackDelayFrames(int32_t delay_frames) {
+#if defined(SPH_SKIP_A2M_BUFF_MSG)
+ return NO_ERROR;
+#endif
+ ALOGD("%s(), delay_frames = %d", __FUNCTION__, delay_frames);
+
+ if (delay_frames < 0) {
+ ALOGE("%s(), delay_frames(%d) must >= 0 !! Set 0 instead.", __FUNCTION__, delay_frames);
+ delay_frames = 0;
+ } else if ((uint32_t)delay_frames > kMaxAcousticLoopbackDelayFrames) {
+ ALOGE("%s(), delay_frames(%d) must <= %d !! Set %d instead.", __FUNCTION__, delay_frames, kMaxAcousticLoopbackDelayFrames, kMaxAcousticLoopbackDelayFrames);
+ delay_frames = kMaxAcousticLoopbackDelayFrames;
+ }
+
+ mAcousticLoopbackDelayFrames = delay_frames;
+
+ if (GetApSideModemStatus(LOOPBACK_STATUS_MASK) == true) {
+ ALOGW("Loopback is enabled now! The new delay_frames will be applied next time.");
+ }
+
+ return NO_ERROR;
+}
+
+status_t SpeechDriverLAD::setLpbkFlag(bool enableLpbk) {
+ AL_AUTOLOCK(mLock);
+ ALOGD("%s(), enableLpbk = %d, old mIsLpbk = %d", __FUNCTION__, enableLpbk, mIsLpbk);
+ if (enableLpbk == mIsLpbk) { return NO_ERROR; }
+ mIsLpbk = enableLpbk;
+ return NO_ERROR;
+}
+
+/*==============================================================================
+ * Volume Control
+ *============================================================================*/
+
+//param gain: data range is 0~0xFF00, which is mapping to 0dB to -64dB. The effective interval is 0.25dB by data increasing/decreasing 1.
+status_t SpeechDriverLAD::SetDownlinkGain(int16_t gain) {
+ ALOGD("%s(), gain = 0x%x, old mDownlinkGain = 0x%x", __FUNCTION__, gain, mDownlinkGain);
+ if (gain == mDownlinkGain) { return NO_ERROR; }
+
+ mDownlinkGain = gain;
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SPH_DL_DIGIT_VOLUME, gain, 0));
+}
+
+status_t SpeechDriverLAD::SetEnh1DownlinkGain(int16_t gain) {
+ ALOGD("%s(), gain = 0x%x, old SetEnh1DownlinkGain = 0x%x", __FUNCTION__, gain, mDownlinkenh1Gain);
+ if (gain == mDownlinkenh1Gain) { return NO_ERROR; }
+
+ mDownlinkenh1Gain = gain;
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SPH_DL_ENH_REF_DIGIT_VOLUME, gain, 0));
+}
+
+//param gain: data range is 0~120, which is mapping to 0dB to 30dB. The effective interval is 1dB by data increasing/decreasing 4.
+status_t SpeechDriverLAD::SetUplinkGain(int16_t gain) {
+ ALOGD("%s(), gain = 0x%x, old mUplinkGain = 0x%x", __FUNCTION__, gain, mUplinkGain);
+ if (gain == mUplinkGain) { return NO_ERROR; }
+
+ mUplinkGain = gain;
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SPH_UL_DIGIT_VOLUME, gain, 0));
+}
+
+status_t SpeechDriverLAD::SetDownlinkMute(bool mute_on) {
+ AL_AUTOLOCK(mLock);
+ ALOGD("%s(), mute_on = %d, old mDownlinkMuteOn = %d", __FUNCTION__, mute_on, mDownlinkMuteOn);
+ if (mute_on == mDownlinkMuteOn) { return NO_ERROR; }
+
+ mDownlinkMuteOn = mute_on;
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_MUTE_SPH_DL, mute_on, 0));
+}
+
+status_t SpeechDriverLAD::SetDownlinkMuteCodec(bool mute_on) {
+ AL_AUTOLOCK(mLock);
+ ALOGD("%s(), mute_on = %d, old mDownlinkMuteOn = %d", __FUNCTION__, mute_on, mDownlinkMuteOn);
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_MUTE_SPH_DL_CODEC, mute_on, 0));
+}
+
+status_t SpeechDriverLAD::SetUplinkMute(bool mute_on) {
+ AL_AUTOLOCK(mLock);
+ ALOGD("%s(), mute_on = %d, old mUplinkMuteOn = %d", __FUNCTION__, mute_on, mUplinkMuteOn);
+
+ mUplinkMuteOn = mute_on;
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_MUTE_SPH_UL, mute_on, 0));
+}
+
+status_t SpeechDriverLAD::SetUplinkSourceMute(bool mute_on) {
+ AL_AUTOLOCK(mLock);
+ ALOGD("%s(), mute_on = %d, old mUplinkSourceMuteOn = %d", __FUNCTION__, mute_on, mUplinkSourceMuteOn);
+ if (mute_on == mUplinkSourceMuteOn) { return NO_ERROR; }
+
+ mUplinkSourceMuteOn = mute_on;
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_MUTE_SPH_UL_SOURCE, mute_on, 0));
+}
+
+status_t SpeechDriverLAD::SetSidetoneGain(int16_t gain) {
+ ALOGD("%s(), gain = 0x%x, old mSideToneGain = 0x%x", __FUNCTION__, gain, mSideToneGain);
+ if (gain == mSideToneGain) { return NO_ERROR; }
+
+ mSideToneGain = gain;
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SIDETONE_VOLUME, gain, 0));
+}
+
+
+status_t SpeechDriverLAD::SetDSPSidetoneFilter(const bool dsp_stf_on) {
+ ALOGD("%s(), dsp_stf_on = %d", __FUNCTION__, dsp_stf_on);
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SIDETONE_CONFIG, dsp_stf_on, 0));
+}
+
+
+/*==============================================================================
+ * Device related Config
+ *============================================================================*/
+
+status_t SpeechDriverLAD::SetModemSideSamplingRate(uint16_t sample_rate) {
+ ALOGD("%s(), sample_rate = %d", __FUNCTION__, sample_rate);
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SET_SAMPLE_RATE, sample_rate, 0));
+}
+
+/*==============================================================================
+ * Speech Enhancement Control
+ *============================================================================*/
+status_t SpeechDriverLAD::SetSpeechEnhancement(bool enhance_on) {
+#if defined(SPH_SKIP_A2M_BUFF_MSG)
+ return NO_ERROR;
+#endif
+ ALOGD("%s(), enhance_on = %d, mForceDisableSpeechEnhancement = %d", __FUNCTION__, enhance_on, mForceDisableSpeechEnhancement);
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_CTRL_SPH_ENH, enhance_on & !mForceDisableSpeechEnhancement, 0));
+}
+
+status_t SpeechDriverLAD::SetSpeechEnhancementMask(const sph_enh_mask_struct_t &mask) {
+#if defined(SPH_SKIP_A2M_BUFF_MSG)
+ return NO_ERROR;
+#endif
+ ALOGD("%s(), main_func = 0x%x, dynamic_func = 0x%x", __FUNCTION__, mask.main_func, mask.dynamic_func);
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_CONFIG_SPH_ENH, mask.main_func, mask.dynamic_func));
+}
+
+status_t SpeechDriverLAD::SetBtHeadsetNrecOn(const bool bt_headset_nrec_on) {
+#if defined(SPH_SKIP_A2M_BUFF_MSG)
+ return NO_ERROR;
+#endif
+ ALOGD("%s(), bt_headset_nrec_on = %d, mSpeechMode = %d", __FUNCTION__, bt_headset_nrec_on, mSpeechMode);
+ mBtHeadsetNrecOn = bt_headset_nrec_on;
+
+ return NO_ERROR;
+}
+
+
+/*==============================================================================
+ * Speech Enhancement Parameters
+ *============================================================================*/
+status_t SpeechDriverLAD::SetDynamicSpeechParameters(const int type, const void *param_arg) {
+#if defined(SPH_SKIP_A2M_BUFF_MSG)
+ return NO_ERROR;
+#endif
+
+ int u4I, size_byte;
+ char *pPackedSphParamUnit = new char [CCCI_MAX_PAYLOAD_DATA_BYTE];
+ ALOGD("+%s(), type[%d]", __FUNCTION__, type);
+ int *u4ParamArg = (int *)param_arg;
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ switch (type) {
+ case AUDIO_TYPE_SPEECH:
+ memset(pPackedSphParamUnit, 0, CCCI_MAX_PAYLOAD_DATA_BYTE);
+#if defined(SINGLE_VOICE_BAND_SPEECH_TRANSFER)
+
+ u4ParamArg[3] = u4ParamArg[3] | 0x2; //bit 1: single band, bit 4~7: band number NB
+ size_byte = SpeechParamParser::getInstance()->GetSpeechParamUnit(pPackedSphParamUnit, u4ParamArg);
+ SetVariousKindsOfSpeechParameters(pPackedSphParamUnit, size_byte, MSG_A2M_EM_DYNAMIC_SPH);
+
+ u4ParamArg[3] = u4ParamArg[3] | 0x10; //bit 1: single band, bit 4~7: band number WB
+ memset(pPackedSphParamUnit, 0, CCCI_MAX_PAYLOAD_DATA_BYTE);
+ size_byte = SpeechParamParser::getInstance()->GetSpeechParamUnit(pPackedSphParamUnit, u4ParamArg);
+ SetVariousKindsOfSpeechParameters(pPackedSphParamUnit, size_byte, MSG_A2M_EM_DYNAMIC_SPH);
+#else
+ size_byte = SpeechParamParser::getInstance()->GetSpeechParamUnit(pPackedSphParamUnit, u4ParamArg);
+ SetVariousKindsOfSpeechParameters(pPackedSphParamUnit, size_byte, MSG_A2M_EM_DYNAMIC_SPH);
+
+#endif
+ break;
+ case AUDIO_TYPE_SPEECH_DMNR:
+ memset(pPackedSphParamUnit, 0, CCCI_MAX_PAYLOAD_DATA_BYTE);
+ //return array with size
+ size_byte = SpeechParamParser::getInstance()->GetDmnrParamUnit(pPackedSphParamUnit);
+
+#if 0
+ for (u4I = 0; u4I<size_byte >> 1; u4I++) {
+ ALOGV("%s(), DMNR pPackedSphParamUnit[%d] = 0x%x", __FUNCTION__, u4I, *((uint16_t *)pPackedSphParamUnit + u4I));
+ }
+#endif
+ SetVariousKindsOfSpeechParameters(pPackedSphParamUnit, size_byte, MSG_A2M_EM_DYNAMIC_SPH);
+ break;
+ case AUDIO_TYPE_SPEECH_GENERAL:
+ memset(pPackedSphParamUnit, 0, CCCI_MAX_PAYLOAD_DATA_BYTE);
+ //return array with size
+ size_byte = SpeechParamParser::getInstance()->GetGeneralParamUnit(pPackedSphParamUnit);
+
+#if 0
+ for (u4I = 0; u4I<size_byte >> 1; u4I++) {
+ ALOGV("%s(), General pPackedSphParamUnit[%d] = 0x%x", __FUNCTION__, u4I, *((uint16_t *)pPackedSphParamUnit + u4I));
+ }
+#endif
+ SetVariousKindsOfSpeechParameters(pPackedSphParamUnit, size_byte, MSG_A2M_EM_DYNAMIC_SPH);
+ break;
+ case AUDIO_TYPE_SPEECH_MAGICLARITY:
+ memset(pPackedSphParamUnit, 0, CCCI_MAX_PAYLOAD_DATA_BYTE);
+ //return array with size
+ size_byte = SpeechParamParser::getInstance()->GetMagiClarityParamUnit(pPackedSphParamUnit);
+#if 0
+ for (u4I = 0; u4I<size_byte >> 1; u4I++) {
+ ALOGV("%s(), MagiClairity pPackedSphParamUnit[%d] = 0x%x", __FUNCTION__, u4I, *((uint16_t *)pPackedSphParamUnit + u4I));
+ }
+#endif
+ SetVariousKindsOfSpeechParameters(pPackedSphParamUnit, size_byte, MSG_A2M_EM_DYNAMIC_SPH);
+ break;
+ case AUDIO_TYPE_SPEECH_ECHOREF:
+ memset(pPackedSphParamUnit, 0, 2048);
+ //return array with size
+ size_byte = SpeechParamParser::getInstance()->GetEchoRefParamUnit(pPackedSphParamUnit);
+ SetVariousKindsOfSpeechParameters(pPackedSphParamUnit, size_byte, MSG_A2M_EM_DYNAMIC_SPH);
+ break;
+ default:
+ break;
+
+ }
+#endif
+ if (pPackedSphParamUnit != NULL) {
+ delete[] pPackedSphParamUnit;
+ }
+ return NO_ERROR;
+
+}
+
+#if defined(MODEM_DYNAMIC_PARAM) && (USE_CCCI_SHARE_BUFFER)
+status_t SpeechDriverLAD::SetVariousKindsOfSpeechParameters(const void *param, const uint16_t data_length, const uint16_t ccci_message_id) {
+#if defined(SPH_SKIP_A2M_BUFF_MSG)
+ return NO_ERROR;
+#endif
+ if (ccci_message_id != MSG_A2M_EM_DYNAMIC_SPH) {
+ ALOGE("%s(), only support Speech Dynamic Parameters", __FUNCTION__);
+ return NO_ERROR;
+ }
+ if (pCCCI->GetMDResetFlag() == false) { // check MD Reset Flag
+ {
+ // get share buffer address
+ uint16_t offset;
+ uint16_t avail;
+ char *addr;
+ uint32_t trycnt = 0;
+ const uint32_t kMaxTryCnt = 30; // total 3 sec
+ do {
+ pCCCI->GetA2MRawParaRingBuffer(&offset, &avail);
+ if (avail >= (data_length + CCCI_SHARE_BUFF_HEADER_LEN)) {
+ break;
+ } else {
+ usleep(100 * 1000);
+ trycnt ++;
+ if (trycnt >= kMaxTryCnt) {break;}
+ }
+ } while (1);
+
+ if (avail < (data_length + CCCI_SHARE_BUFF_HEADER_LEN)) {
+ ALOGE("%s() fail due to unable get buffer space ccci_message_id = 0x%x, avail %d, need %d",
+ __FUNCTION__, ccci_message_id, avail, data_length + (uint16_t)CCCI_SHARE_BUFF_HEADER_LEN);
+ return UNKNOWN_ERROR;
+ }
+
+ share_buff_data_type_t type = SHARE_BUFF_DATA_TYPE_CCCI_DYNAMIC_PARAM_TYPE;
+
+ ALOGD("%s() type = %d, ccci_message_id = 0x%x", __FUNCTION__, type, ccci_message_id);
+
+ // fill header info
+ uint16_t temp[3];
+ pCCCI->SetShareBufHeader((uint16_t *) temp,
+ CCCI_A2M_SHARE_BUFF_HEADER_SYNC,
+ type,
+ data_length);
+
+ // write header to Ring buffer
+ pCCCI->WriteA2MRawParaRingBuffer((char *) temp, CCCI_SHARE_BUFF_HEADER_LEN);
+
+ // fill speech enhancement parameter
+ pCCCI->WriteA2MRawParaRingBuffer((char *) param, data_length);
+
+ // send data notify to modem side
+ const uint16_t payload_length = CCCI_SHARE_BUFF_HEADER_LEN + data_length;
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(ccci_message_id, payload_length, (uint32_t)offset));
+ }
+ } else {
+
+ ALOGD("%s(), SKIP Speech Parameters setting because MD Reset", __FUNCTION__);
+ return NO_ERROR;
+
+ }
+}
+#else
+status_t SpeechDriverLAD::SetVariousKindsOfSpeechParameters(const void *param, const uint16_t data_length, const uint16_t ccci_message_id) {
+#if defined(SPH_SKIP_A2M_BUFF_MSG)
+ return NO_ERROR;
+#endif
+ if (pCCCI->GetMDResetFlag() == false) { // check MD Reset Flag
+ if (pCCCI->A2MBufLock() == false) { // get buffer lock to prevent overwrite other's data
+ ALOGE("%s() fail due to unalbe get A2MBufLock, ccci_message_id = 0x%x", __FUNCTION__, ccci_message_id);
+ return TIMED_OUT;
+ } else {
+ // get share buffer address
+ uint16_t offset = A2M_SHARED_BUFFER_SPH_PARAM_BASE;
+ char *p_header_address = pCCCI->GetA2MShareBufBase() + offset;
+ char *p_data_address = p_header_address + CCCI_SHARE_BUFF_HEADER_LEN;
+ share_buff_data_type_t type = SHARE_BUFF_DATA_TYPE_CCCI_EM_PARAM;
+
+ switch (ccci_message_id) {
+#if defined(MODEM_DYNAMIC_PARAM)
+ case MSG_A2M_EM_DYNAMIC_SPH:
+ type = SHARE_BUFF_DATA_TYPE_CCCI_DYNAMIC_PARAM_TYPE;
+ break;
+
+ default:
+ type = SHARE_BUFF_DATA_TYPE_CCCI_DYNAMIC_PARAM_TYPE;
+ break;
+#else
+ case MSG_A2M_EM_MAGICON:
+ type = SHARE_BUFF_DATA_TYPE_CCCI_MAGICON_PARAM;
+ break;
+ case MSG_A2M_EM_HAC:
+ type = SHARE_BUFF_DATA_TYPE_CCCI_HAC_PARAM;
+ break;
+
+ default:
+ type = SHARE_BUFF_DATA_TYPE_CCCI_EM_PARAM;
+ break;
+#endif
+ }
+
+ ALOGD("%s() type = %d, ccci_message_id = 0x%x", __FUNCTION__, type, ccci_message_id);
+
+ // fill header info
+ pCCCI->SetShareBufHeader((uint16_t *)p_header_address,
+ CCCI_A2M_SHARE_BUFF_HEADER_SYNC,
+ type,
+ data_length);
+
+ // fill speech enhancement parameter
+ memcpy((void *)p_data_address, (void *)param, data_length);
+
+ // send data notify to modem side
+ const uint16_t payload_length = CCCI_SHARE_BUFF_HEADER_LEN + data_length;
+#if defined(MODEM_DYNAMIC_PARAM)
+ if (ccci_message_id == MSG_A2M_EM_DYNAMIC_SPH) {
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(ccci_message_id, payload_length, offset));
+ } else {
+ ALOGE("%s(), only support Speech Dynamic Parameters", __FUNCTION__);
+ pCCCI->A2MBufUnLock();
+ return NO_ERROR;
+ }
+#else
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(ccci_message_id, payload_length, offset));
+
+#endif
+
+
+ }
+ } else {
+
+ ALOGD("%s(), SKIP Speech Parameters setting because MD Reset", __FUNCTION__);
+ return NO_ERROR;
+
+ }
+}
+#endif
+
+status_t SpeechDriverLAD::SetNBSpeechParameters(const void *pSphParamNB) {
+#if defined(SPH_SKIP_A2M_BUFF_MSG)
+ return NO_ERROR;
+#endif
+ ALOGD("%s()", __FUNCTION__);
+ return SetVariousKindsOfSpeechParameters(pSphParamNB, sizeof(AUDIO_CUSTOM_PARAM_STRUCT), MSG_A2M_EM_NB);
+}
+
+status_t SpeechDriverLAD::SetDualMicSpeechParameters(const void *pSphParamDualMic) {
+ if (AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport() < 2) {
+ ALOGE("%s()", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+#if defined(SPH_SKIP_A2M_BUFF_MSG)
+ return NO_ERROR;
+#endif
+ ALOGD("%s()", __FUNCTION__);
+
+#if defined(MTK_WB_SPEECH_SUPPORT)
+ // NVRAM always contain(44+76), for WB we send full (44+76)
+ uint16_t data_length = sizeof(unsigned short) * (NUM_ABF_PARAM + NUM_ABFWB_PARAM); // NB + WB
+
+ // Check if support Loud Speaker Mode DMNR
+ if (sizeof(AUDIO_CUSTOM_EXTRA_PARAM_STRUCT) >= (data_length * 2)) {
+ data_length *= 2; // 1 for receiver mode DMNR, 1 for loud speaker mode DMNR
+ }
+#else
+ // for NB we send (44) only
+ uint16_t data_length = sizeof(unsigned short) * (NUM_ABF_PARAM); // NB Only
+#endif
+
+ return SetVariousKindsOfSpeechParameters(pSphParamDualMic, data_length, MSG_A2M_EM_DMNR);
+}
+
+status_t SpeechDriverLAD::SetMagiConSpeechParameters(const void *pSphParamMagiCon) {
+ if (AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport() < 2) {
+ ALOGE("%s()", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+#if defined(MTK_MAGICONFERENCE_SUPPORT)
+#if defined(SPH_SKIP_A2M_BUFF_MSG)
+ return NO_ERROR;
+#endif
+ ALOGD("%s()", __FUNCTION__);
+
+ uint16_t data_length = sizeof(AUDIO_CUSTOM_MAGI_CONFERENCE_STRUCT); // NB + WB
+
+ return SetVariousKindsOfSpeechParameters(pSphParamMagiCon, data_length, MSG_A2M_EM_MAGICON);
+#else
+ (void)pSphParamMagiCon;
+ ALOGE("%s()", __FUNCTION__);
+ return INVALID_OPERATION;
+#endif
+}
+
+status_t SpeechDriverLAD::SetHACSpeechParameters(const void *pSphParamHAC) {
+#if defined(MTK_HAC_SUPPORT)
+#if defined(SPH_SKIP_A2M_BUFF_MSG)
+ return NO_ERROR;
+#endif
+ AUDIO_CUSTOM_HAC_SPEECH_PARAM_STRUCT mSphParamHAC;
+ memcpy(&mSphParamHAC, pSphParamHAC, sizeof(AUDIO_CUSTOM_HAC_SPEECH_PARAM_STRUCT));
+
+ uint16_t data_length = sizeof(AUDIO_CUSTOM_HAC_SPEECH_PARAM_STRUCT); // NB + WB
+ ALOGD("%s(), data_length=%d", __FUNCTION__, data_length);
+ return SetVariousKindsOfSpeechParameters(&mSphParamHAC, data_length, MSG_A2M_EM_HAC);
+
+#else
+ ALOGE("%s()", __FUNCTION__);
+ (void)pSphParamHAC;
+ return INVALID_OPERATION;
+#endif
+}
+
+#if defined(MTK_WB_SPEECH_SUPPORT)
+status_t SpeechDriverLAD::SetWBSpeechParameters(const void *pSphParamWB) {
+#if defined(SPH_SKIP_A2M_BUFF_MSG)
+ return NO_ERROR;
+#endif
+ ALOGD("%s()", __FUNCTION__);
+ return SetVariousKindsOfSpeechParameters(pSphParamWB, sizeof(AUDIO_CUSTOM_WB_PARAM_STRUCT), MSG_A2M_EM_WB);
+}
+#else
+status_t SpeechDriverLAD::SetWBSpeechParameters(const void *pSphParamWB) {
+ ALOGE("%s()", __FUNCTION__);
+ return INVALID_OPERATION;
+}
+#endif
+
+
+status_t SpeechDriverLAD::GetVibSpkParam(void *eVibSpkParam) {
+ int32_t frequency;
+ AUDIO_ACF_CUSTOM_PARAM_STRUCT audioParam;
+ getAudioCompFltCustParam(AUDIO_COMP_FLT_VIBSPK, &audioParam);
+ PARAM_VIBSPK *pParamVibSpk = (PARAM_VIBSPK *)eVibSpkParam;
+ int dTableIndex;
+
+ if (audioParam.bes_loudness_WS_Gain_Max != VIBSPK_CALIBRATION_DONE && audioParam.bes_loudness_WS_Gain_Max != VIBSPK_SETDEFAULT_VALUE) {
+ frequency = VIBSPK_DEFAULT_FREQ;
+ } else {
+ frequency = audioParam.bes_loudness_WS_Gain_Min;
+ }
+
+ if (frequency < VIBSPK_FREQ_LOWBOUND) {
+ dTableIndex = 0;
+ } else {
+ dTableIndex = (frequency - VIBSPK_FREQ_LOWBOUND + 1) / VIBSPK_FILTER_FREQSTEP;
+ }
+
+ if (dTableIndex < VIBSPK_FILTER_NUM && dTableIndex >= 0) {
+ memcpy(pParamVibSpk->pParam, &SPH_VIBR_FILTER_COEF_Table[dTableIndex], sizeof(uint16_t)*VIBSPK_SPH_PARAM_SIZE);
+ }
+
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_2IN1_SPEAKER)) {
+ pParamVibSpk->flag2in1 = false;
+ } else {
+ pParamVibSpk->flag2in1 = true;
+ }
+
+ return NO_ERROR;
+}
+
+status_t SpeechDriverLAD::SetVibSpkParam(void *eVibSpkParam) {
+ if (pCCCI->A2MBufLock() == false) {
+ ALOGE("%s() fail due to unalbe get A2MBufLock, ccci_message_id = 0x%x", __FUNCTION__, MSG_A2M_VIBSPK_PARAMETER);
+ ALOGD("VibSpkSetSphParam Fail!");
+ return TIMED_OUT;
+ } else {
+ PARAM_VIBSPK paramVibspk;
+ uint16_t offset = A2M_SHARED_BUFFER_SPH_PARAM_BASE;
+ char *p_header_address = pCCCI->GetA2MShareBufBase() + offset;
+ char *p_data_address = p_header_address + CCCI_SHARE_BUFF_HEADER_LEN;
+ uint16_t data_length = sizeof(PARAM_VIBSPK);
+ ALOGD("VibSpkSetSphParam Success!");
+ // fill header info
+ pCCCI->SetShareBufHeader((uint16_t *)p_header_address,
+ CCCI_A2M_SHARE_BUFF_HEADER_SYNC,
+ SHARE_BUFF_DATA_TYPE_CCCI_VIBSPK_PARAM,
+ data_length);
+
+ // fill speech enhancement parameter
+ memcpy((void *)p_data_address, (void *)eVibSpkParam, data_length);
+
+ // send data notify to modem side
+ const uint16_t message_length = CCCI_SHARE_BUFF_HEADER_LEN + data_length;
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_VIBSPK_PARAMETER, message_length, offset));
+ }
+
+}
+//#endif //defined(MTK_VIBSPK_SUPPORT)
+
+typedef struct {
+ bool isFeatureOptOn;
+ short switch_and_delay; // bit8: switch; bit7~0: delay
+ short mic_index; // bit wise definition ordered from main mic to reference mic. Only one bit is set!! bit 0: o17, bit 1: o18, bit 2: o23, bit 3: o24, bit 4: o25
+} PARAM_SMARTPA;
+
+#define SMARTPA_SUPPORT_BIT 8
+#define MIC_INDEX_O17 1<<0
+#define MIC_INDEX_O18 1<<1
+#define MIC_INDEX_O23 1<<2
+#define MIC_INDEX_O24 1<<3
+#define MIC_INDEX_O25 1<<4
+#define MIC_INDEX_O26 1<<3
+#define MIC_INDEX_O27 1<<2 // due to DSP has no mic3
+
+status_t SpeechDriverLAD::GetSmartpaParam(void *eParamSmartpa __unused) {
+ PARAM_SMARTPA *pParamSmartpa = (PARAM_SMARTPA *)eParamSmartpa;;
+
+ if (AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+#if defined(FORCE_DISABLE_EXTCODEC_ECHO_REFERENCE)
+ pParamSmartpa->isFeatureOptOn = 0;
+#else
+ pParamSmartpa->isFeatureOptOn = 1;
+#endif
+
+ if (mModemIndex == MODEM_1) {
+ pParamSmartpa->mic_index = MIC_INDEX_O24;
+ } else {
+ pParamSmartpa->mic_index = MIC_INDEX_O27;
+ }
+
+ pParamSmartpa->switch_and_delay = ((pParamSmartpa->isFeatureOptOn << SMARTPA_SUPPORT_BIT) |
+ (AudioSmartPaController::getInstance()->getSmartPaDelayUs() / 1000));
+
+ ALOGD("%s, isNxpFeatureOptOn=%d, switch_and_delay=%d, mic_index=%d", __FUNCTION__,
+ pParamSmartpa->isFeatureOptOn, pParamSmartpa->switch_and_delay, pParamSmartpa->mic_index);
+ }
+ return NO_ERROR;
+}
+
+status_t SpeechDriverLAD::SetSmartpaParam(void *eParamSmartpa) {
+ if (pCCCI->A2MBufLock() == false) {
+ ALOGE("%s() fail due to unalbe get A2MBufLock, ccci_message_id = 0x%x", __FUNCTION__, MSG_A2M_SMARTPA_PARAMETER);
+ ALOGD("SmartpaSetSphParam Fail!");
+ return TIMED_OUT;
+ } else {
+ //PARAM_SMARTPA paramSmartpa;
+ uint16_t offset = A2M_SHARED_BUFFER_SPH_PARAM_BASE;
+ char *p_header_address = pCCCI->GetA2MShareBufBase() + offset;
+ char *p_data_address = p_header_address + CCCI_SHARE_BUFF_HEADER_LEN;
+ uint16_t data_length = sizeof(PARAM_SMARTPA);
+ ALOGD("SmartpaSetSphParam Success!");
+ // fill header info
+ pCCCI->SetShareBufHeader((uint16_t *)p_header_address,
+ CCCI_A2M_SHARE_BUFF_HEADER_SYNC,
+ SHARE_BUFF_DATA_TYPE_CCCI_SMARTPA_PARAM,
+ data_length);
+
+ // fill speech enhancement parameter
+ memcpy((void *)p_data_address, (void *)eParamSmartpa, data_length);
+
+ // send data notify to modem side
+ const uint16_t message_length = CCCI_SHARE_BUFF_HEADER_LEN + data_length;
+ return pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SMARTPA_PARAMETER, message_length, offset));
+ }
+
+}
+
+status_t SpeechDriverLAD::SetAllSpeechEnhancementInfoToModem() {
+ // Wait until modem ready
+ //if (pCCCI->WaitUntilModemReady() == TIMED_OUT) //entering flight mode, waste too much time waiting...
+ if (pCCCI->GetMDResetFlag() == true) {
+ ALOGD("%s() MD not ready", __FUNCTION__);
+ return NO_ERROR;
+ }
+
+ // Lock
+ static AudioLock _mutex;
+ AL_LOCK_MS(_mutex, 10000); // wait 10 sec
+
+ uint16_t speechEnhancementCore = 1;
+ pCCCI->SendMessageInQueue(pCCCI->InitCcciMailbox(MSG_A2M_SPH_ENH_CORE, speechEnhancementCore, 0));
+
+#if defined(MODEM_DYNAMIC_PARAM)
+
+ int param_arg[4];
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH_GENERAL, param_arg);
+
+#if defined(MTK_SPH_MAGICLARITY_SHAPEFIR_SUPPORT)
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH_MAGICLARITY, param_arg);
+#endif
+ if (AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport() >= 2) {
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH_DMNR, param_arg);
+ }
+#if defined(MTK_USB_PHONECALL)
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH_ECHOREF, param_arg);
+#endif
+
+ if (AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ PARAM_SMARTPA eSmartpaParam;
+ GetSmartpaParam((void *)&eSmartpaParam);
+ SetSmartpaParam((void *)&eSmartpaParam);
+ }
+
+
+#else
+ AudioCustParamClient *pAudioCustParamClient = AudioCustParamClient::GetInstance();
+
+ // NB Speech Enhancement Parameters
+ AUDIO_CUSTOM_PARAM_STRUCT eSphParamNB;
+ pAudioCustParamClient->GetNBSpeechParamFromNVRam(&eSphParamNB);
+ if (mIsLpbk == true) {
+ AUDIO_CUSTOM_SPEECH_LPBK_PARAM_STRUCT eSphParamNBLpbk;
+ pAudioCustParamClient->GetNBSpeechLpbkParamFromNVRam(&eSphParamNBLpbk);
+ //replace receiver/headset/loudspk mode parameters
+ memcpy(&eSphParamNB.speech_mode_para[0][0], &eSphParamNBLpbk, sizeof(AUDIO_CUSTOM_SPEECH_LPBK_PARAM_STRUCT));
+ }
+ SetNBSpeechParameters(&eSphParamNB);
+ ALOGD("NVRAM debug: speech_mode_para[0][0]=%d should not be zero", eSphParamNB.speech_mode_para[0][0]);
+
+ if (AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport() >= 2) {
+ // Dual Mic Speech Enhancement Parameters
+ AUDIO_CUSTOM_EXTRA_PARAM_STRUCT eSphParamDualMic;
+ pAudioCustParamClient->GetDualMicSpeechParamFromNVRam(&eSphParamDualMic);
+ SetDualMicSpeechParameters(&eSphParamDualMic);
+
+#if defined(MTK_INCALL_HANDSFREE_DMNR) ||defined(MTK_MAGICONFERENCE_SUPPORT)
+ AUDIO_CUSTOM_MAGI_CONFERENCE_STRUCT eSphParamMagiCon;
+ pAudioCustParamClient->GetMagiConSpeechParamFromNVRam(&eSphParamMagiCon);
+ SetMagiConSpeechParameters(&eSphParamMagiCon);
+#endif
+ }
+
+#if defined(MTK_HAC_SUPPORT)
+ AUDIO_CUSTOM_HAC_PARAM_STRUCT eSphParamHAC;
+ pAudioCustParamClient->GetHACSpeechParamFromNVRam(&eSphParamHAC);
+ SetHACSpeechParameters(&eSphParamHAC);
+#endif
+
+#if defined(MTK_WB_SPEECH_SUPPORT)
+ // WB Speech Enhancement Parameters
+ AUDIO_CUSTOM_WB_PARAM_STRUCT eSphParamWB;
+ pAudioCustParamClient->GetWBSpeechParamFromNVRam(&eSphParamWB);
+ SetWBSpeechParameters(&eSphParamWB);
+#endif
+ //#if defined(MTK_VIBSPK_SUPPORT)
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_VIBRATION_SPEAKER)) {
+ PARAM_VIBSPK eVibSpkParam;
+ GetVibSpkParam((void *)&eVibSpkParam);
+ SetVibSpkParam((void *)&eVibSpkParam);
+ }
+ //#endif
+
+ if (AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ PARAM_SMARTPA eSmartpaParam;
+ GetSmartpaParam((void *)&eSmartpaParam);
+ SetSmartpaParam((void *)&eSmartpaParam);
+ }
+
+#endif
+
+ // Set speech enhancement parameters' mask to modem side
+ SetSpeechEnhancementMask(SpeechEnhancementController::GetInstance()->GetSpeechEnhancementMask());
+
+ // // Use lock to ensure the previous command with share buffer control is completed
+ // if (pCCCI->A2MBufLock() == true)
+ // {
+ // pCCCI->A2MBufUnLock();
+ // }
+ // else
+ // {
+ // ALOGE("%s() fail to get A2M Buffer Lock!!", __FUNCTION__);
+ // }
+
+ // Unock
+ AL_UNLOCK(_mutex);
+ return NO_ERROR;
+}
+
+
+/*==============================================================================
+ * Recover State
+ *============================================================================*/
+
+void SpeechDriverLAD::RecoverModemSideStatusToInitState() {
+ // Record
+ if (pCCCI->GetModemSideModemStatus(RECORD_STATUS_MASK) == true) {
+ ALOGD("%s(), modem_index = %d, record_on = true", __FUNCTION__, mModemIndex);
+ SetApSideModemStatus(RECORD_STATUS_MASK);
+ recordOff();
+ }
+
+ // Raw Record
+ if (pCCCI->GetModemSideModemStatus(RAW_RECORD_STATUS_MASK) == true) {
+ ALOGD("%s(), modem_index = %d, raw_record_on = true", __FUNCTION__, mModemIndex);
+ SetApSideModemStatus(RAW_RECORD_STATUS_MASK);
+ recordOff(mRecordType);
+ }
+
+ // VM Record
+ if (pCCCI->GetModemSideModemStatus(VM_RECORD_STATUS_MASK) == true) {
+ ALOGD("%s(), modem_index = %d, vm_on = true", __FUNCTION__, mModemIndex);
+ SetApSideModemStatus(VM_RECORD_STATUS_MASK);
+ VoiceMemoRecordOff();
+ }
+
+ // BGS
+ if (pCCCI->GetModemSideModemStatus(BGS_STATUS_MASK) == true) {
+ ALOGD("%s(), modem_index = %d, bgs_on = true", __FUNCTION__, mModemIndex);
+ SetApSideModemStatus(BGS_STATUS_MASK);
+ BGSoundOff();
+ }
+
+ // TTY
+ if (pCCCI->GetModemSideModemStatus(TTY_STATUS_MASK) == true) {
+ ALOGD("%s(), modem_index = %d, tty_on = true", __FUNCTION__, mModemIndex);
+ SetApSideModemStatus(TTY_STATUS_MASK);
+ TtyCtmOff();
+ }
+
+ // P2W
+ if (pCCCI->GetModemSideModemStatus(P2W_STATUS_MASK) == true) {
+ ALOGD("%s(), modem_index = %d, p2w_on = true", __FUNCTION__, mModemIndex);
+ SetApSideModemStatus(P2W_STATUS_MASK);
+ PCM2WayOff();
+ }
+
+ // Phone Call / Loopback
+ if (pCCCI->GetModemSideModemStatus(VT_STATUS_MASK) == true) {
+ ALOGD("%s(), modem_index = %d, vt_on = true", __FUNCTION__, mModemIndex);
+ SetApSideModemStatus(VT_STATUS_MASK);
+ VideoTelephonyOff();
+ } else if (pCCCI->GetModemSideModemStatus(SPEECH_STATUS_MASK) == true) {
+ ALOGD("%s(), modem_index = %d, speech_on = true", __FUNCTION__, mModemIndex);
+ SetApSideModemStatus(SPEECH_STATUS_MASK);
+ SpeechOff();
+ } else if (pCCCI->GetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK) == true) {
+ ALOGD("%s(), modem_index = %d, speech_router_on = true", __FUNCTION__, mModemIndex);
+ SetApSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+ SpeechRouterOff();
+ } else if (pCCCI->GetModemSideModemStatus(LOOPBACK_STATUS_MASK) == true) {
+ ALOGD("%s(), modem_index = %d, loopback_on = true", __FUNCTION__, mModemIndex);
+ SetApSideModemStatus(LOOPBACK_STATUS_MASK);
+ SetAcousticLoopback(false);
+ }
+}
+
+/*==============================================================================
+ * Check Modem Status
+ *============================================================================*/
+bool SpeechDriverLAD::CheckModemIsReady() {
+ return pCCCI->CheckModemIsReady();
+};
+
+/*==============================================================================
+ * Run-Time parameter tuning
+ *============================================================================*/
+int SpeechDriverLAD::updateParam(int audioTypeUpdate) {
+#if (!defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT))||defined(SPH_SKIP_A2M_BUFF_MSG)
+ (void) audioTypeUpdate;
+ return NO_ERROR;
+#else
+
+ switch (audioTypeUpdate) {
+ case AUDIO_TYPE_SPEECH_DMNR:
+ case AUDIO_TYPE_SPEECH_GENERAL:
+ SetDynamicSpeechParameters(audioTypeUpdate, &audioTypeUpdate);
+ break;
+ case AUDIO_TYPE_SPEECH: {
+ bool isSpeechOn = GetApSideModemStatus(SPEECH_STATUS_MASK);
+ if (isSpeechOn) {
+#if defined(MTK_AUDIO_SPH_LPBK_PARAM)
+ if (mIsLpbk) {
+ SpeechParamParser::getInstance()->SetParamInfo(String8("ParamSphLpbk=1;"));
+ }
+#endif
+ int param_arg[4];
+ param_arg[0] = (int) mSpeechMode;
+ param_arg[1] = mVolumeIndex;
+ param_arg[2] = mBtHeadsetNrecOn;
+ param_arg[3] = 0;//bit 0: customized profile, bit 1: single band, bit 4~7: band number
+ SetDynamicSpeechParameters((int)AUDIO_TYPE_SPEECH, param_arg);
+ }
+ break;
+ }
+ default: // do nothing
+ break;
+ }
+#endif
+ return NO_ERROR;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechDriverOpenDSP.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechDriverOpenDSP.cpp
new file mode 100644
index 0000000..a182668
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechDriverOpenDSP.cpp
@@ -0,0 +1,1325 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "SpeechDriverOpenDSP.h"
+
+#include <utils/threads.h>
+#include <cutils/properties.h>
+
+#include <dlfcn.h>
+
+
+#include <cutils/properties.h>
+
+#include <audio_task.h>
+
+#include <arsi_type.h>
+#include <aurisys_scenario_dsp.h>
+#include <aurisys_config.h>
+#include <aurisys_utility.h>
+#include <aurisys_controller.h>
+#include <aurisys_lib_manager.h>
+
+
+#include <AudioLock.h>
+#include "AudioUtility.h"
+
+#include <SpeechUtility.h>
+
+#include "AudioALSAHardwareResourceManager.h"
+#include "AudioALSAStreamManager.h"
+
+#include <SpeechDriverNormal.h>
+
+#include <SpeechEnhancementController.h>
+#include <AudioSmartPaController.h>
+
+#include <AudioMessengerIPI.h>
+#include "audio_speech_msg_id.h"
+#include <tinyalsa/asoundlib.h> // for mixctrl
+
+#ifdef MTK_AUDIODSP_SUPPORT
+#include <audio_dsp_service.h>
+#endif
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechDriverOpenDSP"
+
+
+namespace android {
+
+/**
+ * lib related
+ */
+
+static const char *PROPERTY_KEY_PCM_DUMP_ON = "persist.vendor.audiohal.aurisys.pcm_dump_on";
+
+
+#define DUMP_DSP_PCM_DATA_PATH "/data/vendor/audiohal/aurisys_dump/"
+
+//#define AUDIO_SPEECH_ENABLE_3MIC
+
+
+static FILE *fp_pcm_dump_ul_in1;
+static FILE *fp_pcm_dump_ul_in2;
+static FILE *fp_pcm_dump_ul_in3;
+static FILE *fp_pcm_dump_ul_ref;
+static FILE *fp_pcm_dump_ul_out;
+static FILE *fp_pcm_dump_dl_in;
+static FILE *fp_pcm_dump_dl_out;
+
+enum pcm_dump_t {
+ UL_IN1,
+ UL_IN2,
+ UL_IN3,
+ UL_REF,
+ UL_OUT,
+ DL_IN,
+ DL_OUT
+};
+
+static bool adsp_register_call = false;
+
+static struct mixer *mMixer;
+
+
+
+
+/*==============================================================================
+ * utilities
+ *============================================================================*/
+
+inline uint8_t getInputChannelsByDevice(const audio_devices_t input_device) {
+ uint8_t num_channels = 0;
+
+ switch (input_device) {
+ case AUDIO_DEVICE_IN_BUILTIN_MIC:
+ case AUDIO_DEVICE_IN_BACK_MIC:
+ num_channels = AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport();
+ break;
+ case AUDIO_DEVICE_IN_WIRED_HEADSET:
+ case AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET:
+ case AUDIO_DEVICE_IN_USB_DEVICE:
+ num_channels = 1;
+ break;
+ default: {
+ ALOGE("Not support input_device 0x%x", input_device);
+ WARNING("Need implement device");
+ num_channels = 2;
+ }
+ }
+
+#ifndef AUDIO_SPEECH_ENABLE_3MIC
+ if (num_channels > 2) {
+ ALOGW("num_channels %d, but only support dual mic", num_channels);
+ num_channels = 2;
+ }
+#endif
+
+ return num_channels;
+}
+
+inline uint32_t getScpSpeechStatus(void) {
+ struct mixer_ctl *ctl = mixer_get_ctl_by_name(mMixer, "Speech_SCP_CALL_STATE");
+ if( NULL == ctl ) {
+ ALOGW("unknown name Speech_SCP_CALL_STATE in mixer_ctl");
+ return 0;
+ } else {
+ return mixer_ctl_get_value(ctl, 0);
+ }
+}
+
+inline void setScpSpeechStatus(uint32_t state) {
+ struct mixer_ctl *ctl = mixer_get_ctl_by_name(mMixer, "Speech_SCP_CALL_STATE");
+ if( NULL == ctl ) {
+ ALOGW("unknown name Speech_SCP_CALL_STATE in mixer_ctl");
+ } else {
+ if (mixer_ctl_set_value(ctl, 0, state)) {
+ ALOGE("%s() , Error: Speech_SCP_CALL_STATE %d", __FUNCTION__, state);
+ }
+ }
+}
+/*==============================================================================
+ * Singleton Pattern
+ *============================================================================*/
+
+SpeechDriverOpenDSP *SpeechDriverOpenDSP::mSpeechDriverOpenDSP = NULL;
+
+SpeechDriverInterface *SpeechDriverOpenDSP::GetInstance(
+ modem_index_t modem_index) {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ SpeechDriverOpenDSP *pSpeechDriver = NULL;
+ ALOGD("%s(), modem_index = %d", __FUNCTION__, modem_index);
+
+ switch (modem_index) {
+ case MODEM_1:
+ if (mSpeechDriverOpenDSP == NULL) {
+ mSpeechDriverOpenDSP = new SpeechDriverOpenDSP(modem_index);
+ }
+ pSpeechDriver = mSpeechDriverOpenDSP;
+ break;
+ case MODEM_2:
+ case MODEM_EXTERNAL:
+ ALOGE("%s(), modem_index = %d not support", __FUNCTION__, modem_index);
+ pSpeechDriver = NULL;
+ break;
+ default:
+ ALOGE("%s: no such modem_index %d", __FUNCTION__, modem_index);
+ break;
+ }
+
+ ASSERT(pSpeechDriver != NULL);
+ return pSpeechDriver;
+}
+
+
+/*==============================================================================
+ * Constructor / Destructor / Init / Deinit
+ *============================================================================*/
+
+SpeechDriverOpenDSP::SpeechDriverOpenDSP(modem_index_t modem_index) :
+ mAudioMessengerIPI(AudioMessengerIPI::getInstance()),
+ pSpeechDriverInternal(NULL) {
+
+ mMixer = AudioALSADriverUtility::getInstance()->getMixer();
+ ASSERT(mMixer != NULL);
+
+ ALOGD("%s(), modem_index = %d", __FUNCTION__, modem_index);
+
+ mModemIndex = modem_index;
+
+ // control internal modem & FD216
+ pSpeechDriverInternal = SpeechDriverNormal::GetInstance(modem_index);
+
+ mEnableDump = false;
+
+ mAurisysDspConfig = NULL;
+ mInputDevice = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ mOutputDevices = AUDIO_DEVICE_OUT_EARPIECE;
+
+ mAurisysLibManager = NULL;
+
+#ifndef SPH_SR32K /* non-SWB */
+ mModemDspMaxSampleRate = 16000;
+#elif defined(SPH_SR48K) /* SWB */
+ mModemDspMaxSampleRate = 48000;
+#else /* SWB */
+ mModemDspMaxSampleRate = 32000;
+#endif
+ mModemPcmSampleRate = mModemDspMaxSampleRate;
+
+ /* get scp function state */
+ mScpSideSpeechStatus = getScpSpeechStatus();
+
+ /* recovery scp state for mediaserver die */
+ RecoverModemSideStatusToInitState();
+}
+
+
+SpeechDriverOpenDSP::~SpeechDriverOpenDSP() {
+ ALOGD("%s()", __FUNCTION__);
+
+ pSpeechDriverInternal = NULL;
+}
+
+
+/*==============================================================================
+ * Aurisys
+ *============================================================================*/
+
+
+void SpeechDriverOpenDSP::SetArsiTaskConfig(struct arsi_task_config_t *pTaskConfig) {
+ if (!pTaskConfig) {
+ return;
+ }
+
+ pTaskConfig->input_device_info.devices = mInputDevice;
+ pTaskConfig->input_device_info.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ pTaskConfig->input_device_info.sample_rate = mModemDspMaxSampleRate;
+ pTaskConfig->input_device_info.num_channels = getInputChannelsByDevice(mInputDevice);
+ pTaskConfig->input_device_info.channel_mask = get_input_ch_mask(pTaskConfig->input_device_info.num_channels);
+ pTaskConfig->input_device_info.hw_info_mask = 0;
+
+ pTaskConfig->output_device_info.devices = mOutputDevices;
+ pTaskConfig->output_device_info.audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ pTaskConfig->output_device_info.sample_rate = mModemDspMaxSampleRate;
+ pTaskConfig->output_device_info.num_channels = 1;
+ pTaskConfig->output_device_info.channel_mask = get_output_ch_mask(pTaskConfig->output_device_info.num_channels);
+ pTaskConfig->output_device_info.hw_info_mask = 0;
+
+ /* SMARTPA */
+ if (mOutputDevices == AUDIO_DEVICE_OUT_SPEAKER &&
+ AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ pTaskConfig->output_device_info.hw_info_mask |= OUTPUT_DEVICE_HW_INFO_SMARTPA_SPEAKER;
+ } else {
+ pTaskConfig->output_device_info.hw_info_mask = 0;
+ }
+
+
+ pTaskConfig->task_scene = TASK_SCENE_PHONE_CALL;
+ pTaskConfig->audio_mode = AUDIO_MODE_IN_CALL;
+
+ pTaskConfig->max_input_device_sample_rate = mModemDspMaxSampleRate;
+ pTaskConfig->max_output_device_sample_rate = mModemDspMaxSampleRate;
+ pTaskConfig->max_input_device_num_channels = AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport();
+#ifndef AUDIO_SPEECH_ENABLE_3MIC
+ if (pTaskConfig->max_input_device_num_channels > 2) {
+ pTaskConfig->max_input_device_num_channels = 2;
+ }
+#endif
+
+ pTaskConfig->max_output_device_num_channels = 1;
+
+ pTaskConfig->output_flags = 0;
+ pTaskConfig->input_source = 0;
+ pTaskConfig->input_flags = 0;
+
+
+ pTaskConfig->enhancement_feature_mask = 0;
+ if (mOutputDevices == AUDIO_DEVICE_OUT_EARPIECE &&
+ SpeechEnhancementController::GetInstance()->GetHACOn()) {
+ pTaskConfig->enhancement_feature_mask |= ENHANCEMENT_FEATURE_EARPIECE_HAC;
+ }
+
+ if ((mInputDevice & AUDIO_DEVICE_IN_ALL_SCO)
+ && (pTaskConfig->output_device_info.devices & AUDIO_DEVICE_OUT_ALL_SCO)
+ && SpeechEnhancementController::GetInstance()->GetBtHeadsetNrecOn()) {
+ pTaskConfig->enhancement_feature_mask |= ENHANCEMENT_FEATURE_BT_NREC;
+ }
+
+ dump_task_config(pTaskConfig);
+}
+
+
+void SpeechDriverOpenDSP::SetArsiAttribute() {
+ struct stream_attribute_dsp *attribute = NULL;
+
+ if (!mAurisysDspConfig) {
+ return;
+ }
+
+ /* UL in attribute */
+ attribute = &mAurisysDspConfig->attribute[DATA_BUF_UPLINK_IN];
+ attribute->num_channels = getInputChannelsByDevice(mInputDevice);
+ attribute->sample_rate = mModemDspMaxSampleRate;
+ attribute->audio_format = AUDIO_FORMAT_PCM_16_BIT;
+
+ /* UL out attribute */
+ attribute = &mAurisysDspConfig->attribute[DATA_BUF_UPLINK_OUT];
+ attribute->num_channels = 1;
+ attribute->sample_rate = mModemDspMaxSampleRate;
+ attribute->audio_format = AUDIO_FORMAT_PCM_16_BIT;
+
+ /* AEC attribute */
+ attribute = &mAurisysDspConfig->attribute[DATA_BUF_ECHO_REF];
+ attribute->num_channels = 1;
+ attribute->sample_rate = mModemDspMaxSampleRate;
+ attribute->audio_format = AUDIO_FORMAT_PCM_16_BIT;
+
+
+ /* DL in attribute */
+ attribute = &mAurisysDspConfig->attribute[DATA_BUF_DOWNLINK_IN];
+ attribute->num_channels = 1;
+ attribute->sample_rate = mModemDspMaxSampleRate;
+ attribute->audio_format = AUDIO_FORMAT_PCM_16_BIT;
+
+ /* DL out attribute */
+ attribute = &mAurisysDspConfig->attribute[DATA_BUF_DOWNLINK_OUT];
+ attribute->num_channels = 1;
+ attribute->sample_rate = mModemDspMaxSampleRate;
+ attribute->audio_format = AUDIO_FORMAT_PCM_16_BIT;
+}
+
+
+void SpeechDriverOpenDSP::CreateAurisysLibManager() {
+ struct aurisys_lib_manager_config_t *pManagerConfig = NULL;
+
+ struct data_buf_t paramList;
+ uint8_t *configAndParam = NULL;
+
+ struct ipi_msg_t msg;
+ int retval = 0;
+
+ paramList.data_size = 0;
+ paramList.memory_size = 0;
+ paramList.p_buffer = NULL;
+
+ ALOGD("%s(+)", __FUNCTION__);
+
+
+ if (mAurisysLibManager != NULL || mAurisysDspConfig != NULL) {
+ ALOGE("%p %p already init!!", mAurisysLibManager, mAurisysDspConfig);
+ WARNING("already init!!");
+ return;
+ }
+
+
+ AUDIO_ALLOC_STRUCT(struct aurisys_dsp_config_t, mAurisysDspConfig);
+ mAurisysDspConfig->guard_head = AURISYS_GUARD_HEAD_VALUE;
+ mAurisysDspConfig->guard_tail = AURISYS_GUARD_TAIL_VALUE;
+
+ /* manager config */
+ pManagerConfig = &mAurisysDspConfig->manager_config;
+
+ pManagerConfig->aurisys_scenario = AURISYS_SCENARIO_DSP_PHONE_CALL;
+ pManagerConfig->core_type = AURISYS_CORE_HIFI3;
+ pManagerConfig->arsi_process_type = ARSI_PROCESS_TYPE_UL_AND_DL;
+ pManagerConfig->frame_size_ms = 20;
+ pManagerConfig->num_channels_ul = getInputChannelsByDevice(mInputDevice);
+ pManagerConfig->num_channels_dl = 1;
+ pManagerConfig->audio_format = AUDIO_FORMAT_PCM_16_BIT;
+ pManagerConfig->sample_rate = mModemDspMaxSampleRate;
+ pManagerConfig->dsp_task_scene = TASK_SCENE_PHONE_CALL;
+ ALOGD("manager config: aurisys_scenario %u, core_type %d, " \
+ "arsi_process_type %d, frame_size_ms %d, " \
+ "num_channels_ul %d, num_channels_dl %d, " \
+ "audio_format %u, sample_rate %u",
+ pManagerConfig->aurisys_scenario,
+ pManagerConfig->core_type,
+ pManagerConfig->arsi_process_type,
+ pManagerConfig->frame_size_ms,
+ pManagerConfig->num_channels_ul,
+ pManagerConfig->num_channels_dl,
+ pManagerConfig->audio_format,
+ pManagerConfig->sample_rate);
+
+ /* task config */
+ SetArsiTaskConfig(&pManagerConfig->task_config);
+
+
+ /* attribute */
+ SetArsiAttribute();
+
+ /* gain */
+ mAurisysDspConfig->gain_config.ul_digital_gain = 0;
+ mAurisysDspConfig->gain_config.ul_analog_gain = 0;
+ mAurisysDspConfig->gain_config.dl_digital_gain = 0;
+ mAurisysDspConfig->gain_config.dl_analog_gain = 0;
+
+ /* func */
+ mAurisysDspConfig->voip_on = false;
+ mAurisysDspConfig->aec_on = true;
+
+
+
+ /* create manager */
+ mAurisysLibManager = create_aurisys_lib_manager(pManagerConfig);
+
+ /* parsing param */
+ aurisys_parsing_param_file(mAurisysLibManager);
+
+ paramList.data_size = 0;
+ paramList.memory_size = 32768; /* TODO: refine it */
+ AUDIO_ALLOC_BUFFER(paramList.p_buffer, paramList.memory_size);
+ do {
+ retval = aurisys_get_param_list(mAurisysLibManager, ¶mList);
+ if (retval == 0) {
+ break;
+ }
+ ALOGE("%s(), paramList.memory_size %u not enough!!",
+ __FUNCTION__, paramList.memory_size);
+
+ AUDIO_FREE_POINTER(paramList.p_buffer);
+ paramList.data_size = 0;
+ paramList.memory_size *= 2;
+ AUDIO_ALLOC_BUFFER(paramList.p_buffer, paramList.memory_size);
+ } while (1);
+
+
+ /* send config */
+ configAndParam = (uint8_t *)AUDIO_MALLOC(sizeof(struct aurisys_dsp_config_t) + paramList.data_size);
+ memcpy(configAndParam, mAurisysDspConfig, sizeof(struct aurisys_dsp_config_t));
+ memcpy(configAndParam + sizeof(struct aurisys_dsp_config_t), paramList.p_buffer, paramList.data_size);
+
+ retval = mAudioMessengerIPI->sendIpiMsg(
+ &msg,
+ TASK_SCENE_PHONE_CALL, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_DMA, AUDIO_IPI_MSG_NEED_ACK,
+ IPI_MSG_A2D_AURISYS_INIT,
+ sizeof(struct aurisys_dsp_config_t) + paramList.data_size,
+ 0,
+ configAndParam);
+ if (retval != 0) {
+ ALOGE("%s(), fail!! retval = %d", __FUNCTION__, retval);
+ }
+ AUDIO_FREE_POINTER(configAndParam);
+ AUDIO_FREE_POINTER(paramList.p_buffer);
+
+ ALOGD("%s(-)", __FUNCTION__);
+}
+
+
+void SpeechDriverOpenDSP::UpdateAurisysConfig() {
+ struct aurisys_lib_manager_config_t *pManagerConfig = NULL;
+
+ struct data_buf_t paramList;
+ uint8_t *configAndParam = NULL;
+
+ struct ipi_msg_t msg;
+ int retval = 0;
+
+ paramList.data_size = 0;
+ paramList.memory_size = 0;
+ paramList.p_buffer = NULL;
+
+
+ if (mAurisysLibManager == NULL || mAurisysDspConfig == NULL) {
+ WARNING("not init!!");
+ return;
+ }
+
+ /* manager config */
+ pManagerConfig = &mAurisysDspConfig->manager_config;
+ pManagerConfig->num_channels_ul = getInputChannelsByDevice(mInputDevice);
+
+ /* task config */
+ SetArsiTaskConfig(&pManagerConfig->task_config);
+
+
+ /* attribute */
+ SetArsiAttribute();
+
+
+ /* gain */
+ mAurisysDspConfig->gain_config.ul_digital_gain = 0;
+ mAurisysDspConfig->gain_config.ul_analog_gain = 0;
+ mAurisysDspConfig->gain_config.dl_digital_gain = 0;
+ mAurisysDspConfig->gain_config.dl_analog_gain = 0;
+
+ /* func */
+ mAurisysDspConfig->voip_on = false;
+ mAurisysDspConfig->aec_on = true;
+
+
+ /* parsing param */
+ aurisys_parsing_param_file(mAurisysLibManager);
+
+ paramList.data_size = 0;
+ paramList.memory_size = 32768; /* TODO: refine it */
+ AUDIO_ALLOC_BUFFER(paramList.p_buffer, paramList.memory_size);
+ do {
+ retval = aurisys_get_param_list(mAurisysLibManager, ¶mList);
+ if (retval == 0) {
+ break;
+ }
+ ALOGE("%s(), paramList.memory_size %u not enough!!",
+ __FUNCTION__, paramList.memory_size);
+
+ AUDIO_FREE_POINTER(paramList.p_buffer);
+ paramList.data_size = 0;
+ paramList.memory_size *= 2;
+ AUDIO_ALLOC_BUFFER(paramList.p_buffer, paramList.memory_size);
+ } while (1);
+
+
+ /* send config */
+ configAndParam = (uint8_t *)AUDIO_MALLOC(sizeof(struct aurisys_dsp_config_t) + paramList.data_size);
+ memcpy(configAndParam, mAurisysDspConfig, sizeof(struct aurisys_dsp_config_t));
+ memcpy(configAndParam + sizeof(struct aurisys_dsp_config_t), paramList.p_buffer, paramList.data_size);
+
+ retval = mAudioMessengerIPI->sendIpiMsg(
+ &msg,
+ TASK_SCENE_PHONE_CALL, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_DMA, AUDIO_IPI_MSG_NEED_ACK,
+ IPI_MSG_A2D_AURISYS_ROUTING,
+ sizeof(struct aurisys_dsp_config_t) + paramList.data_size,
+ 0,
+ configAndParam);
+ if (retval != 0) {
+ ALOGE("%s(), fail!! retval = %d", __FUNCTION__, retval);
+ }
+ AUDIO_FREE_POINTER(configAndParam);
+ AUDIO_FREE_POINTER(paramList.p_buffer);
+}
+
+
+
+void SpeechDriverOpenDSP::DestroyAurisysLibManager() {
+ struct ipi_msg_t ipi_msg;
+ int retval = 0;
+
+ ALOGD("%s(+)", __FUNCTION__);
+
+ retval = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_PHONE_CALL,
+ AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY,
+ AUDIO_IPI_MSG_NEED_ACK,
+ IPI_MSG_A2D_AURISYS_DEINIT,
+ 0,
+ 0,
+ NULL);
+ if (retval != 0) {
+ ALOGE("%s(), fail!! retval = %d", __FUNCTION__, retval);
+ }
+
+ if (mAurisysLibManager) {
+ destroy_aurisys_lib_manager(mAurisysLibManager);
+ mAurisysLibManager = NULL;
+ }
+
+ AUDIO_FREE_POINTER(mAurisysDspConfig);
+
+ ALOGD("%s(-)", __FUNCTION__);
+}
+
+
+
+/*==============================================================================
+ * Speech Control
+ *============================================================================*/
+
+static void putTimestampAndEnableToParam(uint32_t *param, const bool enable) {
+ char time_h[3];
+ char time_m[3];
+ char time_s[3];
+
+ uint8_t time_value_h;
+ uint8_t time_value_m;
+ uint8_t time_value_s;
+
+ time_t rawtime;
+ time(&rawtime);
+
+ struct tm *timeinfo = localtime(&rawtime);
+ strftime(time_h, 3, "%H", timeinfo);
+ strftime(time_m, 3, "%M", timeinfo);
+ strftime(time_s, 3, "%S", timeinfo);
+
+ time_value_h = (uint8_t)atoi(time_h);
+ time_value_m = (uint8_t)atoi(time_m);
+ time_value_s = (uint8_t)atoi(time_s);
+
+ /* param[24:31] => hour
+ * param[16:23] => minute
+ * param[8:15] => second
+ * param[0:7] => enable */
+ *param = (time_value_h << 24) |
+ (time_value_m << 16) |
+ (time_value_s << 8) |
+ (enable);
+}
+
+
+static void printTimeFromParam(const uint32_t param) {
+ uint8_t time_value_h = (param & 0xFF000000) >> 24;
+ uint8_t time_value_m = (param & 0x00FF0000) >> 16;
+ uint8_t time_value_s = (param & 0x0000FF00) >> 8;
+
+ ALOGD("HAL Time %02d:%02d:%02d", time_value_h, time_value_m, time_value_s);
+}
+
+
+
+void SpeechDriverOpenDSP::processDmaMsg(struct ipi_msg_t *msg, void *buf, uint32_t size, void *arg) {
+
+ ALOGD("%s() msg_id=0x%x, task_scene=%d, param2=0x%x, size=%d arg=%p\n",
+ __FUNCTION__, msg->msg_id, msg->task_scene, msg->param2, size, arg);
+
+ switch (msg->msg_id) {
+ case IPI_MSG_D2A_PCM_DUMP_DATA_NOTIFY:
+ if (UL_IN1 == msg->param2) {
+ if (fp_pcm_dump_ul_in1) {
+ AudioDumpPCMData(buf, size, fp_pcm_dump_ul_in1);
+ }
+ } else if (UL_IN2 == msg->param2) {
+ if (fp_pcm_dump_ul_in2) {
+ AudioDumpPCMData(buf, size, fp_pcm_dump_ul_in2);
+ }
+ } else if (UL_REF == msg->param2) {
+ if (fp_pcm_dump_ul_ref) {
+ AudioDumpPCMData(buf, size, fp_pcm_dump_ul_ref);
+ }
+ } else if (UL_OUT == msg->param2) {
+ if (fp_pcm_dump_ul_out) {
+ AudioDumpPCMData(buf, size, fp_pcm_dump_ul_out);
+ }
+ } else if (DL_IN == msg->param2) {
+ if (fp_pcm_dump_dl_in) {
+ AudioDumpPCMData(buf, size, fp_pcm_dump_dl_in);
+ }
+ } else if (DL_OUT == msg->param2) {
+ if (fp_pcm_dump_dl_out) {
+ AudioDumpPCMData(buf, size, fp_pcm_dump_dl_out);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void SpeechDriverOpenDSP::createDumpFiles() {
+
+ char file_path_ul_in1[100];
+ char file_path_ul_in2[100];
+ char file_path_ul_in3[100];
+ char file_path_ul_ref[100];
+ char file_path_ul_out[100];
+ char file_path_dl_in[100];
+ char file_path_dl_out[100];
+ char string_time[100];
+ time_t rawtime;
+
+
+ time(&rawtime);
+ struct tm *timeinfo = localtime(&rawtime);
+ strftime(string_time, 100, "%Y_%m_%d_%H%M%S_", timeinfo);
+
+ sprintf(file_path_ul_in1, "%s%s%s", DUMP_DSP_PCM_DATA_PATH, string_time, "ul_in1.pcm");
+ sprintf(file_path_ul_in2, "%s%s%s", DUMP_DSP_PCM_DATA_PATH, string_time, "ul_in2.pcm");
+ sprintf(file_path_ul_in3, "%s%s%s", DUMP_DSP_PCM_DATA_PATH, string_time, "ul_in3.pcm");
+ sprintf(file_path_ul_ref, "%s%s%s", DUMP_DSP_PCM_DATA_PATH, string_time, "ul_ref.pcm");
+ sprintf(file_path_ul_out, "%s%s%s", DUMP_DSP_PCM_DATA_PATH, string_time, "ul_out.pcm");
+ sprintf(file_path_dl_in, "%s%s%s", DUMP_DSP_PCM_DATA_PATH, string_time, "dl_in.pcm");
+ sprintf(file_path_dl_out, "%s%s%s", DUMP_DSP_PCM_DATA_PATH, string_time, "dl_out.pcm");
+
+
+ mEnableDump = (get_uint32_from_property(PROPERTY_KEY_PCM_DUMP_ON) != 0);
+
+
+ fp_pcm_dump_ul_in1 = AudioOpendumpPCMFile(file_path_ul_in1, PROPERTY_KEY_PCM_DUMP_ON);
+ fp_pcm_dump_ul_in2 = AudioOpendumpPCMFile(file_path_ul_in2, PROPERTY_KEY_PCM_DUMP_ON);
+ fp_pcm_dump_ul_in3 = AudioOpendumpPCMFile(file_path_ul_in3, PROPERTY_KEY_PCM_DUMP_ON);
+ fp_pcm_dump_ul_ref = AudioOpendumpPCMFile(file_path_ul_ref, PROPERTY_KEY_PCM_DUMP_ON);
+ fp_pcm_dump_ul_out = AudioOpendumpPCMFile(file_path_ul_out, PROPERTY_KEY_PCM_DUMP_ON);
+ fp_pcm_dump_dl_in = AudioOpendumpPCMFile(file_path_dl_in, PROPERTY_KEY_PCM_DUMP_ON);
+ fp_pcm_dump_dl_out = AudioOpendumpPCMFile(file_path_dl_out, PROPERTY_KEY_PCM_DUMP_ON);
+
+}
+
+
+status_t SpeechDriverOpenDSP::ScpSpeechOn() {
+ ipi_msg_t ipi_msg;
+ status_t retval = NO_ERROR;
+ uint32_t param1 = 0;
+
+ ALOGD("%s(+)", __FUNCTION__);
+
+ putTimestampAndEnableToParam(¶m1, true);
+ printTimeFromParam(param1);
+
+ mAudioMessengerIPI->registerAdspFeature(AURISYS_FEATURE_ID);
+
+ mAudioMessengerIPI->registerDmaCbk(
+ TASK_SCENE_PHONE_CALL,
+ 0x10000,
+ 0x40000,
+ processDmaMsg,
+ this);
+ CreateAurisysLibManager();
+
+
+ createDumpFiles();
+ mAudioMessengerIPI->registerAdspFeature(VOICE_CALL_FEATURE_ID);
+ adsp_register_call = true;
+
+
+ retval = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_PHONE_CALL, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_BYPASS_ACK,
+ IPI_MSG_A2D_PCM_DUMP_ON, mEnableDump, 0,
+ NULL);
+
+ retval = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_PHONE_CALL, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_NEED_ACK,
+ IPI_MSG_A2D_SPH_ON, param1, mModemIndex,
+ NULL);
+
+ ALOGD("%s(-)", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t SpeechDriverOpenDSP::ScpSpeechOff() {
+ ipi_msg_t ipi_msg;
+ status_t retval = NO_ERROR;
+ uint32_t param1 = 0;
+
+ ALOGD("%s(+)", __FUNCTION__);
+
+ putTimestampAndEnableToParam(¶m1, false);
+ printTimeFromParam(param1);
+
+ static const char *kPropertyKeyModemStatus = "vendor.audiohal.modem_1.status";
+
+ for (int i = 0; i < 200; i++) {
+ if (get_uint32_from_mixctrl(kPropertyKeyModemStatus) == 0) {
+ break;
+ } else {
+ ALOGW("%s(), sleep 10ms, i = %d", __FUNCTION__, i);
+ usleep(10000); // sleep 10 ms
+ }
+ }
+ if (adsp_register_call == false) {
+ ALOGD("%s call not yet register %d", __FUNCTION__, adsp_register_call);
+ mAudioMessengerIPI->registerAdspFeature(VOICE_CALL_FEATURE_ID);
+ adsp_register_call = true;
+ }
+ retval = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_PHONE_CALL, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_NEED_ACK,
+ IPI_MSG_A2D_SPH_ON, param1, mModemIndex,
+ NULL);
+
+ AudioCloseDumpPCMFile(fp_pcm_dump_ul_in1);
+ AudioCloseDumpPCMFile(fp_pcm_dump_ul_in2);
+ AudioCloseDumpPCMFile(fp_pcm_dump_ul_in3);
+ AudioCloseDumpPCMFile(fp_pcm_dump_ul_ref);
+ AudioCloseDumpPCMFile(fp_pcm_dump_ul_out);
+ AudioCloseDumpPCMFile(fp_pcm_dump_dl_in);
+ AudioCloseDumpPCMFile(fp_pcm_dump_dl_out);
+
+ DestroyAurisysLibManager();
+
+ mAudioMessengerIPI->deregisterDmaCbk(TASK_SCENE_PHONE_CALL);
+ mAudioMessengerIPI->deregisterAdspFeature(VOICE_CALL_FEATURE_ID);
+ adsp_register_call = false;
+
+ mAudioMessengerIPI->deregisterAdspFeature(AURISYS_FEATURE_ID);
+
+
+ ALOGD("%s(-)", __FUNCTION__);
+ return NO_ERROR;
+}
+
+
+status_t SpeechDriverOpenDSP::SetSpeechMode(const audio_devices_t input_device,
+ const audio_devices_t output_devices) {
+ mInputDevice = input_device;
+ mOutputDevices = output_devices;
+
+ if (mApSideModemStatus != 0) {
+ UpdateAurisysConfig();
+ }
+
+ return pSpeechDriverInternal->SetSpeechMode(input_device, output_devices);
+}
+
+
+status_t SpeechDriverOpenDSP::setMDVolumeIndex(int stream, int device,
+ int index) {
+ return pSpeechDriverInternal->setMDVolumeIndex(stream, device, index);
+}
+
+
+status_t SpeechDriverOpenDSP::SpeechOn() {
+ ALOGD("%s(), mModemIndex = %d", __FUNCTION__, mModemIndex);
+
+ CheckApSideModemStatusAllOffOrDie();
+ SetApSideModemStatus(SPEECH_STATUS_MASK);
+ SetScpSideSpeechStatus(SPEECH_STATUS_MASK);
+
+ ScpSpeechOn();
+ pSpeechDriverInternal->SpeechOn();
+
+ return NO_ERROR;
+}
+
+status_t SpeechDriverOpenDSP::SpeechOff() {
+ ALOGD("%s(), mModemIndex = %d", __FUNCTION__, mModemIndex);
+
+ ResetScpSideSpeechStatus(SPEECH_STATUS_MASK);
+ ResetApSideModemStatus(SPEECH_STATUS_MASK);
+ CheckApSideModemStatusAllOffOrDie();
+
+ // Clean gain value and mute status
+ CleanGainValueAndMuteStatus();
+
+ pSpeechDriverInternal->SpeechOff();
+ ScpSpeechOff();
+
+ return NO_ERROR;
+}
+
+status_t SpeechDriverOpenDSP::VideoTelephonyOn() {
+ ALOGD("%s()", __FUNCTION__);
+ CheckApSideModemStatusAllOffOrDie();
+ SetApSideModemStatus(VT_STATUS_MASK);
+ SetScpSideSpeechStatus(VT_STATUS_MASK);
+
+ ScpSpeechOn();
+ pSpeechDriverInternal->VideoTelephonyOn();
+ return NO_ERROR;
+}
+
+status_t SpeechDriverOpenDSP::VideoTelephonyOff() {
+ ALOGD("%s()", __FUNCTION__);
+ ResetScpSideSpeechStatus(VT_STATUS_MASK);
+ ResetApSideModemStatus(VT_STATUS_MASK);
+ CheckApSideModemStatusAllOffOrDie();
+
+ // Clean gain value and mute status
+ CleanGainValueAndMuteStatus();
+
+ pSpeechDriverInternal->VideoTelephonyOff();
+ ScpSpeechOff();
+
+ return NO_ERROR;
+}
+
+status_t SpeechDriverOpenDSP::SpeechRouterOn() {
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverOpenDSP::SpeechRouterOff() {
+ return INVALID_OPERATION;
+}
+
+
+/*==============================================================================
+ * Recording Control
+ *============================================================================*/
+
+status_t SpeechDriverOpenDSP::recordOn() {
+ return pSpeechDriverInternal->recordOn();
+}
+
+status_t SpeechDriverOpenDSP::recordOn(SpcRecordTypeStruct typeRecord) {
+ return pSpeechDriverInternal->recordOn(typeRecord);
+}
+
+status_t SpeechDriverOpenDSP::recordOff() {
+ return pSpeechDriverInternal->recordOff();
+}
+
+status_t SpeechDriverOpenDSP::recordOff(SpcRecordTypeStruct typeRecord) {
+ return pSpeechDriverInternal->recordOff(typeRecord);
+}
+
+status_t SpeechDriverOpenDSP::setPcmRecordType(SpcRecordTypeStruct typeRecord) {
+ return pSpeechDriverInternal->setPcmRecordType(typeRecord);
+}
+
+status_t SpeechDriverOpenDSP::VoiceMemoRecordOn() {
+ ALOGD("%s()", __FUNCTION__);
+ SetApSideModemStatus(VM_RECORD_STATUS_MASK);
+ return pSpeechDriverInternal->VoiceMemoRecordOn();
+}
+
+status_t SpeechDriverOpenDSP::VoiceMemoRecordOff() {
+ ALOGD("%s()", __FUNCTION__);
+ ResetApSideModemStatus(VM_RECORD_STATUS_MASK);
+ return pSpeechDriverInternal->VoiceMemoRecordOff();
+}
+
+uint16_t SpeechDriverOpenDSP::GetRecordSampleRate() const {
+ return pSpeechDriverInternal->GetRecordSampleRate();
+}
+
+uint16_t SpeechDriverOpenDSP::GetRecordChannelNumber() const {
+ return pSpeechDriverInternal->GetRecordChannelNumber();
+}
+
+
+/*==============================================================================
+ * Background Sound
+ *============================================================================*/
+
+status_t SpeechDriverOpenDSP::BGSoundOn() {
+ return pSpeechDriverInternal->BGSoundOn();
+}
+
+status_t SpeechDriverOpenDSP::BGSoundConfig(uint8_t ul_gain, uint8_t dl_gain) {
+ return pSpeechDriverInternal->BGSoundConfig(ul_gain, dl_gain);
+}
+
+status_t SpeechDriverOpenDSP::BGSoundOff() {
+ return pSpeechDriverInternal->BGSoundOff();
+}
+
+/*==============================================================================
+* PCM 2 Way
+*============================================================================*/
+
+status_t SpeechDriverOpenDSP::PCM2WayOn(const bool wideband_on) {
+ return pSpeechDriverInternal->PCM2WayOn(wideband_on);
+}
+
+
+status_t SpeechDriverOpenDSP::PCM2WayOff() {
+ return pSpeechDriverInternal->PCM2WayOff();
+}
+
+/*==============================================================================
+ * Voice Mixer
+ *============================================================================*/
+status_t SpeechDriverOpenDSP::pcmMixerOn() {
+ status_t retval = NO_ERROR;
+ retval = pSpeechDriverInternal->pcmMixerOn();
+ SetApSideModemStatus(PCM_MIXER_STATUS_MASK);
+ return retval;
+}
+
+status_t SpeechDriverOpenDSP::pcmMixerOff() {
+ status_t retval = NO_ERROR;
+ retval = pSpeechDriverInternal->pcmMixerOff();
+ ResetApSideModemStatus(PCM_MIXER_STATUS_MASK);
+ return retval;
+}
+
+status_t SpeechDriverOpenDSP::pcmMixerConfig(const uint8_t direction, const uint8_t mixType) {
+ return pSpeechDriverInternal->pcmMixerConfig(direction, mixType);
+}
+
+
+/*==============================================================================
+ * TTY-CTM Control
+ *============================================================================*/
+status_t SpeechDriverOpenDSP::TtyCtmOn() {
+ ipi_msg_t ipi_msg;
+ status_t retval = NO_ERROR;
+
+ retval = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_PHONE_CALL, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_NEED_ACK,
+ IPI_MSG_A2D_TTY_ON, true, mTtyMode,
+ NULL);
+ SetApSideModemStatus(TTY_STATUS_MASK);
+ return pSpeechDriverInternal->TtyCtmOn();
+}
+
+status_t SpeechDriverOpenDSP::TtyCtmOff() {
+ ipi_msg_t ipi_msg;
+ status_t retval = NO_ERROR;
+
+ retval = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_PHONE_CALL, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_NEED_ACK,
+ IPI_MSG_A2D_TTY_ON, false, AUD_TTY_OFF,
+ NULL);
+
+ retval = pSpeechDriverInternal->TtyCtmOff();
+ ResetApSideModemStatus(TTY_STATUS_MASK);
+ return retval;
+}
+
+status_t SpeechDriverOpenDSP::TtyCtmDebugOn(bool tty_debug_flag) {
+ return pSpeechDriverInternal->TtyCtmDebugOn(tty_debug_flag);
+}
+
+int SpeechDriverOpenDSP::setTtyMode(const TtyModeType ttyMode) {
+ mTtyMode = ttyMode;
+ return pSpeechDriverInternal->setTtyMode(ttyMode);
+}
+
+/*==============================================================================
+ * RTT
+ *============================================================================*/
+int SpeechDriverOpenDSP::RttConfig(int rttMode) {
+ return pSpeechDriverInternal->RttConfig(rttMode);
+}
+
+/*==============================================================================
+ * Modem Audio DVT and Debug
+ *============================================================================*/
+
+status_t SpeechDriverOpenDSP::SetModemLoopbackPoint(uint16_t loopback_point) {
+ ALOGD("%s(), loopback_point = %d", __FUNCTION__, loopback_point);
+ return pSpeechDriverInternal->SetModemLoopbackPoint(loopback_point);
+}
+
+/*==============================================================================
+ * Speech Encryption
+ *============================================================================*/
+
+status_t SpeechDriverOpenDSP::SetEncryption(bool encryption_on) {
+ ALOGD("%s(), encryption_on = %d", __FUNCTION__, encryption_on);
+ return pSpeechDriverInternal->SetEncryption(encryption_on);
+}
+
+/*==============================================================================
+ * Acoustic Loopback
+ *============================================================================*/
+
+status_t SpeechDriverOpenDSP::SetAcousticLoopback(bool loopback_on) {
+ ALOGD("%s(), loopback_on = %d", __FUNCTION__, loopback_on);
+
+ if (loopback_on == true) {
+ CheckApSideModemStatusAllOffOrDie();
+ SetApSideModemStatus(LOOPBACK_STATUS_MASK);
+ SetScpSideSpeechStatus(LOOPBACK_STATUS_MASK);
+
+ ScpSpeechOn();
+ pSpeechDriverInternal->SetAcousticLoopback(loopback_on);
+ } else {
+ ResetScpSideSpeechStatus(LOOPBACK_STATUS_MASK);
+ ResetApSideModemStatus(LOOPBACK_STATUS_MASK);
+ CheckApSideModemStatusAllOffOrDie();
+
+ // Clean gain value and mute status
+ CleanGainValueAndMuteStatus();
+
+ pSpeechDriverInternal->SetAcousticLoopback(loopback_on);
+ ScpSpeechOff();
+ }
+
+ return NO_ERROR;
+}
+
+status_t SpeechDriverOpenDSP::SetAcousticLoopbackBtCodec(bool enable_codec) {
+ return pSpeechDriverInternal->SetAcousticLoopbackBtCodec(enable_codec);
+}
+
+status_t SpeechDriverOpenDSP::SetAcousticLoopbackDelayFrames(int32_t delay_frames) {
+ return pSpeechDriverInternal->SetAcousticLoopbackDelayFrames(delay_frames);
+}
+
+status_t SpeechDriverOpenDSP::setLpbkFlag(bool enableLpbk) {
+ return pSpeechDriverInternal->setLpbkFlag(enableLpbk);
+}
+
+/*==============================================================================
+ * Volume Control
+ *============================================================================*/
+
+status_t SpeechDriverOpenDSP::SetDownlinkGain(int16_t gain) {
+ ipi_msg_t ipi_msg;
+ status_t retval = NO_ERROR;
+
+ ALOGD("%s(), gain = 0x%x, old mDownlinkGain = 0x%x",
+ __FUNCTION__, gain, mDownlinkGain);
+ if (gain == mDownlinkGain) { return NO_ERROR; }
+
+ mDownlinkGain = gain;
+ mAudioMessengerIPI->registerAdspFeature(VOICE_CALL_FEATURE_ID);
+ retval = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_PHONE_CALL, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_BYPASS_ACK,
+ IPI_MSG_A2D_DL_GAIN, gain, 0/*TODO*/,
+ NULL);
+ mAudioMessengerIPI->deregisterAdspFeature(VOICE_CALL_FEATURE_ID);
+ return retval;
+}
+
+status_t SpeechDriverOpenDSP::SetEnh1DownlinkGain(int16_t gain) {
+ ALOGV("%s(), gain = %d", __FUNCTION__, gain);
+ return INVALID_OPERATION; // not support anymore
+}
+
+status_t SpeechDriverOpenDSP::SetUplinkGain(int16_t gain) {
+ ipi_msg_t ipi_msg;
+ status_t retval = NO_ERROR;
+
+ ALOGD("%s(), gain = 0x%x, old mUplinkGain = 0x%x",
+ __FUNCTION__, gain, mUplinkGain);
+ if (gain == mUplinkGain) { return NO_ERROR; }
+
+ mUplinkGain = gain;
+ mAudioMessengerIPI->registerAdspFeature(VOICE_CALL_FEATURE_ID);
+ retval = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_PHONE_CALL, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_BYPASS_ACK,
+ IPI_MSG_A2D_UL_GAIN, gain, 0/*TODO*/,
+ NULL);
+ mAudioMessengerIPI->deregisterAdspFeature(VOICE_CALL_FEATURE_ID);
+ return retval;
+}
+
+status_t SpeechDriverOpenDSP::SetDownlinkMute(bool mute_on) {
+ ipi_msg_t ipi_msg;
+ status_t retval = NO_ERROR;
+
+ ALOGD("%s(), mute_on = %d, old mDownlinkMuteOn = %d",
+ __FUNCTION__, mute_on, mDownlinkMuteOn);
+ if (mute_on == mDownlinkMuteOn) { return NO_ERROR; }
+
+ mDownlinkMuteOn = mute_on;
+ mAudioMessengerIPI->registerAdspFeature(VOICE_CALL_FEATURE_ID);
+ // mute voice dl + bgs
+ retval = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_PHONE_CALL, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_BYPASS_ACK,
+ IPI_MSG_A2D_DL_MUTE_ON, mute_on, 0,
+ NULL);
+ mAudioMessengerIPI->deregisterAdspFeature(VOICE_CALL_FEATURE_ID);
+ return pSpeechDriverInternal->SetDownlinkMute(mute_on); // for bgs
+}
+
+status_t SpeechDriverOpenDSP::SetDownlinkMuteCodec(bool mute_on) {
+ ALOGD("%s(), mute_on = %d, old mDownlinkMuteOn = %d", __FUNCTION__, mute_on, mDownlinkMuteOn);
+ mDownlinkMuteOn = mute_on;
+ return pSpeechDriverInternal->SetDownlinkMuteCodec(mute_on);
+}
+
+status_t SpeechDriverOpenDSP::SetUplinkMute(bool mute_on) {
+ ipi_msg_t ipi_msg;
+ status_t retval = NO_ERROR;
+
+ ALOGD("%s(), mute_on = %d, old mUplinkMuteOn = %d",
+ __FUNCTION__, mute_on, mUplinkMuteOn);
+ if (mute_on == mUplinkMuteOn) { return NO_ERROR; }
+
+ mUplinkMuteOn = mute_on;
+ mAudioMessengerIPI->registerAdspFeature(VOICE_CALL_FEATURE_ID);
+ // mute voice ul + bgs
+ retval = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_PHONE_CALL, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_BYPASS_ACK,
+ IPI_MSG_A2D_UL_MUTE_ON, mute_on, 0,
+ NULL);
+ mAudioMessengerIPI->deregisterAdspFeature(VOICE_CALL_FEATURE_ID);
+ return pSpeechDriverInternal->SetUplinkMute(mute_on); // for bgs
+}
+
+status_t SpeechDriverOpenDSP::SetUplinkSourceMute(bool mute_on) {
+ ALOGD("%s(), mute_on = %d, old mUplinkSourceMuteOn = %d",
+ __FUNCTION__, mute_on, mUplinkSourceMuteOn);
+ mUplinkSourceMuteOn = mute_on;
+ return pSpeechDriverInternal->SetUplinkSourceMute(mute_on);
+}
+
+status_t SpeechDriverOpenDSP::SetSidetoneGain(int16_t gain) {
+ ALOGD("%s(), gain = 0x%x, old mSideToneGain = 0x%x",
+ __FUNCTION__, gain, mSideToneGain);
+ if (gain == mSideToneGain) { return NO_ERROR; }
+
+ mSideToneGain = gain;
+ return pSpeechDriverInternal->SetSidetoneGain(gain);
+}
+
+
+/*==============================================================================
+ * Device related Config
+ *============================================================================*/
+
+status_t SpeechDriverOpenDSP::SetModemSideSamplingRate(uint16_t sample_rate) {
+ ALOGD("%s(), %u => %u", __FUNCTION__, mModemPcmSampleRate, sample_rate);
+ mModemPcmSampleRate = sample_rate;
+ return pSpeechDriverInternal->SetModemSideSamplingRate(sample_rate);
+}
+
+
+/*==============================================================================
+ * Speech Enhancement Control
+ *============================================================================*/
+status_t SpeechDriverOpenDSP::SetSpeechEnhancement(bool enhance_on) {
+ ipi_msg_t ipi_msg;
+ status_t retval = NO_ERROR;
+
+ mAudioMessengerIPI->registerAdspFeature(VOICE_CALL_FEATURE_ID);
+ retval = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_PHONE_CALL, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_BYPASS_ACK,
+ IPI_MSG_A2D_UL_ENHANCE_ON, enhance_on, 0,
+ NULL);
+ retval = mAudioMessengerIPI->sendIpiMsg(
+ &ipi_msg,
+ TASK_SCENE_PHONE_CALL, AUDIO_IPI_LAYER_TO_DSP,
+ AUDIO_IPI_MSG_ONLY, AUDIO_IPI_MSG_BYPASS_ACK,
+ IPI_MSG_A2D_DL_ENHANCE_ON, enhance_on, 0,
+ NULL);
+ mAudioMessengerIPI->deregisterAdspFeature(VOICE_CALL_FEATURE_ID);
+ return NO_ERROR;
+}
+
+status_t SpeechDriverOpenDSP::SetSpeechEnhancementMask(const sph_enh_mask_struct_t &mask) {
+ ALOGV("%s(), main_func = 0x%x, dynamic_func = 0x%x", __FUNCTION__, mask.main_func, mask.dynamic_func);
+ return INVALID_OPERATION; // not support anymore
+}
+
+status_t SpeechDriverOpenDSP::SetBtHeadsetNrecOn(const bool bt_headset_nrec_on) {
+ ALOGD("%s(), bt_headset_nrec_on %d", __FUNCTION__, bt_headset_nrec_on);
+ return NO_ERROR;
+}
+
+
+/*==============================================================================
+ * Speech Enhancement Parameters
+ *============================================================================*/
+
+status_t SpeechDriverOpenDSP::GetVibSpkParam(void *eVibSpkParam) {
+ return pSpeechDriverInternal->GetVibSpkParam(eVibSpkParam);
+}
+
+status_t SpeechDriverOpenDSP::SetVibSpkParam(void *eVibSpkParam) {
+ return pSpeechDriverInternal->SetVibSpkParam(eVibSpkParam);
+}
+
+status_t SpeechDriverOpenDSP::SetDynamicSpeechParameters(const int type,
+ const void *param_arg) {
+ return pSpeechDriverInternal->SetDynamicSpeechParameters(type, param_arg);
+}
+
+
+/*==============================================================================
+ * Recover State
+ *============================================================================*/
+
+bool SpeechDriverOpenDSP::GetScpSideSpeechStatus(const modem_status_mask_t modem_status_mask) {
+ AL_AUTOLOCK(mScpSideSpeechStatusLock);
+ return ((mScpSideSpeechStatus & modem_status_mask) > 0);
+}
+
+
+void SpeechDriverOpenDSP::SetScpSideSpeechStatus(const modem_status_mask_t modem_status_mask) {
+ ALOGD("%s(), modem_status_mask = 0x%x, mScpSideSpeechStatus = 0x%x",
+ __FUNCTION__, modem_status_mask, mScpSideSpeechStatus);
+
+ AL_AUTOLOCK(mScpSideSpeechStatusLock);
+
+ ASSERT(((mScpSideSpeechStatus & modem_status_mask) > 0) == false);
+ mScpSideSpeechStatus |= modem_status_mask;
+
+ setScpSpeechStatus(mScpSideSpeechStatus);
+}
+
+
+void SpeechDriverOpenDSP::ResetScpSideSpeechStatus(const modem_status_mask_t modem_status_mask) {
+ ALOGD("%s(), modem_status_mask = 0x%x, mScpSideSpeechStatus = 0x%x",
+ __FUNCTION__, modem_status_mask, mScpSideSpeechStatus);
+
+ AL_AUTOLOCK(mScpSideSpeechStatusLock);
+
+ ASSERT(((mScpSideSpeechStatus & modem_status_mask) > 0) == true);
+ mScpSideSpeechStatus &= (~modem_status_mask);
+
+ setScpSpeechStatus(mScpSideSpeechStatus);
+}
+
+
+void SpeechDriverOpenDSP::RecoverModemSideStatusToInitState() {
+ // Phone Call / Loopback
+ if (GetScpSideSpeechStatus(SPEECH_STATUS_MASK) == true) {
+ ALOGD("%s(), modem_index = %d, speech_on = true", __FUNCTION__, mModemIndex);
+ ResetScpSideSpeechStatus(SPEECH_STATUS_MASK);
+ ScpSpeechOff();
+ } else if (GetScpSideSpeechStatus(VT_STATUS_MASK) == true) {
+ ALOGD("%s(), modem_index = %d, vt_on = true", __FUNCTION__, mModemIndex);
+ ResetScpSideSpeechStatus(VT_STATUS_MASK);
+ ScpSpeechOff();
+ } else if (GetScpSideSpeechStatus(LOOPBACK_STATUS_MASK) == true) {
+ ALOGD("%s(), modem_index = %d, loopback_on = true", __FUNCTION__, mModemIndex);
+ ResetScpSideSpeechStatus(LOOPBACK_STATUS_MASK);
+ ScpSpeechOff();
+ }
+}
+
+
+/*==============================================================================
+ * Check Modem Status
+ *============================================================================*/
+bool SpeechDriverOpenDSP::CheckModemIsReady() {
+ // TODO: [OpenDSP] scp ready
+ return pSpeechDriverInternal->CheckModemIsReady();
+}
+
+
+
+} // end of namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechMessengerCCCI.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechMessengerCCCI.cpp
new file mode 100644
index 0000000..b77d067
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechMessengerCCCI.cpp
@@ -0,0 +1,1985 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechMessengerCCCI"
+#include "SpeechMessengerCCCI.h"
+#include <unistd.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <sys/prctl.h>
+#include <sys/resource.h>
+
+#include <cutils/properties.h>
+
+#include <AudioLock.h>
+
+#include "SpeechDriverLAD.h"
+#include "SpeechBGSPlayer.h"
+#include "SpeechPcm2way.h"
+#include "SpeechVMRecorder.h"
+#include "AudioVolumeFactory.h"
+
+#include "AudioALSAHardwareResourceManager.h"
+
+#include "AudioALSACaptureDataProviderVoice.h"
+#include "SpeechDataProcessingHandler.h"
+#include <AudioEventThreadManager.h>
+
+
+#ifndef sph_msleep
+#define sph_msleep(ms) usleep((ms)*1000)
+#endif
+
+namespace android {
+
+/** CCCI driver & ioctl */
+/** CCCI ioctl */
+/*
+extern "C" {
+#include "hardware/ccci_intf.h"
+}
+*/
+/** Property keys*/
+static const char* PROPERTY_KEY_MODEM_STATUS[NUM_MODEM] = {
+ "vendor.audiohal.modem_1.status", "vendor.audiohal.modem_2.status"
+};
+static const char* PROPERTY_KEY_RF_INFO[2] = {
+ "vendor.audiohal.rf_info", "vendor.audiohal.rf_mode"
+};
+
+
+/** CCCI channel No */
+static const uint8_t CCCI_M2A_CHANNEL = 4;
+static const uint8_t CCCI_A2M_CHANNEL = 5;
+
+/** CCCI magic number */
+static const uint32_t CCCI_MAILBOX_MAGIC_NUMBER = 0xFFFFFFFF;
+static const uint32_t ap_working_buf_length = 4096;
+
+#define SPH_DUMP_STR_SIZE (500)
+
+
+SpeechMessengerCCCI::SpeechMessengerCCCI(modem_index_t modem_index, SpeechDriverLAD *pLad)
+ : mModemIndex(modem_index), mLad(pLad) {
+ ALOGD("%s()", __FUNCTION__);
+ CCCIEnable = false;
+
+ fHdlRead = -1;
+ fHdlWrite = -1;
+
+ mA2MShareBufLen = 0;
+ mM2AShareBufLen = 0;
+
+ mA2MShareBufBase = NULL;
+ mM2AShareBufBase = NULL;
+
+ mA2MShareBufEnd = NULL;
+ mM2AShareBufEnd = NULL;
+ mWasModemReset = false;
+
+ //initial the message queue
+ memset((void *)pQueue, 0, sizeof(pQueue));
+ iQRead = 0;
+ iQWrite = 0;
+
+ mWaitAckMessageID = 0;
+ LastSentMessage = 0;
+ LastNeedAckSentMessage = 0;
+
+ //initial modem side modem status
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_MODEM_STATUS[mModemIndex], property_value, "0"); //"0": default all off
+ mModemSideModemStatus = atoi(property_value);
+ ALOGD("%s(), mModemIndex(%d), property read(0x%x)", __FUNCTION__, mModemIndex, mModemSideModemStatus);
+
+ ResetSpeechParamAckCount();
+
+ mIsModemResetDuringPhoneCall = false;
+ mIsModemReset = false;
+ mIsModemEPOF = false;
+}
+
+status_t SpeechMessengerCCCI::Initial() {
+ // Open CCCI and get handler
+ char dev_node_read[32], dev_node_write[32];
+ switch (mModemIndex) {
+ case MODEM_1:
+ snprintf(dev_node_read, 32, "%s", ccci_get_node_name(USR_AUDIO_RX, MD_SYS1));
+ snprintf(dev_node_write, 32, "%s", ccci_get_node_name(USR_AUDIO_TX, MD_SYS1));
+ break;
+ default:
+ snprintf(dev_node_read, 32, "%s", ccci_get_node_name(USR_AUDIO_RX, MD_SYS1));
+ snprintf(dev_node_write, 32, "%s", ccci_get_node_name(USR_AUDIO_TX, MD_SYS1));
+ break;
+ }
+ ALOGD("%s(), dev_node_read=%s, dev_node_write=%s", __FUNCTION__, dev_node_read, dev_node_write);
+ fHdlRead = open(dev_node_read, O_RDWR);
+ fHdlWrite = open(dev_node_write, O_RDWR);
+
+ if (fHdlRead < 0 || fHdlWrite < 0) {
+ ALOGE("%s(), fail to open %s or %s", __FUNCTION__, dev_node_read, dev_node_write);
+ return UNKNOWN_ERROR;
+ }
+
+ // Get total share buffer length & base address
+ uint32_t share_buf_length;
+ char *share_buf_address;
+
+ ::ioctl(fHdlRead, CCCI_IOC_PCM_LEN, &share_buf_length);
+ ALOGD("%s(), ioctl share_buf_length=%d", __FUNCTION__, share_buf_length);
+
+ share_buf_address = (char *)mmap(NULL, share_buf_length, PROT_READ | PROT_WRITE, MAP_SHARED, fHdlRead, 0);
+ ALOGD("%s(), ShareBufAdd:0x%p, ShareBufLen:%u", __FUNCTION__, share_buf_address, share_buf_length);
+
+ mA2MShareBufLen = share_buf_length >> 1; // a2m buffer lengh should be half of share_buf_length
+ mM2AShareBufLen = share_buf_length >> 1; // m2a buffer lengh should be half of share_buf_length
+
+ mA2MShareBufBase = share_buf_address;
+ mM2AShareBufBase = share_buf_address + mA2MShareBufLen;
+
+ mA2MShareBufEnd = mA2MShareBufBase + mA2MShareBufLen;
+ mM2AShareBufEnd = mM2AShareBufBase + mM2AShareBufLen;
+
+ mSphCCCITmpBuf = new char[ap_working_buf_length];
+ mSphPCMBuf = new char[ap_working_buf_length];
+
+ mSphPCMBufEnd = mSphPCMBuf + ap_working_buf_length;
+
+ pcm_ring_buf.bufLen = ap_working_buf_length;
+ pcm_ring_buf.pBufBase = mSphPCMBuf;
+ pcm_ring_buf.pRead = pcm_ring_buf.pBufBase;
+ pcm_ring_buf.pWrite = pcm_ring_buf.pRead;
+
+ /* create the CCCI event reading thread */
+ CCCIEnable = true;
+ return CreateReadingThread();
+}
+
+status_t SpeechMessengerCCCI::Deinitial() {
+ CCCIEnable = false;
+
+ mA2MShareBufLen = 0;
+ mM2AShareBufLen = 0;
+
+ mA2MShareBufBase = NULL;
+ mM2AShareBufBase = NULL;
+
+ mA2MShareBufEnd = NULL;
+ mM2AShareBufEnd = NULL;
+ mSphPCMBufEnd = NULL;
+ if (mSphCCCITmpBuf != NULL) {
+ delete mSphCCCITmpBuf;
+ mSphCCCITmpBuf = NULL;
+ }
+
+ if (mSphPCMBuf != NULL) {
+ delete mSphPCMBuf;
+ mSphPCMBuf = NULL;
+ }
+ if (fHdlRead >= 0) { close(fHdlRead); }
+ if (fHdlWrite >= 0) { close(fHdlWrite); }
+
+ return NO_ERROR;
+}
+
+SpeechMessengerCCCI::~SpeechMessengerCCCI() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+/** Create CCCI message */
+ccci_buff_t SpeechMessengerCCCI::InitCcciMailbox(uint16_t id, uint16_t param_16bit, uint32_t param_32bit) {
+ ccci_buff_t ccci_buff;
+ memset(&ccci_buff, 0, sizeof(ccci_buff));
+
+ ccci_buff.magic = CCCI_MAILBOX_MAGIC_NUMBER;
+ ccci_buff.message = (id << 16) | param_16bit;
+ ccci_buff.channel = CCCI_A2M_CHANNEL;
+ ccci_buff.reserved = param_32bit;
+
+ return ccci_buff;
+}
+
+/** Get CCCI message's ID */
+uint16_t SpeechMessengerCCCI::GetMessageID(const ccci_buff_t &ccci_buff) {
+ return (ccci_buff.message) >> 16;
+}
+
+/** Get CCCI message's parameters */
+uint16_t SpeechMessengerCCCI::GetMessageParam(const ccci_buff_t &ccci_buff) {
+ return (ccci_buff.message) & 0xFFFF;
+}
+
+uint16_t SpeechMessengerCCCI::GetMessageLength(const ccci_buff_t &ccci_buff) {
+ return (ccci_buff.message) & 0xFFFF; //GetMessageParam(ccci_buff);
+}
+
+uint16_t SpeechMessengerCCCI::GetMessageOffset(const ccci_buff_t &ccci_buff) {
+ return (ccci_buff.reserved) & 0xFFFF;
+}
+
+
+char SpeechMessengerCCCI::GetModemCurrentStatus() {
+ unsigned int retStatus = (unsigned int)MODEM_STATUS_INVALID;
+ char bufferStatus[2]= {0};
+ char status = (char)MODEM_STATUS_INVALID;
+
+ int retval = ::ioctl(fHdlRead, CCCI_IOC_GET_MD_STATE, &retStatus);
+ sprintf(bufferStatus, "%c", retStatus);
+ status = atoi(bufferStatus);
+
+ if (mIsModemEPOF == true) {
+ ALOGD("%s() MD EPOF!", __FUNCTION__);
+ status = MODEM_STATUS_INVALID;
+ } else if (retval < 0) {
+ ALOGE("%s() ioctl _IOR(CCCI_IOC_GET_MD_STATEt) fail!! retval = %d", __FUNCTION__, retval);
+ status = MODEM_STATUS_EXPT;
+ }
+ ALOGV("%s(): retStatus(%c), int status(%d)", __FUNCTION__, retStatus, status);
+
+ return status;
+}
+
+bool SpeechMessengerCCCI::CheckModemIsReady() {
+ return (GetModemCurrentStatus() == MODEM_STATUS_READY);
+}
+
+status_t SpeechMessengerCCCI::WaitUntilModemReady() {
+ char status = 0;
+ uint32_t trycnt = 0;
+ const uint32_t kMaxTryCnt = 10; // total 200 msec
+ do {
+ status = GetModemCurrentStatus();
+ if (status == MODEM_STATUS_READY) {
+ ALOGD("%s(), Modem ready", __FUNCTION__);
+ break;
+ } else {
+ ALOGW("%s(), Wait CCCI open #%d times, modem current status = %d, errno: %d",
+ __FUNCTION__, ++trycnt, status, errno);
+ sph_msleep(20);
+ if (trycnt == kMaxTryCnt) { break; }
+ }
+ } while (1);
+
+ return (trycnt < kMaxTryCnt) ? NO_ERROR : TIMED_OUT;
+}
+
+
+int32_t SpeechMessengerCCCI::SendMessage(const ccci_buff_t &ccci_buff) {
+ // check if already initialized
+ if (fHdlWrite < 0) {
+ if (Initial() != NO_ERROR) { return UNKNOWN_ERROR; }
+ }
+
+ // check if need ack
+ const uint16_t message_id = GetMessageID(ccci_buff);
+ const bool b_need_ack = (JudgeAckOfMsg(message_id) == MESSAGE_NEED_ACK) ? true : false;
+
+ // check modem status during phone call
+ char modem_status = GetModemCurrentStatus();
+ if (modem_status != MODEM_STATUS_READY) {
+ ALOGE("%s(), modem_status(%d) != MODEM_STATUS_READY, errno: %d, mIsModemEPOF = %d",
+ __FUNCTION__, modem_status, errno, mIsModemEPOF);
+ mIsModemResetDuringPhoneCall = true;
+ mIsModemReset = true;
+ ResetSpeechParamAckCount();
+ }
+
+ // Do not send any on/off message when mIsModemResetDuringPhoneCall is true
+ if (mIsModemResetDuringPhoneCall == true && IsModemFunctionOnOffMessage(message_id) == true) {
+ ALOGE("%s(), mIsModemResetDuringPhoneCall == true, drop on/off message: 0x%x",
+ __FUNCTION__, ccci_buff.message);
+ SendMsgFailErrorHandling(ccci_buff);
+
+ // clean mIsModemResetDuringPhoneCall when phone call/loopback stop
+ if (message_id == MSG_A2M_SPH_OFF) {
+ ALOGD("%s(), Phone call stop. Set mIsModemResetDuringPhoneCall = false", __FUNCTION__);
+ mIsModemResetDuringPhoneCall = false;
+ } else if (message_id == MSG_A2M_SET_ACOUSTIC_LOOPBACK) {
+ const bool loopback_on = GetMessageParam(ccci_buff) & 0x1;
+ if (loopback_on == false) {
+ ALOGD("%s(), loopback stop. Set mIsModemResetDuringPhoneCall = false", __FUNCTION__);
+ mIsModemResetDuringPhoneCall = false;
+ }
+ }
+
+ return UNKNOWN_ERROR;
+ }
+
+ // save ack info before write to avoid race condition with CCCIReadThread
+ if (b_need_ack == true) {
+ mWaitAckMessageID = message_id;
+ }
+
+ // send message
+ int i = 0;
+ int write_length = 0;
+ status_t ret = UNKNOWN_ERROR;
+ for (i = 0; i < 150; i++) { // try 150 times for every 2 ms if sent message fail
+ write_length = write(fHdlWrite, (void *)&ccci_buff, CCCI_BUF_HEADER_SIZE);
+ if (write_length == CCCI_BUF_HEADER_SIZE) {
+ LastSentMessage = message_id;
+ if (MESSAGE_NEED_ACK == JudgeAckOfMsg(message_id)) {
+ LastNeedAckSentMessage = message_id;
+ }
+ ret = NO_ERROR;
+ break;
+ } else {
+ modem_status = GetModemCurrentStatus();
+ ALOGW("%s(), message: 0x%x, try: #%d, write_length: %d, errno: %d, modem status: %d",
+ __FUNCTION__, ccci_buff.message, i, write_length, errno, modem_status);
+
+ if (errno == 3 || modem_status != MODEM_STATUS_READY) { // md reset cause ccci message fail
+ ALOGE("%s(), MD RESET SKIP MESSAGE: 0x%x", __FUNCTION__, ccci_buff.message);
+ // if modem reset during phone call, raise mIsModemResetDuringPhoneCall
+ if (message_id != MSG_A2M_SPH_OFF && message_id != MSG_A2M_SET_ACOUSTIC_LOOPBACK) {
+ mIsModemResetDuringPhoneCall = true;
+ }
+ mIsModemReset = true;
+
+ ResetSpeechParamAckCount();
+ break;
+ }
+ sph_msleep(2);
+ }
+ }
+
+ // error handling for ack message
+ if (ret != NO_ERROR && b_need_ack == true) {
+ mWaitAckMessageID = 0;
+ SendMsgFailErrorHandling(ccci_buff);
+ }
+
+
+ return ret;
+}
+
+status_t SpeechMessengerCCCI::ReadMessage(ccci_buff_t &ccci_buff) {
+ ALOGV("%s()", __FUNCTION__);
+ /* check if already initialized */
+ if (fHdlRead < 0) {
+ if (Initial() != NO_ERROR) { return UNKNOWN_ERROR; }
+ }
+
+ /* read message */
+ int read_length = read(fHdlRead, (void *)&ccci_buff, CCCI_BUF_HEADER_SIZE);
+
+ uint16_t message_id = GetMessageID(ccci_buff);
+ if (message_id == MSG_M2A_EM_DATA_REQUEST) {
+ mIsModemEPOF = false;
+ }
+
+ if (read_length != CCCI_BUF_HEADER_SIZE && GetModemCurrentStatus() != MODEM_STATUS_READY) {
+ ALOGE("%s() fail, read_length: %d, modem current status: %d",
+ __FUNCTION__, read_length, GetModemCurrentStatus());
+ return UNKNOWN_ERROR;
+ } else if (read_length != -1) {
+ ALOGV("%s(), read_length=%d, data[0](magic)=0x%x, data[1](message)=0x%x, ch=0x%x, reserved=0x%x",
+ __FUNCTION__, read_length, ccci_buff.magic, ccci_buff.message, ccci_buff.channel, ccci_buff.reserved);
+ }
+ return NO_ERROR;
+}
+
+
+uint32_t SpeechMessengerCCCI::GetQueueCount() const {
+ int32_t count = (iQWrite - iQRead);
+ if (count < 0) { count += CCCI_MAX_QUEUE_NUM; }
+ return count;
+}
+
+bool SpeechMessengerCCCI::CheckOffsetAndLength(const ccci_buff_t &ccci_buff) {
+ uint16_t message_id = GetMessageID(ccci_buff);
+ uint16_t length = GetMessageLength(ccci_buff);
+ uint16_t offset = GetMessageOffset(ccci_buff);
+ ALOGV("%s(), CheckOffsetAndLength message_id 0x%x , length 0x%x, offset 0x%x",
+ __FUNCTION__, message_id, length, offset);
+ if (offset > mM2AShareBufLen || length > mM2AShareBufLen) {
+ ALOGE("%s(), message_id = 0x%x, length(0x%x), offset(0x%x), mM2AShareBufLen(0x%x)",
+ __FUNCTION__, message_id, length, offset, mM2AShareBufLen);
+ ASSERT(offset > mM2AShareBufLen || length > mM2AShareBufLen);
+ return false;
+ } else {
+ return true;
+ }
+}
+
+
+ccci_message_ack_t SpeechMessengerCCCI::JudgeAckOfMsg(const uint16_t message_id) {
+ ccci_message_ack_t ack;
+ switch (message_id) {
+ case MSG_A2M_SET_SPH_MODE:
+ case MSG_A2M_SPH_ON:
+ case MSG_A2M_SPH_OFF:
+ case MSG_A2M_SPH_ROUTER_ON:
+#ifdef SPEECH_PCM_VM_SUPPORT
+ case MSG_A2M_PCM_REC_ON:
+ case MSG_A2M_VM_REC_ON:
+ case MSG_A2M_PCM_REC_OFF:
+ case MSG_A2M_VM_REC_OFF:
+#else
+ case MSG_A2M_RECORD_ON:
+ case MSG_A2M_RECORD_OFF:
+#endif
+ case MSG_A2M_BGSND_ON:
+ case MSG_A2M_BGSND_OFF:
+ case MSG_A2M_PNW_ON:
+ case MSG_A2M_PNW_OFF:
+ case MSG_A2M_CTM_ON:
+ case MSG_A2M_CTM_OFF:
+ case MSG_A2M_SET_ACOUSTIC_LOOPBACK:
+ case MSG_A2M_EM_NB:
+ case MSG_A2M_EM_DMNR:
+ case MSG_A2M_EM_MAGICON:
+ case MSG_A2M_EM_HAC:
+ case MSG_A2M_EM_WB:
+ //#if defined(MTK_VIBSPK_SUPPORT)
+ case MSG_A2M_VIBSPK_PARAMETER:
+ //#endif
+ case MSG_A2M_SMARTPA_PARAMETER:
+ case MSG_A2M_RECORD_RAW_PCM_ON:
+ case MSG_A2M_RECORD_RAW_PCM_OFF:
+ ack = MESSAGE_NEED_ACK;
+ break;
+ default:
+ ack = MESSAGE_BYPASS_ACK;
+ }
+ return ack;
+}
+
+bool SpeechMessengerCCCI::IsModemFunctionOnOffMessage(const uint16_t message_id) {
+ bool bIsModemFunctionOnOffMessage = false;
+
+ switch (message_id) {
+ case MSG_A2M_SPH_ON:
+ case MSG_A2M_SPH_OFF:
+ case MSG_A2M_SPH_ROUTER_ON:
+#ifdef SPEECH_PCM_VM_SUPPORT
+ case MSG_A2M_PCM_REC_ON:
+ case MSG_A2M_VM_REC_ON:
+ case MSG_A2M_PCM_REC_OFF:
+ case MSG_A2M_VM_REC_OFF:
+#else
+ case MSG_A2M_RECORD_ON:
+ case MSG_A2M_RECORD_OFF:
+#endif
+ case MSG_A2M_BGSND_ON:
+ case MSG_A2M_BGSND_OFF:
+ case MSG_A2M_PNW_ON:
+ case MSG_A2M_PNW_OFF:
+ case MSG_A2M_CTM_ON:
+ case MSG_A2M_CTM_OFF:
+ case MSG_A2M_SET_ACOUSTIC_LOOPBACK:
+ case MSG_A2M_RECORD_RAW_PCM_ON:
+ case MSG_A2M_RECORD_RAW_PCM_OFF:
+ bIsModemFunctionOnOffMessage = true;
+ break;
+ default:
+ bIsModemFunctionOnOffMessage = false;
+ }
+
+ return bIsModemFunctionOnOffMessage;
+}
+
+status_t SpeechMessengerCCCI::SendMessageInQueue(ccci_buff_t ccci_buff) {
+ AL_LOCK(mCCCIMessageQueueMutex);
+
+ uint32_t count = GetQueueCount();
+ ASSERT(count < (CCCI_MAX_QUEUE_NUM - 1)); // check queue full
+
+ ccci_message_ack_t ack_type = JudgeAckOfMsg(GetMessageID(ccci_buff));
+
+ if (ack_type == MESSAGE_NEED_ACK) {
+ ALOGD("%s(), mModemIndex = %d, need ack message: 0x%x, reserved param: 0x%x",
+ __FUNCTION__, mModemIndex, ccci_buff.message, ccci_buff.reserved);
+ }
+
+
+ status_t ret = NO_ERROR;
+
+ if (mIsModemEPOF == true) {
+ ALOGD("%s(), mIsModemEPOF=%d, Skip message(0x%x) to queue, now count(%u)",
+ __FUNCTION__, mIsModemEPOF, ccci_buff.message, GetQueueCount());
+ A2MBufUnLock();
+
+ } else {
+
+ if (count == 0) { // queue is empty
+ if (ack_type == MESSAGE_BYPASS_ACK) { // no need ack, send directly, don't care ret value
+ ret = SendMessage(ccci_buff);
+ } else { // need ack, en-queue and send message
+ pQueue[iQWrite].ccci_buff = ccci_buff;
+ pQueue[iQWrite].ack_type = ack_type;
+ iQWrite++;
+ if (iQWrite == CCCI_MAX_QUEUE_NUM) { iQWrite -= CCCI_MAX_QUEUE_NUM; }
+
+ ret = SendMessage(ccci_buff);
+ if (ret != NO_ERROR) { // skip this fail CCCI message
+ iQRead++;
+ if (iQRead == CCCI_MAX_QUEUE_NUM) { iQRead -= CCCI_MAX_QUEUE_NUM; }
+ }
+ }
+ } else { // queue is not empty, must queue the element
+ pQueue[iQWrite].ccci_buff = ccci_buff;
+ pQueue[iQWrite].ack_type = ack_type;
+ iQWrite++;
+ if (iQWrite == CCCI_MAX_QUEUE_NUM) { iQWrite -= CCCI_MAX_QUEUE_NUM; }
+
+ ALOGD("%s(), Send message(0x%x) to queue, reserve param(0x%x), mModemIndex(%d),count(%u), "
+ "LastSentMessage(0x%x), LastNeedAckSentMessage(0x%x)",
+ __FUNCTION__, ccci_buff.message, ccci_buff.reserved, mModemIndex, GetQueueCount(),
+ LastSentMessage, LastNeedAckSentMessage);
+ }
+ }
+ AL_UNLOCK(mCCCIMessageQueueMutex);
+ return ret;
+}
+
+status_t SpeechMessengerCCCI::ConsumeMessageInQueue() {
+ AL_LOCK(mCCCIMessageQueueMutex);
+
+ uint32_t count = GetQueueCount();
+ if (count > 10) {
+ ALOGW("%s(), queue count: %u", __FUNCTION__, count);
+ }
+
+ if (count == 0) {
+ ALOGW("%s(), no message in queue", __FUNCTION__);
+ AL_UNLOCK(mCCCIMessageQueueMutex);
+ return UNKNOWN_ERROR;
+ }
+
+ status_t ret = NO_ERROR;
+ while (1) {
+ // when entering this function, the first message in queue must be a message waiting for ack
+ // so we increment index, consuming the first message in queue
+ iQRead++;
+ if (iQRead == CCCI_MAX_QUEUE_NUM) { iQRead -= CCCI_MAX_QUEUE_NUM; }
+
+ // check if empty
+ if (iQRead == iQWrite) {
+ ret = NO_ERROR;
+ break;
+ }
+
+ // update count
+ count = GetQueueCount();
+
+ // send message
+ if (pQueue[iQRead].ack_type == MESSAGE_BYPASS_ACK) { // no need ack, send directly, don't care ret value
+ ALOGD("%s(), no need ack message: 0x%x, count: %u", __FUNCTION__, pQueue[iQRead].ccci_buff.message, count);
+ ret = SendMessage(pQueue[iQRead].ccci_buff);
+ } else if (pQueue[iQRead].ack_type == MESSAGE_NEED_ACK) {
+ ALOGD("%s(), need ack message: 0x%x, count: %u", __FUNCTION__, pQueue[iQRead].ccci_buff.message, count);
+ ret = SendMessage(pQueue[iQRead].ccci_buff);
+ if (ret == NO_ERROR) { // Send CCCI message success and wait for ack
+ break;
+ }
+ } else if (pQueue[iQRead].ack_type == MESSAGE_CANCELED) { // the cancelled message, ignore it
+ ALOGD("%s(), cancel on-off-on message: 0x%x, count: %u",
+ __FUNCTION__, pQueue[iQRead].ccci_buff.message, count);
+ ret = NO_ERROR;
+ }
+ }
+
+ AL_UNLOCK(mCCCIMessageQueueMutex);
+ return ret;
+}
+
+bool SpeechMessengerCCCI::GetMDResetFlag() {
+ ALOGD("%s(), mIsModemReset=%d", __FUNCTION__, mIsModemReset);
+ return mIsModemReset;
+}
+
+bool SpeechMessengerCCCI::MDReset_CheckMessageInQueue() {
+ AL_LOCK(mCCCIMessageQueueMutex);
+ uint32_t count = GetQueueCount();
+ ALOGD("%s(), queue count: %u", __FUNCTION__, count);
+
+ bool ret = true;
+ while (1) {
+ // Modem already reset.
+ // Check every CCCI message in queue.
+ // These messages that are sent before modem reset, don't send to modem.
+ // But AP side need to do related action to make AP side in the correct state.
+
+ // check if empty
+ if (iQRead == iQWrite) {
+ ALOGD("%s(), check message done", __FUNCTION__);
+ ret = true;
+ break;
+ }
+
+ // Need ack message. But modem reset, so simulate that the modem send back ack msg.
+ if (JudgeAckOfMsg(GetMessageID(pQueue[iQRead].ccci_buff)) == MESSAGE_NEED_ACK) {
+ SendMsgFailErrorHandling(pQueue[iQRead].ccci_buff);
+ }
+
+ iQRead++;
+ if (iQRead == CCCI_MAX_QUEUE_NUM) { iQRead -= CCCI_MAX_QUEUE_NUM; }
+ }
+ if (count != 0) {
+ ALOGE("%s(), queue is not empty!!", __FUNCTION__);
+ iQWrite = 0;
+ iQRead = 0;
+ }
+
+ AL_UNLOCK(mCCCIMessageQueueMutex);
+ return ret;
+}
+
+status_t SpeechMessengerCCCI::CreateReadingThread() {
+ int ret = pthread_create(&hReadThread, NULL, SpeechMessengerCCCI::CCCIReadThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+ return NO_ERROR;
+}
+
+void *SpeechMessengerCCCI::CCCIReadThread(void *arg) {
+ pthread_detach(pthread_self());
+
+ prctl(PR_SET_NAME, (unsigned long)__FUNCTION__, 0, 0, 0);
+
+ SpeechMessengerCCCI *pCCCI = (SpeechMessengerCCCI *)arg;
+#if 1
+ // Adjust thread priority
+ int rtnPrio = setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+ if (0 != rtnPrio) {
+ ALOGE("[%s] failed, errno: %d, return=%d", __FUNCTION__, errno, rtnPrio);
+ } else {
+ ALOGD("%s setpriority ok, priority: %d", __FUNCTION__, ANDROID_PRIORITY_AUDIO);
+ }
+#else
+
+ // force to set priority
+ struct sched_param sched_p;
+ sched_getparam(0, &sched_p);
+ sched_p.sched_priority = RTPM_PRIO_AUDIO_CCCI_THREAD;
+ if (0 != sched_setscheduler(0, SCHED_RR, &sched_p)) {
+ ALOGE("[%s] failed, errno: %d", __FUNCTION__, errno);
+ } else {
+ sched_p.sched_priority = RTPM_PRIO_AUDIO_CCCI_THREAD;
+ sched_getparam(0, &sched_p);
+ ALOGD("sched_setscheduler ok, priority: %d", sched_p.sched_priority);
+ }
+#endif
+ ALOGD("%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+
+
+ // Handle CCCI Message From Modems
+ while (pCCCI->CCCIEnable) {
+ /// read message
+ ccci_buff_t ccci_buff;
+ memset((void *)&ccci_buff, 0, sizeof(ccci_buff));
+ status_t ret = pCCCI->ReadMessage(ccci_buff);
+ if (ret != NO_ERROR) {
+ ALOGD("%s(), ret(%d) != NO_ERROR", __FUNCTION__, ret);
+ sph_msleep(10);
+ continue;
+ }
+
+ /// handle message
+ uint16_t m2a_message_id = pCCCI->GetMessageID(ccci_buff);
+ ALOGV("%s(), m2a_message_id = 0x%x", __FUNCTION__, m2a_message_id);
+
+ switch (m2a_message_id) {
+ case MSG_M2A_SET_SPH_MODE_ACK: { // ack of MSG_A2M_SET_SPH_MODE
+ // Do nothing... just leave a log
+ ALOGD("--SetSpeechMode Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Speech */
+ case MSG_M2A_SPH_ON_ACK: { // ack of MSG_A2M_SPH_ON
+ phone_call_mode_t phone_call_mode = (phone_call_mode_t)pCCCI->GetMessageParam(ccci_buff);
+ if (phone_call_mode == RAT_3G324M_MODE) {
+ pCCCI->SetModemSideModemStatus(VT_STATUS_MASK);
+ } else {
+ pCCCI->SetModemSideModemStatus(SPEECH_STATUS_MASK);
+ }
+
+ //pCCCI->mLad->Signal();
+
+ ALOGD("--SpeechOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_SPH_OFF_ACK: { // ack of MSG_A2M_SPH_OFF
+ if (pCCCI->GetModemSideModemStatus(VT_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(VT_STATUS_MASK);
+ } else if (pCCCI->GetModemSideModemStatus(SPEECH_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(SPEECH_STATUS_MASK);
+ } else {
+ ALOGE("--SpeechOff Ack is not paired!!");
+ }
+
+ pCCCI->mLad->Signal();
+
+ ALOGD("--SpeechOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Speech Router */
+ case MSG_M2A_SPH_ROUTER_ON_ACK: { // ack of MSG_A2M_SPH_ROUTER_ON
+ const bool pcm_route_on = pCCCI->GetMessageParam(ccci_buff) & 0x1;
+ if (pcm_route_on == true) { // pcm route on
+ pCCCI->SetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+ } else { // pcm route off
+ if (pCCCI->GetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+ } else {
+ ALOGE("--SpeechRouterOn Ack is not paired!!");
+ }
+ }
+
+ ALOGD("--SpeechRouterOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ //case MSG_M2A_SPH_TYPE_NOTIFY://0xAF29
+ case MSG_M2A_NETWORK_STATUS_NOTIFY: {
+ //speech network type change
+ bool nb = ((ccci_buff.message & 0x8) >> 3) ? false : true;
+#ifdef MTK_AUDIO_GAIN_TABLE
+ AudioVolumeFactory::CreateAudioVolumeController()->speechBandChange(nb);
+#endif
+
+ //pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_SPH_TYPE_ACK, 0, 0));//0x2F29
+ ALOGD("--MSG_M2A_NETWORK_STATUS_NOTIFY (0x%x)", ccci_buff.message);
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_NETWORK_STATUS_ACK, 0, 0));
+ break;
+ }
+ /* Record */
+#ifdef SPEECH_PCM_VM_SUPPORT
+ case MSG_M2A_PCM_REC_ON_ACK: { // ack of MSG_A2M_PCM_REC_ON
+ pCCCI->SetModemSideModemStatus(RECORD_STATUS_MASK);
+ ALOGD("--recordOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ case MSG_M2A_VM_REC_ON_ACK: { // ack of MSG_A2M_VM_REC_ON
+ pCCCI->SetModemSideModemStatus(VM_RECORD_STATUS_MASK);
+ ALOGD("--VMRecordOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+#else
+ case MSG_M2A_RECORD_ON_ACK: { // ack of MSG_A2M_RECORD_ON
+ pCCCI->SetModemSideModemStatus(RECORD_STATUS_MASK);
+ ALOGD("--recordOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+#endif
+
+ case MSG_M2A_RECORD_RAW_PCM_ON_ACK: { // ack of MSG_A2M_RECORD_RAW_PCM_ON
+ pCCCI->SetModemSideModemStatus(RAW_RECORD_STATUS_MASK);
+ ALOGD("--RawRecordOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+
+#ifdef SPEECH_PCM_VM_SUPPORT
+ case MSG_M2A_PCM_REC_DATA_NOTIFY: { // meaning that we are recording, modem have some data
+ ALOGD("%s() MSG_M2A_PCM_REC_DATA_NOTIFY", __FUNCTION__);
+ ASSERT(pCCCI->GetModemSideModemStatus(RECORD_STATUS_MASK) == true);
+
+ if (pCCCI->mLad->GetApSideModemStatus(RECORD_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_PCM_REC_DATA_NOTIFY(0x%x) after AP side trun off record!! Drop it.", ccci_buff.message);
+ } else {
+ ALOGV("MSG_M2A_REC_DATA_NOTIFY(0x%x), data_length: %d",
+ ccci_buff.message, pCCCI->GetMessageLength(ccci_buff) - CCCI_SHARE_BUFF_HEADER_LEN);
+
+ // Phone record
+ AudioALSACaptureDataProviderVoice::getInstance()->provideModemRecordDataToProvider(
+ pCCCI->GetM2AUplinkRingBuffer(ccci_buff));
+
+ if (pCCCI->mLad->GetApSideModemStatus(RECORD_STATUS_MASK) == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_PCM_REC_DATA_READ_ACK, 0, 0));
+ }
+ }
+
+ break;
+ }
+
+ case MSG_M2A_VM_REC_DATA_NOTIFY: { // meaning that we are recording, modem have some data
+ ASSERT(pCCCI->GetModemSideModemStatus(VM_RECORD_STATUS_MASK) == true);
+
+ if (pCCCI->mLad->GetApSideModemStatus(VM_RECORD_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_VM_REC_DATA_NOTIFY(0x%x) after AP side trun off record!! Drop it.", ccci_buff.message);
+ } else {
+ ALOGV("MSG_M2A_VM_REC_DATA_NOTIFY(0x%x), data_length: %d",
+ ccci_buff.message, pCCCI->GetMessageLength(ccci_buff) - CCCI_SHARE_BUFF_HEADER_LEN);
+
+ SpeechVMRecorder *pSpeechVMRecorder = SpeechVMRecorder::getInstance();
+ // VM
+ pSpeechVMRecorder->getVmDataFromModem(pCCCI->GetM2AUplinkRingBuffer(ccci_buff));
+
+ if (pCCCI->mLad->GetApSideModemStatus(VM_RECORD_STATUS_MASK) == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_VM_REC_DATA_READ_ACK, 0, 0));
+ }
+ }
+
+ break;
+ }
+#else
+ case MSG_M2A_REC_DATA_NOTIFY: { // meaning that we are recording, modem have some data
+ ASSERT(pCCCI->GetModemSideModemStatus(RECORD_STATUS_MASK) == true);
+
+ if (pCCCI->mLad->GetApSideModemStatus(RECORD_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_REC_DATA_NOTIFY(0x%x) after AP side trun off record!! Drop it.", ccci_buff.message);
+ } else {
+ ALOGV("MSG_M2A_REC_DATA_NOTIFY(0x%x), data_length: %d",
+ ccci_buff.message, pCCCI->GetMessageLength(ccci_buff) - CCCI_SHARE_BUFF_HEADER_LEN);
+
+ SpeechVMRecorder *pSpeechVMRecorder = SpeechVMRecorder::getInstance();
+ if (pSpeechVMRecorder->getVMRecordStatus() == true) { // VM
+ pSpeechVMRecorder->getVmDataFromModem(pCCCI->GetM2AUplinkRingBuffer(ccci_buff));
+ } else { // Phone record
+ AudioALSACaptureDataProviderVoice::getInstance()->provideModemRecordDataToProvider(
+ pCCCI->GetM2AUplinkRingBuffer(ccci_buff));
+ }
+
+ if (pCCCI->mLad->GetApSideModemStatus(RECORD_STATUS_MASK) == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_REC_DATA_READ_ACK, 0, 0));
+ }
+ }
+
+ break;
+ }
+
+#endif
+ case MSG_M2A_RAW_PCM_REC_DATA_NOTIFY: { // meaning that we are recording, modem have some data
+ ALOGD("%s() MSG_M2A_RAW_PCM_REC_DATA_NOTIFY", __FUNCTION__);
+ ASSERT(pCCCI->GetModemSideModemStatus(RAW_RECORD_STATUS_MASK) == true);
+
+ if (pCCCI->mLad->GetApSideModemStatus(RAW_RECORD_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_PCM_REC_DATA_NOTIFY(0x%x) after AP side trun off record!! Drop it.", ccci_buff.message);
+ } else {
+ uint16_t Bytes_PCM = pCCCI->GetMessageLength(ccci_buff) - CCCI_SHARE_BUFF_HEADER_LEN;
+ SLOGV("MSG_M2A_PCM_REC_DATA_NOTIFY(0x%x), data_length: %d", ccci_buff.message, Bytes_PCM);
+
+ // Phone record
+ SpeechDataProcessingHandler::getInstance()->provideModemRecordDataToProvider(
+ pCCCI->GetM2ARawPcmRingBuffer(ccci_buff));
+
+ if (pCCCI->mLad->GetApSideModemStatus(RAW_RECORD_STATUS_MASK) == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_RAW_PCM_REC_DATA_READ_ACK, 0, 0));
+ } else {
+ ALOGD("%s() RAW_RECORD_STATUS_MASK(%d)",
+ __FUNCTION__, pCCCI->mLad->GetApSideModemStatus(RAW_RECORD_STATUS_MASK));
+ }
+ }
+
+ break;
+ }
+#ifdef SPEECH_PCM_VM_SUPPORT
+ case MSG_M2A_PCM_REC_OFF_ACK: { // ack of MSG_A2M_PCM_REC_OFF
+ if (pCCCI->GetModemSideModemStatus(RECORD_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--recordOff Ack is not paired!!");
+ }
+ ALOGD("--recordOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_VM_REC_OFF_ACK: { // ack of MSG_A2M_VM_REC_OFF
+ if (pCCCI->GetModemSideModemStatus(VM_RECORD_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(VM_RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--VMRecordOff Ack is not paired!!");
+ }
+ ALOGD("--VMRecordOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+#else
+ case MSG_M2A_RECORD_OFF_ACK: { // ack of MSG_A2M_RECORD_OFF
+ if (pCCCI->GetModemSideModemStatus(RECORD_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--recordOff Ack is not paired!!");
+ }
+ ALOGD("--recordOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+#endif
+ case MSG_M2A_RECORD_RAW_PCM_OFF_ACK: { // ack of MSG_A2M_RECORD_RAW_PCM_OFF
+ if (pCCCI->GetModemSideModemStatus(RAW_RECORD_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(RAW_RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--RawRecordOff Ack is not paired!!");
+ }
+ ALOGD("--RawRecordOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Background sound */
+ case MSG_M2A_BGSND_ON_ACK: { // ack of MSG_A2M_BGSND_ON
+ pCCCI->SetModemSideModemStatus(BGS_STATUS_MASK);
+ ALOGD("--BGSoundOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_BGSND_DATA_REQUEST: { // modem request bgs data to play
+ ASSERT(pCCCI->GetModemSideModemStatus(BGS_STATUS_MASK) == true);
+
+ BGSPlayer *pBGSPlayer = BGSPlayer::GetInstance();
+ if (pCCCI->mLad->GetApSideModemStatus(BGS_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_BGSND_DATA_REQUEST(0x%x) after AP side trun off BGS!! Drop it.", ccci_buff.message);
+ } else {
+ SLOGV("MSG_M2A_BGSND_DATA_REQUEST(0x%x), num_data_request: %d",
+ ccci_buff.message, pCCCI->GetMessageParam(ccci_buff));
+
+ // parse size of data request
+ uint16_t num_data_request = pCCCI->GetMessageParam(ccci_buff);
+ uint32_t max_buf_length = A2M_SHARED_BUFFER_BGS_DATA_SIZE;
+ if (num_data_request > max_buf_length) { num_data_request = max_buf_length; }
+
+ // get bgs share buffer address
+ uint16_t offset = A2M_SHARED_BUFFER_BGS_DATA_BASE;
+ char *p_header_address = pCCCI->GetA2MShareBufBase() + offset;
+ char *p_data_address = p_header_address + CCCI_SHARE_BUFF_HEADER_LEN;
+
+ // fill playback data
+ uint16_t data_length = pBGSPlayer->PutDataToSpeaker(p_data_address, num_data_request);
+
+ // fill header info
+ pCCCI->SetShareBufHeader((uint16_t *)p_header_address,
+ CCCI_A2M_SHARE_BUFF_HEADER_SYNC,
+ SHARE_BUFF_DATA_TYPE_CCCI_BGS_TYPE,
+ data_length);
+
+ // send data notify to modem side
+ const uint16_t message_length = CCCI_SHARE_BUFF_HEADER_LEN + data_length;
+ if (pCCCI->mLad->GetApSideModemStatus(BGS_STATUS_MASK) == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_BGSND_DATA_NOTIFY, message_length, offset));
+ }
+ }
+
+ break;
+ }
+ case MSG_M2A_BGSND_OFF_ACK: { // ack of MSG_A2M_BGSND_OFF
+ if (pCCCI->GetModemSideModemStatus(BGS_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(BGS_STATUS_MASK);
+ } else {
+ ALOGE("--BGSoundOff Ack is not paired!!");
+ }
+ ALOGD("--BGSoundOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* PCM2Way */
+ case MSG_M2A_PNW_ON_ACK: { // ack of MSG_A2M_PNW_ON
+ pCCCI->SetModemSideModemStatus(P2W_STATUS_MASK);
+ ALOGD("--PCM2WayOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_PNW_UL_DATA_NOTIFY: { // Get Microphone data from Modem
+ ASSERT(pCCCI->GetModemSideModemStatus(P2W_STATUS_MASK) == true);
+
+ Record2Way *pRecord2Way = Record2Way::GetInstance();
+ if (pCCCI->mLad->GetApSideModemStatus(P2W_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_PNW_UL_DATA_NOTIFY(0x%x) after AP side trun off PCM2Way!! Drop it.", ccci_buff.message);
+ } else {
+ ALOGD("MSG_M2A_PNW_UL_DATA_NOTIFY(0x%x), data_length:%d",
+ ccci_buff.message, pCCCI->GetMessageLength(ccci_buff) - CCCI_SHARE_BUFF_HEADER_LEN);
+ pRecord2Way->GetDataFromMicrophone(pCCCI->GetM2AUplinkRingBuffer(ccci_buff));
+ if (pCCCI->mLad->GetApSideModemStatus(P2W_STATUS_MASK) == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_PNW_UL_DATA_READ_ACK, 0, 0));
+ }
+ }
+
+#if 0 // PCM2WAY: UL -> DL Loopback
+ // Used for debug and Speech DVT
+ uint16_t size_bytes = 320;
+ char buffer[320];
+ pRecord2Way->Read(buffer, size_bytes);
+ Play2Way::GetInstance()->Write(buffer, size_bytes);
+#endif
+ break;
+ }
+ case MSG_M2A_PNW_DL_DATA_REQUEST: { // Put Data to modem and play
+ ASSERT(pCCCI->GetModemSideModemStatus(P2W_STATUS_MASK) == true);
+
+ if (pCCCI->mLad->GetApSideModemStatus(P2W_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_PNW_DL_DATA_REQUEST(0x%x) after AP side trun off PCM2Way! Drop it.", ccci_buff.message);
+ } else {
+ SLOGV("MSG_M2A_PNW_DL_DATA_REQUEST(0x%x), num_data_request: %d",
+ ccci_buff.message, pCCCI->GetMessageParam(ccci_buff));
+
+ // parse size of data request
+ uint16_t num_data_request = pCCCI->GetMessageParam(ccci_buff);
+ uint32_t max_buf_length = A2M_SHARED_BUFFER_P2W_DL_DATA_SIZE;
+ if (num_data_request > max_buf_length) { num_data_request = max_buf_length; }
+
+ // get pcm2way share buffer address
+ uint16_t offset = A2M_SHARED_BUFFER_P2W_DL_DATA_BASE;
+ char *p_header_address = pCCCI->GetA2MShareBufBase() + offset;
+ char *p_data_address = p_header_address + CCCI_SHARE_BUFF_HEADER_LEN;
+
+ // fill playback data
+ Play2Way *pPlay2Way = Play2Way::GetInstance();
+ const uint16_t data_length = pPlay2Way->PutDataToSpeaker(p_data_address, num_data_request);
+
+ // fill header info
+ pCCCI->SetShareBufHeader((uint16_t *)p_header_address,
+ CCCI_A2M_SHARE_BUFF_HEADER_SYNC,
+ SHARE_BUFF_DATA_TYPE_PCM_FillSpk,
+ data_length);
+
+ // send data notify to modem side
+ const uint16_t message_length = CCCI_SHARE_BUFF_HEADER_LEN + data_length;
+ if (pCCCI->mLad->GetApSideModemStatus(P2W_STATUS_MASK) == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_PNW_DL_DATA_NOTIFY, message_length, offset));
+ }
+ }
+ break;
+ }
+ case MSG_M2A_PNW_OFF_ACK: { // ack of MSG_A2M_PNW_OFF
+ if (pCCCI->GetModemSideModemStatus(P2W_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(P2W_STATUS_MASK);
+ } else {
+ ALOGE("--PCM2WayOff Ack is not paired!!");
+ }
+ ALOGD("--PCM2WayOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* TTY */
+ case MSG_M2A_CTM_ON_ACK: { // ack of MSG_A2M_CTM_ON
+ pCCCI->SetModemSideModemStatus(TTY_STATUS_MASK);
+ ALOGD("--TtyCtmOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_CTM_DEBUG_DATA_NOTIFY: {
+ if (pCCCI->mLad->GetApSideModemStatus(TTY_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_CTM_DEBUG_DATA_NOTIFY(0x%x) after AP side trun off TTY!! Drop it.", ccci_buff.message);
+ } else {
+ SLOGV("MSG_M2A_CTM_DEBUG_DATA_NOTIFY(0x%x), data_length: %d",
+ ccci_buff.message, pCCCI->GetMessageLength(ccci_buff) - CCCI_SHARE_BUFF_HEADER_LEN);
+ SpeechVMRecorder *pSpeechVMRecorder = SpeechVMRecorder::getInstance();
+ int i = 4, j;
+ if (pCCCI->GetM2AShareBufSyncWord(ccci_buff) == CCCI_M2A_SHARE_BUFF_HEADER_SYNC) {
+ while (i) {
+ int data_type = pCCCI->GetM2AShareBufDataType(ccci_buff);
+ if (data_type == SHARE_BUFF_DATA_TYPE_CCCI_CTM_UL_IN) {
+ pSpeechVMRecorder->getCtmDebugDataFromModem(pCCCI->GetM2AUplinkRingBuffer(ccci_buff),
+ pSpeechVMRecorder->pCtmDumpFileUlIn);
+ } else if (data_type == SHARE_BUFF_DATA_TYPE_CCCI_CTM_DL_IN) {
+ pSpeechVMRecorder->getCtmDebugDataFromModem(pCCCI->GetM2AUplinkRingBuffer(ccci_buff),
+ pSpeechVMRecorder->pCtmDumpFileDlIn);
+ } else if (data_type == SHARE_BUFF_DATA_TYPE_CCCI_CTM_UL_OUT) {
+ pSpeechVMRecorder->getCtmDebugDataFromModem(pCCCI->GetM2AUplinkRingBuffer(ccci_buff),
+ pSpeechVMRecorder->pCtmDumpFileUlOut);
+ } else if (data_type == SHARE_BUFF_DATA_TYPE_CCCI_CTM_DL_OUT) {
+ pSpeechVMRecorder->getCtmDebugDataFromModem(pCCCI->GetM2AUplinkRingBuffer(ccci_buff),
+ pSpeechVMRecorder->pCtmDumpFileDlOut);
+ }
+ j = pCCCI->GetM2AShareBufDataLength(ccci_buff) + CCCI_SHARE_BUFF_HEADER_LEN;
+ ccci_buff.reserved += j;
+ if (ccci_buff.reserved > pCCCI->mM2AShareBufLen) {
+ ccci_buff.reserved -= pCCCI->mM2AShareBufLen;
+ }
+ i--;
+ }
+ }
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_CTM_DEBUG_DATA_READ_ACK, 0, 0));
+ }
+ break;
+ }
+ case MSG_M2A_CTM_OFF_ACK: { // ack of MSG_A2M_CTM_OFF
+ if (pCCCI->GetModemSideModemStatus(TTY_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(TTY_STATUS_MASK);
+ } else {
+ ALOGE("--TtyCtmOff Ack is not paired!!");
+ }
+ ALOGD("--TtyCtmOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Loopback */
+ case MSG_M2A_SET_ACOUSTIC_LOOPBACK_ACK: { // ack of MSG_A2M_SET_ACOUSTIC_LOOPBACK
+ const bool loopback_on = pCCCI->GetMessageParam(ccci_buff) & 0x1;
+ if (loopback_on == true) { // loopback on
+ pCCCI->SetModemSideModemStatus(LOOPBACK_STATUS_MASK);
+ } else { // loopback off
+ if (pCCCI->GetModemSideModemStatus(LOOPBACK_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(LOOPBACK_STATUS_MASK);
+ } else {
+ ALOGE("--SetAcousticLoopback Ack is not paired!!");
+ }
+ }
+
+ pCCCI->mLad->Signal();
+
+ ALOGD("--SetAcousticLoopback Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Speech Enhancement parameters */
+ case MSG_M2A_EM_NB_ACK: { // ack of MSG_A2M_EM_NB
+ pCCCI->AddSpeechParamAckCount(NB_SPEECH_PARAM);
+ pCCCI->A2MBufUnLock();
+ ALOGD("--SetNBSpeechParameters Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_EM_DMNR_ACK: { // ack of MSG_A2M_EM_DMNR
+ pCCCI->AddSpeechParamAckCount(DMNR_SPEECH_PARAM);
+ pCCCI->A2MBufUnLock();
+ ALOGD("--SetDualMicSpeechParameters Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_EM_MAGICON_ACK: { // ack of MSG_A2M_EM_MAGICON
+ pCCCI->AddSpeechParamAckCount(MAGICON_SPEECH_PARAM);
+ pCCCI->A2MBufUnLock();
+ ALOGD("--SetMagiConSpeechParameters Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_EM_HAC_ACK: { // ack of MSG_A2M_EM_HAC
+ pCCCI->AddSpeechParamAckCount(HAC_SPEECH_PARAM);
+ pCCCI->A2MBufUnLock();
+ ALOGD("--SetHACSpeechParameters Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_EM_WB_ACK: { // ack of MSG_A2M_EM_WB
+ pCCCI->AddSpeechParamAckCount(WB_SPEECH_PARAM);
+ pCCCI->A2MBufUnLock();
+ ALOGD("--SetWBSpeechParameters Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Modem Reset */
+ case MSG_M2A_EM_DATA_REQUEST: { // Modem reset. Requset for all EM data(NB/DMNR/WB)
+ ALOGW("..[MD Reset Notify(MSG_M2A_EM_DATA_REQUEST: 0x%x)]..", ccci_buff.message);
+ pCCCI->mWasModemReset = true;
+
+ // Clean mWaitAckMessageID to avoid the queue receiving the wrong ack
+ pCCCI->mWaitAckMessageID = 0;
+
+ // close analog downlink path when modem reset during phone call
+ if (pCCCI->mLad->GetApSideModemStatus(SPEECH_STATUS_MASK) == true ||
+ pCCCI->mLad->GetApSideModemStatus(VT_STATUS_MASK) == true) {
+ //notify event to do reopen voice call
+ AudioEventThreadManager::getInstance()->notifyCallback(AUDIO_EVENT_PHONECALL_REOPEN, pCCCI);
+ }
+
+ pCCCI->mIsModemResetDuringPhoneCall = false;
+ pCCCI->mIsModemReset = false;
+ pCCCI->mIsModemEPOF = false;
+
+ // Check the first message in queue. If need ack, take action.
+ // Modem reset, flush all CCCI queue first. Don't care for the CCCI queue.
+ pCCCI->MDReset_CheckMessageInQueue();
+ pCCCI->ResetSpeechParamAckCount();
+
+ break;
+ }
+ case MSG_M2A_VIBSPK_PARAMETER_ACK: { // ack of MSG_M2A_VIBSPK_PARAMETER
+ pCCCI->A2MBufUnLock();
+ ALOGD("--SetVibSpkParam Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ case MSG_M2A_SMARTPA_PARAMETER_ACK: {
+ pCCCI->A2MBufUnLock();
+ ALOGD("--SetSmartpaParam Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ /* Modem EPOF */
+ case MSG_M2A_EPOF_NOTIFY: {
+ ALOGW("..[MD EPOF Notify(MSG_M2A_EPOF_NOTIFY: 0x%x)]..", ccci_buff.message);
+
+ // Check the first message in queue. If need ack, take action.
+ // Modem reset, flush all CCCI queue first. Don't care for the CCCI queue.
+ pCCCI->MDReset_CheckMessageInQueue();
+ pCCCI->ResetSpeechParamAckCount();
+
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_EPOF_ACK, 0, 0));
+ pCCCI->mIsModemEPOF = true;
+
+ break;
+ }
+
+ default: {
+ ALOGD("Read modem message(0x%x), don't care. (or no such message)", ccci_buff.message);
+ sph_msleep(10);
+ break;
+ }
+ }
+
+ /// If AP side is waiting for this ack, then consume message queue
+ uint16_t a2m_message_id_of_m2a_ack = m2a_message_id & 0x7FFF; // 0xAF** -> 0x2F**
+ if (pCCCI->JudgeAckOfMsg(a2m_message_id_of_m2a_ack) == MESSAGE_NEED_ACK) {
+ if (a2m_message_id_of_m2a_ack == pCCCI->mWaitAckMessageID) {
+ pCCCI->mWaitAckMessageID = 0; // reset
+ pCCCI->ConsumeMessageInQueue();
+ } else {
+ ALOGW("Message(0x%x) might double ack!! The current mWaitAckMessageID is 0x%x",
+ ccci_buff.message, pCCCI->mWaitAckMessageID);
+ }
+ }
+ }
+ pthread_exit(NULL);
+ return 0;
+}
+
+status_t SpeechMessengerCCCI::CreateSendSphParaThread() {
+ int ret = pthread_create(&hSendSphThread, NULL, SpeechMessengerCCCI::SendSphParaThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+ return NO_ERROR;
+}
+
+void *SpeechMessengerCCCI::SendSphParaThread(void *arg) {
+ pthread_detach(pthread_self());
+
+ prctl(PR_SET_NAME, (unsigned long)__FUNCTION__, 0, 0, 0);
+ // Adjust thread priority
+ int rtnPrio = setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+ if (0 != rtnPrio) {
+ ALOGE("[%s] failed, errno: %d, return=%d", __FUNCTION__, errno, rtnPrio);
+ } else {
+ ALOGD("%s setpriority ok, priority: %d", __FUNCTION__, ANDROID_PRIORITY_AUDIO);
+ }
+ ALOGD("%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+
+ SpeechMessengerCCCI *pCCCI = (SpeechMessengerCCCI *)arg;
+
+ // Get SpeechParamLock
+ if (pCCCI->SpeechParamLock() == false) {
+ ALOGE("%s() fail to get SpeechParamLock!!", __FUNCTION__);
+ return 0;
+ }
+
+ // Check the first message in queue. If need ack, take action.
+ // Modem reset, flush all CCCI queue first. Don't care for the CCCI queue.
+ pCCCI->MDReset_CheckMessageInQueue();
+
+ // Send speech parameters to modem side
+ pCCCI->ResetSpeechParamAckCount();
+ pCCCI->mLad->SetAllSpeechEnhancementInfoToModem();
+
+ // Release SpeechParamLock
+ pCCCI->SpeechParamUnLock();
+
+ pthread_exit(NULL);
+ return 0;
+}
+
+
+bool SpeechMessengerCCCI::A2MBufLock() {
+ const uint32_t kA2MBufLockTimeout = 3000; // 3 sec
+
+ int rc = AL_LOCK_MS(mA2MShareBufMutex, kA2MBufLockTimeout);
+ ALOGD("%s()", __FUNCTION__);
+ if (rc != 0) {
+ ALOGE("%s(), Cannot get Lock!! Timeout : %u msec", __FUNCTION__, kA2MBufLockTimeout);
+ return false;
+ }
+ return true;
+}
+
+void SpeechMessengerCCCI::A2MBufUnLock() {
+ AL_UNLOCK(mA2MShareBufMutex);
+ ALOGD("%s()", __FUNCTION__);
+}
+
+bool SpeechMessengerCCCI::SpeechParamLock() {
+ const uint32_t kSphParamLockTimeout = 10000; // 10 sec
+
+ ALOGD("%s()", __FUNCTION__);
+ int rc = AL_LOCK_MS(mSetSpeechParamMutex, kSphParamLockTimeout);
+ if (rc != 0) {
+ ALOGE("%s(), Cannot get Lock!! Timeout : %u msec", __FUNCTION__, kSphParamLockTimeout);
+ return false;
+ }
+ return true;
+}
+
+void SpeechMessengerCCCI::SpeechParamUnLock() {
+ ALOGD("%s()", __FUNCTION__);
+ AL_UNLOCK(mSetSpeechParamMutex);
+}
+
+void SpeechMessengerCCCI::ResetSpeechParamAckCount() {
+ memset(&mSpeechParamAckCount, 0, sizeof(mSpeechParamAckCount));
+ ALOGD("%s(), NB(%u)/DMNR(%u)/WB(%u)/MAGICON(%u)/HAC(%u)", __FUNCTION__,
+ mSpeechParamAckCount[NB_SPEECH_PARAM],
+ mSpeechParamAckCount[DMNR_SPEECH_PARAM],
+ mSpeechParamAckCount[WB_SPEECH_PARAM],
+ mSpeechParamAckCount[MAGICON_SPEECH_PARAM],
+ mSpeechParamAckCount[HAC_SPEECH_PARAM]);
+}
+
+void SpeechMessengerCCCI::AddSpeechParamAckCount(speech_param_ack_t type) {
+ if (type >= NUM_SPEECH_PARAM_ACK_TYPE || type < 0) {
+ ALOGE("%s(), no such type: %d", __FUNCTION__, type);
+ } else {
+ if (mSpeechParamAckCount[type] < 0xFFFFFFFF) { //prevent overflow
+ mSpeechParamAckCount[type]++;
+ }
+ ALOGD("%s(%d), NB(%u)/DMNR(%u)/WB(%u)/MAGICON(%u)/HAC(%u)", __FUNCTION__, type,
+ mSpeechParamAckCount[NB_SPEECH_PARAM],
+ mSpeechParamAckCount[DMNR_SPEECH_PARAM],
+ mSpeechParamAckCount[WB_SPEECH_PARAM],
+ mSpeechParamAckCount[MAGICON_SPEECH_PARAM],
+ mSpeechParamAckCount[HAC_SPEECH_PARAM]);
+ }
+}
+
+bool SpeechMessengerCCCI::CheckSpeechParamAckAllArrival() {
+ bool ret = true;
+
+ // Get SpeechParamLock
+ if (SpeechParamLock() == false) {
+ ALOGE("%s() fail to get SpeechParamLock!!", __FUNCTION__);
+ return false;
+ }
+
+ if (mSpeechParamAckCount[NB_SPEECH_PARAM] == 0) { ret = false; }
+
+ if (AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport() >= 2) {
+ if (mSpeechParamAckCount[DMNR_SPEECH_PARAM] == 0) { ret = false; }
+
+#if defined(MTK_MAGICONFERENCE_SUPPORT) || defined(MTK_INCALL_HANDSFREE_DMNR)
+ if (mSpeechParamAckCount[MAGICON_SPEECH_PARAM] == 0) { ret = false; }
+#endif
+ }
+
+#if defined(MTK_WB_SPEECH_SUPPORT)
+ if (mSpeechParamAckCount[WB_SPEECH_PARAM] == 0) { ret = false; }
+#endif
+
+#if defined(MTK_HAC_SUPPORT)
+ if (mSpeechParamAckCount[HAC_SPEECH_PARAM] == 0) { ret = false; }
+#endif
+
+ if (ret == true) {
+ ALOGD("%s() Pass", __FUNCTION__);
+ } else {
+ ALOGE("%s() Fail, NB(%u)/DMNR(%u)/WB(%u)/MAGICON(%u)/HAC(%u)", __FUNCTION__,
+ mSpeechParamAckCount[NB_SPEECH_PARAM],
+ mSpeechParamAckCount[DMNR_SPEECH_PARAM],
+ mSpeechParamAckCount[WB_SPEECH_PARAM],
+ mSpeechParamAckCount[MAGICON_SPEECH_PARAM],
+ mSpeechParamAckCount[HAC_SPEECH_PARAM]);
+
+ // Send speech parameters to modem side again
+ mLad->SetAllSpeechEnhancementInfoToModem();
+ ResetWasModemReset(false);
+ }
+
+ // Release SpeechParamLock
+ SpeechParamUnLock();
+
+ return ret;
+}
+
+/** Do error handling here */
+void SpeechMessengerCCCI::SendMsgFailErrorHandling(const ccci_buff_t &ccci_buff) {
+ ALOGE("%s(), message: 0x%x", __FUNCTION__, ccci_buff.message);
+ switch (GetMessageID(ccci_buff)) {
+ case MSG_A2M_SET_SPH_MODE: {
+ // Do nothing...
+ break;
+ }
+ case MSG_A2M_SPH_ON: {
+ phone_call_mode_t phone_call_mode = (phone_call_mode_t)GetMessageParam(ccci_buff);
+ if (phone_call_mode == RAT_3G324M_MODE) {
+ SetModemSideModemStatus(VT_STATUS_MASK);
+ } else {
+ SetModemSideModemStatus(SPEECH_STATUS_MASK);
+ }
+
+ //mLad->Signal();
+
+ break;
+ }
+ case MSG_A2M_SPH_OFF: {
+ if (GetModemSideModemStatus(VT_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(VT_STATUS_MASK);
+ } else if (GetModemSideModemStatus(SPEECH_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(SPEECH_STATUS_MASK);
+ } else {
+ ALOGE("--SpeechOff Ack is not paired!!");
+ }
+
+ mLad->Signal();
+
+ break;
+ }
+ case MSG_A2M_SPH_ROUTER_ON: {
+ const bool pcm_route_on = GetMessageParam(ccci_buff) & 0x1;
+ if (pcm_route_on == true) { // pcm route on
+ SetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+ } else { // pcm route off
+ if (GetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+ } else {
+ ALOGE("--SpeechOn(PCM Route On) Ack is not paired!!");
+ }
+ }
+
+ break;
+ }
+#ifdef SPEECH_PCM_VM_SUPPORT
+
+ case MSG_A2M_PCM_REC_ON: {
+ SetModemSideModemStatus(RECORD_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_PCM_REC_OFF: {
+ if (GetModemSideModemStatus(RECORD_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--recordOff Ack is not paired!!");
+ }
+ break;
+ }
+ case MSG_A2M_RECORD_RAW_PCM_ON: {
+ SetModemSideModemStatus(RAW_RECORD_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_RECORD_RAW_PCM_OFF: {
+ if (GetModemSideModemStatus(RAW_RECORD_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(RAW_RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--RawRecordOff Ack is not paired!!");
+ }
+ break;
+ }
+ case MSG_A2M_VM_REC_ON: {
+ SetModemSideModemStatus(VM_RECORD_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_VM_REC_OFF: {
+ if (GetModemSideModemStatus(VM_RECORD_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(VM_RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--VMRecordOff Ack is not paired!!");
+ }
+ break;
+ }
+#else
+ case MSG_A2M_RECORD_ON: {
+ SetModemSideModemStatus(RECORD_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_RECORD_OFF: {
+ if (GetModemSideModemStatus(RECORD_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--recordOff Ack is not paired!!");
+ }
+ break;
+ }
+#endif
+ case MSG_A2M_BGSND_ON: {
+ SetModemSideModemStatus(BGS_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_BGSND_OFF: {
+ if (GetModemSideModemStatus(BGS_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(BGS_STATUS_MASK);
+ } else {
+ ALOGE("--BGSoundOff Ack is not paired!!");
+ }
+ break;
+ }
+ case MSG_A2M_PNW_ON: {
+ SetModemSideModemStatus(P2W_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_PNW_OFF: {
+ if (GetModemSideModemStatus(P2W_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(P2W_STATUS_MASK);
+ } else {
+ ALOGE("--PCM2WayOff Ack is not paired!!");
+ }
+ break;
+ }
+ case MSG_A2M_CTM_ON: {
+ SetModemSideModemStatus(TTY_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_CTM_OFF: {
+ if (GetModemSideModemStatus(TTY_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(TTY_STATUS_MASK);
+ } else {
+ ALOGE("--TtyCtmOff Ack is not paired!!");
+ }
+ break;
+ }
+ case MSG_A2M_SET_ACOUSTIC_LOOPBACK: {
+ const bool loopback_on = GetMessageParam(ccci_buff) & 0x1;
+ if (loopback_on == true) { // loopback on
+ SetModemSideModemStatus(LOOPBACK_STATUS_MASK);
+ } else { // loopback off
+ if (GetModemSideModemStatus(LOOPBACK_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(LOOPBACK_STATUS_MASK);
+ } else {
+ ALOGE("--SetAcousticLoopback Ack is not paired!!");
+ }
+ }
+
+ mLad->Signal();
+ break;
+ }
+ case MSG_A2M_EM_NB:
+ case MSG_A2M_EM_WB:
+ case MSG_A2M_EM_DMNR:
+ case MSG_A2M_EM_MAGICON:
+ case MSG_A2M_EM_HAC:
+ case MSG_A2M_VIBSPK_PARAMETER:
+ case MSG_A2M_SMARTPA_PARAMETER: {
+ A2MBufUnLock();
+ break;
+ }
+ default: {
+ ALOGW("%s(), message: 0x%x, ack don't care", __FUNCTION__, ccci_buff.message);
+ }
+ }
+}
+
+RingBuf SpeechMessengerCCCI::GetM2AUplinkRingBuffer(const ccci_buff_t &ccci_buff) {
+ // check MD side data msg format
+ CheckOffsetAndLength(ccci_buff);
+
+ RingBuf ul_ring_buf;
+
+ ul_ring_buf.bufLen = mM2AShareBufLen;
+ ul_ring_buf.pBufBase = mM2AShareBufBase;
+ ul_ring_buf.pBufEnd = ul_ring_buf.pBufBase + ul_ring_buf.bufLen;
+
+ ul_ring_buf.pRead = ul_ring_buf.pBufBase + GetMessageOffset(ccci_buff);
+ if (ul_ring_buf.pRead >= mM2AShareBufEnd) { ul_ring_buf.pRead -= ul_ring_buf.bufLen; }
+
+ // share buffer header
+ char *p_sync_word = ul_ring_buf.pRead + 0; // 0 * size(unsigned short)
+ char *p_data_type = ul_ring_buf.pRead + 2; // 1 * size(unsigned short)
+ char *p_data_len = ul_ring_buf.pRead + 4; // 2 * size(unsigned short)
+
+ if (p_data_type >= mM2AShareBufEnd) { p_data_type -= ul_ring_buf.bufLen; }
+ if (p_data_len >= mM2AShareBufEnd) { p_data_len -= ul_ring_buf.bufLen; }
+
+ if (*(uint16_t *)p_sync_word != CCCI_M2A_SHARE_BUFF_HEADER_SYNC) {
+ char idxDump = 10, u4I;
+ char SphDumpStr[SPH_DUMP_STR_SIZE] = {0};
+
+ snprintf(SphDumpStr, SPH_DUMP_STR_SIZE, "ring_buf[pBase %p, pEnd %p, Len 0x%x, pRead %p, offset 0x%x]= ",
+ ul_ring_buf.pBufBase, mM2AShareBufEnd, mM2AShareBufLen, ul_ring_buf.pRead, ccci_buff.message);
+ for (u4I = 0; u4I < idxDump; u4I++) {
+ char SphDumpTemp[100];
+ snprintf(SphDumpTemp, 100, "[%d, %p]0x%x, ", u4I, (uint16_t *)ul_ring_buf.pRead + u4I,
+ *((uint16_t *)ul_ring_buf.pRead + u4I));
+ audio_strncat(SphDumpStr, SphDumpTemp, SPH_DUMP_STR_SIZE);
+ }
+
+ if (u4I != 0) {
+ ALOGD("%s(), offset(0x%x), %s", __FUNCTION__, GetMessageOffset(ccci_buff), SphDumpStr);
+ }
+ ALOGD("%s(), message = 0x%x, *p_sync_word(0x%x), *p_data_type(0x%x), *p_data_len(0x%x)",
+ __FUNCTION__, ccci_buff.message, *(uint16_t *)p_sync_word, *(uint16_t *)p_data_type,
+ *(uint16_t *)p_data_len);
+
+ }
+ ASSERT(*(uint16_t *)p_sync_word == CCCI_M2A_SHARE_BUFF_HEADER_SYNC);
+
+ ul_ring_buf.pRead += CCCI_SHARE_BUFF_HEADER_LEN;
+ if (ul_ring_buf.pRead >= mM2AShareBufEnd) { ul_ring_buf.pRead -= ul_ring_buf.bufLen; }
+
+ ul_ring_buf.pWrite = ul_ring_buf.pRead + (*(uint16_t *)p_data_len);
+ if (ul_ring_buf.pWrite >= mM2AShareBufEnd) { ul_ring_buf.pWrite -= ul_ring_buf.bufLen; }
+
+#if 0
+ uint16_t count = *(uint16_t *)p_data_len;
+ if (ul_ring_buf.pRead <= ul_ring_buf.pWrite) {
+ fwrite((void *)ul_ring_buf.pRead, sizeof(char), count, mLad->fp);
+ } else {
+ char *end = ul_ring_buf.pBufBase + ul_ring_buf.bufLen;
+ int r2e = end - ul_ring_buf.pRead;
+ if (count <= r2e) {
+ fwrite((void *)ul_ring_buf.pRead, sizeof(char), count, mLad->fp);
+ } else {
+ fwrite((void *)ul_ring_buf.pRead, sizeof(char), r2e, mLad->fp);
+ fwrite((void *)ul_ring_buf.pBufBase, sizeof(char), count - r2e, mLad->fp);
+ }
+ }
+#endif
+
+ return ul_ring_buf;
+}
+
+RingBuf SpeechMessengerCCCI::GetM2ACtmRingBuffer(const ccci_buff_t &ccci_buff) {
+ // check MD side data msg format
+ CheckOffsetAndLength(ccci_buff);
+
+ RingBuf ul_ring_buf;
+
+ ul_ring_buf.bufLen = mM2AShareBufLen;
+ ul_ring_buf.pBufBase = mM2AShareBufBase;
+ ul_ring_buf.pBufEnd = ul_ring_buf.pBufBase + ul_ring_buf.bufLen;
+
+ ul_ring_buf.pRead = ul_ring_buf.pBufBase + GetMessageOffset(ccci_buff);
+ if (ul_ring_buf.pRead >= mM2AShareBufEnd) { ul_ring_buf.pRead -= ul_ring_buf.bufLen; }
+
+ // share buffer header
+ char *p_sync_word = ul_ring_buf.pRead + 0; // 0 * size(unsigned short)
+ char *p_data_type = ul_ring_buf.pRead + 2; // 1 * size(unsigned short)
+ char *p_data_len = ul_ring_buf.pRead + 4; // 2 * size(unsigned short)
+
+ if (p_data_type >= mM2AShareBufEnd) { p_data_type -= ul_ring_buf.bufLen; }
+ if (p_data_len >= mM2AShareBufEnd) { p_data_len -= ul_ring_buf.bufLen; }
+
+ if (*(uint16_t *)p_sync_word != CCCI_M2A_SHARE_BUFF_HEADER_SYNC) {
+ char idxDump = 10, u4I;
+ char SphDumpStr[SPH_DUMP_STR_SIZE] = {0};
+
+ snprintf(SphDumpStr, SPH_DUMP_STR_SIZE, "ring_buf[pBase %p, pEnd %p, Len 0x%x, pRead %p, offset 0x%x]= ",
+ ul_ring_buf.pBufBase, mM2AShareBufEnd, mM2AShareBufLen, ul_ring_buf.pRead, ccci_buff.message);
+ for (u4I = 0; u4I < idxDump; u4I++) {
+ char SphDumpTemp[100];
+ snprintf(SphDumpTemp, 100, "[%d, %p]0x%x, ", u4I, (uint16_t *)ul_ring_buf.pRead + u4I,
+ *((uint16_t *)ul_ring_buf.pRead + u4I));
+ audio_strncat(SphDumpStr, SphDumpTemp, SPH_DUMP_STR_SIZE);
+ }
+
+ if (u4I != 0) {
+ ALOGD("%s(), offset(0x%x), %s", __FUNCTION__, GetMessageOffset(ccci_buff), SphDumpStr);
+ }
+
+ ALOGD("%s(), message = 0x%x, *p_sync_word(0x%x), *p_data_type(0x%x), *p_data_len(0x%x)",
+ __FUNCTION__, ccci_buff.message, *(uint16_t *)p_sync_word, *(uint16_t *)p_data_type,
+ *(uint16_t *)p_data_len);
+ }
+
+ ASSERT(*(uint16_t *)p_sync_word == CCCI_M2A_SHARE_BUFF_HEADER_SYNC);
+
+ ul_ring_buf.pRead += CCCI_SHARE_BUFF_HEADER_LEN;
+ if (ul_ring_buf.pRead >= mM2AShareBufEnd) { ul_ring_buf.pRead -= ul_ring_buf.bufLen; }
+
+ ul_ring_buf.pWrite = ul_ring_buf.pRead + GetM2AShareBufDataLength(ccci_buff);
+ if (ul_ring_buf.pWrite >= mM2AShareBufEnd) { ul_ring_buf.pWrite -= ul_ring_buf.bufLen; }
+
+ return ul_ring_buf;
+}
+
+uint16_t SpeechMessengerCCCI::GetPcmFreq(const uint16_t Idx_Freq) {
+ uint16_t Pcm_Freq = 8000;
+
+ switch (Idx_Freq) {
+ case 0:
+ Pcm_Freq = 8000;
+ break;
+
+ case 1:
+ Pcm_Freq = 16000;
+ break;
+
+ case 2:
+ Pcm_Freq = 32000;
+ break;
+
+ case 3:
+ Pcm_Freq = 48000;
+ break;
+
+ case 0xf:
+ Pcm_Freq = 8000;
+ break;
+
+ default:
+ Pcm_Freq = 8000;
+ break;
+
+ }
+ return Pcm_Freq;
+}
+
+RingBuf SpeechMessengerCCCI::GetM2ARawPcmRingBuffer(const ccci_buff_t &ccci_buff) {
+ ALOGV("%s(), id(0x%x), mM2AShareBufLen(0x%x), A2M_SHARED_BUFFER_BGS_DATA_SIZE(%d)",
+ __FUNCTION__, GetMessageID(ccci_buff), mM2AShareBufLen, A2M_SHARED_BUFFER_BGS_DATA_SIZE);
+
+ // check MD side data msg format
+ CheckOffsetAndLength(ccci_buff);
+
+ spcRAWPCMBufInfo header_RawPcmBufInfo;
+ spcApRAWPCMBufHdr header_ApRawPcmBuf;
+
+ char *SeqPcmBuf = new char [mM2AShareBufLen];
+ memset(SeqPcmBuf, 0, mM2AShareBufLen);
+ // char SeqPcmBuf[CCCI_MAX_PAYLOAD_SIZE * 4 + 16] = {0};
+ RingBuf ul_ring_buf;
+
+ uint16_t size_copy1, size_copy2, BytesCopied, BytesToCopy;
+ char *PtrTarget = NULL;
+ char *PtrSource = NULL;
+
+ ul_ring_buf.bufLen = mM2AShareBufLen;
+ ul_ring_buf.pBufBase = mM2AShareBufBase;
+ ul_ring_buf.pBufEnd = ul_ring_buf.pBufBase + ul_ring_buf.bufLen;
+
+ ul_ring_buf.pRead = ul_ring_buf.pBufBase + GetMessageOffset(ccci_buff);
+ if (ul_ring_buf.pRead >= mM2AShareBufEnd) { ul_ring_buf.pRead -= ul_ring_buf.bufLen; }
+
+ // share buffer header
+ //parse message
+ char *p_sync_word = ul_ring_buf.pRead + 0; // size(unsigned short)
+ char *p_data_type = ul_ring_buf.pRead + 2; // size(unsigned short)
+ char *p_data_len = ul_ring_buf.pRead + 4;// size(unsigned short)
+
+ if (p_data_type >= mM2AShareBufEnd) { p_data_type -= ul_ring_buf.bufLen; }
+ if (p_data_len >= mM2AShareBufEnd) { p_data_len -= ul_ring_buf.bufLen; }
+
+ if (*(uint16_t *)p_sync_word != CCCI_M2A_SHARE_BUFF_HEADER_SYNC) {
+ char idxDump = 10, u4I;
+ char SphDumpStr[SPH_DUMP_STR_SIZE] = {0};
+
+ snprintf(SphDumpStr, SPH_DUMP_STR_SIZE, "ring_buf[pBase %p, pEnd %p, Len 0x%x, pRead %p, offset 0x%x]= ",
+ ul_ring_buf.pBufBase, mM2AShareBufEnd, mM2AShareBufLen, ul_ring_buf.pRead, ccci_buff.message);
+ for (u4I = 0; u4I < idxDump; u4I++) {
+ char SphDumpTemp[100];
+ snprintf(SphDumpTemp, 100, "[%d, %p]0x%x, ", u4I, (uint16_t *)ul_ring_buf.pRead + u4I,
+ *((uint16_t *)ul_ring_buf.pRead + u4I));
+ audio_strncat(SphDumpStr, SphDumpTemp, SPH_DUMP_STR_SIZE);
+ }
+
+ if (u4I != 0) {
+ ALOGD("%s(), offset(0x%x), %s", __FUNCTION__, GetMessageOffset(ccci_buff), SphDumpStr);
+ }
+
+ ALOGD("%s(), message = 0x%x, *p_sync_word(0x%x), *p_data_type(0x%x), *p_data_len(0x%x)",
+ __FUNCTION__, ccci_buff.message, *(uint16_t *)p_sync_word, *(uint16_t *)p_data_type,
+ *(uint16_t *)p_data_len);
+ }
+
+ ASSERT(*(uint16_t *)p_sync_word == CCCI_M2A_SHARE_BUFF_HEADER_SYNC);
+
+ BytesCopied = (*(uint16_t *)p_data_len) << 1;
+ ul_ring_buf.pWrite = ul_ring_buf.pRead + BytesCopied;
+
+ ALOGV("%s(), before memcpy mM2AShareBufEnd(%p), BytesCopied(0x%x), p_data_len(0x%x), pRead(%p), pWrite(%p)",
+ __FUNCTION__, mM2AShareBufEnd, BytesCopied, (*(uint16_t *)p_data_len), ul_ring_buf.pRead,
+ ul_ring_buf.pWrite);
+
+ // share buffer header
+ if (ul_ring_buf.pWrite >= mM2AShareBufEnd) {
+ ul_ring_buf.pWrite -= ul_ring_buf.bufLen;
+
+ size_copy1 = mM2AShareBufEnd - ul_ring_buf.pRead;
+ size_copy2 = BytesCopied - size_copy1;
+ ALOGV("%s(), mM2AShareBufEnd(%p), BytesCopied(0x%x), size_copy1(0x%x), size_copy2(0x%x),"
+ " pRead(%p), pWrite(%p)",
+ __FUNCTION__, mM2AShareBufEnd, BytesCopied, size_copy1, size_copy2, ul_ring_buf.pRead,
+ ul_ring_buf.pWrite);
+ memcpy((char *)mSphCCCITmpBuf, (char *)ul_ring_buf.pRead, size_copy1);
+ memcpy((char *)mSphCCCITmpBuf + size_copy1, (char *)ul_ring_buf.pBufBase, size_copy2);
+ } else {
+ ALOGV("%s(), message = 0x%x, mSphCCCITmpBuf(%p), ul_ring_buf.pRead(%p), BytesCopied(0x%x)",
+ __FUNCTION__, ccci_buff.message, (char *)mSphCCCITmpBuf, (uint16_t *)ul_ring_buf.pRead, BytesCopied);
+ memcpy((char *)mSphCCCITmpBuf, (char *)ul_ring_buf.pRead, BytesCopied);
+ }
+ memcpy(&header_RawPcmBufInfo, (char *)mSphCCCITmpBuf + CCCI_SHARE_BUFF_HEADER_LEN, sizeof(spcRAWPCMBufInfo));
+ PtrTarget = (char *)SeqPcmBuf;
+
+ switch (mPcmRecordType) {
+ case RECORD_TYPE_UL:
+ header_ApRawPcmBuf.u16SyncWord = EEMCS_M2A_SHARE_BUFF_HEADER_SYNC;
+ header_ApRawPcmBuf.u16RawPcmDir = RECORD_TYPE_UL;
+ header_ApRawPcmBuf.u16Freq = GetPcmFreq(header_RawPcmBufInfo.u16ULFreq);
+ header_ApRawPcmBuf.u16Length = header_RawPcmBufInfo.u16ULLength;
+ header_ApRawPcmBuf.u16Channel = 1;
+ header_ApRawPcmBuf.u16BitFormat = AUDIO_FORMAT_PCM_16_BIT;
+ //uplink raw pcm header
+ memcpy(PtrTarget, &header_ApRawPcmBuf, sizeof(header_ApRawPcmBuf));
+ BytesCopied = sizeof(header_ApRawPcmBuf);
+
+ //uplink raw pcm
+ PtrTarget = SeqPcmBuf + BytesCopied;
+ PtrSource = (char *)mSphCCCITmpBuf + CCCI_SHARE_BUFF_HEADER_LEN + CCCI_RAW_PCM_BUFF_HEADER_LEN;
+ BytesToCopy = header_RawPcmBufInfo.u16ULLength;
+ memcpy(PtrTarget, PtrSource, BytesToCopy);
+ BytesCopied += BytesToCopy;
+ break;
+
+ case RECORD_TYPE_DL:
+ header_ApRawPcmBuf.u16SyncWord = EEMCS_M2A_SHARE_BUFF_HEADER_SYNC;
+ header_ApRawPcmBuf.u16RawPcmDir = RECORD_TYPE_DL;
+ header_ApRawPcmBuf.u16Freq = GetPcmFreq(header_RawPcmBufInfo.u16DLFreq);
+ header_ApRawPcmBuf.u16Length = header_RawPcmBufInfo.u16DLLength;
+ header_ApRawPcmBuf.u16Channel = 1;
+ header_ApRawPcmBuf.u16BitFormat = AUDIO_FORMAT_PCM_16_BIT;
+ //downlink raw pcm header
+ memcpy(PtrTarget, &header_ApRawPcmBuf, sizeof(header_ApRawPcmBuf));
+ BytesCopied = sizeof(header_ApRawPcmBuf);
+
+ //downlink raw pcm
+ PtrTarget = SeqPcmBuf + BytesCopied;
+ PtrSource = (char *)mSphCCCITmpBuf + CCCI_SHARE_BUFF_HEADER_LEN + CCCI_RAW_PCM_BUFF_HEADER_LEN +
+ header_RawPcmBufInfo.u16ULLength;
+ BytesToCopy = header_RawPcmBufInfo.u16DLLength;
+ memcpy(PtrTarget, PtrSource, BytesToCopy);
+ BytesCopied += BytesToCopy;
+ break;
+ case RECORD_TYPE_MIX:
+ header_ApRawPcmBuf.u16SyncWord = EEMCS_M2A_SHARE_BUFF_HEADER_SYNC;
+ header_ApRawPcmBuf.u16RawPcmDir = RECORD_TYPE_UL;
+ header_ApRawPcmBuf.u16Freq = GetPcmFreq(header_RawPcmBufInfo.u16ULFreq);
+ header_ApRawPcmBuf.u16Length = header_RawPcmBufInfo.u16ULLength;
+ header_ApRawPcmBuf.u16Channel = 1;
+ header_ApRawPcmBuf.u16BitFormat = AUDIO_FORMAT_PCM_16_BIT;
+ //uplink raw pcm header
+ memcpy(PtrTarget, &header_ApRawPcmBuf, sizeof(header_ApRawPcmBuf));
+ BytesCopied = sizeof(header_ApRawPcmBuf);
+
+ //uplink raw pcm
+ PtrTarget = SeqPcmBuf + BytesCopied;
+ PtrSource = (char *)mSphCCCITmpBuf + CCCI_SHARE_BUFF_HEADER_LEN + CCCI_RAW_PCM_BUFF_HEADER_LEN;
+ BytesToCopy = header_RawPcmBufInfo.u16ULLength;
+ memcpy(PtrTarget, PtrSource, BytesToCopy);
+ BytesCopied += BytesToCopy;
+ PtrTarget = SeqPcmBuf + BytesCopied;
+
+
+ //downlink raw pcm header
+ header_ApRawPcmBuf.u16RawPcmDir = RECORD_TYPE_DL;
+ header_ApRawPcmBuf.u16Freq = GetPcmFreq(header_RawPcmBufInfo.u16DLFreq);
+ header_ApRawPcmBuf.u16Length = header_RawPcmBufInfo.u16DLLength;
+ memcpy(PtrTarget, &header_ApRawPcmBuf, sizeof(header_ApRawPcmBuf));
+ BytesCopied += sizeof(header_ApRawPcmBuf);
+
+ //downlink raw pcm
+ PtrTarget = SeqPcmBuf + BytesCopied;
+ PtrSource = (char *)mSphCCCITmpBuf + CCCI_SHARE_BUFF_HEADER_LEN + CCCI_RAW_PCM_BUFF_HEADER_LEN +
+ header_RawPcmBufInfo.u16ULLength;
+ BytesToCopy = header_RawPcmBufInfo.u16DLLength;
+ memcpy(PtrTarget, PtrSource, BytesToCopy);
+ BytesCopied += BytesToCopy;
+ break;
+ }
+ //ring buffer process
+ pcm_ring_buf.pRead = pcm_ring_buf.pWrite;
+ pcm_ring_buf.pWrite = pcm_ring_buf.pRead + BytesCopied;
+ if (pcm_ring_buf.pWrite >= mSphPCMBufEnd) {
+ pcm_ring_buf.pWrite -= pcm_ring_buf.bufLen;
+
+ size_copy1 = mSphPCMBufEnd - pcm_ring_buf.pRead;
+ size_copy2 = BytesCopied - size_copy1;
+ ALOGV("%s(), mSphPCMBufEnd(%p), BytesCopied(0x%x), size_copy1(0x%x), size_copy2(0x%x), pRead(%p), pWrite(%p)",
+ __FUNCTION__, mSphPCMBufEnd, BytesCopied, size_copy1, size_copy2, pcm_ring_buf.pRead,
+ pcm_ring_buf.pWrite);
+ memcpy(pcm_ring_buf.pRead, (char *)SeqPcmBuf, size_copy1);
+ memcpy(pcm_ring_buf.pBufBase, (char *)SeqPcmBuf + size_copy1, size_copy2);
+ } else {
+ memcpy(pcm_ring_buf.pRead, (char *)SeqPcmBuf, BytesCopied);
+ }
+ ALOGV("-%s(), pBufBase(%p), bufLen(0x%x), BytesCopied(0x%x), pRead(%p), pWrite(%p)",
+ __FUNCTION__, pcm_ring_buf.pBufBase, pcm_ring_buf.bufLen, BytesCopied, pcm_ring_buf.pRead,
+ pcm_ring_buf.pWrite);
+
+ if (SeqPcmBuf != NULL) {
+ delete[] SeqPcmBuf;
+ }
+ return pcm_ring_buf;
+}
+
+uint16_t SpeechMessengerCCCI::GetM2AShareBufSyncWord(const ccci_buff_t &ccci_buff) {
+ char *p_sync_word = GetM2AShareBufBase() + GetMessageOffset(ccci_buff) + 0; // 0 * size(unsigned short)
+ if (p_sync_word >= mM2AShareBufEnd) { p_sync_word -= mM2AShareBufLen; }
+ SLOGV("%s(), sync = 0x%x", __FUNCTION__, *(uint16_t *)p_sync_word);
+ return *(uint16_t *)p_sync_word;
+}
+
+uint16_t SpeechMessengerCCCI::GetM2AShareBufDataType(const ccci_buff_t &ccci_buff) {
+ char *p_data_type = GetM2AShareBufBase() + GetMessageOffset(ccci_buff) + 2; // 1 * size(unsigned short)
+ if (p_data_type >= mM2AShareBufEnd) { p_data_type -= mM2AShareBufLen; }
+ SLOGV("%s(), type = 0x%x", __FUNCTION__, *(uint16_t *)p_data_type);
+ return *(uint16_t *)p_data_type;
+}
+
+uint16_t SpeechMessengerCCCI::GetM2AShareBufDataLength(const ccci_buff_t &ccci_buff) {
+ char *p_data_len = GetM2AShareBufBase() + GetMessageOffset(ccci_buff) + 4; // 2 * size(unsigned short)
+ if (p_data_len >= mM2AShareBufEnd) { p_data_len -= mM2AShareBufLen; }
+ SLOGV("%s(), data_len = %d", __FUNCTION__, *(uint16_t *)p_data_len);
+ return *(uint16_t *)p_data_len;
+}
+
+
+bool SpeechMessengerCCCI::GetModemSideModemStatus(const modem_status_mask_t modem_status_mask) const {
+ return ((mModemSideModemStatus & modem_status_mask) > 0);
+}
+
+void SpeechMessengerCCCI::SetModemSideModemStatus(const modem_status_mask_t modem_status_mask) {
+ mModemSideModemStatus |= modem_status_mask;
+
+ // save mModemSideModemStatus in property to avoid medieserver die
+ char property_value[PROPERTY_VALUE_MAX];
+ sprintf(property_value, "%u", mModemSideModemStatus);
+ property_set(PROPERTY_KEY_MODEM_STATUS[mModemIndex], property_value);
+}
+
+void SpeechMessengerCCCI::ResetModemSideModemStatus(const modem_status_mask_t modem_status_mask) {
+ mModemSideModemStatus &= (~modem_status_mask);
+
+ // save mModemSideModemStatus in property to avoid medieserver die
+ char property_value[PROPERTY_VALUE_MAX];
+ sprintf(property_value, "%u", mModemSideModemStatus);
+ property_set(PROPERTY_KEY_MODEM_STATUS[mModemIndex], property_value);
+}
+status_t SpeechMessengerCCCI::setPcmRecordType(RecordType typeRecord) {
+ mPcmRecordType = typeRecord;
+ ALOGD("%s(), mPcmRecordType(%d)", __FUNCTION__, mPcmRecordType);
+ return NO_ERROR;
+}
+
+void SpeechMessengerCCCI::GetRFInfo(void) {
+ uint16_t mRfMode = 0, mRfInfo = 0;
+ char property_value[PROPERTY_VALUE_MAX], property_value2[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_RF_INFO[0], property_value, "0"); //"0": default all off
+ mRfInfo = atoi(property_value);
+
+ property_get(PROPERTY_KEY_RF_INFO[1], property_value2, "0"); //"0": default all off
+ mRfMode = atoi(property_value2);
+
+ ALOGD("%s(), mRfInfo(0x%x), mRfMode(%d)", __FUNCTION__, mRfInfo, mRfMode);
+}
+
+void SpeechMessengerCCCI::SetRFInfo(char mRFIdx, uint16_t mRfData) {
+ // save mRfMode, mRfInfo in property to avoid medieserver die
+ char property_value[PROPERTY_VALUE_MAX];
+ sprintf(property_value, "%u", mRfData);
+ property_set(PROPERTY_KEY_RF_INFO[(unsigned char)mRFIdx], property_value);
+}
+
+void SpeechMessengerCCCI::ResetRFInfo(void) {
+ uint16_t mRfMode = 0, mRfInfo = 0;
+
+ // save mRfMode, mRfInfo in property to avoid medieserver die
+ char property_value[PROPERTY_VALUE_MAX], property_value2[PROPERTY_VALUE_MAX];
+ sprintf(property_value, "%u", mRfMode);
+ property_set(PROPERTY_KEY_RF_INFO[0], property_value);
+
+ sprintf(property_value, "%u", mRfInfo);
+ property_set(PROPERTY_KEY_RF_INFO[1], property_value);
+}
+
+#ifdef USE_CCCI_SHARE_BUFFER
+void SpeechMessengerCCCI::InitA2MRawParaRingBuffer() {
+ return ;
+}
+status_t SpeechMessengerCCCI::GetA2MRawParaRingBuffer(uint16_t *offset, uint16_t *avail) {
+ return NO_ERROR;
+}
+
+status_t SpeechMessengerCCCI::AdvanceA2MRawParaRingBuffer(int datalength) {
+ return NO_ERROR;
+}
+
+status_t SpeechMessengerCCCI::WriteA2MRawParaRingBuffer(char *data, int datalength) {
+ return NO_ERROR;
+}
+#endif
+} // end of namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechMessengerECCCI.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechMessengerECCCI.cpp
new file mode 100644
index 0000000..49c7cd2
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechMessengerECCCI.cpp
@@ -0,0 +1,2355 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechMessengerECCCI"
+#include "SpeechMessengerECCCI.h"
+
+#include <unistd.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include <sys/prctl.h>
+#include <sys/resource.h>
+
+#include <cutils/properties.h>
+
+#include <AudioLock.h>
+
+#include "SpeechDriverLAD.h"
+#include "SpeechBGSPlayer.h"
+#include "SpeechPcm2way.h"
+#include "SpeechVMRecorder.h"
+#include "AudioVolumeFactory.h"
+
+#include "AudioALSAHardwareResourceManager.h"
+
+#include "AudioALSACaptureDataProviderVoice.h"
+#include "SpeechDataProcessingHandler.h"
+#ifdef SPH_VCL_SUPPORT
+#include "SpeechVoiceCustomLogger.h"
+#endif
+#include "LoopbackManager.h"
+
+#if defined (MTK_SPEECH_ENCRYPTION_SUPPORT)
+#include "SpeechDataEncrypter.h"
+#endif
+#include <AudioEventThreadManager.h>
+
+//#include "AudioMTKStreamInManager.h"
+//#include "AudioResourceManager.h"
+/*
+extern "C" {
+#include "hardware/ccci_intf.h"
+}
+*/
+#ifndef sph_msleep
+#define sph_msleep(ms) usleep((ms)*1000)
+#endif
+
+//#define TEST_NEW_RECOED_FOR_OLD_CAPTURE
+
+namespace android {
+
+/** CCCI driver & ioctl */
+/* ECCCI channel buffer structure */
+typedef struct {
+ unsigned int data[2];
+ unsigned int channel;
+ unsigned int reserved;
+ unsigned int payload[CCCI_MAX_PAYLOAD_SIZE];
+} ECCCI_BUFF_T;
+
+/** Property keys*/
+static const char* PROPERTY_KEY_MODEM_STATUS[NUM_MODEM] = {"vendor.audiohal.modem_1.status", "vendor.audiohal.modem_2.status", "vendor.audiohal.modem_ext.status"};
+static const char* PROPERTY_KEY_RF_INFO[2] = {"vendor.audiohal.rf_info", "vendor.audiohal.rf_mode"};
+static const char* PROPERTY_KEY_NW_CODEC_INFO[2] = {"vendor.audiohal.ril.speech.codec.info", "vendor.audiohal.ril.hd.voice.status"};
+
+
+/** CCCI channel No */
+static const uint8_t CCCI_M2A_CHANNEL = 4;
+static const uint8_t CCCI_A2M_CHANNEL = 5;
+
+/** CCCI magic number */
+static const uint32_t CCCI_MAILBOX_MAGIC_NUMBER = 0xFFFFFFFF;
+static bool mA2M_ECCCI_DATA_READ_ACK;
+static const uint32_t ap_working_buf_byte = 4096;
+
+
+#define SPH_DUMP_STR_SIZE (500)
+
+SpeechMessengerECCCI::SpeechMessengerECCCI(modem_index_t modem_index, SpeechDriverLAD *pLad) :
+ mModemIndex(modem_index),
+ mLad(pLad) {
+ ALOGD("%s()", __FUNCTION__);
+ CCCIEnable = false;
+ mA2M_ECCCI_DATA_READ_ACK = false;
+
+ fHdl = -1;
+#ifdef USE_CCCI_SHARE_BUFFER
+ CCCIBuf_Hdl = -1;
+ mA2MParaShareBufBase = NULL;
+ mA2MParaShareBufLen = 0;
+#endif
+
+ mA2MShareBufLen = 0;
+ mM2AShareBufLen = 0;
+
+ mA2MShareBufBase = NULL;
+ mM2AShareBufBase = NULL;
+
+ mA2MShareBufEnd = NULL;
+ mM2AShareBufEnd = NULL;
+ mWasModemReset = false;
+
+ memset(&mM2AShareBuf, 0, sizeof(mM2AShareBuf));
+
+ //initial the message queue
+ memset((void *)pQueue, 0, sizeof(pQueue));
+ iQRead = 0;
+ iQWrite = 0;
+
+ mWaitAckMessageID = 0;
+
+ //initial modem side modem status
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_MODEM_STATUS[mModemIndex], property_value, "0"); //"0": default all off
+ mModemSideModemStatus = atoi(property_value);
+ ALOGD("%s(), mModemIndex(%d), property read(0x%x)", __FUNCTION__, mModemIndex, mModemSideModemStatus);
+
+ ResetSpeechParamAckCount();
+ mLogEnable = 0;
+}
+
+status_t SpeechMessengerECCCI::Initial() {
+ ALOGD("%s()", __FUNCTION__);
+#if defined(MTK_ECCCI_LPBK_TEST) //use eccci loopback for test
+ fHdl = open("/dev/ccci_lp", O_RDWR);
+ if (fHdl < 0) {
+ ALOGE("%s() fail to open/dev/ccci_lp ", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+#else
+ // Open CCCI and get handler
+ char dev_node[32];
+ // Open CCCI and get handler
+ switch (mModemIndex) {
+ case MODEM_1:
+ snprintf(dev_node, 32, "%s", ccci_get_node_name(USR_AUDIO_RX, MD_SYS1));
+ break;
+ case MODEM_2:
+ snprintf(dev_node, 32, "%s", ccci_get_node_name(USR_AUDIO_RX, MD_SYS2));
+ break;
+ default:
+ snprintf(dev_node, 32, "%s", ccci_get_node_name(USR_AUDIO_RX, MD_SYS1));
+ break;
+ }
+ ALOGD("%s(), dev_node=%s", __FUNCTION__, dev_node);
+ fHdl = open(dev_node, O_RDWR);
+ if (fHdl < 0) {
+ ALOGE("%s() fail to open %s, errno: %d", __FUNCTION__, dev_node, errno);
+ return UNKNOWN_ERROR;
+ }
+#endif
+
+#ifdef USE_CCCI_SHARE_BUFFER
+ CCCI_MD md_id = mModemIndex == MODEM_1 ? MD_SYS1 : MD_SYS3;
+ unsigned char *share_addr = NULL;
+ unsigned int length = 0;
+ CCCIBuf_Hdl = ccci_smem_get(md_id, USR_SMEM_RAW_AUDIO, &share_addr, &length);
+ if (CCCIBuf_Hdl < 0) {
+ ALOGE("%s() fail to allocate share buffer for MD %d", __FUNCTION__, md_id);
+ return UNKNOWN_ERROR;
+ }
+ ALOGD("%s(), share_addr %p, length %d", __FUNCTION__, share_addr, length);
+ mA2MParaShareBufBase = (char *) share_addr;
+ mA2MParaShareBufLen = length;
+ InitA2MRawParaRingBuffer();
+#endif
+
+ // Get total share buffer length & base address
+ const uint32_t share_buf_length = 32000;
+ mECCCIShareBuf = new char[share_buf_length];
+
+
+ char *share_buf_address = mECCCIShareBuf;
+ ALOGD("%s(), share_buf_address: %p, share_buf_length: %u", __FUNCTION__, share_buf_address, share_buf_length);
+
+ mA2MShareBufLen = share_buf_length >> 1; // a2m buffer lengh should be half of share_buf_length
+ mM2AShareBufLen = share_buf_length >> 1; // m2a buffer lengh should be half of share_buf_length
+
+ mA2MShareBufBase = share_buf_address;
+ mM2AShareBufBase = share_buf_address + mA2MShareBufLen;
+
+ mA2MShareBufEnd = mA2MShareBufBase + mA2MShareBufLen;
+ mM2AShareBufEnd = mM2AShareBufBase + mM2AShareBufLen;
+
+ mM2AShareBufRead = mM2AShareBufBase;
+
+ mM2AShareBuf.bufLen = mM2AShareBufLen;
+ mM2AShareBuf.pBufBase = mM2AShareBufBase;
+ mM2AShareBuf.pRead = mM2AShareBuf.pBufBase;
+ mM2AShareBuf.pWrite = mM2AShareBuf.pBufBase;
+
+ mSphPCMBuf = new char[ap_working_buf_byte];
+ mSphPCMBufEnd = mSphPCMBuf + ap_working_buf_byte;
+ pcm_ring_buf.bufLen = ap_working_buf_byte;
+ pcm_ring_buf.pBufBase = mSphPCMBuf;
+ pcm_ring_buf.pRead = pcm_ring_buf.pBufBase;
+ pcm_ring_buf.pWrite = pcm_ring_buf.pRead;
+
+ mIsModemResetDuringPhoneCall = false;
+ mIsModemReset = false;
+ mIsModemEPOF = false;
+ mPcmRecordType = RECORD_TYPE_UL;
+ LastSentMessage = 0;
+ LastNeedAckSentMessage = 0;
+
+ /* create the CCCI event reading thread */
+ CCCIEnable = true;
+#if defined(MTK_SPEECH_ENCRYPTION_SUPPORT)
+ //trigger initialization
+ SpeechDataEncrypter::GetInstance()->GetDumpStatus();
+#endif
+ return CreateReadingThread();
+}
+
+status_t SpeechMessengerECCCI::Deinitial() {
+ ALOGD("%s()", __FUNCTION__);
+ CCCIEnable = false;
+
+ if (fHdl >= 0) {
+ close(fHdl);
+ fHdl = -1;
+ }
+#ifdef USE_CCCI_SHARE_BUFFER
+ if (CCCIBuf_Hdl >= 0) {
+ ccci_smem_put(CCCIBuf_Hdl, (unsigned char *) mA2MParaShareBufBase, mA2MParaShareBufLen);
+ CCCIBuf_Hdl = -1;
+ }
+ mA2MParaShareBufBase = NULL;
+ mA2MParaShareBufLen = 0;
+#endif
+
+ if (mECCCIShareBuf != NULL) {
+ delete mECCCIShareBuf;
+ mECCCIShareBuf = NULL;
+
+ mA2MShareBufLen = 0;
+ mM2AShareBufLen = 0;
+
+ mA2MShareBufBase = NULL;
+ mM2AShareBufBase = NULL;
+
+ mA2MShareBufEnd = NULL;
+ mM2AShareBufEnd = NULL;
+ }
+
+ if (mSphPCMBuf != NULL) {
+ delete mSphPCMBuf;
+ mSphPCMBuf = NULL;
+ }
+ mSphPCMBufEnd = NULL;
+
+ return NO_ERROR;
+}
+
+
+SpeechMessengerECCCI::~SpeechMessengerECCCI() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+/** Create CCCI message */
+ccci_buff_t SpeechMessengerECCCI::InitCcciMailbox(uint16_t id, uint16_t param_16bit, uint32_t param_32bit) {
+ ccci_buff_t ccci_buff;
+ memset(&ccci_buff, 0, sizeof(ccci_buff));
+
+
+ //package message
+ switch (id) {
+ case MSG_A2M_PNW_DL_DATA_NOTIFY:
+ case MSG_A2M_BGSND_DATA_NOTIFY:
+ case MSG_A2M_CTM_DATA_NOTIFY:
+ case MSG_A2M_EM_NB:
+ case MSG_A2M_EM_WB:
+ case MSG_A2M_EM_DMNR:
+ case MSG_A2M_EM_MAGICON:
+ case MSG_A2M_EM_HAC:
+ case MSG_A2M_VIBSPK_PARAMETER:
+ case MSG_A2M_SMARTPA_PARAMETER:
+ case MSG_A2M_SPH_UL_ENCRYPTION:
+ case MSG_A2M_SPH_DL_DECRYPTION:
+#ifndef USE_CCCI_SHARE_BUFFER
+ case MSG_A2M_EM_DYNAMIC_SPH:
+#endif
+ ccci_buff.magic = param_32bit;//offset
+ ccci_buff.message = param_16bit;//payload length
+ ccci_buff.channel = CCCI_A2M_CHANNEL;
+ ccci_buff.reserved = (id << 16) | param_16bit;
+ break;
+ default:
+ ccci_buff.magic = CCCI_MAILBOX_MAGIC_NUMBER;
+ ccci_buff.message = (id << 16) | param_16bit;
+ ccci_buff.channel = CCCI_A2M_CHANNEL;
+ ccci_buff.reserved = param_32bit;
+ break;
+ }
+
+
+ return ccci_buff;
+}
+
+/** Get CCCI message's ID */
+uint16_t SpeechMessengerECCCI::GetMessageID(const ccci_buff_t &ccci_buff) {
+ if (ccci_buff.magic != CCCI_MAILBOX_MAGIC_NUMBER) {
+ return (ccci_buff.reserved) >> 16;
+ } else {
+ return (ccci_buff.message) >> 16;
+ }
+}
+
+/** Get CCCI message's parameters */
+uint16_t SpeechMessengerECCCI::GetMessageParam(const ccci_buff_t &ccci_buff) {
+ if (ccci_buff.magic != CCCI_MAILBOX_MAGIC_NUMBER) {
+ return ccci_buff.reserved;
+ } else {
+ return ccci_buff.message;
+ }
+}
+uint32_t SpeechMessengerECCCI::GetMessageReserved(const ccci_buff_t &ccci_buff) {
+ return ccci_buff.reserved;
+}
+
+uint16_t SpeechMessengerECCCI::GetMessageLength(const ccci_buff_t &ccci_buff) {
+ //payload length(6+data)
+ if (ccci_buff.magic != CCCI_MAILBOX_MAGIC_NUMBER) {
+ return ccci_buff.message;
+ } else {
+ return ccci_buff.message & 0xFFFF;
+ }
+}
+
+uint16_t SpeechMessengerECCCI::GetMessageOffset(const ccci_buff_t &ccci_buff) {
+ if (ccci_buff.magic != CCCI_MAILBOX_MAGIC_NUMBER) {
+ return ccci_buff.magic;
+ } else {
+ return 0;//no offset
+ }
+}
+
+
+char SpeechMessengerECCCI::GetModemCurrentStatus() {
+ unsigned int status = (unsigned int)MODEM_STATUS_INVALID;
+
+ int retval = ::ioctl(fHdl, CCCI_IOC_GET_MD_STATE, &status);
+ if (mIsModemEPOF == true) {
+ ALOGD("%s() MD EPOF!", __FUNCTION__);
+ status = MODEM_STATUS_INVALID;
+ } else if (retval < 0) {
+ ALOGE("%s() ioctl CCCI_IOC_GET_MD_STATE fail!! retval = %d, errno: %d", __FUNCTION__, retval, errno);
+ status = MODEM_STATUS_EXPT;
+ }
+
+#if defined(MTK_ECCCI_LPBK_TEST) //use eccci loopback for test, md status always set ready
+ status = MODEM_STATUS_READY;
+#endif
+ return (char)status;
+}
+
+bool SpeechMessengerECCCI::CheckModemIsReady() {
+ return (GetModemCurrentStatus() == MODEM_STATUS_READY);
+}
+
+status_t SpeechMessengerECCCI::WaitUntilModemReady() {
+ char status = 0;
+ uint32_t trycnt = 0;
+ const uint32_t kMaxTryCnt = 10; // total 200 msec
+ do {
+ status = GetModemCurrentStatus();
+ if (status == MODEM_STATUS_READY) {
+ ALOGD("%s(): Modem ready", __FUNCTION__);
+ break;
+ } else {
+ ALOGW("Wait CCCI open #%d times, modem current status = %d, errno: %d", ++trycnt, status, errno);
+ sph_msleep(20);
+ if (trycnt == kMaxTryCnt) { break; }
+ }
+ } while (1);
+
+ return (trycnt < kMaxTryCnt) ? NO_ERROR : TIMED_OUT;
+}
+
+#undef LOG_TAG
+#define LOG_TAG "SpeechMessengerECCCI_Send"
+
+int32_t SpeechMessengerECCCI::SendMessage(const ccci_buff_t &ccci_buff) {
+ ECCCI_BUFF_T msgBuf;
+ uint16_t length_write, size_message;
+ int8_t *pShareBuf;
+ ALOGV("%s()", __FUNCTION__);
+
+ // check if already initialized
+ if (fHdl < 0) {
+ if (Initial() != NO_ERROR) {
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ // check if need ack
+ uint16_t message_id = GetMessageID(ccci_buff);
+ const bool b_need_ack = (JudgeAckOfMsg(message_id) == MESSAGE_NEED_ACK) ? true : false;
+ uint16_t size_payload = GetMessageLength(ccci_buff);//(6+len_data)
+ uint16_t offset_buffer = GetMessageOffset(ccci_buff);
+
+ // check modem status during phone call
+ char modem_status = GetModemCurrentStatus();
+ if (modem_status != MODEM_STATUS_READY) {
+ ALOGE("%s(), modem_status(%d) != MODEM_STATUS_READY, errno: %d, mIsModemEPOF = %d", __FUNCTION__, modem_status, errno, mIsModemEPOF);
+ mIsModemResetDuringPhoneCall = true;
+ mIsModemReset = true;
+ ResetSpeechParamAckCount();
+ }
+
+ // Do not send any on/off message when mIsModemResetDuringPhoneCall is true
+ if (mIsModemResetDuringPhoneCall == true && IsModemFunctionOnOffMessage(message_id) == true) {
+ ALOGE("%s(), mIsModemResetDuringPhoneCall == true, drop on/off message: 0x%x", __FUNCTION__, ccci_buff.message);
+ SendMsgFailErrorHandling(ccci_buff);
+
+ // clean mIsModemResetDuringPhoneCall when phone call/loopback stop
+ if (message_id == MSG_A2M_SPH_OFF) {
+ ALOGD("%s(), Phone call stop. Set mIsModemResetDuringPhoneCall = false", __FUNCTION__);
+ mIsModemResetDuringPhoneCall = false;
+ } else if (message_id == MSG_A2M_SET_ACOUSTIC_LOOPBACK) {
+ const bool loopback_on = GetMessageParam(ccci_buff) & 0x1;
+ if (loopback_on == false) {
+ ALOGD("%s(), loopback stop. Set mIsModemResetDuringPhoneCall = false", __FUNCTION__);
+ mIsModemResetDuringPhoneCall = false;
+ }
+ }
+
+ return UNKNOWN_ERROR;
+ }
+
+ // save ack info before write to avoid race condition with CCCIReadThread
+ if (b_need_ack == true) {
+ mWaitAckMessageID = message_id;
+ }
+
+ // send message
+ int i = 0;
+ int write_length = 0;
+ modem_status = 0;
+ status_t ret = UNKNOWN_ERROR;
+ message_id = GetMessageID(ccci_buff);
+ memcpy(&msgBuf, &ccci_buff, sizeof(ccci_buff_t));
+ switch (message_id) {
+ case MSG_A2M_PNW_DL_DATA_NOTIFY:
+ case MSG_A2M_BGSND_DATA_NOTIFY:
+ case MSG_A2M_CTM_DATA_NOTIFY:
+ case MSG_A2M_EM_NB:
+ case MSG_A2M_EM_WB: // case AUDIO_HD_RECORD_PARAMETER:
+ case MSG_A2M_EM_DMNR:
+ case MSG_A2M_EM_MAGICON:
+ case MSG_A2M_EM_HAC:
+ case MSG_A2M_VIBSPK_PARAMETER:
+ case MSG_A2M_SMARTPA_PARAMETER:
+#ifdef USE_CCCI_SHARE_BUFFER
+ //case MSG_A2M_EM_DYNAMIC_SPH:
+#else
+ case MSG_A2M_EM_DYNAMIC_SPH:
+#endif
+ msgBuf.data[0] = 0;
+ //copy buffer
+ pShareBuf = (int8_t *)GetA2MShareBufBase() + offset_buffer;
+ size_message = size_payload + CCCI_BUF_HEADER_SIZE;
+ memcpy(msgBuf.payload, pShareBuf, size_payload);
+ ALOGV("SendMessage with Buffer: msgBuf.message = 0x%x, size_message = 0x%x, size_payload = 0x%x", msgBuf.data[1], size_message, size_payload);
+ memcpy(msgBuf.payload, pShareBuf, size_payload);
+#ifdef CONFIG_MT_ENG_BUILD // eng load
+ ALOGD("SendMessage ch = 0x%x, reserved=0x%x, msgBuf.payload[0] = 0x%x, payload[1]=0x%x, payload[2] = 0x%x, payload[3]=0x%x", msgBuf.channel, msgBuf.reserved, msgBuf.payload[0], msgBuf.payload[1], msgBuf.payload[2], msgBuf.payload[3]);
+#else
+ if (JudgeLogPrintOfMsg(message_id)) {
+ ALOGD("SendMessage ch = 0x%x, reserved=0x%x, msgBuf.payload[0] = 0x%x, payload[1]=0x%x, payload[2] = 0x%x, payload[3]=0x%x", msgBuf.channel, msgBuf.reserved, msgBuf.payload[0], msgBuf.payload[1], msgBuf.payload[2], msgBuf.payload[3]);
+ } else {
+ ALOGV("SendMessage ch = 0x%x, reserved=0x%x, msgBuf.payload[0] = 0x%x, payload[1]=0x%x, payload[2] = 0x%x, payload[3]=0x%x", msgBuf.channel, msgBuf.reserved, msgBuf.payload[0], msgBuf.payload[1], msgBuf.payload[2], msgBuf.payload[3]);
+ }
+#endif
+ break;
+
+ case MSG_A2M_SPH_UL_ENCRYPTION:
+ case MSG_A2M_SPH_DL_DECRYPTION:
+ msgBuf.data[0] = 0;
+ //copy buffer
+ pShareBuf = (int8_t *)mSphPCMBuf + offset_buffer;
+
+ ALOGD_IF(mLogEnable, "%s(), with Buffer: message[0x%x], pShareBuf = %p, size_payload = 0x%x", __FUNCTION__, msgBuf.data[1], pShareBuf, size_payload);
+ size_message = size_payload + CCCI_BUF_HEADER_SIZE;
+ memcpy(msgBuf.payload, pShareBuf, size_payload);
+ ALOGD_IF(mLogEnable, "SendMessage with Buffer: msgBuf.message = 0x%x, size_message = 0x%x, size_payload = 0x%x", msgBuf.data[1], size_message, size_payload);
+ memcpy(msgBuf.payload, pShareBuf, size_payload);
+ ALOGD_IF(mLogEnable, "SendMessage ch = 0x%x, reserved=0x%x, msgBuf.payload[0] = 0x%x, payload[1]=0x%x, payload[2] = 0x%x, payload[3]=0x%x", msgBuf.channel , msgBuf.reserved, msgBuf.payload[0], msgBuf.payload[1], msgBuf.payload[2], msgBuf.payload[3]);
+ break;
+
+ default:
+ size_message = CCCI_BUF_HEADER_SIZE;
+ ALOGD("SendMessage only command: msgBuf.message = 0x%x, size_message = 0x%x", msgBuf.data[1], size_message);
+ break;
+ }
+ // ALOGD("SendMessage ccci_buff.magic = 0x%x, message=0x%x, channel = 0x%x, reserved=0x%x", ccci_buff.magic, ccci_buff.message, ccci_buff.channel, msgBuf.reserved);
+#ifdef CONFIG_MT_ENG_BUILD // eng load
+ ALOGD("SendMessage msgBuf.data[0] = 0x%x, data[1]=0x%x, ch = 0x%x, reserved=0x%x", msgBuf.data[0], msgBuf.data[1], msgBuf.channel, msgBuf.reserved);
+#else // user and user-debug load
+ ALOGD_IF(mLogEnable, "SendMessage msgBuf.data[0] = 0x%x, data[1]=0x%x, ch = 0x%x, reserved=0x%x", msgBuf.data[0], msgBuf.data[1], msgBuf.channel , msgBuf.reserved);
+#endif
+
+
+ for (i = 0; i < 150; i++) { // try 150 times for every 2 ms if sent message fail
+ length_write = write(fHdl, (void *)&msgBuf, size_message);
+ ALOGV("%s() write %d times, return length_write=%d, size_message=%d", __FUNCTION__, i, length_write, size_message);
+ switch (message_id) {
+ case MSG_A2M_EM_NB:
+ case MSG_A2M_EM_WB: // case AUDIO_HD_RECORD_PARAMETER:
+ case MSG_A2M_EM_DMNR:
+ case MSG_A2M_EM_MAGICON:
+ case MSG_A2M_EM_HAC:
+ case MSG_A2M_VIBSPK_PARAMETER:
+ case MSG_A2M_SMARTPA_PARAMETER:
+ A2MBufUnLock();
+ break;
+#ifndef USE_CCCI_SHARE_BUFFER
+ case MSG_A2M_EM_DYNAMIC_SPH:
+ A2MBufUnLock();
+ break;
+#endif
+ }
+
+ if (length_write == size_message) {
+ LastSentMessage = message_id;
+ if (MESSAGE_NEED_ACK == JudgeAckOfMsg(message_id)) {
+ LastNeedAckSentMessage = message_id;
+ }
+ ret = NO_ERROR;
+ break;
+ } else {
+ modem_status = GetModemCurrentStatus();
+ if (errno == 3 || modem_status != MODEM_STATUS_READY) { // md reset cause ccci message fail
+ ALOGE("%s(), MD RESET SKIP MESSAGE: 0x%x, try: #%d, write_length: %d, errno: %d, modem status: %d",
+ __FUNCTION__, ccci_buff.message, i, write_length, errno, modem_status);
+ // if modem reset during phone call, raise mIsModemResetDuringPhoneCall
+ if (message_id != MSG_A2M_SPH_OFF && message_id != MSG_A2M_SET_ACOUSTIC_LOOPBACK) {
+ mIsModemResetDuringPhoneCall = true;
+ }
+
+ mIsModemReset = true;
+ ResetSpeechParamAckCount();
+ break;
+ }
+ ALOGW("%s(), message: 0x%x, try: #%d, write_length: %d, errno: %d, modem status: %d",
+ __FUNCTION__, ccci_buff.message, i, write_length, errno, modem_status);
+
+ sph_msleep(2);
+ }
+ }
+
+ // error handling for ack message
+ if (ret != NO_ERROR && b_need_ack == true) {
+ mWaitAckMessageID = 0;
+ SendMsgFailErrorHandling(ccci_buff);
+ }
+
+ return ret;
+
+}
+#undef LOG_TAG
+#define LOG_TAG "SpeechMessengerECCCI_Read"
+status_t SpeechMessengerECCCI::ReadMessage(ccci_buff_t &ccci_buff) {
+ uint32_t length_payload, modem_status, temp_msg1, temp_msg2;
+ ALOGV("%s()", __FUNCTION__);
+
+ /* check if already initialized */
+ if (fHdl < 0) {
+ if (Initial() != NO_ERROR) {
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ /* read message */
+ int length_read = read(fHdl, (void *)&ccci_buff, sizeof(ccci_buff_t));
+ if (length_read == -1) {
+ modem_status = GetModemCurrentStatus();
+ ALOGE("%s() fail, read_length: %d, modem current status: %d, errno: %d",
+ __FUNCTION__, length_read, modem_status, errno);
+ return UNKNOWN_ERROR;
+ } else {
+ uint16_t message_id = GetMessageID(ccci_buff);
+ if (ccci_buff.magic != CCCI_MAILBOX_MAGIC_NUMBER) {
+ ccci_buff.message -= CCCI_BUF_HEADER_SIZE; // reduce header size
+ }
+#ifndef CONFIG_MT_ENG_BUILD// user and user debug load
+ // do not print per frame message for message with data payload in user and user-debug load
+ if (ccci_buff.magic == CCCI_MAILBOX_MAGIC_NUMBER && JudgeLogPrintOfMsg(message_id)) {
+ ALOGD("%s(), length_read=%d, data[0](magic)=0x%x, data[1](message)=0x%x, ch=0x%x, reserved=0x%x",
+ __FUNCTION__, length_read, ccci_buff.magic, ccci_buff.message, ccci_buff.channel,
+ ccci_buff.reserved);
+ }
+#else // eng load
+ ALOGD("%s(), length_read=%d, data[0](magic)=0x%x, data[1](message)=0x%x, ch=0x%x, reserved=0x%x",
+ __FUNCTION__, length_read, ccci_buff.magic, ccci_buff.message, ccci_buff.channel, ccci_buff.reserved);
+#endif
+ if (message_id == MSG_M2A_EM_DATA_REQUEST) {
+ mIsModemEPOF = false;
+ }
+ modem_status = GetModemCurrentStatus();
+ if (modem_status != MODEM_STATUS_READY) {
+ ALOGE("%s() fail, read_length: %d, modem current status: %d, errno: %d, mIsModemEPOF(%d)",
+ __FUNCTION__, length_read, modem_status, errno, mIsModemEPOF);
+ return UNKNOWN_ERROR;
+ }
+ }
+ return NO_ERROR;
+}
+
+#undef LOG_TAG
+#define LOG_TAG "SpeechMessengerECCCI"
+
+uint32_t SpeechMessengerECCCI::GetQueueCount() const {
+ int32_t count = (iQWrite - iQRead);
+ if (count < 0) { count += CCCI_MAX_QUEUE_NUM; }
+ return count;
+}
+
+bool SpeechMessengerECCCI::CheckOffsetAndLength(const ccci_buff_t &ccci_buff) {
+ uint16_t message_id = GetMessageID(ccci_buff);
+ uint16_t length = GetMessageLength(ccci_buff);
+ uint16_t offset = GetMessageOffset(ccci_buff);
+
+ if (offset > mM2AShareBufLen || length > mM2AShareBufLen) {
+ ALOGE("%s(), message_id = 0x%x, length(0x%x), offset(0x%x), mM2AShareBufLen(0x%x)", __FUNCTION__, message_id, length, offset, mM2AShareBufLen);
+ ASSERT(offset > mM2AShareBufLen || length > mM2AShareBufLen);
+ return false;
+ } else {
+ return true;
+ }
+}
+
+
+ccci_message_ack_t SpeechMessengerECCCI::JudgeAckOfMsg(const uint16_t message_id) {
+ ccci_message_ack_t ack;
+ switch (message_id) {
+ case MSG_A2M_SET_SPH_MODE:
+ case MSG_A2M_SPH_ON:
+ case MSG_A2M_SPH_OFF:
+ case MSG_A2M_SPH_ROUTER_ON:
+ case MSG_A2M_PCM_REC_ON:
+ case MSG_A2M_VM_REC_ON:
+ case MSG_A2M_PCM_REC_OFF:
+ case MSG_A2M_VM_REC_OFF:
+ case MSG_A2M_BGSND_ON:
+ case MSG_A2M_BGSND_OFF:
+ case MSG_A2M_PNW_ON:
+ case MSG_A2M_PNW_OFF:
+ case MSG_A2M_CTM_ON:
+ case MSG_A2M_CTM_OFF:
+ case MSG_A2M_SET_ACOUSTIC_LOOPBACK:
+ case MSG_A2M_EM_NB:
+ case MSG_A2M_EM_DMNR:
+ case MSG_A2M_EM_MAGICON:
+ case MSG_A2M_EM_HAC:
+ case MSG_A2M_EM_WB:
+ case MSG_A2M_VIBSPK_PARAMETER:
+ case MSG_A2M_SMARTPA_PARAMETER:
+ case MSG_A2M_RECORD_RAW_PCM_ON:
+ case MSG_A2M_RECORD_RAW_PCM_OFF:
+ case MSG_A2M_EM_DYNAMIC_SPH:
+ ack = MESSAGE_NEED_ACK;
+ break;
+ default:
+ ack = MESSAGE_BYPASS_ACK;
+ }
+ return ack;
+}
+
+bool SpeechMessengerECCCI::JudgeLogPrintOfMsg(const uint16_t message_id) {
+ bool isLogPrint = true;
+ switch (message_id) {
+ case MSG_A2M_PNW_DL_DATA_NOTIFY:
+ case MSG_A2M_BGSND_DATA_NOTIFY:
+ case MSG_A2M_CTM_DATA_NOTIFY:
+ case MSG_A2M_SPH_UL_ENCRYPTION:
+ case MSG_A2M_SPH_DL_DECRYPTION:
+ case MSG_A2M_PNW_UL_DATA_READ_ACK:
+ case MSG_A2M_REC_DATA_READ_ACK:
+ case MSG_A2M_CTM_DEBUG_DATA_READ_ACK:
+ case MSG_A2M_PCM_REC_DATA_READ_ACK:
+ case MSG_A2M_VM_REC_DATA_READ_ACK:
+ case MSG_A2M_RAW_PCM_REC_DATA_READ_ACK:
+ case MSG_A2M_CUST_DUMP_READ_ACK:
+ case MSG_M2A_PNW_DL_DATA_REQUEST:
+ case MSG_M2A_BGSND_DATA_REQUEST:
+ case MSG_M2A_CTM_DATA_REQUEST:
+ case MSG_M2A_SPH_UL_ENCRYPTION:
+ case MSG_M2A_SPH_DL_DECRYPTION:
+ case MSG_M2A_PNW_UL_DATA_NOTIFY:
+ case MSG_M2A_CTM_DEBUG_DATA_NOTIFY:
+ case MSG_M2A_PCM_REC_DATA_NOTIFY:
+ case MSG_M2A_VM_REC_DATA_NOTIFY:
+ case MSG_M2A_RAW_PCM_REC_DATA_NOTIFY:
+ case MSG_M2A_CUST_DUMP_NOTIFY:
+ isLogPrint = false;
+ break;
+ default:
+ isLogPrint = true;
+ }
+ return isLogPrint;
+}
+
+bool SpeechMessengerECCCI::IsModemFunctionOnOffMessage(const uint16_t message_id) {
+ bool bIsModemFunctionOnOffMessage = false;
+
+ switch (message_id) {
+ case MSG_A2M_SPH_ON:
+ case MSG_A2M_SPH_OFF:
+ case MSG_A2M_SPH_ROUTER_ON:
+ case MSG_A2M_PCM_REC_ON:
+ case MSG_A2M_VM_REC_ON:
+ case MSG_A2M_PCM_REC_OFF:
+ case MSG_A2M_VM_REC_OFF:
+ case MSG_A2M_BGSND_ON:
+ case MSG_A2M_BGSND_OFF:
+ case MSG_A2M_PNW_ON:
+ case MSG_A2M_PNW_OFF:
+ case MSG_A2M_CTM_ON:
+ case MSG_A2M_CTM_OFF:
+ case MSG_A2M_SET_ACOUSTIC_LOOPBACK:
+ case MSG_A2M_RECORD_RAW_PCM_ON:
+ case MSG_A2M_RECORD_RAW_PCM_OFF:
+ bIsModemFunctionOnOffMessage = true;
+ break;
+ default:
+ bIsModemFunctionOnOffMessage = false;
+ }
+
+ return bIsModemFunctionOnOffMessage;
+}
+
+status_t SpeechMessengerECCCI::SendMessageInQueue(ccci_buff_t ccci_buff) {
+ AL_LOCK(mCCCIMessageQueueMutex);
+ status_t ret = NO_ERROR;
+
+ // check modem status during phone call
+ char modem_status = GetModemCurrentStatus();
+ if (modem_status != MODEM_STATUS_READY) {
+ ALOGE("%s(), modem_status(%d) != MODEM_STATUS_READY, errno: %d, mIsModemEPOF = %d", __FUNCTION__, modem_status, errno, mIsModemEPOF);
+ mIsModemResetDuringPhoneCall = true;
+ mIsModemReset = true;
+ ResetSpeechParamAckCount();
+ AL_UNLOCK(mCCCIMessageQueueMutex);
+ uint16_t message_id = GetMessageID(ccci_buff);
+ switch (message_id) {
+ case MSG_A2M_EM_NB:
+ case MSG_A2M_EM_WB:
+ case MSG_A2M_EM_DMNR:
+ case MSG_A2M_EM_MAGICON:
+ case MSG_A2M_EM_HAC:
+ case MSG_A2M_VIBSPK_PARAMETER:
+ case MSG_A2M_SMARTPA_PARAMETER:
+#ifndef USE_CCCI_SHARE_BUFFER
+ case MSG_A2M_EM_DYNAMIC_SPH:
+#endif
+ {
+ A2MBufUnLock();
+ break;
+ }
+ }
+ return ret;
+ }
+ uint32_t count = GetQueueCount();
+ ASSERT(count < (CCCI_MAX_QUEUE_NUM - 1)); // check queue full
+
+ ccci_message_ack_t ack_type = JudgeAckOfMsg(GetMessageID(ccci_buff));
+
+ if (ack_type == MESSAGE_NEED_ACK) {
+ ALOGV("%s(), mModemIndex = %d, need ack message: 0x%x, reserved param: 0x%x",
+ __FUNCTION__, mModemIndex, ccci_buff.message, ccci_buff.reserved);
+ }
+ if (mIsModemEPOF == true) {
+ ALOGD("%s(), mIsModemEPOF=%d, Skip message(0x%x) to queue, now count(%u)", __FUNCTION__, mIsModemEPOF, ccci_buff.message, GetQueueCount());
+ A2MBufUnLock();
+
+ } else {
+ if (count == 0) { // queue is empty
+ if (ack_type == MESSAGE_BYPASS_ACK) { // no need ack, send directly, don't care ret value
+ ret = SendMessage(ccci_buff);
+ } else { // need ack, en-queue and send message
+ pQueue[iQWrite].ccci_buff = ccci_buff;
+ pQueue[iQWrite].ack_type = ack_type;
+ iQWrite++;
+ if (iQWrite == CCCI_MAX_QUEUE_NUM) { iQWrite -= CCCI_MAX_QUEUE_NUM; }
+
+ ret = SendMessage(ccci_buff);
+ if (ret != NO_ERROR) { // skip this fail CCCI message
+ iQRead++;
+ if (iQRead == CCCI_MAX_QUEUE_NUM) { iQRead -= CCCI_MAX_QUEUE_NUM; }
+ }
+ }
+ } else { // queue is not empty, must queue the element
+ pQueue[iQWrite].ccci_buff = ccci_buff;
+ pQueue[iQWrite].ack_type = ack_type;
+ iQWrite++;
+ if (iQWrite == CCCI_MAX_QUEUE_NUM) { iQWrite -= CCCI_MAX_QUEUE_NUM; }
+
+ ALOGD("%s(), Send message(0x%x) to queue, reserve param(0x%x), mModemIndex(%d),count(%u), LastSentMessage(0x%x), LastNeedAckSentMessage(0x%x)", __FUNCTION__, ccci_buff.message, ccci_buff.reserved, mModemIndex, GetQueueCount(), LastSentMessage, LastNeedAckSentMessage);
+ }
+ }
+ AL_UNLOCK(mCCCIMessageQueueMutex);
+ return ret;
+}
+
+status_t SpeechMessengerECCCI::ConsumeMessageInQueue() {
+ AL_LOCK(mCCCIMessageQueueMutex);
+
+ uint32_t count = GetQueueCount();
+ if (count > 10) {
+ ALOGW("%s(), queue count: %u", __FUNCTION__, count);
+ }
+
+ if (count == 0) {
+ ALOGW("%s(), no message in queue", __FUNCTION__);
+ AL_UNLOCK(mCCCIMessageQueueMutex);
+ return UNKNOWN_ERROR;
+ }
+
+ status_t ret = NO_ERROR;
+ ALOGD("%s,start count [%d]", __FUNCTION__, count);
+ while (1) {
+ // when entering this function, the first message in queue must be a message waiting for ack
+ // so we increment index, consuming the first message in queue
+ iQRead++;
+ if (iQRead == CCCI_MAX_QUEUE_NUM) { iQRead -= CCCI_MAX_QUEUE_NUM; }
+
+ // check if empty
+ if (iQRead == iQWrite) {
+ ret = NO_ERROR;
+ break;
+ }
+
+ // update count
+ count = GetQueueCount();
+
+ // send message
+ if (pQueue[iQRead].ack_type == MESSAGE_BYPASS_ACK) { // no need ack, send directly, don't care ret value
+ ALOGV("%s(), no need ack message: 0x%x, count: %u", __FUNCTION__, pQueue[iQRead].ccci_buff.message, count);
+ ret = SendMessage(pQueue[iQRead].ccci_buff);
+ } else if (pQueue[iQRead].ack_type == MESSAGE_NEED_ACK) {
+ ALOGV("%s(), need ack message: 0x%x, count: %u", __FUNCTION__, pQueue[iQRead].ccci_buff.message, count);
+ ret = SendMessage(pQueue[iQRead].ccci_buff);
+ if (ret == NO_ERROR) { // Send CCCI message success and wait for ack
+ break;
+ }
+ } else if (pQueue[iQRead].ack_type == MESSAGE_CANCELED) { // the cancelled message, ignore it
+ ALOGD("%s(), cancel on-off-on message: 0x%x, count: %u", __FUNCTION__, pQueue[iQRead].ccci_buff.message, count);
+ ret = NO_ERROR;
+ }
+ }
+ ALOGD("%s,end left Count %d", __FUNCTION__, count);
+ AL_UNLOCK(mCCCIMessageQueueMutex);
+ return ret;
+}
+
+bool SpeechMessengerECCCI::MDReset_CheckMessageInQueue() {
+ AL_LOCK(mCCCIMessageQueueMutex);
+ uint32_t count = GetQueueCount();
+ ALOGD("%s(), queue count: %u", __FUNCTION__, count);
+
+ bool ret = true;
+ while (1) {
+ // Modem already reset.
+ // Check every CCCI message in queue.
+ // These messages that are sent before modem reset, don't send to modem.
+ // But AP side need to do related action to make AP side in the correct state.
+
+ // check if empty
+ if (iQRead == iQWrite) {
+ ALOGD("%s(), check message done", __FUNCTION__);
+ ret = true;
+ break;
+ }
+
+ // Need ack message. But modem reset, so simulate that the modem send back ack msg.
+ if (JudgeAckOfMsg(GetMessageID(pQueue[iQRead].ccci_buff)) == MESSAGE_NEED_ACK) {
+ SendMsgFailErrorHandling(pQueue[iQRead].ccci_buff);
+ }
+
+ iQRead++;
+ if (iQRead == CCCI_MAX_QUEUE_NUM) { iQRead -= CCCI_MAX_QUEUE_NUM; }
+ }
+#ifdef USE_CCCI_SHARE_BUFFER
+ // init CCCI buffer again no matter what
+ InitA2MRawParaRingBuffer();
+#endif
+ if (count != 0) {
+ ALOGE("%s(), queue is not empty!!", __FUNCTION__);
+ iQWrite = 0;
+ iQRead = 0;
+ }
+
+ AL_UNLOCK(mCCCIMessageQueueMutex);
+ return ret;
+}
+
+bool SpeechMessengerECCCI::GetMDResetFlag() {
+ ALOGD("%s(), mIsModemReset=%d", __FUNCTION__, mIsModemReset);
+ return mIsModemReset;
+}
+
+status_t SpeechMessengerECCCI::CreateReadingThread() {
+ int ret = pthread_create(&hReadThread, NULL, SpeechMessengerECCCI::CCCIReadThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+ return NO_ERROR;
+}
+
+void *SpeechMessengerECCCI::CCCIReadThread(void *arg) {
+ pthread_detach(pthread_self());
+
+ prctl(PR_SET_NAME, (unsigned long)__FUNCTION__, 0, 0, 0);
+
+ SpeechMessengerECCCI *pCCCI = (SpeechMessengerECCCI *)arg;
+#if 1
+ // Adjust thread priority
+ int rtnPrio = setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+ if (0 != rtnPrio) {
+ ALOGE("[%s] failed, errno: %d, return=%d", __FUNCTION__, errno, rtnPrio);
+ } else {
+ ALOGD("%s setpriority ok, priority: %d", __FUNCTION__, ANDROID_PRIORITY_AUDIO);
+ }
+#else
+ // force to set priority
+ struct sched_param sched_p;
+ sched_getparam(0, &sched_p);
+ sched_p.sched_priority = 92;//RTPM_PRIO_AUDIO_CCCI_THREAD;
+ if (0 != sched_setscheduler(0, SCHED_RR, &sched_p)) {
+ ALOGE("[%s] failed, errno: %d", __FUNCTION__, errno);
+ } else {
+ sched_p.sched_priority = 92;//RTPM_PRIO_AUDIO_CCCI_THREAD;
+ sched_getparam(0, &sched_p);
+ ALOGD("%s sched_setscheduler ok, priority: %d", __FUNCTION__, sched_p.sched_priority);
+ }
+#endif
+ ALOGD("%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+
+ // Handle CCCI Message From Modems
+ while (pCCCI->CCCIEnable) {
+ /// read message
+ ccci_buff_t ccci_buff;
+ memset((void *)&ccci_buff, 0, sizeof(ccci_buff));
+ status_t ret = pCCCI->ReadMessage(ccci_buff);
+ if (ret != NO_ERROR) {
+ ALOGD("%s(), ret(%d) != NO_ERROR", __FUNCTION__, ret);
+ sph_msleep(10);
+ continue;
+ }
+
+ /// handle message
+ uint16_t m2a_message_id = pCCCI->GetMessageID(ccci_buff);
+
+ switch (m2a_message_id) {
+ case MSG_M2A_SET_SPH_MODE_ACK: { // ack of MSG_A2M_SET_SPH_MODE
+ // Do nothing... just leave a log
+ ALOGV("--SetSpeechMode Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Speech */
+ case MSG_M2A_SPH_ON_ACK: { // ack of MSG_A2M_SPH_ON
+ phone_call_mode_t phone_call_mode = (phone_call_mode_t)pCCCI->GetMessageParam(ccci_buff);
+ if (phone_call_mode == RAT_3G324M_MODE) {
+ pCCCI->SetModemSideModemStatus(VT_STATUS_MASK);
+ } else {
+ pCCCI->SetModemSideModemStatus(SPEECH_STATUS_MASK);
+ }
+
+ //pCCCI->mLad->Signal();
+
+ ALOGD("--SpeechOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_SPH_OFF_ACK: { // ack of MSG_A2M_SPH_OFF
+ if (pCCCI->GetModemSideModemStatus(VT_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(VT_STATUS_MASK);
+ } else if (pCCCI->GetModemSideModemStatus(SPEECH_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(SPEECH_STATUS_MASK);
+ } else {
+ ALOGE("--SpeechOff Ack is not paired!!");
+ }
+
+ property_set(PROPERTY_KEY_NW_CODEC_INFO[0], "");
+ property_set(PROPERTY_KEY_NW_CODEC_INFO[1], "");
+
+ ALOGD("--SpeechOff Ack done(0x%x)", ccci_buff.message);
+ pCCCI->mLad->Signal();
+
+ break;
+ }
+
+ /* Speech Router */
+ case MSG_M2A_SPH_ROUTER_ON_ACK: { // ack of MSG_A2M_SPH_ROUTER_ON
+ const bool pcm_route_on = pCCCI->GetMessageParam(ccci_buff) & 0x1;
+ if (pcm_route_on == true) { // pcm route on
+ pCCCI->SetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+ } else { // pcm route off
+ if (pCCCI->GetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+ } else {
+ ALOGE("--SpeechRouterOn Ack is not paired!!");
+ }
+ }
+
+ ALOGV("--SpeechRouterOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Record */
+ case MSG_M2A_PCM_REC_ON_ACK: { // ack of MSG_A2M_PCM_REC_ON
+ pCCCI->SetModemSideModemStatus(RECORD_STATUS_MASK);
+ ALOGV("--recordOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_VM_REC_ON_ACK: { // ack of MSG_A2M_VM_REC_ON
+ pCCCI->SetModemSideModemStatus(VM_RECORD_STATUS_MASK);
+ ALOGV("--VMRecordOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_RECORD_RAW_PCM_ON_ACK: { // ack of MSG_A2M_RECORD_RAW_PCM_ON
+ pCCCI->SetModemSideModemStatus(RAW_RECORD_STATUS_MASK);
+ ALOGV("--RawRecordOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_PCM_REC_DATA_NOTIFY: { // meaning that we are recording, modem have some data
+ ALOGV("%s() MSG_M2A_PCM_REC_DATA_NOTIFY", __FUNCTION__);
+ ASSERT(pCCCI->GetModemSideModemStatus(RECORD_STATUS_MASK) == true);
+
+ if (pCCCI->mLad->GetApSideModemStatus(RECORD_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_PCM_REC_DATA_NOTIFY(0x%x) after AP side trun off record!! Drop it.", ccci_buff.message);
+ } else {
+ uint16_t Bytes_PCM = pCCCI->GetMessageLength(ccci_buff) - CCCI_PAYLOAD_BUFF_HEADER_LEN;
+ SLOGV("MSG_M2A_PCM_REC_DATA_NOTIFY(0x%x), data_length: %d", ccci_buff.message, Bytes_PCM);
+
+ // Phone record
+ AudioALSACaptureDataProviderVoice::getInstance()->provideModemRecordDataToProvider(pCCCI->GetM2AUplinkRingBuffer(ccci_buff));
+
+ if ((pCCCI->mLad->GetApSideModemStatus(RECORD_STATUS_MASK) == true) && (mA2M_ECCCI_DATA_READ_ACK == true)) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_PCM_REC_DATA_READ_ACK, 0, 0));
+ mA2M_ECCCI_DATA_READ_ACK = false;
+ } else {
+ ALOGD("%s() RECORD_STATUS_MASK(%d)", __FUNCTION__, pCCCI->mLad->GetApSideModemStatus(RECORD_STATUS_MASK));
+ }
+ }
+
+ break;
+ }
+ case MSG_M2A_RAW_PCM_REC_DATA_NOTIFY: { // meaning that we are recording, modem have some data
+ ALOGV("%s() MSG_M2A_RAW_PCM_REC_DATA_NOTIFY", __FUNCTION__);
+ ASSERT(pCCCI->GetModemSideModemStatus(RAW_RECORD_STATUS_MASK) == true);
+
+ if (pCCCI->mLad->GetApSideModemStatus(RAW_RECORD_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_PCM_REC_DATA_NOTIFY(0x%x) after AP side trun off record!! Drop it.", ccci_buff.message);
+ } else {
+ uint16_t Bytes_PCM = pCCCI->GetMessageLength(ccci_buff) - CCCI_PAYLOAD_BUFF_HEADER_LEN;
+ SLOGV("MSG_M2A_PCM_REC_DATA_NOTIFY(0x%x), data_length: %d", ccci_buff.message, Bytes_PCM);
+
+ // Phone record
+
+#ifndef TEST_NEW_RECOED_FOR_OLD_CAPTURE
+ SpeechDataProcessingHandler::getInstance()->provideModemRecordDataToProvider(pCCCI->GetM2ARawPcmRingBuffer(ccci_buff));
+#else
+ AudioALSACaptureDataProviderVoice::getInstance()->provideModemRecordDataToProvider(pCCCI->GetM2ARawPcmRingBuffer(ccci_buff));
+#endif
+
+ if ((pCCCI->mLad->GetApSideModemStatus(RAW_RECORD_STATUS_MASK) == true) && (mA2M_ECCCI_DATA_READ_ACK == true)) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_RAW_PCM_REC_DATA_READ_ACK, 0, 0));
+ mA2M_ECCCI_DATA_READ_ACK = false;
+ } else {
+ ALOGD("%s() RAW_RECORD_STATUS_MASK(%d)", __FUNCTION__, pCCCI->mLad->GetApSideModemStatus(RAW_RECORD_STATUS_MASK));
+ }
+ }
+
+ break;
+ }
+
+ case MSG_M2A_VM_REC_DATA_NOTIFY: { // meaning that we are recording, modem have some data
+ ASSERT(pCCCI->GetModemSideModemStatus(VM_RECORD_STATUS_MASK) == true);
+
+ if (pCCCI->mLad->GetApSideModemStatus(VM_RECORD_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_VM_REC_DATA_NOTIFY(0x%x) after AP side trun off record!! Drop it.", ccci_buff.message);
+ } else {
+ SLOGV("MSG_M2A_VM_REC_DATA_NOTIFY(0x%x), data_length: %u", ccci_buff.message, (unsigned int)(pCCCI->GetMessageLength(ccci_buff) - CCCI_PAYLOAD_BUFF_HEADER_LEN));
+
+ SpeechVMRecorder *pSpeechVMRecorder = SpeechVMRecorder::getInstance();
+ // VM
+ pSpeechVMRecorder->getVmDataFromModem(pCCCI->GetM2AUplinkRingBuffer(ccci_buff));
+
+ if ((pCCCI->mLad->GetApSideModemStatus(VM_RECORD_STATUS_MASK) == true) && (mA2M_ECCCI_DATA_READ_ACK == true)) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_VM_REC_DATA_READ_ACK, 0, 0));
+ mA2M_ECCCI_DATA_READ_ACK = false;
+ }
+ }
+ break;
+ }
+#ifdef SPH_VCL_SUPPORT
+
+ case MSG_M2A_CUST_DUMP_NOTIFY: { // meaning that we are recording, modem have some data
+ // check VCL need open
+ SpeechVoiceCustomLogger *pSpeechVoiceCustomLogger = SpeechVoiceCustomLogger::GetInstance();
+ if (pSpeechVoiceCustomLogger->GetVCLRecordStatus() == false) {
+ ALOGW("MSG_M2A_CUST_DUMP_NOTIFY(0x%x) after AP side trun off record!! Drop it.", ccci_buff.message);
+ } else {
+ ALOGD("MSG_M2A_CUST_DUMP_NOTIFY(0x%x), data_length: %d", ccci_buff.message, pCCCI->GetMessageLength(ccci_buff) - CCCI_PAYLOAD_BUFF_HEADER_LEN);
+
+ pSpeechVoiceCustomLogger->CopyBufferToVCL(pCCCI->GetM2AUplinkRingBuffer(ccci_buff));
+
+ if (mA2M_ECCCI_DATA_READ_ACK == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_CUST_DUMP_READ_ACK, 0, 0));
+ mA2M_ECCCI_DATA_READ_ACK = false;
+ }
+ }
+ break;
+ }
+#endif
+ case MSG_M2A_PCM_REC_OFF_ACK: { // ack of MSG_A2M_PCM_REC_OFF
+ if (pCCCI->GetModemSideModemStatus(RECORD_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--recordOff Ack is not paired!!");
+ }
+ ALOGV("--recordOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_VM_REC_OFF_ACK: { // ack of MSG_A2M_VM_REC_OFF
+ if (pCCCI->GetModemSideModemStatus(VM_RECORD_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(VM_RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--VMRecordOff Ack is not paired!!");
+ }
+ ALOGV("--VMRecordOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_RECORD_RAW_PCM_OFF_ACK: { // ack of MSG_A2M_RECORD_RAW_PCM_OFF
+ if (pCCCI->GetModemSideModemStatus(RAW_RECORD_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(RAW_RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--RawRecordOff Ack is not paired!!");
+ }
+ ALOGV("--RawRecordOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Background sound */
+ case MSG_M2A_BGSND_ON_ACK: { // ack of MSG_A2M_BGSND_ON
+ pCCCI->SetModemSideModemStatus(BGS_STATUS_MASK);
+ ALOGV("--BGSoundOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_BGSND_DATA_REQUEST: { // modem request bgs data to play
+ ASSERT(pCCCI->GetModemSideModemStatus(BGS_STATUS_MASK) == true);
+
+ BGSPlayer *pBGSPlayer = BGSPlayer::GetInstance();
+ if (pCCCI->mLad->GetApSideModemStatus(BGS_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_BGSND_DATA_REQUEST(0x%x) after AP side trun off BGS!! Drop it.", ccci_buff.message);
+ } else {
+ SLOGV("MSG_M2A_BGSND_DATA_REQUEST(0x%x), num_data_request: %d", ccci_buff.message, pCCCI->GetMessageParam(ccci_buff));
+
+ // parse size of data request
+ uint16_t num_data_request = pCCCI->GetMessageParam(ccci_buff);
+ uint32_t max_buf_length = A2M_SHARED_BUFFER_BGS_DATA_SIZE - CCCI_SHARE_BUFF_HEADER_LEN;
+ if (num_data_request > max_buf_length) { num_data_request = max_buf_length; }
+
+ // get bgs share buffer address
+ uint16_t offset = A2M_SHARED_BUFFER_BGS_DATA_BASE;
+ char *p_header_address = pCCCI->GetA2MShareBufBase() + offset;
+ char *p_data_address = p_header_address + CCCI_SHARE_BUFF_HEADER_LEN;
+
+ // fill playback data
+ uint16_t data_length = pBGSPlayer->PutDataToSpeaker(p_data_address, num_data_request);
+
+ // fill header info
+ pCCCI->SetShareBufHeader((uint16_t *)p_header_address,
+ CCCI_A2M_SHARE_BUFF_HEADER_SYNC,
+ SHARE_BUFF_DATA_TYPE_CCCI_BGS_TYPE,
+ data_length);
+
+ // send data notify to modem side
+ const uint16_t message_length = CCCI_SHARE_BUFF_HEADER_LEN + data_length;
+ if (pCCCI->mLad->GetApSideModemStatus(BGS_STATUS_MASK) == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_BGSND_DATA_NOTIFY, message_length, offset));
+ }
+ }
+
+ break;
+ }
+ case MSG_M2A_BGSND_OFF_ACK: { // ack of MSG_A2M_BGSND_OFF
+ if (pCCCI->GetModemSideModemStatus(BGS_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(BGS_STATUS_MASK);
+ } else {
+ ALOGE("--BGSoundOff Ack is not paired!!");
+ }
+ ALOGV("--BGSoundOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* PCM2Way */
+ case MSG_M2A_PNW_ON_ACK: { // ack of MSG_A2M_PNW_ON
+ pCCCI->SetModemSideModemStatus(P2W_STATUS_MASK);
+ ALOGV("--PCM2WayOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_PNW_UL_DATA_NOTIFY: { // Get Microphone data from Modem
+ ASSERT(pCCCI->GetModemSideModemStatus(P2W_STATUS_MASK) == true);
+
+ Record2Way *pRecord2Way = Record2Way::GetInstance();
+ if (pCCCI->mLad->GetApSideModemStatus(P2W_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_PNW_UL_DATA_NOTIFY(0x%x) after AP side trun off PCM2Way!! Drop it.", ccci_buff.message);
+ } else {
+ SLOGV("MSG_M2A_PNW_UL_DATA_NOTIFY(0x%x), data_length:%u", ccci_buff.message, (unsigned int)(pCCCI->GetMessageLength(ccci_buff) - CCCI_PAYLOAD_BUFF_HEADER_LEN));
+ pRecord2Way->GetDataFromMicrophone(pCCCI->GetM2AUplinkRingBuffer(ccci_buff));
+ if ((pCCCI->mLad->GetApSideModemStatus(P2W_STATUS_MASK) == true) && (mA2M_ECCCI_DATA_READ_ACK == true)) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_PNW_UL_DATA_READ_ACK, 0, 0));
+ mA2M_ECCCI_DATA_READ_ACK = false;
+ }
+ }
+
+#if 0 // PCM2WAY: UL -> DL Loopback
+ // Used for debug and Speech DVT
+ uint16_t size_bytes = 320;
+ char buffer[320];
+ pRecord2Way->Read(buffer, size_bytes);
+ Play2Way::GetInstance()->Write(buffer, size_bytes);
+#endif
+ break;
+ }
+ case MSG_M2A_PNW_DL_DATA_REQUEST: { // Put Data to modem and play
+ ASSERT(pCCCI->GetModemSideModemStatus(P2W_STATUS_MASK) == true);
+
+ if (pCCCI->mLad->GetApSideModemStatus(P2W_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_PNW_DL_DATA_REQUEST(0x%x) after AP side trun off PCM2Way!! Drop it.", ccci_buff.message);
+ } else {
+ SLOGV("MSG_M2A_PNW_DL_DATA_REQUEST(0x%x), num_data_request: %d", ccci_buff.message, pCCCI->GetMessageParam(ccci_buff));
+
+ // parse size of data request
+ uint16_t num_data_request = pCCCI->GetMessageParam(ccci_buff);
+ uint32_t max_buf_length = A2M_SHARED_BUFFER_P2W_DL_DATA_SIZE - CCCI_SHARE_BUFF_HEADER_LEN;
+ if (num_data_request > max_buf_length) { num_data_request = max_buf_length; }
+
+ // get pcm2way share buffer address
+ uint16_t offset = A2M_SHARED_BUFFER_P2W_DL_DATA_BASE;
+ char *p_header_address = pCCCI->GetA2MShareBufBase() + offset;
+ char *p_data_address = p_header_address + CCCI_SHARE_BUFF_HEADER_LEN;
+
+ // fill playback data
+ Play2Way *pPlay2Way = Play2Way::GetInstance();
+ const uint16_t data_length = pPlay2Way->PutDataToSpeaker(p_data_address, num_data_request);
+
+ // fill header info
+ pCCCI->SetShareBufHeader((uint16_t *)p_header_address,
+ CCCI_A2M_SHARE_BUFF_HEADER_SYNC,
+ SHARE_BUFF_DATA_TYPE_PCM_FillSpk,
+ data_length);
+
+ // send data notify to modem side
+ uint16_t message_length = CCCI_SHARE_BUFF_HEADER_LEN + data_length;
+ if (pCCCI->mLad->GetApSideModemStatus(P2W_STATUS_MASK) == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_PNW_DL_DATA_NOTIFY, message_length, offset));
+ }
+ }
+ break;
+ }
+ case MSG_M2A_PNW_OFF_ACK: { // ack of MSG_A2M_PNW_OFF
+ if (pCCCI->GetModemSideModemStatus(P2W_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(P2W_STATUS_MASK);
+ } else {
+ ALOGE("--PCM2WayOff Ack is not paired!!");
+ }
+ ALOGV("--PCM2WayOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ /* PCM Encryption */
+ case MSG_M2A_SPH_ENCRYPTION_ACK: { // ack of MSG_A2M_SPH_ENCRYPTION
+ ALOGD("--SetEncryption Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_SPH_UL_ENCRYPTION: {
+#if defined(MTK_SPEECH_ENCRYPTION_SUPPORT)
+ if ((pCCCI->GetModemSideModemStatus(SPEECH_STATUS_MASK) == true) || (pCCCI->GetModemSideModemStatus(VT_STATUS_MASK) == true)) {
+ struct timespec entertime;
+ struct timespec leavetime;
+ unsigned long long timediffns = 0;
+ entertime = GetSystemTime();
+
+ uint16_t OffsetTarget = A2M_SHARED_BUFFER_ULENC_TARGET_BASE;
+ char *BufferSource = pCCCI->mSphPCMBuf + A2M_SHARED_BUFFER_ULENC_SOURCE_BASE;
+ char *BufferTarget = pCCCI->mSphPCMBuf + OffsetTarget;
+ char *BufferDataTarget = BufferTarget + CCCI_SHARE_BUFF_HEADER_LEN;
+
+ const uint16_t ByteDataSource = pCCCI->GetM2AUplinkData(ccci_buff, BufferSource);
+ ALOGD_IF(pCCCI->mLogEnable, "+%s(), MSG_M2A_SPH_UL_ENCRYPTION(0x%x), ByteDataSource=%d", __FUNCTION__, m2a_message_id, ByteDataSource);
+ ALOGD_IF(pCCCI->mLogEnable, "+%s(), MSG_M2A_SPH_UL_ENCRYPTION(0x%x), BufferSource[0] = 0x%x, BufferSource[1]=0x%x, BufferSource[2] = 0x%x, BufferSource[3]=0x%x", __FUNCTION__, m2a_message_id, *((uint16_t *)BufferSource), *((uint16_t *)BufferSource + 1), *((uint16_t *)BufferSource + 2), *((uint16_t *)BufferSource + 3));
+
+ uint16_t ByteDataTarget = SpeechDataEncrypter::GetInstance()->Encryption(BufferDataTarget, BufferSource, ByteDataSource);
+
+ // fill header info
+ pCCCI->SetShareBufHeader((uint16_t *)BufferTarget,
+ CCCI_A2M_SHARE_BUFF_HEADER_SYNC,
+ SHARE_BUFF_DATA_TYPE_CCCI_UL_ENC,
+ ByteDataTarget);
+
+ ALOGD_IF(pCCCI->mLogEnable, "%s(), MSG_M2A_SPH_UL_ENCRYPTION(0x%x), BufferTarget = %p, ByteDataTarget = 0x%x", __FUNCTION__, m2a_message_id, BufferTarget, ByteDataTarget);
+ ALOGD_IF(pCCCI->mLogEnable, "%s(), MSG_M2A_SPH_UL_ENCRYPTION(0x%x), BufferDataTarget[0] = 0x%x, BufferDataTarget[1]=0x%x, BufferDataTarget[2] = 0x%x, BufferDataTarget[3]=0x%x", __FUNCTION__, m2a_message_id, *((uint16_t *)BufferDataTarget), *((uint16_t *)BufferDataTarget + 1), *((uint16_t *)BufferDataTarget + 2), *((uint16_t *)BufferDataTarget + 3));
+
+ // send data notify to modem side
+ uint16_t ByteMessage = CCCI_SHARE_BUFF_HEADER_LEN + ByteDataTarget;
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_SPH_UL_ENCRYPTION, ByteMessage, OffsetTarget));
+ leavetime = GetSystemTime();
+
+ timediffns = TimeDifference(leavetime, entertime);
+ ALOGD_IF(pCCCI->mLogEnable, "-%s(), MSG_M2A_SPH_UL_ENCRYPTION(0x%x), ByteDataTarget=%d, process time=%lld(ns)", __FUNCTION__, m2a_message_id, ByteDataTarget, timediffns);
+ } else {
+ ALOGD("-%s(), MSG_M2A_SPH_UL_ENCRYPTION(0x%x), not in call, skip ", __FUNCTION__, m2a_message_id);
+ }
+#else
+ ALOGD("%s(), MSG_M2A_SPH_UL_ENCRYPTION(0x%x) not support, skip", __FUNCTION__, ccci_buff.message);
+#endif
+ break;
+ }
+ case MSG_M2A_SPH_DL_DECRYPTION: {
+#if defined(MTK_SPEECH_ENCRYPTION_SUPPORT)
+ if ((pCCCI->GetModemSideModemStatus(SPEECH_STATUS_MASK) == true) || (pCCCI->GetModemSideModemStatus(VT_STATUS_MASK) == true)) {
+ struct timespec entertime;
+ struct timespec leavetime;
+ unsigned long long timediffns = 0;
+ entertime = GetSystemTime();
+ uint16_t OffsetTarget = A2M_SHARED_BUFFER_DLDEC_TARGET_BASE;
+ char *BufferSource = pCCCI->mSphPCMBuf + A2M_SHARED_BUFFER_DLDEC_SOURCE_BASE;
+ char *BufferTarget = pCCCI->mSphPCMBuf + OffsetTarget;
+ char *BufferDataTarget = BufferTarget + CCCI_SHARE_BUFF_HEADER_LEN;
+
+ const uint16_t ByteDataSource = pCCCI->GetM2AUplinkData(ccci_buff, BufferSource);
+ ALOGD_IF(pCCCI->mLogEnable, "+%s(), MSG_M2A_SPH_DL_DECRYPTION(0x%x), ByteDataSource=%d", __FUNCTION__, m2a_message_id, ByteDataSource);
+ ALOGD_IF(pCCCI->mLogEnable, "+%s(), MSG_M2A_SPH_DL_DECRYPTION(0x%x), BufferSource[0] = 0x%x, BufferSource[1]=0x%x, BufferSource[2] = 0x%x, BufferSource[3]=0x%x", __FUNCTION__, m2a_message_id, *((uint16_t *)BufferSource), *((uint16_t *)BufferSource + 1), *((uint16_t *)BufferSource + 2), *((uint16_t *)BufferSource + 3));
+
+ uint16_t ByteDataTarget = SpeechDataEncrypter::GetInstance()->Decryption(BufferDataTarget, BufferSource, ByteDataSource);
+
+ // fill header info
+ pCCCI->SetShareBufHeader((uint16_t *)BufferTarget,
+ CCCI_A2M_SHARE_BUFF_HEADER_SYNC,
+ SHARE_BUFF_DATA_TYPE_CCCI_DL_DEC,
+ ByteDataTarget);
+
+ ALOGD_IF(pCCCI->mLogEnable, "%s(), MSG_M2A_SPH_UL_ENCRYPTION(0x%x), BufferTarget = %p, ByteDataTarget = 0x%x", __FUNCTION__, m2a_message_id, BufferTarget, ByteDataTarget);
+ ALOGD_IF(pCCCI->mLogEnable, "%s(), MSG_M2A_SPH_UL_ENCRYPTION(0x%x), BufferDataTarget[0] = 0x%x, BufferDataTarget[1]=0x%x, BufferDataTarget[2] = 0x%x, BufferDataTarget[3]=0x%x", __FUNCTION__, m2a_message_id, *((uint16_t *)BufferDataTarget), *((uint16_t *)BufferDataTarget + 1), *((uint16_t *)BufferDataTarget + 2), *((uint16_t *)BufferDataTarget + 3));
+ // send data notify to modem side
+ uint16_t ByteMessage = CCCI_SHARE_BUFF_HEADER_LEN + ByteDataTarget;
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_SPH_DL_DECRYPTION, ByteMessage, OffsetTarget));
+ leavetime = GetSystemTime();
+
+ timediffns = TimeDifference(leavetime, entertime);
+ ALOGD_IF(pCCCI->mLogEnable, "-%s(), MSG_M2A_SPH_DL_DECRYPTION(0x%x), ByteDataTarget=%d, process time=%lld(ns)", __FUNCTION__, m2a_message_id, ByteDataTarget, timediffns);
+ } else {
+ ALOGD("-%s(), MSG_M2A_SPH_DL_DECRYPTION(0x%x), not in call, skip ", __FUNCTION__, m2a_message_id);
+ }
+#else
+ ALOGD("%s(), MSG_M2A_SPH_DL_DECRYPTION(0x%x) not support, skip", __FUNCTION__, ccci_buff.message);
+#endif
+ break;
+ }
+
+ /* TTY */
+ case MSG_M2A_CTM_ON_ACK: { // ack of MSG_A2M_CTM_ON
+ pCCCI->SetModemSideModemStatus(TTY_STATUS_MASK);
+ ALOGV("--TtyCtmOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_CTM_DEBUG_DATA_NOTIFY: {
+ if (pCCCI->mLad->GetApSideModemStatus(TTY_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_CTM_DEBUG_DATA_NOTIFY(0x%x) after AP side trun off TTY!! Drop it.", ccci_buff.message);
+ } else {
+ SLOGV("MSG_M2A_CTM_DEBUG_DATA_NOTIFY(0x%x), data_length: %u", ccci_buff.message, (unsigned int)(pCCCI->GetMessageLength(ccci_buff) - CCCI_PAYLOAD_BUFF_HEADER_LEN));
+ SpeechVMRecorder *pSpeechVMRecorder = SpeechVMRecorder::getInstance();
+ const int data_type = pCCCI->GetM2AShareBufDataType(ccci_buff);
+ if (data_type == SHARE_BUFF_DATA_TYPE_CCCI_CTM_UL_IN) {
+ pSpeechVMRecorder->getCtmDebugDataFromModem(pCCCI->GetM2AUplinkRingBuffer(ccci_buff), pSpeechVMRecorder->pCtmDumpFileUlIn);
+ } else if (data_type == SHARE_BUFF_DATA_TYPE_CCCI_CTM_DL_IN) {
+ pSpeechVMRecorder->getCtmDebugDataFromModem(pCCCI->GetM2AUplinkRingBuffer(ccci_buff), pSpeechVMRecorder->pCtmDumpFileDlIn);
+ } else if (data_type == SHARE_BUFF_DATA_TYPE_CCCI_CTM_UL_OUT) {
+ pSpeechVMRecorder->getCtmDebugDataFromModem(pCCCI->GetM2AUplinkRingBuffer(ccci_buff), pSpeechVMRecorder->pCtmDumpFileUlOut);
+ } else if (data_type == SHARE_BUFF_DATA_TYPE_CCCI_CTM_DL_OUT) {
+ pSpeechVMRecorder->getCtmDebugDataFromModem(pCCCI->GetM2AUplinkRingBuffer(ccci_buff), pSpeechVMRecorder->pCtmDumpFileDlOut);
+ } else {
+ ALOGW("%s(), data_type(0x%x) error", __FUNCTION__, data_type);
+ ASSERT(0);
+ }
+
+ if (mA2M_ECCCI_DATA_READ_ACK == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_CTM_DEBUG_DATA_READ_ACK, 0, 0));
+ mA2M_ECCCI_DATA_READ_ACK = false;
+ }
+ }
+ break;
+ }
+ case MSG_M2A_CTM_OFF_ACK: { // ack of MSG_A2M_CTM_OFF
+ if (pCCCI->GetModemSideModemStatus(TTY_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(TTY_STATUS_MASK);
+ } else {
+ ALOGE("--TtyCtmOff Ack is not paired!!");
+ }
+ ALOGD("--TtyCtmOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Loopback */
+ case MSG_M2A_SET_ACOUSTIC_LOOPBACK_ACK: { // ack of MSG_A2M_SET_ACOUSTIC_LOOPBACK
+ const bool loopback_on = pCCCI->GetMessageParam(ccci_buff) & 0x1;
+ if (loopback_on == true) { // loopback on
+ pCCCI->SetModemSideModemStatus(LOOPBACK_STATUS_MASK);
+ } else { // loopback off
+ if (pCCCI->GetModemSideModemStatus(LOOPBACK_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(LOOPBACK_STATUS_MASK);
+ } else {
+ ALOGE("--SetAcousticLoopback Ack is not paired!!");
+ }
+ }
+
+ pCCCI->mLad->Signal();
+
+ ALOGV("--SetAcousticLoopback Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Speech Enhancement parameters */
+ case MSG_M2A_EM_NB_ACK: { // ack of MSG_A2M_EM_NB
+ pCCCI->AddSpeechParamAckCount(NB_SPEECH_PARAM);
+ // pCCCI->A2MBufUnLock();
+ ALOGV("--SetNBSpeechParameters Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_EM_DMNR_ACK: { // ack of MSG_A2M_EM_DMNR
+ pCCCI->AddSpeechParamAckCount(DMNR_SPEECH_PARAM);
+ // pCCCI->A2MBufUnLock();
+ ALOGV("--SetDualMicSpeechParameters Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_EM_MAGICON_ACK: { // ack of MSG_A2M_EM_MAGICON
+ pCCCI->AddSpeechParamAckCount(MAGICON_SPEECH_PARAM);
+ // pCCCI->A2MBufUnLock();
+ ALOGV("--SetMagiConSpeechParameters Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_EM_HAC_ACK: { // ack of MSG_A2M_EM_HAC
+ pCCCI->AddSpeechParamAckCount(HAC_SPEECH_PARAM);
+ // pCCCI->A2MBufUnLock();
+ ALOGV("--SetHACSpeechParameters Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_EM_WB_ACK: { // ack of MSG_A2M_EM_WB
+ pCCCI->AddSpeechParamAckCount(WB_SPEECH_PARAM);
+ // pCCCI->A2MBufUnLock();
+ ALOGV("--SetWBSpeechParameters Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_EM_DYNAMIC_SPH_ACK: { // ack of MSG_A2M_EM_DYNAMIC_SPH
+ switch (ccci_buff.message & 0xFFFF) {
+ case 0xAA01:
+ pCCCI->AddSpeechParamAckCount(DYNAMIC_SPH_PARAM);
+ break;
+ case 0xAA03:
+ pCCCI->AddSpeechParamAckCount(DMNR_SPEECH_PARAM);
+ break;
+ case 0:
+ pCCCI->AddSpeechParamAckCount(DYNAMIC_SPH_PARAM);//some MD ack with 0
+ break;
+ }
+ ALOGV("--SetDynamicSpeechParameters Ack done(0x%x)", ccci_buff.message);
+
+#ifdef USE_CCCI_SHARE_BUFFER
+ //release buffer when ack received
+ int datalength = pCCCI->GetMessageLength(pCCCI->pQueue[pCCCI->iQRead].ccci_buff);
+ pCCCI->AdvanceA2MRawParaRingBuffer(datalength);
+#endif
+ break;
+ }
+ case MSG_M2A_SPH_ENH_CORE_ACK: { // ack of MSG_A2M_SPH_ENH_CORE
+ // Do nothing... just leave a log
+ ALOGD("--MSG_M2A_SPH_ENH_CORE_ACK Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Modem Reset */
+ case MSG_M2A_EM_DATA_REQUEST: { // Modem reset. Requset for all EM data(NB/DMNR/WB)
+ ALOGW("..[MD Reset Notify(MSG_M2A_EM_DATA_REQUEST: 0x%x)]..", ccci_buff.message);
+ pCCCI->mWasModemReset = true;
+ // Clean mWaitAckMessageID to avoid the queue receiving the wrong ack
+ pCCCI->mWaitAckMessageID = 0;
+
+ // close analog downlink path when modem reset during phone call
+ if (pCCCI->mLad->GetApSideModemStatus(SPEECH_STATUS_MASK) == true ||
+ pCCCI->mLad->GetApSideModemStatus(VT_STATUS_MASK) == true) {
+ //notify event to do reopen voice call
+ AudioEventThreadManager::getInstance()->notifyCallback(AUDIO_EVENT_PHONECALL_REOPEN, pCCCI);
+ }
+ pCCCI->mIsModemResetDuringPhoneCall = false;
+ pCCCI->mIsModemReset = false;
+ pCCCI->mIsModemEPOF = false;
+ // Check the first message in queue. If need ack, take action.
+ // Modem reset, flush all CCCI queue first. Don't care for the CCCI queue.
+ pCCCI->ResetSpeechParamAckCount();
+ pCCCI->MDReset_CheckMessageInQueue();
+
+ break;
+ }
+ case MSG_M2A_VIBSPK_PARAMETER_ACK: { // ack of MSG_M2A_VIBSPK_PARAMETER
+ // pCCCI->A2MBufUnLock();
+ ALOGV("--SetVibSpkParam Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ case MSG_M2A_SMARTPA_PARAMETER_ACK: {
+ // pCCCI->A2MBufUnLock();
+ ALOGV("--SetSmartpaParam Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_NETWORK_STATUS_NOTIFY: {
+ uint16_t mRfMode = ccci_buff.message & 0xFFFF;
+
+ // save mRfMode in property to avoid mediaserver die
+ pCCCI->SetRFInfo(1, mRfMode);
+ pCCCI->GetRFInfo();
+
+#ifdef MTK_AUDIO_GAIN_TABLE
+ // speech network type change
+ //bit 0~3: Network; bit 4,5: Voice Band, bit 15: 0 no network support, 1: network support
+ AudioVolumeFactory::CreateAudioVolumeController()->speechNetworkChange(ccci_buff.message);
+#endif
+ ALOGV("--MSG_M2A_NETWORK_STATUS_NOTIFY (0x%x)", ccci_buff.message);
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_NETWORK_STATUS_ACK, 0, 0));
+ break;
+ }
+ /* Modem EPOF */
+ case MSG_M2A_EPOF_NOTIFY: { // Modem reset. Requset for all EM data(NB/DMNR/WB)
+ ALOGW("..[MD EPOF Notify(MSG_M2A_EPOF_NOTIFY: 0x%x)]..", ccci_buff.message);
+
+ // Check the first message in queue. If need ack, take action.
+
+ // Modem reset, flush all CCCI queue first. Don't care for the CCCI queue.
+ pCCCI->ResetSpeechParamAckCount();
+ pCCCI->MDReset_CheckMessageInQueue();
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_EPOF_ACK, 0, 0));
+ pCCCI->mIsModemEPOF = true;
+
+ break;
+ }
+ case MSG_M2A_NW_CODEC_INFO_NOTIFY: {
+ ALOGV("--MSG_M2A_NW_CODEC_INFO_NOTIFY (0x%x)", ccci_buff.message);
+ pCCCI->SetNWCodecInfo(ccci_buff);
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_NW_CODEC_INFO_READ_ACK, 0, 0));
+ break;
+ }
+ default: {
+ //ALOGD("Read modem message(0x%x), don't care. (or no such message)", ccci_buff.message);
+ sph_msleep(10);
+ break;
+ }
+ }
+
+ /// If AP side is waiting for this ack, then consume message queue
+ uint16_t a2m_message_id_of_m2a_ack = m2a_message_id & 0x7FFF; // 0xAF** -> 0x2F**
+ if (pCCCI->JudgeAckOfMsg(a2m_message_id_of_m2a_ack) == MESSAGE_NEED_ACK) {
+ if (a2m_message_id_of_m2a_ack == pCCCI->mWaitAckMessageID) {
+ pCCCI->mWaitAckMessageID = 0; // reset
+ pCCCI->ConsumeMessageInQueue();
+ } else {
+ ALOGW("Message(0x%x) might double ack!! The current mWaitAckMessageID is 0x%x", ccci_buff.message, pCCCI->mWaitAckMessageID);
+ }
+ }
+ }
+ pthread_exit(NULL);
+ return 0;
+}
+
+status_t SpeechMessengerECCCI::CreateSendSphParaThread() {
+ int ret = pthread_create(&hSendSphThread, NULL, SpeechMessengerECCCI::SendSphParaThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+ return NO_ERROR;
+}
+
+void *SpeechMessengerECCCI::SendSphParaThread(void *arg) {
+ pthread_detach(pthread_self());
+
+ prctl(PR_SET_NAME, (unsigned long)__FUNCTION__, 0, 0, 0);
+ // Adjust thread priority
+ int rtnPrio = setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+ if (0 != rtnPrio) {
+ ALOGE("[%s] failed, errno: %d, return=%d", __FUNCTION__, errno, rtnPrio);
+ } else {
+ ALOGD("%s setpriority ok, priority: %d", __FUNCTION__, ANDROID_PRIORITY_AUDIO);
+ }
+ ALOGD("%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+
+ SpeechMessengerECCCI *pCCCI = (SpeechMessengerECCCI *)arg;
+
+ // Check the first message in queue. If need ack, take action.
+ // Modem reset, flush all CCCI queue first. Don't care for the CCCI queue.
+ pCCCI->MDReset_CheckMessageInQueue();
+
+ // Get SpeechParamLock
+ if (pCCCI->SpeechParamLock() == false) {
+ ALOGE("%s() fail to get SpeechParamLock!!", __FUNCTION__);
+ return 0;
+ }
+
+ // Send speech parameters to modem side
+ pCCCI->ResetSpeechParamAckCount();
+ pCCCI->mLad->SetAllSpeechEnhancementInfoToModem();
+
+ // Release SpeechParamLock
+ pCCCI->SpeechParamUnLock();
+
+ pthread_exit(NULL);
+ return 0;
+}
+
+bool SpeechMessengerECCCI::A2MBufLock() {
+ const uint32_t kA2MBufLockTimeout = 3000; // 3 sec
+
+ int rc = AL_LOCK_MS(mA2MShareBufMutex, kA2MBufLockTimeout);
+ ALOGD("%s()", __FUNCTION__);
+ if (rc != 0) {
+ ALOGE("%s(), Cannot get Lock!! Timeout : %u msec, rc %d", __FUNCTION__, kA2MBufLockTimeout, rc);
+ return false;
+ }
+ return true;
+}
+
+void SpeechMessengerECCCI::A2MBufUnLock() {
+ AL_UNLOCK(mA2MShareBufMutex);
+ ALOGD("%s()", __FUNCTION__);
+}
+
+bool SpeechMessengerECCCI::SpeechParamLock() {
+ const uint32_t kSphParamLockTimeout = 10000; // 10 sec
+
+ ALOGD("%s()", __FUNCTION__);
+ int rc = AL_LOCK_MS(mSetSpeechParamMutex, kSphParamLockTimeout);
+ if (rc != 0) {
+ ALOGE("%s(), Cannot get Lock!! Timeout : %u msec", __FUNCTION__, kSphParamLockTimeout);
+ return false;
+ }
+ return true;
+}
+
+void SpeechMessengerECCCI::SpeechParamUnLock() {
+ ALOGD("%s()", __FUNCTION__);
+ AL_UNLOCK(mSetSpeechParamMutex);
+}
+
+void SpeechMessengerECCCI::ResetSpeechParamAckCount() {
+ memset(&mSpeechParamAckCount, 0, sizeof(mSpeechParamAckCount));
+ ALOGD("%s(), NB(%u)/DMNR(%u)/WB(%u)/MAGICON(%u)/HAC(%u)/DynamicSPH(%u)", __FUNCTION__,
+ mSpeechParamAckCount[NB_SPEECH_PARAM],
+ mSpeechParamAckCount[DMNR_SPEECH_PARAM],
+ mSpeechParamAckCount[WB_SPEECH_PARAM],
+ mSpeechParamAckCount[MAGICON_SPEECH_PARAM],
+ mSpeechParamAckCount[HAC_SPEECH_PARAM],
+ mSpeechParamAckCount[DYNAMIC_SPH_PARAM]);
+}
+
+void SpeechMessengerECCCI::AddSpeechParamAckCount(speech_param_ack_t type) {
+ if (type >= NUM_SPEECH_PARAM_ACK_TYPE || type < 0) {
+ ALOGE("%s(), no such type: %d", __FUNCTION__, type);
+ } else {
+ if (mSpeechParamAckCount[type] < 0xFFFFFFFF) { //prevent overflow
+ mSpeechParamAckCount[type]++;
+ }
+ ALOGD("%s(%d), NB(%u)/DMNR(%u)/WB(%u)/MAGICON(%u)/HAC(%u)/DynamicSPH(%u)", __FUNCTION__, type,
+ mSpeechParamAckCount[NB_SPEECH_PARAM],
+ mSpeechParamAckCount[DMNR_SPEECH_PARAM],
+ mSpeechParamAckCount[WB_SPEECH_PARAM],
+ mSpeechParamAckCount[MAGICON_SPEECH_PARAM],
+ mSpeechParamAckCount[HAC_SPEECH_PARAM],
+ mSpeechParamAckCount[DYNAMIC_SPH_PARAM]);
+ }
+}
+
+bool SpeechMessengerECCCI::CheckSpeechParamAckAllArrival() {
+ bool ret = true;
+
+ // Get SpeechParamLock
+ if (SpeechParamLock() == false) {
+ ALOGE("%s() fail to get SpeechParamLock!!", __FUNCTION__);
+ return false;
+ }
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ if (mSpeechParamAckCount[DYNAMIC_SPH_PARAM] == 0) { ret = false; }
+#else
+
+ if (mSpeechParamAckCount[NB_SPEECH_PARAM] == 0) { ret = false; }
+
+ if (AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport() >= 2) {
+ if (mSpeechParamAckCount[DMNR_SPEECH_PARAM] == 0) { ret = false; }
+
+#if defined(MTK_MAGICONFERENCE_SUPPORT) || defined(MTK_INCALL_HANDSFREE_DMNR)
+ if (mSpeechParamAckCount[MAGICON_SPEECH_PARAM] == 0) { ret = false; }
+#endif
+ }
+
+#if defined(MTK_WB_SPEECH_SUPPORT)
+ if (mSpeechParamAckCount[WB_SPEECH_PARAM] == 0) { ret = false; }
+#endif
+
+#if defined(MTK_HAC_SUPPORT)
+ if (mSpeechParamAckCount[HAC_SPEECH_PARAM] == 0) { ret = false; }
+#endif
+#endif
+
+ if (ret == true) {
+ ALOGD("%s() Pass", __FUNCTION__);
+ } else {
+ ALOGE("%s() Fail, NB(%u)/DMNR(%u)/WB(%u)/MAGICON(%u)/HAC(%u)/DynamicSPH(%u)", __FUNCTION__,
+ mSpeechParamAckCount[NB_SPEECH_PARAM],
+ mSpeechParamAckCount[DMNR_SPEECH_PARAM],
+ mSpeechParamAckCount[WB_SPEECH_PARAM],
+ mSpeechParamAckCount[MAGICON_SPEECH_PARAM],
+ mSpeechParamAckCount[HAC_SPEECH_PARAM],
+ mSpeechParamAckCount[DYNAMIC_SPH_PARAM]);
+
+ // Send speech parameters to modem side again
+ mLad->SetAllSpeechEnhancementInfoToModem();
+ }
+
+ // Release SpeechParamLock
+ SpeechParamUnLock();
+
+ return ret;
+}
+
+/** Do error handling here */
+void SpeechMessengerECCCI::SendMsgFailErrorHandling(const ccci_buff_t &ccci_buff) {
+ ALOGE("%s(), message: 0x%x", __FUNCTION__, ccci_buff.message);
+ switch (GetMessageID(ccci_buff)) {
+ case MSG_A2M_SET_SPH_MODE: {
+ // Do nothing...
+ break;
+ }
+ case MSG_A2M_SPH_ON: {
+ phone_call_mode_t phone_call_mode = (phone_call_mode_t)GetMessageParam(ccci_buff);
+ if (phone_call_mode == RAT_3G324M_MODE) {
+ SetModemSideModemStatus(VT_STATUS_MASK);
+ } else {
+ SetModemSideModemStatus(SPEECH_STATUS_MASK);
+ }
+
+ //mLad->Signal();
+
+ break;
+ }
+ case MSG_A2M_SPH_OFF: {
+ if (GetModemSideModemStatus(VT_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(VT_STATUS_MASK);
+ } else if (GetModemSideModemStatus(SPEECH_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(SPEECH_STATUS_MASK);
+ } else {
+ ALOGE("--SpeechOff Ack is not paired!!");
+ }
+
+ mLad->Signal();
+
+ break;
+ }
+ case MSG_A2M_SPH_ROUTER_ON: {
+ const bool pcm_route_on = GetMessageParam(ccci_buff) & 0x1;
+ if (pcm_route_on == true) { // pcm route on
+ SetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+ } else { // pcm route off
+ if (GetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+ } else {
+ ALOGE("--SpeechOn(PCM Route On) Ack is not paired!!");
+ }
+ }
+
+ break;
+ }
+ case MSG_A2M_PCM_REC_ON: {
+ SetModemSideModemStatus(RECORD_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_PCM_REC_OFF: {
+ if (GetModemSideModemStatus(RECORD_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--recordOff Ack is not paired!!");
+ }
+ break;
+ }
+ case MSG_A2M_RECORD_RAW_PCM_ON: {
+ SetModemSideModemStatus(RAW_RECORD_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_RECORD_RAW_PCM_OFF: {
+ if (GetModemSideModemStatus(RAW_RECORD_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(RAW_RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--RawRecordOff Ack is not paired!!");
+ }
+ break;
+ }
+ case MSG_A2M_VM_REC_ON: {
+ SetModemSideModemStatus(VM_RECORD_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_VM_REC_OFF: {
+ if (GetModemSideModemStatus(VM_RECORD_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(VM_RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--VMRecordOff Ack is not paired!!");
+ }
+ break;
+ }
+ case MSG_A2M_BGSND_ON: {
+ SetModemSideModemStatus(BGS_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_BGSND_OFF: {
+ if (GetModemSideModemStatus(BGS_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(BGS_STATUS_MASK);
+ } else {
+ ALOGE("--BGSoundOff Ack is not paired!!");
+ }
+ break;
+ }
+ case MSG_A2M_PNW_ON: {
+ SetModemSideModemStatus(P2W_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_PNW_OFF: {
+ if (GetModemSideModemStatus(P2W_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(P2W_STATUS_MASK);
+ } else {
+ ALOGE("--PCM2WayOff Ack is not paired!!");
+ }
+ break;
+ }
+ case MSG_A2M_CTM_ON: {
+ SetModemSideModemStatus(TTY_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_CTM_OFF: {
+ if (GetModemSideModemStatus(TTY_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(TTY_STATUS_MASK);
+ } else {
+ ALOGE("--TtyCtmOff Ack is not paired!!");
+ }
+ break;
+ }
+ case MSG_A2M_SET_ACOUSTIC_LOOPBACK: {
+ const bool loopback_on = GetMessageParam(ccci_buff) & 0x1;
+ if (loopback_on == true) { // loopback on
+ SetModemSideModemStatus(LOOPBACK_STATUS_MASK);
+ } else { // loopback off
+ if (GetModemSideModemStatus(LOOPBACK_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(LOOPBACK_STATUS_MASK);
+ } else {
+ ALOGE("--SetAcousticLoopback Ack is not paired!!");
+ }
+ }
+
+ mLad->Signal();
+ break;
+ }
+ case MSG_A2M_EM_NB:
+ case MSG_A2M_EM_WB:
+ case MSG_A2M_EM_DMNR:
+ case MSG_A2M_EM_MAGICON:
+ case MSG_A2M_EM_HAC:
+ case MSG_A2M_VIBSPK_PARAMETER:
+ case MSG_A2M_SMARTPA_PARAMETER:
+#ifndef USE_CCCI_SHARE_BUFFER
+ case MSG_A2M_EM_DYNAMIC_SPH:
+#endif
+ {
+ A2MBufUnLock();
+ break;
+ }
+#ifdef USE_CCCI_SHARE_BUFFER
+ case MSG_A2M_EM_DYNAMIC_SPH: {
+ // clear CCCI parameter Buffer
+ //InitA2MRawParaRingBuffer();
+ break;
+ }
+#endif
+ default: {
+ ALOGW("%s(), message: 0x%x, ack don't care", __FUNCTION__, ccci_buff.message);
+ }
+ }
+}
+
+uint16_t SpeechMessengerECCCI::GetPcmFreq(const uint16_t Idx_Freq) {
+ uint16_t Pcm_Freq = 8000;
+
+ switch (Idx_Freq) {
+ case 0:
+ Pcm_Freq = 8000;
+ break;
+
+ case 1:
+ Pcm_Freq = 16000;
+ break;
+
+ case 2:
+ Pcm_Freq = 32000;
+ break;
+
+ case 3:
+ Pcm_Freq = 48000;
+ break;
+
+ case 0xf:
+ Pcm_Freq = 8000;
+ break;
+
+ default:
+ Pcm_Freq = 8000;
+ break;
+
+ }
+ return Pcm_Freq;
+}
+
+RingBuf SpeechMessengerECCCI::GetM2AUplinkRingBuffer(const ccci_buff_t &ccci_buff) {
+ RingBuf ul_ring_buf;
+ uint16_t size_copy1, size_copy2;
+ ul_ring_buf.bufLen = mM2AShareBufLen;
+ ul_ring_buf.pBufBase = mM2AShareBufBase;
+ ul_ring_buf.pBufEnd = ul_ring_buf.pBufBase + ul_ring_buf.bufLen;
+
+ ul_ring_buf.pRead = mM2AShareBufRead;
+
+ ul_ring_buf.pWrite = ul_ring_buf.pRead + GetMessageLength(ccci_buff);
+ if (ul_ring_buf.pWrite >= mM2AShareBufEnd) {
+ ul_ring_buf.pWrite -= ul_ring_buf.bufLen;
+
+ size_copy1 = mM2AShareBufEnd - ul_ring_buf.pRead;
+ size_copy2 = GetMessageLength(ccci_buff) - size_copy1;
+ ALOGV("%s(), mM2AShareBufEnd(%p), payloadLen(0x%x), size_copy1(0x%x), size_copy2(0x%x), pRead(%p), pWrite(%p)",
+ __FUNCTION__, mM2AShareBufEnd, GetMessageLength(ccci_buff), size_copy1, size_copy2, ul_ring_buf.pRead, ul_ring_buf.pWrite);
+ memcpy(ul_ring_buf.pRead, (char *)ccci_buff.payload, size_copy1);
+ memcpy(ul_ring_buf.pBufBase, (char *)ccci_buff.payload + size_copy1, size_copy2);
+ } else {
+ memcpy(ul_ring_buf.pRead, (char *)ccci_buff.payload, GetMessageLength(ccci_buff));
+ }
+ ALOGV("%s(), pBufBase(%p), bufLen(0x%x), payloadLen(0x%x), mM2AShareBufRead(%p), pRead(%p), pWrite(%p)",
+ __FUNCTION__, ul_ring_buf.pBufBase, ul_ring_buf.bufLen, GetMessageLength(ccci_buff), mM2AShareBufRead, ul_ring_buf.pRead, ul_ring_buf.pWrite);
+
+ // share buffer header
+ char *p_sync_word = (char *)ccci_buff.payload + 0; // size(unsigned short)
+ char *p_data_type = (char *)ccci_buff.payload + 2; // size(unsigned short)
+ char *p_data_len = (char *)ccci_buff.payload + 4; // size(unsigned short)
+ char *p_data_curIdx = (char *)ccci_buff.payload + 6; // size(unsigned short)
+ char *p_data_totalIdx = (char *)ccci_buff.payload + 8; // size(unsigned short)
+
+ if (*(uint16_t *)p_data_curIdx == *(uint16_t *)p_data_totalIdx) { mA2M_ECCCI_DATA_READ_ACK = true; }
+
+#ifdef CONFIG_MT_ENG_BUILD
+ ALOGD("%s(), *p_sync_word(0x%x), *p_data_type(0x%x), *p_data_len(0x%x), *p_data_curIdx(0x%x), *p_data_totalIdx(0x%x), mA2M_ECCCI_DATA_READ_ACK(%d)",
+ __FUNCTION__, *(uint16_t *)p_sync_word, *(uint16_t *)p_data_type, *(uint16_t *)p_data_len, *(uint16_t *)p_data_curIdx, *(uint16_t *)p_data_totalIdx, mA2M_ECCCI_DATA_READ_ACK);
+#else
+ ALOGV("%s(), *p_sync_word(0x%x), *p_data_type(0x%x), *p_data_len(0x%x), *p_data_curIdx(0x%x), *p_data_totalIdx(0x%x), mA2M_ECCCI_DATA_READ_ACK(%d)",
+ __FUNCTION__, *(uint16_t *)p_sync_word, *(uint16_t *)p_data_type, *(uint16_t *)p_data_len, *(uint16_t *)p_data_curIdx, *(uint16_t *)p_data_totalIdx, mA2M_ECCCI_DATA_READ_ACK);
+#endif
+
+ SLOGV("CCCI get uplink data from modem. message = 0x%x, sync = 0x%x, type = 0x%x, data_len = %d",
+ ccci_buff.message, *(uint16_t *)p_sync_word, *(uint16_t *)p_data_type, *(uint16_t *)p_data_len);
+
+ ASSERT(*(uint16_t *)p_sync_word == EEMCS_M2A_SHARE_BUFF_HEADER_SYNC);
+
+ ul_ring_buf.pRead += CCCI_PAYLOAD_BUFF_HEADER_LEN;
+ if (ul_ring_buf.pRead >= mM2AShareBufEnd) { ul_ring_buf.pRead -= ul_ring_buf.bufLen; }
+
+ mM2AShareBufRead = ul_ring_buf.pWrite;
+
+ return ul_ring_buf;
+}
+#ifdef USE_CCCI_SHARE_BUFFER
+void SpeechMessengerECCCI::InitA2MRawParaRingBuffer() {
+ mA2MParaShareBuf.pBufBase = mA2MParaShareBufBase + CCCI_SHAREBUF_GUARD_LENGTH;
+ mA2MParaShareBuf.pRead = mA2MParaShareBuf.pBufBase;
+ mA2MParaShareBuf.pWrite = mA2MParaShareBuf.pBufBase;
+ mA2MParaShareBuf.bufLen = mA2MParaShareBufLen - 2 * CCCI_SHAREBUF_GUARD_LENGTH;
+ mA2MParaShareBuf.pBufEnd = mA2MParaShareBuf.pBufBase + mA2MParaShareBuf.bufLen;
+ // add guard pattern here
+ memset((void *)mA2MParaShareBufBase, 0xa, CCCI_SHAREBUF_GUARD_LENGTH);
+ memset((void *)mA2MParaShareBuf.pBufEnd, 0xa, CCCI_SHAREBUF_GUARD_LENGTH);
+ mIsA2MParaShareBufEmpty = true;
+ ALOGD("%s pBufBase %p, pBufEnd %p, bufLen %d ", __FUNCTION__, mA2MParaShareBuf.pBufBase,
+ mA2MParaShareBuf.pBufEnd, mA2MParaShareBuf.bufLen);
+ return ;
+}
+
+// return the offset of ring buffer for driver to write parameter
+// get offset and avail length
+// avail and offset's range in 20K , 16 bit should cover it.
+status_t SpeechMessengerECCCI::GetA2MRawParaRingBuffer(uint16_t *offset, uint16_t *avail) {
+ *offset = (uint16_t)(mA2MParaShareBuf.pWrite - mA2MParaShareBufBase);
+ if (mA2MParaShareBuf.pWrite > mA2MParaShareBuf.pRead) {
+ * avail = (uint16_t)(mA2MParaShareBuf.bufLen - (mA2MParaShareBuf.pWrite - mA2MParaShareBuf.pRead));
+ } else if (mA2MParaShareBuf.pWrite == mA2MParaShareBuf.pRead) {
+ * avail = (uint16_t)(mIsA2MParaShareBufEmpty ? mA2MParaShareBuf.bufLen : 0);
+ } else {
+ * avail = (uint16_t)(mA2MParaShareBuf.pRead - mA2MParaShareBuf.pWrite);
+ }
+#ifdef CONFIG_MT_ENG_BUILD
+ ALOGD("%s mA2MParaShareBuf.pWrite %p ,*offset %d, *avail %d", __FUNCTION__, mA2MParaShareBuf.pWrite, *offset, *avail);
+#else
+ ALOGV("%s mA2MParaShareBuf.pWrite %p ,*offset %d, *avail %d", __FUNCTION__, mA2MParaShareBuf.pWrite, *offset, *avail);
+#endif
+ return NO_ERROR;
+}
+
+// renew share buffer pointer when receive ack
+// advance read pointer
+status_t SpeechMessengerECCCI::AdvanceA2MRawParaRingBuffer(int datalength) {
+ ASSERT(datalength < mA2MParaShareBuf.bufLen);
+ ALOGV("%s, %d", __FUNCTION__, datalength);
+ mA2MParaShareBuf.pRead += datalength;
+ if (mA2MParaShareBuf.pRead >= mA2MParaShareBuf.pBufEnd) {
+ mA2MParaShareBuf.pRead -= mA2MParaShareBuf.bufLen;
+ }
+ if (mA2MParaShareBuf.pRead == mA2MParaShareBuf.pWrite) {
+ mIsA2MParaShareBufEmpty = true;
+ }
+
+#ifdef CONFIG_MT_ENG_BUILD
+ ALOGD("%s, mA2MParaShareBuf.pRead = %p", __FUNCTION__, mA2MParaShareBuf.pRead);
+#else
+ ALOGV("%s, mA2MParaShareBuf.pRead = %p", __FUNCTION__, mA2MParaShareBuf.pRead);
+#endif
+ return NO_ERROR;
+}
+
+
+// user must make sure that data length < available length
+status_t SpeechMessengerECCCI::WriteA2MRawParaRingBuffer(char *data, int datalength) {
+ if (data == NULL || datalength > mA2MParaShareBuf.bufLen) {
+ ALOGD("%s wrong pointer %p or data length %d", __FUNCTION__, data, datalength);
+ return -1;
+ }
+ int part1;
+ part1 = (mA2MParaShareBuf.pWrite >= mA2MParaShareBuf.pRead) ?
+ (mA2MParaShareBuf.pBufEnd - mA2MParaShareBuf.pWrite) : (mA2MParaShareBuf.pRead - mA2MParaShareBuf.pWrite);
+ if (part1 > datalength) {
+ SpeechMemCpy(mA2MParaShareBuf.pWrite, data, datalength);
+ mA2MParaShareBuf.pWrite += datalength;
+ } else {
+ int part2 = datalength - part1;
+ SpeechMemCpy(mA2MParaShareBuf.pWrite, data, part1);
+ SpeechMemCpy(mA2MParaShareBuf.pBufBase, data + part1, part2);
+ mA2MParaShareBuf.pWrite = mA2MParaShareBuf.pBufBase + part2;
+ }
+ mIsA2MParaShareBufEmpty = false;
+ ALOGV("%s after write %d ,mA2MParaShareBuf.pWrite %p", __FUNCTION__, datalength, mA2MParaShareBuf.pWrite);
+ return NO_ERROR;
+}
+#endif
+
+RingBuf SpeechMessengerECCCI::GetM2ARawPcmRingBuffer(const ccci_buff_t &ccci_buff) {
+ spcRAWPCMBufInfo header_RawPcmBufInfo;
+ spcApRAWPCMBufHdr header_ApRawPcmBuf;
+
+ char SeqPcmBuf[CCCI_MAX_PAYLOAD_SIZE * 4 + 16] = {0};
+ RingBuf ul_ring_buf;
+ uint16_t size_copy1, size_copy2, BytesCopied, BytesToCopy;
+ char *PtrTarget = NULL;
+ char *PtrSource = NULL;
+ //parse message
+ char *p_sync_word = (char *)ccci_buff.payload + 0; // size(unsigned short)
+ char *p_data_type = (char *)ccci_buff.payload + 2; // size(unsigned short)
+ char *p_data_len = (char *)ccci_buff.payload + 4; // size(unsigned short)
+ char *p_data_curIdx = (char *)ccci_buff.payload + 6; // size(unsigned short)
+ char *p_data_totalIdx = (char *)ccci_buff.payload + 8; // size(unsigned short)
+
+ if (*(uint16_t *)p_data_curIdx == *(uint16_t *)p_data_totalIdx) { mA2M_ECCCI_DATA_READ_ACK = true; }
+ ALOGD("+%s(), message(0x%x) ,sync(0x%x), type(0x%x), len(0x%x)",
+ __FUNCTION__, ccci_buff.message, *(uint16_t *)p_sync_word, *(uint16_t *)p_data_type, *(uint16_t *)p_data_len);
+
+ ALOGV("CCCI get uplink data from modem. message = 0x%x, sync = 0x%x, type = 0x%x, data_len = %d",
+ ccci_buff.message, *(uint16_t *)p_sync_word, *(uint16_t *)p_data_type, *(uint16_t *)p_data_len);
+
+ ASSERT(*(uint16_t *)p_sync_word == EEMCS_M2A_SHARE_BUFF_HEADER_SYNC);
+
+
+ // share buffer header
+ memcpy(&header_RawPcmBufInfo, (char *)ccci_buff.payload + CCCI_PAYLOAD_BUFF_HEADER_LEN, sizeof(spcRAWPCMBufInfo));
+ PtrTarget = (char *)SeqPcmBuf;
+
+ switch (mPcmRecordType) {
+ case RECORD_TYPE_UL:
+ header_ApRawPcmBuf.u16SyncWord = EEMCS_M2A_SHARE_BUFF_HEADER_SYNC;
+ header_ApRawPcmBuf.u16RawPcmDir = RECORD_TYPE_UL;
+ header_ApRawPcmBuf.u16Freq = GetPcmFreq(header_RawPcmBufInfo.u16ULFreq);
+ header_ApRawPcmBuf.u16Length = header_RawPcmBufInfo.u16ULLength;
+ header_ApRawPcmBuf.u16Channel = 1;
+ header_ApRawPcmBuf.u16BitFormat = AUDIO_FORMAT_PCM_16_BIT;
+ //uplink raw pcm header
+ memcpy(PtrTarget, &header_ApRawPcmBuf, sizeof(header_ApRawPcmBuf));
+ BytesCopied = sizeof(header_ApRawPcmBuf);
+
+ //uplink raw pcm
+ PtrTarget = SeqPcmBuf + BytesCopied;
+ PtrSource = (char *)ccci_buff.payload + CCCI_PAYLOAD_BUFF_HEADER_LEN + CCCI_RAW_PCM_BUFF_HEADER_LEN;
+ BytesToCopy = header_RawPcmBufInfo.u16ULLength;
+ memcpy(PtrTarget, PtrSource, BytesToCopy);
+ BytesCopied += BytesToCopy;
+ break;
+
+ case RECORD_TYPE_DL:
+ header_ApRawPcmBuf.u16SyncWord = EEMCS_M2A_SHARE_BUFF_HEADER_SYNC;
+ header_ApRawPcmBuf.u16RawPcmDir = RECORD_TYPE_DL;
+ header_ApRawPcmBuf.u16Freq = GetPcmFreq(header_RawPcmBufInfo.u16DLFreq);
+ header_ApRawPcmBuf.u16Length = header_RawPcmBufInfo.u16DLLength;
+ header_ApRawPcmBuf.u16Channel = 1;
+ header_ApRawPcmBuf.u16BitFormat = AUDIO_FORMAT_PCM_16_BIT;
+ //downlink raw pcm header
+ memcpy(PtrTarget, &header_ApRawPcmBuf, sizeof(header_ApRawPcmBuf));
+ BytesCopied = sizeof(header_ApRawPcmBuf);
+
+ //downlink raw pcm
+ PtrTarget = SeqPcmBuf + BytesCopied;
+ PtrSource = (char *)ccci_buff.payload + CCCI_PAYLOAD_BUFF_HEADER_LEN + CCCI_RAW_PCM_BUFF_HEADER_LEN + header_RawPcmBufInfo.u16ULLength;
+ BytesToCopy = header_RawPcmBufInfo.u16DLLength;
+ memcpy(PtrTarget, PtrSource, BytesToCopy);
+ BytesCopied += BytesToCopy;
+ break;
+ case RECORD_TYPE_MIX:
+ header_ApRawPcmBuf.u16SyncWord = EEMCS_M2A_SHARE_BUFF_HEADER_SYNC;
+ header_ApRawPcmBuf.u16RawPcmDir = RECORD_TYPE_UL;
+ header_ApRawPcmBuf.u16Freq = GetPcmFreq(header_RawPcmBufInfo.u16ULFreq);
+ header_ApRawPcmBuf.u16Length = header_RawPcmBufInfo.u16ULLength;
+ header_ApRawPcmBuf.u16Channel = 1;
+ header_ApRawPcmBuf.u16BitFormat = AUDIO_FORMAT_PCM_16_BIT;
+ //uplink raw pcm header
+ memcpy(PtrTarget, &header_ApRawPcmBuf, sizeof(header_ApRawPcmBuf));
+ BytesCopied = sizeof(header_ApRawPcmBuf);
+
+ //uplink raw pcm
+ PtrTarget = SeqPcmBuf + BytesCopied;
+ PtrSource = (char *)ccci_buff.payload + CCCI_PAYLOAD_BUFF_HEADER_LEN + CCCI_RAW_PCM_BUFF_HEADER_LEN;
+ BytesToCopy = header_RawPcmBufInfo.u16ULLength;
+ memcpy(PtrTarget, PtrSource, BytesToCopy);
+ BytesCopied += BytesToCopy;
+ PtrTarget = SeqPcmBuf + BytesCopied;
+
+
+ //downlink raw pcm header
+ header_ApRawPcmBuf.u16RawPcmDir = RECORD_TYPE_DL;
+ header_ApRawPcmBuf.u16Freq = GetPcmFreq(header_RawPcmBufInfo.u16DLFreq);
+ header_ApRawPcmBuf.u16Length = header_RawPcmBufInfo.u16DLLength;
+ memcpy(PtrTarget, &header_ApRawPcmBuf, sizeof(header_ApRawPcmBuf));
+ BytesCopied += sizeof(header_ApRawPcmBuf);
+
+ //downlink raw pcm
+ PtrTarget = SeqPcmBuf + BytesCopied;
+ PtrSource = (char *)ccci_buff.payload + CCCI_PAYLOAD_BUFF_HEADER_LEN + CCCI_RAW_PCM_BUFF_HEADER_LEN + header_RawPcmBufInfo.u16ULLength;
+ BytesToCopy = header_RawPcmBufInfo.u16DLLength;
+ memcpy(PtrTarget, PtrSource, BytesToCopy);
+ BytesCopied += BytesToCopy;
+
+
+ break;
+ }
+
+ //ring buffer process
+ ul_ring_buf.bufLen = mM2AShareBufLen;
+ ul_ring_buf.pBufBase = mM2AShareBufBase;
+ ul_ring_buf.pBufEnd = ul_ring_buf.pBufBase + ul_ring_buf.bufLen;
+ ul_ring_buf.pRead = mM2AShareBufRead;
+
+ ul_ring_buf.pWrite = ul_ring_buf.pRead + BytesCopied;
+ if (ul_ring_buf.pWrite >= mM2AShareBufEnd) {
+ ul_ring_buf.pWrite -= ul_ring_buf.bufLen;
+
+ size_copy1 = mM2AShareBufEnd - ul_ring_buf.pRead;
+ size_copy2 = BytesCopied - size_copy1;
+ ALOGV("%s(), mM2AShareBufEnd(%p), BytesCopied(0x%x), size_copy1(0x%x), size_copy2(0x%x), pRead(%p), pWrite(%p)",
+ __FUNCTION__, mM2AShareBufEnd, BytesCopied, size_copy1, size_copy2, ul_ring_buf.pRead, ul_ring_buf.pWrite);
+ memcpy(ul_ring_buf.pRead, (char *)SeqPcmBuf, size_copy1);
+ memcpy(ul_ring_buf.pBufBase, (char *)SeqPcmBuf + size_copy1, size_copy2);
+ } else {
+ memcpy(ul_ring_buf.pRead, (char *)SeqPcmBuf, BytesCopied);
+ }
+ ALOGV("-%s(), pBufBase(%p), bufLen(0x%x), BytesCopied(0x%x), mM2AShareBufRead(%p), pRead(%p), pWrite(%p)",
+ __FUNCTION__, ul_ring_buf.pBufBase, ul_ring_buf.bufLen, BytesCopied, mM2AShareBufRead, ul_ring_buf.pRead, ul_ring_buf.pWrite);
+
+ mM2AShareBufRead = ul_ring_buf.pWrite;
+
+ return ul_ring_buf;
+}
+
+uint16_t SpeechMessengerECCCI::GetM2AUplinkData(const ccci_buff_t &ccci_buff, char *TargetBuf) {
+ uint16_t BytePayload = GetMessageLength(ccci_buff);
+ uint16_t ByteData;
+
+
+ // share buffer header
+ char *p_sync_word = (char *)ccci_buff.payload + 0; // size(unsigned short)
+ char *p_data_type = (char *)ccci_buff.payload + 2; // size(unsigned short)
+ char *p_data_len = (char *)ccci_buff.payload + 4; // size(unsigned short)
+ char *p_data_curIdx = (char *)ccci_buff.payload + 6; // size(unsigned short)
+ char *p_data_totalIdx = (char *)ccci_buff.payload + 8; // size(unsigned short)
+ ByteData = *(uint16_t *)p_data_len;
+
+ if (*(uint16_t *)p_data_curIdx == *(uint16_t *)p_data_totalIdx) { mA2M_ECCCI_DATA_READ_ACK = true; }
+
+ if (*(uint16_t *)p_sync_word != EEMCS_M2A_SHARE_BUFF_HEADER_SYNC) {
+ char idxDump = 10, IdxDump;
+ char SphDumpStr[SPH_DUMP_STR_SIZE] = {0};
+
+ snprintf(SphDumpStr, SPH_DUMP_STR_SIZE, "payload[pBase 0x%p, msg 0x%x]= ", ccci_buff.payload, ccci_buff.message);
+ for (IdxDump = 0; IdxDump < idxDump; IdxDump++) {
+ char SphDumpTemp[100];
+ snprintf(SphDumpTemp, 100, "[%d, 0x%p]0x%x, ", IdxDump, ccci_buff.payload + IdxDump, *((uint16_t *)ccci_buff.payload + IdxDump));
+ audio_strncat(SphDumpStr, SphDumpTemp, SPH_DUMP_STR_SIZE);
+ }
+ if (IdxDump != 0) {
+ ALOGD("%s(), %s", __FUNCTION__, SphDumpStr);
+ }
+ ALOGD("%s(), message = 0x%x, *p_sync_word(0x%x), *p_data_type(0x%x), *p_data_len(%d)",
+ __FUNCTION__, ccci_buff.message, *(uint16_t *)p_sync_word, *(uint16_t *)p_data_type, *(uint16_t *)p_data_len);
+ }
+ ASSERT(*(uint16_t *)p_sync_word == EEMCS_M2A_SHARE_BUFF_HEADER_SYNC);
+ //reset the data ptr of buffer
+ memcpy(TargetBuf, (char *)ccci_buff.payload + CCCI_PAYLOAD_BUFF_HEADER_LEN, ByteData);
+ ALOGV("-%s(), TargetBuf(%p), ByteData(0x%x)", __FUNCTION__, TargetBuf, ByteData);
+
+ return ByteData;
+}
+
+
+uint16_t SpeechMessengerECCCI::GetM2AShareBufSyncWord(const ccci_buff_t &ccci_buff) {
+ char *p_sync_word = (char *)ccci_buff.payload + 0; // 0 * size(unsigned short)
+ SLOGV("%s(), sync = 0x%x", __FUNCTION__, *(uint16_t *)p_sync_word);
+ return *(uint16_t *)p_sync_word;
+}
+
+uint16_t SpeechMessengerECCCI::GetM2AShareBufDataType(const ccci_buff_t &ccci_buff) {
+ char *p_data_type = (char *)ccci_buff.payload + 2; // 1 * size(unsigned short)
+ SLOGV("%s(), type = 0x%x", __FUNCTION__, *(uint16_t *)p_data_type);
+ return *(uint16_t *)p_data_type;
+}
+
+uint16_t SpeechMessengerECCCI::GetM2AShareBufDataLength(const ccci_buff_t &ccci_buff) {
+ char *p_data_len = (char *)ccci_buff.payload + 4; // 2 * size(unsigned short)
+ SLOGV("%s(), data_len = %d", __FUNCTION__, *(uint16_t *)p_data_len);
+ return *(uint16_t *)p_data_len;
+}
+
+
+bool SpeechMessengerECCCI::GetModemSideModemStatus(const modem_status_mask_t modem_status_mask) const {
+ return ((mModemSideModemStatus & modem_status_mask) > 0);
+}
+
+void SpeechMessengerECCCI::SetModemSideModemStatus(const modem_status_mask_t modem_status_mask) {
+ mModemSideModemStatus |= modem_status_mask;
+
+ // save mModemSideModemStatus in property to avoid medieserver die
+ char property_value[PROPERTY_VALUE_MAX];
+ sprintf(property_value, "%u", mModemSideModemStatus);
+ property_set(PROPERTY_KEY_MODEM_STATUS[mModemIndex], property_value);
+}
+
+void SpeechMessengerECCCI::ResetModemSideModemStatus(const modem_status_mask_t modem_status_mask) {
+ mModemSideModemStatus &= (~modem_status_mask);
+
+ // save mModemSideModemStatus in property to avoid medieserver die
+ char property_value[PROPERTY_VALUE_MAX];
+ sprintf(property_value, "%u", mModemSideModemStatus);
+ property_set(PROPERTY_KEY_MODEM_STATUS[mModemIndex], property_value);
+}
+
+void SpeechMessengerECCCI::GetRFInfo(void) {
+ uint16_t mRfMode = 0, mRfInfo = 0;
+ char property_value[PROPERTY_VALUE_MAX], property_value2[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_RF_INFO[0], property_value, "0"); //"0": default all off
+ mRfInfo = atoi(property_value);
+
+ property_get(PROPERTY_KEY_RF_INFO[1], property_value2, "0"); //"0": default all off
+ mRfMode = atoi(property_value2);
+
+ ALOGD("%s(), mRfInfo(0x%x), mRfMode(%d)", __FUNCTION__, mRfInfo, mRfMode);
+}
+
+void SpeechMessengerECCCI::SetRFInfo(char mRFIdx, uint16_t mRfData) {
+ // save mRfMode, mRfInfo in property to avoid medieserver die
+ char property_value[PROPERTY_VALUE_MAX];
+ sprintf(property_value, "%u", mRfData);
+ property_set(PROPERTY_KEY_RF_INFO[(unsigned char)mRFIdx], property_value);
+}
+
+void SpeechMessengerECCCI::ResetRFInfo(void) {
+ uint16_t mRfMode = 0, mRfInfo = 0;
+
+ // save mRfMode, mRfInfo in property to avoid medieserver die
+ char property_value[PROPERTY_VALUE_MAX], property_value2[PROPERTY_VALUE_MAX];
+ sprintf(property_value, "%u", mRfMode);
+ property_set(PROPERTY_KEY_RF_INFO[0], property_value);
+
+ sprintf(property_value, "%u", mRfInfo);
+ property_set(PROPERTY_KEY_RF_INFO[1], property_value);
+}
+
+status_t SpeechMessengerECCCI::setPcmRecordType(RecordType typeRecord) {
+ mPcmRecordType = typeRecord;
+ ALOGD("%s(), mPcmRecordType(%d)", __FUNCTION__, mPcmRecordType);
+ return NO_ERROR;
+}
+
+status_t SpeechMessengerECCCI::SetNWCodecInfo(const ccci_buff_t &ccci_buff) {
+ spcCodecInfoStruct sCodecInfo;
+ int returnPinfo = 0, returnHStatus = 0;
+ //parse message
+ char *p_sync_word = (char *)ccci_buff.payload + 0; // size(unsigned short)
+ char *p_data_type = (char *)ccci_buff.payload + 2; // size(unsigned short)
+ char *p_data_len = (char *)ccci_buff.payload + 4; // size(unsigned short)
+ char *p_data_curIdx = (char *)ccci_buff.payload + 6; // size(unsigned short)
+ char *p_data_totalIdx = (char *)ccci_buff.payload + 8; // size(unsigned short)
+ ALOGV("%s(), *p_sync_word(0x%x), *p_data_type(0x%x), *p_data_len(0x%x), *p_data_curIdx(0x%x), *p_data_totalIdx(0x%x)",
+ __FUNCTION__, *(uint16_t *)p_sync_word, *(uint16_t *)p_data_type, *(uint16_t *)p_data_len, *(uint16_t *)p_data_curIdx, *(uint16_t *)p_data_totalIdx);
+
+ ASSERT(*(uint16_t *)p_sync_word == EEMCS_M2A_SHARE_BUFF_HEADER_SYNC);
+
+ // share buffer header
+ memcpy(&sCodecInfo, (char *)ccci_buff.payload + CCCI_PAYLOAD_BUFF_HEADER_LEN, sizeof(spcCodecInfoStruct));
+
+ ALOGD("%s(), sCodecInfo.codecInfo = %s, sCodecInfo.codecOp = %s", __FUNCTION__, sCodecInfo.codecInfo, sCodecInfo.codecOp);
+
+ returnPinfo = property_set(PROPERTY_KEY_NW_CODEC_INFO[0], sCodecInfo.codecInfo);
+ returnHStatus = property_set(PROPERTY_KEY_NW_CODEC_INFO[1], sCodecInfo.codecOp);
+
+ char pValue_CodecInfo[PROPERTY_VALUE_MAX];
+ char pValue_HDVoiceStatus[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_NW_CODEC_INFO[0], pValue_CodecInfo, ""); //"": default
+ property_get(PROPERTY_KEY_NW_CODEC_INFO[1], pValue_HDVoiceStatus, ""); //"": default
+
+ ALOGD("%s(), get %s = %s, %s = %s", __FUNCTION__, PROPERTY_KEY_NW_CODEC_INFO[0], pValue_CodecInfo, PROPERTY_KEY_NW_CODEC_INFO[1], pValue_HDVoiceStatus);
+
+ return NO_ERROR;
+
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechMessengerEVDO.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechMessengerEVDO.cpp
new file mode 100644
index 0000000..5cb51b4
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechMessengerEVDO.cpp
@@ -0,0 +1,2653 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechMessengerEVDO"
+#include "SpeechMessengerEVDO.h"
+#include <unistd.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include <sys/prctl.h>
+#include <sys/resource.h>
+
+#include <cutils/properties.h>
+
+#include "SpeechDriverLAD.h"
+#include "SpeechBGSPlayer.h"
+#include "SpeechPcm2way.h"
+#include "SpeechVMRecorder.h"
+#include "AudioVolumeFactory.h"
+
+#include "AudioALSAHardwareResourceManager.h"
+
+#include "AudioALSACaptureDataProviderVoice.h"
+#include "SpeechDataProcessingHandler.h"
+#if defined(SPH_VCL_SUPPORT)
+#include "SpeechVoiceCustomLogger.h"
+#endif
+
+#if defined(MTK_SPEECH_ENCRYPTION_SUPPORT)
+#include "SpeechDataEncrypter.h"
+#endif
+
+//#include "AudioMTKStreamInManager.h"
+//#include "AudioResourceManager.h"
+extern "C" {
+#ifndef MTK_ECCCI_C2K
+#include <c2kutils.h>
+#endif
+//#include "hardware/ccci_intf.h"
+}
+#include <dlfcn.h>
+
+
+#ifndef sph_msleep
+#define sph_msleep(ms) usleep((ms)*1000)
+#endif
+
+namespace android {
+
+/** CCCI driver & ioctl */
+
+
+/** CCCI ioctl */
+//static const char DEVICE_NAME[] = "/dev/ttySDIO4";
+
+//const variable
+#define BUFFER_SIZE 512
+#define MAX_RETRY 5
+#define READ_BUF_SIZE 4096
+
+
+#define SPH_DUMP_STR_SIZE (500)
+
+/** Property keys*/
+static const char* PROPERTY_KEY_MODEM_STATUS[NUM_MODEM] = {"vendor.audiohal.modem_1.status", "vendor.audiohal.modem_2.status", "vendor.audiohal.modem_ext.status"};
+static const char* PROPERTY_KEY_NW_CODEC_INFO[2] = {"vendor.audiohal.ril.speech.codec.info", "vendor.audiohal.ril.hd.voice.status"};
+
+
+/** CCCI channel No */
+static const uint8_t CCCI_M2A_CHANNEL = 4;
+static const uint8_t CCCI_A2M_CHANNEL = 5;
+
+/** CCCI magic number */
+static const uint32_t CCCI_MAILBOX_MAGIC_NUMBER = 0xFFFFFFFF;
+
+/** UART channel No */
+static const uint32_t CCCI_MAILBOX_COMMAND_NUMBER = 0x22224444;
+static const uint32_t CCCI_MAILBOX_DATA_NUMBER = 0x33336666;
+
+#define EVDO_BUF_HEADER_FOOTER_SIZE (16)
+
+static const uint32_t ap_working_buf_byte = 4096;
+
+//static FILE *fout = NULL;
+//static FILE *fout2 = NULL;
+
+SpeechMessengerEVDO::SpeechMessengerEVDO(modem_index_t modem_index, SpeechDriverLAD *pLad) :
+ mModemIndex(modem_index),
+ mLad(pLad) {
+ ALOGD("%s()", __FUNCTION__);
+ CCCIEnable = false;
+ mModemStatus = MODEM_STATUS_INVALID;
+
+ fHdl = -1;
+
+ mA2MShareBufLen = 0;
+ mM2AShareBufLen = 0;
+
+ mA2MShareBufBase = NULL;
+ mM2AShareBufBase = NULL;
+
+ mA2MShareBufEnd = NULL;
+ mM2AShareBufEnd = NULL;
+ mWasModemReset = false;
+
+ memset(&mM2AShareBuf, 0, sizeof(mM2AShareBuf));
+
+ //initial the message queue
+ memset((void *)pQueue, 0, sizeof(pQueue));
+ iQRead = 0;
+ iQWrite = 0;
+
+ mWaitAckMessageID = 0;
+#ifdef USE_CCCI_SHARE_BUFFER
+ CCCIBuf_Hdl = -1;
+ mA2MParaShareBufBase = NULL;
+ mA2MParaShareBufLen = 0;
+#endif
+
+ //initial modem side modem status
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_MODEM_STATUS[mModemIndex], property_value, "0"); //"0": default all off
+ mModemSideModemStatus = atoi(property_value);
+ ALOGD("%s(), mModemIndex(%d), property read(0x%x)", __FUNCTION__, mModemIndex, mModemSideModemStatus);
+
+ ResetSpeechParamAckCount();
+ mECCCIShareBuf = NULL;
+ mM2AShareBufRead = NULL;
+
+ mModemStatus = MODEM_STATUS_READY;
+ mWaitAckMessageID = 0;
+ mIsModemResetDuringPhoneCall = false;
+ mIsModemReset = false;
+ mIsModemEPOF = false;
+ mPcmRecordType = RECORD_TYPE_UL;
+ mCreatingSphThreadFlag = false;
+ mWaitSphThreadFlag = false;
+ hReadThread = 0;
+ hSendSphThread = 0;
+ hOpenMuxdDeviceThread = 0;
+ mLogEnable = 0;
+
+}
+
+void SpeechMessengerEVDO::OpenMuxdDeviceUntilReady() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ if (fHdl >= 0) {
+ close(fHdl);
+ fHdl = -1;
+ }
+
+ while (fHdl < 0) {
+ sph_msleep(100);
+
+ AL_LOCK(mfHdlLock);
+ AL_LOCK(mGetModemCurrentStatusLock);
+ char dev_node[32];
+
+#ifdef MTK_ECCCI_C2K
+ snprintf(dev_node, 32, "%s", ccci_get_node_name(USR_AUDIO_RX, MD_SYS3));
+ ALOGD("%s(), dev_node=%s", __FUNCTION__, dev_node);
+ fHdl = open(dev_node, O_RDWR);
+#else
+ snprintf(dev_node, 32, "%s", "/dev/ttySDIO0");
+ ALOGD("%s(), dev_node=%s", __FUNCTION__, dev_node);
+ fHdl = open(dev_node, O_RDWR | O_NONBLOCK);
+#endif
+
+ if (fHdl < 0) {
+ ALOGE("%s(), re-open(%s) fail, fHdl = %d, errno = %d", __FUNCTION__, dev_node, fHdl, errno);
+ } else {
+ ALOGD("%s(), re-open(%s) success, fHdl = %d", __FUNCTION__, dev_node, fHdl);
+ }
+
+ AL_UNLOCK(mfHdlLock);
+ AL_UNLOCK(mGetModemCurrentStatusLock);
+ }
+
+ // Clean mWaitAckMessageID to avoid the queue receiving the wrong ack
+ mWaitAckMessageID = 0;
+
+ mIsModemResetDuringPhoneCall = false;
+ mIsModemReset = false;
+ mIsModemEPOF = false;
+
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+
+void *SpeechMessengerEVDO::OpenMuxdDeviceThread(void *arg) {
+ pthread_detach(pthread_self());
+
+ prctl(PR_SET_NAME, (unsigned long)__FUNCTION__, 0, 0, 0);
+ // Adjust thread priority
+ int rtnPrio = setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+ if (0 != rtnPrio) {
+ ALOGE("[%s] failed, errno: %d, return=%d", __FUNCTION__, errno, rtnPrio);
+ } else {
+ ALOGD("%s setpriority ok, priority: %d", __FUNCTION__, ANDROID_PRIORITY_AUDIO);
+ }
+ ALOGD("%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+
+ SpeechMessengerEVDO *pCCCI = (SpeechMessengerEVDO *)arg;
+
+ pCCCI->OpenMuxdDeviceUntilReady();
+
+ pthread_exit(NULL);
+ return 0;
+}
+
+
+status_t SpeechMessengerEVDO::Initial() {
+ ALOGD("%s()", __FUNCTION__);
+ AL_AUTOLOCK(mfHdlLock);
+
+ char dev_node[32];
+#ifdef MTK_ECCCI_C2K
+ snprintf(dev_node, 32, "%s", ccci_get_node_name(USR_AUDIO_RX, MD_SYS3));
+ ALOGD("%s(), dev_node=%s", __FUNCTION__, dev_node);
+ fHdl = open(dev_node, O_RDWR);
+#else
+ snprintf(dev_node, 32, "%s", "/dev/ttySDIO0");
+ ALOGD("%s(), dev_node=%s", __FUNCTION__, dev_node);
+ fHdl = open(dev_node, O_RDWR | O_NONBLOCK);
+#endif
+
+ if (fHdl < 0) {
+ ALOGE("%s(), open(%s) fail, fHdl = %d, errno=%d, return", __FUNCTION__, dev_node, fHdl, errno);
+ mModemStatus = MODEM_STATUS_INIT;
+
+ int ret = pthread_create(&hOpenMuxdDeviceThread, NULL, SpeechMessengerEVDO::OpenMuxdDeviceThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create hOpenMuxdDeviceThread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ ALOGD("%s(), open(%s) success, fHdl = %d", __FUNCTION__, dev_node, fHdl);
+ mModemStatus = MODEM_STATUS_READY;
+
+ // Clean mWaitAckMessageID to avoid the queue receiving the wrong ack
+ mWaitAckMessageID = 0;
+
+ mIsModemResetDuringPhoneCall = false;
+ mIsModemReset = false;
+ mIsModemEPOF = false;
+ mPcmRecordType = RECORD_TYPE_UL;
+ mCreatingSphThreadFlag = false;
+ mWaitSphThreadFlag = false;
+
+ }
+
+#ifdef USE_CCCI_SHARE_BUFFER
+ CCCI_MD md_id = MD_SYS3;
+ unsigned char *share_addr = NULL;
+ unsigned int length = 0;
+ CCCIBuf_Hdl = ccci_smem_get(md_id, USR_SMEM_RAW_AUDIO, &share_addr, &length);
+ if (CCCIBuf_Hdl < 0) {
+ ALOGE("%s() fail to allocate share buffer for MD %d", __FUNCTION__, md_id);
+ return UNKNOWN_ERROR;
+ }
+ ALOGD("%s(), share_addr %p, length %d", __FUNCTION__, share_addr, length);
+ mA2MParaShareBufBase = (char *) share_addr;
+ mA2MParaShareBufLen = length;
+ InitA2MRawParaRingBuffer();
+#endif
+
+ // Get total share buffer length & base address
+ const uint32_t share_buf_length = 32000;
+ mECCCIShareBuf = new char[share_buf_length];
+
+ char *share_buf_address = mECCCIShareBuf;
+ ALOGD("%s(), share_buf_address: %p, share_buf_length: %u", __FUNCTION__, share_buf_address, share_buf_length);
+
+ mA2MShareBufLen = share_buf_length >> 1; // a2m buffer lengh should be half of share_buf_length
+ mM2AShareBufLen = share_buf_length >> 1; // m2a buffer lengh should be half of share_buf_length
+
+ mA2MShareBufBase = share_buf_address;
+ mM2AShareBufBase = share_buf_address + mA2MShareBufLen;
+
+ mA2MShareBufEnd = mA2MShareBufBase + mA2MShareBufLen;
+ mM2AShareBufEnd = mM2AShareBufBase + mM2AShareBufLen;
+
+ mM2AShareBufRead = mM2AShareBufBase;
+
+ mM2AShareBuf.bufLen = mM2AShareBufLen;
+ mM2AShareBuf.pBufBase = mM2AShareBufBase;
+ mM2AShareBuf.pRead = mM2AShareBuf.pBufBase;
+ mM2AShareBuf.pWrite = mM2AShareBuf.pBufBase;
+
+ mSphPCMBuf = new char[ap_working_buf_byte];
+ mSphPCMBufEnd = mSphPCMBuf + ap_working_buf_byte;
+ pcm_ring_buf.bufLen = ap_working_buf_byte;
+ pcm_ring_buf.pBufBase = mSphPCMBuf;
+ pcm_ring_buf.pRead = pcm_ring_buf.pBufBase;
+ pcm_ring_buf.pWrite = pcm_ring_buf.pRead;
+ LastSentMessage = 0;
+ LastNeedAckSentMessage = 0;
+ /* create the CCCI event reading thread */
+ CCCIEnable = true;
+#if defined(MTK_SPEECH_ENCRYPTION_SUPPORT)
+ //trigger initialization
+ SpeechDataEncrypter::GetInstance()->GetDumpStatus();
+#endif
+ mLogEnable = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);
+
+ return CreateReadingThread();
+}
+
+status_t SpeechMessengerEVDO::Deinitial() {
+ ALOGD("%s()", __FUNCTION__);
+ AL_AUTOLOCK(mfHdlLock);
+
+ CCCIEnable = false;
+
+ if (fHdl >= 0) {
+ close(fHdl);
+ fHdl = -1;
+ }
+
+ if (mECCCIShareBuf != NULL) {
+ delete mECCCIShareBuf;
+ mECCCIShareBuf = NULL;
+
+ mA2MShareBufLen = 0;
+ mM2AShareBufLen = 0;
+
+ mA2MShareBufBase = NULL;
+ mM2AShareBufBase = NULL;
+
+ mA2MShareBufEnd = NULL;
+ mM2AShareBufEnd = NULL;
+ }
+
+ if (mSphPCMBuf != NULL) {
+ delete mSphPCMBuf;
+ mSphPCMBuf = NULL;
+ }
+ mSphPCMBufEnd = NULL;
+
+#if defined(USE_CCCI_SHARE_BUFFER)
+ if (CCCIBuf_Hdl >= 0) {
+ ccci_smem_put(CCCIBuf_Hdl, (unsigned char *) mA2MParaShareBufBase, mA2MParaShareBufLen);
+ CCCIBuf_Hdl = -1;
+ }
+ mA2MParaShareBufBase = NULL;
+ mA2MParaShareBufLen = 0;
+#endif
+
+ return NO_ERROR;
+}
+
+
+SpeechMessengerEVDO::~SpeechMessengerEVDO() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+/** Create CCCI message */
+ccci_buff_t SpeechMessengerEVDO::InitCcciMailbox(uint16_t id, uint16_t param_16bit, uint32_t param_32bit) {
+ ccci_buff_t ccci_buff;
+ memset(&ccci_buff, 0, sizeof(ccci_buff));
+
+ ccci_buff.magic = CCCI_MAILBOX_MAGIC_NUMBER;
+ ccci_buff.message = (id << 16) | param_16bit;
+ ccci_buff.channel = CCCI_A2M_CHANNEL;
+ ccci_buff.reserved = param_32bit;
+
+ // ALOGD("JT:-InitCcciMailBox");
+ return ccci_buff;
+}
+
+/** Get CCCI message's ID */
+uint16_t SpeechMessengerEVDO::GetMessageID(const ccci_buff_t &ccci_buff) {
+ return (ccci_buff.message) >> 16;
+}
+
+/** Get CCCI message's parameters */
+uint16_t SpeechMessengerEVDO::GetMessageParam(const ccci_buff_t &ccci_buff) {
+ return (ccci_buff.message) & 0xFFFF;
+}
+
+/** Get CCCI message's payload length */
+uint16_t SpeechMessengerEVDO::GetMessageLength(const ccci_buff_t &ccci_buff) { // TODO(Harvey): rename payload length
+ return (ccci_buff.message) & 0xFFFF;
+}
+
+uint16_t SpeechMessengerEVDO::GetMessageOffset(const ccci_buff_t &ccci_buff) {
+ return (ccci_buff.reserved) & 0xFFFF;
+}
+
+
+char SpeechMessengerEVDO::GetModemCurrentStatus() {
+ AL_AUTOLOCK(mGetModemCurrentStatusLock);
+
+ if (mIsModemEPOF == true) {
+ mModemStatus = MODEM_STATUS_INVALID;
+ ALOGD("%s() MD EPOF!set mModemStatus=%d", __FUNCTION__, mModemStatus);
+ } else {
+ unsigned int status = (unsigned int)MODEM_STATUS_INVALID;
+ int retval = 0;
+#ifdef MTK_ECCCI_C2K
+ retval = ::ioctl(fHdl, CCCI_IOC_GET_MD_STATE, &status);
+#else
+ retval = ::ioctl(fHdl, CMDM_IOCTL_CHECK_MD_READY, &status);
+#endif
+ if (retval < 0) {
+ mModemStatus = MODEM_STATUS_EXPT;
+ ALOGE("%s() ioctl CCCI_IOC_GET_MD_STATE fail!! retval = %d, errno: %d, set mModemStatus=%d",
+ __FUNCTION__, retval, errno, mModemStatus);
+ } else {
+ mModemStatus = (char)status;
+ }
+ }
+ return mModemStatus;
+}
+
+bool SpeechMessengerEVDO::CheckModemIsReady() {
+ return (GetModemCurrentStatus() == MODEM_STATUS_READY);
+}
+
+status_t SpeechMessengerEVDO::WaitUntilModemReady() {
+ char status = 0;
+ uint32_t trycnt = 0;
+ const uint32_t kMaxTryCnt = 10; // total 200 msec
+ do {
+ status = GetModemCurrentStatus();
+ if (status == MODEM_STATUS_READY) {
+ ALOGD("%s(): Modem ready", __FUNCTION__);
+ break;
+ } else {
+ ALOGW("Wait CCCI open #%d times, modem current status = %d", ++trycnt, status);
+ sph_msleep(20);
+ if (trycnt == kMaxTryCnt) { break; }
+ }
+ } while (1);
+
+ return (trycnt < kMaxTryCnt) ? NO_ERROR : TIMED_OUT;
+}
+
+#undef LOG_TAG
+#define LOG_TAG "SpeechMessengerEVDO_Send"
+
+int32_t SpeechMessengerEVDO::SendMessage(const ccci_buff_t &ccci_buff) {
+ ALOGV("%s()", __FUNCTION__);
+ AL_AUTOLOCK(mfHdlLock);
+
+ // check if need ack
+ uint16_t message_id = GetMessageID(ccci_buff);
+ const bool b_need_ack = (JudgeAckOfMsg(message_id) == MESSAGE_NEED_ACK) ? true : false;
+
+ // check modem status during phone call
+ char modem_status = GetModemCurrentStatus();
+ if (modem_status != MODEM_STATUS_READY) {
+ ALOGE("%s(), modem_status(%d) != MODEM_STATUS_READY, mIsModemEPOF = %d", __FUNCTION__, modem_status, mIsModemEPOF);
+ mIsModemResetDuringPhoneCall = true;
+ mIsModemReset = true;
+ ResetSpeechParamAckCount();
+ }
+
+ // Do not send any on/off message when mIsModemResetDuringPhoneCall is true
+ if (mIsModemResetDuringPhoneCall == true && IsModemFunctionOnOffMessage(message_id) == true) {
+ ALOGE("%s(), mIsModemResetDuringPhoneCall == true, drop on/off message: 0x%x", __FUNCTION__, ccci_buff.message);
+ SendMsgFailErrorHandling(ccci_buff);
+
+ // clean mIsModemResetDuringPhoneCall when phone call/loopback stop
+ if (message_id == MSG_A2M_SPH_OFF) {
+ ALOGD("%s(), Phone call stop. Set mIsModemResetDuringPhoneCall = false", __FUNCTION__);
+ mIsModemResetDuringPhoneCall = false;
+ } else if (message_id == MSG_A2M_SET_ACOUSTIC_LOOPBACK) {
+ const bool loopback_on = GetMessageParam(ccci_buff) & 0x1;
+ if (loopback_on == false) {
+ ALOGD("%s(), loopback stop. Set mIsModemResetDuringPhoneCall = false", __FUNCTION__);
+ mIsModemResetDuringPhoneCall = false;
+ }
+ }
+
+ return UNKNOWN_ERROR;
+ }
+
+ // save ack info before write to avoid race condition with CCCIReadThread
+ if (b_need_ack == true) {
+ mWaitAckMessageID = message_id;
+ }
+
+ // init send msg
+ ccci_buff_t uart_buf;
+
+ uint16_t offset_buffer = GetMessageOffset(ccci_buff);
+ uint16_t size_payload = 0;
+ uint16_t size_message = 0;
+ char *pPayload = NULL;
+ switch (message_id) {
+ case MSG_A2M_PNW_DL_DATA_NOTIFY:
+ case MSG_A2M_BGSND_DATA_NOTIFY:
+ case MSG_A2M_CTM_DATA_NOTIFY:
+ case MSG_A2M_EM_NB:
+ case MSG_A2M_EM_WB: // case AUDIO_HD_RECORD_PARAMETER:
+ case MSG_A2M_EM_DMNR:
+ case MSG_A2M_EM_MAGICON:
+ case MSG_A2M_EM_HAC:
+ case MSG_A2M_VIBSPK_PARAMETER:
+ case MSG_A2M_SMARTPA_PARAMETER:
+#ifdef USE_CCCI_SHARE_BUFFER
+ //case MSG_A2M_EM_DYNAMIC_SPH:
+#else
+ case MSG_A2M_EM_DYNAMIC_SPH:
+#endif
+ size_payload = GetMessageLength(ccci_buff);
+ size_message = size_payload + CCCI_BUF_HEADER_SIZE;
+
+ uart_buf.magic = 0; // offset => 0 for modem side
+ uart_buf.message = size_payload;
+ uart_buf.channel = CCCI_MAILBOX_DATA_NUMBER;
+ uart_buf.reserved = ccci_buff.message;
+
+ pPayload = GetA2MShareBufBase() + offset_buffer;
+ ASSERT(size_payload <= (CCCI_MAX_PAYLOAD_SIZE * sizeof(uint32_t)));
+ memcpy(uart_buf.payload, pPayload, size_payload);
+#ifdef CONFIG_MT_ENG_BUILD // eng load
+ ALOGD("%s(), channel=0x%x, message=0x%x, length=0x%x, payload[0]=0x%x, payload[1]=0x%x, payload[2]=0x%x, payload[3]=0x%x",
+ __FUNCTION__, uart_buf.channel, uart_buf.reserved, uart_buf.message, uart_buf.payload[0], uart_buf.payload[1], uart_buf.payload[2], uart_buf.payload[3]);
+#else
+ if (JudgeLogPrintOfMsg(message_id)) {
+ ALOGD("%s(), channel=0x%x, message=0x%x, length=0x%x, payload[0]=0x%x, payload[1]=0x%x, payload[2]=0x%x, payload[3]=0x%x",
+ __FUNCTION__, uart_buf.channel, uart_buf.reserved, uart_buf.message, uart_buf.payload[0], uart_buf.payload[1], uart_buf.payload[2], uart_buf.payload[3]);
+ } else {
+ ALOGV("%s(), channel=0x%x, message=0x%x, length=0x%x, payload[0]=0x%x, payload[1]=0x%x, payload[2]=0x%x, payload[3]=0x%x",
+ __FUNCTION__, uart_buf.channel, uart_buf.reserved, uart_buf.message, uart_buf.payload[0], uart_buf.payload[1], uart_buf.payload[2], uart_buf.payload[3]);
+ }
+#endif
+ break;
+ case MSG_A2M_SPH_UL_ENCRYPTION:
+ case MSG_A2M_SPH_DL_DECRYPTION:
+ size_payload = GetMessageLength(ccci_buff);
+ size_message = size_payload + CCCI_BUF_HEADER_SIZE;
+
+ uart_buf.magic = 0; // offset => 0 for modem side
+ uart_buf.message = size_payload;
+ uart_buf.channel = CCCI_MAILBOX_DATA_NUMBER;
+ uart_buf.reserved = ccci_buff.message;
+
+ pPayload = mSphPCMBuf + offset_buffer;
+ ASSERT(size_payload <= (CCCI_MAX_PAYLOAD_SIZE * sizeof(uint32_t)));
+ memcpy(uart_buf.payload, pPayload, size_payload);
+ ALOGD_IF(mLogEnable, "%s(), channel=0x%x, message=0x%x, length=0x%x, payload[0]=0x%x, payload[1]=0x%x, payload[2]=0x%x, payload[3]=0x%x",
+ __FUNCTION__, uart_buf.channel, uart_buf.reserved, uart_buf.message, uart_buf.payload[0], uart_buf.payload[1], uart_buf.payload[2], uart_buf.payload[3]);
+ break;
+ default: {
+ size_message = CCCI_BUF_HEADER_SIZE;
+
+ uart_buf.magic = ccci_buff.magic;
+ uart_buf.message = ccci_buff.message;
+ uart_buf.channel = CCCI_MAILBOX_COMMAND_NUMBER;
+ uart_buf.reserved = ccci_buff.reserved;
+#ifdef CONFIG_MT_ENG_BUILD// eng load
+ ALOGD("%s(), size_message = %d, data[0] = 0x%x, data[1] = 0x%x, channel = 0x%x, reserved = 0x%x, b_need_ack %d",
+ __FUNCTION__, size_message, uart_buf.magic, uart_buf.message, uart_buf.channel, uart_buf.reserved, b_need_ack);
+#else // use and use debug load
+ if (ccci_buff.magic == CCCI_MAILBOX_MAGIC_NUMBER) { // message without data payload
+ ALOGD("%s(), size_message = %d, data[0] = 0x%x, data[1] = 0x%x, channel = 0x%x, reserved = 0x%x, b_need_ack %d",
+ __FUNCTION__, size_message, uart_buf.magic, uart_buf.message, uart_buf.channel, uart_buf.reserved, b_need_ack);
+ } else {
+ ALOGV("%s(), size_message = %d, data[0] = 0x%x, data[1] = 0x%x, channel = 0x%x, reserved = 0x%x, b_need_ack %d",
+ __FUNCTION__, size_message, uart_buf.magic, uart_buf.message, uart_buf.channel, uart_buf.reserved, b_need_ack);
+ }
+#endif
+ break;
+ }
+ }
+
+ //if (b_need_ack == true)
+ //{
+ // ALOGD("%s(), size_message = %d, data[0] = 0x%x, data[1] = 0x%x, channel = 0x%x, reserved = 0x%x",
+ // __FUNCTION__, size_message, uart_buf.magic, uart_buf.message, uart_buf.channel , uart_buf.reserved);
+ //}
+
+ // send message
+ int i = 0;
+ int write_length = 0;
+ status_t ret = UNKNOWN_ERROR;
+
+ if (fHdl < 0) {
+ ALOGW("%s(), fHdl(%d) < 0", __FUNCTION__, fHdl);
+ } else {
+ for (i = 0; i < 150; i++) { // try 150 times for every 2 ms if sent message fail
+ write_length = write(fHdl, (void *)&uart_buf, size_message);
+ if (i != 0) {
+ ALOGD("%s() write %d times, return write_length = %d, size_message = %d", __FUNCTION__, i, write_length, size_message);
+ }
+ if (write_length == size_message) {
+ LastSentMessage = message_id;
+ if (MESSAGE_NEED_ACK == JudgeAckOfMsg(message_id)) {
+ LastNeedAckSentMessage = message_id;
+ }
+ ret = NO_ERROR;
+ break;
+ } else if (write_length > 0) {
+ int total_write_length = write_length;
+ char *pWriteBuf = ((char *)&uart_buf) + write_length;
+ do {
+ write_length = write(fHdl, pWriteBuf, size_message - total_write_length);
+ if (write_length < 0) {
+ ALOGE("%s() fail, write_length: %d, modem current status: %d, errno: %d", __FUNCTION__, write_length, GetModemCurrentStatus(), errno);
+ if (message_id != MSG_A2M_SPH_OFF && message_id != MSG_A2M_SET_ACOUSTIC_LOOPBACK) {
+ mIsModemResetDuringPhoneCall = true;
+ }
+ ResetSpeechParamAckCount();
+ break;
+ }
+
+ total_write_length += write_length;
+ pWriteBuf += write_length;
+ } while (total_write_length == size_message);
+
+ if (total_write_length == size_message) { ret = NO_ERROR; }
+ break;
+ } else {
+ modem_status = GetModemCurrentStatus();
+ ALOGW("%s(), message_id: 0x%x, try: #%d, write_length: %d, errno: %d, modem status: %d",
+ __FUNCTION__, message_id, i, write_length, errno, modem_status);
+
+ if (errno == 3 || modem_status != MODEM_STATUS_READY) {
+ ALOGE("%s(), MD RESET SKIP MESSAGE: 0x%x", __FUNCTION__, ccci_buff.message);
+ // if modem reset during phone call, raise mIsModemResetDuringPhoneCall
+ if (message_id != MSG_A2M_SPH_OFF && message_id != MSG_A2M_SET_ACOUSTIC_LOOPBACK) {
+ mIsModemResetDuringPhoneCall = true;
+ }
+ mIsModemReset = true;
+ ResetSpeechParamAckCount();
+ break;
+ }
+ sph_msleep(2);
+ }
+
+ }
+ }
+
+ // error handling for ack message
+ if (ret != NO_ERROR && b_need_ack == true) {
+ mWaitAckMessageID = 0;
+ SendMsgFailErrorHandling(ccci_buff);
+ }
+
+ return ret;
+
+}
+
+#undef LOG_TAG
+#define LOG_TAG "SpeechMessengerEVDO_Read"
+
+status_t SpeechMessengerEVDO::ReadMessage(ccci_buff_t &ccci_buff) {
+
+ if (fHdl < 0) {
+ ALOGD("%s(), fHdl(%d) < 0", __FUNCTION__, fHdl);
+ return UNKNOWN_ERROR;
+ }
+
+ /* read message */
+ fd_set fds;
+
+ FD_ZERO(&fds);
+ FD_SET(fHdl, &fds);
+ int rc = select(fHdl + 1, &fds, NULL, NULL, NULL);
+ ALOGV("%s(), rc: %d, errno: %d", __FUNCTION__, rc, errno);
+ FD_CLR(fHdl, &fds);
+
+ //ccci_buff_t uart_buf;
+ evdo_buff_t uart_buf;
+
+ int length_read = read(fHdl, (void *)&uart_buf, CCCI_BUF_HEADER_SIZE);
+ if (length_read != CCCI_BUF_HEADER_SIZE) {
+ mModemStatus = MODEM_STATUS_EXPT;
+ ALOGE("%s() fail, read_length: %d, errno = %d, force set mModemStatus = %d", __FUNCTION__, length_read, errno, mModemStatus);
+ return UNKNOWN_ERROR;
+ }
+
+#ifdef CONFIG_MT_ENG_BUILD // eng load
+ ALOGD("%s(), length_read = %d, data[0] = 0x%x, data[1] = 0x%x, ch = 0x%x, reserved = 0x%x",
+ __FUNCTION__, length_read, uart_buf.magic, uart_buf.message, uart_buf.channel, uart_buf.reserved);
+#endif
+ if (uart_buf.magic == CCCI_MAILBOX_MAGIC_NUMBER) { // message
+ ASSERT(uart_buf.channel == CCCI_MAILBOX_COMMAND_NUMBER);
+
+ ccci_buff.magic = uart_buf.magic;
+ ccci_buff.message = uart_buf.message;
+ ccci_buff.channel = CCCI_M2A_CHANNEL;
+ ccci_buff.reserved = uart_buf.reserved;
+#ifndef CONFIG_MT_ENG_BUILD // user or user debug load
+ if (ccci_buff.magic == CCCI_MAILBOX_MAGIC_NUMBER && JudgeLogPrintOfMsg(GetMessageID(ccci_buff))) {
+ ALOGD("%s(), length_read = %d, data[0] = 0x%x, data[1] = 0x%x, ch = 0x%x, reserved = 0x%x",
+ __FUNCTION__, length_read, uart_buf.magic, uart_buf.message, uart_buf.channel, uart_buf.reserved);
+ } else {
+ ALOGV("%s(), length_read = %d, data[0] = 0x%x, data[1] = 0x%x, ch = 0x%x, reserved = 0x%x",
+ __FUNCTION__, length_read, uart_buf.magic, uart_buf.message, uart_buf.channel, uart_buf.reserved);
+ }
+#endif
+
+ } else { // data
+ ASSERT(uart_buf.magic == 0);
+ ASSERT(uart_buf.channel == CCCI_MAILBOX_DATA_NUMBER);
+
+ ccci_buff.magic = CCCI_MAILBOX_MAGIC_NUMBER;
+ ccci_buff.message = uart_buf.reserved;
+ ccci_buff.channel = CCCI_M2A_CHANNEL;
+ ccci_buff.reserved = mM2AShareBuf.pWrite - mM2AShareBuf.pBufBase; // offset, read to write
+
+ const uint16_t payload_length = GetMessageLength(ccci_buff);
+ ASSERT(payload_length == uart_buf.message); // TODO(Harvey): check only, remove later
+ //ALOGD("%s(), payload_length = %d", __FUNCTION__, payload_length);
+
+ int read_payload_length = 0;
+ char *pPayload = (char *)uart_buf.payload;
+ do {
+ FD_ZERO(&fds);
+ FD_SET(fHdl, &fds);
+ rc = select(fHdl + 1, &fds, NULL, NULL, NULL);
+ ALOGV("%s(), rc: %d, errno: %d", __FUNCTION__, rc, errno);
+ FD_CLR(fHdl, &fds);
+
+ length_read = read(fHdl, pPayload, payload_length - read_payload_length);
+ char status = GetModemCurrentStatus();
+ // ALOGD("%s(), pPayload[0]=0x%x, pPayload[1]=0x%x, pPayload[2]=0x%x, pPayload[3]=0x%x, pPayload[4]=0x%x, pPayload[5]=0x%x, pPayload[6]=0x%x, pPayload[7]=0x%x, pPayload[8]=0x%x, pPayload[9]=0x%x, pPayload[10]=0x%x, pPayload[11]=0x%x, pPayload[12]=0x%x, pPayload[13]=0x%x",
+ // __FUNCTION__, pPayload[0], pPayload[1], pPayload[2], pPayload[3], pPayload[4], pPayload[5], pPayload[6], pPayload[7], pPayload[8], pPayload[9], pPayload[10], pPayload[11], pPayload[12], pPayload[13]);
+ if (length_read <= 0) {
+ ALOGE("%s() data fail, read_length: %d, errno = %d", __FUNCTION__, length_read, errno);
+
+ mModemStatus = MODEM_STATUS_EXPT;
+ OpenMuxdDeviceUntilReady();
+
+ return UNKNOWN_ERROR;
+ } else if (status != MODEM_STATUS_READY) {
+ ALOGE("%s() modem status(%d) != ready", __FUNCTION__, status);
+ return UNKNOWN_ERROR;
+ } else {
+ read_payload_length += length_read;
+ pPayload += length_read;
+
+#ifdef CONFIG_MT_ENG_BUILD // eng load
+ ALOGD("%s(), read_payload_length = %d, payload_length = %d", __FUNCTION__, read_payload_length, payload_length);
+#else
+ ALOGV("%s(), read_payload_length = %d, payload_length = %d", __FUNCTION__, read_payload_length, payload_length);
+#endif
+ }
+ } while (read_payload_length != payload_length);
+
+ uint16_t *pHeader = (uint16_t *)uart_buf.payload;
+ //ALOGD("%s(), sync = 0x%x, type = 0x%x, data_len = %d", __FUNCTION__ , pHeader[0], pHeader[1], pHeader[2]);
+
+ //fwrite((void *)&pHeader[3], sizeof(char), payload_length - 6, fout);
+
+ RingBuf_copyFromLinear(&mM2AShareBuf, (char *)uart_buf.payload, payload_length);
+
+#ifdef CONFIG_MT_ENG_BUILD // eng load
+ ALOGD("%s(), message=0x%x, length=0x%x, payload[0]=0x%x, payload[1]=0x%x, payload[2]=0x%x, payload[3]=0x%x",
+ __FUNCTION__, uart_buf.reserved, uart_buf.message, uart_buf.payload[0], uart_buf.payload[1], uart_buf.payload[2], uart_buf.payload[3]);
+#else
+ ALOGV("%s(), message=0x%x, length=0x%x, payload[0]=0x%x, payload[1]=0x%x, payload[2]=0x%x, payload[3]=0x%x",
+ __FUNCTION__, uart_buf.reserved, uart_buf.message, uart_buf.payload[0], uart_buf.payload[1], uart_buf.payload[2], uart_buf.payload[3]);
+#endif
+ mM2AShareBuf.pRead = mM2AShareBuf.pWrite; // pseudo read
+ }
+
+ /* check modem status */
+ AL_LOCK(mfHdlLock);
+ uint16_t message_id = GetMessageID(ccci_buff);
+ if (message_id == MSG_M2A_EM_DATA_REQUEST) {
+ mIsModemResetDuringPhoneCall = false;
+ mIsModemReset = false;
+ mIsModemEPOF = false;
+ }
+
+ char status = GetModemCurrentStatus();
+ if (fHdl < 0) {
+ ALOGD("%s(), fHdl(%d) < 0", __FUNCTION__, fHdl);
+ sph_msleep(100);
+ AL_UNLOCK(mfHdlLock);
+ return UNKNOWN_ERROR;
+ } else if (status != MODEM_STATUS_READY) {
+ ALOGD("%s() modem current status = %d, return", __FUNCTION__, status);
+ sph_msleep(100);
+ AL_UNLOCK(mfHdlLock);
+ return UNKNOWN_ERROR;
+ }
+ AL_UNLOCK(mfHdlLock);
+
+ return NO_ERROR;
+}
+
+#undef LOG_TAG
+#define LOG_TAG "SpeechMessengerEVDO"
+
+uint32_t SpeechMessengerEVDO::GetQueueCount() const {
+ int32_t count = (iQWrite - iQRead);
+ if (count < 0) { count += CCCI_MAX_QUEUE_NUM; }
+ return count;
+}
+
+bool SpeechMessengerEVDO::CheckOffsetAndLength(const ccci_buff_t &ccci_buff) {
+ uint16_t message_id = GetMessageID(ccci_buff);
+ uint16_t length = GetMessageLength(ccci_buff);
+ uint16_t offset = GetMessageOffset(ccci_buff);
+
+ if (offset > mM2AShareBufLen || length > mM2AShareBufLen) {
+ ALOGE("%s(), message_id = 0x%x, length(0x%x), offset(0x%x), mM2AShareBufLen(0x%x)", __FUNCTION__, message_id, length, offset, mM2AShareBufLen);
+ ASSERT(offset > mM2AShareBufLen || length > mM2AShareBufLen);
+ return false;
+ } else {
+ return true;
+ }
+}
+
+
+ccci_message_ack_t SpeechMessengerEVDO::JudgeAckOfMsg(const uint16_t message_id) {
+ // ALOGD("JT: +JudgeAckOfMsg()");
+ ccci_message_ack_t ack;
+ switch (message_id) {
+ case MSG_A2M_SET_SPH_MODE:
+ case MSG_A2M_SPH_ON:
+ case MSG_A2M_SPH_OFF:
+ case MSG_A2M_SPH_ROUTER_ON:
+ case MSG_A2M_PCM_REC_ON:
+ case MSG_A2M_VM_REC_ON:
+ case MSG_A2M_PCM_REC_OFF:
+ case MSG_A2M_VM_REC_OFF:
+ case MSG_A2M_BGSND_ON:
+ case MSG_A2M_BGSND_OFF:
+ case MSG_A2M_PNW_ON:
+ case MSG_A2M_PNW_OFF:
+ case MSG_A2M_CTM_ON:
+ case MSG_A2M_CTM_OFF:
+ case MSG_A2M_SET_ACOUSTIC_LOOPBACK:
+ case MSG_A2M_EM_NB:
+ case MSG_A2M_EM_DMNR:
+ case MSG_A2M_EM_WB:
+ case MSG_A2M_EM_MAGICON:
+ case MSG_A2M_EM_HAC:
+ case MSG_A2M_VIBSPK_PARAMETER:
+ case MSG_A2M_SMARTPA_PARAMETER:
+ case MSG_A2M_RECORD_RAW_PCM_ON:
+ case MSG_A2M_RECORD_RAW_PCM_OFF:
+ case MSG_A2M_EM_DYNAMIC_SPH:
+ ack = MESSAGE_NEED_ACK;
+ break;
+ default:
+ ack = MESSAGE_BYPASS_ACK;
+ }
+ // ALOGD("JT: -JudgeAckOfMsg(), ack=%d", ack);
+ return ack;
+}
+
+bool SpeechMessengerEVDO::JudgeLogPrintOfMsg(const uint16_t message_id) {
+ bool isLogPrint = true;
+ switch (message_id) {
+ case MSG_A2M_PNW_DL_DATA_NOTIFY:
+ case MSG_A2M_BGSND_DATA_NOTIFY:
+ case MSG_A2M_CTM_DATA_NOTIFY:
+ case MSG_A2M_SPH_UL_ENCRYPTION:
+ case MSG_A2M_SPH_DL_DECRYPTION:
+ case MSG_A2M_PNW_UL_DATA_READ_ACK:
+ case MSG_A2M_REC_DATA_READ_ACK:
+ case MSG_A2M_CTM_DEBUG_DATA_READ_ACK:
+ case MSG_A2M_PCM_REC_DATA_READ_ACK:
+ case MSG_A2M_VM_REC_DATA_READ_ACK:
+ case MSG_A2M_RAW_PCM_REC_DATA_READ_ACK:
+ case MSG_A2M_CUST_DUMP_READ_ACK:
+ case MSG_M2A_PNW_DL_DATA_REQUEST:
+ case MSG_M2A_BGSND_DATA_REQUEST:
+ case MSG_M2A_CTM_DATA_REQUEST:
+ case MSG_M2A_SPH_UL_ENCRYPTION:
+ case MSG_M2A_SPH_DL_DECRYPTION:
+ case MSG_M2A_PNW_UL_DATA_NOTIFY:
+ case MSG_M2A_CTM_DEBUG_DATA_NOTIFY:
+ case MSG_M2A_PCM_REC_DATA_NOTIFY:
+ case MSG_M2A_VM_REC_DATA_NOTIFY:
+ case MSG_M2A_RAW_PCM_REC_DATA_NOTIFY:
+ case MSG_M2A_CUST_DUMP_NOTIFY:
+ isLogPrint = false;
+ break;
+ default:
+ isLogPrint = true;
+ }
+ return isLogPrint;
+}
+
+
+bool SpeechMessengerEVDO::IsModemFunctionOnOffMessage(const uint16_t message_id) {
+ bool bIsModemFunctionOnOffMessage = false;
+
+ switch (message_id) {
+ case MSG_A2M_SPH_ON:
+ case MSG_A2M_SPH_OFF:
+ case MSG_A2M_SPH_ROUTER_ON:
+ case MSG_A2M_PCM_REC_ON:
+ case MSG_A2M_VM_REC_ON:
+ case MSG_A2M_PCM_REC_OFF:
+ case MSG_A2M_VM_REC_OFF:
+ case MSG_A2M_BGSND_ON:
+ case MSG_A2M_BGSND_OFF:
+ case MSG_A2M_PNW_ON:
+ case MSG_A2M_PNW_OFF:
+ case MSG_A2M_CTM_ON:
+ case MSG_A2M_CTM_OFF:
+ case MSG_A2M_SET_ACOUSTIC_LOOPBACK:
+ case MSG_A2M_RECORD_RAW_PCM_ON:
+ case MSG_A2M_RECORD_RAW_PCM_OFF:
+ bIsModemFunctionOnOffMessage = true;
+ break;
+ default:
+ bIsModemFunctionOnOffMessage = false;
+ }
+
+ return bIsModemFunctionOnOffMessage;
+}
+
+status_t SpeechMessengerEVDO::SendMessageInQueue(ccci_buff_t ccci_buff) {
+ AL_LOCK(mCCCIMessageQueueMutex);
+ status_t ret = NO_ERROR;
+
+ // check modem status during phone call
+ char modem_status = GetModemCurrentStatus();
+ if (modem_status != MODEM_STATUS_READY) {
+ ALOGE("%s(), modem_status(%d) != MODEM_STATUS_READY, errno: %d, mIsModemEPOF = %d", __FUNCTION__, modem_status, errno, mIsModemEPOF);
+ mIsModemResetDuringPhoneCall = true;
+ mIsModemReset = true;
+ ResetSpeechParamAckCount();
+ AL_UNLOCK(mCCCIMessageQueueMutex);
+ uint16_t message_id = GetMessageID(ccci_buff);
+ switch (message_id) {
+ case MSG_A2M_EM_NB:
+ case MSG_A2M_EM_WB:
+ case MSG_A2M_EM_DMNR:
+ case MSG_A2M_EM_MAGICON:
+ case MSG_A2M_EM_HAC:
+ case MSG_A2M_VIBSPK_PARAMETER:
+ case MSG_A2M_SMARTPA_PARAMETER:
+#ifndef USE_CCCI_SHARE_BUFFER
+ case MSG_A2M_EM_DYNAMIC_SPH:
+#endif
+ {
+ A2MBufUnLock();
+ break;
+ }
+ }
+ return ret;
+ }
+
+ uint32_t count = GetQueueCount();
+ ALOGV("%s(), count of message in queue =%d", __FUNCTION__, count);
+
+ ccci_message_ack_t ack_type = JudgeAckOfMsg(GetMessageID(ccci_buff));
+#ifdef CONFIG_MT_ENG_BUILD
+ if (ack_type == MESSAGE_NEED_ACK) {
+ ALOGD("%s(), mModemIndex = %d, need ack message: 0x%x, reserved param: 0x%x",
+ __FUNCTION__, mModemIndex, ccci_buff.message, ccci_buff.reserved);
+ } else {
+ ALOGV("%s(), mModemIndex = %d, no ack message: 0x%x, reserved param: 0x%x",
+ __FUNCTION__, mModemIndex, ccci_buff.message, ccci_buff.reserved);
+ }
+#else
+ if (ack_type == MESSAGE_NEED_ACK) {
+ ALOGV("%s(), mModemIndex = %d, need ack message: 0x%x, reserved param: 0x%x",
+ __FUNCTION__, mModemIndex, ccci_buff.message, ccci_buff.reserved);
+ } else {
+ ALOGV("%s(), mModemIndex = %d, no ack message: 0x%x, reserved param: 0x%x",
+ __FUNCTION__, mModemIndex, ccci_buff.message, ccci_buff.reserved);
+ }
+#endif
+
+ ASSERT(count < (CCCI_MAX_QUEUE_NUM - 1)); // check queue full
+
+ if (mIsModemEPOF == true) {
+ ALOGD("%s(), mIsModemEPOF=%d, Skip message(0x%x) to queue, now count(%u)", __FUNCTION__, mIsModemEPOF, ccci_buff.message, GetQueueCount());
+ A2MBufUnLock();
+
+ } else {
+
+
+ if (count == 0) { // queue is empty
+ if (ack_type == MESSAGE_BYPASS_ACK) { // no need ack, send directly, don't care ret value
+ ret = SendMessage(ccci_buff);
+ } else { // need ack, en-queue and send message
+ pQueue[iQWrite].ccci_buff = ccci_buff;
+ pQueue[iQWrite].ack_type = ack_type;
+ iQWrite++;
+ if (iQWrite == CCCI_MAX_QUEUE_NUM) { iQWrite -= CCCI_MAX_QUEUE_NUM; }
+
+ ret = SendMessage(ccci_buff);
+ if (ret != NO_ERROR) { // skip this fail CCCI message
+ iQRead++;
+ if (iQRead == CCCI_MAX_QUEUE_NUM) { iQRead -= CCCI_MAX_QUEUE_NUM; }
+ }
+ }
+ } else { // queue is not empty, must queue the element
+ pQueue[iQWrite].ccci_buff = ccci_buff;
+ pQueue[iQWrite].ack_type = ack_type;
+ iQWrite++;
+ if (iQWrite == CCCI_MAX_QUEUE_NUM) { iQWrite -= CCCI_MAX_QUEUE_NUM; }
+
+#ifdef CONFIG_MT_ENG_BUILD
+ ALOGD("%s(), Send message(0x%x) to queue, reserve param(0x%x), mModemIndex (%d), count(%u), LastSentMessage(0x%x), LastNeedAckSentMessage(0x%x)", __FUNCTION__, ccci_buff.message, ccci_buff.reserved, mModemIndex, GetQueueCount(), LastSentMessage, LastNeedAckSentMessage);
+#else
+ ALOGV("%s(), Send message(0x%x) to queue, reserve param(0x%x), mModemIndex (%d), count(%u), LastSentMessage(0x%x), LastNeedAckSentMessage(0x%x)", __FUNCTION__, ccci_buff.message, ccci_buff.reserved, mModemIndex, GetQueueCount(), LastSentMessage, LastNeedAckSentMessage);
+#endif
+ }
+ }
+ AL_UNLOCK(mCCCIMessageQueueMutex);
+ return ret;
+}
+
+status_t SpeechMessengerEVDO::ConsumeMessageInQueue() {
+ AL_LOCK(mCCCIMessageQueueMutex);
+
+ uint32_t count = GetQueueCount();
+ if (count > 10) {
+ ALOGW("%s(), queue count: %u", __FUNCTION__, count);
+ }
+
+ if (count == 0) {
+ ALOGW("%s(), no message in queue", __FUNCTION__);
+ AL_UNLOCK(mCCCIMessageQueueMutex);
+ return UNKNOWN_ERROR;
+ }
+
+ status_t ret = NO_ERROR;
+ ALOGD("%s,start count [%d]", __FUNCTION__, count);
+ while (1) {
+ // when entering this function, the first message in queue must be a message waiting for ack
+ // so we increment index, consuming the first message in queue
+ iQRead++;
+ if (iQRead == CCCI_MAX_QUEUE_NUM) { iQRead -= CCCI_MAX_QUEUE_NUM; }
+
+ // check if empty
+ if (iQRead == iQWrite) {
+ ret = NO_ERROR;
+ break;
+ }
+
+ // update count
+ count = GetQueueCount();
+
+ // send message
+ if (pQueue[iQRead].ack_type == MESSAGE_BYPASS_ACK) { // no need ack, send directly, don't care ret value
+ ALOGV("%s(), no need ack message: 0x%x, count: %u", __FUNCTION__, pQueue[iQRead].ccci_buff.message, count);
+ ret = SendMessage(pQueue[iQRead].ccci_buff);
+ } else if (pQueue[iQRead].ack_type == MESSAGE_NEED_ACK) {
+ ALOGV("%s(), need ack message: 0x%x, count: %u", __FUNCTION__, pQueue[iQRead].ccci_buff.message, count);
+ ret = SendMessage(pQueue[iQRead].ccci_buff);
+ if (ret == NO_ERROR) { // Send CCCI message success and wait for ack
+ break;
+ }
+ } else if (pQueue[iQRead].ack_type == MESSAGE_CANCELED) { // the cancelled message, ignore it
+ ALOGD("%s(), cancel on-off-on message: 0x%x, count: %u", __FUNCTION__, pQueue[iQRead].ccci_buff.message, count);
+ ret = NO_ERROR;
+ }
+ }
+ ALOGD("%s,end left Count %d", __FUNCTION__, count);
+ AL_UNLOCK(mCCCIMessageQueueMutex);
+ return ret;
+}
+
+bool SpeechMessengerEVDO::MDReset_CheckMessageInQueue() {
+ AL_LOCK(mCCCIMessageQueueMutex);
+ uint32_t count = GetQueueCount();
+ ALOGD("%s(), queue count: %u", __FUNCTION__, count);
+
+ bool ret = true;
+ while (1) {
+ // Modem already reset.
+ // Check every CCCI message in queue.
+ // These messages that are sent before modem reset, don't send to modem.
+ // But AP side need to do related action to make AP side in the correct state.
+
+ // check if empty
+ if (iQRead == iQWrite) {
+ ALOGD("%s(), check message done", __FUNCTION__);
+ ret = true;
+ break;
+ }
+
+ // Need ack message. But modem reset, so simulate that the modem send back ack msg.
+ if (JudgeAckOfMsg(GetMessageID(pQueue[iQRead].ccci_buff)) == MESSAGE_NEED_ACK) {
+ SendMsgFailErrorHandling(pQueue[iQRead].ccci_buff);
+ }
+
+ iQRead++;
+ if (iQRead == CCCI_MAX_QUEUE_NUM) { iQRead -= CCCI_MAX_QUEUE_NUM; }
+ }
+
+ if (count != 0) {
+ ALOGE("%s(), queue is not empty!!", __FUNCTION__);
+ iQWrite = 0;
+ iQRead = 0;
+ }
+
+ AL_UNLOCK(mCCCIMessageQueueMutex);
+ return ret;
+}
+
+bool SpeechMessengerEVDO::GetMDResetFlag() {
+ ALOGD("%s(), mIsModemReset=%d", __FUNCTION__, mIsModemReset);
+ return mIsModemReset;
+}
+
+status_t SpeechMessengerEVDO::CreateReadingThread() {
+ int ret = pthread_create(&hReadThread, NULL, SpeechMessengerEVDO::EVDOReadThread, (void *)this);
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+ return NO_ERROR;
+}
+
+void *SpeechMessengerEVDO::EVDOReadThread(void *arg) {
+ pthread_detach(pthread_self());
+
+ prctl(PR_SET_NAME, (unsigned long)__FUNCTION__, 0, 0, 0);
+
+ SpeechMessengerEVDO *pCCCI = (SpeechMessengerEVDO *)arg;
+ // Adjust thread priority
+ int rtnPrio = setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+ if (0 != rtnPrio) {
+ ALOGE("[%s] failed, errno: %d, return=%d", __FUNCTION__, errno, rtnPrio);
+ } else {
+ ALOGD("%s setpriority ok, priority: %d", __FUNCTION__, ANDROID_PRIORITY_AUDIO);
+ }
+
+ // Handle CCCI Message From Modems
+ while (pCCCI->CCCIEnable) {
+ /// read message
+ ccci_buff_t ccci_buff;
+ memset((void *)&ccci_buff, 0, sizeof(ccci_buff));
+ status_t ret = pCCCI->ReadMessage(ccci_buff);
+ if (ret != NO_ERROR) {
+ ALOGD("%s(), ret(%d) != NO_ERROR", __FUNCTION__, ret);
+ sph_msleep(10);
+ continue;
+ }
+
+ /// handle message
+ uint16_t m2a_message_id = pCCCI->GetMessageID(ccci_buff);
+
+ switch (m2a_message_id) {
+ case MSG_M2A_SET_SPH_MODE_ACK: { // ack of MSG_A2M_SET_SPH_MODE
+ // Do nothing... just leave a log
+ ALOGV("--SetSpeechMode Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Speech */
+ case MSG_M2A_SPH_ON_ACK: { // ack of MSG_A2M_SPH_ON
+ phone_call_mode_t phone_call_mode = (phone_call_mode_t)pCCCI->GetMessageParam(ccci_buff);
+ if (phone_call_mode == RAT_3G324M_MODE) {
+ pCCCI->SetModemSideModemStatus(VT_STATUS_MASK);
+ } else {
+ pCCCI->SetModemSideModemStatus(SPEECH_STATUS_MASK);
+ }
+ ALOGD("--SpeechOn Ack done(0x%x)", ccci_buff.message);
+#if defined(MTK_AUDIO_GAIN_TABLE)
+ // update speech network type: CDMA, NB
+ //bit 0~3: Network; bit 4,5: Voice Band, bit 15: 0 no network support, 1: network support
+#if defined(MTK_AUDIO_GAIN_TABLE_SUPPORT_CDMA)
+ uint32_t messageNetwork = 0x8004;
+#else
+ uint32_t messageNetwork = 0x0;
+#endif
+ ALOGD("%s(), apply gain with messageNetwork = %d", __FUNCTION__, messageNetwork);
+ AudioVolumeFactory::CreateAudioVolumeController()->speechNetworkChange(messageNetwork);
+#endif
+ break;
+ }
+ case MSG_M2A_SPH_OFF_ACK: { // ack of MSG_A2M_SPH_OFF
+ if (pCCCI->GetModemSideModemStatus(VT_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(VT_STATUS_MASK);
+ } else if (pCCCI->GetModemSideModemStatus(SPEECH_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(SPEECH_STATUS_MASK);
+ } else {
+ ALOGE("--SpeechOff Ack is not paired!!");
+ }
+ property_set(PROPERTY_KEY_NW_CODEC_INFO[0], "");
+ property_set(PROPERTY_KEY_NW_CODEC_INFO[1], "");
+
+ pCCCI->mLad->Signal();
+
+ ALOGD("--SpeechOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Speech Router */
+ case MSG_M2A_SPH_ROUTER_ON_ACK: { // ack of MSG_A2M_SPH_ROUTER_ON
+ const bool pcm_route_on = pCCCI->GetMessageParam(ccci_buff) & 0x1;
+ if (pcm_route_on == true) { // pcm route on
+ pCCCI->SetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+ } else { // pcm route off
+ if (pCCCI->GetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+ } else {
+ ALOGE("--SpeechRouterOn Ack is not paired!!");
+ }
+ }
+
+ ALOGV("--SpeechRouterOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Record */
+ case MSG_M2A_PCM_REC_ON_ACK: { // ack of MSG_A2M_PCM_REC_ON
+ pCCCI->SetModemSideModemStatus(RECORD_STATUS_MASK);
+ ALOGV("--recordOn Ack done(0x%x)", ccci_buff.message);
+ //fout = fopen("/data/vendor/audiohal/audio_dump/record.bin", "wb");
+ //fout2 = fopen("/data/vendor/audiohal/audio_dump/record2.bin", "wb");
+ break;
+ }
+
+ case MSG_M2A_VM_REC_ON_ACK: { // ack of MSG_A2M_VM_REC_ON
+ pCCCI->SetModemSideModemStatus(VM_RECORD_STATUS_MASK);
+ ALOGV("--VMRecordOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_RECORD_RAW_PCM_ON_ACK: { // ack of MSG_A2M_RECORD_RAW_PCM_ON
+ pCCCI->SetModemSideModemStatus(RAW_RECORD_STATUS_MASK);
+ ALOGV("--RawRecordOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_PCM_REC_DATA_NOTIFY: { // meaning that we are recording, modem have some data
+ ASSERT(pCCCI->GetModemSideModemStatus(RECORD_STATUS_MASK) == true);
+
+ if (pCCCI->mLad->GetApSideModemStatus(RECORD_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_PCM_REC_DATA_NOTIFY(0x%x) after AP side trun off record!! Drop it.", ccci_buff.message);
+ } else {
+ SLOGV("MSG_M2A_PCM_REC_DATA_NOTIFY(0x%x), data_length: %u", ccci_buff.message, (unsigned int)(pCCCI->GetMessageLength(ccci_buff) - CCCI_SHARE_BUFF_HEADER_LEN));
+
+ AudioALSACaptureDataProviderVoice::getInstance()->provideModemRecordDataToProvider(pCCCI->GetM2AUplinkRingBuffer(ccci_buff));
+
+ if (pCCCI->mLad->GetApSideModemStatus(RECORD_STATUS_MASK) == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_PCM_REC_DATA_READ_ACK, 0, 0));
+ } else {
+ ALOGW("%s() RECORD_STATUS_MASK(%d)", __FUNCTION__, pCCCI->mLad->GetApSideModemStatus(RECORD_STATUS_MASK));
+ }
+ }
+
+ break;
+ }
+ case MSG_M2A_RAW_PCM_REC_DATA_NOTIFY: { // meaning that we are recording, modem have some data
+ ALOGV("%s() MSG_M2A_RAW_PCM_REC_DATA_NOTIFY(0x%x), data_length: %d", __FUNCTION__, ccci_buff.message, pCCCI->GetMessageLength(ccci_buff));
+ ASSERT(pCCCI->GetModemSideModemStatus(RAW_RECORD_STATUS_MASK) == true);
+
+ if (pCCCI->mLad->GetApSideModemStatus(RAW_RECORD_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_RAW_PCM_REC_DATA_NOTIFY(0x%x) after AP side trun off record!! Drop it.", ccci_buff.message);
+ } else {
+ SLOGV("MSG_M2A_RAW_PCM_REC_DATA_NOTIFY(0x%x), data_length: %u", ccci_buff.message, (unsigned int)(pCCCI->GetMessageLength(ccci_buff) - CCCI_SHARE_BUFF_HEADER_LEN));
+
+ // Phone record
+
+#ifndef TEST_NEW_RECOED_FOR_OLD_CAPTURE
+ SpeechDataProcessingHandler::getInstance()->provideModemRecordDataToProvider(pCCCI->GetM2ARawPcmRingBuffer(ccci_buff));
+#else
+ AudioALSACaptureDataProviderVoice::getInstance()->provideModemRecordDataToProvider(pCCCI->GetM2ARawPcmRingBuffer(ccci_buff));
+#endif
+
+ if (pCCCI->mLad->GetApSideModemStatus(RAW_RECORD_STATUS_MASK) == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_RAW_PCM_REC_DATA_READ_ACK, 0, 0));
+ } else {
+ ALOGV("%s() RAW_RECORD_STATUS_MASK(%d)", __FUNCTION__, pCCCI->mLad->GetApSideModemStatus(RAW_RECORD_STATUS_MASK));
+ }
+ }
+
+ break;
+ }
+
+ case MSG_M2A_VM_REC_DATA_NOTIFY: { // meaning that we are recording, modem have some data
+ ASSERT(pCCCI->GetModemSideModemStatus(VM_RECORD_STATUS_MASK) == true);
+
+ if (pCCCI->mLad->GetApSideModemStatus(VM_RECORD_STATUS_MASK) == false) {
+ ALOGD("MSG_M2A_VM_REC_DATA_NOTIFY(0x%x) after AP side trun off record!! Drop it.", ccci_buff.message);
+ } else {
+ ALOGV("MSG_M2A_VM_REC_DATA_NOTIFY(0x%x), data_length: %u", ccci_buff.message, (unsigned int)(pCCCI->GetMessageLength(ccci_buff) - CCCI_SHARE_BUFF_HEADER_LEN));
+
+ SpeechVMRecorder::getInstance()->getVmDataFromModem(pCCCI->GetM2AUplinkRingBuffer(ccci_buff));
+
+ if (pCCCI->mLad->GetApSideModemStatus(VM_RECORD_STATUS_MASK) == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_VM_REC_DATA_READ_ACK, 0, 0));
+ } else {
+ ALOGD("%s() VM_RECORD_STATUS_MASK(%d)", __FUNCTION__, pCCCI->mLad->GetApSideModemStatus(VM_RECORD_STATUS_MASK));
+ }
+ }
+
+ break;
+ }
+#ifdef SPH_VCL_SUPPORT
+ case MSG_M2A_CUST_DUMP_NOTIFY: { // meaning that we are recording, modem have some data
+ // check VCL need open
+ SpeechVoiceCustomLogger *pSpeechVoiceCustomLogger = SpeechVoiceCustomLogger::GetInstance();
+ if (pSpeechVoiceCustomLogger->GetVCLRecordStatus() == false) {
+ ALOGW("MSG_M2A_CUST_DUMP_NOTIFY(0x%x) after AP side trun off record!! Drop it.", ccci_buff.message);
+ } else {
+ ALOGD("MSG_M2A_CUST_DUMP_NOTIFY(0x%x), data_length: %d", ccci_buff.message, pCCCI->GetMessageLength(ccci_buff) - CCCI_SHARE_BUFF_HEADER_LEN);
+
+ pSpeechVoiceCustomLogger->CopyBufferToVCL(pCCCI->GetM2AUplinkRingBuffer(ccci_buff));
+
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_CUST_DUMP_READ_ACK, 0, 0));
+ }
+
+ break;
+ }
+#endif
+ case MSG_M2A_PCM_REC_OFF_ACK: { // ack of MSG_A2M_PCM_REC_OFF
+ if (pCCCI->GetModemSideModemStatus(RECORD_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(RECORD_STATUS_MASK);
+ //fclose(fout);
+ //fclose(fout2);
+ } else {
+ ALOGE("--recordOff Ack is not paired!!");
+ }
+ ALOGV("--recordOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_VM_REC_OFF_ACK: { // ack of MSG_A2M_VM_REC_OFF
+ if (pCCCI->GetModemSideModemStatus(VM_RECORD_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(VM_RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--VMRecordOff Ack is not paired!!");
+ }
+ ALOGV("--VMRecordOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_RECORD_RAW_PCM_OFF_ACK: { // ack of MSG_A2M_RECORD_RAW_PCM_OFF
+ if (pCCCI->GetModemSideModemStatus(RAW_RECORD_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(RAW_RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--RawRecordOff Ack is not paired!!");
+ }
+ ALOGV("--RawRecordOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ /* Background sound */
+ case MSG_M2A_BGSND_ON_ACK: { // ack of MSG_A2M_BGSND_ON
+ pCCCI->SetModemSideModemStatus(BGS_STATUS_MASK);
+ ALOGV("--BGSoundOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_BGSND_DATA_REQUEST: { // modem request bgs data to play
+ ASSERT(pCCCI->GetModemSideModemStatus(BGS_STATUS_MASK) == true);
+
+ BGSPlayer *pBGSPlayer = BGSPlayer::GetInstance();
+ if (pCCCI->mLad->GetApSideModemStatus(BGS_STATUS_MASK) == false) {
+ ALOGV("MSG_M2A_BGSND_DATA_REQUEST(0x%x) after AP side trun off BGS!! Drop it.", ccci_buff.message);
+ } else {
+ ALOGV("MSG_M2A_BGSND_DATA_REQUEST(0x%x), num_data_request: %d", ccci_buff.message, pCCCI->GetMessageParam(ccci_buff));
+
+ // parse size of data request
+ uint16_t num_data_request = pCCCI->GetMessageParam(ccci_buff);
+ uint32_t max_buf_length = A2M_SHARED_BUFFER_BGS_DATA_SIZE - CCCI_SHARE_BUFF_HEADER_LEN;
+ if (num_data_request > max_buf_length) { num_data_request = max_buf_length; }
+
+ // get bgs share buffer address
+ uint16_t offset = A2M_SHARED_BUFFER_BGS_DATA_BASE;
+ char *p_header_address = pCCCI->GetA2MShareBufBase() + offset;
+ char *p_data_address = p_header_address + CCCI_SHARE_BUFF_HEADER_LEN;
+
+ // fill playback data
+ uint16_t data_length = pBGSPlayer->PutDataToSpeaker(p_data_address, num_data_request);
+
+ // fill header info
+ pCCCI->SetShareBufHeader((uint16_t *)p_header_address,
+ CCCI_A2M_SHARE_BUFF_HEADER_SYNC,
+ SHARE_BUFF_DATA_TYPE_CCCI_BGS_TYPE,
+ data_length);
+
+ // send data notify to modem side
+ const uint16_t payload_length = CCCI_SHARE_BUFF_HEADER_LEN + data_length;
+ if (pCCCI->mLad->GetApSideModemStatus(BGS_STATUS_MASK) == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_BGSND_DATA_NOTIFY, payload_length, offset));
+ }
+ }
+
+ break;
+ }
+ case MSG_M2A_BGSND_OFF_ACK: { // ack of MSG_A2M_BGSND_OFF
+ if (pCCCI->GetModemSideModemStatus(BGS_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(BGS_STATUS_MASK);
+ } else {
+ ALOGE("--BGSoundOff Ack is not paired!!");
+ }
+ ALOGV("--BGSoundOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* PCM2Way */
+ case MSG_M2A_PNW_ON_ACK: { // ack of MSG_A2M_PNW_ON
+ pCCCI->SetModemSideModemStatus(P2W_STATUS_MASK);
+ ALOGV("--PCM2WayOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_PNW_UL_DATA_NOTIFY: { // Get Microphone data from Modem
+ ASSERT(pCCCI->GetModemSideModemStatus(P2W_STATUS_MASK) == true);
+
+ Record2Way *pRecord2Way = Record2Way::GetInstance();
+ if (pCCCI->mLad->GetApSideModemStatus(P2W_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_PNW_UL_DATA_NOTIFY(0x%x) after AP side trun off PCM2Way!! Drop it.", ccci_buff.message);
+ } else {
+ SLOGV("MSG_M2A_PNW_UL_DATA_NOTIFY(0x%x), data_length: %u", ccci_buff.message, (unsigned int)(pCCCI->GetMessageLength(ccci_buff) - CCCI_SHARE_BUFF_HEADER_LEN));
+ pRecord2Way->GetDataFromMicrophone(pCCCI->GetM2AUplinkRingBuffer(ccci_buff));
+ if (pCCCI->mLad->GetApSideModemStatus(P2W_STATUS_MASK) == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_PNW_UL_DATA_READ_ACK, 0, 0));
+ }
+ }
+
+#if 0 // PCM2WAY: UL -> DL Loopback
+ // Used for debug and Speech DVT
+ uint16_t size_bytes = 320;
+ char buffer[320];
+ pRecord2Way->Read(buffer, size_bytes);
+ Play2Way::GetInstance()->Write(buffer, size_bytes);
+#endif
+ break;
+ }
+ case MSG_M2A_PNW_DL_DATA_REQUEST: { // Put Data to modem and play
+ ASSERT(pCCCI->GetModemSideModemStatus(P2W_STATUS_MASK) == true);
+
+ if (pCCCI->mLad->GetApSideModemStatus(P2W_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_PNW_DL_DATA_REQUEST(0x%x) after AP side trun off PCM2Way!! Drop it.", ccci_buff.message);
+ } else {
+ SLOGV("MSG_M2A_PNW_DL_DATA_REQUEST(0x%x), num_data_request: %d", ccci_buff.message, pCCCI->GetMessageParam(ccci_buff));
+
+ // parse size of data request
+ uint16_t num_data_request = pCCCI->GetMessageParam(ccci_buff);
+ uint32_t max_buf_length = A2M_SHARED_BUFFER_BGS_DATA_SIZE - CCCI_SHARE_BUFF_HEADER_LEN;
+ if (num_data_request > max_buf_length) { num_data_request = max_buf_length; }
+
+ // get pcm2way share buffer address
+ uint16_t offset = A2M_SHARED_BUFFER_P2W_DL_DATA_BASE;
+ char *p_header_address = pCCCI->GetA2MShareBufBase() + offset;
+ char *p_data_address = p_header_address + CCCI_SHARE_BUFF_HEADER_LEN;
+
+ // fill playback data
+ Play2Way *pPlay2Way = Play2Way::GetInstance();
+ const uint16_t data_length = pPlay2Way->PutDataToSpeaker(p_data_address, num_data_request);
+
+ // fill header info
+ pCCCI->SetShareBufHeader((uint16_t *)p_header_address,
+ CCCI_A2M_SHARE_BUFF_HEADER_SYNC,
+ SHARE_BUFF_DATA_TYPE_PCM_FillSpk,
+ data_length);
+
+ // send data notify to modem side
+ const uint16_t payload_length = CCCI_SHARE_BUFF_HEADER_LEN + data_length;
+ if (pCCCI->mLad->GetApSideModemStatus(P2W_STATUS_MASK) == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_PNW_DL_DATA_NOTIFY, payload_length, offset));
+ }
+ }
+ break;
+ }
+ case MSG_M2A_PNW_OFF_ACK: { // ack of MSG_A2M_PNW_OFF
+ if (pCCCI->GetModemSideModemStatus(P2W_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(P2W_STATUS_MASK);
+ } else {
+ ALOGE("--PCM2WayOff Ack is not paired!!");
+ }
+ ALOGV("--PCM2WayOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ /* PCM Encryption */
+ case MSG_M2A_SPH_ENCRYPTION_ACK: { // ack of MSG_A2M_SPH_ENCRYPTION
+ ALOGD("--SetEncryption Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_SPH_UL_ENCRYPTION: {
+#if defined(MTK_SPEECH_ENCRYPTION_SUPPORT)
+ if ((pCCCI->GetModemSideModemStatus(SPEECH_STATUS_MASK) == true) || (pCCCI->GetModemSideModemStatus(VT_STATUS_MASK) == true)) {
+ struct timespec entertime;
+ struct timespec leavetime;
+ unsigned long long timediffns = 0;
+ entertime = GetSystemTime();
+
+ uint16_t OffsetTarget = A2M_SHARED_BUFFER_ULENC_TARGET_BASE;
+ char *BufferSource = pCCCI->mSphPCMBuf + A2M_SHARED_BUFFER_ULENC_SOURCE_BASE;
+ char *BufferTarget = pCCCI->mSphPCMBuf + OffsetTarget;
+ char *BufferDataTarget = BufferTarget + CCCI_SHARE_BUFF_HEADER_LEN;
+
+ const uint16_t ByteDataSource = pCCCI->GetM2AUplinkData(ccci_buff, BufferSource);
+ ALOGD_IF(pCCCI->mLogEnable, "+%s(), MSG_M2A_SPH_UL_ENCRYPTION(0x%x), ByteDataSource=%d", __FUNCTION__, m2a_message_id, ByteDataSource);
+ ALOGD_IF(pCCCI->mLogEnable, "+%s(), MSG_M2A_SPH_UL_ENCRYPTION(0x%x), BufferSource[0] = 0x%x, BufferSource[1]=0x%x, BufferSource[2] = 0x%x, BufferSource[3]=0x%x", __FUNCTION__, m2a_message_id, *((uint16_t *)BufferSource), *((uint16_t *)BufferSource + 1), *((uint16_t *)BufferSource + 2), *((uint16_t *)BufferSource + 3));
+
+ uint16_t ByteDataTarget = SpeechDataEncrypter::GetInstance()->Encryption(BufferDataTarget, BufferSource, ByteDataSource);
+
+ // fill header info
+ pCCCI->SetShareBufHeader((uint16_t *)BufferTarget,
+ CCCI_A2M_SHARE_BUFF_HEADER_SYNC,
+ SHARE_BUFF_DATA_TYPE_CCCI_UL_ENC,
+ ByteDataTarget);
+
+ ALOGD_IF(pCCCI->mLogEnable, "%s(), MSG_M2A_SPH_UL_ENCRYPTION(0x%x), BufferTarget = %p, ByteDataTarget = 0x%x", __FUNCTION__, m2a_message_id, BufferTarget, ByteDataTarget);
+ ALOGD_IF(pCCCI->mLogEnable, "%s(), MSG_M2A_SPH_UL_ENCRYPTION(0x%x), BufferDataTarget[0] = 0x%x, BufferDataTarget[1]=0x%x, BufferDataTarget[2] = 0x%x, BufferDataTarget[3]=0x%x", __FUNCTION__, m2a_message_id, *((uint16_t *)BufferDataTarget), *((uint16_t *)BufferDataTarget + 1), *((uint16_t *)BufferDataTarget + 2), *((uint16_t *)BufferDataTarget + 3));
+
+ // send data notify to modem side
+ uint16_t ByteMessage = CCCI_SHARE_BUFF_HEADER_LEN + ByteDataTarget;
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_SPH_UL_ENCRYPTION, ByteMessage, OffsetTarget));
+ leavetime = GetSystemTime();
+
+ timediffns = TimeDifference(leavetime, entertime);
+ ALOGD_IF(pCCCI->mLogEnable, "-%s(), MSG_M2A_SPH_UL_ENCRYPTION(0x%x), ByteDataTarget=%d, process time=%lld(ns)", __FUNCTION__, m2a_message_id, ByteDataTarget, timediffns);
+ } else {
+ ALOGD("-%s(), MSG_M2A_SPH_UL_ENCRYPTION(0x%x), not in call, skip ", __FUNCTION__, m2a_message_id);
+ }
+#else
+ ALOGD("%s(), MSG_M2A_SPH_UL_ENCRYPTION(0x%x) not support, skip", __FUNCTION__, ccci_buff.message);
+#endif
+ break;
+ }
+ case MSG_M2A_SPH_DL_DECRYPTION: {
+#if defined(MTK_SPEECH_ENCRYPTION_SUPPORT)
+ if ((pCCCI->GetModemSideModemStatus(SPEECH_STATUS_MASK) == true) || (pCCCI->GetModemSideModemStatus(VT_STATUS_MASK) == true)) {
+ struct timespec entertime;
+ struct timespec leavetime;
+ unsigned long long timediffns = 0;
+ entertime = GetSystemTime();
+ uint16_t OffsetTarget = A2M_SHARED_BUFFER_DLDEC_TARGET_BASE;
+ char *BufferSource = pCCCI->mSphPCMBuf + A2M_SHARED_BUFFER_DLDEC_SOURCE_BASE;
+ char *BufferTarget = pCCCI->mSphPCMBuf + OffsetTarget;
+ char *BufferDataTarget = BufferTarget + CCCI_SHARE_BUFF_HEADER_LEN;
+
+ const uint16_t ByteDataSource = pCCCI->GetM2AUplinkData(ccci_buff, BufferSource);
+ ALOGD_IF(pCCCI->mLogEnable, "+%s(), MSG_M2A_SPH_DL_DECRYPTION(0x%x), ByteDataSource=%d, BufferSource[0] = 0x%x, BufferSource[1]=0x%x, BufferSource[2] = 0x%x, BufferSource[3]=0x%x", __FUNCTION__, m2a_message_id, ByteDataSource, *((uint16_t *)BufferSource), *((uint16_t *)BufferSource + 1), *((uint16_t *)BufferSource + 2), *((uint16_t *)BufferSource + 3));
+
+ uint16_t ByteDataTarget = SpeechDataEncrypter::GetInstance()->Decryption(BufferDataTarget, BufferSource, ByteDataSource);
+
+ // fill header info
+ pCCCI->SetShareBufHeader((uint16_t *)BufferTarget,
+ CCCI_A2M_SHARE_BUFF_HEADER_SYNC,
+ SHARE_BUFF_DATA_TYPE_CCCI_DL_DEC,
+ ByteDataTarget);
+
+ ALOGD_IF(pCCCI->mLogEnable, "%s(), MSG_M2A_SPH_DL_DECRYPTION(0x%x), ByteDataSource=%d, BufferSource[0] = 0x%x, BufferSource[1]=0x%x, BufferSource[2] = 0x%x, BufferSource[3]=0x%x", __FUNCTION__, m2a_message_id, ByteDataSource, *((uint16_t *)BufferSource), *((uint16_t *)BufferSource + 1), *((uint16_t *)BufferSource + 2), *((uint16_t *)BufferSource + 3));
+ // send data notify to modem side
+ uint16_t ByteMessage = CCCI_SHARE_BUFF_HEADER_LEN + ByteDataTarget;
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_SPH_DL_DECRYPTION, ByteMessage, OffsetTarget));
+ leavetime = GetSystemTime();
+
+ timediffns = TimeDifference(leavetime, entertime);
+ ALOGD_IF(pCCCI->mLogEnable, "-%s(), MSG_M2A_SPH_DL_DECRYPTION(0x%x), ByteDataTarget=%d, process time=%lld(ns)", __FUNCTION__, m2a_message_id, ByteDataTarget, timediffns);
+ } else {
+ ALOGD("-%s(), MSG_M2A_SPH_DL_DECRYPTION(0x%x), not in call, skip ", __FUNCTION__, m2a_message_id);
+ }
+#else
+ ALOGD("%s(), MSG_M2A_SPH_DL_DECRYPTION(0x%x) not support, skip", __FUNCTION__, ccci_buff.message);
+#endif
+ break;
+ }
+
+ /* TTY */
+ case MSG_M2A_CTM_ON_ACK: { // ack of MSG_A2M_CTM_ON
+ pCCCI->SetModemSideModemStatus(TTY_STATUS_MASK);
+ ALOGV("--TtyCtmOn Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_CTM_DEBUG_DATA_NOTIFY: {
+ if (pCCCI->mLad->GetApSideModemStatus(TTY_STATUS_MASK) == false) {
+ ALOGW("MSG_M2A_CTM_DEBUG_DATA_NOTIFY(0x%x) after AP side trun off TTY!! Drop it.", ccci_buff.message);
+ } else {
+ SLOGV("MSG_M2A_CTM_DEBUG_DATA_NOTIFY(0x%x), data_length: %u", ccci_buff.message, (unsigned int)(pCCCI->GetMessageLength(ccci_buff) - CCCI_SHARE_BUFF_HEADER_LEN));
+ SpeechVMRecorder *pSpeechVMRecorder = SpeechVMRecorder::getInstance();
+
+ const uint16_t data_type = pCCCI->GetM2AShareBufDataType(ccci_buff);
+ if (data_type == SHARE_BUFF_DATA_TYPE_CCCI_CTM_UL_IN) {
+ pSpeechVMRecorder->getCtmDebugDataFromModem(pCCCI->GetM2AUplinkRingBuffer(ccci_buff), pSpeechVMRecorder->pCtmDumpFileUlIn);
+ } else if (data_type == SHARE_BUFF_DATA_TYPE_CCCI_CTM_DL_IN) {
+ pSpeechVMRecorder->getCtmDebugDataFromModem(pCCCI->GetM2AUplinkRingBuffer(ccci_buff), pSpeechVMRecorder->pCtmDumpFileDlIn);
+ } else if (data_type == SHARE_BUFF_DATA_TYPE_CCCI_CTM_UL_OUT) {
+ pSpeechVMRecorder->getCtmDebugDataFromModem(pCCCI->GetM2AUplinkRingBuffer(ccci_buff), pSpeechVMRecorder->pCtmDumpFileUlOut);
+ } else if (data_type == SHARE_BUFF_DATA_TYPE_CCCI_CTM_DL_OUT) {
+ pSpeechVMRecorder->getCtmDebugDataFromModem(pCCCI->GetM2AUplinkRingBuffer(ccci_buff), pSpeechVMRecorder->pCtmDumpFileDlOut);
+ } else {
+ ALOGW("%s(), data_type(0x%x) error", __FUNCTION__, data_type);
+ ASSERT(0);
+ }
+
+ if (pCCCI->mLad->GetApSideModemStatus(TTY_STATUS_MASK) == true) {
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_CTM_DEBUG_DATA_READ_ACK, 0, 0));
+ }
+ }
+ break;
+ }
+ case MSG_M2A_CTM_OFF_ACK: { // ack of MSG_A2M_CTM_OFF
+ if (pCCCI->GetModemSideModemStatus(TTY_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(TTY_STATUS_MASK);
+ } else {
+ ALOGE("--TtyCtmOff Ack is not paired!!");
+ }
+ ALOGV("--TtyCtmOff Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Loopback */
+ case MSG_M2A_SET_ACOUSTIC_LOOPBACK_ACK: { // ack of MSG_A2M_SET_ACOUSTIC_LOOPBACK
+ const bool loopback_on = pCCCI->GetMessageParam(ccci_buff) & 0x1;
+ if (loopback_on == true) { // loopback on
+ pCCCI->SetModemSideModemStatus(LOOPBACK_STATUS_MASK);
+ } else { // loopback off
+ if (pCCCI->GetModemSideModemStatus(LOOPBACK_STATUS_MASK) == true) {
+ pCCCI->ResetModemSideModemStatus(LOOPBACK_STATUS_MASK);
+ } else {
+ ALOGE("--SetAcousticLoopback Ack is not paired!!");
+ }
+ }
+
+ pCCCI->mLad->Signal();
+
+ ALOGV("--SetAcousticLoopback Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Speech Enhancement parameters */
+ case MSG_M2A_EM_NB_ACK: { // ack of MSG_A2M_EM_NB
+ pCCCI->AddSpeechParamAckCount(NB_SPEECH_PARAM);
+ pCCCI->A2MBufUnLock();
+ ALOGV("--SetNBSpeechParameters Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_EM_DMNR_ACK: { // ack of MSG_A2M_EM_DMNR
+ pCCCI->AddSpeechParamAckCount(DMNR_SPEECH_PARAM);
+ pCCCI->A2MBufUnLock();
+ ALOGV("--SetDualMicSpeechParameters Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_EM_MAGICON_ACK: { // ack of MSG_A2M_EM_MAGICON
+ pCCCI->AddSpeechParamAckCount(MAGICON_SPEECH_PARAM);
+ pCCCI->A2MBufUnLock();
+ ALOGV("--SetMagiConSpeechParameters Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_EM_HAC_ACK: { // ack of MSG_A2M_EM_HAC
+ pCCCI->AddSpeechParamAckCount(HAC_SPEECH_PARAM);
+ pCCCI->A2MBufUnLock();
+ ALOGV("--SetHACSpeechParameters Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ case MSG_M2A_EM_WB_ACK: { // ack of MSG_A2M_EM_WB
+ pCCCI->AddSpeechParamAckCount(WB_SPEECH_PARAM);
+ pCCCI->A2MBufUnLock();
+ ALOGV("--SetWBSpeechParameters Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ case MSG_M2A_EM_DYNAMIC_SPH_ACK: { // ack of MSG_A2M_EM_DYNAMIC_SPH
+ switch (ccci_buff.message & 0xFFFF) {
+ case 0xAA01:
+ pCCCI->AddSpeechParamAckCount(DYNAMIC_SPH_PARAM);
+ break;
+ case 0xAA03:
+ pCCCI->AddSpeechParamAckCount(DMNR_SPEECH_PARAM);
+ break;
+ case 0:
+ pCCCI->AddSpeechParamAckCount(DYNAMIC_SPH_PARAM);//some MD ack with 0
+ break;
+ }
+ pCCCI->A2MBufUnLock();
+ ALOGV("--SetDynamicSpeechParameters Ack done(0x%x)", ccci_buff.message);
+#ifdef USE_CCCI_SHARE_BUFFER
+ //release buffer when ack received
+ int datalength = pCCCI->GetMessageLength(pCCCI->pQueue[pCCCI->iQRead].ccci_buff);
+ pCCCI->AdvanceA2MRawParaRingBuffer(datalength);
+#endif
+ break;
+ }
+ case MSG_M2A_SPH_ENH_CORE_ACK: { // ack of MSG_A2M_SPH_ENH_CORE
+ // Do nothing... just leave a log
+ ALOGD("--MSG_M2A_SPH_ENH_CORE_ACK Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ /* Modem Reset */
+ case MSG_M2A_EM_DATA_REQUEST: { // Modem reset. Requset for all EM data(NB/DMNR/WB)
+ ALOGW("..[MD Reset Notify(MSG_M2A_EM_DATA_REQUEST: 0x%x)]..mCreatingSphThreadFlag =%d", ccci_buff.message, pCCCI->mCreatingSphThreadFlag);
+
+ // Clean mWaitAckMessageID to avoid the queue receiving the wrong ack
+ pCCCI->mWaitAckMessageID = 0;
+
+ // close analog downlink path when modem reset during phone call
+ if (pCCCI->mLad->GetApSideModemStatus(SPEECH_STATUS_MASK) == true ||
+ pCCCI->mLad->GetApSideModemStatus(VT_STATUS_MASK) == true) {
+ //AudioResourceManager::getInstance()->StopOutputDevice();
+ }
+ pCCCI->mIsModemResetDuringPhoneCall = false;
+ pCCCI->mIsModemReset = false;
+ pCCCI->mIsModemEPOF = false;
+
+ // Create Send Sph Para Thread
+#if 0
+ if (pCCCI->mCreatingSphThreadFlag == false) {
+ pCCCI->mCreatingSphThreadFlag = true;
+ pCCCI->CreateSendSphParaThread();
+ } else {
+ pCCCI->mWaitSphThreadFlag = true;
+ while (pCCCI->mCreatingSphThreadFlag == true) {
+ sph_msleep(5);
+ }
+ ALOGD("Finaly, mCreatingSphThreadFlag==%d", pCCCI->mCreatingSphThreadFlag);
+ pCCCI->mCreatingSphThreadFlag = true;
+ pCCCI->mWaitSphThreadFlag = false;
+ pCCCI->CreateSendSphParaThread();
+ }
+#endif
+ // Check the first message in queue. If need ack, take action.
+ // Modem reset, flush all CCCI queue first. Don't care for the CCCI queue.
+ pCCCI->ResetSpeechParamAckCount();
+ pCCCI->MDReset_CheckMessageInQueue();
+ break;
+ }
+ case MSG_M2A_VIBSPK_PARAMETER_ACK: { // ack of MSG_M2A_VIBSPK_PARAMETER
+ pCCCI->A2MBufUnLock();
+ ALOGV("--SetVibSpkParam Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+
+ case MSG_M2A_SMARTPA_PARAMETER_ACK: {
+ pCCCI->A2MBufUnLock();
+ ALOGV("--SetSmartpaParam Ack done(0x%x)", ccci_buff.message);
+ break;
+ }
+ /* Modem EPOF */
+ case MSG_M2A_EPOF_NOTIFY: {
+ ALOGW("..[MD EPOF Notify(MSG_M2A_EPOF_NOTIFY: 0x%x)]..", ccci_buff.message);
+
+ // Check the first message in queue. If need ack, take action.
+
+ // Modem reset, flush all CCCI queue first. Don't care for the CCCI queue.
+ pCCCI->ResetSpeechParamAckCount();
+ pCCCI->MDReset_CheckMessageInQueue();
+
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_EPOF_ACK, 0, 0));
+ pCCCI->mIsModemEPOF = true;
+
+ break;
+ }
+
+ case MSG_M2A_NW_CODEC_INFO_NOTIFY: {
+ ALOGV("--MSG_M2A_NW_CODEC_INFO_NOTIFY (0x%x)", ccci_buff.message);
+ pCCCI->SetNWCodecInfo(ccci_buff);
+ pCCCI->SendMessage(pCCCI->InitCcciMailbox(MSG_A2M_NW_CODEC_INFO_READ_ACK, 0, 0));
+ break;
+ }
+
+ default: {
+ //TINA REMOVE TEMP
+ ALOGD("Read modem message(0x%x), don't care. (or no such message)", ccci_buff.message);
+ sph_msleep(10);
+ break;
+ }
+ }
+
+ /// If AP side is waiting for this ack, then consume message queue
+ uint16_t a2m_message_id_of_m2a_ack = m2a_message_id & 0x7FFF; // 0xAF** -> 0x2F**
+ if (pCCCI->JudgeAckOfMsg(a2m_message_id_of_m2a_ack) == MESSAGE_NEED_ACK) {
+ if (a2m_message_id_of_m2a_ack == pCCCI->mWaitAckMessageID) {
+ pCCCI->mWaitAckMessageID = 0; // reset
+ pCCCI->ConsumeMessageInQueue();
+ } else {
+ ALOGD("Message(0x%x) might double ack!! The current mWaitAckMessageID is 0x%x", ccci_buff.message, pCCCI->mWaitAckMessageID);
+ }
+ }
+ }
+ pthread_exit(NULL);
+ return 0;
+}
+
+status_t SpeechMessengerEVDO::CreateSendSphParaThread() {
+
+ // ALOGD("%s, mCreatingSphThreadFlag=%d", __FUNCTION__, mCreatingSphThreadFlag);
+ // if (mCreatingSphThreadFlag == false)
+ // {
+ // mCreatingSphThreadFlag = true;
+ int ret = pthread_create(&hSendSphThread, NULL, SpeechMessengerEVDO::SendSphParaThread, (void *)this);
+
+ if (ret != 0) {
+ ALOGE("%s() create thread fail!!", __FUNCTION__);
+ // mCreatingSphThreadFlag = false;
+ return UNKNOWN_ERROR;
+ }
+ // }
+ return NO_ERROR;
+}
+
+void *SpeechMessengerEVDO::SendSphParaThread(void *arg) {
+ pthread_detach(pthread_self());
+
+ prctl(PR_SET_NAME, (unsigned long)__FUNCTION__, 0, 0, 0);
+ // Adjust thread priority
+ int rtnPrio = setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+ if (0 != rtnPrio) {
+ ALOGE("[%s] failed, errno: %d, return=%d", __FUNCTION__, errno, rtnPrio);
+ } else {
+ ALOGD("%s setpriority ok, priority: %d", __FUNCTION__, ANDROID_PRIORITY_AUDIO);
+ }
+ ALOGD("%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+
+ SpeechMessengerEVDO *pCCCI = (SpeechMessengerEVDO *)arg;
+
+ // Check the first message in queue. If need ack, take action.
+ // Modem reset, flush all CCCI queue first. Don't care for the CCCI queue.
+ pCCCI->MDReset_CheckMessageInQueue();
+
+ // Get SpeechParamLock
+ if (pCCCI->SpeechParamLock() == false) {
+ ALOGE("%s() fail to get SpeechParamLock!!", __FUNCTION__);
+ return 0;
+ }
+ if (pCCCI->mWaitSphThreadFlag == true) {
+ pCCCI->SpeechParamUnLock();
+ pCCCI->mCreatingSphThreadFlag = false;
+ pthread_exit(NULL);
+ ALOGD("%s(), another MD reset is waiting for speech parameter thread", __FUNCTION__);
+ return 0;
+ }
+
+ // Send speech parameters to modem side
+ pCCCI->ResetSpeechParamAckCount();
+ pCCCI->mLad->SetAllSpeechEnhancementInfoToModem();
+
+ // Release SpeechParamLock
+ pCCCI->SpeechParamUnLock();
+
+ pCCCI->mCreatingSphThreadFlag = false;
+
+ pthread_exit(NULL);
+ return 0;
+}
+
+bool SpeechMessengerEVDO::A2MBufLock() {
+ const uint32_t kA2MBufLockTimeout = 3000; // 3 sec
+
+ int rc = AL_LOCK_MS(mA2MShareBufMutex, kA2MBufLockTimeout);
+ ALOGD("%s()", __FUNCTION__);
+ if (rc != 0) {
+ ALOGE("%s(), Cannot get Lock!! Timeout : %u msec", __FUNCTION__, kA2MBufLockTimeout);
+ return false;
+ }
+ return true;
+}
+
+void SpeechMessengerEVDO::A2MBufUnLock() {
+ AL_UNLOCK(mA2MShareBufMutex);
+ ALOGD("%s()", __FUNCTION__);
+}
+
+bool SpeechMessengerEVDO::SpeechParamLock() {
+ const uint32_t kSphParamLockTimeout = 10000; // 10 sec
+
+ ALOGD("%s()", __FUNCTION__);
+ int rc = AL_LOCK_MS(mSetSpeechParamMutex, kSphParamLockTimeout);
+ if (rc != 0) {
+ ALOGE("%s(), Cannot get Lock!! Timeout : %u msec", __FUNCTION__, kSphParamLockTimeout);
+ return false;
+ }
+ return true;
+}
+
+void SpeechMessengerEVDO::SpeechParamUnLock() {
+ ALOGD("%s()", __FUNCTION__);
+ AL_UNLOCK(mSetSpeechParamMutex);
+}
+
+void SpeechMessengerEVDO::ResetSpeechParamAckCount() {
+ memset(&mSpeechParamAckCount, 0, sizeof(mSpeechParamAckCount));
+ ALOGD("%s(), NB(%u)/DMNR(%u)/WB(%u)/MAGICON(%u)/HAC(%u)/DynamicSPH(%u)", __FUNCTION__,
+ mSpeechParamAckCount[NB_SPEECH_PARAM],
+ mSpeechParamAckCount[DMNR_SPEECH_PARAM],
+ mSpeechParamAckCount[WB_SPEECH_PARAM],
+ mSpeechParamAckCount[MAGICON_SPEECH_PARAM],
+ mSpeechParamAckCount[HAC_SPEECH_PARAM],
+ mSpeechParamAckCount[DYNAMIC_SPH_PARAM]);
+}
+
+void SpeechMessengerEVDO::AddSpeechParamAckCount(speech_param_ack_t type) {
+ if (type >= NUM_SPEECH_PARAM_ACK_TYPE || type < 0) {
+ ALOGE("%s(), no such type: %d", __FUNCTION__, type);
+ } else {
+ if (mSpeechParamAckCount[type] < 0xFFFFFFFF) { //prevent overflow
+ mSpeechParamAckCount[type]++;
+ }
+ ALOGD("%s()(%d), NB(%u)/DMNR(%u)/WB(%u)/MAGICON(%u)/HAC(%u)/DynamicSPH(%u)", __FUNCTION__, type,
+ mSpeechParamAckCount[NB_SPEECH_PARAM],
+ mSpeechParamAckCount[DMNR_SPEECH_PARAM],
+ mSpeechParamAckCount[WB_SPEECH_PARAM],
+ mSpeechParamAckCount[MAGICON_SPEECH_PARAM],
+ mSpeechParamAckCount[HAC_SPEECH_PARAM],
+ mSpeechParamAckCount[DYNAMIC_SPH_PARAM]);
+ }
+}
+
+bool SpeechMessengerEVDO::CheckSpeechParamAckAllArrival() {
+ bool ret = true;
+
+ // Get SpeechParamLock
+ if (SpeechParamLock() == false) {
+ ALOGE("%s() fail to get SpeechParamLock!!", __FUNCTION__);
+ return false;
+ }
+
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ if (mSpeechParamAckCount[DYNAMIC_SPH_PARAM] == 0) { ret = false; }
+#else
+
+ if (mSpeechParamAckCount[NB_SPEECH_PARAM] == 0) { ret = false; }
+
+ if (AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport() >= 2) {
+ if (mSpeechParamAckCount[DMNR_SPEECH_PARAM] == 0) { ret = false; }
+
+#if defined(MTK_MAGICONFERENCE_SUPPORT) || defined(MTK_INCALL_HANDSFREE_DMNR)
+ if (mSpeechParamAckCount[MAGICON_SPEECH_PARAM] == 0) { ret = false; }
+#endif
+ }
+
+#if defined(MTK_WB_SPEECH_SUPPORT)
+ if (mSpeechParamAckCount[WB_SPEECH_PARAM] == 0) { ret = false; }
+#endif
+
+#if defined(MTK_HAC_SUPPORT)
+ if (mSpeechParamAckCount[HAC_SPEECH_PARAM] == 0) { ret = false; }
+#endif
+#endif
+
+ if (ret == true) {
+ ALOGD("%s() Pass", __FUNCTION__);
+ } else {
+ ALOGE("%s() Fail, NB(%u)/DMNR(%u)/WB(%u)/MAGICON(%u)/HAC(%u)/DynamicSPH(%u)", __FUNCTION__,
+ mSpeechParamAckCount[NB_SPEECH_PARAM],
+ mSpeechParamAckCount[DMNR_SPEECH_PARAM],
+ mSpeechParamAckCount[WB_SPEECH_PARAM],
+ mSpeechParamAckCount[MAGICON_SPEECH_PARAM],
+ mSpeechParamAckCount[HAC_SPEECH_PARAM],
+ mSpeechParamAckCount[DYNAMIC_SPH_PARAM]);
+
+ // Send speech parameters to modem side again
+ mLad->SetAllSpeechEnhancementInfoToModem();
+ }
+
+ // Release SpeechParamLock
+ SpeechParamUnLock();
+
+ return ret;
+}
+
+/** Do error handling here */
+void SpeechMessengerEVDO::SendMsgFailErrorHandling(const ccci_buff_t &ccci_buff) {
+ ALOGE("%s(), message: 0x%x", __FUNCTION__, ccci_buff.message);
+ switch (GetMessageID(ccci_buff)) {
+ case MSG_A2M_SET_SPH_MODE: {
+ // Do nothing...
+ break;
+ }
+ case MSG_A2M_SPH_ON: {
+ phone_call_mode_t phone_call_mode = (phone_call_mode_t)GetMessageParam(ccci_buff);
+ if (phone_call_mode == RAT_3G324M_MODE) {
+ SetModemSideModemStatus(VT_STATUS_MASK);
+ } else {
+ SetModemSideModemStatus(SPEECH_STATUS_MASK);
+ }
+
+ //mLad->Signal();
+
+ break;
+ }
+ case MSG_A2M_SPH_OFF: {
+ if (GetModemSideModemStatus(VT_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(VT_STATUS_MASK);
+ } else if (GetModemSideModemStatus(SPEECH_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(SPEECH_STATUS_MASK);
+ } else {
+ ALOGE("--SpeechOff Ack is not paired!!");
+ }
+
+ mLad->Signal();
+
+ break;
+ }
+ case MSG_A2M_SPH_ROUTER_ON: {
+ const bool pcm_route_on = GetMessageParam(ccci_buff) & 0x1;
+ if (pcm_route_on == true) { // pcm route on
+ SetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+ } else { // pcm route off
+ if (GetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+ } else {
+ ALOGE("--SpeechRouterOn Ack is not paired!!");
+ }
+ }
+
+ break;
+ }
+ case MSG_A2M_PCM_REC_ON: {
+ SetModemSideModemStatus(RECORD_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_PCM_REC_OFF: {
+ if (GetModemSideModemStatus(RECORD_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--recordOff Ack is not paired!!");
+ }
+ break;
+ }
+ case MSG_A2M_RECORD_RAW_PCM_ON: {
+ SetModemSideModemStatus(RAW_RECORD_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_RECORD_RAW_PCM_OFF: {
+ if (GetModemSideModemStatus(RAW_RECORD_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(RAW_RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--RawRecordOff Ack is not paired!!");
+ }
+ break;
+ }
+ case MSG_A2M_VM_REC_ON: {
+ SetModemSideModemStatus(VM_RECORD_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_VM_REC_OFF: {
+ if (GetModemSideModemStatus(VM_RECORD_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(VM_RECORD_STATUS_MASK);
+ } else {
+ ALOGE("--VMRecordOff Ack is not paired!!");
+ }
+ break;
+ }
+ case MSG_A2M_BGSND_ON: {
+ SetModemSideModemStatus(BGS_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_BGSND_OFF: {
+ if (GetModemSideModemStatus(BGS_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(BGS_STATUS_MASK);
+ } else {
+ ALOGE("--BGSoundOff Ack is not paired!!");
+ }
+ break;
+ }
+ case MSG_A2M_PNW_ON: {
+ SetModemSideModemStatus(P2W_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_PNW_OFF: {
+ if (GetModemSideModemStatus(P2W_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(P2W_STATUS_MASK);
+ } else {
+ ALOGE("--PCM2WayOff Ack is not paired!!");
+ }
+ break;
+ }
+ case MSG_A2M_CTM_ON: {
+ SetModemSideModemStatus(TTY_STATUS_MASK);
+ break;
+ }
+ case MSG_A2M_CTM_OFF: {
+ if (GetModemSideModemStatus(TTY_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(TTY_STATUS_MASK);
+ } else {
+ ALOGE("--TtyCtmOff Ack is not paired!!");
+ }
+ break;
+ }
+ case MSG_A2M_SET_ACOUSTIC_LOOPBACK: {
+ const bool loopback_on = GetMessageParam(ccci_buff) & 0x1;
+ if (loopback_on == true) { // loopback on
+ SetModemSideModemStatus(LOOPBACK_STATUS_MASK);
+ } else { // loopback off
+ if (GetModemSideModemStatus(LOOPBACK_STATUS_MASK) == true) {
+ ResetModemSideModemStatus(LOOPBACK_STATUS_MASK);
+ } else {
+ ALOGE("--SetAcousticLoopback Ack is not paired!!");
+ }
+ }
+
+ mLad->Signal();
+ break;
+ }
+ case MSG_A2M_EM_NB:
+ case MSG_A2M_EM_WB:
+ case MSG_A2M_EM_DMNR:
+ case MSG_A2M_EM_MAGICON:
+ case MSG_A2M_EM_HAC:
+ case MSG_A2M_VIBSPK_PARAMETER:
+ case MSG_A2M_SMARTPA_PARAMETER:
+#ifndef USE_CCCI_SHARE_BUFFER
+ case MSG_A2M_EM_DYNAMIC_SPH:
+#endif
+ {
+ A2MBufUnLock();
+ break;
+ }
+#ifdef USE_CCCI_SHARE_BUFFER
+ case MSG_A2M_EM_DYNAMIC_SPH: {
+ // clear CCCI parameter Buffer
+ InitA2MRawParaRingBuffer();
+ break;
+ }
+#endif
+ default: {
+ ALOGW("%s(), message: 0x%x, ack don't care", __FUNCTION__, ccci_buff.message);
+ }
+ }
+}
+
+uint16_t SpeechMessengerEVDO::GetPcmFreq(const uint16_t Idx_Freq) {
+ uint16_t Pcm_Freq = 8000;
+
+ switch (Idx_Freq) {
+ case 0:
+ Pcm_Freq = 8000;
+ break;
+
+ case 1:
+ Pcm_Freq = 16000;
+ break;
+
+ case 2:
+ Pcm_Freq = 32000;
+ break;
+
+ case 3:
+ Pcm_Freq = 48000;
+ break;
+
+ case 0xf:
+ Pcm_Freq = 8000;
+ break;
+
+ default:
+ Pcm_Freq = 8000;
+ break;
+
+ }
+ return Pcm_Freq;
+}
+
+RingBuf SpeechMessengerEVDO::GetM2AUplinkRingBuffer(const ccci_buff_t &ccci_buff) {
+ // check MD side data msg format
+ CheckOffsetAndLength(ccci_buff);
+
+ RingBuf ul_ring_buf;
+
+ ul_ring_buf.bufLen = mM2AShareBufLen;
+ ul_ring_buf.pBufBase = mM2AShareBufBase;
+ ul_ring_buf.pBufEnd = ul_ring_buf.pBufBase + ul_ring_buf.bufLen;
+
+ ul_ring_buf.pRead = ul_ring_buf.pBufBase + GetMessageOffset(ccci_buff);
+ if (ul_ring_buf.pRead >= mM2AShareBufEnd) { ul_ring_buf.pRead -= ul_ring_buf.bufLen; }
+
+ // share buffer header
+ char *p_sync_word = ul_ring_buf.pRead + 0; // 0 * size(unsigned short)
+ char *p_data_type = ul_ring_buf.pRead + 2; // 1 * size(unsigned short)
+ char *p_data_len = ul_ring_buf.pRead + 4; // 2 * size(unsigned short)
+
+ if (p_data_type >= mM2AShareBufEnd) { p_data_type -= ul_ring_buf.bufLen; }
+ if (p_data_len >= mM2AShareBufEnd) { p_data_len -= ul_ring_buf.bufLen; }
+
+ if (*(uint16_t *)p_sync_word != CCCI_M2A_SHARE_BUFF_HEADER_SYNC) {
+ char TotalIdxDump = 10, IdxDump;
+ char SphDumpStr[SPH_DUMP_STR_SIZE] = {0};
+
+ snprintf(SphDumpStr, SPH_DUMP_STR_SIZE, "ring_buf[pBase 0x%p, pEnd 0x%p, Len 0x%x, pRead 0x%p, offset 0x%x]= ", ul_ring_buf.pBufBase, mM2AShareBufEnd, mM2AShareBufLen, ul_ring_buf.pRead, ccci_buff.message);
+ for (IdxDump = 0; IdxDump < TotalIdxDump; IdxDump++) {
+ char SphDumpTemp[100];
+ snprintf(SphDumpTemp, 100, "[%d, 0x%p]0x%x, ", IdxDump, ul_ring_buf.pRead + IdxDump, *((uint16_t *)ul_ring_buf.pRead + IdxDump));
+ audio_strncat(SphDumpStr, SphDumpTemp, SPH_DUMP_STR_SIZE);
+ }
+ if (IdxDump != 0) {
+ ALOGD("%s(), offset(0x%x), %s", __FUNCTION__, GetMessageOffset(ccci_buff), SphDumpStr);
+ }
+ ALOGD("%s(), message = 0x%x, *p_sync_word(0x%x), *p_data_type(0x%x), *p_data_len(0x%x)",
+ __FUNCTION__, ccci_buff.message, *(uint16_t *)p_sync_word, *(uint16_t *)p_data_type, *(uint16_t *)p_data_len);
+ }
+ ASSERT(*(uint16_t *)p_sync_word == CCCI_M2A_SHARE_BUFF_HEADER_SYNC);
+
+ ul_ring_buf.pRead += CCCI_SHARE_BUFF_HEADER_LEN;
+ if (ul_ring_buf.pRead >= mM2AShareBufEnd) { ul_ring_buf.pRead -= ul_ring_buf.bufLen; }
+
+ ul_ring_buf.pWrite = ul_ring_buf.pRead + (*(uint16_t *)p_data_len);
+ if (ul_ring_buf.pWrite >= mM2AShareBufEnd) { ul_ring_buf.pWrite -= ul_ring_buf.bufLen; }
+
+#if 0
+ uint16_t count = *(uint16_t *)p_data_len;
+ if (ul_ring_buf.pRead <= ul_ring_buf.pWrite) {
+ fwrite((void *)ul_ring_buf.pRead, sizeof(char), count, fout2);
+ } else {
+ char *end = ul_ring_buf.pBufBase + ul_ring_buf.bufLen;
+ int r2e = end - ul_ring_buf.pRead;
+ if (count <= r2e) {
+ fwrite((void *)ul_ring_buf.pRead, sizeof(char), count, fout2);
+ } else {
+ fwrite((void *)ul_ring_buf.pRead, sizeof(char), r2e, fout2);
+ fwrite((void *)ul_ring_buf.pBufBase, sizeof(char), count - r2e, fout2);
+ }
+ }
+#endif
+
+ return ul_ring_buf;
+}
+
+uint16_t SpeechMessengerEVDO::GetM2AUplinkData(const ccci_buff_t &ccci_buff, char *TargetBuf) {
+ char hdrPcmBuf[CCCI_SHARE_BUFF_HEADER_LEN] = {0};
+
+ // check MD side data msg format
+ CheckOffsetAndLength(ccci_buff);
+
+ RingBuf ul_ring_buf;
+
+ ul_ring_buf.bufLen = mM2AShareBufLen;
+ ul_ring_buf.pBufBase = mM2AShareBufBase;
+
+ ul_ring_buf.pRead = ul_ring_buf.pBufBase + GetMessageOffset(ccci_buff);
+ if (ul_ring_buf.pRead >= mM2AShareBufEnd) { ul_ring_buf.pRead -= ul_ring_buf.bufLen; }
+
+ //copy header 6 first
+ if ((ul_ring_buf.pRead + CCCI_SHARE_BUFF_HEADER_LEN) >= mM2AShareBufEnd) {
+ uint16_t byteBufEnd = mM2AShareBufEnd - ul_ring_buf.pRead;
+ memcpy(hdrPcmBuf, ul_ring_buf.pRead, byteBufEnd);
+ memcpy(hdrPcmBuf + byteBufEnd, mM2AShareBufBase, CCCI_SHARE_BUFF_HEADER_LEN - byteBufEnd);
+ ul_ring_buf.pRead = mM2AShareBufBase + CCCI_SHARE_BUFF_HEADER_LEN - byteBufEnd;
+ } else {
+ memcpy(hdrPcmBuf, (char *)ul_ring_buf.pRead, CCCI_SHARE_BUFF_HEADER_LEN);
+ ul_ring_buf.pRead = ul_ring_buf.pRead + CCCI_SHARE_BUFF_HEADER_LEN;
+ }
+ // share buffer header
+ char *p_sync_word = hdrPcmBuf + 0; // size(unsigned short)
+ char *p_data_type = hdrPcmBuf + 2; // size(unsigned short)
+ char *p_data_len = hdrPcmBuf + 4; // size(unsigned short)
+ uint16_t ByteData = *(uint16_t *)p_data_len;
+ if (*(uint16_t *)p_sync_word != CCCI_M2A_SHARE_BUFF_HEADER_SYNC) {
+ char TotalIdxDump = 10, IdxDump;
+ char SphDumpStr[SPH_DUMP_STR_SIZE] = {0};
+
+ snprintf(SphDumpStr, SPH_DUMP_STR_SIZE, "share_buf[pBase 0x%p, pEnd 0x%p, Len 0x%x, pRead 0x%p, offset 0x%x]= ", mM2AShareBufBase, mM2AShareBufEnd, mM2AShareBufLen, ul_ring_buf.pRead, ccci_buff.message);
+ for (IdxDump = 0; IdxDump < TotalIdxDump; IdxDump++) {
+ char SphDumpTemp[100];
+ snprintf(SphDumpTemp, 100, "[%d, 0x%p]0x%x, ", IdxDump, ul_ring_buf.pRead + IdxDump, *((uint16_t *)ul_ring_buf.pRead + IdxDump));
+ audio_strncat(SphDumpStr, SphDumpTemp, SPH_DUMP_STR_SIZE);
+ }
+ if (IdxDump != 0) {
+ ALOGD("%s(), offset(0x%x), %s", __FUNCTION__, GetMessageOffset(ccci_buff), SphDumpStr);
+ }
+ ALOGD("%s(), message = 0x%x, *p_sync_word(0x%x), *p_data_type(0x%x), *p_data_len(0x%x)",
+ __FUNCTION__, ccci_buff.message, *(uint16_t *)p_sync_word, *(uint16_t *)p_data_type, *(uint16_t *)p_data_len);
+ }
+ ASSERT(*(uint16_t *)p_sync_word == CCCI_M2A_SHARE_BUFF_HEADER_SYNC);
+ //copy data
+ if ((ul_ring_buf.pRead + ByteData) >= mM2AShareBufEnd) {
+ uint16_t byteBufEnd = mM2AShareBufEnd - ul_ring_buf.pRead;
+ memcpy(TargetBuf, ul_ring_buf.pRead, byteBufEnd);
+ memcpy(TargetBuf + byteBufEnd, mM2AShareBufBase, ByteData - byteBufEnd);
+ } else {
+ memcpy(TargetBuf, (char *)ul_ring_buf.pRead, ByteData);
+ }
+ ALOGV("-%s(), TargetBuf(0x%p), ByteData(0x%x)", __FUNCTION__, TargetBuf, ByteData);
+ return ByteData;
+}
+
+RingBuf SpeechMessengerEVDO::GetM2ARawPcmRingBuffer(const ccci_buff_t &ccci_buff) {
+ spcRAWPCMBufInfo header_RawPcmBufInfo;
+ spcApRAWPCMBufHdr header_ApRawPcmBuf;
+
+ char SeqPcmBuf[CCCI_MAX_PAYLOAD_SIZE * 4 + 16] = {0};
+ RingBuf ul_ring_buf;
+ uint16_t size_copy1, size_copy2, BytesCopied, BytesToCopy;
+ char *PtrTarget = NULL;
+ char *PtrSource = NULL;
+
+ // check MD side data msg format
+ CheckOffsetAndLength(ccci_buff);
+ RingBuf ul_ring_buf1; // already have data in mM2AShareBufBase when ReadMessage
+ ul_ring_buf1.bufLen = mM2AShareBufLen;
+ ul_ring_buf1.pBufBase = mM2AShareBufBase;
+ ul_ring_buf1.pRead = ul_ring_buf1.pBufBase + GetMessageOffset(ccci_buff);
+ if (ul_ring_buf1.pRead >= mM2AShareBufEnd) { ul_ring_buf1.pRead -= ul_ring_buf1.bufLen; }
+ ALOGD("+%s(), address check: bufLen=0x%x, pBufBase=0x%p, pRead=0x%p, mM2AShareBufEnd=0x%p, pwrite=0x%p",
+ __FUNCTION__, ul_ring_buf1.bufLen, ul_ring_buf1.pBufBase, ul_ring_buf1.pRead, mM2AShareBufEnd, ul_ring_buf1.pRead + 6 + 8 + 320 + 640);
+
+ //parse message
+ char *p_sync_word = (char *)ul_ring_buf1.pRead + 0; // size(unsigned short)
+ char *p_data_type = (char *)ul_ring_buf1.pRead + 2; // size(unsigned short)
+ char *p_data_len = (char *)ul_ring_buf1.pRead + 4; // size(unsigned short)
+ if (p_data_type >= mM2AShareBufEnd) { p_data_type -= ul_ring_buf1.bufLen; }
+ if (p_data_len >= mM2AShareBufEnd) { p_data_len -= ul_ring_buf1.bufLen; }
+
+ if (*(uint16_t *)p_sync_word != CCCI_M2A_SHARE_BUFF_HEADER_SYNC) {
+ char TotalIdxDump = 10, IdxDump;
+ char SphDumpStr[SPH_DUMP_STR_SIZE] = {0};
+
+ snprintf(SphDumpStr, SPH_DUMP_STR_SIZE, "share_buf[pBase 0x%p, pEnd 0x%p, Len 0x%x, pRead 0x%p, offset 0x%x]= ", mM2AShareBufBase, mM2AShareBufEnd, mM2AShareBufLen, ul_ring_buf1.pRead, ccci_buff.message);
+ for (IdxDump = 0; IdxDump < TotalIdxDump; IdxDump++) {
+ char SphDumpTemp[100];
+ snprintf(SphDumpTemp, 100, "[%d, 0x%p]0x%x, ", IdxDump, ul_ring_buf1.pRead + IdxDump, *((uint16_t *)ul_ring_buf1.pRead + IdxDump));
+ audio_strncat(SphDumpStr, SphDumpTemp, SPH_DUMP_STR_SIZE);
+ }
+ if (IdxDump != 0) {
+ ALOGD("%s(), offset(0x%x), %s", __FUNCTION__, GetMessageOffset(ccci_buff), SphDumpStr);
+ }
+ ALOGD("%s(), message = 0x%x, *p_sync_word(0x%x), *p_data_type(0x%x), *p_data_len(0x%x), mPcmRecordType=%d",
+ __FUNCTION__, ccci_buff.message, *(uint16_t *)p_sync_word, *(uint16_t *)p_data_type, *(uint16_t *)p_data_len, mPcmRecordType);
+ }
+ ASSERT(*(uint16_t *)p_sync_word == CCCI_M2A_SHARE_BUFF_HEADER_SYNC);
+
+
+ // share buffer header
+ if ((ul_ring_buf1.pRead + CCCI_SHARE_BUFF_HEADER_LEN) >= mM2AShareBufEnd) {
+ char *ptr = mM2AShareBufBase + (ul_ring_buf1.pRead + CCCI_SHARE_BUFF_HEADER_LEN - mM2AShareBufEnd);
+ memcpy(&header_RawPcmBufInfo, ptr, sizeof(spcRAWPCMBufInfo));
+ } else if ((ul_ring_buf1.pRead + CCCI_SHARE_BUFF_HEADER_LEN + sizeof(spcRAWPCMBufInfo)) >= mM2AShareBufEnd) {
+ uint16_t size = mM2AShareBufEnd - (ul_ring_buf1.pRead + CCCI_SHARE_BUFF_HEADER_LEN);
+ char *ptr = (char *)(&header_RawPcmBufInfo);
+ memcpy(&header_RawPcmBufInfo, ul_ring_buf1.pRead + CCCI_SHARE_BUFF_HEADER_LEN, size);
+ memcpy(ptr + size, mM2AShareBufBase, sizeof(spcRAWPCMBufInfo) - size);
+ //ALOGD("%s(), &header_RawPcmBufInfo=0x%x, ptr+size=0x%x, size=%d, sizeof(spcRAWPCMBufInfo)=%d",__FUNCTION__, &header_RawPcmBufInfo, ptr+size, size, sizeof(spcRAWPCMBufInfo));
+ } else {
+ memcpy(&header_RawPcmBufInfo, (char *)ul_ring_buf1.pRead + CCCI_SHARE_BUFF_HEADER_LEN, sizeof(spcRAWPCMBufInfo));
+ }
+ PtrTarget = (char *)SeqPcmBuf;
+ ALOGD("%s(), header_RawPcmBufInfo: ULFreq=%d, ULLength=%d, DLFreq=%d, DLLength=%d", __FUNCTION__, header_RawPcmBufInfo.u16ULFreq, header_RawPcmBufInfo.u16ULLength, header_RawPcmBufInfo.u16DLFreq, header_RawPcmBufInfo.u16DLLength);
+
+ switch (mPcmRecordType) {
+ case RECORD_TYPE_UL:
+ header_ApRawPcmBuf.u16SyncWord = EEMCS_M2A_SHARE_BUFF_HEADER_SYNC;
+ header_ApRawPcmBuf.u16RawPcmDir = RECORD_TYPE_UL;
+ header_ApRawPcmBuf.u16Freq = GetPcmFreq(header_RawPcmBufInfo.u16ULFreq);
+ header_ApRawPcmBuf.u16Length = header_RawPcmBufInfo.u16ULLength;
+ header_ApRawPcmBuf.u16Channel = 1;
+ header_ApRawPcmBuf.u16BitFormat = AUDIO_FORMAT_PCM_16_BIT;
+ //uplink raw pcm header
+ memcpy(PtrTarget, &header_ApRawPcmBuf, sizeof(header_ApRawPcmBuf));
+ BytesCopied = sizeof(header_ApRawPcmBuf);
+
+ //uplink raw pcm
+ PtrTarget = SeqPcmBuf + BytesCopied;
+ PtrSource = (char *)ul_ring_buf1.pRead + CCCI_SHARE_BUFF_HEADER_LEN + CCCI_RAW_PCM_BUFF_HEADER_LEN;
+ if (PtrSource >= mM2AShareBufEnd) { PtrSource -= ul_ring_buf1.bufLen; }
+ BytesToCopy = header_RawPcmBufInfo.u16ULLength;
+ if (PtrSource + BytesToCopy >= mM2AShareBufEnd) {
+ uint16_t size = mM2AShareBufEnd - PtrSource;
+ memcpy(PtrTarget, PtrSource, size);
+ memcpy(PtrTarget + size, mM2AShareBufBase, BytesToCopy - size);
+ } else {
+ memcpy(PtrTarget, PtrSource, BytesToCopy);
+ }
+ BytesCopied += BytesToCopy;
+ break;
+
+ case RECORD_TYPE_DL:
+ header_ApRawPcmBuf.u16SyncWord = EEMCS_M2A_SHARE_BUFF_HEADER_SYNC;
+ header_ApRawPcmBuf.u16RawPcmDir = RECORD_TYPE_DL;
+ header_ApRawPcmBuf.u16Freq = GetPcmFreq(header_RawPcmBufInfo.u16DLFreq);
+ header_ApRawPcmBuf.u16Length = header_RawPcmBufInfo.u16DLLength;
+ header_ApRawPcmBuf.u16Channel = 1;
+ header_ApRawPcmBuf.u16BitFormat = AUDIO_FORMAT_PCM_16_BIT;
+ //downlink raw pcm header
+ memcpy(PtrTarget, &header_ApRawPcmBuf, sizeof(header_ApRawPcmBuf));
+ BytesCopied = sizeof(header_ApRawPcmBuf);
+
+ //downlink raw pcm
+ PtrTarget = SeqPcmBuf + BytesCopied;
+ PtrSource = (char *)ul_ring_buf1.pRead + CCCI_SHARE_BUFF_HEADER_LEN + CCCI_RAW_PCM_BUFF_HEADER_LEN + header_RawPcmBufInfo.u16ULLength;
+ if (PtrSource >= mM2AShareBufEnd) { PtrSource -= ul_ring_buf1.bufLen; }
+ BytesToCopy = header_RawPcmBufInfo.u16DLLength;
+ if (PtrSource + BytesToCopy >= mM2AShareBufEnd) {
+ uint16_t size = mM2AShareBufEnd - PtrSource;
+ memcpy(PtrTarget, PtrSource, size);
+ memcpy(PtrTarget + size, mM2AShareBufBase, BytesToCopy - size);
+ } else {
+ memcpy(PtrTarget, PtrSource, BytesToCopy);
+ }
+ BytesCopied += BytesToCopy;
+ break;
+
+ case RECORD_TYPE_MIX:
+ header_ApRawPcmBuf.u16SyncWord = EEMCS_M2A_SHARE_BUFF_HEADER_SYNC;
+ header_ApRawPcmBuf.u16RawPcmDir = RECORD_TYPE_UL;
+ header_ApRawPcmBuf.u16Freq = GetPcmFreq(header_RawPcmBufInfo.u16ULFreq);
+ header_ApRawPcmBuf.u16Length = header_RawPcmBufInfo.u16ULLength;
+ header_ApRawPcmBuf.u16Channel = 1;
+ header_ApRawPcmBuf.u16BitFormat = AUDIO_FORMAT_PCM_16_BIT;
+ //uplink raw pcm header
+ memcpy(PtrTarget, &header_ApRawPcmBuf, sizeof(header_ApRawPcmBuf));
+ BytesCopied = sizeof(header_ApRawPcmBuf);
+
+ //uplink raw pcm
+ PtrTarget = SeqPcmBuf + BytesCopied;
+ PtrSource = (char *)ul_ring_buf1.pRead + CCCI_SHARE_BUFF_HEADER_LEN + CCCI_RAW_PCM_BUFF_HEADER_LEN;
+ if (PtrSource >= mM2AShareBufEnd) { PtrSource -= ul_ring_buf1.bufLen; }
+ BytesToCopy = header_RawPcmBufInfo.u16ULLength;
+ if (PtrSource + BytesToCopy >= mM2AShareBufEnd) {
+ uint16_t size = mM2AShareBufEnd - PtrSource;
+ memcpy(PtrTarget, PtrSource, size);
+ memcpy(PtrTarget + size, mM2AShareBufBase, BytesToCopy - size);
+ } else {
+ memcpy(PtrTarget, PtrSource, BytesToCopy);
+ }
+ BytesCopied += BytesToCopy;
+#if 0 // Dump uplink in speech driver for debug
+ FILE *pDumpUplink;
+ AudiocheckAndCreateDirectory("/data/vendor/audiohal/Uplink.pcm");
+ pDumpUplink = fopen("/data/vendor/audiohal/Uplink.pcm", "ab");
+ if (pDumpUplink == NULL) { ALOGW("Fail to Open pDumpUplink"); }
+ fwrite(PtrTarget, sizeof(char), BytesToCopy, pDumpUplink);
+ fclose(pDumpUplink);
+ ALOGD("%s(),ul_ring_buf1.pRead[0]=%x,pRead[1]=0x%x,pRead[2]=%x,pRead[3]=0x%x,pRead[4]=%x,pRead[5]=0x%x,pRead[6]=%x,pRead[7]=0x%x,pRead[8]=%x, pRead[9]=0x%x, ul_ring_buf1.pRead[10]=%x,pRead[11]=0x%x,pRead[12]=%x,pRead[13]=0x%x,pRead[14]=%x,pRead[15]=0x%x,pRead[16]=%x,pRead[17]=0x%x,pRead[18]=%x, pRead[19]=0x%x", __FUNCTION__,
+ ul_ring_buf1.pRead[0], ul_ring_buf1.pRead[1], ul_ring_buf1.pRead[2], ul_ring_buf1.pRead[3], ul_ring_buf1.pRead[4],
+ ul_ring_buf1.pRead[5], ul_ring_buf1.pRead[6], ul_ring_buf1.pRead[7], ul_ring_buf1.pRead[8], ul_ring_buf1.pRead[9],
+ ul_ring_buf1.pRead[10], ul_ring_buf1.pRead[11], ul_ring_buf1.pRead[12], ul_ring_buf1.pRead[13], ul_ring_buf1.pRead[14],
+ ul_ring_buf1.pRead[15], ul_ring_buf1.pRead[16], ul_ring_buf1.pRead[17], ul_ring_buf1.pRead[18], ul_ring_buf1.pRead[19]);
+#endif
+ PtrTarget = SeqPcmBuf + BytesCopied;
+
+
+ //downlink raw pcm header
+ header_ApRawPcmBuf.u16RawPcmDir = RECORD_TYPE_DL;
+ header_ApRawPcmBuf.u16Freq = GetPcmFreq(header_RawPcmBufInfo.u16DLFreq);
+ header_ApRawPcmBuf.u16Length = header_RawPcmBufInfo.u16DLLength;
+ memcpy(PtrTarget, &header_ApRawPcmBuf, sizeof(header_ApRawPcmBuf));
+ BytesCopied += sizeof(header_ApRawPcmBuf);
+
+ //downlink raw pcm
+ PtrTarget = SeqPcmBuf + BytesCopied;
+ PtrSource = (char *)ul_ring_buf1.pRead + CCCI_SHARE_BUFF_HEADER_LEN + CCCI_RAW_PCM_BUFF_HEADER_LEN + header_RawPcmBufInfo.u16ULLength;
+ if (PtrSource >= mM2AShareBufEnd) { PtrSource -= ul_ring_buf1.bufLen; }
+ BytesToCopy = header_RawPcmBufInfo.u16DLLength;
+ if (PtrSource + BytesToCopy >= mM2AShareBufEnd) {
+ uint16_t size = mM2AShareBufEnd - PtrSource;
+ memcpy(PtrTarget, PtrSource, size);
+ memcpy(PtrTarget + size, mM2AShareBufBase, BytesToCopy - size);
+ } else {
+ memcpy(PtrTarget, PtrSource, BytesToCopy);
+ }
+ BytesCopied += BytesToCopy;
+#if 0 // Dump downlink in speech driver for debug
+ FILE *pDumpDownlink;
+ AudiocheckAndCreateDirectory("/data/vendor/audiohal/Downlink.pcm");
+ pDumpDownlink = fopen("/data/vendor/audiohal/Downlink.pcm", "ab");
+ if (pDumpDownlink == NULL) { ALOGW("Fail to Open pDumpDownlink"); }
+ fwrite(PtrTarget, sizeof(char), BytesToCopy, pDumpDownlink);
+ fclose(pDumpDownlink);
+ ALOGD("%s(),ul_ring_buf1.pRead[DL last]=0x%x", __FUNCTION__, ul_ring_buf1.pRead[6 + 10 + 320 + 640]);
+#endif
+ break;
+ }
+
+
+ //ring buffer process, pass to StreamIn
+ ul_ring_buf.bufLen = mM2AShareBufLen;
+ ul_ring_buf.pBufBase = mM2AShareBufBase;
+ ul_ring_buf.pBufEnd = ul_ring_buf.pBufBase + ul_ring_buf.bufLen;
+
+ ul_ring_buf.pRead = mM2AShareBufRead;
+
+ ul_ring_buf.pWrite = ul_ring_buf.pRead + BytesCopied;
+ if (ul_ring_buf.pWrite >= mM2AShareBufEnd) {
+ ul_ring_buf.pWrite -= ul_ring_buf.bufLen;
+
+ size_copy1 = mM2AShareBufEnd - ul_ring_buf.pRead;
+ size_copy2 = BytesCopied - size_copy1;
+ ALOGD("%s(), mM2AShareBufEnd(0x%p), BytesCopied(0x%x), size_copy1(0x%x), size_copy2(0x%x), pRead(0x%p), pWrite(0x%p)",
+ __FUNCTION__, mM2AShareBufEnd, BytesCopied, size_copy1, size_copy2, ul_ring_buf.pRead, ul_ring_buf.pWrite);
+ memcpy(ul_ring_buf.pRead, (char *)SeqPcmBuf, size_copy1);
+ memcpy(ul_ring_buf.pBufBase, (char *)SeqPcmBuf + size_copy1, size_copy2);
+ } else {
+ memcpy(ul_ring_buf.pRead, (char *)SeqPcmBuf, BytesCopied);
+ }
+ ALOGV("-%s(), pBufBase(0x%p), bufLen(0x%x), BytesCopied(0x%x), mM2AShareBufRead(0x%p), pRead(0x%p), pWrite(0x%p)",
+ __FUNCTION__, ul_ring_buf.pBufBase, ul_ring_buf.bufLen, BytesCopied, mM2AShareBufRead, ul_ring_buf.pRead, ul_ring_buf.pWrite);
+
+ mM2AShareBufRead = ul_ring_buf.pWrite;
+
+ return ul_ring_buf;
+}
+
+uint16_t SpeechMessengerEVDO::GetM2AShareBufSyncWord(const ccci_buff_t &ccci_buff) {
+ char *p_sync_word = GetM2AShareBufBase() + GetMessageOffset(ccci_buff) + 0; // 0 * size(unsigned short)
+ if (p_sync_word >= mM2AShareBufEnd) { p_sync_word -= mM2AShareBufLen; }
+ SLOGV("%s(), sync = 0x%x", __FUNCTION__, *(uint16_t *)p_sync_word);
+ return *(uint16_t *)p_sync_word;
+}
+
+uint16_t SpeechMessengerEVDO::GetM2AShareBufDataType(const ccci_buff_t &ccci_buff) {
+ char *p_data_type = GetM2AShareBufBase() + GetMessageOffset(ccci_buff) + 2; // 1 * size(unsigned short)
+ if (p_data_type >= mM2AShareBufEnd) { p_data_type -= mM2AShareBufLen; }
+ SLOGV("%s(), type = 0x%x", __FUNCTION__, *(uint16_t *)p_data_type);
+ return *(uint16_t *)p_data_type;
+}
+
+uint16_t SpeechMessengerEVDO::GetM2AShareBufDataLength(const ccci_buff_t &ccci_buff) {
+ char *p_data_len = GetM2AShareBufBase() + GetMessageOffset(ccci_buff) + 4; // 2 * size(unsigned short)
+ if (p_data_len >= mM2AShareBufEnd) { p_data_len -= mM2AShareBufLen; }
+ SLOGV("%s(), data_len = %d", __FUNCTION__, *(uint16_t *)p_data_len);
+ return *(uint16_t *)p_data_len;
+}
+
+
+bool SpeechMessengerEVDO::GetModemSideModemStatus(const modem_status_mask_t modem_status_mask) const {
+ return ((mModemSideModemStatus & modem_status_mask) > 0);
+}
+
+void SpeechMessengerEVDO::SetModemSideModemStatus(const modem_status_mask_t modem_status_mask) {
+ mModemSideModemStatus |= modem_status_mask;
+
+ // save mModemSideModemStatus in property to avoid medieserver die
+ char property_value[PROPERTY_VALUE_MAX];
+ sprintf(property_value, "%u", mModemSideModemStatus);
+ property_set(PROPERTY_KEY_MODEM_STATUS[mModemIndex], property_value);
+}
+
+void SpeechMessengerEVDO::ResetModemSideModemStatus(const modem_status_mask_t modem_status_mask) {
+ mModemSideModemStatus &= (~modem_status_mask);
+
+ // save mModemSideModemStatus in property to avoid medieserver die
+ char property_value[PROPERTY_VALUE_MAX];
+ sprintf(property_value, "%u", mModemSideModemStatus);
+ property_set(PROPERTY_KEY_MODEM_STATUS[mModemIndex], property_value);
+}
+
+status_t SpeechMessengerEVDO::setPcmRecordType(RecordType typeRecord) {
+ mPcmRecordType = typeRecord;
+ ALOGD("%s(), mPcmRecordType(%d)", __FUNCTION__, mPcmRecordType);
+ return NO_ERROR;
+}
+
+status_t SpeechMessengerEVDO::SetNWCodecInfo(const ccci_buff_t &ccci_buff) {
+ spcCodecInfoStruct sCodecInfo;
+ int returnPinfo = 0, returnHStatus = 0;
+ char SeqPcmBuf[CCCI_MAX_PAYLOAD_SIZE * 4 + 16] = {0};
+ RingBuf ul_ring_buf;
+ uint16_t size_copy1, size_copy2, BytesCopied, BytesToCopy;
+ char *PtrTarget = NULL;
+ char *PtrSource = NULL;
+
+ // check MD side data msg format
+ CheckOffsetAndLength(ccci_buff);
+ RingBuf ul_ring_buf1; // already have data in mM2AShareBufBase when ReadMessage
+ ul_ring_buf1.bufLen = mM2AShareBufLen;
+ ul_ring_buf1.pBufBase = mM2AShareBufBase;
+ ul_ring_buf1.pRead = ul_ring_buf1.pBufBase + GetMessageOffset(ccci_buff);
+ if (ul_ring_buf1.pRead >= mM2AShareBufEnd) { ul_ring_buf1.pRead -= ul_ring_buf1.bufLen; }
+ ALOGV("%s(), address check: bufLen=0x%x, pBufBase=0x%p, pRead=0x%p, mM2AShareBufEnd=0x%p, pwrite=0x%p",
+ __FUNCTION__, ul_ring_buf1.bufLen, ul_ring_buf1.pBufBase, ul_ring_buf1.pRead, mM2AShareBufEnd, ul_ring_buf1.pRead + 6 + 8 + 320 + 640);
+
+ //parse message
+ char *p_sync_word = (char *)ul_ring_buf1.pRead + 0; // size(unsigned short)
+ char *p_data_type = (char *)ul_ring_buf1.pRead + 2; // size(unsigned short)
+ char *p_data_len = (char *)ul_ring_buf1.pRead + 4; // size(unsigned short)
+ if (p_data_type >= mM2AShareBufEnd) { p_data_type -= ul_ring_buf1.bufLen; }
+ if (p_data_len >= mM2AShareBufEnd) { p_data_len -= ul_ring_buf1.bufLen; }
+
+ ALOGV("%s(), payload header: *p_sync_word(0x%x), *p_data_type(0x%x), *p_data_len(0x%x), mPcmRecordType=%d",
+ __FUNCTION__, *(uint16_t *)p_sync_word, *(uint16_t *)p_data_type, *(uint16_t *)p_data_len, mPcmRecordType);
+
+ ASSERT(*(uint16_t *)p_sync_word == CCCI_M2A_SHARE_BUFF_HEADER_SYNC);
+
+
+ // share buffer header
+ if ((ul_ring_buf1.pRead + CCCI_SHARE_BUFF_HEADER_LEN) >= mM2AShareBufEnd) {
+ char *ptr = mM2AShareBufBase + (ul_ring_buf1.pRead + CCCI_SHARE_BUFF_HEADER_LEN - mM2AShareBufEnd);
+ memcpy(&sCodecInfo, ptr, sizeof(spcCodecInfoStruct));
+ } else if ((ul_ring_buf1.pRead + CCCI_SHARE_BUFF_HEADER_LEN + sizeof(spcCodecInfoStruct)) >= mM2AShareBufEnd) {
+ uint16_t size = mM2AShareBufEnd - (ul_ring_buf1.pRead + CCCI_SHARE_BUFF_HEADER_LEN);
+ char *ptr = (char *)(&sCodecInfo);
+ memcpy(&sCodecInfo, ul_ring_buf1.pRead + CCCI_SHARE_BUFF_HEADER_LEN, size);
+ memcpy(ptr + size, mM2AShareBufBase, sizeof(sCodecInfo) - size);
+ //ALOGD("%s(), &header_RawPcmBufInfo=0x%x, ptr+size=0x%x, size=%d, sizeof(spcRAWPCMBufInfo)=%d",__FUNCTION__, &header_RawPcmBufInfo, ptr+size, size, sizeof(spcRAWPCMBufInfo));
+ } else {
+ memcpy(&sCodecInfo, (char *)ul_ring_buf1.pRead + CCCI_SHARE_BUFF_HEADER_LEN, sizeof(spcCodecInfoStruct));
+ }
+
+ ALOGD("%s(), sCodecInfo.codecInfo = %s, sCodecInfo.codecOp = %s", __FUNCTION__, sCodecInfo.codecInfo, sCodecInfo.codecOp);
+
+ returnPinfo = property_set(PROPERTY_KEY_NW_CODEC_INFO[0], sCodecInfo.codecInfo);
+ returnHStatus = property_set(PROPERTY_KEY_NW_CODEC_INFO[1], sCodecInfo.codecOp);
+
+ char pValue_CodecInfo[PROPERTY_VALUE_MAX];
+ char pValue_HDVoiceStatus[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_NW_CODEC_INFO[0], pValue_CodecInfo, ""); //"": default
+ property_get(PROPERTY_KEY_NW_CODEC_INFO[1], pValue_HDVoiceStatus, ""); //"": default
+ ALOGD("%s(), get %s = %s, %s = %s", __FUNCTION__, PROPERTY_KEY_NW_CODEC_INFO[0], pValue_CodecInfo, PROPERTY_KEY_NW_CODEC_INFO[1], pValue_HDVoiceStatus);
+
+ return NO_ERROR;
+
+}
+#ifdef USE_CCCI_SHARE_BUFFER
+void SpeechMessengerEVDO::InitA2MRawParaRingBuffer() {
+ mA2MParaShareBuf.pBufBase = mA2MParaShareBufBase + CCCI_SHAREBUF_GUARD_LENGTH;
+ mA2MParaShareBuf.pRead = mA2MParaShareBuf.pBufBase;
+ mA2MParaShareBuf.pWrite = mA2MParaShareBuf.pBufBase;
+ mA2MParaShareBuf.bufLen = mA2MParaShareBufLen - 2 * CCCI_SHAREBUF_GUARD_LENGTH;
+ mA2MParaShareBuf.pBufEnd = mA2MParaShareBuf.pBufBase + mA2MParaShareBuf.bufLen;
+ // add guard pattern here
+ memset((void *)mA2MParaShareBufBase, 0xa, CCCI_SHAREBUF_GUARD_LENGTH);
+ memset((void *)mA2MParaShareBuf.pBufEnd, 0xa, CCCI_SHAREBUF_GUARD_LENGTH);
+ mIsA2MParaShareBufEmpty = true;
+ ALOGD("%s pBufBase %p, pBufEnd %p, bufLen %d ", __FUNCTION__, mA2MParaShareBuf.pBufBase,
+ mA2MParaShareBuf.pBufEnd, mA2MParaShareBuf.bufLen);
+ return ;
+}
+status_t SpeechMessengerEVDO::GetA2MRawParaRingBuffer(uint16_t *offset, uint16_t *avail) {
+ *offset = (uint16_t)(mA2MParaShareBuf.pWrite - mA2MParaShareBufBase);
+ if (mA2MParaShareBuf.pWrite > mA2MParaShareBuf.pRead) {
+ * avail = (uint16_t)(mA2MParaShareBuf.bufLen - (mA2MParaShareBuf.pWrite - mA2MParaShareBuf.pRead));
+ } else if (mA2MParaShareBuf.pWrite == mA2MParaShareBuf.pRead) {
+ * avail = (uint16_t)(mIsA2MParaShareBufEmpty ? mA2MParaShareBuf.bufLen : 0);
+ } else {
+ * avail = (uint16_t)(mA2MParaShareBuf.pRead - mA2MParaShareBuf.pWrite);
+ }
+ ALOGV("%s mA2MParaShareBuf.pWrite %p ,*offset %d, *avail %d", __FUNCTION__, mA2MParaShareBuf.pWrite, *offset, *avail);
+ return NO_ERROR;
+}
+
+status_t SpeechMessengerEVDO::AdvanceA2MRawParaRingBuffer(int datalength) {
+ ALOGV("%s, %d", __FUNCTION__, datalength);
+ mA2MParaShareBuf.pRead += datalength;
+ if (mA2MParaShareBuf.pRead >= mA2MParaShareBuf.pBufEnd) {
+ mA2MParaShareBuf.pRead -= mA2MParaShareBuf.bufLen;
+ }
+ if (mA2MParaShareBuf.pRead == mA2MParaShareBuf.pWrite) {
+ mIsA2MParaShareBufEmpty = true;
+ }
+ ALOGV("%s, mA2MParaShareBuf.pRead = %p", __FUNCTION__, mA2MParaShareBuf.pRead);
+ return NO_ERROR;
+}
+
+status_t SpeechMessengerEVDO::WriteA2MRawParaRingBuffer(char *data, int datalength) {
+ if (data == NULL || datalength > mA2MParaShareBuf.bufLen) {
+ ALOGD("%s wrong pointer %p or data length %d", __FUNCTION__, data, datalength);
+ return -1;
+ }
+ int part1;
+ part1 = (mA2MParaShareBuf.pWrite >= mA2MParaShareBuf.pRead) ?
+ (mA2MParaShareBuf.pBufEnd - mA2MParaShareBuf.pWrite) : (mA2MParaShareBuf.pRead - mA2MParaShareBuf.pWrite);
+ if (part1 > datalength) {
+ SpeechMemCpy(mA2MParaShareBuf.pWrite, data, datalength);
+ mA2MParaShareBuf.pWrite += datalength;
+ } else {
+ int part2 = datalength - part1;
+ SpeechMemCpy(mA2MParaShareBuf.pWrite, data, part1);
+ SpeechMemCpy(mA2MParaShareBuf.pBufBase, data + part1, part2);
+ mA2MParaShareBuf.pWrite = mA2MParaShareBuf.pBufBase + part2;
+ }
+ mIsA2MParaShareBufEmpty = false;
+ ALOGV("%s after write %d ,mA2MParaShareBuf.pWrite %p", __FUNCTION__, datalength, mA2MParaShareBuf.pWrite);
+ return NO_ERROR;
+}
+#endif
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechParamParser.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechParamParser.cpp
new file mode 100644
index 0000000..19abf3f
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechParamParser.cpp
@@ -0,0 +1,1470 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechParamParser"
+#include "SpeechParamParser.h"
+#include "utstring.h"
+#include <utils/Log.h>
+#include <inttypes.h>
+#include <media/AudioParameter.h>
+
+#include "AudioUtility.h"//Mutex/assert
+#include "AudioALSAStreamManager.h"
+#include <audio_memory_control.h>
+
+
+namespace android {
+
+#define MAX_BYTE_PARAM_SPEECH 3434
+
+#define SPH_DUMP_STR_SIZE (500)
+#define SPH_PARAM_UNIT_DUMP_STR_SIZE (1024)
+
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+struct SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT {
+ uint16_t sphParserVer;
+ uint16_t numLayer;
+ uint16_t numEachLayer ;
+ uint16_t paramHeader[4] ;//Network, VoiceBand, Reserved, Reserved
+ uint16_t sphUnitMagiNum;
+
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT() : sphParserVer(0), numLayer(0),
+ numEachLayer(0), paramHeader(), sphUnitMagiNum(0) {}
+};
+
+struct AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT {
+ char *audioTypeName;
+ char numCategoryType;//4
+ std::vector<String8> categoryType;
+ std::vector<String8> categoryName;
+ char numParam;//4
+ std::vector<String8> paramName;
+ char *logPrintParamUnit;
+
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT() : audioTypeName(NULL), numCategoryType(0),
+ categoryType(), categoryName(), numParam(0), paramName(),
+ logPrintParamUnit(NULL) {}
+};
+
+struct SPEECH_PARAM_INFO_STRUCT {
+ speech_mode_t speechMode;
+ unsigned int idxVolume;
+ bool isBtNrecOn;
+ bool isLPBK;
+ unsigned char numHeadsetPole;
+ bool isSingleBandTransfer;
+ unsigned char idxVoiceBandStart;
+ bool isSV;
+ unsigned char idxTTY;
+
+ SPEECH_PARAM_INFO_STRUCT() : speechMode(SPEECH_MODE_NORMAL), idxVolume(0), isBtNrecOn(0),
+ isLPBK(0), numHeadsetPole(0), isSingleBandTransfer(0), idxVoiceBandStart(0),
+ isSV(0), idxTTY(0) {}
+};
+
+struct SPEECH_PARAM_SUPPORT_STRUCT {
+ bool isNetworkSupport;
+ bool isTTYSupport;
+ bool isSuperVolumeSupport;
+
+ SPEECH_PARAM_SUPPORT_STRUCT() : isNetworkSupport(0), isTTYSupport(0),
+ isSuperVolumeSupport(0) {}
+};
+
+struct SPEECH_NETWORK_STRUCT {
+ char name[128];
+ uint16_t supportBit;//4
+
+ SPEECH_NETWORK_STRUCT() : name(), supportBit(0) {}
+};
+
+enum speech_profile_t {
+ SPEECH_PROFILE_HANDSET = 0,
+ SPEECH_PROFILE_4_POLE_HEADSET = 1,
+ SPEECH_PROFILE_HANDSFREE = 2,
+ SPEECH_PROFILE_BT_EARPHONE = 3,
+ SPEECH_PROFILE_BT_NREC_OFF = 4,
+ SPEECH_PROFILE_MAGICONFERENCE = 5,
+ SPEECH_PROFILE_HAC = 6,
+ SPEECH_PROFILE_LPBK_HANDSET = 7,
+ SPEECH_PROFILE_LPBK_HEADSET = 8,
+ SPEECH_PROFILE_LPBK_HANDSFREE = 9,
+ SPEECH_PROFILE_3_POLE_HEADSET = 10,
+ SPEECH_PROFILE_5_POLE_HEADSET = 11,
+ SPEECH_PROFILE_5_POLE_HEADSET_ANC = 12,
+ SPEECH_PROFILE_USB_HEADSET = 13,
+ SPEECH_PROFILE_HANDSET_SV = 14,
+ SPEECH_PROFILE_HANDSFREE_SV = 15,
+ SPEECH_PROFILE_TTY_HCO_HANDSET = 16,
+ SPEECH_PROFILE_TTY_HCO_HANDSFREE = 17,
+ SPEECH_PROFILE_TTY_VCO_HANDSET = 18,
+ SPEECH_PROFILE_TTY_VCO_HANDSFREE = 19,
+
+ SPEECH_PROFILE_MAX_NUM = 20
+};
+
+//--------------------------------------------------------------------------------
+//audio type: Speech
+#define MAX_NUM_CATEGORY_TYPE_SPEECH 4
+#define MAX_NUM_PARAM_SPEECH 3
+const String8 audioType_Speech_CategoryType[ ] = {
+ String8("Band"),
+ String8("Profile"),
+ String8("VolIndex"),
+ String8("Network")
+};
+
+const String8 audioType_Speech_ParamName[ ] = {
+ String8("speech_mode_para"),
+ String8("sph_in_fir"),
+ String8("sph_out_fir"),
+ String8("sph_in_iir_mic1_dsp"),
+ String8("sph_in_iir_mic2_dsp"),
+ String8("sph_in_iir_enh_dsp"),
+ String8("sph_out_iir_enh_dsp")
+};
+
+#define NUM_VOLUME_SPEECH 7
+const char audioType_Speech_CategoryName3[NUM_VOLUME_SPEECH][128] = {"0", "1", "2", "3", "4", "5", "6"};
+const char audioType_Speech_CategoryName2[SPEECH_PROFILE_MAX_NUM][128] = {
+ "Normal",
+ "4_pole_Headset",
+ "Handsfree",
+ "BT_Earphone",
+ "BT_NREC_Off",
+ "MagiConference",
+ "HAC",
+ "Lpbk_Handset",
+ "Lpbk_Headset",
+ "Lpbk_Handsfree",
+ "3_pole_Headset",
+ "5_pole_Headset",
+ "5_pole_Headset+ANC",
+ "Usb_Headset",
+ "Handset_SV",
+ "Handsfree_SV",
+ "Tty_HCO_Handset",
+ "Tty_HCO_Handsfree",
+ "Tty_VCO_Handset",
+ "Tty_VCO_Handsfree"
+};
+
+//--------------------------------------------------------------------------------
+//audio type: SpeechDMNR
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_DMNR 2
+#define MAX_NUM_PARAM_SPEECH_DMNR 1
+const String8 audioType_SpeechDMNR_CategoryType[ ] = {String8("Band"), String8("Profile")};
+const char audioType_SpeechDMNR_CategoryName2[2][128] = {"Handset", "MagiConference"};
+const String8 audioType_SpeechDMNR_ParamName[ ] = {String8("dmnr_para")};
+
+//--------------------------------------------------------------------------------
+//audio type: SpeechGeneral
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_GENERAL 1
+#define MAX_NUM_PARAM_SPEECH_GENERAL 2
+const String8 audioType_SpeechGeneral_CategoryType[ ] = {String8("CategoryLayer")};
+const char audioType_SpeechGeneral_CategoryName1[1][128] = {"Common"};
+const String8 audioType_SpeechGeneral_ParamName[ ] = {String8("speech_common_para"), String8("debug_info")};
+
+//--------------------------------------------------------------------------------
+//audio type: SpeechMagiClarity
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_MAGICLARITY 1
+#define MAX_NUM_PARAM_SPEECH_MAGICLARITY 1
+const String8 audioType_SpeechMagiClarity_CategoryType[ ] = {String8("CategoryLayer")};
+const char audioType_SpeechMagiClarity_CategoryName1[1][128] = {"Common"};
+const String8 audioType_SpeechMagiClarity_ParamName[ ] = {String8("shape_rx_fir_para")};
+
+//--------------------------------------------------------------------------------
+//audio type: SpeechNetwork
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_NETWORK 1
+#define MAX_NUM_PARAM_SPEECH_NETWORK 1
+const String8 audioType_SpeechNetwork_CategoryType[ ] = {String8("Network")};
+const String8 audioType_SpeechNetwork_ParamName[ ] = {String8("speech_network_support")};
+
+
+//--------------------------------------------------------------------------------
+//audio type: SpeechEchoRef
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_ECHOREF 1
+#define MAX_NUM_PARAM_SPEECH_ECHOREF 1
+const String8 audioType_SpeechEchoRef_CategoryType[ ] = {String8("Device")};
+const char audioType_SpeechEchoRef_CategoryName1[1][128] = {"USBAudio"};
+const String8 audioType_SpeechEchoRef_ParamName[ ] = {String8("EchoRef_para")};
+
+
+/*==============================================================================
+ * Property keys
+ *============================================================================*/
+const char *PROPERTY_KEY_SPEECHLOG_ON = "persist.vendor.audiohal.speech_log_on";
+
+/*==============================================================================
+ * Singleton Pattern
+ *============================================================================*/
+
+SpeechParamParser *SpeechParamParser::UniqueSpeechParamParser = NULL;
+
+
+SpeechParamParser *SpeechParamParser::getInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+ ALOGV("%s()", __FUNCTION__);
+
+ if (UniqueSpeechParamParser == NULL) {
+ UniqueSpeechParamParser = new SpeechParamParser();
+ }
+ ASSERT(UniqueSpeechParamParser != NULL);
+ return UniqueSpeechParamParser;
+}
+/*==============================================================================
+ * Constructor / Destructor / Init / Deinit
+ *============================================================================*/
+
+SpeechParamParser::SpeechParamParser() {
+ ALOGD("%s()", __FUNCTION__);
+ mAppHandle = NULL;
+ mSpeechParamVerFirst = 0;
+ mSpeechParamVerLast = 0;
+ mNumSpeechParam = 3;
+
+ mSphParamInfo = NULL;
+ mSphParamSupport = NULL;
+ mListSpeechNetwork = NULL;
+ mNameForEachSpeechNetwork = NULL;
+ AUDIO_ALLOC_STRUCT(SPEECH_PARAM_INFO_STRUCT, mSphParamInfo);
+ AUDIO_ALLOC_STRUCT(SPEECH_PARAM_SUPPORT_STRUCT, mSphParamSupport);
+ AUDIO_ALLOC_STRUCT_ARRAY(SPEECH_NETWORK_STRUCT, 12, mListSpeechNetwork);
+ AUDIO_ALLOC_STRUCT_ARRAY(SPEECH_NETWORK_STRUCT, 12, mNameForEachSpeechNetwork);
+
+ init();
+}
+
+SpeechParamParser::~SpeechParamParser() {
+ ALOGD("%s()", __FUNCTION__);
+
+ AUDIO_FREE_POINTER(mSphParamInfo);
+ AUDIO_FREE_POINTER(mSphParamSupport);
+ AUDIO_FREE_POINTER(mListSpeechNetwork);
+ AUDIO_FREE_POINTER(mNameForEachSpeechNetwork);
+}
+
+void SpeechParamParser::init() {
+ ALOGD("%s()", __FUNCTION__);
+ initAppParser();
+ initSpeechNetwork();
+
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ } else {
+ const char *strSphVersion = appOps->appHandleGetFeatureOptionValue(mAppHandle, "SPH_PARAM_VERSION");
+ if (strSphVersion != NULL) {
+ sscanf(strSphVersion, "%" SCNd8 ".%" SCNd8, &mSpeechParamVerFirst, &mSpeechParamVerLast);
+ switch (mSpeechParamVerFirst) {
+ case 2:
+ mSphParamSupport->isNetworkSupport = true;
+ mNumSpeechParam = 7;
+ break;
+ case 1:
+ mSphParamSupport->isNetworkSupport = true;
+ mNumSpeechParam = 3;
+ break;
+ default:
+ mSphParamSupport->isNetworkSupport = false;
+ mNumSpeechParam = 3;
+ break;
+ }
+ } else {
+ mSpeechParamVerFirst = 0;
+ mSpeechParamVerLast = 0;
+ mSphParamSupport->isNetworkSupport = false;
+ mNumSpeechParam = 3;
+ }
+ const char *strSphTTY = appOps->appHandleGetFeatureOptionValue(mAppHandle, "SPH_PARAM_TTY");
+ if (strSphTTY != NULL) {
+ if (strcmp(strSphTTY, "yes") == 0) {
+ mSphParamSupport->isTTYSupport = true;
+ } else {
+ mSphParamSupport->isTTYSupport = false;
+ }
+ } else {
+ mSphParamSupport->isTTYSupport = false;
+ }
+
+ const char *strSphSV = appOps->appHandleGetFeatureOptionValue(mAppHandle, "SPH_PARAM_SV");
+ if (strSphSV != NULL) {
+ if (strcmp(strSphSV, "yes") == 0) {
+ mSphParamSupport->isSuperVolumeSupport = true;
+ } else {
+ mSphParamSupport->isSuperVolumeSupport = false;
+ }
+ } else {
+ mSphParamSupport->isSuperVolumeSupport = false;
+ }
+ }
+}
+
+/*==============================================================================
+ * SpeechParamParser Imeplementation
+ *============================================================================*/
+bool SpeechParamParser::GetSpeechParamSupport(const char *paramName) {
+ bool mSupport = false;
+ if (paramName != NULL) {
+ if (strcmp(paramName, "SPH_PARAM_TTY") == 0) {
+ mSupport = mSphParamSupport->isTTYSupport;
+ } else if (strcmp(paramName, "SPH_PARAM_SV") == 0) {
+ mSupport = mSphParamSupport->isSuperVolumeSupport;
+ } else {
+ mSupport = false;
+ }
+ ALOGV("%s(), %s = %d", __FUNCTION__, paramName, mSupport);
+ } else {
+ mSupport = false;
+ }
+ return mSupport;
+}
+
+void SpeechParamParser::initAppParser() {
+ ALOGD("+%s()", __FUNCTION__);
+ /* Init AppHandle */
+ ALOGD("%s() appHandleGetInstance", __FUNCTION__);
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return;
+ }
+ mAppHandle = appOps->appHandleGetInstance();
+ ALOGD("%s() appHandleRegXmlChangedCb", __FUNCTION__);
+
+}
+
+status_t SpeechParamParser::speechDataDump(char *bufDump,
+ uint16_t idxSphType,
+ const char *nameParam,
+ const char *speechParamData) {
+ if (nameParam == NULL) {
+ return NO_ERROR;
+ }
+ // Speech Log system property
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_SPEECHLOG_ON, property_value, "0"); //"0": default off
+ if (property_value[0] == '0') {
+#if !defined(CONFIG_MT_ENG_BUILD) // user or user debug load
+ return NO_ERROR;
+#endif
+ }
+
+ ALOGV("+%s(), idxSphType=%d", __FUNCTION__, idxSphType);
+ char sphDumpStr[SPH_DUMP_STR_SIZE] = {0};
+ int idxDump = 0, sizeDump = 0, DataTypePrint = 0;
+ //speech parameter dump
+
+ switch (idxSphType) {
+ case AUDIO_TYPE_SPEECH: {
+ if (strcmp(nameParam, "speech_mode_para") == 0) {
+ sizeDump = 16;
+ } else if (strcmp(nameParam, "sph_in_fir") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_out_fir") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_in_iir_mic1_dsp") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_in_iir_mic2_dsp") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_in_iir_enh_dsp") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_out_iir_enh_dsp") == 0) {
+ sizeDump = 5;
+ }
+ break;
+ }
+ case AUDIO_TYPE_SPEECH_GENERAL: {
+ if (strcmp(nameParam, "speech_common_para") == 0) {
+ sizeDump = 12;
+ } else if (strcmp(nameParam, "debug_info") == 0) {
+ sizeDump = 8;
+ }
+ break;
+ }
+ case AUDIO_TYPE_SPEECH_NETWORK: {
+ if (strcmp(nameParam, "speech_network_support") == 0) {
+ DataTypePrint = 1;
+ sizeDump = 1;
+ }
+ break;
+ }
+ case AUDIO_TYPE_SPEECH_ECHOREF: {
+ if (strcmp(nameParam, "USBAudio") == 0) {
+ sizeDump = 3;
+ }
+ break;
+ }
+
+ }
+ snprintf(sphDumpStr, SPH_DUMP_STR_SIZE, "%s[%d]=", nameParam, sizeDump);
+
+ for (idxDump = 0; idxDump < sizeDump; idxDump++) {
+ char sphDumpTemp[100] = {0};
+ if (DataTypePrint == 1) {
+ snprintf(sphDumpTemp, 100, "[%d]0x%x,", idxDump, *((uint16_t *)speechParamData + idxDump));
+ } else {
+ snprintf(sphDumpTemp, 100, "[%d]%d,", idxDump, *((uint16_t *)speechParamData + idxDump));
+ }
+ audio_strncat(sphDumpStr, sphDumpTemp, SPH_DUMP_STR_SIZE);
+ }
+
+ if (idxDump != 0 && bufDump != NULL) {
+ audio_strncat(bufDump, sphDumpStr, SPH_DUMP_STR_SIZE);
+ }
+ return NO_ERROR;
+}
+
+
+status_t SpeechParamParser::getSpeechParamFromAppParser(uint16_t idxSphType,
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT *paramLayerInfo,
+ char *bufParamUnit,
+ uint16_t *sizeByteTotal) {
+ ALOGV("+%s(), paramLayerInfo->numCategoryType=0x%x", __FUNCTION__, paramLayerInfo->numCategoryType);
+
+ if (mAppHandle == NULL) {
+ ALOGE("%s() mAppHandle == NULL, Assert!!!", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ char *categoryPath = NULL;
+ ParamUnit *paramUnit = NULL;
+ uint16_t sizeByteParam = 0, idxCount;
+ Param *SpeechParam;
+ UT_string *uts_categoryPath = NULL;
+
+ /* If user select a category path, just like "NarrowBand / Normal of Handset / Level0" */
+ utstring_new(uts_categoryPath);
+
+ ALOGV("%s(), categoryType.size=%zu, paramName.size=%zu",
+ __FUNCTION__, paramLayerInfo->categoryType.size(), paramLayerInfo->paramName.size());
+ for (idxCount = 0; idxCount < paramLayerInfo->categoryType.size() ; idxCount++) {
+ ALOGV("%s(), categoryType[%d]= %s",
+ __FUNCTION__, idxCount, paramLayerInfo->categoryType.at(idxCount).string());
+ }
+ for (idxCount = 0; idxCount < paramLayerInfo->categoryName.size() ; idxCount++) {
+ ALOGV("%s(), categoryName[%d]= %s",
+ __FUNCTION__, idxCount, paramLayerInfo->categoryName.at(idxCount).string());
+ }
+
+
+ for (idxCount = 0; idxCount < paramLayerInfo->numCategoryType ; idxCount++) {
+ if (idxCount == paramLayerInfo->numCategoryType - 1) {
+ //last time concat
+ utstring_printf(uts_categoryPath, "%s,%s", (char *)(paramLayerInfo->categoryType.at(idxCount).string()),
+ (char *)(paramLayerInfo->categoryName.at(idxCount).string()));
+ } else {
+ utstring_printf(uts_categoryPath, "%s,%s,", (char *)(paramLayerInfo->categoryType.at(idxCount).string()),
+ (char *)(paramLayerInfo->categoryName.at(idxCount).string()));
+ }
+ }
+ categoryPath = strdup(utstring_body(uts_categoryPath));
+ utstring_free(uts_categoryPath);
+
+ ALOGV("%s() audioTypeName=%s", __FUNCTION__, paramLayerInfo->audioTypeName);
+ /* Query AudioType */
+ AppOps *appOps = appOpsGetInstance();
+ AudioType *audioType = NULL;
+ if (appOps == NULL) {
+ free(categoryPath);
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ } else {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo->audioTypeName);
+ }
+ if (!audioType) {
+ free(categoryPath);
+ ALOGE("%s() can't find audioTypeName=%s, Assert!!!", __FUNCTION__, paramLayerInfo->audioTypeName);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ /* Query the ParamUnit */
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, categoryPath);
+ if (!paramUnit) {
+ appOps->audioTypeUnlock(audioType);
+ ALOGE("%s() can't find paramUnit, Assert!!! audioType=%s, categoryPath=%s",
+ __FUNCTION__, audioType->name, categoryPath);
+ free(categoryPath);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "(path=%s,id=%d),", categoryPath, paramUnit->paramId);
+ audio_strncat(paramLayerInfo->logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+
+ //for speech param dump
+ char *bufParamDump = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(bufParamDump, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ for (idxCount = 0; idxCount < (*paramLayerInfo).numParam ; idxCount++) {
+
+ SpeechParam = appOps->paramUnitGetParamByName(paramUnit,
+ (const char *)paramLayerInfo->paramName.at(idxCount).string());
+ if (SpeechParam) {
+ sizeByteParam = sizeByteParaData((DATA_TYPE)SpeechParam->paramInfo->dataType, SpeechParam->arraySize);
+ memcpy(bufParamUnit + *sizeByteTotal, SpeechParam->data, sizeByteParam);
+ *sizeByteTotal += sizeByteParam;
+ ALOGV("%s() paramName=%s, sizeByteParam=%d",
+ __FUNCTION__, paramLayerInfo->paramName.at(idxCount).string(), sizeByteParam);
+ //speech parameter dump
+ speechDataDump(bufParamDump, idxSphType, (const char *)paramLayerInfo->paramName.at(idxCount).string(),
+ (const char *)SpeechParam->data);
+ }
+ }
+
+ if (bufParamDump != NULL) {
+ if (bufParamDump[0] != 0) {
+ ALOGD("%s(),dump: %s", __FUNCTION__, bufParamDump);
+ }
+ delete[] bufParamDump;
+ }
+
+ appOps->audioTypeUnlock(audioType);
+ free(categoryPath);
+
+ return NO_ERROR;
+}
+
+uint16_t SpeechParamParser::sizeByteParaData(uint16_t dataType, uint16_t arraySize) {
+ uint16_t sizeUnit = 4;
+ switch (dataType) {
+ case TYPE_INT:
+ sizeUnit = 4;
+ break;
+ case TYPE_UINT:
+ sizeUnit = 4;
+ break;
+ case TYPE_FLOAT:
+ sizeUnit = 4;
+ break;
+ case TYPE_BYTE_ARRAY:
+ sizeUnit = arraySize;
+ break;
+ case TYPE_UBYTE_ARRAY:
+ sizeUnit = arraySize;
+ break;
+ case TYPE_SHORT_ARRAY:
+ sizeUnit = arraySize << 1;
+ break;
+ case TYPE_USHORT_ARRAY:
+ sizeUnit = arraySize << 1;
+ break;
+ case TYPE_INT_ARRAY:
+ sizeUnit = arraySize << 2;
+ break;
+ case TYPE_UINT_ARRAY:
+ sizeUnit = arraySize << 2;
+ break;
+ default:
+ ALOGE("%s(), Not an available dataType(%d)", __FUNCTION__, dataType);
+
+ break;
+
+ }
+
+ ALOGV("-%s(), arraySize=%d, sizeUnit=%d", __FUNCTION__, arraySize, sizeUnit);
+
+ return sizeUnit;
+
+
+}
+
+
+int SpeechParamParser::GetDmnrParamUnit(char *bufParamUnit) {
+ ALOGV("+%s()", __FUNCTION__);
+ uint16_t size = 0, idxBand = 0, idxProfile = 0, sizeByteFromApp = 0;
+ uint16_t dataHeader, idxTmp = 0, numBand = 0, numProfile = 0;
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT headerParamUnit;
+ memset(&headerParamUnit, 0, sizeof(headerParamUnit));
+
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+
+ paramLayerInfo.audioTypeName = (char *) audioTypeNameList[AUDIO_TYPE_SPEECH_DMNR];
+ paramLayerInfo.numCategoryType = MAX_NUM_CATEGORY_TYPE_SPEECH_DMNR;//4
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_DMNR;//4
+ paramLayerInfo.categoryType.assign(audioType_SpeechDMNR_CategoryType,
+ audioType_SpeechDMNR_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechDMNR_ParamName,
+ audioType_SpeechDMNR_ParamName + paramLayerInfo.numParam);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ ALOGV("%s(), categoryType.size=%zu, paramName.size=%zu",
+ __FUNCTION__, paramLayerInfo.categoryType.size(), paramLayerInfo.paramName.size());
+ /* Query AudioType */
+ AppOps *appOps = appOpsGetInstance();
+ AudioType *audioType = NULL;
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ } else {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo.audioTypeName);
+ }
+ char *packedParamUnitFromApp = new char [MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp, 0, MAX_BYTE_PARAM_SPEECH);
+
+ CategoryType *categoryBand = appOps->audioTypeGetCategoryTypeByName(audioType,
+ audioType_SpeechDMNR_CategoryType[0].string());
+ numBand = appOps->categoryTypeGetNumOfCategory(categoryBand);
+ CategoryType *categoryProfile = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_SpeechDMNR_CategoryType[1].string());
+ numProfile = appOps->categoryTypeGetNumOfCategory(categoryProfile);
+ idxTmp = (numBand & 0xF) << 4;
+ headerParamUnit.numEachLayer = idxTmp + (numProfile & 0xF);
+ setMDParamUnitHdr(AUDIO_TYPE_SPEECH_DMNR, &headerParamUnit, numBand);
+
+ memcpy(bufParamUnit + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ for (idxBand = 0; idxBand < numBand; idxBand++) { //NB, WB, SWB
+ for (idxProfile = 0; idxProfile < numProfile; idxProfile++) {
+ sizeByteFromApp = 0;
+ dataHeader = ((idxBand + 1) << 4) + (idxProfile + 1);
+ memcpy(bufParamUnit + size, &dataHeader, sizeof(dataHeader));
+ size += sizeof(dataHeader);
+ Category *CateBand = appOps->categoryTypeGetCategoryByIndex(categoryBand, idxBand);
+ paramLayerInfo.categoryName.push_back(String8(CateBand->name));//Band
+ paramLayerInfo.categoryName.push_back(String8(audioType_SpeechDMNR_CategoryName2[idxProfile]));//Profile
+
+ getSpeechParamFromAppParser(AUDIO_TYPE_SPEECH_DMNR, ¶mLayerInfo,
+ packedParamUnitFromApp, &sizeByteFromApp);
+
+ memcpy(bufParamUnit + size, packedParamUnitFromApp, sizeByteFromApp);
+ size += sizeByteFromApp;
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "header=0x%x[%d,%d], size(b)=%d;",
+ dataHeader, idxBand, idxProfile, sizeByteFromApp);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ paramLayerInfo.categoryName.pop_back();
+ paramLayerInfo.categoryName.pop_back();
+
+ }
+ }
+
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "total size(b)=%d", size);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ ALOGD("%s(),MagiNum(0x%x),xml(%s), %s", __FUNCTION__,
+ headerParamUnit.sphUnitMagiNum, paramLayerInfo.audioTypeName, paramLayerInfo.logPrintParamUnit);
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+
+ return size;
+}
+
+int SpeechParamParser::GetGeneralParamUnit(char *bufParamUnit) {
+ ALOGV("+%s()", __FUNCTION__);
+ uint16_t size = 0, idxCount = 0, idxCount2 = 0, sizeByteFromApp = 0;
+ uint16_t dataHeader;
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT headerParamUnit;
+ memset(&headerParamUnit, 0, sizeof(headerParamUnit));
+
+ headerParamUnit.sphParserVer = 1;
+ headerParamUnit.numLayer = 0x1;
+ headerParamUnit.numEachLayer = 0x1;
+ headerParamUnit.paramHeader[0] = 0x1;//Common
+ headerParamUnit.sphUnitMagiNum = 0xAA02;
+
+ memcpy(bufParamUnit + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ char *packedParamUnitFromApp = new char [MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp, 0, MAX_BYTE_PARAM_SPEECH);
+
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+
+ paramLayerInfo.audioTypeName = (char *) audioTypeNameList[AUDIO_TYPE_SPEECH_GENERAL];
+ paramLayerInfo.numCategoryType = MAX_NUM_CATEGORY_TYPE_SPEECH_GENERAL;//4
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_GENERAL;//4
+
+ paramLayerInfo.categoryType.assign(audioType_SpeechGeneral_CategoryType,
+ audioType_SpeechGeneral_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechGeneral_ParamName,
+ audioType_SpeechGeneral_ParamName + paramLayerInfo.numParam);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ ALOGV("%s(), eParamUnitHdr.sphUnitMagiNum= 0x%x, categoryType.size=%zu, paramName.size=%zu", __FUNCTION__,
+ headerParamUnit.sphUnitMagiNum, paramLayerInfo.categoryType.size(), paramLayerInfo.paramName.size());
+ for (idxCount = 0; idxCount < paramLayerInfo.paramName.size() ; idxCount++) {
+ ALOGV("%s(), paramName[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.paramName.at(idxCount).string());
+ }
+
+ dataHeader = 0x000F;
+ memcpy(bufParamUnit + size, &dataHeader, sizeof(dataHeader));
+ size += sizeof(dataHeader);
+
+ paramLayerInfo.categoryName.push_back(String8(audioType_SpeechGeneral_CategoryName1[0]));
+
+ getSpeechParamFromAppParser(AUDIO_TYPE_SPEECH_GENERAL, ¶mLayerInfo, packedParamUnitFromApp, &sizeByteFromApp);
+
+ memcpy(bufParamUnit + size, packedParamUnitFromApp, sizeByteFromApp);
+ size += sizeByteFromApp;
+
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "total size(b)=%d", size);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ ALOGD("%s(),MagiNum(0x%x),xml(%s), %s",
+ __FUNCTION__, headerParamUnit.sphUnitMagiNum, paramLayerInfo.audioTypeName, paramLayerInfo.logPrintParamUnit);
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+
+ return size;
+}
+
+int SpeechParamParser::GetEchoRefParamUnit(char *bufParamUnit) {
+ ALOGV("+%s()", __FUNCTION__);
+ uint16_t size = 0, idxCount = 0, idxCount2 = 0, sizeByteFromApp = 0;
+ uint16_t dataHeader;
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT headerParamUnit;
+ memset(&headerParamUnit, 0, sizeof(headerParamUnit));
+
+ headerParamUnit.sphParserVer = 1;
+ headerParamUnit.numLayer = 0x1;
+ headerParamUnit.numEachLayer = 0x1;
+ headerParamUnit.paramHeader[0] = 0x1;
+ headerParamUnit.sphUnitMagiNum = 0xAA06;
+
+ memcpy(bufParamUnit + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ char *packedParamUnitFromApp = new char [MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp, 0, MAX_BYTE_PARAM_SPEECH);
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+
+ paramLayerInfo.audioTypeName = (char *) audioTypeNameList[AUDIO_TYPE_SPEECH_ECHOREF];
+ paramLayerInfo.numCategoryType = MAX_NUM_CATEGORY_TYPE_SPEECH_ECHOREF;//4
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_ECHOREF;//4
+
+ paramLayerInfo.categoryType.assign(audioType_SpeechEchoRef_CategoryType,
+ audioType_SpeechEchoRef_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechEchoRef_ParamName,
+ audioType_SpeechEchoRef_ParamName + paramLayerInfo.numParam);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ ALOGV("%s(), eParamUnitHdr.sphUnitMagiNum= 0x%x, categoryType.size=%zu, paramName.size=%zu", __FUNCTION__,
+ headerParamUnit.sphUnitMagiNum, paramLayerInfo.categoryType.size(), paramLayerInfo.paramName.size());
+ for (idxCount = 0; idxCount < paramLayerInfo.paramName.size() ; idxCount++) {
+ ALOGV("%s(), paramName[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.paramName.at(idxCount).string());
+ }
+
+ dataHeader = 0x000F;
+ memcpy(bufParamUnit + size, &dataHeader, sizeof(dataHeader));
+ size += sizeof(dataHeader);
+
+ paramLayerInfo.categoryName.push_back(String8(audioType_SpeechEchoRef_CategoryName1[0]));
+
+ getSpeechParamFromAppParser(AUDIO_TYPE_SPEECH_ECHOREF, ¶mLayerInfo, packedParamUnitFromApp, &sizeByteFromApp);
+
+ memcpy(bufParamUnit + size, packedParamUnitFromApp, sizeByteFromApp);
+ size += sizeByteFromApp;
+
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "total size(b)=%d", size);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ ALOGD("%s(),MagiNum(0x%x),xml(%s), %s", __FUNCTION__, headerParamUnit.sphUnitMagiNum,
+ paramLayerInfo.audioTypeName, paramLayerInfo.logPrintParamUnit);
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+
+ return size;
+}
+int SpeechParamParser::getSpeechProfile(const speech_mode_t sphMode, bool btHeadsetNrecOn) {
+ speech_profile_t idxSphProfile;
+
+ if (mSphParamInfo->isLPBK) {
+ switch (sphMode) {
+ case SPEECH_MODE_NORMAL:
+ idxSphProfile = SPEECH_PROFILE_LPBK_HANDSET;
+ break;
+ case SPEECH_MODE_EARPHONE:
+ idxSphProfile = SPEECH_PROFILE_LPBK_HEADSET;
+ break;
+ case SPEECH_MODE_LOUD_SPEAKER:
+ idxSphProfile = SPEECH_PROFILE_LPBK_HANDSFREE;
+ break;
+ default:
+ idxSphProfile = SPEECH_PROFILE_LPBK_HANDSET;
+
+ break;
+ }
+ } else {
+ switch (sphMode) {
+ case SPEECH_MODE_NORMAL:
+ if (mSphParamInfo->idxTTY == TTY_PARAM_OFF) {
+ if (mSphParamInfo->isSV) {
+ idxSphProfile = SPEECH_PROFILE_HANDSET_SV;
+ } else {
+ idxSphProfile = SPEECH_PROFILE_HANDSET;
+ }
+ } else {
+ switch (mSphParamInfo->idxTTY) {
+ case TTY_PARAM_HCO:
+ idxSphProfile = SPEECH_PROFILE_TTY_HCO_HANDSET;
+ break;
+ case TTY_PARAM_VCO:
+ idxSphProfile = SPEECH_PROFILE_TTY_VCO_HANDSET;
+ break;
+ default:
+ idxSphProfile = SPEECH_PROFILE_TTY_HCO_HANDSET;
+ break;
+ }
+ }
+ break;
+
+ case SPEECH_MODE_EARPHONE:
+ switch (mSphParamInfo->numHeadsetPole) {
+ case 3:
+ idxSphProfile = SPEECH_PROFILE_3_POLE_HEADSET;
+ break;
+ case 4:
+ idxSphProfile = SPEECH_PROFILE_4_POLE_HEADSET;
+ break;
+ case 5:
+ idxSphProfile = SPEECH_PROFILE_5_POLE_HEADSET;
+ break;
+ default:
+ idxSphProfile = SPEECH_PROFILE_4_POLE_HEADSET;
+ break;
+ }
+ break;
+ case SPEECH_MODE_LOUD_SPEAKER:
+ if (mSphParamInfo->idxTTY == TTY_PARAM_OFF) {
+ if (mSphParamInfo->isSV) {
+ idxSphProfile = SPEECH_PROFILE_HANDSFREE_SV;
+ } else {
+ idxSphProfile = SPEECH_PROFILE_HANDSFREE;
+ }
+ } else {
+ switch (mSphParamInfo->idxTTY) {
+ case TTY_PARAM_HCO:
+ idxSphProfile = SPEECH_PROFILE_TTY_HCO_HANDSFREE;
+ break;
+ case TTY_PARAM_VCO:
+ idxSphProfile = SPEECH_PROFILE_TTY_VCO_HANDSFREE;
+ break;
+ default:
+ idxSphProfile = SPEECH_PROFILE_TTY_HCO_HANDSFREE;
+ break;
+ }
+ }
+ break;
+ case SPEECH_MODE_BT_EARPHONE:
+ case SPEECH_MODE_BT_CORDLESS:
+ case SPEECH_MODE_BT_CARKIT:
+ if (btHeadsetNrecOn == true) {
+ idxSphProfile = SPEECH_PROFILE_BT_EARPHONE;
+ } else {
+ idxSphProfile = SPEECH_PROFILE_BT_NREC_OFF;
+ }
+ break;
+ case SPEECH_MODE_MAGIC_CON_CALL:
+ idxSphProfile = SPEECH_PROFILE_MAGICONFERENCE;
+ break;
+ case SPEECH_MODE_HAC:
+ idxSphProfile = SPEECH_PROFILE_HAC;
+ break;
+ case SPEECH_MODE_USB_AUDIO:
+ idxSphProfile = SPEECH_PROFILE_USB_HEADSET;
+ break;
+ default:
+ idxSphProfile = SPEECH_PROFILE_HANDSET;
+
+ break;
+ }
+ }
+ ALOGV("%s(), sphMode = %d, idxSphProfile = %d", __FUNCTION__, sphMode, idxSphProfile);
+
+ return idxSphProfile;
+}
+
+status_t SpeechParamParser::setMDParamUnitHdr(speech_type_dynamic_param_t idxAudioType,
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT *paramUnitHdr,
+ uint16_t configValue) {
+ switch (idxAudioType) {
+ case AUDIO_TYPE_SPEECH:
+ paramUnitHdr->sphUnitMagiNum = 0xAA01;
+ paramUnitHdr->sphParserVer = 1;
+ paramUnitHdr->numLayer = 0x2;
+ paramUnitHdr->paramHeader[0] = 0x1F;//all network use, while modem not check it
+ //Network: bit0: GSM, bit1: WCDMA,.bit2: CDMA, bit3: VoLTE, bit4:C2K
+ if (mSphParamInfo->isSingleBandTransfer) {
+ switch (configValue) {
+ case 0:
+ paramUnitHdr->paramHeader[1] = 0x1;//voice band:NB
+ break;
+ case 1:
+ paramUnitHdr->paramHeader[1] = 0x2;//voice band:WB
+ break;
+
+ default:
+ paramUnitHdr->paramHeader[1] = 0x1;//voice band:NB
+ break;
+ }
+ } else {
+ switch (configValue) {
+ case 1:
+ paramUnitHdr->paramHeader[1] = 0x1;//voice band:NB
+ break;
+ case 2:
+ paramUnitHdr->paramHeader[1] = 0x3;//voice band:NB,WB
+ break;
+ case 3:
+ paramUnitHdr->paramHeader[1] = 0x7;//voice band:NB,WB,SWB
+ break;
+ case 4:
+ paramUnitHdr->paramHeader[1] = 0xF;//voice band:NB,WB,SWB,FB
+ break;
+ default:
+ paramUnitHdr->paramHeader[1] = 0x3;//voice band:NB,WB
+ break;
+ }
+ }
+ paramUnitHdr->paramHeader[2] = (mSpeechParamVerFirst << 4) + mSpeechParamVerLast;
+ ALOGV("%s(), sphUnitMagiNum = 0x%x, SPH_PARAM_VERSION(0x%x)",
+ __FUNCTION__, paramUnitHdr->sphUnitMagiNum, paramUnitHdr->paramHeader[2]);
+ break;
+ case AUDIO_TYPE_SPEECH_DMNR:
+ paramUnitHdr->sphUnitMagiNum = 0xAA03;
+ paramUnitHdr->sphParserVer = 1;
+ paramUnitHdr->numLayer = 0x2;
+ paramUnitHdr->paramHeader[0] = 0x3;//OutputDeviceType
+ switch (configValue) {
+ case 1:
+ paramUnitHdr->paramHeader[1] = 0x1;//voice band:NB
+ break;
+ case 2:
+ paramUnitHdr->paramHeader[1] = 0x3;//voice band:NB,WB
+ break;
+ case 3:
+ paramUnitHdr->paramHeader[1] = 0x7;//voice band:NB,WB,SWB
+ break;
+ case 4:
+ paramUnitHdr->paramHeader[1] = 0xF;//voice band:NB,WB,SWB,FB
+ break;
+ default:
+ paramUnitHdr->paramHeader[1] = 0x3;//voice band:NB,WB
+ break;
+ }
+ paramUnitHdr->paramHeader[2] = (mSpeechParamVerFirst << 4) + mSpeechParamVerLast;
+ ALOGV("%s(), sphUnitMagiNum = 0x%x, Version = 0x%x",
+ __FUNCTION__, paramUnitHdr->sphUnitMagiNum, paramUnitHdr->paramHeader[2]);
+ break;
+
+ default:
+ break;
+ }
+
+ // Speech Log system property
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_SPEECHLOG_ON, property_value, "0"); //"0": default off
+ if (property_value[0] == '0') {
+ return NO_ERROR;
+ } else {
+ char sphDumpStr[SPH_DUMP_STR_SIZE] = "MDParamUnitHdr ";
+ int idxDump = 0;
+ for (idxDump = 0; idxDump < (int)(sizeof(paramUnitHdr) >> 1); idxDump++) { //uint16_t
+ char sphDumpTemp[100] = {0};
+ snprintf(sphDumpTemp, 100, "[%d]0x%x, ", idxDump, *((uint16_t *)¶mUnitHdr + idxDump));
+ audio_strncat(sphDumpStr, sphDumpTemp, SPH_DUMP_STR_SIZE);
+ }
+ if (idxDump != 0) {
+ ALOGD("%s(), %s", __FUNCTION__, sphDumpStr);
+ }
+ }
+ return NO_ERROR;
+}
+
+uint16_t SpeechParamParser::setMDParamDataHdr(SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT paramUnitHdr,
+ const char *cateBandName, const char *cateNetworkName) {
+ uint16_t idxCount = 0;
+ uint16_t dataHeader = 0, MaskNetwork = 0;
+ bool bNetworkMatch = false;
+
+ if (cateBandName != NULL) {
+ if (strcmp(cateBandName, "NB") == 0) { //All netwrok use
+ dataHeader = 0x1000;
+ } else if (strcmp(cateBandName, "WB") == 0) {
+ dataHeader = 0x2000;
+ } else if (strcmp(cateBandName, "SWB") == 0) {
+ dataHeader = 0x3000;
+ } else if (strcmp(cateBandName, "FB") == 0) {
+ dataHeader = 0x4000;
+ }
+ } else {
+ dataHeader = 0x1000;
+ }
+ //search matched network
+ if (cateNetworkName != NULL) {
+ for (idxCount = 0; idxCount < mNumSpeechNetwork ; idxCount++) {
+ ALOGV("%s(), cateNetwork= %s, mListSpeechNetwork[%d]=%s",
+ __FUNCTION__, cateNetworkName, idxCount, mListSpeechNetwork[idxCount].name);
+ if (strcmp(cateNetworkName, mListSpeechNetwork[idxCount].name) == 0) {
+ MaskNetwork = mListSpeechNetwork[idxCount].supportBit;
+ ALOGV("%s(), cateNetwork= %s, mListSpeechNetwork[%d]=%s, MaskNetwork=0x%x",
+ __FUNCTION__, cateNetworkName, idxCount, mListSpeechNetwork[idxCount].name, MaskNetwork);
+ bNetworkMatch = true;
+ break;
+ }
+ }
+ if (!bNetworkMatch) {
+ ALOGE("%s(), cateNetwork= %s, mListSpeechNetwork[%d]=%s, bNetworkMatch=%d, NO match!!!",
+ __FUNCTION__, cateNetworkName, idxCount, mListSpeechNetwork[idxCount].name, bNetworkMatch);
+ }
+ }
+ if (!mSphParamSupport->isNetworkSupport) {
+ dataHeader = dataHeader >> 8;
+ MaskNetwork = 0xF;
+ }
+ dataHeader |= MaskNetwork;
+ ALOGV("-%s(), sphUnitMagiNum=0x%x, dataHeader=0x%x, MaskNetwork=0x%x, cateBand=%s",
+ __FUNCTION__, paramUnitHdr.sphUnitMagiNum, dataHeader, MaskNetwork, cateBandName);
+
+ return dataHeader;
+}
+
+
+int SpeechParamParser::initSpeechNetwork(void) {
+ uint16_t size = 0, idxCount, sizeByteFromApp = 0;
+ char *packedParamUnitFromApp = new char [10];
+ memset(packedParamUnitFromApp, 0, 10);
+
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+
+ //-------------
+ paramLayerInfo.audioTypeName = (char *) audioTypeNameList[AUDIO_TYPE_SPEECH_NETWORK];
+
+ if (mAppHandle == NULL) {
+ ALOGE("%s() mAppHandle == NULL, Assert!!!", __FUNCTION__);
+ ASSERT(0);
+ }
+
+ /* Query AudioType */
+ AppOps *appOps = appOpsGetInstance();
+ AudioType *audioType = NULL;
+ if (appOps != NULL) {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo.audioTypeName);
+ paramLayerInfo.numCategoryType = appOps->audioTypeGetNumOfCategoryType(audioType);//1
+
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_NETWORK;//4
+
+ paramLayerInfo.categoryType.assign(audioType_SpeechNetwork_CategoryType,
+ audioType_SpeechNetwork_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechNetwork_ParamName,
+ audioType_SpeechNetwork_ParamName + paramLayerInfo.numParam);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ ALOGV("%s(), categoryType.size=%zu, paramName.size=%zu",
+ __FUNCTION__, paramLayerInfo.categoryType.size(), paramLayerInfo.paramName.size());
+ for (idxCount = 0; idxCount < paramLayerInfo.categoryType.size() ; idxCount++) {
+ ALOGV("%s(), categoryType[%d]= %s",
+ __FUNCTION__, idxCount, paramLayerInfo.categoryType.at(idxCount).string());
+ }
+ for (idxCount = 0; idxCount < paramLayerInfo.paramName.size() ; idxCount++) {
+ ALOGV("%s(), paramName[%d]= %s",
+ __FUNCTION__, idxCount, paramLayerInfo.paramName.at(idxCount).string());
+ }
+ //-----------
+ //parse layer
+ CategoryType *categoryNetwork = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_SpeechNetwork_CategoryType[0].string());
+ mNumSpeechNetwork = appOps->categoryTypeGetNumOfCategory(categoryNetwork);
+
+ //parse network
+ for (int idxNetwork = 0; idxNetwork < mNumSpeechNetwork; idxNetwork++) {
+ Category *CateNetwork = appOps->categoryTypeGetCategoryByIndex(categoryNetwork, idxNetwork);
+ sizeByteFromApp = 0;
+ //clear
+ while (!paramLayerInfo.categoryName.empty()) {
+ paramLayerInfo.categoryName.pop_back();
+ }
+ audio_strncpy(mListSpeechNetwork[idxNetwork].name, CateNetwork->name, 128);
+
+ paramLayerInfo.categoryName.push_back(String8(CateNetwork->name));//Network
+
+ getSpeechParamFromAppParser(AUDIO_TYPE_SPEECH_NETWORK, ¶mLayerInfo, packedParamUnitFromApp, &sizeByteFromApp);
+ mListSpeechNetwork[idxNetwork].supportBit = *((uint16_t *)packedParamUnitFromApp);
+ size += sizeByteFromApp;
+
+ ALOGD("%s(), idxNetwork=%d, sizeByteFromApp=%d, supportBit=0x%x",
+ __FUNCTION__, idxNetwork, sizeByteFromApp, mListSpeechNetwork[idxNetwork].supportBit);
+ }
+ ALOGD("-%s(), total size byte=%d", __FUNCTION__, size);
+ } else {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ }
+ //init the Name mapping table for each SpeechNetwork
+ bool IsNetworkFound = false;
+ for (int bitIndex = 0; bitIndex < 12; bitIndex++) {
+ IsNetworkFound = false;
+ for (int NetworkIndex = 0; NetworkIndex < mNumSpeechNetwork; NetworkIndex++) {
+ if (((mListSpeechNetwork[NetworkIndex].supportBit >> bitIndex) & 1) == 1) {
+ audio_strncpy(mNameForEachSpeechNetwork[bitIndex].name, mListSpeechNetwork[NetworkIndex].name, 128);
+ IsNetworkFound = true;
+ break;
+ }
+ }
+ if (!IsNetworkFound) {
+ audio_strncpy(mNameForEachSpeechNetwork[bitIndex].name, mListSpeechNetwork[0].name, 128);
+ }
+ ALOGD("%s(), mNameForEachSpeechNetwork[%d].name = %s",
+ __FUNCTION__, bitIndex, mNameForEachSpeechNetwork[bitIndex].name);
+ }
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+ return size;
+}
+
+
+int SpeechParamParser::GetSpeechParamUnit(char *bufParamUnit, int *paramArg) {
+ uint16_t size = 0, idxCount, sizeByteFromApp = 0;
+ uint16_t dataHeader, idxInfo = 0, idxTmp = 0, numBand = 0, numNetwork = 0, numVolume = 0;
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT headerParamUnit;
+ int idxProfile = 0, parserOption = 0;
+
+ speech_mode_t sphMode = (speech_mode_t) * ((int *)paramArg);
+ int idxVolume = *((int *)paramArg + 1);
+ bool btHeadsetNrecOn = (bool) * ((int *)paramArg + 2);
+ mSphParamInfo->isBtNrecOn = btHeadsetNrecOn;
+ mSphParamInfo->idxVolume = idxVolume;
+ mSphParamInfo->speechMode = sphMode;
+
+ parserOption = * ((int *)paramArg + 3);
+ //bit 0: dv profile, bit 1: single band, bit 4~7: band number
+ mSphParamInfo->isSingleBandTransfer = (bool)(parserOption & 0x2);
+ mSphParamInfo->idxVoiceBandStart = (unsigned char)((parserOption & 0xf0) >> 4);
+
+ idxProfile = getSpeechProfile(sphMode, btHeadsetNrecOn);
+ ALOGD("+%s(), sphMode=0x%x, Volume=0x%x, BtNrecOn=0x%x, Profile=%d, parserOption=0x%x",
+ __FUNCTION__, sphMode, idxVolume, btHeadsetNrecOn, idxProfile, parserOption);
+
+ memset(&headerParamUnit, 0, sizeof(headerParamUnit));
+
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+ //-------------
+ paramLayerInfo.audioTypeName = (char *) audioTypeNameList[AUDIO_TYPE_SPEECH];
+
+ if (mAppHandle == NULL) {
+ ALOGE("%s() mAppHandle == NULL, Assert!!!", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ /* Query AudioType */
+ AppOps *appOps = appOpsGetInstance();
+ AudioType *audioType = NULL;
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ } else {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo.audioTypeName);
+ }
+
+ char *packedParamUnitFromApp = new char [MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp, 0, MAX_BYTE_PARAM_SPEECH);
+
+ paramLayerInfo.numCategoryType = appOps->audioTypeGetNumOfCategoryType(audioType);
+ paramLayerInfo.numParam = mNumSpeechParam;//4
+
+ paramLayerInfo.categoryType.assign(audioType_Speech_CategoryType,
+ audioType_Speech_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_Speech_ParamName, audioType_Speech_ParamName + paramLayerInfo.numParam);
+
+ ALOGV("%s(), categoryType.size=%zu, paramName.size=%zu",
+ __FUNCTION__, paramLayerInfo.categoryType.size(), paramLayerInfo.paramName.size());
+ for (idxCount = 0; idxCount < paramLayerInfo.categoryType.size() ; idxCount++) {
+ ALOGV("%s(), categoryType[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.categoryType.at(idxCount).string());
+ }
+ for (idxCount = 0; idxCount < paramLayerInfo.paramName.size() ; idxCount++) {
+ ALOGV("%s(), paramName[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.paramName.at(idxCount).string());
+ }
+ //-----------
+
+ //parse layer
+ CategoryType *categoryNetwork = appOps->audioTypeGetCategoryTypeByName(audioType,
+ audioType_Speech_CategoryType[3].string());
+ CategoryType *categoryBand = appOps->audioTypeGetCategoryTypeByName(audioType,
+ audioType_Speech_CategoryType[0].string());
+ numNetwork = appOps->categoryTypeGetNumOfCategory(categoryNetwork);
+ numBand = appOps->categoryTypeGetNumOfCategory(categoryBand);
+
+ CategoryType *categoryVolume = appOps->audioTypeGetCategoryTypeByName(audioType,
+ audioType_Speech_CategoryType[2].string());
+ CategoryGroup *categoryGroupVolume = appOps->categoryTypeGetCategoryGroupByIndex(categoryVolume, 0);
+ numVolume = appOps->categoryGroupGetNumOfCategory(categoryGroupVolume);
+ idxTmp = (numBand & 0xF) << 4;
+ headerParamUnit.numEachLayer = idxTmp + (numNetwork & 0xF);
+ ALOGV("%s(), sphUnitMagiNum= 0x%x, numEachLayer=0x%x",
+ __FUNCTION__, headerParamUnit.sphUnitMagiNum, headerParamUnit.numEachLayer);
+ if (mSphParamInfo->isSingleBandTransfer) {
+ setMDParamUnitHdr(AUDIO_TYPE_SPEECH, &headerParamUnit, mSphParamInfo->idxVoiceBandStart);
+ } else {
+ setMDParamUnitHdr(AUDIO_TYPE_SPEECH, &headerParamUnit, numBand);
+ }
+ ALOGV("%s(), sphUnitMagiNum= 0x%x, numEachLayer=0x%x",
+ __FUNCTION__, headerParamUnit.sphUnitMagiNum, headerParamUnit.numEachLayer);
+ ALOGV("%s(), categoryNetwork= %s, categoryBand = %s, categoryVolume = %s",
+ __FUNCTION__, categoryNetwork->name, categoryBand->name, categoryVolume->name);
+ ALOGV("%s(), numNetwork= %d, numBand = %d, numVolume = %d", __FUNCTION__, numNetwork, numBand, numVolume);
+
+ memcpy(bufParamUnit + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ idxInfo = sphMode & 0xF;
+ ALOGV("%s(), add mode idxInfo=0x%x", __FUNCTION__, idxInfo);
+ idxTmp = idxVolume << 4;
+ idxInfo += idxTmp;
+ ALOGV("%s(), add volume<<4 idxInfo=0x%x, idxTmp=0x%x", __FUNCTION__, idxInfo, idxTmp);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ memcpy(bufParamUnit + size, &idxInfo, sizeof(idxInfo));
+ size += sizeof(idxInfo);
+ //parse network
+ for (int idxNetwork = 0; idxNetwork < numNetwork; idxNetwork++) {
+ Category *CateNetwork = appOps->categoryTypeGetCategoryByIndex(categoryNetwork, idxNetwork);
+ //parse band
+ for (int idxBand = mSphParamInfo->idxVoiceBandStart; idxBand < mSphParamInfo->idxVoiceBandStart + numBand; idxBand++) {
+ sizeByteFromApp = 0;
+ Category *CateBand = appOps->categoryTypeGetCategoryByIndex(categoryBand, idxBand);
+
+ dataHeader = setMDParamDataHdr(headerParamUnit, CateBand->name, CateNetwork->name);
+ memcpy(bufParamUnit + size, &dataHeader, sizeof(dataHeader));
+ size += sizeof(dataHeader);
+ while (!paramLayerInfo.categoryName.empty()) {
+ paramLayerInfo.categoryName.pop_back();
+ }
+ //Band
+ paramLayerInfo.categoryName.push_back(String8(CateBand->name));//Band
+ //Profile
+ paramLayerInfo.categoryName.push_back(String8(audioType_Speech_CategoryName2[idxProfile]));
+ //Volume
+ if (idxVolume >= NUM_VOLUME_SPEECH || idxVolume < 0) {
+ paramLayerInfo.categoryName.push_back(String8(audioType_Speech_CategoryName3[3]));//volume
+ ALOGE("%s(), Invalid idxVolume=0x%x, use %s !!!",
+ __FUNCTION__, idxVolume, audioType_Speech_CategoryName3[3]);
+ } else {
+ paramLayerInfo.categoryName.push_back(String8(audioType_Speech_CategoryName3[idxVolume]));
+ }
+ paramLayerInfo.categoryName.push_back(String8(CateNetwork->name));//Network
+
+ for (idxCount = 0; idxCount < paramLayerInfo.categoryName.size() ; idxCount++) {
+ ALOGV("%s(), categoryName[%d]= %s",
+ __FUNCTION__, idxCount, paramLayerInfo.categoryName.at(idxCount).string());
+ }
+
+ getSpeechParamFromAppParser(AUDIO_TYPE_SPEECH, ¶mLayerInfo, packedParamUnitFromApp, &sizeByteFromApp);
+
+ memcpy(bufParamUnit + size, packedParamUnitFromApp, sizeByteFromApp);
+ size += sizeByteFromApp;
+
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "size(b)=%d; total size(b)=%d", sizeByteFromApp, size);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ }
+
+ ALOGD("-%s(), MagiNum(0x%x),xml(%s),version(0x%x),%s", __FUNCTION__, headerParamUnit.sphUnitMagiNum,
+ paramLayerInfo.audioTypeName, headerParamUnit.paramHeader[2], paramLayerInfo.logPrintParamUnit);
+ //reset buffer pointer
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+ paramLayerInfo.logPrintParamUnit[0] = '\0';
+ }
+
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+
+ return size;
+}
+
+
+status_t SpeechParamParser::SetParamInfo(const String8 &keyParamPairs) {
+ ALOGV("+%s(): %s", __FUNCTION__, keyParamPairs.string());
+ AudioParameter param = AudioParameter(keyParamPairs);
+ int value;
+ if (param.getInt(String8("ParamSphLpbk"), value) == NO_ERROR) {
+ param.remove(String8("ParamSphLpbk"));
+#if defined(MTK_AUDIO_SPH_LPBK_PARAM)
+ mSphParamInfo->isLPBK = (value == 1) ? true : false;
+#else
+ mSphParamInfo->isLPBK = false;
+
+#endif
+ ALOGD("%s(): mSphParamInfo->isLPBK = %d", __FUNCTION__, mSphParamInfo->isLPBK);
+ }
+ if (param.getInt(String8("ParamHeadsetPole"), value) == NO_ERROR) {
+ param.remove(String8("ParamHeadsetPole"));
+ if (value == 3 || value == 4 || value == 5) {
+ mSphParamInfo->numHeadsetPole = value;
+ } else {
+ mSphParamInfo->numHeadsetPole = 4;
+ ALOGE("%s(): Invalid HeadsetPole(%d), set default 4_pole!!!", __FUNCTION__, value);
+ }
+ ALOGD("%s(): mSphParamInfo->numHeadsetPole = %d", __FUNCTION__, mSphParamInfo->numHeadsetPole);
+ }
+ if (param.getInt(String8("ParamSphTty"), value) == NO_ERROR) {
+ param.remove(String8("ParamSphTty"));
+ if (mSphParamSupport->isTTYSupport) {
+ mSphParamInfo->idxTTY = value;
+ }
+ ALOGD("%s(): mSphParamInfo->idxTTY = %d", __FUNCTION__, mSphParamInfo->idxTTY);
+ }
+ if (param.getInt(String8("ParamSphSV"), value) == NO_ERROR) {
+ param.remove(String8("ParamSphSV"));
+ if (mSphParamSupport->isSuperVolumeSupport) {
+ mSphParamInfo->isSV = (value == 1) ? true : false;
+ } else {
+ mSphParamInfo->isSV = false;
+ }
+ ALOGD("%s(): mSphParamInfo->isSV = %d", __FUNCTION__, mSphParamInfo->isSV);
+ }
+
+ ALOGD("-%s(): %s", __FUNCTION__, keyParamPairs.string());
+ return NO_ERROR;
+}
+
+bool SpeechParamParser::GetParamStatus(const char *paramName) {
+ bool status = false;
+ if (paramName != NULL) {
+ if (strcmp(paramName, "ParamSphTty") == 0) {
+ status = (mSphParamInfo->idxTTY == 0) ? false : true;
+ } else if (strcmp(paramName, "ParamSphSV") == 0) {
+ status = mSphParamInfo->isSV;
+ } else {
+ status = false;
+ }
+ ALOGD("%s(), %s = %d", __FUNCTION__, paramName, status);
+ } else {
+ status = false;
+ }
+ return status;
+}
+
+int SpeechParamParser::GetMagiClarityParamUnit(char *bufParamUnit) {
+ ALOGV("+%s()", __FUNCTION__);
+ uint16_t size = 0, idxCount = 0, idxCount2 = 0, sizeByteFromApp = 0;
+ uint16_t dataHeader;
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT headerParamUnit;
+ memset(&headerParamUnit, 0, sizeof(headerParamUnit));
+
+ headerParamUnit.sphParserVer = 1;
+ headerParamUnit.numLayer = 0x1;
+ headerParamUnit.numEachLayer = 0x1;
+ headerParamUnit.paramHeader[0] = 0x1;//Common
+ headerParamUnit.sphUnitMagiNum = 0xAA04;
+
+ memcpy(bufParamUnit + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ char *packedParamUnitFromApp = new char [MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp, 0, MAX_BYTE_PARAM_SPEECH);
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+
+ paramLayerInfo.audioTypeName = (char *) audioTypeNameList[AUDIO_TYPE_SPEECH_MAGICLARITY];
+ paramLayerInfo.numCategoryType = MAX_NUM_CATEGORY_TYPE_SPEECH_MAGICLARITY;//4
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_MAGICLARITY;//4
+
+ paramLayerInfo.categoryType.assign(audioType_SpeechMagiClarity_CategoryType,
+ audioType_SpeechMagiClarity_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechMagiClarity_ParamName,
+ audioType_SpeechMagiClarity_ParamName + paramLayerInfo.numParam);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ for (idxCount = 0; idxCount < paramLayerInfo.paramName.size() ; idxCount++) {
+ ALOGV("%s(), paramName[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.paramName.at(idxCount).string());
+ }
+ dataHeader = 0x000F;
+ memcpy(bufParamUnit + size, &dataHeader, sizeof(dataHeader));
+ size += sizeof(dataHeader);
+
+ paramLayerInfo.categoryName.push_back(String8(audioType_SpeechMagiClarity_CategoryName1[0]));
+
+ getSpeechParamFromAppParser(AUDIO_TYPE_SPEECH_MAGICLARITY, ¶mLayerInfo,
+ packedParamUnitFromApp, &sizeByteFromApp);
+
+ memcpy(bufParamUnit + size, packedParamUnitFromApp, sizeByteFromApp);
+ size += sizeByteFromApp;
+
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "total size(b)=%d", size);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ ALOGD("%s(),MagiNum(0x%x),xml(%s), %s", __FUNCTION__,
+ headerParamUnit.sphUnitMagiNum, paramLayerInfo.audioTypeName, paramLayerInfo.logPrintParamUnit);
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+
+ return size;
+}
+
+int SpeechParamParser::GetBtDelayTime(const char *btDeviceName) {
+ int btDelayMs = 0;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL || btDeviceName == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return 0;
+ } else {
+ /* Get the BT device delay parameter */
+ AudioType *audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, "BtInfo");
+ if (audioType) {
+ String8 categoryPath("BT headset,");
+ categoryPath += btDeviceName;
+
+ ParamUnit *paramUnit = appOps->audioTypeGetParamUnit(audioType, categoryPath.string());
+ ASSERT(paramUnit);
+
+ Param *param = appOps->paramUnitGetParamByName(paramUnit, "voice_cp_delay_ms");
+ ASSERT(param);
+
+ btDelayMs = *(int *)param->data;
+ }
+ ALOGD("%s(), btDeviceName=%s, btDelayMs=%d", __FUNCTION__, btDeviceName, btDelayMs);
+ return btDelayMs;
+ }
+}
+}
+
+//namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechVMRecorder.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechVMRecorder.cpp
new file mode 100644
index 0000000..8919638
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechVMRecorder.cpp
@@ -0,0 +1,726 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechVMRecorder"
+#include "SpeechVMRecorder.h"
+
+#include <sys/prctl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <cutils/properties.h>
+
+#include <utils/threads.h>
+
+#include <ftw.h>
+
+#include <hardware_legacy/power.h>
+
+#include <SpeechType.h>
+
+#include <audio_memory_control.h>
+#include <audio_time.h>
+
+#include <SpeechUtility.h>
+
+#include <SpeechDriverFactory.h>
+#include <SpeechDriverInterface.h>
+#include <audio_dump_path.h>
+
+#if !defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+#include <AudioCustParamClient.h>
+#include <SpeechEnhancementController.h>
+#endif
+//#define FORCE_ENABLE_VM
+//#define VM_FILENAME_ONLY_USE_VM0_TO_VM7
+
+namespace android {
+
+/*==============================================================================
+ * Property keys
+ *============================================================================*/
+const char *PROPERTY_KEY_VM_INDEX = "persist.vendor.audiohal.vm_index";
+const char *PROPERTY_KEY_VM_RECYCLE_ON = "persist.vendor.audiohal.vm_recycle_on";
+const char *PROPERTY_KEY_VM_CFG = "persist.vendor.audiohal.vm_cfg";
+
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+// 100 ms (modem local buf: 10k, and EPL has 2304 byte for each frame (20 ms))
+static const uint32_t kCondWaitTimeoutMsec = 100;
+
+static const uint32_t kReadBufferSize = 0x20000; // 128 k
+static const uint32_t kSdCardBufferSize = 0x4000; // 16 k
+
+static uint32_t gThreadOpenIndex = 0;
+static AudioLock gThreadOpenIndexLock;
+
+/*==============================================================================
+ * VM File Recycle
+ *============================================================================*/
+static const uint32_t kMaxNumOfVMFiles = 100;
+
+static const uint32_t kMinKeepNumOfVMFiles = 16; // keep at least 16 files which will not be removed
+static const uint32_t kMaxSizeOfAllVMFiles = 209715200; // Total > 200 M
+
+static const char kFolderOfVMFile[] = LOG_PATH_AUDIO_DUMP;
+static char kPrefixOfVMFileName[128] = {0};
+static uint32_t kSizeOfPrefixOfVMFileName = 0;
+static const uint32_t kMaxSizeOfVMFileName = 128;
+
+typedef struct {
+ char path[kMaxSizeOfVMFileName];
+ uint32_t size;
+} vm_file_info_t;
+
+static vm_file_info_t gVMFileList[kMaxNumOfVMFiles];
+static uint32_t gNumOfVMFiles = 0;
+static uint32_t gTotalSizeOfVMFiles; // Total size of VM files in SD card
+
+static int getVMFileList(const char *path, const struct stat *sb, int typeflag __unused) {
+ if (strncmp(path, kPrefixOfVMFileName, kSizeOfPrefixOfVMFileName) != 0) {
+ return 0;
+ }
+
+ if (gNumOfVMFiles >= kMaxNumOfVMFiles) {
+ return 0;
+ }
+
+ // path
+ audio_strncpy(gVMFileList[gNumOfVMFiles].path, path, kMaxSizeOfVMFileName);
+
+ // size
+ gVMFileList[gNumOfVMFiles].size = sb->st_size;
+ gTotalSizeOfVMFiles += sb->st_size;
+
+ // increase index
+ gNumOfVMFiles++;
+
+ return 0; // To tell ftw() to continue
+}
+
+static int compareVMFileName(const void *a, const void *b) {
+ return strcmp(((vm_file_info_t *)a)->path,
+ ((vm_file_info_t *)b)->path);
+}
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+SpeechVMRecorder *SpeechVMRecorder::mSpeechVMRecorder = NULL;
+SpeechVMRecorder *SpeechVMRecorder::getInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+
+ if (mSpeechVMRecorder == NULL) {
+ mSpeechVMRecorder = new SpeechVMRecorder();
+ }
+ ASSERT(mSpeechVMRecorder != NULL);
+ return mSpeechVMRecorder;
+}
+
+SpeechVMRecorder::SpeechVMRecorder() {
+ mVMConfig = SPEECH_VM_DISABLE;
+ mIsDumpThreadStart = false;
+ mIsVmEnable = false;
+
+ memset((void *)&mRingBuf, 0, sizeof(RingBuf));
+ mIsCtmDebugStart = false;
+ pCtmDumpFileUlIn = NULL;
+ pCtmDumpFileDlIn = NULL;
+ pCtmDumpFileUlOut = NULL;
+ pCtmDumpFileDlOut = NULL;
+ mRecordThread = 0;
+ mOpenIndex = 0;
+#if !defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ AUDIO_CUSTOM_PARAM_STRUCT sphParamNB;
+ AudioCustParamClient::GetInstance()->GetNBSpeechParamFromNVRam(&sphParamNB);
+ char property_value[PROPERTY_VALUE_MAX];
+ snprintf(property_value, sizeof(property_value), "%d", (uint8_t) sphParamNB.uAutoVM);
+ property_set(PROPERTY_KEY_VM_CFG, property_value);
+#endif
+ sprintf(kPrefixOfVMFileName, "%s%s", kFolderOfVMFile, "VMLog");
+ kSizeOfPrefixOfVMFileName = strlen(kPrefixOfVMFileName);
+ getVmConfig();
+ ALOGD("%s(), mVMConfig(%d)", __FUNCTION__, mVMConfig);
+
+}
+
+SpeechVMRecorder::~SpeechVMRecorder() {
+ close();
+}
+
+/**
+ * VM Config
+ */
+#if !defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+int SpeechVMRecorder::configVm(const AUDIO_CUSTOM_PARAM_STRUCT *sphParamNB) {
+ ALOGD("%s(), uAutoVM = 0x%x, debug_info[0] = %u, speech_common_para[0] = %u", __FUNCTION__,
+ sphParamNB->uAutoVM, sphParamNB->debug_info[0], sphParamNB->speech_common_para[0]);
+ uint8_t vmConfig = (uint8_t)sphParamNB->uAutoVM;
+ return configVm(vmConfig);
+}
+#endif
+
+int SpeechVMRecorder::configVm(const uint8_t vmConfig) {
+ if (vmConfig < 0 || vmConfig >= NUM_SPEECH_VM_TYPE) {
+ ALOGW("%s(), not support type %d", __FUNCTION__, vmConfig);
+ return -EINVAL;
+ }
+ if (mVMConfig == (SpeechVmType) vmConfig) {
+ ALOGW("%s(), mVMConfig(%d) == vmConfig(%d), return.", __FUNCTION__, mVMConfig, vmConfig);
+ return 0;
+ }
+
+ char property_value[PROPERTY_VALUE_MAX];
+ snprintf(property_value, sizeof(property_value), "%d", vmConfig);
+ property_set(PROPERTY_KEY_VM_CFG, property_value);
+
+ mVMConfig = (SpeechVmType) vmConfig;
+
+ triggerSpeechVm();
+ ALOGD("%s(), mVMConfig = %d", __FUNCTION__, mVMConfig);
+ return 0;
+}
+
+int SpeechVMRecorder::configVmEpl(const bool isEpl) {
+ ALOGD("%s(), isEpl=%d,", __FUNCTION__, isEpl);
+#if !defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ AUDIO_CUSTOM_PARAM_STRUCT eSphParamNB;
+ AudioCustParamClient::GetInstance()->GetNBSpeechParamFromNVRam(&eSphParamNB);
+ if (isEpl) { // EPL
+ eSphParamNB.debug_info[0] = 3;
+ if (eSphParamNB.speech_common_para[0] == 0) { // if not assign EPL debug type yet, set a default one
+ eSphParamNB.speech_common_para[0] = 6;
+ }
+ } else {// normal VM
+ eSphParamNB.debug_info[0] = 0;
+ }
+ AudioCustParamClient::GetInstance()->SetNBSpeechParamToNVRam(&eSphParamNB);
+ SpeechEnhancementController::GetInstance()->SetNBSpeechParametersToAllModem(&eSphParamNB);
+#endif
+
+ return 0;
+}
+
+SpeechVmType SpeechVMRecorder::getVmConfig() {
+#if defined(FORCE_ENABLE_VM)
+ mVMConfig = SPEECH_VM_SPEECH;
+#else
+ // VM Log system property
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_VM_CFG, property_value, "0"); //"0": default off
+ if (property_value[0] == '1') {
+ mVMConfig = SPEECH_VM_SPEECH;
+ } else if (property_value[0] == '2') {
+ mVMConfig = SPEECH_VM_CTM4WAY;
+ } else {
+ mVMConfig = SPEECH_VM_DISABLE;
+ }
+#endif
+ return mVMConfig;
+}
+
+void SpeechVMRecorder::triggerSpeechVm() {
+ ALOGD("%s(), mVMConfig = %d", __FUNCTION__, mVMConfig);
+ SpeechDriverInterface *pSpeechDriver = SpeechDriverFactory::GetInstance()->GetSpeechDriver();
+ const bool isSpeechOn = pSpeechDriver->GetApSideModemStatus(SPEECH_STATUS_MASK);
+ const bool isVoiceRecordOn = pSpeechDriver->GetApSideModemStatus(RECORD_STATUS_MASK);
+
+ if (isSpeechOn) {
+ if (getVmConfig() == SPEECH_VM_SPEECH && mIsVmEnable == false) {
+ // turn off normal phone record
+ if (isVoiceRecordOn == true) {
+ ALOGW("%s(), Turn off normal phone recording!!", __FUNCTION__);
+ ALOGW("%s(), The following record file will be silence until VM/EPL is closed.", __FUNCTION__);
+ }
+
+ ALOGD("%s(), Open VM/EPL record", __FUNCTION__);
+ open();
+ } else if (getVmConfig() != SPEECH_VM_SPEECH && mIsVmEnable == true) {
+ ALOGD("%s(), Close VM/EPL record", __FUNCTION__);
+ ALOGD("%s(), Able to continue to do phone record.", __FUNCTION__);
+ close();
+ }
+ }
+}
+
+/**
+ * VM for vocie call
+ */
+status_t SpeechVMRecorder::open() {
+ AL_LOCK(mMutex);
+
+ // create another thread to avoid fwrite() block CCCI read thread
+ ASSERT(mIsVmEnable == false);
+ mIsVmEnable = true;
+ mOpenIndex++;
+ ALOGD("%s(), mOpenIndex: %u", __FUNCTION__, mOpenIndex);
+ pthread_create(&mRecordThread, NULL, dumpVMRecordDataThread, (void *)this);
+
+ AL_UNLOCK(mMutex);
+
+ return NO_ERROR;
+}
+
+status_t SpeechVMRecorder::close() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ AL_LOCK(mThreadStartMutex);
+ mIsDumpThreadStart = false;
+ AL_UNLOCK(mThreadStartMutex);
+
+ AL_LOCK(mMutex);
+ if (mIsVmEnable == false) {
+ ALOGW("-%s(), mIsVmEnable == false, return!!", __FUNCTION__);
+ AL_SIGNAL(mMutex); // wake up thread to exit
+ AL_UNLOCK(mMutex);
+ return INVALID_OPERATION;
+ }
+ // turn off record function
+ SpeechDriverInterface *pSpeechDriver = SpeechDriverFactory::GetInstance()->GetSpeechDriver();
+ if (pSpeechDriver->GetApSideModemStatus(VM_RECORD_STATUS_MASK) == true) {
+ SpeechDriverFactory::GetInstance()->GetSpeechDriver()->VoiceMemoRecordOff();
+ }
+
+ mIsVmEnable = false;
+ AL_SIGNAL(mMutex); // wake up thread to exit
+ AL_UNLOCK(mMutex);
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+uint16_t SpeechVMRecorder::getVmDataFromModem(RingBuf ul_ring_buf) {
+ struct timespec ts_start;
+ struct timespec ts_stop;
+
+ uint64_t time_diff_lock = 0;
+ uint64_t time_diff_copy = 0;
+ uint64_t time_diff_unlock = 0;
+
+
+ audio_get_timespec_monotonic(&ts_start);
+
+ AL_LOCK(mThreadStartMutex);
+
+ if (mIsDumpThreadStart == false) {
+ ALOGD("%s(), mIsDumpThreadStart == false, return.", __FUNCTION__);
+ AL_UNLOCK(mThreadStartMutex);
+ return 0;
+ }
+
+ AL_LOCK(mMutex);
+
+ if (mRingBuf.pBufBase == NULL) {
+ ALOGD("%s(), mRingBuf.pBufBase == NULL, return.", __FUNCTION__);
+ AL_UNLOCK(mMutex);
+ AL_UNLOCK(mThreadStartMutex);
+ return 0;
+ }
+
+ audio_get_timespec_monotonic(&ts_stop);
+ time_diff_lock = get_time_diff_ms(&ts_start, &ts_stop);
+
+ // get free space of internal input buffer
+ uint16_t free_space = RingBuf_getFreeSpace(&mRingBuf);
+ SLOGV("%s(), mRingBuf remain data count: %u, free_space: %u",
+ __FUNCTION__, RingBuf_getDataCount(&mRingBuf), free_space);
+
+ // get data count in share buffer
+ uint16_t ul_data_count = RingBuf_getDataCount(&ul_ring_buf);
+ SLOGV("%s(), ul_ring_buf data count: %u", __FUNCTION__, ul_data_count);
+
+ // check free space for internal input buffer
+ uint16_t copy_data_count = 0;
+ if (ul_data_count <= free_space) {
+ copy_data_count = ul_data_count;
+ } else {
+ ALOGE("%s(), ul_data_count(%u) > free_space(%u)", __FUNCTION__, ul_data_count, free_space);
+ copy_data_count = free_space;
+ }
+
+ // copy data from modem share buffer to internal input buffer
+ if (copy_data_count > 0) {
+ SLOGV("%s(), copy_data_count: %u", __FUNCTION__, copy_data_count);
+ RingBuf_copyFromRingBuf(&mRingBuf, &ul_ring_buf, copy_data_count);
+ }
+
+ audio_get_timespec_monotonic(&ts_stop);
+ time_diff_copy = get_time_diff_ms(&ts_start, &ts_stop);
+
+ // signal
+ AL_SIGNAL(mMutex); // wake up thread to fwrite data.
+ AL_UNLOCK(mMutex);
+ AL_UNLOCK(mThreadStartMutex);
+
+ audio_get_timespec_monotonic(&ts_stop);
+ time_diff_unlock = get_time_diff_ms(&ts_start, &ts_stop);
+
+
+ if (time_diff_unlock > 10) {
+ ALOGW("%s(), time too long, lock %ju, copy %ju, unlock %ju", __FUNCTION__,
+ time_diff_lock,
+ time_diff_copy - time_diff_lock,
+ time_diff_unlock - time_diff_copy);
+ }
+
+ return copy_data_count;
+}
+
+void *SpeechVMRecorder::dumpVMRecordDataThread(void *arg) {
+ pthread_detach(pthread_self());
+
+ char thread_name[128] = {0};
+ CONFIG_THREAD(thread_name, ANDROID_PRIORITY_AUDIO);
+
+ AL_LOCK(gThreadOpenIndexLock);
+ gThreadOpenIndex++;
+ const uint32_t local_open_index = gThreadOpenIndex;
+ AL_UNLOCK(gThreadOpenIndexLock);
+
+ SpeechVMRecorder *pSpeechVMRecorder = (SpeechVMRecorder *)arg;
+ if (pSpeechVMRecorder == NULL) {
+ ALOGW("%s(), pSpeechVMRecorder == NULL!!", __FUNCTION__);
+ pthread_exit(NULL);
+ return NULL;
+ }
+
+ FILE *dumpFile = NULL;
+
+ char *local_buf = NULL;
+ char *sd_card_buf = NULL;
+
+ uint32_t data_count = 0;
+ uint32_t free_space = 0;
+ uint32_t write_bytes = 0;
+
+
+ // open file
+ dumpFile = pSpeechVMRecorder->openFile();
+ if (dumpFile == NULL) {
+ ALOGE("%s(), openFile() fail!! Return.", __FUNCTION__);
+ pthread_exit(NULL);
+ return NULL;
+ }
+
+ AL_LOCK(pSpeechVMRecorder->mThreadStartMutex);
+ AL_LOCK(pSpeechVMRecorder->mMutex);
+
+ // run SpeechVMRecorder::Close() before dumpVMRecordDataThread launched!!
+ if (pSpeechVMRecorder->mIsVmEnable == false ||
+ local_open_index != pSpeechVMRecorder->mOpenIndex) {
+ ALOGW("%s(), mIsVmEnable: %d or index %d != %d!! Return.", __FUNCTION__,
+ pSpeechVMRecorder->mIsVmEnable,
+ local_open_index, pSpeechVMRecorder->mOpenIndex);
+ AL_UNLOCK(pSpeechVMRecorder->mMutex);
+ AL_UNLOCK(pSpeechVMRecorder->mThreadStartMutex);
+ // close file
+ if (dumpFile != NULL) {
+ fclose(dumpFile);
+ dumpFile = NULL;
+ }
+ pthread_exit(NULL);
+ return NULL;
+ }
+
+ // open modem record function
+ SpeechDriverInterface *pSpeechDriver = SpeechDriverFactory::GetInstance()->GetSpeechDriver();
+ status_t retval = pSpeechDriver->VoiceMemoRecordOn();
+ if (retval != NO_ERROR && retval != -ETIMEDOUT) {
+ ALOGE("%s(), VoiceMemoRecordOn() fail!! Return.", __FUNCTION__);
+ pSpeechVMRecorder->mIsVmEnable = false;
+ pSpeechDriver->VoiceMemoRecordOff();
+ AL_UNLOCK(pSpeechVMRecorder->mMutex);
+ AL_UNLOCK(pSpeechVMRecorder->mThreadStartMutex);
+ // close file
+ if (dumpFile != NULL) {
+ fclose(dumpFile);
+ dumpFile = NULL;
+ }
+ pthread_exit(NULL);
+ return NULL;
+ }
+
+ // Internal Input Buffer Initialization
+ AUDIO_ALLOC_CHAR_BUFFER(local_buf, kReadBufferSize);
+ pSpeechVMRecorder->mRingBuf.pBufBase = local_buf;
+ pSpeechVMRecorder->mRingBuf.bufLen = kReadBufferSize;
+ pSpeechVMRecorder->mRingBuf.pRead = pSpeechVMRecorder->mRingBuf.pBufBase;
+ pSpeechVMRecorder->mRingBuf.pWrite = pSpeechVMRecorder->mRingBuf.pBufBase;
+
+ pSpeechVMRecorder->mIsDumpThreadStart = true;
+
+ AL_UNLOCK(pSpeechVMRecorder->mMutex);
+ AL_UNLOCK(pSpeechVMRecorder->mThreadStartMutex);
+
+ AUDIO_ALLOC_CHAR_BUFFER(sd_card_buf, kSdCardBufferSize);
+
+ ALOGD("%s(), pid: %d, tid: %d, VM start, local_open_index: %u",
+ __FUNCTION__, getpid(), gettid(), local_open_index);
+
+ while (1) {
+ // lock & wait data
+ AL_LOCK(pSpeechVMRecorder->mMutex);
+
+ // make sure VM is still recording after fwrite
+ if (pSpeechVMRecorder->mIsVmEnable == true &&
+ local_open_index == pSpeechVMRecorder->mOpenIndex) {
+ data_count = (uint32_t)RingBuf_getDataCount(&pSpeechVMRecorder->mRingBuf);
+ if (data_count == 0) {
+ if (AL_WAIT_MS(pSpeechVMRecorder->mMutex, kCondWaitTimeoutMsec) != 0) {
+ ALOGW("%s(), wait fail", __FUNCTION__);
+ }
+ data_count = (uint32_t)RingBuf_getDataCount(&pSpeechVMRecorder->mRingBuf);
+ }
+ }
+
+ // make sure VM is still recording after conditional wait
+ if (pSpeechVMRecorder->mIsVmEnable == false ||
+ local_open_index != pSpeechVMRecorder->mOpenIndex) {
+ ALOGD("%s(), pid: %d, tid: %d, VM stop, mIsVmEnable: %d or index %d != %d",
+ __FUNCTION__, getpid(), gettid(), pSpeechVMRecorder->mIsVmEnable,
+ local_open_index, pSpeechVMRecorder->mOpenIndex);
+
+ // reset ring buffer
+ if (pSpeechVMRecorder->mRingBuf.pBufBase == local_buf) {
+ memset((void *)&pSpeechVMRecorder->mRingBuf, 0, sizeof(RingBuf));
+ }
+
+ AL_UNLOCK(pSpeechVMRecorder->mMutex);
+ break;
+ }
+
+ if (data_count == 0) {
+ AUD_LOG_W("%s(), data_count == 0, continue", __FUNCTION__);
+ AL_UNLOCK(pSpeechVMRecorder->mMutex);
+ usleep(100);
+ continue;
+ }
+
+ if (data_count > kSdCardBufferSize) {
+ AUD_LOG_W("%s(), data_count %u > kSdCardBufferSize %u!!", __FUNCTION__, data_count, kSdCardBufferSize);
+ data_count = kSdCardBufferSize;
+ }
+ RingBuf_copyToLinear(sd_card_buf, &pSpeechVMRecorder->mRingBuf, data_count);
+ AL_UNLOCK(pSpeechVMRecorder->mMutex);
+
+ // write data to sd card
+ write_bytes = fwrite((void *)sd_card_buf, sizeof(char), data_count, dumpFile);
+ if (write_bytes != data_count) {
+ ALOGE("%s(), write_bytes(%u) != data_count(%u), SD Card might be full!!",
+ __FUNCTION__, write_bytes, data_count);
+ }
+ SLOGV("data_count: %u, write_bytes: %u", data_count, write_bytes);
+ }
+
+ // close file
+ if (dumpFile != NULL) {
+ fflush(dumpFile);
+ fclose(dumpFile);
+ dumpFile = NULL;
+ }
+
+ AUDIO_FREE_POINTER(sd_card_buf);
+ AUDIO_FREE_POINTER(local_buf);
+
+ // VM log recycle mechanism
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_VM_RECYCLE_ON, property_value, "1"); //"1": default on
+ const bool vm_recycle_on = (property_value[0] == '0') ? false : true;
+
+ int ret = 0;
+
+ if (vm_recycle_on == true) {
+ // Get gVMFileList, gNumOfVMFiles, gTotalSizeOfVMFiles
+ memset(gVMFileList, 0, sizeof(gVMFileList));
+ gNumOfVMFiles = 0;
+ gTotalSizeOfVMFiles = 0;
+
+ ret = ftw(kFolderOfVMFile, getVMFileList, FTW_D);
+ ASSERT(ret == 0);
+
+ // Sort file name
+ qsort(gVMFileList, gNumOfVMFiles, sizeof(vm_file_info_t), compareVMFileName);
+ //for(int i = 0; i < gNumOfVMFiles; i++)
+ // ALOGD("%s(), %s, %u", __FUNCTION__, gVMFileList[i].path, gVMFileList[i].size);
+
+ // Remove VM files
+ uint32_t index_vm_file_list = 0;
+ while (gNumOfVMFiles > kMinKeepNumOfVMFiles && gTotalSizeOfVMFiles > kMaxSizeOfAllVMFiles) {
+ ALOGD("%s(), gNumOfVMFiles = %u, gTotalSizeOfVMFiles = %u",
+ __FUNCTION__, gNumOfVMFiles, gTotalSizeOfVMFiles);
+
+ ALOGD("%s(), remove(%s), size = %u",
+ __FUNCTION__, gVMFileList[index_vm_file_list].path, gVMFileList[index_vm_file_list].size);
+ ret = remove(gVMFileList[index_vm_file_list].path);
+
+ if (ret == ENOENT) {
+ ALOGW("%s(), file remove fail(%d)! No such file or directory.", __FUNCTION__, ret);
+ } else if (ret != 0) {
+ ALOGE("%s(), file remove fail(%d)! errno(%d) AP Force Assert.", __FUNCTION__, ret, errno);
+ ASSERT(ret == 0);
+ }
+ gNumOfVMFiles--;
+ gTotalSizeOfVMFiles -= gVMFileList[index_vm_file_list].size;
+
+ index_vm_file_list++;
+ }
+ }
+
+ ALOGD("%s terminated", thread_name);
+ pthread_exit(NULL);
+ return NULL;
+}
+
+
+FILE *SpeechVMRecorder::openFile() {
+ char vm_file_path[kMaxSizeOfVMFileName];
+ memset((void *)vm_file_path, 0, kMaxSizeOfVMFileName);
+
+#if defined(VM_FILENAME_ONLY_USE_VM0_TO_VM7)
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_VM_INDEX, property_value, "0");
+
+ uint8_t vm_file_number = atoi(property_value);
+ sprintf(vm_file_path, "%s_%u.vm", kPrefixOfVMFileName, vm_file_number++);
+
+ sprintf(property_value, "%u", vm_file_number & 0x7);
+ property_set(PROPERTY_KEY_VM_INDEX, property_value);
+#else
+ time_t rawtime;
+ time(&rawtime);
+ struct tm *timeinfo = localtime(&rawtime);
+ audio_strncpy(vm_file_path, kPrefixOfVMFileName, kMaxSizeOfVMFileName);
+ strftime(vm_file_path + kSizeOfPrefixOfVMFileName, kMaxSizeOfVMFileName - kSizeOfPrefixOfVMFileName - 1,
+ "_%Y_%m_%d_%H%M%S.vm", timeinfo);
+#endif
+
+ ALOGD("%s(), vm_file_path: \"%s\"", __FUNCTION__, vm_file_path);
+
+ // check vm_file_path is valid
+ int ret = AudiocheckAndCreateDirectory(vm_file_path);
+ if (ret < 0) {
+ ALOGE("%s(), AudiocheckAndCreateDirectory(%s) fail!!", __FUNCTION__, vm_file_path);
+ return NULL;
+ }
+
+ // open VM file
+ FILE *dumpFile = fopen(vm_file_path, "wb");
+ if (dumpFile == NULL) {
+ ALOGE("%s(), fopen(%s) fail!!", __FUNCTION__, vm_file_path);
+ return NULL;
+ }
+
+ return dumpFile;
+}
+
+/**
+ * CTM Debug for TTY
+ */
+int SpeechVMRecorder::startCtmDebug() {
+ ALOGD("%s()", __FUNCTION__);
+
+ if (mIsCtmDebugStart) { return false; }
+
+ const uint8_t kMaxPathLength = 80;
+ char ctm_file_path_UlIn[kMaxPathLength];
+ char ctm_file_path_DlIn[kMaxPathLength];
+ char ctm_file_path_UlOut[kMaxPathLength];
+ char ctm_file_path_DlOut[kMaxPathLength];
+ memset((void *)ctm_file_path_UlIn, 0, kMaxPathLength);
+ memset((void *)ctm_file_path_DlIn, 0, kMaxPathLength);
+ memset((void *)ctm_file_path_UlOut, 0, kMaxPathLength);
+ memset((void *)ctm_file_path_DlOut, 0, kMaxPathLength);
+ time_t rawtime;
+ time(&rawtime);
+ struct tm *timeinfo = localtime(&rawtime);
+ strftime(ctm_file_path_UlIn, kMaxPathLength,
+ "/data/vendor/audiohal/audio_dump/%Y_%m_%d_%H%M%S_CtmUlIn.pcm", timeinfo);
+ strftime(ctm_file_path_DlIn, kMaxPathLength,
+ "/data/vendor/audiohal/audio_dump/%Y_%m_%d_%H%M%S_CtmDlIn.pcm", timeinfo);
+ strftime(ctm_file_path_UlOut, kMaxPathLength,
+ "/data/vendor/audiohal/audio_dump/%Y_%m_%d_%H%M%S_CtmUlOut.pcm", timeinfo);
+ strftime(ctm_file_path_DlOut, kMaxPathLength,
+ "/data/vendor/audiohal/audio_dump/%Y_%m_%d_%H%M%S_CtmDlOut.pcm", timeinfo);
+ int ret;
+ ret = AudiocheckAndCreateDirectory(ctm_file_path_UlIn);
+ if (ret < 0) {
+ ALOGE("%s(), AudiocheckAndCreateDirectory(%s) fail!!", __FUNCTION__, ctm_file_path_UlIn);
+ return UNKNOWN_ERROR;
+ }
+ ret = AudiocheckAndCreateDirectory(ctm_file_path_DlIn);
+ if (ret < 0) {
+ ALOGE("%s(), AudiocheckAndCreateDirectory(%s) fail!!", __FUNCTION__, ctm_file_path_DlIn);
+ return UNKNOWN_ERROR;
+ }
+ ret = AudiocheckAndCreateDirectory(ctm_file_path_UlOut);
+ if (ret < 0) {
+ ALOGE("%s(), AudiocheckAndCreateDirectory(%s) fail!!", __FUNCTION__, ctm_file_path_UlOut);
+ return UNKNOWN_ERROR;
+ }
+ ret = AudiocheckAndCreateDirectory(ctm_file_path_DlOut);
+ if (ret < 0) {
+ ALOGE("%s(), AudiocheckAndCreateDirectory(%s) fail!!", __FUNCTION__, ctm_file_path_DlOut);
+ return UNKNOWN_ERROR;
+ }
+ pCtmDumpFileUlIn = fopen(ctm_file_path_UlIn, "wb");
+ pCtmDumpFileDlIn = fopen(ctm_file_path_DlIn, "wb");
+ pCtmDumpFileUlOut = fopen(ctm_file_path_UlOut, "wb");
+ pCtmDumpFileDlOut = fopen(ctm_file_path_DlOut, "wb");
+
+ if (pCtmDumpFileUlIn == NULL) { ALOGW("Fail to Open pCtmDumpFileUlIn"); }
+ if (pCtmDumpFileDlIn == NULL) { ALOGW("Fail to Open pCtmDumpFileDlIn"); }
+ if (pCtmDumpFileUlOut == NULL) { ALOGW("Fail to Open pCtmDumpFileUlOut"); }
+ if (pCtmDumpFileDlOut == NULL) { ALOGW("Fail to Open pCtmDumpFileDlOut"); }
+
+ mIsCtmDebugStart = true;
+
+ return true;
+}
+
+int SpeechVMRecorder::stopCtmDebug() {
+ ALOGD("%s()", __FUNCTION__);
+
+ if (!mIsCtmDebugStart) { return false; }
+
+ mIsCtmDebugStart = false;
+
+ fclose(pCtmDumpFileUlIn);
+ fclose(pCtmDumpFileDlIn);
+ fclose(pCtmDumpFileUlOut);
+ fclose(pCtmDumpFileDlOut);
+ return true;
+}
+
+void SpeechVMRecorder::getCtmDebugDataFromModem(RingBuf ul_ring_buf, FILE *pFile) {
+ int InpBuf_freeSpace = 0;
+ int ShareBuf_dataCnt = 0;
+
+ if (mIsCtmDebugStart == false) {
+ ALOGW("%s(), mIsCtmDebugStart=%d, return.", __FUNCTION__, mIsCtmDebugStart);
+ return;
+ }
+
+ // get data count in share buffer
+ ShareBuf_dataCnt = RingBuf_getDataCount(&ul_ring_buf);
+ if (ShareBuf_dataCnt >= 0) {
+ char linear_buffer[ShareBuf_dataCnt];
+ char *pM2AShareBufEnd = ul_ring_buf.pBufBase + ul_ring_buf.bufLen;
+ if (ul_ring_buf.pRead + ShareBuf_dataCnt <= pM2AShareBufEnd) {
+ memcpy(linear_buffer, ul_ring_buf.pRead, ShareBuf_dataCnt);
+ } else {
+ uint32_t r2e = pM2AShareBufEnd - ul_ring_buf.pRead;
+ memcpy(linear_buffer, ul_ring_buf.pRead, r2e);
+ memcpy((void *)(linear_buffer + r2e), ul_ring_buf.pBufBase, ShareBuf_dataCnt - r2e);
+ }
+
+ fwrite(linear_buffer, sizeof(char), ShareBuf_dataCnt, pFile);
+ }
+}
+
+};
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechVoiceCustomLogger.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechVoiceCustomLogger.cpp
new file mode 100644
index 0000000..4e3f086
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/V3/speech_driver/SpeechVoiceCustomLogger.cpp
@@ -0,0 +1,371 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "SpeechVoiceCustomLogger.h"
+
+#include <sys/prctl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <cutils/properties.h>
+#include <utils/threads.h>
+
+#include <ftw.h>
+#include <hardware_legacy/power.h>
+
+
+
+//#define FORCE_ENABLE_VCL
+#define LOG_TAG "SpeechVoiceCustomLogger"
+
+namespace android {
+
+/*==============================================================================
+ * Property keys
+ *============================================================================*/
+const char* PROPERTY_KEY_VCL_ON = "persist.vendor.audiohal.vcl_on";
+const char* PROPERTY_KEY_VCL_RECYCLE_ON = "persist.vendor.audiohal.vcl_recycle_on";
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+static const char VCL_RECORD_WAKELOCK_NAME[] = "VCL_RECORD_WAKELOCK";
+
+static const uint32_t kCondWaitTimeoutMsec = 100; // 100 ms (modem local buf: 10k, and EPL has 2304 byte for each frame (20 ms))
+
+static const uint32_t kReadBufferSize = 0x4000; // 16 k
+
+
+/*==============================================================================
+ * VCL File Recycle
+ *============================================================================*/
+static const uint32_t kMaxNumOfVCLFiles = 4096;
+
+static const uint32_t kMinKeepNumOfVCLFiles = 16; // keep at least 16 files which will not be removed
+static const uint32_t kMaxSizeOfAllVCLFiles = 209715200; // Total > 200 M
+
+static const char kFolderOfVCLFile[] = "/data/vendor/audiohal/audio_dump/";
+static const char kPrefixOfVCLFileName[] = "/data/vendor/audiohal/audio_dump/VCL";
+static const uint32_t kSizeOfPrefixOfVCLFileName = sizeof(kPrefixOfVCLFileName) - 1;
+static const uint32_t kMaxSizeOfVCLFileName = 128;
+
+typedef struct {
+ char path[kMaxSizeOfVCLFileName];
+ uint32_t size;
+} vcl_file_info_t;
+
+static vcl_file_info_t gVCLFileList[kMaxNumOfVCLFiles];
+static uint32_t gNumOfVCLFiles = 0;
+static uint32_t gTotalSizeOfVCLFiles; // Total size of VCL files in SD card
+
+static int GetVCLFileList(const char *path, const struct stat *sb, int typeflag) {
+ if (strncmp(path, kPrefixOfVCLFileName, kSizeOfPrefixOfVCLFileName) != 0) {
+ return 0;
+ }
+
+ if (gNumOfVCLFiles >= kMaxNumOfVCLFiles) {
+ return 0;
+ }
+
+ // path
+ audio_strncpy(gVCLFileList[gNumOfVCLFiles].path, path, kMaxSizeOfVCLFileName);
+
+ // size
+ gVCLFileList[gNumOfVCLFiles].size = sb->st_size;
+ gTotalSizeOfVCLFiles += sb->st_size;
+
+ // increase index
+ gNumOfVCLFiles++;
+
+ return 0; // To tell ftw() to continue
+}
+
+static int CompareVCLFileName(const void *a, const void *b) {
+ return strcmp(((vcl_file_info_t *)a)->path,
+ ((vcl_file_info_t *)b)->path);
+}
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+SpeechVoiceCustomLogger *SpeechVoiceCustomLogger::mSpeechVoiceCustomLogger = NULL;
+SpeechVoiceCustomLogger *SpeechVoiceCustomLogger::GetInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+
+ if (mSpeechVoiceCustomLogger == NULL) {
+ mSpeechVoiceCustomLogger = new SpeechVoiceCustomLogger();
+ }
+ ASSERT(mSpeechVoiceCustomLogger != NULL);
+ return mSpeechVoiceCustomLogger;
+}
+
+SpeechVoiceCustomLogger::SpeechVoiceCustomLogger() {
+ mStarting = false;
+ mEnable = false;
+ mVCLEnable = false;
+
+ mRecordThread = 0;
+
+ mDumpFile = NULL;
+ memset((void *)&mRingBuf, 0, sizeof(RingBuf));
+}
+
+SpeechVoiceCustomLogger::~SpeechVoiceCustomLogger() {
+ Close();
+}
+
+
+bool SpeechVoiceCustomLogger::UpdateVCLSwitch() {
+#if defined(FORCE_ENABLE_VCL)
+ mVCLEnable = true;
+#else
+ // VCL log recycle mechanism
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_VCL_ON, property_value, "0"); //"0": default off
+ mVCLEnable = (property_value[0] == '0') ? false : true;
+#endif
+ ALOGD("-%s(), mVCLEnable=%d", __FUNCTION__, mVCLEnable);
+ return mVCLEnable;
+}
+
+status_t SpeechVoiceCustomLogger::Open() {
+ AL_LOCK(mMutex);
+
+ ALOGD("+%s()", __FUNCTION__);
+
+ ASSERT(mEnable == false);
+
+ int ret = acquire_wake_lock(PARTIAL_WAKE_LOCK, VCL_RECORD_WAKELOCK_NAME);
+ ALOGD("%s(), acquire_wake_lock: %s, return %d.", __FUNCTION__, VCL_RECORD_WAKELOCK_NAME, ret);
+
+ // create another thread to avoid fwrite() block CCCI read thread
+ pthread_create(&mRecordThread, NULL, DumpVCLRecordDataThread, (void *)this);
+
+ AL_UNLOCK(mMutex);
+ mEnable = true;
+
+ ALOGD("-%s(), mEnable=%d ", __FUNCTION__, mEnable);
+ return NO_ERROR;
+}
+
+status_t SpeechVoiceCustomLogger::Close() {
+ AL_LOCK(mMutex);
+
+ ALOGD("+%s()", __FUNCTION__);
+
+ if (mEnable == false) {
+ ALOGW("-%s(), mEnable == false, return!!", __FUNCTION__);
+ AL_UNLOCK(mMutex);
+ return INVALID_OPERATION;
+ }
+
+ mStarting = false;
+
+ int ret = 0;
+
+
+ // VCL log recycle mechanism
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_VCL_RECYCLE_ON, property_value, "1"); //"1": default on
+ const bool vcl_recycle_on = (property_value[0] == '0') ? false : true;
+
+ if (vcl_recycle_on == true) {
+ memset(gVCLFileList, 0, sizeof(gVCLFileList));
+ gNumOfVCLFiles = 0;
+ gTotalSizeOfVCLFiles = 0;
+
+ ret = ftw(kFolderOfVCLFile, GetVCLFileList, FTW_D);
+ ASSERT(ret == 0);
+
+ // Sort file name
+ qsort(gVCLFileList, gNumOfVCLFiles, sizeof(vcl_file_info_t), CompareVCLFileName);
+
+ // Remove VCL files
+ uint32_t index_vcl_file_list = 0;
+ while (gNumOfVCLFiles > kMinKeepNumOfVCLFiles && gTotalSizeOfVCLFiles > kMaxSizeOfAllVCLFiles) {
+ ALOGD("%s(), gNumOfVCLFiles = %lu, gTotalSizeOfVCLFiles = %lu", __FUNCTION__, gNumOfVCLFiles, gTotalSizeOfVCLFiles);
+
+ ALOGD("%s(), remove(%s), size = %lu", __FUNCTION__, gVCLFileList[index_vcl_file_list].path, gVCLFileList[index_vcl_file_list].size);
+ ret = remove(gVCLFileList[index_vcl_file_list].path);
+ ASSERT(ret == 0);
+
+ gNumOfVCLFiles--;
+ gTotalSizeOfVCLFiles -= gVCLFileList[index_vcl_file_list].size;
+
+ index_vcl_file_list++;
+ }
+ }
+
+ // release wake lock
+ ret = release_wake_lock(VCL_RECORD_WAKELOCK_NAME);
+ ALOGD("%s(), release_wake_lock:%s return %d.", __FUNCTION__, VCL_RECORD_WAKELOCK_NAME, ret);
+ mEnable = false;
+ AL_SIGNAL(mMutex); // wake up thread to exit
+ AL_UNLOCK(mMutex);
+
+ ALOGD("-%s()", __FUNCTION__);
+ return NO_ERROR;
+}
+
+status_t SpeechVoiceCustomLogger::OpenFile() {
+ char vcl_file_path[kMaxSizeOfVCLFileName];
+ memset((void *)vcl_file_path, 0, kMaxSizeOfVCLFileName);
+
+ time_t rawtime;
+ time(&rawtime);
+ struct tm *timeinfo = localtime(&rawtime);
+ audio_strncpy(vcl_file_path, kPrefixOfVCLFileName, kMaxSizeOfVCLFileName);
+ strftime(vcl_file_path + kSizeOfPrefixOfVCLFileName, kMaxSizeOfVCLFileName - kSizeOfPrefixOfVCLFileName - 1, "_%Y_%m_%d_%H%M%S.pcm", timeinfo);
+
+ ALOGD("%s(), vcl_file_path: \"%s\"", __FUNCTION__, vcl_file_path);
+
+ // check vcl_file_path is valid
+ int ret = AudiocheckAndCreateDirectory(vcl_file_path);
+ if (ret < 0) {
+ ALOGE("%s(), AudiocheckAndCreateDirectory(%s) fail!!", __FUNCTION__, vcl_file_path);
+ return UNKNOWN_ERROR;
+ }
+
+ // open VCL file
+ mDumpFile = fopen(vcl_file_path, "wb");
+ if (mDumpFile == NULL) {
+ ALOGE("%s(), fopen(%s) fail!!", __FUNCTION__, vcl_file_path);
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+uint16_t SpeechVoiceCustomLogger::CopyBufferToVCL(RingBuf ul_ring_buf) {
+ AL_LOCK(mMutex);
+
+ if (mStarting == false) {
+ ALOGD("%s(), mStarting == false, return.", __FUNCTION__);
+ AL_SIGNAL(mMutex); // wake up thread to exit
+ AL_UNLOCK(mMutex);
+ return 0;
+ }
+
+ // get free space of internal input buffer
+ uint16_t free_space = RingBuf_getFreeSpace(&mRingBuf);
+ SLOGV("%s(), mRingBuf remain data count: %u, free_space: %u", __FUNCTION__, RingBuf_getDataCount(&mRingBuf), free_space);
+
+ // get data count in share buffer
+ uint16_t ul_data_count = RingBuf_getDataCount(&ul_ring_buf);
+ SLOGV("%s(), ul_ring_buf data count: %u", __FUNCTION__, ul_data_count);
+
+ // check free space for internal input buffer
+ uint16_t copy_data_count = 0;
+ if (ul_data_count <= free_space) {
+ copy_data_count = ul_data_count;
+ } else {
+ ALOGE("%s(), ul_data_count(%u) > free_space(%u)", __FUNCTION__, ul_data_count, free_space);
+ copy_data_count = free_space;
+ }
+
+ // copy data from modem share buffer to internal input buffer
+ if (copy_data_count > 0) {
+ SLOGV("%s(), copy_data_count: %u", __FUNCTION__, copy_data_count);
+ RingBuf_copyFromRingBuf(&mRingBuf, &ul_ring_buf, copy_data_count);
+ }
+
+ // signal
+ AL_SIGNAL(mMutex); // wake up thread to fwrite data.
+ AL_UNLOCK(mMutex);
+
+ return copy_data_count;
+}
+
+void *SpeechVoiceCustomLogger::DumpVCLRecordDataThread(void *arg) {
+ pthread_detach(pthread_self());
+
+ // Adjust thread priority
+ prctl(PR_SET_NAME, (unsigned long)__FUNCTION__, 0, 0, 0);
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+
+ ALOGD("%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid());
+
+ SpeechVoiceCustomLogger *pSpeechVoiceCustomLogger = (SpeechVoiceCustomLogger *)arg;
+ RingBuf &ring_buf = pSpeechVoiceCustomLogger->mRingBuf;
+
+ // open file
+ if (pSpeechVoiceCustomLogger->OpenFile() != NO_ERROR) {
+ pSpeechVoiceCustomLogger->mEnable = false;
+ pthread_exit(NULL);
+ return 0;
+ }
+ // Internal Input Buffer Initialization
+ pSpeechVoiceCustomLogger->mRingBuf.pBufBase = new char[kReadBufferSize];
+ pSpeechVoiceCustomLogger->mRingBuf.bufLen = kReadBufferSize;
+ pSpeechVoiceCustomLogger->mRingBuf.pRead = pSpeechVoiceCustomLogger->mRingBuf.pBufBase;
+ pSpeechVoiceCustomLogger->mRingBuf.pWrite = pSpeechVoiceCustomLogger->mRingBuf.pBufBase;
+
+ ASSERT(pSpeechVoiceCustomLogger->mRingBuf.pBufBase != NULL);
+ memset(pSpeechVoiceCustomLogger->mRingBuf.pBufBase, 0, pSpeechVoiceCustomLogger->mRingBuf.bufLen);
+
+ pSpeechVoiceCustomLogger->mStarting = true;
+
+ while (1) {
+ // lock & wait data
+ AL_LOCK(pSpeechVoiceCustomLogger->mMutex);
+ if (AL_WAIT_MS(pSpeechVoiceCustomLogger->mMutex, kCondWaitTimeoutMsec) != 0) {
+ ALOGW("%s(), waitRelative fail", __FUNCTION__);
+ }
+
+ // make sure VCL is still recording after conditional wait
+ if (pSpeechVoiceCustomLogger->mEnable == false) {
+
+ // close file
+ if (pSpeechVoiceCustomLogger->mDumpFile != NULL) {
+ fflush(pSpeechVoiceCustomLogger->mDumpFile);
+ fclose(pSpeechVoiceCustomLogger->mDumpFile);
+ pSpeechVoiceCustomLogger->mDumpFile = NULL;
+ }
+
+ // release local ring buffer
+ if (pSpeechVoiceCustomLogger->mRingBuf.pBufBase != NULL) {
+ delete []pSpeechVoiceCustomLogger->mRingBuf.pBufBase;
+ pSpeechVoiceCustomLogger->mRingBuf.pBufBase = NULL;
+ pSpeechVoiceCustomLogger->mRingBuf.pRead = NULL;
+ pSpeechVoiceCustomLogger->mRingBuf.pWrite = NULL;
+ pSpeechVoiceCustomLogger->mRingBuf.bufLen = 0;
+ }
+
+ ALOGD("%s(), pid: %d, tid: %d, mEnable == false, break.", __FUNCTION__, getpid(), gettid());
+ AL_UNLOCK(pSpeechVoiceCustomLogger->mMutex);
+ break;
+ }
+
+ // write data to sd card
+ const uint16_t data_count = RingBuf_getDataCount(&ring_buf);
+ uint16_t write_bytes = 0;
+
+ if (data_count > 0) {
+ const char *end = ring_buf.pBufBase + ring_buf.bufLen;
+ if (ring_buf.pRead <= ring_buf.pWrite) {
+ write_bytes += fwrite((void *)ring_buf.pRead, sizeof(char), data_count, pSpeechVoiceCustomLogger->mDumpFile);
+ } else {
+ int r2e = end - ring_buf.pRead;
+ write_bytes += fwrite((void *)ring_buf.pRead, sizeof(char), r2e, pSpeechVoiceCustomLogger->mDumpFile);
+ write_bytes += fwrite((void *)ring_buf.pBufBase, sizeof(char), data_count - r2e, pSpeechVoiceCustomLogger->mDumpFile);
+ }
+
+ ring_buf.pRead += write_bytes;
+ if (ring_buf.pRead >= end) { ring_buf.pRead -= ring_buf.bufLen; }
+
+ SLOGV("%s(), data_count: %u, write_bytes: %u", __FUNCTION__, data_count, write_bytes);
+ }
+
+ if (write_bytes != data_count) {
+ ALOGE("%s(), write_bytes(%d) != data_count(%d), SD Card might be full!!", __FUNCTION__, write_bytes, data_count);
+ }
+
+ // unlock
+ AL_UNLOCK(pSpeechVoiceCustomLogger->mMutex);
+ }
+
+ pthread_exit(NULL);
+ return 0;
+}
+
+};
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioCustEncryptClient.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioCustEncryptClient.cpp
new file mode 100644
index 0000000..289c8d6
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioCustEncryptClient.cpp
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+/*******************************************************************************
+ *
+ * Filename:
+ * ---------
+ * AudioCustEncryptClient.cpp
+ *
+ * Project:
+ * --------
+ * Android
+ *
+ * Description:
+ * ------------
+ * This file a client for AudioCustEncrypt
+ *
+ * Author:
+ * -------
+ * Tina Tsai
+ *
+ *******************************************************************************/
+#include "AudioCustEncryptClient.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioCustEncryptClient"
+
+namespace android {
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioCustEncryptClient *AudioCustEncryptClient::mAudioCustEncryptClient = NULL;
+AudioCustEncryptClient *AudioCustEncryptClient::GetInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+
+ if (mAudioCustEncryptClient == NULL) {
+ mAudioCustEncryptClient = new AudioCustEncryptClient();
+ }
+ ASSERT(mAudioCustEncryptClient != NULL);
+ return mAudioCustEncryptClient;
+}
+
+AudioCustEncryptClient::AudioCustEncryptClient() {
+ ALOGD("%s()", __FUNCTION__);
+ acpOpsInited = 0;
+ Init();
+}
+
+AudioCustEncryptClient::~AudioCustEncryptClient() {
+ ALOGD("%s()", __FUNCTION__);
+ Deinit();
+}
+
+void AudioCustEncryptClient::Init(void) {
+ const char *error;
+ const char *funName = NULL;
+ ALOGD("%s(), acpOpsInited(%d)", __FUNCTION__, acpOpsInited);
+
+ if (acpOpsInited == 0) {
+ ALOGD("%s(), init AcpOps struct", __FUNCTION__);
+
+ /* dlopen */
+ handle = dlopen("libaudiocustencrypt.so", RTLD_LAZY);
+ if (handle == NULL) {
+ ALOGE("%s(), dlopen fail! (%s)\n", __FUNCTION__, dlerror());
+ } else {
+ dlerror(); /* Clear any existing error */
+ /* dlsym */
+ funName = "Initial";
+ ALOGD("%s(), dlsym %s", __FUNCTION__, funName);
+ Initial = (int (*)(void)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ funName = "EncryptProcess";
+ ALOGD("%s(), dlsym %s", __FUNCTION__, funName);
+ EncryptProcess = (int (*)(char *TargetBuf, char *SourceBuf, uint16_t SourceByte)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ funName = "DecryptProcess";
+ ALOGD("%s(), dlsym %s", __FUNCTION__, funName);
+ DecryptProcess = (int (*)(char *TargetBuf, char *SourceBuf, uint16_t SourceByte)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ acpOpsInited = 1;
+ }
+ }
+
+ ALOGD("-%s(), acpOpsInited(%d)", __FUNCTION__, acpOpsInited);
+}
+
+void AudioCustEncryptClient::Deinit() {
+ ALOGD("+%s(), acpOpsInited (%d)\n", __FUNCTION__, acpOpsInited);
+ if (acpOpsInited != 0) {
+ dlclose(handle);
+ acpOpsInited = 0;
+ }
+ ALOGD("-%s(), acpOpsInited (%d)\n", __FUNCTION__, acpOpsInited);
+}
+
+
+}
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioCustParamClient.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioCustParamClient.cpp
new file mode 100644
index 0000000..a57d254
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioCustParamClient.cpp
@@ -0,0 +1,360 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioCustParamClient.h"
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "AudioCustParamClient"
+
+namespace android {
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+AudioCustParamClient *AudioCustParamClient::mAudioCustParamClient = NULL;
+AudioCustParamClient *AudioCustParamClient::GetInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+
+ if (mAudioCustParamClient == NULL) {
+ mAudioCustParamClient = new AudioCustParamClient();
+ }
+ ASSERT(mAudioCustParamClient != NULL);
+ return mAudioCustParamClient;
+}
+
+AudioCustParamClient::AudioCustParamClient() {
+ ALOGD("%s()", __FUNCTION__);
+ acpOpsInited = 0;
+ QueryFeatureSupportInfo = NULL;
+ GetNBSpeechParamFromNVRam = NULL;
+ SetNBSpeechParamToNVRam = NULL;
+ GetDualMicSpeechParamFromNVRam = NULL;
+ SetDualMicSpeechParamToNVRam = NULL;
+ GetWBSpeechParamFromNVRam = NULL;
+ SetWBSpeechParamToNVRam = NULL;
+ GetMedParamFromNV = NULL;
+ SetMedParamToNV = NULL;
+ GetVolumeVer1ParamFromNV = NULL;
+ SetVolumeVer1ParamToNV = NULL;
+ GetAudioCustomParamFromNV = NULL;
+ SetAudioCustomParamToNV = NULL;
+ GetAudioGainTableParamFromNV = NULL;
+ SetAudioGainTableParamToNV = NULL;
+ GetHdRecordParamFromNV = NULL;
+ SetHdRecordParamToNV = NULL;
+ GetHdRecordSceneTableFromNV = NULL;
+ SetHdRecordSceneTableToNV = NULL;
+ GetAudioVoIPParamFromNV = NULL;
+ SetAudioVoIPParamToNV = NULL;
+ GetAudioHFPParamFromNV = NULL;
+ SetAudioHFPParamToNV = NULL;
+ GetMagiConSpeechParamFromNVRam = NULL;
+ SetMagiConSpeechParamToNVRam = NULL;
+ GetHACSpeechParamFromNVRam = NULL;
+ SetHACSpeechParamToNVRam = NULL;
+ GetNBSpeechLpbkParamFromNVRam = NULL;
+ SetNBSpeechLpbkParamToNVRam = NULL;
+ GetAudioBTGainParamFromNV = NULL;
+ SetAudioBTGainParamToNV = NULL;
+
+ mGetNumMicSupport = NULL;
+
+ init();
+
+ memset(&mDeviceParam, 0, sizeof(struct AudioDeviceParam));
+ initParam();
+}
+
+AudioCustParamClient::~AudioCustParamClient() {
+ ALOGD("%s()", __FUNCTION__);
+ deinit();
+}
+
+void AudioCustParamClient::init(void) {
+ const char *error;
+ const char *funName = NULL;
+ ALOGD("%s(), acpOpsInited(%d)", __FUNCTION__, acpOpsInited);
+
+ if (acpOpsInited == 0) {
+ ALOGD("%s(), init AcpOps struct", __FUNCTION__);
+
+ /* dlopen */
+ handle = dlopen("libaudiocustparam_vendor.so", RTLD_LAZY);
+ if (handle == NULL) {
+ ALOGE("%s(), dlopen fail! (%s)\n", __FUNCTION__, dlerror());
+ } else {
+ dlerror(); /* Clear any existing error */
+
+ /* dlsym */
+ // QueryFeatureSupportInfo
+ funName = "QueryFeatureSupportInfo";
+ QueryFeatureSupportInfo = (uint32_t (*)(void)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+ // NB speech parameters
+ funName = "GetNBSpeechParamFromNVRam";
+ GetNBSpeechParamFromNVRam = (int (*)(AUDIO_CUSTOM_PARAM_STRUCT * pSphParamNB)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ funName = "SetNBSpeechParamToNVRam";
+ SetNBSpeechParamToNVRam = (int (*)(AUDIO_CUSTOM_PARAM_STRUCT * pSphParamNB)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ // Dual mic speech parameters
+ funName = "GetDualMicSpeechParamFromNVRam";
+ GetDualMicSpeechParamFromNVRam = (int (*)(AUDIO_CUSTOM_EXTRA_PARAM_STRUCT * pSphParamDualMic)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ funName = "SetDualMicSpeechParamToNVRam";
+ SetDualMicSpeechParamToNVRam = (int (*)(AUDIO_CUSTOM_EXTRA_PARAM_STRUCT * pSphParamDualMic)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ // WB speech parameters
+ funName = "GetWBSpeechParamFromNVRam";
+ GetWBSpeechParamFromNVRam = (int (*)(AUDIO_CUSTOM_WB_PARAM_STRUCT * pSphParamWB)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ funName = "SetWBSpeechParamToNVRam";
+ SetWBSpeechParamToNVRam = (int (*)(AUDIO_CUSTOM_WB_PARAM_STRUCT * pSphParamWB)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ // Med param parameter
+ funName = "GetMedParamFromNV";
+ GetMedParamFromNV = (int (*)(AUDIO_PARAM_MED_STRUCT * pPara)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ funName = "SetMedParamToNV";
+ SetMedParamToNV = (int (*)(AUDIO_PARAM_MED_STRUCT * pPara)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ // VolumeVer1 parameter
+ funName = "GetVolumeVer1ParamFromNV";
+ GetVolumeVer1ParamFromNV = (int (*)(AUDIO_VER1_CUSTOM_VOLUME_STRUCT * pPara)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ funName = "SetVolumeVer1ParamToNV";
+ SetVolumeVer1ParamToNV = (int (*)(AUDIO_VER1_CUSTOM_VOLUME_STRUCT * pPara)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ // Audio Custom Paramete
+ funName = "GetAudioCustomParamFromNV";
+ GetAudioCustomParamFromNV = (int (*)(AUDIO_VOLUME_CUSTOM_STRUCT * pPara)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ funName = "SetAudioCustomParamToNV";
+ SetAudioCustomParamToNV = (int (*)(AUDIO_VOLUME_CUSTOM_STRUCT * pPara)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ // AudioGainTable Parameter
+ funName = "GetAudioGainTableParamFromNV";
+ GetAudioGainTableParamFromNV = (int (*)(AUDIO_GAIN_TABLE_STRUCT * pPara)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ funName = "SetAudioGainTableParamToNV";
+ SetAudioGainTableParamToNV = (int (*)(AUDIO_GAIN_TABLE_STRUCT * pPara)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ // Audio HD record parameters
+ funName = "GetHdRecordParamFromNV";
+ GetHdRecordParamFromNV = (int (*)(AUDIO_HD_RECORD_PARAM_STRUCT * pPara)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ funName = "SetHdRecordParamToNV";
+ SetHdRecordParamToNV = (int (*)(AUDIO_HD_RECORD_PARAM_STRUCT * pPara)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ // Audio HD record scene table
+ funName = "GetHdRecordSceneTableFromNV";
+ GetHdRecordSceneTableFromNV = (int (*)(AUDIO_HD_RECORD_SCENE_TABLE_STRUCT * pPara)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ funName = "SetHdRecordSceneTableToNV";
+ SetHdRecordSceneTableToNV = (int (*)(AUDIO_HD_RECORD_SCENE_TABLE_STRUCT * pPara)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ // Audio VoIP Parameters
+ funName = "GetAudioVoIPParamFromNV";
+ GetAudioVoIPParamFromNV = (int (*)(AUDIO_VOIP_PARAM_STRUCT * pPara)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ funName = "SetAudioVoIPParamToNV";
+ SetAudioVoIPParamToNV = (int (*)(AUDIO_VOIP_PARAM_STRUCT * pPara)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ // Audio HFP Parameters
+ funName = "GetAudioHFPParamFromNV";
+ GetAudioHFPParamFromNV = (int (*)(AUDIO_HFP_PARAM_STRUCT * pPara)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ funName = "SetAudioHFPParamToNV";
+ SetAudioHFPParamToNV = (int (*)(AUDIO_HFP_PARAM_STRUCT * pPara)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ // Magic Conference Call parameters
+ funName = "GetMagiConSpeechParamFromNVRam";
+ GetMagiConSpeechParamFromNVRam = (int (*)(AUDIO_CUSTOM_MAGI_CONFERENCE_STRUCT * pSphParamMagiCon)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ funName = "SetMagiConSpeechParamToNVRam";
+ SetMagiConSpeechParamToNVRam = (int (*)(AUDIO_CUSTOM_MAGI_CONFERENCE_STRUCT * pSphParamMagiCon)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ // HAC parameters
+ funName = "GetHACSpeechParamFromNVRam";
+ GetHACSpeechParamFromNVRam = (int (*)(AUDIO_CUSTOM_HAC_PARAM_STRUCT * pSphParamHAC)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ funName = "SetHACSpeechParamToNVRam";
+ SetHACSpeechParamToNVRam = (int (*)(AUDIO_CUSTOM_HAC_PARAM_STRUCT * pSphParamHAC)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ // Speech Loopback parameters
+ funName = "GetNBSpeechLpbkParamFromNVRam";
+ GetNBSpeechLpbkParamFromNVRam = (int (*)(AUDIO_CUSTOM_SPEECH_LPBK_PARAM_STRUCT * pSphParamNBLpbk)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ funName = "SetNBSpeechLpbkParamToNVRam";
+ SetNBSpeechLpbkParamToNVRam = (int (*)(AUDIO_CUSTOM_SPEECH_LPBK_PARAM_STRUCT * pSphParamNBLpbk)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ // BT Gain parameter
+ funName = "GetAudioBTGainParamFromNV";
+ GetAudioBTGainParamFromNV = (int (*)(AUDIO_BT_GAIN_STRUCT * pParaBT)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ funName = "SetAudioBTGainParamToNV";
+ SetAudioBTGainParamToNV = (int (*)(AUDIO_BT_GAIN_STRUCT * pParaBT)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ // mGetNumMicSupport
+ funName = "getNumMicSupport";
+ mGetNumMicSupport = (int (*)(void)) dlsym(handle, funName);
+ error = dlerror();
+ if (error != NULL) {
+ ALOGE("%s(), dlsym %s fail. (%s)\n", __FUNCTION__, funName, error);
+ }
+
+ acpOpsInited = 1;
+ }
+ }
+}
+
+void AudioCustParamClient::deinit() {
+ ALOGD("%s(), acpOpsInited (%d)\n", __FUNCTION__, acpOpsInited);
+ if (acpOpsInited != 0) {
+ dlclose(handle);
+ acpOpsInited = 0;
+ }
+}
+
+void AudioCustParamClient::initParam() {
+ if (mGetNumMicSupport) {
+ mDeviceParam.numMicSupport = mGetNumMicSupport();
+ } else {
+ ALOGE("%s(), mGetNumMicSupport == NULL", __FUNCTION__);
+ ASSERT(0);
+ mDeviceParam.numMicSupport = 2;
+ }
+}
+
+int AudioCustParamClient::getNumMicSupport() {
+ return mDeviceParam.numMicSupport;
+}
+
+}
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioEventThreadManager.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioEventThreadManager.cpp
new file mode 100644
index 0000000..934bd66
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioEventThreadManager.cpp
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <AudioEventThreadManager.h>
+#include <AudioAssert.h>
+#include <utils/threads.h>
+#include <SpeechUtility.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioEventThreadManager"
+
+namespace android {
+
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+/**
+ * callback function structure
+ */
+struct CallbackStruc {
+ CallbackFunc cb;
+ void *regArg;
+ void *arg;
+};
+
+/*
+ * =============================================================================
+ * AudioEventThread
+ * =============================================================================
+ */
+class AudioEventThread {
+public:
+ AudioEventThread(AudioEventType audioEventType);
+ virtual ~AudioEventThread();
+
+ pthread_t mThreadHandle;
+ AudioEventType mAudioEventType;
+ std::vector<CallbackStruc> mCallbackStrucs;
+ void *mArg;
+ bool mEventThreadEnable;
+
+ void signal(void *arg);
+ int addCallback(CallbackFunc callbackFunc, void *regArg);
+
+private:
+ static void *eventThread(void *arg);
+ AudioLock mLock;
+};
+
+AudioEventThread::AudioEventThread(AudioEventType audioEventType) {
+ int retval = 0;
+ ALOGD("%s(), audioEventType = %d", __FUNCTION__, audioEventType);
+ mAudioEventType = audioEventType;
+ mArg = NULL;
+ mThreadHandle = 0;
+
+ retval = pthread_create(&mThreadHandle, NULL,
+ AudioEventThread::eventThread,
+ (void *)this);
+ mEventThreadEnable = true;
+ ASSERT(retval == 0);
+
+}
+
+AudioEventThread::~AudioEventThread() {
+ ALOGD("%s()", __FUNCTION__);
+ mEventThreadEnable = false;
+ signal(NULL);
+ pthread_join(mThreadHandle, NULL);
+}
+
+void AudioEventThread::signal(void *arg) {
+ AL_LOCK(mLock);
+ mArg = arg;
+ AL_SIGNAL(mLock);
+ AL_UNLOCK(mLock);
+}
+
+int AudioEventThread::addCallback(CallbackFunc callbackFunc, void *regArg) {
+ struct CallbackStruc callback;
+ callback.cb = callbackFunc;
+ callback.regArg = regArg;
+ callback.arg = NULL;
+ mCallbackStrucs.push_back(callback);
+ return 0;
+}
+
+void *AudioEventThread::eventThread(void *arg) {
+ char thread_name[128];
+
+ AudioEventThread *pAudioEventThread = NULL;
+ CONFIG_THREAD(thread_name, ANDROID_PRIORITY_AUDIO);
+
+ pAudioEventThread = static_cast<AudioEventThread *>(arg);
+ if (pAudioEventThread == NULL) {
+ ALOGE("%s(), NULL!! pAudioEventThread %p", __FUNCTION__, pAudioEventThread);
+ goto PROCESS_EVENT_THREAD_DONE;
+ }
+
+ AL_LOCK(pAudioEventThread->mLock);
+ while (pAudioEventThread->mEventThreadEnable == true) {
+ // sleep until signal comes
+ AL_WAIT_NO_TIMEOUT(pAudioEventThread->mLock);
+ ALOGV("%s(), signal comes, mEventThreadEnable=%d", __FUNCTION__, pAudioEventThread->mEventThreadEnable);
+
+ //signal callbacks
+ for (int idxCallback = 0; idxCallback < (int) pAudioEventThread->mCallbackStrucs.size(); idxCallback ++) {
+ pAudioEventThread->mCallbackStrucs.at(idxCallback).arg = pAudioEventThread->mArg;
+
+ (*pAudioEventThread->mCallbackStrucs.at(idxCallback).cb)
+ ((int)pAudioEventThread->mAudioEventType,
+ (void *)pAudioEventThread->mCallbackStrucs.at(idxCallback).regArg,
+ (void *)pAudioEventThread->mCallbackStrucs.at(idxCallback).arg);
+ }
+ }
+ AL_UNLOCK(pAudioEventThread->mLock);
+
+PROCESS_EVENT_THREAD_DONE:
+ ALOGD("%s terminated", thread_name);
+ pthread_exit(NULL);
+ return NULL;
+}
+
+/*
+ * =============================================================================
+ * Singleton Pattern
+ * =============================================================================
+ */
+AudioEventThreadManager *AudioEventThreadManager::uniqueAudioEventThreadManager = NULL;
+
+AudioEventThreadManager *AudioEventThreadManager::getInstance() {
+ static AudioLock getInstanceLock;
+ AL_AUTOLOCK(getInstanceLock);
+
+ if (uniqueAudioEventThreadManager == NULL) {
+ uniqueAudioEventThreadManager = new AudioEventThreadManager();
+ }
+ ASSERT(uniqueAudioEventThreadManager != NULL);
+ return uniqueAudioEventThreadManager;
+}
+
+/*
+ * =============================================================================
+ * AudioEventThreadManager
+ * =============================================================================
+ */
+AudioEventThreadManager::~AudioEventThreadManager() {
+ ALOGD("%s()", __FUNCTION__);
+ if (!mEventThreads.empty()) {
+ mEventThreads.clear();
+ }
+}
+
+int AudioEventThreadManager::registerCallback(AudioEventType audioEventType,
+ CallbackFunc callbackFunc, void *regArg) {
+ ALOGD("%s(), audioEventType=%d, callbackFunc = %p", __FUNCTION__, audioEventType, callbackFunc);
+ bool isCallbackFound = false;
+ if (hasAudioEventThread(audioEventType)) {
+ AudioEventThread *audioEvnetHandler = getAudioEventThread(audioEventType);
+ for (int idxCallback = 0; idxCallback < (int)audioEvnetHandler->mCallbackStrucs.size(); idxCallback ++) {
+ if (callbackFunc == audioEvnetHandler->mCallbackStrucs.at(idxCallback).cb &&
+ regArg == audioEvnetHandler->mCallbackStrucs.at(idxCallback).regArg) {
+ ALOGW("%s(), callback already existed. return audioEventType=%d, callbackFunc = %p",
+ __FUNCTION__, audioEventType, callbackFunc);
+ return 1;
+ }
+ }
+ audioEvnetHandler->addCallback(callbackFunc, regArg);
+ ALOGD("%s(), add callbackFunc(%p) to audioEventType(%d), ", __FUNCTION__, callbackFunc, audioEventType);
+ } else {
+ AudioEventThread *audioEvnetHandler = new AudioEventThread(audioEventType);
+ audioEvnetHandler->addCallback(callbackFunc, regArg);
+ mEventThreads.push_back(audioEvnetHandler);
+ ALOGD("%s(), add new audioEventType=%d, callbackFunc = %p", __FUNCTION__, audioEventType, callbackFunc);
+ }
+ return 0;
+}
+
+int AudioEventThreadManager::unregisterCallback(AudioEventType audioEventType, CallbackFunc callbackFunc, void *regArg) {
+ ALOGD("+%s(), audioEventType=%d, callbackFunc = %p", __FUNCTION__, audioEventType, callbackFunc);
+ bool isCallbackFound = false;
+
+ for (int idxEvent = 0; idxEvent < (int) mEventThreads.size(); idxEvent ++) {
+ AudioEventThread *audioEvnetHandler = mEventThreads.at(idxEvent);
+ if (audioEventType == audioEvnetHandler->mAudioEventType) {
+ for (int idxCallback = 0; idxCallback < (int)audioEvnetHandler->mCallbackStrucs.size(); idxCallback ++) {
+ if (callbackFunc == audioEvnetHandler->mCallbackStrucs.at(idxCallback).cb &&
+ regArg == audioEvnetHandler->mCallbackStrucs.at(idxCallback).regArg) {
+ isCallbackFound = true;
+ audioEvnetHandler->mCallbackStrucs.erase(audioEvnetHandler->mCallbackStrucs.begin() + idxCallback);
+ if (audioEvnetHandler->mCallbackStrucs.size() == 0) {
+ mEventThreads.at(idxEvent)->mEventThreadEnable = false;
+ mEventThreads.at(idxEvent)->signal(NULL);
+ pthread_join(audioEvnetHandler->mThreadHandle, NULL);
+ mEventThreads.erase(mEventThreads.begin() + idxEvent);
+ }
+ break;
+ }
+ }
+ }
+ }
+ if (isCallbackFound) {
+ ALOGD("-%s(), audioEventType=%d, callbackFunc = %p", __FUNCTION__, audioEventType, callbackFunc);
+ return 0;
+ } else {
+ ALOGW("-%s(), can not find callbackFunc(%p) to audioEventType(%d), return",
+ __FUNCTION__, callbackFunc, audioEventType);
+ return 1;
+ }
+}
+
+int AudioEventThreadManager::unregisterCallback(AudioEventType audioEventType) {
+ ALOGD("+%s(), audioEventType=%d", __FUNCTION__, audioEventType);
+ for (int idxEvent = 0; idxEvent < (int) mEventThreads.size(); idxEvent ++) {
+ if (audioEventType == mEventThreads.at(idxEvent)->mAudioEventType) {
+ mEventThreads.at(idxEvent)->mEventThreadEnable = false;
+ mEventThreads.at(idxEvent)->signal(NULL);
+ mEventThreads.at(idxEvent)->mCallbackStrucs.clear();
+ pthread_join(mEventThreads.at(idxEvent)->mThreadHandle, NULL);
+ mEventThreads.erase(mEventThreads.begin() + idxEvent);
+ break;
+ }
+ }
+ ALOGD("-%s(), audioEventType=%d", __FUNCTION__, audioEventType);
+ return 0;
+}
+
+int AudioEventThreadManager::notifyCallback(AudioEventType audioEventType, void *arg) {
+ int retval = 0;
+ int idxEvent = 0;
+ bool isThreadFound = false;
+
+ for (idxEvent = 0; idxEvent < (int) mEventThreads.size(); idxEvent ++) {
+ if (audioEventType == mEventThreads.at(idxEvent)->mAudioEventType) {
+ isThreadFound = true;
+ break;
+ }
+ }
+ if (isThreadFound) {
+ mEventThreads.at(idxEvent)->signal(arg);
+ ALOGD("%s(), audioEventType(0x%x), idxEvent=%d", __FUNCTION__, audioEventType, idxEvent);
+ } else {
+ ALOGW("%s(), audioEventType(0x%x), arg(%p), no event callback registered. skip",
+ __FUNCTION__, audioEventType, arg);
+ }
+ return 0;
+}
+
+bool AudioEventThreadManager::hasAudioEventThread(AudioEventType audioEventType) {
+ bool isThreadExisted = false;
+ for (int idxEvent = 0; idxEvent < (int) mEventThreads.size(); idxEvent ++) {
+ if (audioEventType == mEventThreads.at(idxEvent)->mAudioEventType) {
+ isThreadExisted = true;
+ break;
+ }
+ }
+ return isThreadExisted;
+}
+
+AudioEventThread *AudioEventThreadManager::getAudioEventThread(AudioEventType audioEventType) {
+ AudioEventThread *audioEvnetHandler = NULL;
+ for (int idxEvent = 0; idxEvent < (int) mEventThreads.size(); idxEvent ++) {
+ if (audioEventType == mEventThreads.at(idxEvent)->mAudioEventType) {
+ audioEvnetHandler = mEventThreads.at(idxEvent);
+ break;
+ }
+ }
+ return audioEvnetHandler;
+}
+
+
+} /* end of namespace android */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioFtmBase.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioFtmBase.cpp
new file mode 100644
index 0000000..883bfb8
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioFtmBase.cpp
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioFtmBase.h"
+
+#include <utils/threads.h>
+#include <utils/Log.h>
+
+#include "AudioAssert.h"
+
+#include "AudioFtm.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioFtmBase"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+android::AudioFtmBaseVirtual *pfuncGetAudioFtmByDL(void) {
+ return android::AudioFtmBase::createAudioFtmInstance();
+}
+#ifdef __cplusplus
+}
+#endif
+
+
+namespace android {
+
+AudioFtmBase *AudioFtmBase::createAudioFtmInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+
+ return AudioFtm::getInstance();
+}
+
+AudioFtmBase::AudioFtmBase() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+AudioFtmBase::~AudioFtmBase() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+/// Codec
+void AudioFtmBase::Audio_Set_Speaker_Vol(int level __unused) {
+ ALOGW("%s()", __FUNCTION__);
+}
+void AudioFtmBase::Audio_Set_Speaker_On(int Channel __unused) {
+ ALOGW("%s()", __FUNCTION__);
+}
+void AudioFtmBase::Audio_Set_Speaker_Off(int Channel __unused) {
+ ALOGW("%s()", __FUNCTION__);
+}
+void AudioFtmBase::Audio_Set_HeadPhone_On(int Channel __unused) {
+ ALOGW("%s()", __FUNCTION__);
+}
+void AudioFtmBase::Audio_Set_HeadPhone_Off(int Channel __unused) {
+ ALOGW("%s()", __FUNCTION__);
+}
+void AudioFtmBase::Audio_Set_Earpiece_On() {
+ ALOGW("%s()", __FUNCTION__);
+}
+void AudioFtmBase::Audio_Set_Earpiece_Off() {
+ ALOGW("%s()", __FUNCTION__);
+}
+
+
+/// for factory mode & Meta mode (Analog part)
+void AudioFtmBase::FTM_AnaLpk_on(void) {
+ ALOGW("%s()", __FUNCTION__);
+}
+
+void AudioFtmBase::FTM_AnaLpk_off(void) {
+ ALOGW("%s()", __FUNCTION__);
+}
+
+int AudioFtmBase::SineGenTest(char sinegen_test __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+
+/// Output device test
+int AudioFtmBase::RecieverTest(char receiver_test __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+
+int AudioFtmBase::LouderSPKTest(char left_channel __unused, char right_channel __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+int AudioFtmBase::EarphoneTest(char bEnable __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+int AudioFtmBase::EarphoneTestLR(char bLR __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+
+/// Input device test
+int AudioFtmBase::SpecificBuildInMicTest(char type __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+
+/// Speaker over current test
+int AudioFtmBase::Audio_READ_SPK_OC_STA(void) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+int AudioFtmBase::LouderSPKOCTest(char left_channel __unused, char right_channel __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+
+
+/// Loopback
+int AudioFtmBase::PhoneMic_Receiver_Loopback(char echoflag __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+int AudioFtmBase::PhoneMic_EarphoneLR_Loopback(char echoflag __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+int AudioFtmBase::PhoneMic_SpkLR_Loopback(char echoflag __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+int AudioFtmBase::HeadsetMic_EarphoneLR_Loopback(char bEnable __unused, char bHeadsetMic __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+int AudioFtmBase::HeadsetMic_SpkLR_Loopback(char echoflag __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+
+int AudioFtmBase::HeadsetMic_Receiver_Loopback(char bEnable __unused, char bHeadsetMic __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+
+int AudioFtmBase::PhoneMic_Receiver_Acoustic_Loopback(int Acoustic_Type __unused, int *Acoustic_Status_Flag __unused, int bHeadset_Output __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+
+
+/// FM / mATV
+int AudioFtmBase::FMLoopbackTest(char bEnable __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+
+int AudioFtmBase::Audio_FM_I2S_Play(char bEnable __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+int AudioFtmBase::Audio_MATV_I2S_Play(int enable_flag __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+int AudioFtmBase::Audio_FMTX_Play(bool Enable __unused, unsigned int Freq __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+
+int AudioFtmBase::ATV_AudPlay_On(void) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+int AudioFtmBase::ATV_AudPlay_Off(void) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+unsigned int AudioFtmBase::ATV_AudioWrite(void *buffer __unused, unsigned int bytes __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return true;
+}
+
+
+/// HDMI
+int AudioFtmBase::HDMI_SineGenPlayback(bool bEnable __unused, int dSamplingRate __unused) {
+ ALOGE("%s() is not supported!!", __FUNCTION__);
+ return false;
+}
+
+
+/// Vibration Speaker
+int AudioFtmBase::SetVibSpkCalibrationParam(void *cali_param __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return 0;
+}
+
+uint32_t AudioFtmBase::GetVibSpkCalibrationStatus() {
+ ALOGW("%s()", __FUNCTION__);
+ return 0;
+}
+
+void AudioFtmBase::SetVibSpkEnable(bool enable __unused, uint32_t freq __unused) {
+ ALOGW("%s()", __FUNCTION__);
+}
+
+void AudioFtmBase::SetVibSpkRampControl(uint8_t rampcontrol __unused) {
+ ALOGW("%s()", __FUNCTION__);
+}
+
+bool AudioFtmBase::ReadAuxadcData(int channel __unused, int *value __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return false;
+}
+
+void AudioFtmBase::SetStreamOutPostProcessBypass(bool flag __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return;
+}
+
+bool AudioFtmBase::SpeakerCalibration(int calibrateStage __unused) {
+ ALOGW("%s()", __FUNCTION__);
+ return false;
+}
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioMTKDec.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioMTKDec.cpp
new file mode 100644
index 0000000..0e4dbc4
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioMTKDec.cpp
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: MediaTekProprietary
+
+#include <stdlib.h>
+#include "AudioMTKDec.h"
+#include "mp3dec_exp.h"
+
+#define LOG_TAG "AudioMTKDec"
+
+namespace android {
+
+
+AudioMTKDecHandlerBase::AudioMTKDecHandlerBase() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+AudioMTKDecHandlerBase::~AudioMTKDecHandlerBase() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+AudioMTKDecHandlerMP3::AudioMTKDecHandlerMP3() :
+ AudioMTKDecHandlerBase(),
+ mMp3Dec(NULL),
+ mMp3InitFlag(false) {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+AudioMTKDecHandlerMP3::~AudioMTKDecHandlerMP3() {
+ if (mMp3Dec) {
+ if (mMp3Dec->working_buf1) {
+ free(mMp3Dec->working_buf1);
+ mMp3Dec->working_buf1 = NULL;
+ }
+
+ if (mMp3Dec->working_buf2) {
+ free(mMp3Dec->working_buf2);
+ mMp3Dec->working_buf2 = NULL;
+ }
+
+ free(mMp3Dec);
+ mMp3Dec = NULL;
+ }
+}
+
+bool AudioMTKDecHandlerMP3::InitAudioDecoder() {
+ if (!mMp3InitFlag) {
+ ALOGD("+%s()", __FUNCTION__);
+ mMp3Dec = (mp3DecEngine *)malloc(sizeof(mp3DecEngine));
+ if (mMp3Dec == NULL) {
+ ALOGD("%s() allocate engine fail", __FUNCTION__);
+ }
+ memset(mMp3Dec, 0, sizeof(mp3DecEngine));
+
+ MP3Dec_GetMemSize(&mMp3Dec->min_bs_size, &mMp3Dec->pcm_size, &mMp3Dec->workingbuf_size1, &mMp3Dec->workingbuf_size2);
+ ALOGD("%s >> min_bs_size=%u, pcm_size=%u, workingbuf_size1=%u,workingbuf_size2=%u", __FUNCTION__,
+ mMp3Dec->min_bs_size, mMp3Dec->pcm_size, mMp3Dec->workingbuf_size1, mMp3Dec->workingbuf_size2);
+
+ mMp3Dec->working_buf1 = malloc(mMp3Dec->workingbuf_size1);
+ mMp3Dec->working_buf2 = malloc(mMp3Dec->workingbuf_size2);
+ mMp3Dec->pcm_buf = malloc(mMp3Dec->pcm_size);
+
+ if ((NULL == mMp3Dec->working_buf1) || (NULL == mMp3Dec->working_buf2)) {
+ ALOGD("%s() allocate working buf fail", __FUNCTION__);
+ return false;
+ }
+
+ memset(mMp3Dec->working_buf1, 0, mMp3Dec->workingbuf_size1);
+ memset(mMp3Dec->working_buf2, 0, mMp3Dec->workingbuf_size2);
+ memset(mMp3Dec->pcm_buf, 0, mMp3Dec->pcm_size);
+
+ if (mMp3Dec->handle == NULL) {
+ mMp3Dec->handle = MP3Dec_Init(mMp3Dec->working_buf1, mMp3Dec->working_buf2);
+
+ if (mMp3Dec->handle == NULL) {
+ ALOGD("%s() Init Decoder Fail", __FUNCTION__);
+
+ if (mMp3Dec->working_buf1) {
+ free(mMp3Dec->working_buf1);
+ mMp3Dec->working_buf1 = NULL;
+ }
+
+ if (mMp3Dec->working_buf2) {
+ free(mMp3Dec->working_buf2);
+ mMp3Dec->working_buf2 = NULL;
+ }
+
+ if (mMp3Dec->pcm_buf) {
+ free(mMp3Dec->pcm_buf);
+ mMp3Dec->pcm_buf = NULL;
+ }
+
+ free(mMp3Dec);
+ mMp3Dec = NULL;
+ return false;
+ }
+ }
+
+ mMp3InitFlag = true;
+ mEndFlag = false;
+ ALOGD("-%s()", __FUNCTION__);
+ }
+
+ return true;
+}
+
+void AudioMTKDecHandlerMP3::DeinitAudioDecoder() {
+ ALOGD("+%s()", __FUNCTION__);
+
+ if ((mMp3InitFlag == true) && (mMp3Dec != NULL)) {
+ if (mMp3Dec->working_buf1) {
+ free(mMp3Dec->working_buf1);
+ mMp3Dec->working_buf1 = NULL;
+ }
+
+ if (mMp3Dec->working_buf2) {
+ free(mMp3Dec->working_buf2);
+ mMp3Dec->working_buf2 = NULL;
+ }
+
+ if (mMp3Dec->pcm_buf) {
+ free(mMp3Dec->pcm_buf);
+ mMp3Dec->pcm_buf = NULL;
+ }
+
+ free(mMp3Dec);
+ mMp3Dec = NULL;
+ mMp3InitFlag = false;
+ }
+ ALOGD("-%s()", __FUNCTION__);
+}
+
+int32_t AudioMTKDecHandlerMP3::ParseAudioHeader(int8_t *inputBsbuf) {
+ int32_t ver_idx, mp3_version, layer, bit_rate_idx, sample_rate_idx, channel_idx;
+ struct mp3_header header;
+ ALOGD("+%s()", __FUNCTION__);
+
+ memcpy((void *)&header, (void *)inputBsbuf, sizeof(header));
+
+ /* check sync bits */
+ if ((header.sync & MP3_SYNC) != MP3_SYNC) {
+ ALOGD("%s(), Can't find sync word", __FUNCTION__);
+ return -1;
+ }
+ ver_idx = (header.sync >> 11) & 0x03;
+ mp3_version = ver_idx == 0 ? MPEG25 : ((ver_idx & 0x1) ? MPEG1 : MPEG2);
+ layer = 4 - ((header.sync >> 9) & 0x03);
+ bit_rate_idx = ((header.format1 >> 4) & 0x0f);
+ sample_rate_idx = ((header.format1 >> 2) & 0x03);
+ channel_idx = ((header.format2 >> 6) & 0x03);
+
+ if (sample_rate_idx == 3 || layer == 4 || bit_rate_idx == 15) {
+ ALOGD("%s(), Error: Can't find valid header", __FUNCTION__);
+ return -1;
+ }
+ mChannel = (channel_idx == MONO ? 1 : 2);
+ mSampleRate = mp3_sample_rates[mp3_version][sample_rate_idx];
+ mBitRate = (mp3_bit_rates[mp3_version][layer - 1][bit_rate_idx]) * 1000;
+
+ ALOGD("-%s()", __FUNCTION__);
+ return 0;
+}
+
+int32_t AudioMTKDecHandlerMP3::BsbufferSize() {
+ return mMp3Dec->min_bs_size;
+}
+
+int32_t AudioMTKDecHandlerMP3::PcmbufferSize() {
+ return mMp3Dec->pcm_size;
+}
+
+int32_t AudioMTKDecHandlerMP3::DecodeAudio(int8_t *inputBsbuf, int8_t *outputPcmbuf, int32_t BsbufSize) {
+ ALOGV("%s():%p %p", __FUNCTION__, inputBsbuf, outputPcmbuf);
+ int32_t ret;
+ ret = MP3Dec_Decode(mMp3Dec->handle, (void *)mMp3Dec->pcm_buf, (void *)inputBsbuf, BsbufSize, (void *)inputBsbuf);
+ memcpy(outputPcmbuf, mMp3Dec->pcm_buf, mMp3Dec->pcm_size);
+
+ return ret;
+}
+
+}
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioMTKFilter.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioMTKFilter.cpp
new file mode 100644
index 0000000..918f342
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioMTKFilter.cpp
@@ -0,0 +1,922 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#define LOG_TAG "AudioMTKFilter"
+
+#define MTK_LOG_ENABLE 1
+#include <cutils/compiler.h>
+
+#include "audio_custom_exp.h"
+#include "AudioCustParamClient.h"
+#include"AudioMTKFilter.h"
+#include <log/log.h>
+
+#include "AudioType.h"
+#include "AudioUtility.h"
+//#if defined(MTK_VIBSPK_SUPPORT)
+#include "AudioCompFltCustParam.h"
+#include "AudioVIBSPKControl.h"
+//#endif
+#include "AudioFtm.h"
+#include "AudioMTKFilter.h"
+
+#ifndef VIBSPK_DEFAULT_FREQ
+#define VIBSPK_DEFAULT_FREQ (156) //141~330 Hz
+#endif
+
+//#define MERGE_HCF_AUDENH_WITH_UI_OPTION
+
+namespace {
+
+#define AUDIO_COMPENSATION_FLT_MODE AUDIO_CMP_FLT_LOUDNESS_COMP
+#define AUDIO_COMPENSATION_FLT_MODE_LOW_LATENCY_WITH_LIMITER AUDIO_CMP_FLT_LOUDNESS_COMP_LOW_LATENCY_WITH_LIMITER
+#define AUDIO_COMPENSATION_FLT_MODE_LOW_LATENCY_WITHOUT_LIMITER AUDIO_CMP_FLT_LOUDNESS_COMP_LOW_LATENCY_WITHOUT_LIMITER
+
+
+
+}
+
+
+namespace android {
+#define PROPERTY_KEY_AUDENH_SWITCH_STATE "persist.vendor.audiohal.audenh_state";
+#define AUDENH_SWITCH_DEFAULT_STATE (0)
+
+AudioMTKFilter::AudioMTKFilter(
+ AudioCompFltType_t type,
+ AudioComFltMode_t mode,
+ uint32_t sampleRate,
+ uint32_t channel,
+ uint32_t format,
+ size_t bufferSize) :
+ bIsZeroCoeff(false),
+ mType(type),
+ mMode(mode),
+ mSampleTate(sampleRate),
+ mChannel(channel),
+ mFormat(format),
+ mBufferSize(bufferSize),
+ mFilter(NULL),
+ mStart(false),
+ mActive(false) {
+}
+
+AudioMTKFilter::~AudioMTKFilter() {
+ if (mFilter) {
+ mFilter->close();
+ deleteMtkAudioLoud(mFilter);
+ mFilter = NULL;
+ }
+}
+
+status_t AudioMTKFilter::init() {
+ Mutex::Autolock _l(&mLock);
+
+ if (mType < AUDIO_COMP_FLT_NUM && mFilter == NULL) {
+ mFilter = newMtkAudioLoud(mType);
+
+ if (NULL != mFilter) {
+ int format = (mFormat == AUDIO_FORMAT_PCM_32_BIT ? BLOUD_IN_Q1P31_OUT_Q1P31 : BLOUD_IN_Q1P15_OUT_Q1P15);
+ mFilter->setParameter(BLOUD_PAR_SET_PCM_FORMAT, (void *)((long)format));
+ mFilter->setParameter(BLOUD_PAR_SET_CHANNEL_NUMBER, (void *)((long)mChannel));
+ mFilter->setParameter(BLOUD_PAR_SET_SAMPLE_RATE, (void *)((long)mSampleTate));
+ mFilter->setParameter(BLOUD_PAR_SET_WORK_MODE, (void *)((long)mMode));
+ mFilter->setParameter(BLOUD_PAR_SET_USE_DEFAULT_PARAM, (void *)NULL);
+#if defined(ENABLE_STEREO_SPEAKER)&&defined(MTK_STEREO_SPK_ACF_TUNING_SUPPORT)
+ if (AUDIO_COMP_FLT_AUDIO == mType) {
+#if defined(MTK_AUDIO_BLOUD_CUSTOMPARAMETER_V4)
+ mFilter->setParameter(BLOUD_PAR_SET_SEP_LR_FILTER, (void *)true);
+#endif
+ mFilter->setParameter(BLOUD_PAR_SET_USE_DEFAULT_PARAM_SUB, (void *)NULL);
+ }
+#else
+ if (AUDIO_COMP_FLT_AUDIO == mType) {
+
+#if defined(MTK_AUDIO_BLOUD_CUSTOMPARAMETER_V4)
+ mFilter->setParameter(BLOUD_PAR_SET_SEP_LR_FILTER, (void *)false);
+#else
+ mFilter->setParameter(BLOUD_PAR_SET_USE_DEFAULT_PARAM_SUB, (void *)NULL);
+#endif
+ }
+#endif
+ bIsZeroCoeff = mFilter->isZeroCoeffFilter();
+ return NO_ERROR;
+ } else {
+ ALOGE("Error: %s Line#%d mType %d mFilter %p", __FUNCTION__, __LINE__, mType, mFilter);
+ return NO_INIT;
+ }
+ } else {
+ ALOGE("Error: %s Line#%d mType %d mFilter %p", __FUNCTION__, __LINE__, mType, mFilter);
+ return INVALID_OPERATION;
+ }
+}
+
+void AudioMTKFilter::start(bool bFirstDataWrite) {
+ Mutex::Autolock _l(mLock);
+ if (mFilter && !mActive) {
+ ALOGD("AudioMTKFilter::start() type %d mode %d bFirstDataWrite %d", mType, mMode, bFirstDataWrite);
+
+ mFilter->setWorkMode(mChannel, mSampleTate, mMode, bFirstDataWrite ? false : true);
+ mFilter->open();
+ mStart = true;
+ mActive = true;
+ }
+ return;
+}
+
+void AudioMTKFilter::stop() {
+ Mutex::Autolock _l(mLock);
+ if (mFilter && mActive) {
+ ALOGD("AudioMTKFilter::stop() type %d mode %d", mType, mMode);
+ //mFilter->Stop();
+ mFilter->resetBuffer();
+ mFilter->close();
+ mStart = false;
+ mActive = false;
+ }
+ return;
+}
+
+void AudioMTKFilter::pause() {
+ Mutex::Autolock _l(mLock);
+ if (mFilter && mActive) {
+ ALOGD("AudioMTKFilter::pause() type %d mode %d", mType, mMode);
+ if (mFilter->change2ByPass() == ACE_SUCCESS) {
+ mActive = false;
+ }
+ }
+}
+
+void AudioMTKFilter::resume() {
+ Mutex::Autolock _l(mLock);
+ if (mFilter && !mActive) {
+ ALOGD("AudioMTKFilter::resume() type %d mode %d", mType, mMode);
+ if (mFilter->change2Normal() == ACE_SUCCESS) {
+ mActive = true;
+ }
+ }
+}
+
+bool AudioMTKFilter::isStart() {
+ Mutex::Autolock _l(mLock);
+ return mStart;
+}
+
+bool AudioMTKFilter::isActive() {
+ Mutex::Autolock _l(mLock);
+ return mActive;
+}
+
+void AudioMTKFilter::setParameter(void *param) {
+ Mutex::Autolock _l(mLock);
+ if (mFilter) {
+ ALOGD("AudioMTKFilter::setParameter type %d mode %d mActive %d", mType, mMode, mActive);
+ mFilter->resetBuffer();
+ mFilter->close();
+ mFilter->setParameter(BLOUD_PAR_SET_CHANNEL_NUMBER, (void *)((long)mChannel));
+ mFilter->setParameter(BLOUD_PAR_SET_SAMPLE_RATE, (void *)((long)mSampleTate));
+ mFilter->setParameter(BLOUD_PAR_SET_WORK_MODE, (void *)((long)mMode));
+ mFilter->setParameter(BLOUD_PAR_SET_PREVIEW_PARAM, (void *)param);
+ mFilter->open();
+ if (!mActive && mStart) {
+ mFilter->change2ByPass();
+ }
+
+ bIsZeroCoeff = mFilter->isZeroCoeffFilter();
+ }
+}
+
+void AudioMTKFilter::setOutputGain(int32_t gain, uint32_t ramp_sample_cnt) {
+ Mutex::Autolock _l(mLock);
+ if (mFilter != NULL) {
+ mFilter->setOutputGain(gain, ramp_sample_cnt);
+ }
+ return;
+}
+
+void AudioMTKFilter::setFilterParam(unsigned int fc, unsigned int bw, int th) {
+ Mutex::Autolock _l(mLock);
+ if (mFilter != NULL) {
+ mFilter->setNotchFilterParam(fc, bw, th);
+ }
+ return;
+}
+
+void AudioMTKFilter::setParameter2Sub(void *param) {
+#if (defined(ENABLE_STEREO_SPEAKER)&&defined(MTK_STEREO_SPK_ACF_TUNING_SUPPORT))||(!defined(MTK_AUDIO_BLOUD_CUSTOMPARAMETER_V4))
+
+ Mutex::Autolock _l(mLock);
+ if (mFilter) {
+ ALOGV("AudioMTKFilter::setParameter2Sub type %d mode %d mActive %d", mType, mMode, mActive);
+ mFilter->resetBuffer();
+ mFilter->close();
+ mFilter->setParameter(BLOUD_PAR_SET_CHANNEL_NUMBER, (void *)((long)mChannel));
+ mFilter->setParameter(BLOUD_PAR_SET_SAMPLE_RATE, (void *)((long)mSampleTate));
+ mFilter->setParameter(BLOUD_PAR_SET_WORK_MODE, (void *)((long)mMode));
+ mFilter->setParameter(BLOUD_PAR_SET_PREVIEW_PARAM_SUB, (void *)param);
+ mFilter->open();
+ if (!mActive && mStart) {
+ mFilter->change2ByPass();
+ }
+ }
+#else
+ ALOGD("UnSupport Stereo Speaker.");
+#endif
+}
+
+
+uint32_t AudioMTKFilter::process(void *inBuffer, uint32_t bytes, void *outBuffer, uint32_t outBytes) {
+ // if return 0, means CompFilter can't do anything. Caller should use input buffer to write to Hw.
+ // do post process
+ Mutex::Autolock _l(mLock);
+ if (mFilter && mStart) {
+ //SXLOGD("AudioMTKFilter::process type %d mode %d", mType, mMode);
+ uint32_t inBytes = bytes;
+ uint32_t outBytes2 = outBytes;
+
+ mFilter->process((short *)inBuffer, &inBytes, (short *)outBuffer, &outBytes2);
+ //SXLOGD("AudioMTKFilter::process type %d mode %d", mType, mMode);
+ return outBytes2;
+ }
+ return 0;
+}
+
+
+//filter manager
+#undef LOG_TAG
+#define LOG_TAG "AudioMTKFilterManager"
+
+AudioMTKFilterManager::AudioMTKFilterManager(
+ uint32_t sampleRate,
+ uint32_t channel,
+ uint32_t format,
+ size_t bufferSize)
+ : mSamplerate(sampleRate),
+ mChannel(channel),
+ mFormat(format),
+ mBufferSize(bufferSize),
+ mFixedParam(false),
+ mSpeakerFilter(NULL),
+ mHeadphoneFilter(NULL),
+ mEnhanceFilter(NULL),
+ //#if defined(MTK_VIBSPK_SUPPORT)
+ mVIBSPKFilter(NULL),
+ //#endif
+ mVibspkAddToneFilter(NULL),
+ mBuffer(NULL),
+ mDevices(0) {
+}
+
+AudioMTKFilterManager::~AudioMTKFilterManager() {
+ deinit();
+}
+void AudioMTKFilterManager::deinit() {
+ if (mSpeakerFilter) {
+ mSpeakerFilter->stop();
+ delete mSpeakerFilter;
+ mSpeakerFilter = NULL;
+ }
+ if (mHeadphoneFilter) {
+ mHeadphoneFilter->stop();
+ delete mHeadphoneFilter;
+ mHeadphoneFilter = NULL;
+ }
+ if (mEnhanceFilter) {
+ mEnhanceFilter->stop();
+ delete mEnhanceFilter;
+ mEnhanceFilter = NULL;
+ }
+ if (mVIBSPKFilter) {
+ mVIBSPKFilter->stop();
+ delete mVIBSPKFilter;
+ mVIBSPKFilter = NULL;
+ }
+ if (mVibspkAddToneFilter) {
+ delete mVibspkAddToneFilter;
+ mVibspkAddToneFilter = NULL;
+ }
+ if (mBuffer) {
+ delete[] mBuffer;
+ mBuffer = NULL;
+ }
+}
+status_t AudioMTKFilterManager::init(uint32_t flags) {
+ bool bInitFail = false;
+ do {
+#if defined(ENABLE_AUDIO_COMPENSATION_FILTER)
+ AudioComFltMode_t mSpeakerFilterMode;
+ if (flags & AUDIO_OUTPUT_FLAG_FAST) {
+ if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+ mSpeakerFilterMode = AUDIO_COMPENSATION_FLT_MODE_LOW_LATENCY_WITH_LIMITER; // with limiter
+ } else {
+ mSpeakerFilterMode = AUDIO_COMPENSATION_FLT_MODE_LOW_LATENCY_WITHOUT_LIMITER; // without limiter
+ }
+ } else {
+ mSpeakerFilterMode = AUDIO_COMPENSATION_FLT_MODE;
+ }
+ mSpeakerFilter = new AudioMTKFilter(AUDIO_COMP_FLT_AUDIO, mSpeakerFilterMode,
+ mSamplerate, mChannel, mFormat, mBufferSize);
+ if (mSpeakerFilter == NULL) {
+ ALOGE("Error: %s Line#%d", __FUNCTION__, __LINE__);
+ bInitFail = true;
+ break;
+ } else {
+ if (mSpeakerFilter->init() != NO_ERROR) {
+ ALOGE("Error: %s Line#%d", __FUNCTION__, __LINE__);
+ bInitFail = true;
+ break;
+ }
+ }
+#endif
+
+#if defined(ENABLE_HEADPHONE_COMPENSATION_FILTER)
+ mHeadphoneFilter = new AudioMTKFilter(AUDIO_COMP_FLT_HEADPHONE, AUDIO_CMP_FLT_LOUDNESS_COMP_HEADPHONE,
+ mSamplerate, mChannel, mFormat, mBufferSize);
+ if (mHeadphoneFilter == NULL) {
+ ALOGE("Error: %s Line#%d", __FUNCTION__, __LINE__);
+ bInitFail = true;
+ break;
+ } else {
+ if (mHeadphoneFilter->init() != NO_ERROR) {
+ ALOGE("Error: %s Line#%d", __FUNCTION__, __LINE__);
+ bInitFail = true;
+ break;
+ }
+ }
+#endif
+
+#if defined(MTK_AUDENH_SUPPORT) //For reduce resource
+ mEnhanceFilter = new AudioMTKFilter(AUDIO_COMP_FLT_AUDENH, AUDIO_CMP_FLT_LOUDNESS_COMP_AUDENH,
+ mSamplerate, mChannel, mFormat, mBufferSize);
+
+ if (mEnhanceFilter == NULL) {
+ ALOGE("Error: %s Line#%d", __FUNCTION__, __LINE__);
+ bInitFail = true;
+ break;
+ } else {
+ if (mEnhanceFilter->init() != NO_ERROR) {
+ ALOGE("Error: %s Line#%d", __FUNCTION__, __LINE__);
+ bInitFail = true;
+ break;
+ }
+ }
+
+ mBuffer = new uint8_t[mBufferSize];
+ if (mBuffer == NULL) {
+ ALOGE("Error: %s Line#%d", __FUNCTION__, __LINE__);
+ bInitFail = true;
+ break;
+ }
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_AUDENH_SWITCH_STATE, property_value, AUDENH_SWITCH_DEFAULT_STATE ? "1":"0");
+ int audenh_enable = atoi(property_value);
+ if (audenh_enable) {
+ mFixedParam = true;
+ } else {
+ mFixedParam = false;
+ }
+#endif
+
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_VIBRATION_SPEAKER)) {
+ mVibspkAddToneFilter = new AudioMTKFilter_VibSpkAddTone(mSamplerate, mChannel, mFormat, mBufferSize);
+ if (mVibspkAddToneFilter == NULL) {
+ ALOGE("Error: %s Line#%d", __FUNCTION__, __LINE__);
+ bInitFail = true;
+ break;
+ } else {
+ if (mVibspkAddToneFilter->init() != NO_ERROR) {
+ ALOGE("Error: %s Line#%d", __FUNCTION__, __LINE__);
+ bInitFail = true;
+ break;
+ }
+ }
+
+ mVIBSPKFilter = new AudioMTKFilter(AUDIO_COMP_FLT_VIBSPK, AUDIO_CMP_FLT_LOUDNESS_COMP,
+ mSamplerate, mChannel, mFormat, mBufferSize);
+
+ if (mVIBSPKFilter == NULL) {
+ ALOGE("Error: %s Line#%d", __FUNCTION__, __LINE__);
+ bInitFail = true;
+ break;
+ } else {
+ if (mVIBSPKFilter->init() != NO_ERROR) {
+ ALOGE("Error: %s Line#%d", __FUNCTION__, __LINE__);
+ bInitFail = true;
+ break;
+ }
+ }
+
+ if (mBuffer == NULL) {
+ mBuffer = new uint8_t[mBufferSize];
+ if (mBuffer == NULL) {
+ ALOGE("Error: %s Line#%d", __FUNCTION__, __LINE__);
+ bInitFail = true;
+ break;
+ }
+ }
+ }
+ } while (0);
+
+ if (bInitFail) {
+ deinit();
+ ALOGE("Error: %s Line#%d Allocate Fail", __FUNCTION__, __LINE__);
+ return INVALID_OPERATION;
+ } else {
+ ALOGD("mFixedParam %d", mFixedParam);
+ return NO_ERROR;
+ }
+}
+
+void AudioMTKFilterManager::start(bool bFirstDataWrite) {
+ uint32_t device = mDevices;
+#if defined(CONFIG_MT_ENG_BUILD)
+ ALOGV("start() device 0x%x", device);
+#endif
+
+ if (device & AUDIO_DEVICE_OUT_SPEAKER) {
+ //stop hcf & enhangce
+ if (mHeadphoneFilter) { mHeadphoneFilter->stop(); }
+ if (mEnhanceFilter) { mEnhanceFilter->stop(); }
+ // start acf
+ if (mSpeakerFilter) { mSpeakerFilter->start(bFirstDataWrite); }
+ //#if defined(MTK_VIBSPK_SUPPORT)
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_VIBRATION_SPEAKER))
+ if (mVIBSPKFilter) { mVIBSPKFilter->start(bFirstDataWrite); }
+ //#endif
+
+ } else if ((device & AUDIO_DEVICE_OUT_WIRED_HEADSET) || (device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+ //#if defined(MTK_VIBSPK_SUPPORT)
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_VIBRATION_SPEAKER))
+ if (mVIBSPKFilter) { mVIBSPKFilter->stop(); }
+ //#endif
+ // stop acf
+ if (mSpeakerFilter) { mSpeakerFilter->stop(); }
+ // start hcf
+#ifdef MERGE_HCF_AUDENH_WITH_UI_OPTION
+ if (mHeadphoneFilter && mHeadphoneFilter->bIsZeroCoeff != true) {
+ if (false == mFixedParam) {
+ if (mHeadphoneFilter->isStart()) { mHeadphoneFilter->pause(); }
+ } else {
+ if (!mHeadphoneFilter->isStart()) {
+ mHeadphoneFilter->start(bFirstDataWrite);
+ } else {
+ mHeadphoneFilter->resume();
+ }
+ }
+ } else if (mEnhanceFilter) {
+ if (false == mFixedParam) {
+ if (mEnhanceFilter->isStart()) { mEnhanceFilter->pause(); }
+ } else {
+ if (!mEnhanceFilter->isStart()) {
+ mEnhanceFilter->start(bFirstDataWrite);
+ } else {
+ mEnhanceFilter->resume();
+ }
+ }
+ }
+#else
+ if (mHeadphoneFilter) { mHeadphoneFilter->start(bFirstDataWrite); }
+
+ if (mEnhanceFilter) {
+ if (false == mFixedParam) {
+ if (mEnhanceFilter->isStart()) { mEnhanceFilter->pause(); }
+ } else {
+ if (!mEnhanceFilter->isStart()) {
+ mEnhanceFilter->start(bFirstDataWrite);
+ } else {
+ mEnhanceFilter->resume();
+ }
+ }
+ }
+#endif
+ }
+ //#if defined(MTK_VIBSPK_SUPPORT)
+ else if (device & AUDIO_DEVICE_OUT_EARPIECE) {
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_VIBRATION_SPEAKER) && IsAudioSupportFeature(AUDIO_SUPPORT_2IN1_SPEAKER)) {
+ if (mHeadphoneFilter) { mHeadphoneFilter->stop(); }
+ if (mEnhanceFilter) { mEnhanceFilter->stop(); }
+ if (mSpeakerFilter) { mSpeakerFilter->stop(); }
+ if (mVIBSPKFilter) { mVIBSPKFilter->start(bFirstDataWrite); }
+ }
+ }
+ //#endif
+
+}
+
+void AudioMTKFilterManager::stop() {
+ ALOGV("stop()");
+ //#if defined(MTK_VIBSPK_SUPPORT)
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_VIBRATION_SPEAKER))
+ if (mVIBSPKFilter) { mVIBSPKFilter->stop(); }
+ //#endif
+ if (mSpeakerFilter) { mSpeakerFilter->stop(); }
+ if (mHeadphoneFilter) { mHeadphoneFilter->stop(); }
+ if (mEnhanceFilter) { mEnhanceFilter->stop(); }
+}
+
+bool AudioMTKFilterManager::isFilterStart(uint32_t type) {
+ if (type == AUDIO_COMP_FLT_AUDIO && mSpeakerFilter) {
+ return mSpeakerFilter->isStart();
+ } else if (type == AUDIO_COMP_FLT_HEADPHONE && mHeadphoneFilter) {
+ return mHeadphoneFilter->isStart();
+ } else if (type == AUDIO_COMP_FLT_AUDENH && mEnhanceFilter) {
+ return mEnhanceFilter->isStart();
+ }
+ //#if defined(MTK_VIBSPK_SUPPORT)
+ else if (type == AUDIO_COMP_FLT_VIBSPK && mVIBSPKFilter && (IsAudioSupportFeature(AUDIO_SUPPORT_VIBRATION_SPEAKER))) {
+ return mVIBSPKFilter->isStart();
+ }
+ //#endif
+
+ return false;
+}
+
+void AudioMTKFilterManager::setParamFixed(bool flag) {
+ ALOGD("setParamFixed() flag %d", flag);
+
+#if defined(MTK_AUDENH_SUPPORT)
+ mFixedParam = flag;
+ property_set(PROPERTY_KEY_AUDENH_SWITCH_STATE, (mFixedParam) ? "1" : "0");
+#else
+ ALOGW("Unsupport AudEnh Feature");
+#endif
+}
+
+bool AudioMTKFilterManager::isParamFixed() {
+ ALOGD("mFixedParam [%d]", mFixedParam);
+ return mFixedParam;
+}
+
+void AudioMTKFilterManager::setDevice(uint32_t devices) {
+ mDevices = devices;
+ return;
+}
+
+uint32_t AudioMTKFilterManager::process(void *inBuffer, uint32_t bytes, void *outBuffer, uint32_t outSize) {
+#if defined(CONFIG_MT_ENG_BUILD)
+ ALOGV("+process() insize %u", bytes);
+#endif
+ uint32_t outputSize = 0;
+ //#ifndef MTK_BASIC_PACKAGE
+#if 1
+ uint32_t device = mDevices;
+ if (device & AUDIO_DEVICE_OUT_SPEAKER) {
+ if (mSpeakerFilter) {
+ if (mSpeakerFilter->isStart()) {
+ outputSize = mSpeakerFilter->process(inBuffer, bytes, outBuffer, outSize);
+ }
+ }
+ //#if defined(MTK_VIBSPK_SUPPORT)
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_VIBRATION_SPEAKER)) {
+ if (mVIBSPKFilter) { //Notch filter
+ if (mVIBSPKFilter->isStart()) {
+ void *out;
+ void *in;
+ if (CC_UNLIKELY(outputSize == 0)) {
+ in = inBuffer;
+ } else {
+ in = outBuffer;
+
+ }
+
+ out = mBuffer;
+ outputSize = mVIBSPKFilter->process(in, bytes, out, outSize);
+
+ //Temp Use mSwapBufferVoIP for memory reduce
+ void *vibspkin = out;
+ void *vibspkout = outBuffer;
+ mVibspkAddToneFilter->DoVibSignal2DLProcess(vibspkout, vibspkin, outputSize);
+
+
+ }
+
+ }
+ }
+ //#endif
+ } else if ((device & AUDIO_DEVICE_OUT_WIRED_HEADSET) || (device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+ if (mEnhanceFilter) {
+ if (mEnhanceFilter->isStart()) {
+ outputSize = mEnhanceFilter->process(inBuffer, bytes, outBuffer, outSize);
+ }
+ }
+ if (mHeadphoneFilter) {
+ if (mHeadphoneFilter->isStart()) {
+ if (CC_UNLIKELY(outputSize == 0)) {
+ outputSize = mHeadphoneFilter->process(inBuffer, bytes, outBuffer, outSize);
+ } else {
+ void *in = outBuffer;
+ void *out = mBuffer;
+ outputSize = mHeadphoneFilter->process(in, outputSize, out, outSize);
+ if (outputSize > 0) { memcpy(outBuffer, out, outputSize); }
+ }
+ }
+ }
+ }
+ //#if defined(MTK_VIBSPK_SUPPORT)
+ else if (device & AUDIO_DEVICE_OUT_EARPIECE) {
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_VIBRATION_SPEAKER) && IsAudioSupportFeature(AUDIO_SUPPORT_2IN1_SPEAKER)) {
+ if (mVIBSPKFilter) {
+ if (mVIBSPKFilter->isStart()) {
+ outputSize = mVIBSPKFilter->process(inBuffer, bytes, outBuffer, outSize);
+ }
+ }
+ }
+ }
+ //#endif
+#endif
+#if defined(CONFIG_MT_ENG_BUILD)
+ ALOGV("-process() outsize %u", outputSize);
+#endif
+ return outputSize;
+
+}
+
+void AudioMTKFilterManager::setParameter(uint32_t type, void *param) {
+ ALOGV("setParameter() type %u", type);
+
+ if (type == AUDIO_COMP_FLT_AUDIO && mSpeakerFilter) {
+ return mSpeakerFilter->setParameter(param);
+ } else if (type == AUDIO_COMP_FLT_HEADPHONE && mHeadphoneFilter) {
+ return mHeadphoneFilter->setParameter(param);
+ } else if (type == AUDIO_COMP_FLT_AUDENH && mEnhanceFilter) {
+ return mEnhanceFilter->setParameter(param);
+ } else if (type == AUDIO_COMP_FLT_AUDIO_SUB && mSpeakerFilter) {
+ return mSpeakerFilter->setParameter2Sub(param);
+ } else {
+ // MTKFilter doesn't process DRC LID
+ ALOGW("MTKFilter doesn't process FLDID [%d]", type);
+ return;
+ }
+}
+
+void AudioMTKFilterManager::setSpkOutputGain(int32_t gain, uint32_t ramp_sample_cnt) {
+ ALOGV("setSpkMntrGain() target gain %d, sample %d", gain, ramp_sample_cnt);
+ if (mSpeakerFilter != NULL) {
+ return mSpeakerFilter->setOutputGain(gain, ramp_sample_cnt);
+ }
+ //Only speaker, need to update others in the future?
+}
+
+void AudioMTKFilterManager::setSpkFilterParam(unsigned int fc, unsigned int bw, int th) {
+ if (mSpeakerFilter != NULL) {
+ return mSpeakerFilter->setFilterParam(fc, bw, th);
+ }
+}
+
+//#if defined(MTK_VIBSPK_SUPPORT)
+const unsigned int AUD_VIBR_FILTER_COEF_Table[VIBSPK_FILTER_NUM][36] = {
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_141,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_144,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_147,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_150,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_153,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_156,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_159,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_162,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_165,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_168,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_171,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_174,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_177,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_180,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_183,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_186,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_189,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_192,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_195,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_198,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_201,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_204,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_207,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_210,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_213,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_216,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_219,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_222,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_225,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_228,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_231,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_234,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_237,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_240,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_243,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_246,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_249,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_252,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_255,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_258,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_261,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_264,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_267,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_270,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_273,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_276,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_279,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_282,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_285,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_288,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_291,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_294,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_297,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_300,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_303,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_306,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_309,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_312,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_315,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_318,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_321,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_324,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_327,
+ DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_330
+};
+
+
+AudioMTKFilter_VibSpkAddTone::AudioMTKFilter_VibSpkAddTone(
+ uint32_t sampleRate,
+ uint32_t channel,
+ uint32_t format,
+ size_t bufferSize) {
+ //#if defined(MTK_VIBSPK_SUPPORT)
+ ALOGD("+Init AudioMTKFilter_VibSpkAddTone");
+ ALOGD("sampleRate [%d] channel [%d] format [0x%x] bufferSize [%zu]", sampleRate, channel, format, bufferSize);
+ mChannels = channel;
+ mSampleRate = sampleRate;
+ mFormat = format;
+ mBufferSize = bufferSize;
+ mShifter_to_1_31_VIBSPK = NULL;
+ mVibSpk = NULL;
+ mVibSpkFreq = 0;
+ mVibSpkEnable = false;
+ mVIBSPKToneBuffer = NULL;
+ mVIBSPKToneWorkBuffer = NULL;
+ ALOGD("-Init AudioMTKFilter_VibSpkAddTone");
+}
+
+status_t AudioMTKFilter_VibSpkAddTone::init() {
+ bool bInitFail = false;
+ do {
+ mVibSpk = AudioVIBSPKControl::getInstance();
+ mVibSpkFreq = AudioFtm::getInstance()->GetVibSpkCalibrationStatus();
+ ALOGD("VibSpkReadFrequency:%x", mVibSpkFreq);
+ if (mVibSpkFreq == 0) {
+ AUDIO_ACF_CUSTOM_PARAM_STRUCT *pCali_param = new AUDIO_ACF_CUSTOM_PARAM_STRUCT;
+ ASSERT(pCali_param != NULL);
+ memset(pCali_param, 0, sizeof(AUDIO_ACF_CUSTOM_PARAM_STRUCT));
+#if defined(MTK_AUDIO_BLOUD_CUSTOMPARAMETER_V4)||defined(MTK_AUDIO_BLOUD_CUSTOMPARAMETER_V3)
+ memcpy(&(pCali_param->bes_loudness_bpf_coeff), &AUD_VIBR_FILTER_COEF_Table[(VIBSPK_DEFAULT_FREQ - VIBSPK_FREQ_LOWBOUND + 1) / VIBSPK_FILTER_FREQSTEP], sizeof(uint32_t)*VIBSPK_AUD_PARAM_SIZE);
+#else
+ memcpy(&(pCali_param->bes_loudness_f_param.V5ViVSPK.bes_loudness_bpf_coeff), (void *)&AUD_VIBR_FILTER_COEF_Table[(VIBSPK_DEFAULT_FREQ - VIBSPK_FREQ_LOWBOUND + 1) / VIBSPK_FILTER_FREQSTEP], sizeof(uint32_t)*VIBSPK_AUD_PARAM_SIZE);
+#endif
+ pCali_param->bes_loudness_WS_Gain_Min = VIBSPK_DEFAULT_FREQ;
+ pCali_param->bes_loudness_WS_Gain_Max = VIBSPK_SETDEFAULT_VALUE;
+ setAudioCompFltCustParam(AUDIO_COMP_FLT_VIBSPK, pCali_param);
+ ALOGD("[VibSpk] SetDefaultFreq");
+ mVibSpkFreq = VIBSPK_DEFAULT_FREQ;
+ delete pCali_param;
+ }
+
+ mVibSpk->setParameters(mSampleRate/*44100*/, mVibSpkFreq, MOD_FREQ, DELTA_FREQ);
+ mVibSpkEnable = false;
+
+ mVIBSPKToneBuffer = NULL;
+ mVIBSPKToneBuffer = new uint8_t[mBufferSize];
+ if (mVIBSPKToneBuffer == NULL) {
+ ALOGE("mVIBSPKToneBuffer for VIBSPK allocate fail Size %zu !!! \n", mBufferSize);
+ ASSERT(1);
+ }
+
+ mVIBSPKToneWorkBuffer = NULL;
+ mVIBSPKToneWorkBuffer = new uint8_t[mBufferSize];
+ if (mVIBSPKToneWorkBuffer == NULL) {
+ ALOGE("mVIBSPKToneWorkBuffer for VIBSPK allocate fail Size %zu !!! \n", mBufferSize);
+ ASSERT(1);
+ }
+
+ if (mFormat == AUDIO_FORMAT_PCM_32_BIT) {
+ mShifter_to_1_31_VIBSPK = newMtkAudioBitConverter(mSampleRate, mChannels, BCV_IN_Q1P15_OUT_Q1P31);
+ if (mShifter_to_1_31_VIBSPK == NULL) {
+ ALOGE("Error: %s Line#%d", __FUNCTION__, __LINE__);
+ bInitFail = true;
+ break;
+ } else {
+ mShifter_to_1_31_VIBSPK->open();
+ }
+ } else {
+ mShifter_to_1_31_VIBSPK = NULL;
+ }
+
+ } while (0);
+
+ if (bInitFail) {
+ deinit();
+ ALOGE("Error: %s Line#%d Allocate Fail", __FUNCTION__, __LINE__);
+ return INVALID_OPERATION;
+ }
+ return NO_ERROR;
+}
+
+void AudioMTKFilter_VibSpkAddTone::deinit() {
+ if (mShifter_to_1_31_VIBSPK) {
+ deleteMtkAudioBitConverter(mShifter_to_1_31_VIBSPK);
+ mShifter_to_1_31_VIBSPK = NULL;
+ }
+
+ if (mVIBSPKToneBuffer) {
+ delete []mVIBSPKToneBuffer;
+ mVIBSPKToneBuffer = NULL;
+ }
+
+ if (mVIBSPKToneWorkBuffer) {
+ delete []mVIBSPKToneWorkBuffer;
+ mVIBSPKToneWorkBuffer = NULL;
+ }
+}
+
+AudioMTKFilter_VibSpkAddTone::~AudioMTKFilter_VibSpkAddTone() {
+ deinit();
+}
+
+
+size_t AudioMTKFilter_VibSpkAddTone::DoVibSignal2DLProcess(void *outbuffer, void *src2DLbuffer, size_t bytes) {
+ bool bSkipVibTone = false;
+ size_t dToneSize;
+ dToneSize = (mShifter_to_1_31_VIBSPK == NULL) ? bytes : (bytes >> 1);
+ void *bToneTempWrokBuf;
+
+ if (mVibSpk->getVibSpkEnable()) {
+
+ if (mVibSpkEnable == false) {
+ mVibSpkEnable = true;
+ if (mShifter_to_1_31_VIBSPK) { mShifter_to_1_31_VIBSPK->resetBuffer(); }
+ mVibSpk->VibSpkRampControl(2);
+ }
+
+ mVibSpk->VibSpkProcess(dToneSize, mVIBSPKToneBuffer, mChannels);//Gen Tone
+ //dumpPcm(mVIBsignalDumpFile, mVIBSPKToneBuffer, dToneSize);
+ } else {
+ if (mVibSpkEnable == true) {
+ mVibSpkEnable = false;
+ mVibSpk->VibSpkRampControl(1);
+ mVibSpk->VibSpkProcess(dToneSize, mVIBSPKToneBuffer, mChannels);
+ //dumpPcm(mVIBsignalDumpFile, mVIBSPKToneBuffer, dToneSize);
+ } else {
+ bSkipVibTone = true;
+ }
+ }
+
+ if (mShifter_to_1_31_VIBSPK && !bSkipVibTone) {
+ unsigned int in_size = (unsigned int)dToneSize;
+ unsigned int out_size = bytes;
+ mShifter_to_1_31_VIBSPK->process((void *)mVIBSPKToneBuffer, (unsigned int *)&in_size, (void *)mVIBSPKToneWorkBuffer, (unsigned int *)&out_size);
+ bToneTempWrokBuf = mVIBSPKToneWorkBuffer;
+ } else {
+ bToneTempWrokBuf = mVIBSPKToneBuffer;
+ }
+
+ if (mShifter_to_1_31_VIBSPK) {
+ int dAudioGain = 0x7FFF - mVibSpk->getVibSpkGain();
+ uint32_t dSampleCount = bytes >> 2;
+ int *pVibToneData = (int *)bToneTempWrokBuf;
+ int *pAudioData = (int *)src2DLbuffer;
+ int *pOutputData = (int *)outbuffer;
+
+ while (dSampleCount) {
+ if (bSkipVibTone) {
+ *pOutputData = (*pAudioData);//(int)(((int64_t)(*pAudioData) * dAudioGain) >> 15);
+ } else {
+ *pOutputData = (*pVibToneData) + (int)(((int64_t)(*pAudioData) * dAudioGain) >> 15);
+ }
+
+ pOutputData++;
+ pVibToneData++;
+ pAudioData++;
+ dSampleCount--;
+ }
+ } else {
+ int dAudioGain = 0x7FFF - mVibSpk->getVibSpkGain();
+ uint32_t dSampleCount = bytes >> 1;
+ short *pVibToneData = (short *)bToneTempWrokBuf;
+ short *pAudioData = (short *)src2DLbuffer;
+ short *pOutputData = (short *)outbuffer;
+
+ while (dSampleCount) {
+ if (bSkipVibTone) {
+ *pOutputData = (*pAudioData);//(((*pAudioData) * dAudioGain) >> 15);
+ } else {
+ *pOutputData = (*pVibToneData) + (((*pAudioData) * dAudioGain) >> 15);
+ }
+
+ pOutputData++;
+ pVibToneData++;
+ pAudioData++;
+ dSampleCount--;
+ }
+ }
+
+
+ return bytes;
+
+}
+//#endif
+
+
+}
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioMTKHeadsetMessager.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioMTKHeadsetMessager.cpp
new file mode 100644
index 0000000..4b7d75e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioMTKHeadsetMessager.cpp
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+
+/*****************************************************************************
+* Copyright Statement:
+* --------------------
+* This software is protected by Copyright and the information contained
+* herein is confidential. The software may not be copied and the information
+* contained herein may not be used or disclosed except with the written
+* permission of MediaTek Inc. (C) 2009
+*
+* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
+* NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
+* SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
+*
+* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
+* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
+* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
+* LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
+* RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
+* THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
+*
+*****************************************************************************/
+
+
+/*****************************************************************************
+* E X T E R N A L R E F E R E N C E S
+******************************************************************************
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <pthread.h>
+#include <utils/Log.h>
+#include <unistd.h>
+#include "AudioMTKHeadsetMessager.h"
+
+/*****************************************************************************
+* C O N S T A N T S
+******************************************************************************
+*/
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioHeadSetMessager"
+
+#ifdef ENABLE_LOG_AUDIOHEADSETMESSAGER
+#define LOG_AudioHeadSetMessager ALOGD
+#else
+#define LOG_AudioHeadSetMessager ALOGV
+#endif
+
+namespace android {
+
+/*****************************************************************************
+* G L O B A L V A R I A B L E
+******************************************************************************
+*/
+static int HeadsetFd = -1;
+#define BUF_LEN 1
+static char rbuf[BUF_LEN] = {'\0'};
+static char stringStatusHeadset[BUF_LEN] = {'1'};
+static char stringStatusEarphone[BUF_LEN] = {'2'};
+
+AudioMTKHeadSetMessager *AudioMTKHeadSetMessager::UniqueHeadsetInstance = 0;
+
+/*****************************************************************************
+* F U N C T I O N D E F I N I T I O N
+******************************************************************************
+*/
+AudioMTKHeadSetMessager *AudioMTKHeadSetMessager::getInstance() {
+ if (UniqueHeadsetInstance == 0) {
+ ALOGD("+UniqueDigitalInstance\n");
+ UniqueHeadsetInstance = new AudioMTKHeadSetMessager();
+ ALOGD("-UniqueDigitalInstance\n");
+ }
+ return UniqueHeadsetInstance;
+}
+
+bool AudioMTKHeadSetMessager::SetHeadInit() {
+ LOG_AudioHeadSetMessager("SetHeadInit");
+ int ret = 0;
+ if (HeadsetFd < 0) {
+ // open headset device
+ HeadsetFd = open(HEADSET_PATH, O_RDONLY);
+ if (HeadsetFd < 0) {
+ ALOGE("open %s error fd = %d", HEADSET_PATH, HeadsetFd);
+ return false;
+ }
+ }
+ ret = ::ioctl(HeadsetFd, ACCDET_INIT, 0);
+ return true;
+}
+
+AudioMTKHeadSetMessager::AudioMTKHeadSetMessager() {
+ LOG_AudioHeadSetMessager("AudioHeadSetMessager Contructor");
+ if (HeadsetFd >= 0) {
+ // open headset device
+ ::close(HeadsetFd);
+ HeadsetFd = -1;
+ }
+ hHeadsetReadThread = 0;
+}
+
+void AudioMTKHeadSetMessager::SetHeadSetState(int state) {
+ LOG_AudioHeadSetMessager("SetHeadSetState state = %d", state);
+ int ret = 0;
+ if (HeadsetFd <= 0) {
+ // open headset device
+ HeadsetFd = open(HEADSET_PATH, O_RDONLY);
+ if (HeadsetFd < 0) {
+ ALOGE("open %s error fd = %d", HEADSET_PATH, HeadsetFd);
+ return;
+ }
+ }
+ ret = ::ioctl(HeadsetFd, SET_CALL_STATE, state);
+}
+
+bool AudioMTKHeadSetMessager::Get_headset_info(void) {
+ int headstatusFd = -1;
+ headstatusFd = open(YUSUHEADSET_STAUTS_PATH, O_RDONLY, 0);
+
+ if (headstatusFd < 0) {
+ ALOGE("open %s error fd = %d", YUSUHEADSET_STAUTS_PATH, headstatusFd);
+ return false;
+ }
+
+ if (::read(headstatusFd, rbuf, BUF_LEN) == -1) {
+ ALOGD("Get_headset_info Can't read headset");
+ ::close(headstatusFd);
+ return false;
+ }
+
+ ALOGD("%s => %c", YUSUHEADSET_STAUTS_PATH, rbuf[0]);
+
+ if (!strncmp(stringStatusHeadset, rbuf, BUF_LEN)) {
+ ::close(headstatusFd);
+ return true;
+ } else if (!strncmp(stringStatusEarphone, rbuf, BUF_LEN)) {
+ ::close(headstatusFd);
+ return true;
+ } else {
+ ::close(headstatusFd);
+ return false;
+ }
+}
+
+
+bool AudioMTKHeadSetMessager::isHeadsetPlugged() {
+ int headstatusFd = open(YUSUHEADSET_STAUTS_PATH, O_RDONLY, 0);
+
+ if (headstatusFd < 0) {
+ ALOGE("open %s error fd = %d", YUSUHEADSET_STAUTS_PATH, headstatusFd);
+ return false;
+ }
+
+ if (::read(headstatusFd, rbuf, BUF_LEN) == -1) {
+ ALOGD("Get_headset_info Can't read headset");
+ ::close(headstatusFd);
+ return false;
+ }
+
+ ALOGD("%s => %c", YUSUHEADSET_STAUTS_PATH, rbuf[0]);
+
+ if (!strncmp(stringStatusHeadset, rbuf, BUF_LEN)) {
+ ::close(headstatusFd);
+ return true;
+ } else {
+ ::close(headstatusFd);
+ return false;
+ }
+}
+
+bool AudioMTKHeadSetMessager::isEarphonePlugged() {
+ int headstatusFd = open(YUSUHEADSET_STAUTS_PATH, O_RDONLY, 0);
+
+ if (headstatusFd < 0) {
+ ALOGE("open %s error fd = %d", YUSUHEADSET_STAUTS_PATH, headstatusFd);
+ return false;
+ }
+
+ if (::read(headstatusFd, rbuf, BUF_LEN) == -1) {
+ ALOGD("Get_headset_info Can't read headset");
+ ::close(headstatusFd);
+ return false;
+ }
+
+ ALOGD("%s => %c", YUSUHEADSET_STAUTS_PATH, rbuf[0]);
+
+ if (!strncmp(stringStatusEarphone, rbuf, BUF_LEN)) {
+ ::close(headstatusFd);
+ return true;
+ } else {
+ ::close(headstatusFd);
+ return false;
+ }
+}
+
+}
+
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioToolkit.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioToolkit.cpp
new file mode 100644
index 0000000..d584fdd
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioToolkit.cpp
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioToolkit"
+#include "AudioToolkit.h"
+
+#if defined(PC_EMULATION)
+#include "windows.h"
+#else
+#include "unistd.h"
+#include "pthread.h"
+#endif
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+namespace android {
+//---------- implementation of base64 encode/decode--------------
+// function for encode/decode string
+static const char table_base64[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3',
+ '4', '5', '6', '7', '8', '9', '+', '/'
+ };
+static const int table_mod[] = {0, 2, 1};
+static char *decoding_table = NULL;
+
+//Base64_Encode: output_length = 4 * ((input_length + 2) / 3);
+//Base64_Decode: output_length = input_length / 4 * 3;
+size_t Base64_OutputSize(bool bEncode, size_t input_length) {
+ size_t output_length = 0;
+
+ if (bEncode) {
+ output_length = 4 * ((input_length + 2) / 3);
+ } else {
+ output_length = input_length / 4 * 3;
+ }
+ ALOGV("-%s(), bEncode(%d), input_length= %zu, output_length=%zu", __FUNCTION__, bEncode, input_length, output_length);
+ return output_length;
+}
+
+size_t Base64_Encode(const unsigned char *data_input, char *data_encoded, size_t input_length) {
+ size_t output_length = 4 * ((input_length + 2) / 3);
+ ALOGV("+%s(), data_input(%p), data_encoded(%p), input_length= %zu", __FUNCTION__, data_input, data_encoded, input_length);
+
+ // char *encoded_data = malloc(*output_length);
+ if (data_encoded == NULL) {return 0;}
+
+ for (size_t i = 0, j = 0; i < input_length;) {
+
+ uint32_t octet_a = i < input_length ? (unsigned char)data_input[i++] : 0;
+ uint32_t octet_b = i < input_length ? (unsigned char)data_input[i++] : 0;
+ uint32_t octet_c = i < input_length ? (unsigned char)data_input[i++] : 0;
+ uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
+
+ data_encoded[j++] = table_base64[(triple >> 3 * 6) & 0x3F];
+ data_encoded[j++] = table_base64[(triple >> 2 * 6) & 0x3F];
+ data_encoded[j++] = table_base64[(triple >> 1 * 6) & 0x3F];
+ data_encoded[j++] = table_base64[(triple >> 0 * 6) & 0x3F];
+ ALOGV("%s(), i(%zu), j(%zu)", __FUNCTION__, i, j);
+ }
+ for (int i = 0; i < table_mod[input_length % 3]; i++) {
+ data_encoded[output_length - 1 - i] = '-';
+ }
+ ALOGV("-%s(), output_length=%zu", __FUNCTION__, output_length);
+ return output_length;
+}
+
+void build_decoding_table() {
+ if (decoding_table == NULL) {
+ decoding_table = new char [256];
+
+ for (int i = 0; i < 64; i++) {
+ decoding_table[(unsigned char) table_base64[i]] = i;
+ }
+ } else {
+ ALOGV("-%s(), decoding_table already exist", __FUNCTION__);
+ }
+}
+
+void base64_cleanup() {
+ ALOGV("+%s()", __FUNCTION__);
+ if (decoding_table != NULL) {
+ delete[] decoding_table;
+ decoding_table = NULL;
+ }
+ ALOGV("-%s()", __FUNCTION__);
+}
+
+size_t Base64_Decode(const char *data_input, unsigned char *data_decoded, size_t input_length) {
+ ALOGV("+%s(), data_input(%p), data_decoded(%p), input_length= %zu", __FUNCTION__, data_input, data_decoded, input_length);
+ if ((input_length % 4 != 0) || (data_decoded == NULL)) {
+ return 0;
+ }
+ build_decoding_table();
+
+ size_t output_length = input_length / 4 * 3;
+ if (data_input[input_length - 1] == '-') { (output_length)--; }
+ if (data_input[input_length - 2] == '-') { (output_length)--; }
+
+ //unsigned char *decoded_data = malloc(*output_length);
+
+ for (size_t i = 0, j = 0; i < input_length;) {
+ uint32_t sextet_a = data_input[i] == '-' ? 0 & i++ : decoding_table[(unsigned char)data_input[i++]];
+ uint32_t sextet_b = data_input[i] == '-' ? 0 & i++ : decoding_table[(unsigned char)data_input[i++]];
+ uint32_t sextet_c = data_input[i] == '-' ? 0 & i++ : decoding_table[(unsigned char)data_input[i++]];
+ uint32_t sextet_d = data_input[i] == '-' ? 0 & i++ : decoding_table[(unsigned char)data_input[i++]];
+
+ uint32_t triple = (sextet_a << 3 * 6)
+ + (sextet_b << 2 * 6)
+ + (sextet_c << 1 * 6)
+ + (sextet_d << 0 * 6);
+
+ if (j < output_length) { data_decoded[j++] = (triple >> 2 * 8) & 0xFF; }
+ if (j < output_length) { data_decoded[j++] = (triple >> 1 * 8) & 0xFF; }
+ if (j < output_length) { data_decoded[j++] = (triple >> 0 * 8) & 0xFF; }
+ ALOGV("%s(), i(%zu), j(%zu)", __FUNCTION__, i, j);
+ }
+ base64_cleanup();
+ ALOGV("-%s(), output_length=%zu", __FUNCTION__, output_length);
+
+ return output_length;
+}
+
+status_t AudioToolKit_GetDecodedData(String8 strPara, size_t len, void *ptr)
+{
+ size_t sz_in = strPara.size();
+ size_t sz_needed = Base64_OutputSize(false, sz_in);
+ size_t sz_dec;
+ status_t ret = NO_ERROR;
+
+ if (sz_in <= 0)
+ return NO_ERROR;
+
+ ALOGD("%s in, len = %zu", __FUNCTION__, len);
+ unsigned char *buf_dec = new unsigned char[sz_needed];
+ sz_dec = Base64_Decode(strPara.string(), buf_dec, sz_in);
+
+ if (sz_dec > sz_needed || sz_dec <= sz_needed -3) {
+ ALOGE("%s(), Decode Error!!!after decode (%s), sz_in(%zu), sz_needed(%zu), sz_dec(%zu)",
+ __FUNCTION__, buf_dec, sz_in, sz_needed, sz_dec);
+ } else {
+ // sz_needed-3 < sz_dec <= sz_needed
+ }
+
+ if( (len == 0) || (len == sz_dec-sizeof(ret)) ) {
+ if ( len ) {
+ ret = (status_t) *(buf_dec);
+ unsigned char *buff = (buf_dec+4);
+ memcpy(ptr, buff, len);
+ } else {
+ const char * IntPtr = (char *)buf_dec;
+ ret = atoi(IntPtr);
+ ALOGD("%s len = 0 ret(%d)", __FUNCTION__, ret);
+ }
+ } else {
+ ALOGD("%s decoded buffer isn't right format", __FUNCTION__);
+ }
+
+ if (buf_dec != NULL) {
+ delete[] buf_dec;
+ }
+
+ return ret;
+}
+
+}
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioUtility.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioUtility.cpp
new file mode 100644
index 0000000..fc32440
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioUtility.cpp
@@ -0,0 +1,2396 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "AudioUtility.h"
+
+#include <AudioLock.h>
+#include <sys/auxv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <queue>
+#include <utils/KeyedVector.h>
+#if defined(MTK_YOCTO_AUDIO)
+#include "MtkAudioSrc.h"
+#endif
+
+
+#include <dlfcn.h>
+
+#include <audio_ringbuf.h>
+
+#if (defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT) && (MTK_AUDIO_TUNING_TOOL_V2_PHASE >= 2))
+#include "AudioParamParser.h"
+#endif
+
+#if defined(MTK_POWERHAL_AUDIO_LATENCY) || defined(MTK_POWERHAL_AUDIO_POWER) || defined(MTK_POWERHAL_WIFI_POWRER_SAVE)
+#include <vendor/mediatek/hardware/power/2.0/IPower.h>
+#include <vendor/mediatek/hardware/power/2.0/types.h>
+#include <power_cus_types.h>
+using namespace vendor::mediatek::hardware::power::V2_0;
+using android::hardware::Return;
+using android::hardware::hidl_death_recipient;
+using android::hidl::base::V1_0::IBase;
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioUtility"
+#define UNUSED(x) ((void)(x))
+
+
+#if defined(MTK_POWERHAL_AUDIO_LATENCY) || defined(MTK_POWERHAL_AUDIO_POWER) || defined(MTK_POWERHAL_WIFI_POWRER_SAVE)
+static android::sp<IPower> gPowerHal = NULL;
+static AudioLock gPowerHalLock;
+
+struct PowerDeathRecipient : virtual public hidl_death_recipient {
+ virtual void serviceDied(uint64_t cookie __unused, const android::wp<IBase> &who __unused) override {
+ ALOGW("%s(), power hal died, get power hal again", __FUNCTION__);
+ AL_LOCK(gPowerHalLock);
+ gPowerHal = NULL;
+ android::getPowerHal();
+ AL_UNLOCK(gPowerHalLock);
+ }
+};
+
+static android::sp<PowerDeathRecipient> powerHalDeathRecipient = NULL;
+
+#endif
+
+namespace android {
+
+/* Name for MicInfo */
+#define MIC_INFO_AUDIO_TYPE_NAME "MicInfo"
+#define PROJECTS_CATEGORY_TYPE_NAME "projects"
+#define MICROPHONES_CATEGORY_TYPE_NAME "microphones"
+#define PROJECT_ID_PARAM_NAME "device_id"
+#define DEVICE_IN_TYPE_PARAM_NAME "device_in_type"
+#define ADDRESS_PARAM_NAME "address"
+#define MIC_LOCATION_PARAM_NAME "mic_location"
+#define DEVICE_GROUP_PARAM_NAME "device_group"
+#define INDEX_IN_THE_GROUP_PARAM_NAME "index_in_the_group"
+#define GEOMETRIC_LOCATION_PARAM_NAME "geometric_location"
+#define ORIENTATION_PARAM_NAME "orientation"
+#define FREQUENCY_RESPONSES_PARAM_NAME "frequency_responses"
+#define SENSITIVITY_PARAM_NAME "sensitivity"
+#define MAX_SPL_PARAM_NAME "max_spl"
+#define MIN_SPL_PARAM_NAME "min_spl"
+#define DIRECTIONALITY_PARAM_NAME "directionality"
+
+#define DEVICE_IN_TYPE_SEPERATOR "|"
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+#if defined(__LP64__)
+const char *AUDIO_COMPENSATION_FILTER_LIB_VENDOR_PATH = "/vendor/lib64/libaudiocompensationfilter_vendor.so";
+const char *AUDIO_COMPENSATION_FILTER_LIB_PATH = "/system/lib64/libaudiocompensationfilter.so";
+const char *AUDIO_COMPONENT_ENGINE_LIB_VENDOR_PATH = "/vendor/lib64/libaudiocomponentengine_vendor.so";
+const char *AUDIO_COMPONENT_ENGINE_LIB_PATH = "/system/lib64/libaudiocomponentengine.so";
+
+#else
+const char *AUDIO_COMPENSATION_FILTER_LIB_VENDOR_PATH = "/vendor/lib/libaudiocompensationfilter_vendor.so";
+const char *AUDIO_COMPENSATION_FILTER_LIB_PATH = "/system/lib/libaudiocompensationfilter.so";
+const char *AUDIO_COMPONENT_ENGINE_LIB_VENDOR_PATH = "/vendor/lib/libaudiocomponentengine_vendor.so";
+const char *AUDIO_COMPONENT_ENGINE_LIB_PATH = "/system/lib/libaudiocomponentengine.so";
+
+#endif
+static void *g_AudioComponentEngineHandle = NULL;
+static create_AudioBitConverter *g_CreateMtkAudioBitConverter = NULL;
+static create_AudioSrc *g_CreateMtkAudioSrc = NULL;
+static create_AudioLoud *g_CreateMtkAudioLoud = NULL;
+static create_DcRemove *g_CreateMtkDcRemove = NULL;
+static destroy_AudioBitConverter *g_DestroyMtkAudioBitConverter = NULL;
+static destroy_AudioSrc *g_DestroyMtkAudioSrc = NULL;
+static destroy_AudioLoud *g_DestroyMtkAudioLoud = NULL;
+static destroy_DcRemove *g_DestroyMtkDcRemove = NULL;
+static void *g_AudioCompensationFilterHandle = NULL;
+#if !defined(MTK_YOCTO_AUDIO)
+static setFunAudioCompFltCustParam *g_setAudioCompFltCustParamFrom = NULL;
+static getFunAudioCompFltCustParam *g_getAudioCompFltCustParamFrom = NULL;
+#endif
+
+const static char *ProcessBitsString[] = {"v7l", "v8l", "aarch64"};
+
+#define DUMP_PATH "/data/vendor/audiohal/audio_dump/"
+
+const char *audio_dump_path = DUMP_PATH;
+const char *streamout_ori = DUMP_PATH"streamoutori_dump.pcm";
+const char *streamout_ori_propty = "streamout_ori.pcm.dump";
+const char *streamout_dcr = DUMP_PATH"streamoutdcr_dump.pcm";
+const char *streamout_dcr_propty = "streamout_dcr.pcm.dump";
+
+const char *streamout_s2m = DUMP_PATH"streamouts2m_dump.pcm";
+const char *streamout_s2m_propty = "streamout_s2m.pcm.dump";
+const char *streamout_acf = DUMP_PATH"streamoutacf_dump.pcm";
+const char *streamout_acf_propty = "streamout_acf.pcm.dump";
+const char *streamout_hcf = DUMP_PATH"streamouthcf_dump.pcm";
+const char *streamout_hcf_propty = "streamout_hcf.pcm.dump";
+
+const char *streamout = DUMP_PATH"streamout.pcm";
+const char *streamoutfinal = DUMP_PATH"streamoutfinal.pcm";
+const char *streamout_propty = "vendor.streamout.pcm.dump";
+const char *aud_dumpftrace_dbg_propty = "dumpftrace_dbg";
+const char *streaminIVCPMIn = DUMP_PATH"StreamIVPCMIn_Dump.pcm";
+const char *streaminIVIn = DUMP_PATH"StreamIVIn_Dump.pcm";
+const char *streamout_vibsignal = DUMP_PATH"streamoutvib.pcm";
+const char *streamout_notch = DUMP_PATH"streamoutnotch.pcm";
+const char *streamoutdsp_propty = "vendor.streamout.dsp.dump";
+const char *a2dpdsp_propty = "vendor.a2dp.streamout.pcm";
+
+const char *streaminmanager = DUMP_PATH"StreamInManager_Dump.pcm";
+const char *streamin = DUMP_PATH"StreamIn_Dump.pcm";
+const char *streaminOri = DUMP_PATH"StreamInOri_Dump.pcm";
+const char *streaminI2S = DUMP_PATH"StreamInI2S_Dump.pcm";
+const char *streaminDAIBT = DUMP_PATH"StreamInDAIBT_Dump.pcm";
+const char *streaminSpk = DUMP_PATH"streamin_spk.pcm";
+const char *streaminSpk_propty = "streamin.spkpcm.dump";
+const char *capture_data_provider = DUMP_PATH"CaptureDataProvider";
+
+const char *streamin_propty = "vendor.streamin.pcm.dump";
+const char *streamindsp_propty = "vendor.streamin.dsp.dump";
+
+const char *streamin_epl_propty = "vendor.streamin.epl.dump";
+
+const char *allow_low_latency_propty = "streamout.lowlatency.allow";
+const char *streamhfp_propty = "streamhfp.pcm.dump";
+const char *allow_offload_propty = "vendor.streamout.offload.allow";
+const char *streaminlog_propty = "vendor.streamin.log";
+const char *platform_arch = "aarch64";
+
+#define EPL_PACKET_BYTE_SIZE 9600 //4800 * 2(short)
+
+static bool bNeedAEETimeoutFlg;
+
+/**
+ * Get enum by string
+ */
+struct enum_to_str_table {
+ const char* name;
+ uint32_t value;
+};
+
+
+/**
+ * write smoother
+ */
+#define MAX_WRITE_SMOOTHER_DELAY_TIME_US (200 * 1000) /* 200 ms */
+
+struct WriteSmoother {
+ struct timespec mOpenTime;
+ uint64_t mTotalBufferTimeUs; // total accumulated buffer time since open
+ bool mDumpLogFlag;
+};
+
+
+#define AUDIO_ENUM_TO_STR(X) { #X, X }
+
+static const struct enum_to_str_table micLoccationTable[] = {
+ AUDIO_ENUM_TO_STR(AUDIO_MICROPHONE_LOCATION_UNKNOWN),
+ AUDIO_ENUM_TO_STR(AUDIO_MICROPHONE_LOCATION_MAINBODY),
+ AUDIO_ENUM_TO_STR(AUDIO_MICROPHONE_LOCATION_MAINBODY_MOVABLE),
+ AUDIO_ENUM_TO_STR(AUDIO_MICROPHONE_LOCATION_PERIPHERAL),
+ {NULL, 0},
+};
+
+static const struct enum_to_str_table micDirectionalityTable[] = {
+ AUDIO_ENUM_TO_STR(AUDIO_MICROPHONE_DIRECTIONALITY_UNKNOWN),
+ AUDIO_ENUM_TO_STR(AUDIO_MICROPHONE_DIRECTIONALITY_OMNI),
+ AUDIO_ENUM_TO_STR(AUDIO_MICROPHONE_DIRECTIONALITY_BI_DIRECTIONAL),
+ AUDIO_ENUM_TO_STR(AUDIO_MICROPHONE_DIRECTIONALITY_CARDIOID),
+ AUDIO_ENUM_TO_STR(AUDIO_MICROPHONE_DIRECTIONALITY_HYPER_CARDIOID),
+ AUDIO_ENUM_TO_STR(AUDIO_MICROPHONE_DIRECTIONALITY_SUPER_CARDIOID),
+ {NULL, 0},
+};
+
+static const struct enum_to_str_table micChannelMappingTable[] = {
+ AUDIO_ENUM_TO_STR(AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED),
+ AUDIO_ENUM_TO_STR(AUDIO_MICROPHONE_CHANNEL_MAPPING_DIRECT),
+ AUDIO_ENUM_TO_STR(AUDIO_MICROPHONE_CHANNEL_MAPPING_PROCESSED),
+ {NULL, 0},
+};
+
+static const struct enum_to_str_table deviceInTypeTable[] = {
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_COMMUNICATION),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_AMBIENT),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_BUILTIN_MIC),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_WIRED_HEADSET),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_AUX_DIGITAL),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_HDMI),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_VOICE_CALL),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_TELEPHONY_RX),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_BACK_MIC),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_USB_ACCESSORY),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_USB_DEVICE),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_FM_TUNER),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_TV_TUNER),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_LINE),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_SPDIF),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_LOOPBACK),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_IP),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_BUS),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_PROXY),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_USB_HEADSET),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_BLUETOOTH_BLE),
+ AUDIO_ENUM_TO_STR(AUDIO_DEVICE_IN_DEFAULT),
+ {NULL, 0},
+};
+
+unsigned long long TimeDifference(struct timespec time1, struct timespec time2) {
+ unsigned long long diffns = 0;
+ struct timespec tstemp1 = time1;
+ struct timespec tstemp2 = time2;
+
+ // ALOGD("TimeStampDiff time1 sec= %ld, nsec=%ld, time2 sec=%ld, nsec=%ld" ,tstemp1.tv_sec, tstemp1.tv_nsec, tstemp2.tv_sec, tstemp2.tv_nsec);
+
+ if (tstemp1.tv_sec > tstemp2.tv_sec) {
+ if (tstemp1.tv_nsec >= tstemp2.tv_nsec) {
+ diffns = ((tstemp1.tv_sec - tstemp2.tv_sec) * (unsigned long long)1000000000) + tstemp1.tv_nsec - tstemp2.tv_nsec;
+ } else {
+ diffns = ((tstemp1.tv_sec - tstemp2.tv_sec - 1) * (unsigned long long)1000000000) + tstemp1.tv_nsec + 1000000000 - tstemp2.tv_nsec;
+ }
+ } else if (tstemp1.tv_sec == tstemp2.tv_sec) {
+ if (tstemp1.tv_nsec >= tstemp2.tv_nsec) {
+ diffns = tstemp1.tv_nsec - tstemp2.tv_nsec;
+ } else {
+ diffns = tstemp2.tv_nsec - tstemp1.tv_nsec;
+ }
+ } else {
+ if (tstemp2.tv_nsec >= tstemp1.tv_nsec) {
+ diffns = ((tstemp2.tv_sec - tstemp1.tv_sec) * (unsigned long long)1000000000) + tstemp2.tv_nsec - tstemp1.tv_nsec;
+ } else {
+ diffns = ((tstemp2.tv_sec - tstemp1.tv_sec - 1) * (unsigned long long)1000000000) + tstemp2.tv_nsec + 1000000000 - tstemp1.tv_nsec;
+ }
+ }
+ // ALOGD("TimeDifference time1 sec= %ld, nsec=%ld, time2 sec=%ld, nsec=%ld, diffns=%lld" ,tstemp1.tv_sec, tstemp1.tv_nsec, tstemp2.tv_sec,tstemp2.tv_nsec,diffns);
+ return diffns;
+}
+
+
+//---------- implementation of ringbuffer--------------
+
+
+// function for get how many data is available
+
+/**
+* function for get how many data is available
+* @return how many data exist
+*/
+
+int RingBuf_getDataCount(const RingBuf *RingBuf1) {
+ /*
+ ALOGD("RingBuf1->pBase = 0x%x RingBuf1->pWrite = 0x%x RingBuf1->bufLen = %d RingBuf1->pRead = 0x%x",
+ RingBuf1->pBufBase,RingBuf1->pWrite, RingBuf1->bufLen,RingBuf1->pRead);
+ */
+ int count = RingBuf1->pWrite - RingBuf1->pRead;
+ if (count < 0) { count += RingBuf1->bufLen; }
+ return count;
+}
+
+/**
+* function for get how free space available
+* @return how free sapce
+*/
+
+int RingBuf_getFreeSpace(const RingBuf *RingBuf1) {
+ /*
+ ALOGD("RingBuf1->pBase = 0x%x RingBuf1->pWrite = 0x%x RingBuf1->bufLen = %d RingBuf1->pRead = 0x%x",
+ RingBuf1->pBufBase,RingBuf1->pWrite, RingBuf1->bufLen,RingBuf1->pRead);*/
+ int count = 0;
+
+ if (RingBuf1->pRead > RingBuf1->pWrite) {
+ count = RingBuf1->pRead - RingBuf1->pWrite - RING_BUF_SIZE_OFFSET;
+ } else { // RingBuf1->pRead <= RingBuf1->pWrite
+ count = RingBuf1->pRead - RingBuf1->pWrite + RingBuf1->bufLen - RING_BUF_SIZE_OFFSET;
+ }
+
+ return (count > 0) ? count : 0;
+}
+
+/**
+* copy count number bytes from ring buffer to buf
+* @param buf buffer copy from
+* @param RingBuf1 buffer copy to
+* @param count number of bytes need to copy
+*/
+
+void RingBuf_copyToLinear(char *buf, RingBuf *RingBuf1, int count) {
+ /*
+ ALOGD("RingBuf1->pBase = 0x%x RingBuf1->pWrite = 0x%x RingBuf1->bufLen = %d RingBuf1->pRead = 0x%x",
+ RingBuf1->pBufBase,RingBuf1->pWrite, RingBuf1->bufLen,RingBuf1->pRead);*/
+ if (RingBuf1->pRead <= RingBuf1->pWrite) {
+ memcpy(buf, RingBuf1->pRead, count);
+ RingBuf1->pRead += count;
+ } else {
+ char *end = RingBuf1->pBufBase + RingBuf1->bufLen;
+ int r2e = end - RingBuf1->pRead;
+ if (count <= r2e) {
+ //ALOGD("2 RingBuf_copyToLinear r2e= %d count = %d",r2e,count);
+ memcpy(buf, RingBuf1->pRead, count);
+ RingBuf1->pRead += count;
+ if (RingBuf1->pRead == end) {
+ RingBuf1->pRead = RingBuf1->pBufBase;
+ }
+ } else {
+ //ALOGD("3 RingBuf_copyToLinear r2e= %d count = %d",r2e,count);
+ memcpy(buf, RingBuf1->pRead, r2e);
+ memcpy(buf + r2e, RingBuf1->pBufBase, count - r2e);
+ RingBuf1->pRead = RingBuf1->pBufBase + count - r2e;
+ }
+ }
+}
+
+/**
+* copy count number bytes from buf to RingBuf1
+* @param RingBuf1 ring buffer copy from
+* @param buf copy to
+* @param count number of bytes need to copy
+*/
+void RingBuf_copyFromLinear(RingBuf *RingBuf1, const char *buf, int count) {
+ int spaceIHave;
+ char *end = RingBuf1->pBufBase + RingBuf1->bufLen;
+
+ // count buffer data I have
+ spaceIHave = RingBuf1->bufLen - RingBuf_getDataCount(RingBuf1) - RING_BUF_SIZE_OFFSET;
+ //spaceIHave = RingBuf_getDataCount(RingBuf1);
+
+ // if not enough, assert
+ ASSERT(spaceIHave >= count);
+
+ if (RingBuf1->pRead <= RingBuf1->pWrite) {
+ int w2e = end - RingBuf1->pWrite;
+ if (count <= w2e) {
+ memcpy(RingBuf1->pWrite, buf, count);
+ RingBuf1->pWrite += count;
+ if (RingBuf1->pWrite == end) {
+ RingBuf1->pWrite = RingBuf1->pBufBase;
+ }
+ } else {
+ memcpy(RingBuf1->pWrite, buf, w2e);
+ memcpy(RingBuf1->pBufBase, buf + w2e, count - w2e);
+ RingBuf1->pWrite = RingBuf1->pBufBase + count - w2e;
+ }
+ } else {
+ memcpy(RingBuf1->pWrite, buf, count);
+ RingBuf1->pWrite += count;
+ }
+
+}
+
+/**
+* fill count number zero bytes to RingBuf1
+* @param RingBuf1 ring buffer fill from
+* @param count number of bytes need to copy
+*/
+void RingBuf_fillZero(RingBuf *RingBuf1, int count) {
+ int spaceIHave;
+ char *end = RingBuf1->pBufBase + RingBuf1->bufLen;
+
+ // count buffer data I have
+ spaceIHave = RingBuf1->bufLen - RingBuf_getDataCount(RingBuf1) - RING_BUF_SIZE_OFFSET;
+ //spaceIHave = RingBuf_getDataCount(RingBuf1);
+
+ // if not enough, assert
+ ASSERT(spaceIHave >= count);
+
+ if (RingBuf1->pRead <= RingBuf1->pWrite) {
+ int w2e = end - RingBuf1->pWrite;
+ if (count <= w2e) {
+ memset(RingBuf1->pWrite, 0, sizeof(char)*count);
+ RingBuf1->pWrite += count;
+ if (RingBuf1->pWrite == end) {
+ RingBuf1->pWrite = RingBuf1->pBufBase;
+ }
+ } else {
+ memset(RingBuf1->pWrite, 0, sizeof(char)*w2e);
+ memset(RingBuf1->pBufBase, 0, sizeof(char) * (count - w2e));
+ RingBuf1->pWrite = RingBuf1->pBufBase + count - w2e;
+ }
+ } else {
+ memset(RingBuf1->pWrite, 0, sizeof(char)*count);
+ RingBuf1->pWrite += count;
+ }
+
+}
+
+
+/**
+* copy ring buffer from RingBufs(source) to RingBuft(target)
+* @param RingBuft ring buffer copy to
+* @param RingBufs copy from copy from
+*/
+
+void RingBuf_copyEmpty(RingBuf *RingBuft, RingBuf *RingBufs) {
+ if (RingBufs->pRead <= RingBufs->pWrite) {
+ RingBuf_copyFromLinear(RingBuft, RingBufs->pRead, RingBufs->pWrite - RingBufs->pRead);
+ //RingBufs->pRead = RingBufs->pWrite;
+ // no need to update source read pointer, because it is read to empty
+ } else {
+ char *end = RingBufs->pBufBase + RingBufs->bufLen;
+ RingBuf_copyFromLinear(RingBuft, RingBufs->pRead, end - RingBufs->pRead);
+ RingBuf_copyFromLinear(RingBuft, RingBufs->pBufBase, RingBufs->pWrite - RingBufs->pBufBase);
+ }
+}
+
+
+/**
+* copy ring buffer from RingBufs(source) to RingBuft(target) with count
+* @param RingBuft ring buffer copy to
+* @param RingBufs copy from copy from
+*/
+int RingBuf_copyFromRingBuf(RingBuf *RingBuft, RingBuf *RingBufs, int count) {
+ int cntInRingBufs = RingBuf_getDataCount(RingBufs);
+ int freeSpaceInRingBuft = RingBuf_getFreeSpace(RingBuft);
+ if (count > cntInRingBufs || count > freeSpaceInRingBuft) {
+ ALOGE("%s(), src: b %p, r %p, w %p, e %p, sz %u. cnt %d, avail %d",
+ __FUNCTION__,
+ RingBufs->pBufBase,
+ RingBufs->pRead,
+ RingBufs->pWrite,
+ RingBufs->pBufEnd,
+ RingBufs->bufLen,
+ count,
+ cntInRingBufs);
+ ALOGE("%s(), tar: b %p, r %p, w %p, e %p, sz %u. cnt %d, free %d",
+ __FUNCTION__,
+ RingBuft->pBufBase,
+ RingBuft->pRead,
+ RingBuft->pWrite,
+ RingBuft->pBufEnd,
+ RingBuft->bufLen,
+ count,
+ freeSpaceInRingBuft);
+ ASSERT(count <= cntInRingBufs && count <= freeSpaceInRingBuft);
+ return 0;
+ }
+
+ if (RingBufs->pRead <= RingBufs->pWrite) {
+ RingBuf_copyFromLinear(RingBuft, RingBufs->pRead, count);
+ RingBufs->pRead += count;
+ // no need to update source read pointer, because it is read to empty
+ } else {
+ char *end = RingBufs->pBufBase + RingBufs->bufLen;
+ int cnt2e = end - RingBufs->pRead;
+ if (cnt2e >= count) {
+ RingBuf_copyFromLinear(RingBuft, RingBufs->pRead, count);
+ RingBufs->pRead += count;
+ if (RingBufs->pRead == end) {
+ RingBufs->pRead = RingBufs->pBufBase;
+ }
+ } else {
+ RingBuf_copyFromLinear(RingBuft, RingBufs->pRead, cnt2e);
+ RingBuf_copyFromLinear(RingBuft, RingBufs->pBufBase, count - cnt2e);
+ RingBufs->pRead = RingBufs->pBufBase + count - cnt2e;
+ }
+ }
+ return count;
+}
+
+/**
+* write bytes size of count woith value
+* @param RingBuf1 ring buffer copy to
+* @value value put into buffer
+* @count bytes ned to put.
+*/
+void RingBuf_writeDataValue(RingBuf *RingBuf1, const int value, const int count) {
+ int spaceIHave;
+
+ // count buffer data I have
+ spaceIHave = RingBuf1->bufLen - RingBuf_getDataCount(RingBuf1) - RING_BUF_SIZE_OFFSET;
+
+ // if not enough, assert
+ ASSERT(spaceIHave >= count);
+
+ if (RingBuf1->pRead <= RingBuf1->pWrite) {
+ char *end = RingBuf1->pBufBase + RingBuf1->bufLen;
+ int w2e = end - RingBuf1->pWrite;
+ if (count <= w2e) {
+ memset(RingBuf1->pWrite, value, count);
+ RingBuf1->pWrite += count;
+ } else {
+ memset(RingBuf1->pWrite, value, w2e);
+ memset(RingBuf1->pBufBase, value, count - w2e);
+ RingBuf1->pWrite = RingBuf1->pBufBase + count - w2e;
+ }
+ } else {
+ memset(RingBuf1->pWrite, value, count);
+ RingBuf1->pWrite += count;
+ }
+
+}
+
+/**
+* discard count bytes data in ring buffer
+* @param ringBuf ring buffer to discard data
+* @param count bytes size to discard
+* @return 0 if discard successfully, -EINVAL if count or RingBuf1 is invalid
+*/
+int RingBuf_discardData(RingBuf *ringBuf, int count) {
+ if (!ringBuf) {
+ ALOGE("%s(), ringBuf == NULL", __FUNCTION__);
+ ASSERT(0);
+ return -EINVAL;
+ }
+
+ if (count > RingBuf_getDataCount(ringBuf)) {
+ ALOGE("%s(), count %d > remain data %d", __FUNCTION__, count, RingBuf_getDataCount(ringBuf));
+ ASSERT(0);
+ return -EINVAL;
+ }
+
+ if (ringBuf->pRead <= ringBuf->pWrite) {
+ ringBuf->pRead += count;
+ } else {
+ char *end = ringBuf->pBufBase + ringBuf->bufLen;
+ int r2e = end - ringBuf->pRead;
+ if (count <= r2e) {
+ ringBuf->pRead += count;
+ if (ringBuf->pRead == end) {
+ ringBuf->pRead = ringBuf->pBufBase;
+ }
+ } else {
+ ringBuf->pRead = ringBuf->pBufBase + count - r2e;
+ }
+ }
+ return 0;
+}
+
+/**
+* check if next count bytes data will cross boundary
+* @param ringBuf ring buffer to check
+* @param count bytes size to check
+* @return 1 if cross boundary, 0 if not, < 0 if errno
+*/
+int RingBuf_checkDataCrossBoundary(const RingBuf *ringBuf, int count) {
+ if (!ringBuf) {
+ ALOGE("%s(), ringBuf == NULL", __FUNCTION__);
+ ASSERT(0);
+ return -EINVAL;
+ }
+
+ if (count > RingBuf_getDataCount(ringBuf)) {
+ ALOGE("%s(), count %d > remain data %d", __FUNCTION__, count, RingBuf_getDataCount(ringBuf));
+ ASSERT(0);
+ return -EINVAL;
+ }
+
+ if (ringBuf->pRead <= ringBuf->pWrite) {
+ return 0;
+ } else {
+ char *end = ringBuf->pBufBase + ringBuf->bufLen;
+ int r2e = end - ringBuf->pRead;
+ if (count <= r2e) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+void RingBuf_dynamicChangeBufSize(struct RingBuf *ringBuf, uint32_t count) {
+ uint32_t dataCount = 0;
+ uint32_t freeSpace = 0;
+
+ uint32_t newCount = 0;
+ struct RingBuf newRingBuf;
+
+ if (!ringBuf) {
+ WARNING("null");
+ return;
+ }
+ if (!count) {
+ return;
+ }
+
+ memset(&newRingBuf, 0, sizeof(struct RingBuf));
+
+ dataCount = RingBuf_getDataCount(ringBuf);
+ freeSpace = RingBuf_getFreeSpace(ringBuf);
+
+ if ((freeSpace < count) ||
+ (freeSpace > (8 * (dataCount + count)))) {
+ newCount = (2 * (dataCount + count));
+ newCount += RING_BUF_SIZE_OFFSET;
+
+ ALOGD("%s(), %p: %u -> %u, dataCount %u, count %u, freeSpace %u",
+ __FUNCTION__,
+ ringBuf->pBufBase,
+ ringBuf->bufLen,
+ newCount,
+ dataCount,
+ count,
+ freeSpace);
+
+ newRingBuf.bufLen = newCount;
+ newRingBuf.pBufBase = new char[newRingBuf.bufLen];
+ newRingBuf.pRead = newRingBuf.pBufBase;
+ newRingBuf.pWrite = newRingBuf.pBufBase;
+ newRingBuf.pBufEnd = newRingBuf.pBufBase + newRingBuf.bufLen;
+
+ memset(newRingBuf.pBufBase, 0, newCount);
+
+ /* copy old data */
+ RingBuf_copyFromRingBuf(
+ &newRingBuf,
+ ringBuf,
+ dataCount);
+
+ /* delete old ringbuf */
+ delete[] ringBuf->pBufBase;
+
+ /* update info */
+ ringBuf->bufLen = newRingBuf.bufLen;
+ ringBuf->pBufBase = newRingBuf.pBufBase;
+ ringBuf->pRead = newRingBuf.pRead;
+ ringBuf->pWrite = newRingBuf.pWrite;
+ ringBuf->pBufEnd = newRingBuf.pBufEnd;
+ }
+}
+
+
+//---------end of ringbuffer implemenation------------------------------------------------------
+
+
+struct WriteSmoother *createWriteSmoother(void) {
+ struct WriteSmoother *smoother = NULL;
+
+ smoother = (struct WriteSmoother *)malloc(sizeof(struct WriteSmoother));
+ if (smoother == NULL) {
+ return NULL;
+ }
+
+ memset(smoother, 0, sizeof(struct WriteSmoother));
+
+ clock_gettime(CLOCK_MONOTONIC, &smoother->mOpenTime);
+
+ return smoother;
+}
+
+
+void doWriteSmoother(
+ struct WriteSmoother *smoother,
+ const uint64_t bufferTimeUs,
+ const uint64_t safeFrames) { // at least keep # frames in buf
+ struct timespec mCurTime;
+
+ uint64_t spendTimeUs = 0;
+ uint64_t diffTimeUs = 0;
+ uint64_t safeTimeUs = 0;
+
+ if (smoother == NULL) {
+ return;
+ }
+
+ // accumulate buffer playback time
+ smoother->mTotalBufferTimeUs += bufferTimeUs;
+
+ // spend time since open
+ memset((void *)&mCurTime, 0, sizeof(mCurTime));
+ clock_gettime(CLOCK_MONOTONIC, &mCurTime);
+ spendTimeUs = get_time_diff_ns(&smoother->mOpenTime, &mCurTime) / 1000;
+
+ if (spendTimeUs < smoother->mTotalBufferTimeUs) {
+ smoother->mDumpLogFlag = false; // normal case, clear dump flag
+
+ diffTimeUs = smoother->mTotalBufferTimeUs - spendTimeUs;
+ safeTimeUs = safeFrames * bufferTimeUs;
+
+ ALOGV("%s(), spend %u, accumulated %u, diff %u, safe %u",
+ __FUNCTION__,
+ (uint32_t)(spendTimeUs & 0xFFFFFFFF),
+ (uint32_t)(smoother->mTotalBufferTimeUs & 0xFFFFFFFF),
+ (uint32_t)(diffTimeUs & 0xFFFFFFFF),
+ (uint32_t)(safeTimeUs & 0xFFFFFFFF));
+
+ if (diffTimeUs > safeTimeUs) {
+ usleep(diffTimeUs - safeTimeUs);
+ }
+ } else {
+ diffTimeUs = spendTimeUs - smoother->mTotalBufferTimeUs;
+ if (diffTimeUs > MAX_WRITE_SMOOTHER_DELAY_TIME_US) {
+ ALOGE("%s(), spend %u, accumulated %u, diff %u > max %u. reset!!",
+ __FUNCTION__,
+ (uint32_t)(spendTimeUs & 0xFFFFFFFF),
+ (uint32_t)(smoother->mTotalBufferTimeUs & 0xFFFFFFFF),
+ (uint32_t)(diffTimeUs & 0xFFFFFFFF),
+ (uint32_t)(MAX_WRITE_SMOOTHER_DELAY_TIME_US & 0xFFFFFFFF));
+ smoother->mTotalBufferTimeUs = spendTimeUs;
+ } else if (smoother->mDumpLogFlag == false) {
+ smoother->mDumpLogFlag = true; // performace issue, only dump once
+ ALOGW("%s(), spend %u, accumulated %u, diff %u",
+ __FUNCTION__,
+ (uint32_t)(spendTimeUs & 0xFFFFFFFF),
+ (uint32_t)(smoother->mTotalBufferTimeUs & 0xFFFFFFFF),
+ (uint32_t)(diffTimeUs & 0xFFFFFFFF));
+ }
+ }
+}
+
+
+void updateWriteSmootherTime( // for suspend, update time only
+ struct WriteSmoother *smoother,
+ const uint64_t bufferTimeUs) {
+ if (smoother == NULL) {
+ return;
+ }
+
+ // accumulate buffer playback time
+ smoother->mTotalBufferTimeUs += bufferTimeUs;
+}
+
+
+void destroyWriteSmoother(struct WriteSmoother **smoother) {
+ if (smoother == NULL) {
+ return;
+ }
+ if (*smoother) {
+ free(*smoother);
+ *smoother = NULL;
+ }
+}
+
+
+
+
+short clamp16(int sample) {
+ if ((sample >> 15) ^ (sample >> 31)) {
+ sample = 0x7FFF ^ (sample >> 31);
+ }
+ return sample;
+}
+
+
+BCV_PCM_FORMAT get_bcv_pcm_format(audio_format_t source, audio_format_t target) {
+ BCV_PCM_FORMAT bcv_pcm_format = BCV_SIMPLE_SHIFT_BIT_END;
+ if (source == AUDIO_FORMAT_PCM_16_BIT) {
+ if (target == AUDIO_FORMAT_PCM_8_24_BIT) {
+ bcv_pcm_format = BCV_IN_Q1P15_OUT_Q9P23;
+ } else if (target == AUDIO_FORMAT_PCM_32_BIT) {
+ bcv_pcm_format = BCV_IN_Q1P15_OUT_Q1P31;
+ }
+ } else if (source == AUDIO_FORMAT_PCM_8_24_BIT) {
+ if (target == AUDIO_FORMAT_PCM_16_BIT) {
+ ALOGV("BCV_IN_Q1P31_OUT_Q1P15");
+ bcv_pcm_format = BCV_IN_Q1P31_OUT_Q1P15; /* NOTE: sync with SRC_IN_Q9P23_OUT_Q1P31 */
+ } else if (target == AUDIO_FORMAT_PCM_32_BIT) {
+ bcv_pcm_format = BCV_IN_Q9P23_OUT_Q1P31;
+ }
+ } else if (source == AUDIO_FORMAT_PCM_32_BIT) {
+ if (target == AUDIO_FORMAT_PCM_16_BIT) {
+ bcv_pcm_format = BCV_IN_Q1P31_OUT_Q1P15;
+ } else if (target == AUDIO_FORMAT_PCM_8_24_BIT) {
+ bcv_pcm_format = BCV_IN_Q1P31_OUT_Q9P23;
+ }
+ }
+ ALOGV("%s(), bcv_pcm_format %d", __FUNCTION__, bcv_pcm_format);
+ return bcv_pcm_format;
+}
+
+size_t getSizePerFrame(audio_format_t fmt, unsigned int numChannel)
+{
+ size_t sizePerChannel = audio_bytes_per_sample(fmt);
+ return numChannel * sizePerChannel;
+}
+
+uint32_t getPeriodBufSize(const stream_attribute_t *attribute, uint32_t period_time_ms) {
+ uint32_t size_per_frame = getSizePerFrame(attribute->audio_format, attribute->num_channels);
+ uint32_t size_per_period = (size_per_frame *
+ attribute->sample_rate *
+ period_time_ms) / 1000;
+
+ return size_per_period;
+}
+
+
+uint64_t getBufferLatencyMs(const stream_attribute_t *attribute, uint64_t bytes) {
+ if (attribute == NULL) {
+ return 0;
+ }
+
+ uint64_t size_per_sample = audio_bytes_per_sample(attribute->audio_format);
+ uint64_t size_per_frame = attribute->num_channels * size_per_sample;
+ uint64_t size_per_second = attribute->sample_rate * size_per_frame;
+
+ if (size_per_second == 0) {
+ return 0;
+ }
+ return (bytes * (uint64_t)1000) / (size_per_second);
+}
+
+
+uint64_t getBufferLatencyUs(const stream_attribute_t *attribute, uint64_t bytes) {
+ if (attribute == NULL) {
+ return 0;
+ }
+
+ uint64_t size_per_sample = audio_bytes_per_sample(attribute->audio_format);
+ uint64_t size_per_frame = attribute->num_channels * size_per_sample;
+ uint64_t size_per_second = attribute->sample_rate * size_per_frame;
+
+ if (size_per_second == 0) {
+ return 0;
+ }
+ return (bytes * (uint64_t)1000000) / (size_per_second);
+}
+
+
+//--------pc dump operation
+
+struct BufferDump {
+ FILE *fp;
+ bool fileClosed;
+ void *pBufBase;
+ int ssize_t;
+};
+
+#if defined(PC_EMULATION)
+HANDLE hPCMDumpThread = NULL;
+HANDLE PCMDataNotifyEvent = NULL;
+#else
+pthread_t hPCMDumpThread = 0;
+pthread_cond_t PCMDataNotifyEvent;
+pthread_mutex_t PCMDataNotifyMutex;
+#endif
+bool pcmDumpThreadCreated = false;
+
+AudioLock mPCMDumpMutex; // use for PCM buffer dump
+
+Vector<FILE *> mDumpFileVector; // vector to save current recording files
+std::queue<BufferDump *> mDumpBufferQueue; // vector to save current recording data
+
+int mSleepTime = 2;
+
+void *PCMDumpThread(void *arg);
+
+int AudiocheckAndCreateDirectory(const char *pC) {
+ char tmp[PATH_MAX];
+ int i = 0;
+ while (*pC) {
+ tmp[i] = *pC;
+ if (*pC == '/' && i) {
+ tmp[i] = '\0';
+ if (access(tmp, F_OK) != 0) {
+ if (mkdir(tmp, 0770) == -1) {
+ ALOGE("AudioDumpPCM: mkdir error! %s\n", (char *)strerror(errno));
+ return -1;
+ }
+ }
+ tmp[i] = '/';
+ }
+ i++;
+ pC++;
+ }
+ return 0;
+}
+
+bool bDumpStreamOutFlg = false;
+bool bDumpStreamInFlg = false;
+
+FILE *AudioOpendumpPCMFile(const char *filepath, const char *propty) {
+#ifdef MTK_AUDIO_HAL_DUMP_DISABLE
+ UNUSED(filepath);
+ UNUSED(propty);
+#else
+ char value[PROPERTY_VALUE_MAX];
+ int ret;
+ property_get(propty, value, "0");
+ int bflag = atoi(value);
+
+ if (!bflag) {
+ if (!strcmp(propty, streamout_propty) && bDumpStreamOutFlg) {
+ bflag = 1;
+ } else if (!strcmp(propty, streamin_propty) && bDumpStreamInFlg) {
+ bflag = 1;
+ }
+ }
+
+ if (bflag) {
+ ret = AudiocheckAndCreateDirectory(filepath);
+ if (ret < 0) {
+ ALOGE("AudioOpendumpPCMFile dumpPCMData checkAndCreateDirectory() fail!!!");
+ } else {
+ FILE *fp = fopen(filepath, "wb");
+ if (fp != NULL) {
+
+ AL_LOCK(mPCMDumpMutex);
+ //ALOGD("AudioOpendumpPCMFile file=%p, pBD=%p",fp, pBD);
+ mDumpFileVector.add(fp);
+ /*for (size_t i = 0; i < mDumpFileVector.size() ; i++)
+ {
+ ALOGD("AudioOpendumpPCMFile i=%zu, handle=%p",i,mDumpFileVector.itemAt(i));
+ }*/
+
+ if (!pcmDumpThreadCreated) {
+#if defined(PC_EMULATION)
+ PCMDataNotifyEvent = CreateEvent(NULL, TRUE, FALSE, "PCMDataNotifyEvent");
+ hPCMDumpThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PCMDumpThread, NULL, 0, 0);
+ if (hPCMDumpThread == 0) {
+ ALOGE("hPCMDumpThread create fail!!!");
+ } else {
+ ALOGD("hPCMDumpThread=%lu created", hPCMDumpThread);
+ pcmDumpThreadCreated = true;
+ }
+#else
+ //create PCM data dump thread here
+ int ret;
+ ret = pthread_create(&hPCMDumpThread, NULL, PCMDumpThread, NULL);
+ if (ret != 0) {
+ ALOGE("hPCMDumpThread create fail!!!");
+ } else {
+ ALOGD("hPCMDumpThread created");
+ pcmDumpThreadCreated = true;
+ }
+ ret = pthread_cond_init(&PCMDataNotifyEvent, NULL);
+ if (ret != 0) {
+ ALOGE("PCMDataNotifyEvent create fail!!!");
+ }
+
+ ret = pthread_mutex_init(&PCMDataNotifyMutex, NULL);
+ if (ret != 0) {
+ ALOGE("PCMDataNotifyMutex create fail!!!");
+ }
+#endif
+ }
+ AL_UNLOCK(mPCMDumpMutex);
+ return fp;
+ } else {
+ ALOGE("AudioFlinger AudioOpendumpPCMFile %s fail", propty);
+ }
+ }
+ }
+#endif
+ return NULL;
+}
+
+void AudioCloseDumpPCMFile(FILE *file) {
+#ifdef MTK_AUDIO_HAL_DUMP_DISABLE
+ UNUSED(file);
+#else
+ if (file != NULL) {
+ AL_LOCK(mPCMDumpMutex);
+ //ALOGD("AudioCloseDumpPCMFile file=%p, HandleCount=%d",file,mDumpFileVector.size());
+ if (mDumpFileVector.size()) {
+ for (size_t i = 0; i < mDumpFileVector.size(); i++) {
+ //ALOGD("AudioCloseDumpPCMFile i=%d, handle=%p",i,mDumpFileVector.itemAt(i));
+ if (file == mDumpFileVector.itemAt(i)) {
+ // Add file closed notice to mDumpBufferQueue
+ BufferDump *newInBuffer = new BufferDump;
+ newInBuffer->fp = file;
+ newInBuffer->pBufBase = NULL;
+ newInBuffer->ssize_t = 0;
+ newInBuffer->fileClosed = true;
+ mDumpBufferQueue.push(newInBuffer);
+
+ mDumpFileVector.removeAt(i);
+ }
+ }
+ }
+ AL_UNLOCK(mPCMDumpMutex);
+
+ if (!pcmDumpThreadCreated) {
+ fclose(file);
+ }
+ file = NULL;
+ } else {
+ ALOGE("AudioCloseDumpPCMFile file== NULL");
+ }
+#endif
+}
+
+void AudioDumpPCMData(void *buffer, uint32_t bytes, FILE *file) {
+#ifdef MTK_AUDIO_HAL_DUMP_DISABLE
+ UNUSED(buffer);
+ UNUSED(bytes);
+ UNUSED(file);
+#else
+ if (pcmDumpThreadCreated) {
+ AL_LOCK(mPCMDumpMutex);
+ if (mDumpFileVector.size()) {
+ for (size_t i = 0; i < mDumpFileVector.size() ; i++) {
+ if (file == mDumpFileVector.itemAt(i)) {
+ BufferDump *newInBuffer = new BufferDump;
+ newInBuffer->pBufBase = (short *) malloc(bytes);
+ memcpy(newInBuffer->pBufBase, buffer, bytes);
+ newInBuffer->ssize_t = bytes;
+ newInBuffer->fp = file;
+ newInBuffer->fileClosed = false;
+ mDumpBufferQueue.push(newInBuffer);
+
+ if (mSleepTime == -1) { //need to send event
+#if defined(PC_EMULATION)
+ SetEvent(PCMDataNotifyEvent);
+#else
+ pthread_mutex_lock(&PCMDataNotifyMutex);
+ pthread_cond_signal(&PCMDataNotifyEvent);
+ pthread_mutex_unlock(&PCMDataNotifyMutex);
+#endif
+ }
+ }
+ }
+ }
+ AL_UNLOCK(mPCMDumpMutex);
+ } else { //if no dump thread, just write the data
+ fwrite((void *)buffer, sizeof(char), bytes, file);
+ }
+#endif
+}
+
+void *PCMDumpThread(void *arg __unused) {
+ ALOGD("PCMDumpThread");
+ bool bHasdata = false;
+ int iNoDataCount = 0;
+ BufferDump *bp = NULL;
+
+ while (1) {
+ bHasdata = false;
+ bp = NULL;
+
+ AL_LOCK(mPCMDumpMutex);
+ if (mDumpBufferQueue.size()) {
+ bp = mDumpBufferQueue.front();
+ mDumpBufferQueue.pop();
+ bHasdata = true;
+ }
+ AL_UNLOCK(mPCMDumpMutex);
+
+ if (bp != NULL) {
+ if (bp->pBufBase && bp->fp) {
+ fwrite(bp->pBufBase, bp->ssize_t, 1, bp->fp);
+ free(bp->pBufBase);
+ }
+ if (bp->fileClosed) {
+ fclose(bp->fp);
+ }
+ delete bp;
+ }
+
+ if (!bHasdata) {
+ iNoDataCount++;
+ if (iNoDataCount >= 1000) {
+ mSleepTime = -1;
+ ALOGD("PCMDumpThread, wait for new data dump\n");
+#if defined(PC_EMULATION)
+ WaitForSingleObject(PCMDataNotifyEvent, INFINITE);
+ ResetEvent(PCMDataNotifyEvent);
+#else
+ pthread_mutex_lock(&PCMDataNotifyMutex);
+ pthread_cond_wait(&PCMDataNotifyEvent, &PCMDataNotifyMutex);
+ pthread_mutex_unlock(&PCMDataNotifyMutex);
+ ALOGD("PCMDumpThread, PCM data dump again\n");
+#endif
+ } else {
+ mSleepTime = 10;
+ usleep(mSleepTime * 1000);
+ }
+ } else {
+ iNoDataCount = 0;
+ //mSleepTime = 2;
+ //usleep(mSleepTime * 1000);
+ }
+ /*
+ if((mDumpFileVector.size() == 0) && (mDumpBufferQueue.size() == 0))
+ {
+ ALOGD( "PCMDumpThread exit, no dump handle real");
+ hPCMDumpThread = NULL;
+ pthread_exit(NULL);
+ return 0;
+ }*/
+
+ }
+
+ ALOGD("PCMDumpThread exit");
+ pcmDumpThreadCreated = false;
+ pthread_exit(NULL);
+ return 0;
+}
+
+#define CVSD_LOOPBACK_BUFFER_SIZE (960 * 10)//BTSCO_CVSD_RX_FRAME*SCO_RX_PCM8K_BUF_SIZE * 10
+static uint8_t cvsd_temp_buffer[CVSD_LOOPBACK_BUFFER_SIZE]; //temp buf only for dump to file
+static uint32_t cvsd_temp_w = 0;
+static uint32_t cvsd_temp_r = 0;
+const static uint32_t cvsd_temp_size = CVSD_LOOPBACK_BUFFER_SIZE;
+
+void CVSDLoopbackGetWriteBuffer(uint8_t **buffer, uint32_t *buf_len) { // in bytes
+ int32_t count;
+
+ if (cvsd_temp_r > cvsd_temp_w) {
+ count = cvsd_temp_r - cvsd_temp_w - 8;
+ } else {
+ count = cvsd_temp_size - cvsd_temp_w;
+ }
+
+ *buffer = (uint8_t *)&cvsd_temp_buffer[cvsd_temp_w];
+ *buf_len = (count > 0) ? count : 0;
+ // ALOGD("BT_SW_CVSD CODEC LOOPBACK record thread: CVSDLoopbackGetWriteBuffer: buf_len: %d, cvsd_temp_buffer %p", *buf_len, cvsd_temp_buffer);
+ ALOGD("%s(), cvsd_temp_w %u, cvsd_temp_r %u, cvsd_temp_buffer %p, ret buffer %p, buf_len %u",
+ __FUNCTION__, cvsd_temp_w, cvsd_temp_r, cvsd_temp_buffer, *buffer, *buf_len);
+}
+
+void CVSDLoopbackGetReadBuffer(uint8_t **buffer, uint32_t *buf_len) { // in bytes
+ int32_t count;
+
+ if (cvsd_temp_w >= cvsd_temp_r) {
+ count = cvsd_temp_w - cvsd_temp_r;
+ } else {
+ count = cvsd_temp_size - cvsd_temp_r;
+ }
+
+ *buffer = (uint8_t *)&cvsd_temp_buffer[cvsd_temp_r];
+ *buf_len = count;
+ ALOGD("%s(), cvsd_temp_w %u, cvsd_temp_r %u, cvsd_temp_buffer %p, ret buffer %p, buf_len %u",
+ __FUNCTION__, cvsd_temp_w, cvsd_temp_r, cvsd_temp_buffer, *buffer, *buf_len);
+
+ // ALOGD("BT_SW_CVSD CODEC LOOPBACK record thread: CVSDLoopbackGetReadBuffer: buf_len: %d, cvsd_temp_buffer %p", count, cvsd_temp_buffer);
+}
+
+void CVSDLoopbackReadDataDone(uint32_t len) { // in bytes
+ cvsd_temp_r += len;
+ if (cvsd_temp_r >= cvsd_temp_size) {
+ cvsd_temp_r = 0;
+ }
+ // ALOGD("BT_SW_CVSD CODEC LOOPBACK record thread: CVSDLoopbackReadDataDone: len: %d", len);
+ ALOGD("%s(), cvsd_temp_w %u, cvsd_temp_r %u, cvsd_temp_buffer %p, len %u",
+ __FUNCTION__, cvsd_temp_w, cvsd_temp_r, cvsd_temp_buffer, len);
+
+}
+
+void CVSDLoopbackWriteDataDone(uint32_t len) { // in bytes
+ cvsd_temp_w += len;
+ if (cvsd_temp_w >= cvsd_temp_size) {
+ cvsd_temp_w = 0;
+ }
+ ALOGD("%s(), cvsd_temp_w %u, cvsd_temp_r %u, cvsd_temp_buffer %p, len %u",
+ __FUNCTION__, cvsd_temp_w, cvsd_temp_r, cvsd_temp_buffer, len);
+}
+
+void CVSDLoopbackResetBuffer(void) { // in bytes
+ memset(cvsd_temp_buffer, 0, CVSD_LOOPBACK_BUFFER_SIZE);
+ cvsd_temp_w = CVSD_LOOPBACK_BUFFER_SIZE / 2; //if 0, deadlock
+ cvsd_temp_r = 0;
+ ALOGD("BT_SW_CVSD CODEC LOOPBACK record thread: CVSDLoopbackResetBuffer");
+}
+
+int32_t CVSDLoopbackGetFreeSpace(void) {
+ int32_t count;
+
+ if (cvsd_temp_r > cvsd_temp_w) {
+ count = cvsd_temp_r - cvsd_temp_w - 8;
+ } else {
+ count = cvsd_temp_size + cvsd_temp_r - cvsd_temp_w - 8;
+ }
+
+ return (count > 0) ? count : 0; // free size in byte
+}
+
+int32_t CVSDLoopbackGetDataCount(void) {
+ return (cvsd_temp_size - CVSDLoopbackGetFreeSpace() - 8);
+}
+
+const char* PROPERTY_KEY_2IN1SPK_ON = "vendor.persist.af.feature.2in1spk";
+const char* PROPERTY_KEY_VIBSPK_ON = "vendor.persist.af.feature.vibspk";
+const char* PROPERTY_VOW_DUAL_MIC_ON = "vendor.persist.af.feature.vowdualmic";
+static const char *g_phone_mic_propty = "persist.vendor.rm.debug.phonemic";
+static const char *g_headset_mic_propty = "persist.vendor.rm.debug.headsetmic";
+
+bool IsAudioSupportFeature(int dFeatureOption) {
+ bool bSupportFlg = false;
+ char stForFeatureUsage[PROPERTY_VALUE_MAX];
+ bool dmic_usage = false;
+ bool property_set = false;
+
+ switch (dFeatureOption) {
+ case AUDIO_SUPPORT_DMIC: {
+ // PHONE_MIC_MODE/HEADSET_MIC_MODE defined in audio_custom_exp.h
+ bSupportFlg = ((PHONE_MIC_MODE == AUDIO_MIC_MODE_DMIC) || (PHONE_MIC_MODE == AUDIO_MIC_MODE_DMIC_LP) ||
+ (HEADSET_MIC_MODE == AUDIO_MIC_MODE_DMIC) || (HEADSET_MIC_MODE == AUDIO_MIC_MODE_DMIC_LP)) ?
+ true : false;
+
+ property_get(g_phone_mic_propty, stForFeatureUsage, "0");
+ if (atoi(stForFeatureUsage) != 0) {
+ property_set = true;
+ dmic_usage = (atoi(stForFeatureUsage) == AUDIO_MIC_MODE_DMIC) ||
+ (atoi(stForFeatureUsage) == AUDIO_MIC_MODE_DMIC_LP) ? true : false;
+ }
+ property_get(g_headset_mic_propty, stForFeatureUsage, "0");
+ if (atoi(stForFeatureUsage) != 0) {
+ property_set = true;
+ dmic_usage |= (atoi(stForFeatureUsage) == AUDIO_MIC_MODE_DMIC) ||
+ (atoi(stForFeatureUsage) == AUDIO_MIC_MODE_DMIC_LP) ? true : false;
+ }
+
+ if (property_set) {
+ bSupportFlg = dmic_usage;
+ }
+ ALOGV("%s AUDIO_SUPPORT_DMIC bSupportFlg[%d]", __FUNCTION__, bSupportFlg);
+
+ break;
+ }
+ case AUDIO_SUPPORT_2IN1_SPEAKER: {
+#ifdef USING_2IN1_SPEAKER
+ property_get(PROPERTY_KEY_2IN1SPK_ON, stForFeatureUsage, "1"); //"1": default on
+#else
+ property_get(PROPERTY_KEY_2IN1SPK_ON, stForFeatureUsage, "0"); //"0": default off
+#endif
+ bSupportFlg = (stForFeatureUsage[0] == '0') ? false : true;
+ //ALOGD("IsAudioSupportFeature AUDIO_SUPPORT_2IN1_SPEAKER [%d]\n",bSupportFlg);
+
+ break;
+ }
+ case AUDIO_SUPPORT_VIBRATION_SPEAKER: {
+#ifdef MTK_VIBSPK_SUPPORT
+ property_get(PROPERTY_KEY_VIBSPK_ON, stForFeatureUsage, "1"); //"1": default on
+#else
+ property_get(PROPERTY_KEY_VIBSPK_ON, stForFeatureUsage, "0"); //"0": default off
+#endif
+ bSupportFlg = (stForFeatureUsage[0] == '0') ? false : true;
+ //ALOGD("IsAudioSupportFeature AUDIO_SUPPORT_VIBRATION_SPEAKER [%d]\n",bSupportFlg);
+
+ break;
+ }
+ case AUDIO_SUPPORT_EXTERNAL_BUILTIN_MIC: {
+#ifdef MTK_EXTERNAL_BUILTIN_MIC_SUPPORT
+ bSupportFlg = true;
+#else
+ bSupportFlg = false;
+#endif
+ break;
+ }
+ case AUDIO_SUPPORT_EXTERNAL_ECHO_REFERENCE: {
+#ifdef MTK_EXTERNAL_SPEAKER_DAC_SUPPORT
+ bSupportFlg = true;
+#else
+ bSupportFlg = false;
+#endif
+ break;
+ }
+ case AUDIO_SUPPORT_VOW_DUAL_MIC: {
+ property_get(PROPERTY_VOW_DUAL_MIC_ON, stForFeatureUsage, "0"); //"0": default off
+
+ bSupportFlg = (stForFeatureUsage[0] == '0') ? false : true;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return bSupportFlg;
+}
+
+bool isBtSpkDevice(audio_devices_t devices) {
+ return (devices & AUDIO_DEVICE_OUT_SPEAKER) && (devices & AUDIO_DEVICE_OUT_ALL_SCO);
+}
+
+timespec GetSystemTime(bool print) {
+ struct timespec systemtime;
+ int rc;
+ rc = clock_gettime(CLOCK_MONOTONIC, &systemtime);
+ if (rc != 0) {
+ systemtime.tv_sec = 0;
+ systemtime.tv_nsec = 0;
+ ALOGD("%s() clock_gettime error", __FUNCTION__);
+ }
+ if (print == true) {
+ ALOGD("%s(), sec %ld nsec %ld", __FUNCTION__, systemtime.tv_sec, systemtime.tv_nsec);
+ }
+
+ return systemtime;
+}
+
+uint32_t GetMicDeviceMode(uint32_t mic_category) { //0: phonemic, 1: headsetmic
+ char value[PROPERTY_VALUE_MAX];
+ int ret, bflag;
+ uint32_t mPhoneMicMode, mHeadsetMicMode;
+
+ if (mic_category == 0) {
+#ifdef PHONE_MIC_MODE //defined in audio_custom_exp.h
+ mPhoneMicMode = PHONE_MIC_MODE;
+ ALOGD("PHONE_MIC_MODE defined!, mPhoneMicMode = %d", mPhoneMicMode);
+#else
+ mPhoneMicMode = AUDIO_MIC_MODE_DCC;
+#endif
+ // control by setprop
+ property_get(g_phone_mic_propty, value, "0");
+ bflag = atoi(value);
+ if (bflag != 0) {
+ mPhoneMicMode = bflag;
+ ALOGD("mPhoneMicMode getprop, mPhoneMicMode = %d", mPhoneMicMode);
+ }
+ return mPhoneMicMode;
+ } else if (mic_category == 1) {
+#ifdef HEADSET_MIC_MODE //defined in audio_custom_exp.h
+ mHeadsetMicMode = HEADSET_MIC_MODE;
+ ALOGD("HEADSET_MIC_MODE defined!, mHeadsetMicMode = %d", mHeadsetMicMode);
+#else
+ mHeadsetMicMode = AUDIO_MIC_MODE_DCC;
+#endif
+ // control by setprop
+ property_get(g_headset_mic_propty, value, "0");
+ bflag = atoi(value);
+ if (bflag != 0) {
+ mHeadsetMicMode = bflag;
+ ALOGD("mHeadsetMicMode getprop, mHeadsetMicMode = %d", mHeadsetMicMode);
+ }
+ return mHeadsetMicMode;
+ } else {
+ ALOGE("%s() wrong mic_category!!!", __FUNCTION__);
+ return 0;
+ }
+}
+
+unsigned int FormatTransfer(int SourceFormat, int TargetFormat, void *Buffer, unsigned int mReadBufferSize) {
+ unsigned mReformatSize = 0;
+ int *srcbuffer = (int *)Buffer;
+ short *dstbuffer = (short *)Buffer;
+ if (SourceFormat == PCM_FORMAT_S32_LE && TargetFormat == PCM_FORMAT_S16_LE) {
+ short temp = 0;
+ while (mReadBufferSize) {
+ temp = (short)((*srcbuffer) >> 8);
+ *dstbuffer = temp;
+ srcbuffer++;
+ dstbuffer++;
+ mReadBufferSize -= sizeof(int);
+ mReformatSize += sizeof(short);
+ }
+ } else {
+ mReformatSize = mReadBufferSize;
+ }
+ return mReformatSize;
+}
+
+#define FACTORY_BOOT 4
+#define ATE_FACTORY_BOOT 6
+#define BOOTMODE_PATH "/sys/class/BOOT/BOOT/boot/boot_mode"
+
+int readSys_int(char const *path) {
+ int fd;
+
+ if (path == NULL) {
+ return -1;
+ }
+
+ fd = open(path, O_RDONLY);
+ if (fd >= 0) {
+ char buffer[20];
+ int amt = read(fd, buffer, sizeof(int));
+ close(fd);
+ return amt == -1 ? -errno : atoi(buffer);
+ }
+ ALOGE("write_int failed to open %s\n", path);
+ return -errno;
+}
+
+int InFactoryMode() {
+ int bootMode;
+ int ret = false;
+
+#if defined(MTK_YOCTO_AUDIO)
+ bootMode = readSys_int(NULL);
+#else
+ bootMode = readSys_int(BOOTMODE_PATH);
+#endif
+ ALOGD("bootMode = %d", bootMode);
+ if (FACTORY_BOOT == bootMode) {
+ ALOGD("Factory mode boot!\n");
+ ret = true;
+ } else if (ATE_FACTORY_BOOT == bootMode) {
+ ALOGD("ATE Factory mode boot!\n");
+ ret = true;
+ } else {
+ ret = false;
+ ALOGD("Unsupported factory mode!\n");
+ }
+ return ret;
+}
+
+int In64bitsProcess() {
+ char *platform = (char *)getauxval(AT_PLATFORM);
+ if (strcmp(platform, platform_arch) == 0) {
+ return true;
+ }
+ return false;
+}
+
+inline void *openAudioRelatedLib(const char *filepath) {
+ if (filepath == NULL) {
+ ALOGE("%s null input parameter", __FUNCTION__);
+ return NULL;
+ } else {
+ if (access(filepath, R_OK) == 0) {
+ return dlopen(filepath, RTLD_NOW);
+ } else {
+ ALOGE("%s filepath %s doesn't exist", __FUNCTION__, filepath);
+ return NULL;
+ }
+ }
+}
+inline bool openAudioComponentEngine(void) {
+ if (g_AudioComponentEngineHandle == NULL) {
+ g_CreateMtkAudioBitConverter = NULL;
+ g_CreateMtkAudioSrc = NULL;
+ g_CreateMtkAudioLoud = NULL;
+ g_DestroyMtkAudioBitConverter = NULL;
+ g_DestroyMtkAudioSrc = NULL;
+ g_DestroyMtkAudioLoud = NULL;
+ g_AudioComponentEngineHandle = openAudioRelatedLib(AUDIO_COMPONENT_ENGINE_LIB_VENDOR_PATH);
+ if (g_AudioComponentEngineHandle == NULL) {
+ g_AudioComponentEngineHandle = openAudioRelatedLib(AUDIO_COMPONENT_ENGINE_LIB_PATH);
+ return (g_AudioComponentEngineHandle == NULL) ? false : true;
+ }
+ }
+ return true;
+}
+
+inline void closeAudioComponentEngine(void) {
+ if (g_AudioComponentEngineHandle != NULL) {
+ dlclose(g_AudioComponentEngineHandle);
+ g_AudioComponentEngineHandle = NULL;
+ g_CreateMtkAudioBitConverter = NULL;
+ g_CreateMtkAudioSrc = NULL;
+ g_CreateMtkAudioLoud = NULL;
+ g_DestroyMtkAudioBitConverter = NULL;
+ g_DestroyMtkAudioSrc = NULL;
+ g_DestroyMtkAudioLoud = NULL;
+ }
+}
+
+MtkAudioBitConverterBase *newMtkAudioBitConverter(uint32_t sampling_rate, uint32_t channel_num, BCV_PCM_FORMAT format) {
+ if (!openAudioComponentEngine()) {
+ return NULL;
+ }
+
+ if (g_CreateMtkAudioBitConverter == NULL) {
+ g_CreateMtkAudioBitConverter = (create_AudioBitConverter *)dlsym(g_AudioComponentEngineHandle, "createMtkAudioBitConverter");
+ const char *dlsym_error1 = dlerror();
+ if (g_CreateMtkAudioBitConverter == NULL) {
+ ALOGE("Error -dlsym createMtkAudioBitConverter fail");
+ closeAudioComponentEngine();
+ return NULL;
+ }
+ }
+ ALOGV("%p g_CreateMtkAudioBitConverter %p", g_AudioComponentEngineHandle, g_CreateMtkAudioBitConverter);
+ return g_CreateMtkAudioBitConverter(sampling_rate, channel_num, format);
+}
+
+MtkAudioSrcBase *newMtkAudioSrc(uint32_t input_SR, uint32_t input_channel_num, uint32_t output_SR, uint32_t output_channel_num, SRC_PCM_FORMAT format) {
+#if !defined(MTK_YOCTO_AUDIO)
+ if (!openAudioComponentEngine()) {
+ return NULL;
+ }
+
+ if (g_CreateMtkAudioSrc == NULL) {
+ g_CreateMtkAudioSrc = (create_AudioSrc *)dlsym(g_AudioComponentEngineHandle, "createMtkAudioSrc");
+ const char *dlsym_error1 = dlerror();
+ if (g_CreateMtkAudioSrc == NULL) {
+ ALOGE("Error -dlsym createMtkAudioSrc fail");
+ closeAudioComponentEngine();
+ return NULL;
+ }
+ }
+ ALOGV("%p g_CreateMtkAudioSrc %p", g_AudioComponentEngineHandle, g_CreateMtkAudioSrc);
+ return g_CreateMtkAudioSrc(input_SR, input_channel_num, output_SR, output_channel_num, format);
+#else
+ return new MtkAudioSrc(input_SR, input_channel_num, output_SR, output_channel_num, format);
+#endif
+}
+
+MtkAudioLoudBase *newMtkAudioLoud(uint32_t eFLTtype) {
+ if (!openAudioComponentEngine()) {
+ return NULL;
+ }
+
+ if (g_CreateMtkAudioLoud == NULL) {
+ g_CreateMtkAudioLoud = (create_AudioLoud *)dlsym(g_AudioComponentEngineHandle, "createMtkAudioLoud");
+ const char *dlsym_error1 = dlerror();
+ if (g_CreateMtkAudioLoud == NULL) {
+ ALOGE("Error -dlsym createMtkAudioLoud fail");
+ closeAudioComponentEngine();
+ return NULL;
+ }
+ }
+ ALOGV("%p g_CreateMtkAudioLoud %p", g_AudioComponentEngineHandle, g_CreateMtkAudioLoud);
+ return g_CreateMtkAudioLoud(eFLTtype);
+}
+
+MtkAudioDcRemoveBase *newMtkDcRemove() {
+ if (!openAudioComponentEngine()) {
+ ALOGD("openAudioComponentEngine fail");
+ return NULL;
+ }
+
+ if (g_CreateMtkDcRemove == NULL) {
+ g_CreateMtkDcRemove = (create_DcRemove *)dlsym(g_AudioComponentEngineHandle, "createMtkDcRemove");
+ const char *dlsym_error1 = dlerror();
+ if (g_CreateMtkDcRemove == NULL) {
+ ALOGE("Error -dlsym createMtkDcRemove fail");
+ closeAudioComponentEngine();
+ return NULL;
+ }
+ }
+ ALOGV("%p g_CreateMtkDcRemove %p", g_AudioComponentEngineHandle, g_CreateMtkDcRemove);
+ return g_CreateMtkDcRemove();
+}
+
+void deleteMtkAudioBitConverter(MtkAudioBitConverterBase *pObject) {
+ if (!openAudioComponentEngine()) {
+ return;
+ }
+
+ if (g_DestroyMtkAudioBitConverter == NULL) {
+ g_DestroyMtkAudioBitConverter = (destroy_AudioBitConverter *)dlsym(g_AudioComponentEngineHandle, "destroyMtkAudioBitConverter");
+ const char *dlsym_error1 = dlerror();
+ if (g_DestroyMtkAudioBitConverter == NULL) {
+ ALOGE("Error -dlsym destroyMtkAudioBitConverter fail");
+ closeAudioComponentEngine();
+ return;
+ }
+ }
+ ALOGV("%p g_DestroyMtkAudioBitConverter %p", g_AudioComponentEngineHandle, g_DestroyMtkAudioBitConverter);
+ g_DestroyMtkAudioBitConverter(pObject);
+ return;
+}
+
+void deleteMtkAudioSrc(MtkAudioSrcBase *pObject) {
+#if !defined(MTK_YOCTO_AUDIO)
+ if (!openAudioComponentEngine()) {
+ return;
+ }
+
+ if (g_DestroyMtkAudioSrc == NULL) {
+ g_DestroyMtkAudioSrc = (destroy_AudioSrc *)dlsym(g_AudioComponentEngineHandle, "destroyMtkAudioSrc");
+ const char *dlsym_error1 = dlerror();
+ if (g_DestroyMtkAudioSrc == NULL) {
+ ALOGE("Error -dlsym destroyMtkAudioSrc fail");
+ closeAudioComponentEngine();
+ return;
+ }
+ }
+ ALOGV("%p g_DestroyMtkAudioSrc %p", g_AudioComponentEngineHandle, g_DestroyMtkAudioSrc);
+ g_DestroyMtkAudioSrc(pObject);
+#else
+ if (pObject != NULL) {
+ delete pObject;
+ }
+#endif
+}
+
+void deleteMtkAudioLoud(MtkAudioLoudBase *pObject) {
+ if (!openAudioComponentEngine()) {
+ return;
+ }
+
+ if (g_DestroyMtkAudioLoud == NULL) {
+ g_DestroyMtkAudioLoud = (destroy_AudioLoud *)dlsym(g_AudioComponentEngineHandle, "destroyMtkAudioLoud");
+ const char *dlsym_error1 = dlerror();
+ if (g_DestroyMtkAudioLoud == NULL) {
+ ALOGE("Error -dlsym destroyMtkAudioLoud fail");
+ closeAudioComponentEngine();
+ return;
+ }
+ }
+ ALOGV("%p g_DestroyMtkAudioLoud %p", g_AudioComponentEngineHandle, g_DestroyMtkAudioLoud);
+ g_DestroyMtkAudioLoud(pObject);
+ return;
+}
+
+void deleteMtkDcRemove(MtkAudioDcRemoveBase *pObject) {
+ if (!openAudioComponentEngine()) {
+ return;
+ }
+
+ if (g_DestroyMtkDcRemove == NULL) {
+ g_DestroyMtkDcRemove = (destroy_DcRemove *)dlsym(g_AudioComponentEngineHandle, "destroyMtkAudioDcRemove");
+ const char *dlsym_error1 = dlerror();
+ if (g_DestroyMtkDcRemove == NULL) {
+ ALOGE("Error -dlsym destroyMtkDcRemove fail");
+ closeAudioComponentEngine();
+ return;
+ }
+ }
+ ALOGV("%p g_DestroyMtkAudioLoud %p", g_AudioComponentEngineHandle, g_DestroyMtkDcRemove);
+ g_DestroyMtkDcRemove(pObject);
+ return;
+}
+#if !defined(MTK_YOCTO_AUDIO)
+inline bool openAudioCompensationFilter(void) {
+ if (g_AudioCompensationFilterHandle == NULL) {
+ g_setAudioCompFltCustParamFrom = NULL;
+ g_getAudioCompFltCustParamFrom = NULL;
+ g_AudioCompensationFilterHandle = openAudioRelatedLib(AUDIO_COMPENSATION_FILTER_LIB_VENDOR_PATH);
+ if (g_AudioCompensationFilterHandle == NULL) {
+ g_AudioCompensationFilterHandle = openAudioRelatedLib(AUDIO_COMPENSATION_FILTER_LIB_PATH);
+ return (g_AudioCompensationFilterHandle == NULL) ? false : true;
+ }
+ }
+ return true;
+}
+
+inline void closeAudioCompensationFilter(void) {
+ if (g_AudioCompensationFilterHandle != NULL) {
+ dlclose(g_AudioCompensationFilterHandle);
+ g_AudioCompensationFilterHandle = NULL;
+ g_setAudioCompFltCustParamFrom = NULL;
+ g_getAudioCompFltCustParamFrom = NULL;
+ }
+}
+
+int setAudioCompFltCustParam(AudioCompFltType_t eFLTtype, AUDIO_ACF_CUSTOM_PARAM_STRUCT *audioParam) {
+ if (!openAudioCompensationFilter()) {
+ return 0;
+ } else {
+ if (g_setAudioCompFltCustParamFrom == NULL) {
+ g_setAudioCompFltCustParamFrom = (setFunAudioCompFltCustParam *)dlsym(g_AudioCompensationFilterHandle, "setAudioCompFltCustParamToStorage");
+ const char *dlsym_error1 = dlerror();
+ if (g_setAudioCompFltCustParamFrom == NULL) {
+ closeAudioCompensationFilter();
+ ALOGE("Error -dlsym setAudioCompFltCustParam fail");
+ return 0;
+ }
+ }
+ }
+ return g_setAudioCompFltCustParamFrom(eFLTtype, audioParam);
+}
+
+int getAudioCompFltCustParam(AudioCompFltType_t eFLTtype, AUDIO_ACF_CUSTOM_PARAM_STRUCT *audioParam, const char *custScene) {
+ if (!openAudioCompensationFilter()) {
+ return 0;
+ } else {
+ if (g_getAudioCompFltCustParamFrom == NULL) {
+ g_getAudioCompFltCustParamFrom = (getFunAudioCompFltCustParam *)dlsym(g_AudioCompensationFilterHandle, "getAudioCompFltCustParamFromStorage");
+ const char *dlsym_error1 = dlerror();
+ if (g_getAudioCompFltCustParamFrom == NULL) {
+ closeAudioCompensationFilter();
+ ALOGE("Error -dlsym getAudioCompFltCustParam fail");
+ return 0;
+ }
+ }
+ }
+ return g_getAudioCompFltCustParamFrom(eFLTtype, audioParam, custScene);
+}
+#endif
+
+bool generateVmDumpByEpl(const char *eplPath, const char *vmPath) {
+ bool ret = true;
+ FILE *eplFp = fopen(eplPath, "rb");
+ FILE *vmFp = fopen(vmPath, "wb");
+
+ if (eplFp && vmFp) {
+ uint16_t sampleRate = 0;
+
+ fseek(eplFp, 0, SEEK_END);
+ size_t totalSize = ftell(eplFp);
+ rewind(eplFp);
+
+ size_t size = totalSize;
+ while (size >= EPL_PACKET_BYTE_SIZE) {
+ char rawBuffer[EPL_PACKET_BYTE_SIZE];
+ if (fread(rawBuffer, 1, EPL_PACKET_BYTE_SIZE, eplFp) != EPL_PACKET_BYTE_SIZE) {
+ ALOGW("%s(), Cannot read %d bytes from EPL file!", __FUNCTION__, EPL_PACKET_BYTE_SIZE);
+ break;
+ }
+
+ uint16_t *buffer = (uint16_t *)rawBuffer;
+
+ sampleRate = buffer[3843];
+
+ if (sampleRate == 48000) {
+ fwrite(buffer, 2, 1920, vmFp); // VM short [0~1919]: EPL short [0~1919]
+ fwrite(&buffer[3847], 2, 1, vmFp); // VM short [1920]: EPL short [3847]
+ fwrite(&buffer[3848], 2, 1, vmFp); // VM short [1921]: EPL short [3848]
+ } else if (sampleRate == 16000) {
+ fwrite(&buffer[640], 2, 640, vmFp); // VM short [0~639]: EPL[640+i]
+ fwrite(&buffer[3847], 2, 1, vmFp); // VM short [640]: EPL[3847]
+ fwrite(&buffer[3848], 2, 1, vmFp); // VM short [641]: EPL[3848]
+ } else {
+ ALOGE("%s(), unsupport sample rate(%hu, remain size 0x%zx)! cannot convert EPL to vm", __FUNCTION__, sampleRate, size);
+ ret = false;
+ break;
+ }
+
+ size -= EPL_PACKET_BYTE_SIZE;
+
+ ALOGV("%s(), sample rate = %d (0x%4x), remaining size = %zu", __FUNCTION__, sampleRate, sampleRate, size);
+ }
+
+ if (ret) {
+ ALOGD("%s(), %s(size = %zu) -> %s , sample rate = %d succefully", __FUNCTION__, eplPath, totalSize, vmPath, sampleRate);
+ }
+ } else {
+ if (eplFp == NULL) {
+ ALOGE("%s(), fp == NULL (eplPath = %s)", __FUNCTION__, eplPath);
+ ret = false;
+ }
+
+ if (eplFp == NULL) {
+ ALOGE("%s(), fp == NULL (vmPath = %s)", __FUNCTION__, vmPath);
+ ret = false;
+ }
+ }
+
+ if (eplFp) {
+ fclose(eplFp);
+ eplFp = NULL;
+ }
+
+ if (vmFp) {
+ fclose(vmFp);
+ vmFp = NULL;
+ }
+
+ /* Backup the tmp EPL dump for debugging */
+ if (rename(eplPath, "/data/vendor/audiohal/SPE_EPL.bak") != 0) {
+ ALOGW("%s(), Cannot rename %s EPL succefully!", __FUNCTION__, eplPath);
+ }
+
+ return ret;
+}
+void SpeechMemCpy(void *dest, void *src, size_t n) {
+ char *c_src = (char *)src;
+ char *c_dest = (char *)dest;
+ char tmp;
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ c_dest[i] = c_src[i];
+ asm("" ::: "memory");
+ }
+ asm volatile("dsb ish": : : "memory");
+}
+
+void adjustTimeStamp(struct timespec *startTime, int delayMs) {
+ /* Adjust delay time */
+ if (delayMs > 0) {
+ long delayNs = (long)delayMs * 1000000;
+ startTime->tv_nsec += delayNs;
+ if (startTime->tv_nsec >= 1000000000) {
+ startTime->tv_nsec -= 1000000000;
+ startTime->tv_sec += 1;
+ }
+ } else if (delayMs < 0) {
+ long delayNs = -(long)delayMs * 1000000;
+ if (startTime->tv_nsec >= delayNs) {
+ startTime->tv_nsec -= delayNs;
+ } else {
+ startTime->tv_nsec = 1000000000 - (delayNs - startTime->tv_nsec);
+ startTime->tv_sec -= 1;
+ }
+ }
+}
+
+void calculateTimeStampByFrames(struct timespec startTime, uint32_t mTotalCaptureFrameSize, stream_attribute_t streamAttribute, struct timespec *newTimeStamp) {
+ uint32_t framesPerSec = streamAttribute.sample_rate;
+ unsigned long sec = mTotalCaptureFrameSize / framesPerSec;
+ unsigned long ns = (mTotalCaptureFrameSize % framesPerSec) / (float)framesPerSec * 1000000000;
+
+ newTimeStamp->tv_sec = startTime.tv_sec + sec;
+ newTimeStamp->tv_nsec = startTime.tv_nsec + ns;
+
+ if (newTimeStamp->tv_nsec >= 1000000000) {
+ newTimeStamp->tv_nsec -= 1000000000;
+ newTimeStamp->tv_sec += 1;
+ }
+
+ ALOGV("%s(), Start time = %ld.%09ld, framesPerSec = %d = %zu(format) * %d(ch) * %d(sr), New time = %ld.%09ld",
+ __FUNCTION__,
+ startTime.tv_sec, startTime.tv_nsec,
+ framesPerSec,
+ audio_bytes_per_sample(streamAttribute.audio_format),
+ streamAttribute.num_channels,
+ streamAttribute.sample_rate,
+ newTimeStamp->tv_sec, newTimeStamp->tv_nsec);
+}
+
+void calculateTimeStampByBytes(struct timespec startTime, uint32_t totalBufferSize, stream_attribute_t streamAttribute, struct timespec *newTimeStamp) {
+ uint32_t bytesPerSec = audio_bytes_per_sample(streamAttribute.audio_format) * streamAttribute.num_channels * streamAttribute.sample_rate;
+ unsigned long sec = totalBufferSize / bytesPerSec;
+ unsigned long ns = (totalBufferSize % bytesPerSec) / (float)bytesPerSec * 1000000000;
+
+ newTimeStamp->tv_sec = startTime.tv_sec + sec;
+ newTimeStamp->tv_nsec = startTime.tv_nsec + ns;
+
+ if (newTimeStamp->tv_nsec >= 1000000000) {
+ newTimeStamp->tv_nsec -= 1000000000;
+ newTimeStamp->tv_sec += 1;
+ }
+
+ ALOGV("%s(), Start time = %ld.%09ld, bytesPerSec = %d = %zu(format) * %d(ch) * %d(sr), New time = %ld.%09ld",
+ __FUNCTION__,
+ startTime.tv_sec, startTime.tv_nsec,
+ bytesPerSec,
+ audio_bytes_per_sample(streamAttribute.audio_format),
+ streamAttribute.num_channels,
+ streamAttribute.sample_rate,
+ newTimeStamp->tv_sec, newTimeStamp->tv_nsec);
+}
+
+uint32_t convertMsToBytes(const uint32_t ms, const stream_attribute_t *streamAttribute) {
+ return ms * streamAttribute->num_channels * audio_bytes_per_sample(streamAttribute->audio_format) * streamAttribute->sample_rate / 1000;
+}
+
+static bool isolatedDeepBuffer = false;
+
+bool isIsolatedDeepBuffer(const audio_output_flags_t flag) {
+ return ((flag & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) && !(flag & AUDIO_OUTPUT_FLAG_PRIMARY)) ? true : false;
+}
+
+void collectPlatformOutputFlags(audio_output_flags_t flag) {
+ if (isIsolatedDeepBuffer(flag)) {
+ isolatedDeepBuffer = true;
+ }
+}
+
+bool platformIsolatedDeepBuffer() {
+ return isolatedDeepBuffer;
+}
+
+unsigned int wordSizeAlign(unsigned int inSize)
+{
+ unsigned int alignSize;
+
+ /* sram is device memory, need word size align, 8 byte for 64 bit platform */
+ /* [3:0] = 4'h0 for the convenience of the hardware implementation */
+ alignSize = inSize & 0xFFFFFFF0;
+ return alignSize;
+}
+
+
+char *audio_strncpy(char *target, const char *source, size_t target_size) {
+ char *retval = NULL;
+
+ if (target != NULL && source != NULL && target_size > 0) {
+ retval = strncpy(target, source, target_size);
+ target[target_size - 1] = '\0';
+ } else {
+ retval = target;
+ }
+
+ return retval;
+}
+
+
+char *audio_strncat(char *target, const char *source, size_t target_size) {
+ char *retval = NULL;
+
+ if (target != NULL && source != NULL && target_size > (strlen(target) + 1)) {
+ retval = strncat(target, source, target_size - strlen(target) - 1);
+ } else {
+ retval = target;
+ }
+
+ return retval;
+}
+
+void initPowerHal() {
+#if defined(MTK_POWERHAL_AUDIO_LATENCY) || defined(MTK_POWERHAL_AUDIO_POWER) || defined(MTK_POWERHAL_WIFI_POWRER_SAVE)
+ AL_LOCK(gPowerHalLock);
+ android::getPowerHal();
+ AL_UNLOCK(gPowerHalLock);
+#endif
+}
+
+bool getPowerHal() {
+#if defined(MTK_POWERHAL_AUDIO_LATENCY) || defined(MTK_POWERHAL_AUDIO_POWER) || defined(MTK_POWERHAL_WIFI_POWRER_SAVE)
+ if (gPowerHal == NULL) {
+ ALOGD("%s(), get PowerHal Service", __FUNCTION__);
+ gPowerHal = IPower::tryGetService();
+ if (gPowerHal != NULL) {
+ powerHalDeathRecipient = new PowerDeathRecipient();
+ hardware::Return<bool> linked = gPowerHal->linkToDeath(powerHalDeathRecipient, 0);
+ if (!linked.isOk()) {
+ ALOGE("%s(), Transaction error in linking to PowerHal death: %s", __FUNCTION__,
+ linked.description().c_str());
+ } else if (!linked) {
+ ALOGW("%s(), Unable to link to PowerHal death notifications", __FUNCTION__);
+ } else {
+ ALOGD("%s(), Link to death notification successfully", __FUNCTION__);
+ }
+ } else {
+ ALOGD("%s(), Cound not get PowerHal Service", __FUNCTION__);
+ }
+ }
+ return gPowerHal != NULL;
+#else
+ return false;
+#endif
+}
+
+void power_hal_hint(PowerHalHint hint, bool enable) {
+#if defined(MTK_POWERHAL_AUDIO_LATENCY) || defined(MTK_POWERHAL_AUDIO_POWER) || defined(MTK_POWERHAL_WIFI_POWRER_SAVE)
+ AL_LOCK(gPowerHalLock);
+ if (getPowerHal() == false) {
+ ALOGE("IPower error!!");
+ AL_UNLOCK(gPowerHalLock);
+ return;
+ }
+
+ MtkCusPowerHintInternal custPowerHint;
+ switch (hint) {
+#if defined(MTK_POWERHAL_AUDIO_LATENCY)
+ case POWERHAL_LATENCY_DL:
+ custPowerHint = MtkCusPowerHintInternal::MTK_CUS_AUDIO_LATENCY_DL;
+ break;
+ case POWERHAL_LATENCY_UL:
+ custPowerHint = MtkCusPowerHintInternal::MTK_CUS_AUDIO_LATENCY_UL;
+ break;
+#endif
+#if defined(MTK_POWERHAL_AUDIO_POWER)
+ case POWERHAL_POWER_DL:
+ custPowerHint = MtkCusPowerHintInternal::MTK_CUS_AUDIO_POWER_DL;
+ break;
+#endif
+#if defined(MTK_POWERHAL_WIFI_POWRER_SAVE)
+ case POWERHAL_DISABLE_WIFI_POWER_SAVE:
+ custPowerHint = MtkCusPowerHintInternal::MTK_CUS_AUDIO_DISABLE_WIFI_POWER_SAVE;
+ break;
+#endif
+ default:
+ ALOGE("%s - no support hint %d", __FUNCTION__, hint);
+ AL_UNLOCK(gPowerHalLock);
+ return;
+ }
+
+ int data = enable ? (int)MtkHintOp::MTK_HINT_ALWAYS_ENABLE : 0;
+ gPowerHal->mtkCusPowerHint((int32_t)custPowerHint, data);
+ ALOGD("%s - custPowerHint %d, data %d", __FUNCTION__, custPowerHint, data);
+ AL_UNLOCK(gPowerHalLock);
+#else
+ (void) hint;
+ (void) enable;
+#endif
+}
+
+int audio_sched_setschedule(pid_t pid, int policy, int sched_priority) {
+ int ret;
+ struct sched_param sched_p;
+
+ ret = sched_getparam(pid, &sched_p);
+ if (ret)
+ {
+ ALOGE("%s(), sched_getparam failed, errno: %d, ret %d", __FUNCTION__, errno, ret);
+ }
+
+ sched_p.sched_priority = sched_priority;
+
+ ret = sched_setscheduler(pid, policy, &sched_p);
+ if (ret)
+ {
+ ALOGE("%s(), sched_setscheduler failed, errno: %d, ret %d", __FUNCTION__, errno, ret);
+ }
+
+ return ret;
+}
+
+void setNeedAEETimeoutFlg(bool state) { bNeedAEETimeoutFlg = state; }
+bool getNeedAEETimeoutFlg() { return bNeedAEETimeoutFlg; }
+
+bool findEnumByString(const struct enum_to_str_table* table, const char *str, uint32_t *enumVal)
+{
+ if (table == NULL) {
+ ALOGW("%s(), table is NULL", __FUNCTION__);
+ return false;
+ }
+
+ if (str == NULL) {
+ ALOGW("%s(), str is NULL", __FUNCTION__);
+ return false;
+ }
+
+ for(size_t i = 0; table[i].name != NULL; i++) {
+ if (strcmp(table[i].name, str) == 0) {
+ *enumVal = table[i].value;
+ return true;
+ }
+ }
+ return false;
+}
+
+uint32_t deviceInTypeStrToEnum(const char* deviceInType) {
+ uint32_t retEnumVal = 0;
+ char *restOfStr = NULL;
+ char* str = NULL;
+
+ if (deviceInType == NULL) {
+ return 0;
+ }
+
+ str = strdup(deviceInType);
+ char *deviceInTypeStr = strtok_r(str, DEVICE_IN_TYPE_SEPERATOR, &restOfStr);
+ while (deviceInTypeStr) {
+ uint32_t enumVal = 0;
+ if (findEnumByString(deviceInTypeTable, deviceInTypeStr, &enumVal)) {
+ ALOGV("%s(), deviceInTypeStr = %s => enum 0x%x", __FUNCTION__, deviceInTypeStr, enumVal);
+ retEnumVal |= enumVal;
+ } else {
+ ALOGW("%s(), no match device in type string (%s)", __FUNCTION__, deviceInTypeStr);
+ continue;
+ }
+ deviceInTypeStr = strtok_r(NULL, DEVICE_IN_TYPE_SEPERATOR, &restOfStr);
+ }
+ ALOGV("%s(), deviceInTypeStr = %s, enum = 0x%x", __FUNCTION__, deviceInType, retEnumVal);
+ free(str);
+
+ return retEnumVal;
+}
+
+#if (defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT) && (MTK_AUDIO_TUNING_TOOL_V2_PHASE >= 2))
+bool getMicInfoFromXml(const char* projectName, audio_microphone_characteristic_t* micArray, size_t *micCount) {
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return false;
+ }
+
+ AppHandle *appHandle = appOps->appHandleGetInstance();
+ AudioType* micInfoAudioType = appOps->appHandleGetAudioTypeByName(appHandle, MIC_INFO_AUDIO_TYPE_NAME);
+ if (micInfoAudioType == NULL) {
+ ALOGE("%s(), Error: micInfoAudioType == NULL", __FUNCTION__);
+ ASSERT(0);
+ return false;
+ }
+
+ // get number of mics
+ CategoryType* categoryType = appOps->audioTypeGetCategoryTypeByName(micInfoAudioType, MICROPHONES_CATEGORY_TYPE_NAME);
+ if (categoryType == NULL) {
+ ALOGE("%s(), Error: categoryType == NULL", __FUNCTION__);
+ ASSERT(0);
+ return false;
+ }
+
+ size_t micArrayIndex = 0;
+ size_t numOfCategory = appOps->categoryTypeGetNumOfCategory(categoryType);
+ for (size_t i = 0; i < numOfCategory; i++) {
+ audio_microphone_characteristic_t micInfo;
+ Param *param = NULL;
+ size_t size = 0;
+ uint32_t enumVal = 0;
+
+ memset(&micInfo, 0, sizeof(micInfo));
+
+ Category *category = appOps->categoryTypeGetCategoryByIndex(categoryType, i);
+ std::string categoryPath = std::string(PROJECTS_CATEGORY_TYPE_NAME) + "," + projectName + "," + categoryType->name + "," + category->name;
+ ALOGD("Mic[%zu] %s\n", i, categoryPath.c_str());
+
+ ParamUnit *paramUnit = appOps->audioTypeGetParamUnit(micInfoAudioType, categoryPath.c_str());
+ if (paramUnit == NULL) {
+ ALOGW("Mic[%zu] %s is NULL.\n", i, categoryPath.c_str());
+ continue;
+ }
+
+ param = appOps->paramUnitGetParamByName(paramUnit, PROJECT_ID_PARAM_NAME);
+ if (param != NULL) {
+ char* deviceId = (char*)param->data;
+ ASSERT(strlen(deviceId) < AUDIO_MICROPHONE_ID_MAX_LEN);
+ strncpy(micInfo.device_id, deviceId, AUDIO_MICROPHONE_ID_MAX_LEN);
+ micInfo.device_id[AUDIO_MICROPHONE_ID_MAX_LEN - 1] = '\0';
+ ALOGV("device_id = %s", deviceId);
+ } else {
+ ALOGW("%s(), param is NULL", __FUNCTION__);
+ ASSERT(param != NULL);
+ continue;
+ }
+
+ param = appOps->paramUnitGetParamByName(paramUnit, DEVICE_IN_TYPE_PARAM_NAME);
+ if (param != NULL) {
+ char* deviceInType = (char *)param->data;
+ enumVal = deviceInTypeStrToEnum(deviceInType);
+ micInfo.device = enumVal;
+ ALOGV("deviceInType = %s, enum = 0x%x", deviceInType, enumVal);
+ } else {
+ ALOGW("%s(), param is NULL", __FUNCTION__);
+ ASSERT(param != NULL);
+ continue;
+ }
+
+ param = appOps->paramUnitGetParamByName(paramUnit, ADDRESS_PARAM_NAME);
+ if (param != NULL) {
+ char *address = (char *)param->data;
+ ASSERT(strlen(address) < AUDIO_DEVICE_MAX_ADDRESS_LEN);
+ strncpy(micInfo.address, address, AUDIO_DEVICE_MAX_ADDRESS_LEN);
+ micInfo.address[AUDIO_DEVICE_MAX_ADDRESS_LEN - 1] = '\0';
+ ALOGV("address = %s", address);
+ } else {
+ ALOGW("%s(), param is NULL", __FUNCTION__);
+ ASSERT(param != NULL);
+ continue;
+ }
+
+ param = appOps->paramUnitGetParamByName(paramUnit, MIC_LOCATION_PARAM_NAME);
+ if (param != NULL) {
+ char* micLocation = (char *)param->data;
+ ASSERT(findEnumByString(micLoccationTable, micLocation, &enumVal));
+ micInfo.location= (audio_microphone_location_t)enumVal;
+ ALOGV("mic_location = %s, enum = %d", micLocation, enumVal);
+ } else {
+ ALOGW("%s(), param is NULL", __FUNCTION__);
+ ASSERT(param != NULL);
+ continue;
+ }
+
+ param = appOps->paramUnitGetParamByName(paramUnit, DEVICE_GROUP_PARAM_NAME);
+ if (param != NULL) {
+ int deviceGroup = *(int *)param->data;
+ micInfo.group = deviceGroup;
+ ALOGV("device_group = %d", deviceGroup);
+ } else {
+ ALOGW("%s(), param is NULL", __FUNCTION__);
+ ASSERT(param != NULL);
+ continue;
+ }
+
+ param = appOps->paramUnitGetParamByName(paramUnit, INDEX_IN_THE_GROUP_PARAM_NAME);
+ if (param != NULL) {
+ int indexInTheGroup = *(int *)param->data;
+ micInfo.index_in_the_group = indexInTheGroup;
+ ALOGV("index_in_the_group = %d", indexInTheGroup);
+ } else {
+ ALOGW("%s(), param is NULL", __FUNCTION__);
+ ASSERT(param != NULL);
+ continue;
+ }
+
+ param = appOps->paramUnitGetParamByName(paramUnit, GEOMETRIC_LOCATION_PARAM_NAME);
+ if (param) {
+ double *geometric_location = (double *)param->data;
+ size = param->arraySize;
+ if (size == 3) {
+ micInfo.geometric_location.x = (float)geometric_location[0];
+ micInfo.geometric_location.y = (float)geometric_location[1];
+ micInfo.geometric_location.z = (float)geometric_location[2];
+ ALOGV("geometric_location = (%f, %f, %f), size = %zu", geometric_location[0], geometric_location[1], geometric_location[2], size);
+ } else {
+ ALOGW("%s(), size is invalid (%zu)", __FUNCTION__, size);
+ ASSERT(size == 3);
+ continue;
+ }
+ } else {
+ micInfo.geometric_location.x = 0;
+ micInfo.geometric_location.y = 0;
+ micInfo.geometric_location.z = 0;
+ }
+
+ param = appOps->paramUnitGetParamByName(paramUnit, ORIENTATION_PARAM_NAME);
+ if (param) {
+ double *orientation = (double *)param->data;
+ size = param->arraySize;
+ if (size == 3) {
+ micInfo.orientation.x = (float)orientation[0];
+ micInfo.orientation.y = (float)orientation[1];
+ micInfo.orientation.z = (float)orientation[2];
+ ALOGV("orientation = (%f,%f,%f), size = %zu", orientation[0], orientation[1], orientation[2], size);
+ } else {
+ ALOGW("%s(), size is invalid (%zu)", __FUNCTION__, size);
+ ASSERT(size == 3);
+ continue;
+ }
+ } else {
+ micInfo.orientation.x = 0;
+ micInfo.orientation.y = 0;
+ micInfo.orientation.z = 0;
+ }
+
+ param = appOps->paramUnitGetParamByName(paramUnit, FREQUENCY_RESPONSES_PARAM_NAME);
+ if (param) {
+ double *frequency_responses = (double *)param->data;
+ size = param->arraySize;
+ if ((size > 0) && (size % 2 == 0)) {
+ for (size_t i = 0; i < size; i+=2) {
+ micInfo.frequency_responses[0][i/2] = (float)frequency_responses[i];
+ micInfo.frequency_responses[1][i/2] = (float)frequency_responses[i+1];
+ ALOGV("frequency_responses freq: %f, amp:%f", frequency_responses[i], frequency_responses[i+1]);
+ }
+ micInfo.num_frequency_responses = size / 2;
+ } else {
+ ALOGW("%s(), the freq response size is invalid (%zu)", __FUNCTION__, size);
+ ASSERT(0);
+ continue;
+ }
+ } else {
+ ALOGW("%s(), param is NULL", __FUNCTION__);
+ ASSERT(param != NULL);
+ continue;
+ }
+
+ param = appOps->paramUnitGetParamByName(paramUnit, SENSITIVITY_PARAM_NAME);
+ if (param) {
+ float sensitivity = *(float *)param->data;
+ micInfo.sensitivity = sensitivity;
+ ALOGV("sensitivity = %f", sensitivity);
+ } else {
+ micInfo.sensitivity = AUDIO_MICROPHONE_SENSITIVITY_UNKNOWN;
+ }
+
+ param = appOps->paramUnitGetParamByName(paramUnit, MAX_SPL_PARAM_NAME);
+ if (param) {
+ float max_spl = *(float *)param->data;
+ micInfo.max_spl = max_spl;
+ ALOGV("max_spl = %f", max_spl);
+ } else {
+ micInfo.max_spl = AUDIO_MICROPHONE_SPL_UNKNOWN;
+ }
+
+ param = appOps->paramUnitGetParamByName(paramUnit, MIN_SPL_PARAM_NAME);
+ if (param) {
+ float min_spl = *(float *)param->data;
+ micInfo.min_spl = min_spl;
+ ALOGV("min_spl = %f", min_spl);
+ } else {
+ micInfo.min_spl = AUDIO_MICROPHONE_SPL_UNKNOWN;
+ }
+
+ param = appOps->paramUnitGetParamByName(paramUnit, DIRECTIONALITY_PARAM_NAME);
+ if (param) {
+ char* directionality = (char *)param->data;
+ ASSERT(findEnumByString(micDirectionalityTable, directionality, &enumVal));
+ micInfo.directionality = (audio_microphone_directionality_t)enumVal;
+ ALOGV("directionality = %s, enum = %d", directionality, enumVal);
+ } else {
+ ALOGW("%s(), param is NULL", __FUNCTION__);
+ ASSERT(param != NULL);
+ continue;
+ }
+
+ micArray[micArrayIndex++] = micInfo;
+ }
+
+ *micCount = micArrayIndex;
+
+ return true;
+}
+#endif
+
+bool getMicInfo(audio_microphone_characteristic_t* micArray, size_t *micCount) {
+#if (defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT) && (MTK_AUDIO_TUNING_TOOL_V2_PHASE >= 2))
+ /* Query projects' mic info */
+ const char* project = NULL;
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_DMIC)) {
+ project = "dmic_proj";
+ } else {
+ project = "amic_proj";
+ }
+
+ return getMicInfoFromXml(project, micArray, micCount);
+#else
+ *micCount = 2;
+
+ /* Setup main mic */
+ memset(&micArray[0], 0, sizeof(micArray[0]));
+ strncpy(micArray[0].device_id, "SPH1642HT5H_REV_B", AUDIO_MICROPHONE_ID_MAX_LEN);
+ micArray[0].device_id[AUDIO_MICROPHONE_ID_MAX_LEN - 1] = '\0';
+
+ micArray[0].device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+
+ strncpy(micArray[0].address, "bottom", AUDIO_DEVICE_MAX_ADDRESS_LEN);
+ micArray[0].address[AUDIO_DEVICE_MAX_ADDRESS_LEN - 1] = '\0';
+
+ micArray[0].location= AUDIO_MICROPHONE_LOCATION_MAINBODY;
+
+ micArray[0].group = 0;
+ micArray[0].index_in_the_group = 0;
+
+ micArray[0].geometric_location.x = 0.5f;
+ micArray[0].geometric_location.y = 0.0f;
+ micArray[0].geometric_location.z = 0.5f;
+
+ micArray[0].orientation.x = 0.0f;
+ micArray[0].orientation.y = -1.0f;
+ micArray[0].orientation.z = 0.0f;
+
+ /* Setup freq response array */
+ micArray[0].frequency_responses[0][0] = 80;
+ micArray[0].frequency_responses[0][1] = 100;
+ micArray[0].frequency_responses[0][2] = 500;
+ micArray[0].frequency_responses[0][3] = 5000;
+ micArray[0].frequency_responses[0][4] = 10000;
+
+ micArray[0].frequency_responses[1][0] = -2.0f;
+ micArray[0].frequency_responses[1][1] = -1.25f;
+ micArray[0].frequency_responses[1][2] = 0.0f;
+ micArray[0].frequency_responses[1][3] = 0.0f;
+ micArray[0].frequency_responses[1][4] = 1.75f;
+ micArray[0].num_frequency_responses = 5;
+
+ micArray[0].sensitivity = -41;
+ micArray[0].max_spl = 124;
+ micArray[0].min_spl = 124;
+
+ micArray[0].directionality = AUDIO_MICROPHONE_DIRECTIONALITY_OMNI;
+
+ /* Setup sub mic */
+ memset(&micArray[1], 0, sizeof(micArray[1]));
+
+ strncpy(micArray[1].device_id, "SPH1642HT5H_REV_B", AUDIO_MICROPHONE_ID_MAX_LEN);
+ micArray[1].device_id[AUDIO_MICROPHONE_ID_MAX_LEN - 1] = '\0';
+
+ micArray[1].device = AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_BACK_MIC;
+
+ strncpy(micArray[1].address, "back", AUDIO_DEVICE_MAX_ADDRESS_LEN);
+ micArray[1].address[AUDIO_DEVICE_MAX_ADDRESS_LEN - 1] = '\0';
+
+ micArray[1].location= AUDIO_MICROPHONE_LOCATION_MAINBODY;
+
+ micArray[1].group = 1;
+ micArray[1].index_in_the_group = 0;
+
+ micArray[1].geometric_location.x = 0.5f;
+ micArray[1].geometric_location.y = 0.7f;
+ micArray[1].geometric_location.z = 0.0f;
+
+ micArray[1].orientation.x = 0.0f;
+ micArray[1].orientation.y = 0.0f;
+ micArray[1].orientation.z = -1.0f;
+
+ /* Setup freq response array */
+ micArray[1].frequency_responses[0][0] = 80;
+ micArray[1].frequency_responses[0][1] = 100;
+ micArray[1].frequency_responses[0][2] = 500;
+ micArray[1].frequency_responses[0][3] = 5000;
+ micArray[1].frequency_responses[0][4] = 10000;
+ micArray[1].frequency_responses[1][0] = -2.0f;
+ micArray[1].frequency_responses[1][1] = -1.25f;
+ micArray[1].frequency_responses[1][2] = 0.0f;
+ micArray[1].frequency_responses[1][3] = 0.0f;
+ micArray[1].frequency_responses[1][4] = 1.75f;
+ micArray[1].num_frequency_responses = 5;
+
+ micArray[1].sensitivity = -41;
+ micArray[1].max_spl = 124;
+ micArray[1].min_spl = 124;
+
+ micArray[1].directionality = AUDIO_MICROPHONE_DIRECTIONALITY_OMNI;
+
+ return true;
+#endif
+}
+
+void dumpMicInfo(struct audio_microphone_characteristic_t *micArray, size_t micCount) {
+ ALOGD("%s(), ======= micCount = %zu =======", __FUNCTION__, micCount);
+ for(size_t i = 0; i< micCount; i++) {
+ ALOGD("micArray[%zu].address = %s", i, micArray[i].address);
+ ALOGD("micArray[%zu].device = 0x%x", i, micArray[i].device);
+ ALOGD("micArray[%zu].device_id = %s", i, micArray[i].device_id);
+ ALOGD("micArray[%zu].directionality = %d", i, micArray[i].directionality);
+ ALOGD("micArray[%zu].num_frequency_responses = %d", i, micArray[i].num_frequency_responses);
+ for (size_t j = 0; j < micArray[i].num_frequency_responses; j++) {
+ ALOGD("micArray[%zu].frequency_responses[%zu] freq: %f, amp:%f",i, j, micArray[i].frequency_responses[0][j], micArray[i].frequency_responses[1][j]);
+ }
+ ALOGD("micArray[%zu].geometric_location = %f, %f, %f", i, micArray[i].geometric_location.x, micArray[i].geometric_location.y, micArray[i].geometric_location.z);
+ ALOGD("micArray[%zu].group = %d", i, micArray[i].group);
+ ALOGD("micArray[%zu].index_in_the_group = %d", i, micArray[i].index_in_the_group);
+ ALOGD("micArray[%zu].location = %d", i, micArray[i].location);
+ ALOGD("micArray[%zu].max_spl = %f", i, micArray[i].max_spl);
+ ALOGD("micArray[%zu].min_spl = %f", i, micArray[i].min_spl);
+ ALOGD("micArray[%zu].orientation = %f, %f, %f", i, micArray[i].orientation.x, micArray[i].orientation.y, micArray[i].orientation.z);
+ ALOGD("micArray[%zu].sensitivity = %f", i, micArray[i].sensitivity);
+ }
+ ALOGD("%s(), =====================", __FUNCTION__);
+}
+
+
+}
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioVIBSPKControl.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioVIBSPKControl.cpp
new file mode 100644
index 0000000..1a5a52a
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/AudioVIBSPKControl.cpp
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#define LOG_TAG "AudioVIBSPKControl"
+#include "AudioVIBSPKControl.h"
+#include "audio_custom_exp.h"
+
+#include "AudioAssert.h"
+
+
+namespace android {
+//#if defined(MTK_VIBSPK_SUPPORT)
+
+AudioVIBSPKControl *AudioVIBSPKControl::UniqueAudioVIBSPKControl = NULL;
+AudioVIBSPKVsgGen *AudioVIBSPKVsgGen::UniqueAudioVIBSPKVsgGen = NULL;
+
+// VSG_SIN_TAB_SIZE must be 2^n - 1
+#define VSG_PHASE_BITS 15
+#define VSG_PHASE_ADJUST (15-VSG_PHASE_BITS)
+#define VSG_SIN_TAB_SIZE 65
+#define VSG_ODD_STAT (VSG_SIN_TAB_SIZE-2)
+#define VSG_SIN_TAB_ORDER 6
+#define VSG_SIN_L_SHIFT (VSG_PHASE_BITS-VSG_SIN_TAB_ORDER)
+#define VSG_SIN_R_SHIFT (VSG_PHASE_BITS-VSG_SIN_TAB_ORDER)
+#define DEC_LEN_MAX 1152
+
+
+/// define Vibration SPK Default Center Freq and RMS
+#ifndef VIBSPK_MV_RMS
+#define VIBSPK_MV_RMS (350) //280~560, 70 per step
+#endif
+
+
+
+const short vsg_sin_tab[VSG_SIN_TAB_SIZE] = {
+ 0, 804, 1608, 2410, 3212, 4011, 4808, 5602, 6393, 7179,
+ 7962, 8739, 9512, 10278, 11039, 11793, 12539, 13279, 14010, 14732,
+ 15446, 16151, 16846, 17530, 18204, 18868, 19519, 20159, 20787, 21403,
+ 22005, 22594, 23170, 23731, 24279, 24811, 25329, 25832, 26319, 26790,
+ 27245, 27683, 28105, 28510, 28898, 29268, 29621, 29956, 30273, 30571,
+ 30852, 31113, 31356, 31580, 31785, 31971, 32137, 32285, 32412, 32521,
+ 32609, 32678, 32728, 32757, 32767
+};
+
+
+const short vsg_gain_tab[5][16] = {
+ {0x08a7, 0x09b5, 0x0ae4, 0x0c39, 0x0db7, 0x0f63, 0x1144, 0x135f, 0x15bc, 0x1863, 0x1b5d, 0x1eb4, 0x2273, 0x26a7, 0x2b5e, 0x30a9}, //280MVRMS
+ {0x0ace, 0x0c20, 0x0d9a, 0x0f43, 0x1120, 0x1337, 0x158f, 0x1831, 0x1b25, 0x1e75, 0x222c, 0x2658, 0x2b05, 0x3045, 0x3629, 0x3cc5}, //350MVRMS
+ {0x0cf6, 0x0e8b, 0x1051, 0x124f, 0x148b, 0x170d, 0x19dd, 0x1d05, 0x208f, 0x2488, 0x28fd, 0x2dfe, 0x339b, 0x39e7, 0x40f7, 0x48e5}, //420MVRMS
+ {0x0f20, 0x10f8, 0x130a, 0x155d, 0x17f8, 0x1ae5, 0x1e2d, 0x21dc, 0x25fe, 0x2aa0, 0x2fd4, 0x35aa, 0x3c36, 0x438f, 0x4bce, 0x550d}, //490MVRMS
+ {0x1149, 0x1365, 0x15c3, 0x186a, 0x1b65, 0x1ebd, 0x227d, 0x26b2, 0x2b6b, 0x30b8, 0x36a9, 0x3d55, 0x44d1, 0x4d36, 0x56a2, 0x6134} //560MVRMS
+};
+
+//=============================================================================================
+// AudioVIBSPKVsgGen Imeplementation
+//=============================================================================================
+AudioVIBSPKVsgGen::AudioVIBSPKVsgGen() {
+ mRampControl = 0;
+ mCenter_Freq = 0;
+ mDelta_Freq = 0;
+ mMod_Freq = 0;
+ mCenter_Phase = 0;
+ mCenter_PhaseInc = 0;
+ mCenter_PhaseStat = 0;
+ mMod_Phase = 0;
+ mMod_PhaseInc = 0;
+ mMod_PhaseStat = 0;
+ mMod_Idx = 0;
+ mGain = 0;
+ ALOGD("VsgGen constructor");
+}
+
+AudioVIBSPKVsgGen::~AudioVIBSPKVsgGen() {
+ ALOGD("VsgGen destructor");
+}
+
+AudioVIBSPKVsgGen *AudioVIBSPKVsgGen::getInstance() {
+ if (UniqueAudioVIBSPKVsgGen == NULL) {
+ ALOGD("+UniqueAudioVIBSPKVsgGen");
+ UniqueAudioVIBSPKVsgGen = new AudioVIBSPKVsgGen();
+ ALOGD("-UniqueAudioVIBSPKVsgGen");
+ }
+ ALOGD("VsgGen getInstance()");
+ return UniqueAudioVIBSPKVsgGen;
+}
+
+void AudioVIBSPKVsgGen::freeInstance() {
+ if (UniqueAudioVIBSPKVsgGen != NULL) {
+ delete UniqueAudioVIBSPKVsgGen;
+ }
+ ALOGD("VsgGen freeInstance()");
+}
+
+void AudioVIBSPKVsgGen::vsgInit(int32_t samplerate, int32_t center_freq, int32_t mod_freq, int32_t delta_freq) {
+ uint16_t my0;
+ ALOGD("VsgGenInit");
+ switch (samplerate) { // my0: Q5.11
+ case 8000:
+ my0 = 0x8312;
+ break;
+ case 11025:
+ my0 = 0x5F1B;
+ break;
+ case 12000:
+ my0 = 0x5761;
+ break;
+ case 16000:
+ my0 = 0x4189;
+ break;
+ case 22050:
+ my0 = 0x2F8D;
+ break;
+ case 24000:
+ my0 = 0x2BB0;
+ break;
+ case 32000:
+ my0 = 0x20C4;
+ break;
+ case 44100:
+ my0 = 0x17C6;
+ break;
+ case 48000:
+ my0 = 0x15D8;
+ break;
+ default:
+ my0 = 0x15D8;
+ break;
+ }
+
+ mCenter_Freq = center_freq;
+ mDelta_Freq = delta_freq;
+ mMod_Freq = mod_freq;
+
+ // limitation: the generated tone is Fs/4 at most
+ mCenter_Phase = 0;
+ mCenter_PhaseInc = (int16_t)(((uint32_t)mCenter_Freq * my0 << 1) >> 12);
+ mCenter_PhaseStat = 0;
+
+ mMod_Phase = 0;
+ mMod_PhaseInc = (int16_t)(((uint32_t)mMod_Freq * my0 << 1) >> 12);
+ mMod_PhaseStat = 0;
+
+ my0 = 0x517D; // 2^16/pi, Q2.14
+ if (mMod_Freq == 0) {
+ mMod_Idx = 0;
+ } else {
+ mMod_Idx = (uint16_t)((uint32_t)mDelta_Freq * my0 / mMod_Freq);
+ }
+
+ mRampControl = 0;
+ mGain = 0;
+
+}
+
+void AudioVIBSPKVsgGen::vsgDeInit() {
+ // mCenter_Freq = 0;
+}
+
+int16_t AudioVIBSPKVsgGen::SineGen(int16_t cur_ph, int16_t ph_st) {
+ uint16_t ft;
+ int16_t lo_idx, lo_value, hi_value, lo_ph, v_diff, p_diff, temp_out;
+ uint32_t temp_mr, temp_sr;
+
+ ft = cur_ph << VSG_PHASE_ADJUST;
+ lo_idx = cur_ph >> VSG_SIN_R_SHIFT;
+
+ if ((ph_st & 0x1) != 0) {
+ lo_idx = VSG_ODD_STAT - lo_idx;
+ ft = 0x8000 - (cur_ph << VSG_PHASE_ADJUST);
+ }
+
+ lo_ph = lo_idx << (VSG_SIN_L_SHIFT + VSG_PHASE_ADJUST);
+
+ lo_value = vsg_sin_tab[lo_idx];
+ hi_value = vsg_sin_tab[lo_idx + 1];
+
+ v_diff = hi_value - lo_value;
+ p_diff = ft - lo_ph;
+ temp_mr = (uint32_t)v_diff * (uint32_t)p_diff * 2;
+ temp_sr = temp_mr >> 10;
+ temp_out = lo_value + (int16_t)temp_sr;
+
+ if ((ph_st & 0x2) != 0) {
+ temp_out = ~temp_out;
+ }
+
+ return temp_out;
+}
+
+uint32_t AudioVIBSPKVsgGen::Process(uint32_t size, void *buffer, uint16_t channels, uint8_t rampcontrol, int32_t gain) {
+ uint32_t I;
+ int16_t mr1, ar, vsg_temp_stat, temp_out, vsg_temp_phase;
+ int32_t outputsample;
+ int16_t *ptr16 = (int16_t *)buffer;
+
+ if (mRampControl != rampcontrol) {
+ if (rampcontrol == 0 || rampcontrol == 1) {
+ mGain = gain;
+ } else if (rampcontrol == 2) {
+ mGain = 0;
+ }
+ mRampControl = rampcontrol;
+ }
+
+ for (I = 0; I < size; I++) {
+ mMod_Phase += mMod_PhaseInc;
+
+ if (mMod_Phase < 0) {
+ mMod_PhaseStat++;
+ mMod_Phase &= 0x7FFF;
+ //mMod_PhaseStat &= 0x3;
+ }
+
+ ar = SineGen(mMod_Phase, mMod_PhaseStat);
+ mr1 = (int16_t)((int32_t)ar * mMod_Idx >> 15);
+
+ mCenter_Phase += mCenter_PhaseInc;
+ if (mCenter_Phase < 0) {
+ mCenter_PhaseStat += 1;
+ mCenter_Phase &= 0x7FFF;
+ //mCenter_PhaseStat &= 0x3;
+ }
+
+ vsg_temp_phase = mCenter_Phase + mr1;
+ vsg_temp_stat = mCenter_PhaseStat;
+
+ if (vsg_temp_phase < 0) {
+ vsg_temp_phase &= 0x7FFF;
+ if (mr1 < 0) {
+ vsg_temp_stat--;
+ } else {
+ vsg_temp_stat++;
+ }
+ }
+
+ temp_out = SineGen(vsg_temp_phase, vsg_temp_stat);
+ outputsample = (temp_out * mGain) >> 15;
+ if (mRampControl == 1 && mGain > 0) {
+ mGain -= VIB_RAMPSTEP;
+ if (mGain < 0) {
+ mGain = 0;
+ }
+ } else if (mRampControl == 2 && mGain < gain) {
+ mGain += VIB_RAMPSTEP;
+ if (mGain > gain) {
+ mGain = gain;
+ }
+ }
+
+ *ptr16++ = (int16_t)outputsample;
+ if (channels == 2) {
+ *ptr16++ = (int16_t)outputsample;
+ I++;
+ }
+ }
+ return I;
+}
+
+//=============================================================================================
+// AudioVIBSPKControl Imeplementation
+//=============================================================================================
+
+AudioVIBSPKControl::AudioVIBSPKControl() {
+ mEnable = false;
+ mSampleRate = 44100;
+ mCenterFreq = 0;
+ mModFreq = 0;
+ mDeltaFreq = 0;
+ mRampControl = 0;
+ mDigitalGain = 0;
+ mVsg = AudioVIBSPKVsgGen::getInstance();
+ ALOGD("constructor");
+}
+
+AudioVIBSPKControl::~AudioVIBSPKControl() {
+ ALOGD("destructor");
+}
+
+AudioVIBSPKControl *AudioVIBSPKControl::getInstance() {
+ if (UniqueAudioVIBSPKControl == NULL) {
+ ALOGD("+UniqueAudioVIBSPKControl");
+ UniqueAudioVIBSPKControl = new AudioVIBSPKControl();
+ ASSERT(NULL != UniqueAudioVIBSPKControl);
+ ALOGD("-UniqueAudioVIBSPKControl");
+ }
+ ALOGD("getInstance()");
+ return UniqueAudioVIBSPKControl;
+}
+
+void AudioVIBSPKControl::freeInstance() {
+ if (UniqueAudioVIBSPKControl != NULL) {
+ delete UniqueAudioVIBSPKControl;
+ }
+ ALOGD("freeInstance()");
+}
+
+void AudioVIBSPKControl::setVibSpkEnable(bool enable) {
+ if (enable && !mEnable) {
+ Mutex::Autolock _l(mMutex);
+ mEnable = true;
+ } else if (!enable && mEnable) {
+ Mutex::Autolock _l(mMutex);
+ mVsg->vsgDeInit();
+ mEnable = false;
+ // mCenterFreq = 0;
+ }
+ ALOGD("Enable:%x", enable);
+}
+
+bool AudioVIBSPKControl::getVibSpkEnable(void) {
+ return mEnable;
+}
+
+void AudioVIBSPKControl::VibSpkRampControl(uint8_t rampcontrol) {
+ Mutex::Autolock _l(mMutex);
+ mRampControl = rampcontrol;
+ ALOGD("Ramp : [%d] 0--none, 1--rampdown, 2--rampup", mRampControl);
+}
+
+void AudioVIBSPKControl::setParameters(int32_t rate, int32_t center_freq, int32_t mod_freq, int32_t delta_freq) {
+ ALOGD("setParameters:%x %x %x %x", rate, center_freq, mod_freq, delta_freq);
+ if (mSampleRate != rate || mCenterFreq != center_freq || mModFreq != mod_freq || mDeltaFreq != delta_freq) {
+ Mutex::Autolock _l(mMutex);
+ mSampleRate = rate;
+ mCenterFreq = center_freq;
+ mModFreq = mod_freq;
+ mDeltaFreq = delta_freq;
+ mVsg->vsgInit(mSampleRate, mCenterFreq, mModFreq, mDeltaFreq);
+ }
+}
+
+void AudioVIBSPKControl::setVibSpkGain(int32_t MaxVolume, int32_t MinVolume, int32_t VolumeRange) {
+ int32_t mvrms, index;
+ ALOGD("setVibSpkGain:%x %x %x", MaxVolume, MinVolume, VolumeRange);
+
+ mvrms = VIBSPK_MV_RMS;
+ if ((mvrms < 280)) {
+ mvrms = 280;
+ } else if (mvrms > 560) {
+ mvrms = 560;
+ }
+
+ index = (mvrms - 280) / 70;
+ mDigitalGain = vsg_gain_tab[index][VolumeRange];
+}
+
+int16_t AudioVIBSPKControl::getVibSpkGain(void) {
+ return (int16_t)mDigitalGain;
+}
+
+void AudioVIBSPKControl::VibSpkProcess(uint32_t size, void *buffer, uint32_t channels) {
+ Mutex::Autolock _l(mMutex);
+ mVsg->Process(size >> 1, buffer, channels, mRampControl, mDigitalGain);
+}
+
+
+
+//#endif//#if defined(MTK_VIBSPK_SUPPORT)
+
+} //namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/WCNChipController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/WCNChipController.cpp
new file mode 100644
index 0000000..d5b1706
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/WCNChipController.cpp
@@ -0,0 +1,542 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "WCNChipController.h"
+
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <utils/threads.h>
+
+#include <linux/fm.h>
+
+#include <dlfcn.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "WCNChipController"
+
+//#define MTK_BASIC_PACKAGE//Eenable For WCN test
+
+/*
+ * following declaration must sync with
+ * vendor\mediatek\proprietary\hardware\connectivity\bluetooth\driver\pure\inc\bt_drv.h
+ */
+
+typedef enum {
+ /* [operation]
+ * Return audio configuration for BT SCO on current chipset
+ * [input param]
+ * A pointer to union type with content of BT_INFO.
+ * Typecasting conversion: (BT_INFO *) param.
+ * [return]
+ * 0 - default, don't care.
+ * [callback]
+ * None.
+ */
+ BT_MTK_OP_AUDIO_GET_CONFIG,
+ /* Audio config related information */
+} bt_mtk_opcode_t;
+
+typedef enum {
+ PCM = 0, // PCM 4 pins interface
+ I2S, // I2S interface
+ MERGE_INTERFACE, // PCM & I2S merge interface
+ CVSD_REMOVAL // SOC consys
+} AUDIO_IF;
+
+typedef enum {
+ SYNC_8K = 0,
+ SYNC_16K
+} SYNC_CLK; // DAIBT sample rate
+
+typedef enum {
+ SHORT_FRAME = 0,
+ LONG_FRAME
+} SYNC_FORMAT; // DAIBT sync
+
+typedef struct {
+ AUDIO_IF hw_if;
+ SYNC_CLK sample_rate;
+ SYNC_FORMAT sync_format;
+ unsigned int bit_len; // bit-length of sync frame in long frame sync
+} AUDIO_CONFIG;
+
+/* Information carring for all OPs (In/Out) */
+typedef union {
+ AUDIO_CONFIG audio_conf;
+} BT_INFO;
+
+namespace android {
+
+/*==============================================================================
+ * Property keys
+ *============================================================================*/
+
+/*==============================================================================
+ * Const Value
+ *============================================================================*/
+
+static const uint32_t kMaxFMChipVolume = 15;
+
+static const char kFmAudPathName[4][16] = {"FM_AUD_ANALOG", "FM_AUD_I2S", "FM_AUD_MRGIF", "FM_AUD_ERR"};
+static const char kFmI2sPadName[3][16] = {"FM_I2S_PAD_CONN", "FM_I2S_PAD_IO", "FM_I2S_PAD_ERR"};
+static const char kFmI2sModeName[3][16] = {"FM_I2S_MASTER", "FM_I2S_SLAVE", "FM_I2S_MODE_ERR"};
+static const char kFmI2sSampleRateName[4][16] = {"FM_I2S_32K", "FM_I2S_44K", "FM_I2S_48K", "FM_I2S_SR_ERR"};
+static const uint32_t kFmI2sSampleRateMapNum[4] = {32000, 44100, 48000, 44100}; // FM_I2S_SR_ERR => use default 44100Hz
+
+/*==============================================================================
+ * Enumerator
+ *============================================================================*/
+
+/*==============================================================================
+ * Singleton Pattern
+ *============================================================================*/
+
+WCNChipController *WCNChipController::mWCNChipController = NULL;
+AUDIO_CONFIG mBTAudioInfo;
+
+
+WCNChipController *WCNChipController::GetInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+
+ if (mWCNChipController == NULL) {
+ mWCNChipController = new WCNChipController();
+ }
+ ASSERT(mWCNChipController != NULL);
+ return mWCNChipController;
+}
+
+/*==============================================================================
+ * Constructor / Destructor / Init / Deinit
+ *============================================================================*/
+
+WCNChipController::WCNChipController() {
+ ALOGD("%s()", __FUNCTION__);
+
+ mInitAudioFMInfoFlag = false;
+ mInitAudioBTInfoFlag = false;
+ mPlatformSupportFM = IsCustomizedPlatformSupportFM();
+
+ // Default config error value
+ mFmAudioInfo.aud_path = FM_AUD_ERR;
+ mFmAudioInfo.i2s_info.status = FM_I2S_STATE_ERR;
+ mFmAudioInfo.i2s_info.mode = FM_I2S_MODE_ERR;
+ mFmAudioInfo.i2s_info.rate = FM_I2S_SR_ERR;
+ mFmAudioInfo.i2s_pad = FM_I2S_PAD_ERR;
+
+ mBTAudioInfo.hw_if = MERGE_INTERFACE;
+ mBTAudioInfo.sample_rate = SYNC_8K;
+ mBTAudioInfo.sync_format = SHORT_FRAME;
+ mBTAudioInfo.bit_len = 0;
+ //mBTAudioInfo.security_hi_lo = 0;
+
+ mBTCurrentSamplingRateNumber = 8000;
+}
+
+WCNChipController::~WCNChipController() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+/*==============================================================================
+ * WCN FM Chip Control
+ *============================================================================*/
+
+bool WCNChipController::GetFmChipPowerInfo() {
+ static const size_t BUF_LEN = 1;
+
+ char rbuf[BUF_LEN] = {'\0'};
+ char wbuf[BUF_LEN] = {'1'};
+ const char *FM_POWER_STAUTS_PATH = "/proc/fm";
+
+ ALOGD("+%s()", __FUNCTION__);
+ if (!mPlatformSupportFM) {
+ return false;
+ }
+
+ int fd = open(FM_POWER_STAUTS_PATH, O_RDONLY, 0);
+ if (fd < 0) {
+ ALOGE("-%s(), open(%s) fail!! fd = %d", __FUNCTION__, FM_POWER_STAUTS_PATH, fd);
+ return false;
+ }
+
+ int ret = read(fd, rbuf, BUF_LEN);
+ if (ret != BUF_LEN) {
+ ALOGE("-%s(), read(%s) fail!! ret = %d", __FUNCTION__, FM_POWER_STAUTS_PATH, ret);
+ close(fd);
+ return false;
+ }
+ close(fd);
+
+ const bool fm_power_on = (strncmp(wbuf, rbuf, BUF_LEN) == 0) ? true : false;
+
+ ALOGD("-%s(), fm_power_on = %d", __FUNCTION__, fm_power_on);
+ return fm_power_on;
+}
+
+status_t WCNChipController::SetFmChipVolume(const uint32_t fm_chip_volume) {
+ ALOGD("+%s(), fm_chip_volume = %u", __FUNCTION__, fm_chip_volume);
+
+ if (!mPlatformSupportFM) {
+ return INVALID_OPERATION;
+ }
+
+ WARNING("No need to set FM Chip Volume in Audio Driver");
+
+ ASSERT(0 <= fm_chip_volume && fm_chip_volume <= kMaxFMChipVolume);
+
+ ASSERT(GetFmChipPowerInfo() == true);
+
+ int fd_fm = open(FM_DEVICE_NAME, O_RDWR);
+ ALOGD("%s(), open(%s), fd_fm = %d", __FUNCTION__, FM_DEVICE_NAME, fd_fm);
+
+ if (fd_fm >= 0) {
+ int ret = ::ioctl(fd_fm, FM_IOCTL_SETVOL, &fm_chip_volume);
+ ALOGD("%s(), ioctl: FM_IOCTL_SETVOL, ret = %d", __FUNCTION__, ret);
+
+ close(fd_fm);
+ }
+
+ ALOGD("-%s(), fm_chip_volume = %u", __FUNCTION__, fm_chip_volume);
+ return NO_ERROR;
+}
+
+
+status_t WCNChipController::SetFmChipSampleRate(const uint32_t sample_rate) {
+ ALOGD("+%s(), sample_rate = %u", __FUNCTION__, sample_rate);
+
+ if (!mPlatformSupportFM) {
+ return INVALID_OPERATION;
+ }
+ //ASSERT(GetFmChipPowerInfo() == true);
+
+ if (mInitAudioFMInfoFlag == false) { InitAudioFMInfo(); }
+ ASSERT(mFmAudioInfo.i2s_info.mode != FM_I2S_MODE_ERR);
+
+ struct fm_i2s_setting fmSetting;
+ fmSetting.onoff = FM_I2S_ON;
+ fmSetting.mode = mFmAudioInfo.i2s_info.mode;
+ if (sample_rate == 32000) {
+ fmSetting.sample = FM_I2S_32K;
+ } else if (sample_rate == 44100) {
+ fmSetting.sample = FM_I2S_44K;
+ } else if (sample_rate == 48000) {
+ fmSetting.sample = FM_I2S_48K;
+ } else {
+ ALOGW("%s(), no such sample_rate = %u, return!!", __FUNCTION__, sample_rate);
+ return BAD_VALUE;
+ }
+
+
+ int fd_fm = open(FM_DEVICE_NAME, O_RDWR);
+ ALOGD("%s(), open(%s), fd_fm = %d", __FUNCTION__, FM_DEVICE_NAME, fd_fm);
+
+ if (fd_fm >= 0) {
+ int ret = ::ioctl(fd_fm, FM_IOCTL_I2S_SETTING, &fmSetting);
+ ALOGD("%s(), ioctl: FM_IOCTL_I2S_SETTING, ret = %d", __FUNCTION__, ret);
+
+ close(fd_fm);
+ }
+
+ ALOGD("-%s(), sample_rate = %u", __FUNCTION__, sample_rate);
+ return NO_ERROR;
+}
+
+
+status_t WCNChipController::InitAudioFMInfo() {
+ Mutex::Autolock _l(mLock);
+
+ if (!mPlatformSupportFM) {
+ return INVALID_OPERATION;
+ }
+
+ if (mInitAudioFMInfoFlag == true) {
+ ALOGD("%s(), mInitAudioFMInfoFlag == true, return", __FUNCTION__);
+ return NO_ERROR;
+ }
+ mInitAudioFMInfoFlag = true;
+
+#if defined(MTK_FM_SUPPORT)
+ // Get audio fm related info from fm driver
+ int fd_fm = 0;
+ const int kMaxTryCnt = 30; // max wait 3 sec
+ for (int trycnt = 1; trycnt <= kMaxTryCnt; trycnt++) {
+ ALOGD("%s(), +open(%s), fd_fm = %d", __FUNCTION__, FM_DEVICE_NAME, fd_fm);
+ fd_fm = open(FM_DEVICE_NAME, O_RDWR);
+ ALOGD("%s(), -open(%s), fd_fm = %d", __FUNCTION__, FM_DEVICE_NAME, fd_fm);
+ if (fd_fm < 0) {
+ ALOGE("%s(), open(%s) failed #%d times!! sleep 100 ms & try it again", __FUNCTION__, FM_DEVICE_NAME, trycnt);
+ usleep(100 * 1000);
+ } else {
+ int ret = ::ioctl(fd_fm, FM_IOCTL_GET_AUDIO_INFO, &mFmAudioInfo);
+ ALOGD("%s(), ioctl: FM_IOCTL_GET_AUDIO_INFO, ret = %d", __FUNCTION__, ret);
+
+ // Not support analog line in, check here
+ ASSERT(mFmAudioInfo.aud_path != FM_AUD_ANALOG);
+
+ close(fd_fm);
+ break;
+ }
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+#if defined(__LP64__)
+#define AUDIO_BT_LIB_VENDOR_PATH "/vendor/lib64/libbluetooth_mtk_pure.so"
+#define AUDIO_BT_LIB_PATH "/system/lib64/libbluetooth_mtk_pure.so"
+#else
+#define AUDIO_BT_LIB_VENDOR_PATH "/vendor/lib/libbluetooth_mtk_pure.so"
+#define AUDIO_BT_LIB_PATH "/system/lib/libbluetooth_mtk_pure.so"
+#endif
+
+status_t WCNChipController::InitAudioBTInfo() {
+ Mutex::Autolock _l(mLock);
+
+ if (mInitAudioBTInfoFlag == true) {
+ ALOGD("%s(), mInitAudioBTInfoFlag == true, return", __FUNCTION__);
+ return NO_ERROR;
+ }
+ mInitAudioBTInfoFlag = true;
+
+ BT_INFO result;//BT_RESULT result;
+ int ret;
+
+ void *libHandle = NULL;
+ int (*mtk_bt_op)(bt_mtk_opcode_t opcode, void *param);
+ ALOGD("%s(), dlopen %s", __FUNCTION__, AUDIO_BT_LIB_VENDOR_PATH);
+ // load bt lib
+ libHandle = dlopen(AUDIO_BT_LIB_VENDOR_PATH, RTLD_NOW);
+ if (!libHandle) {
+ ALOGW("%s(), dlopen %s failed, dlerror = %s, try %s",
+ __FUNCTION__, AUDIO_BT_LIB_VENDOR_PATH, dlerror(), AUDIO_BT_LIB_PATH);
+
+ libHandle = dlopen(AUDIO_BT_LIB_PATH, RTLD_NOW);
+ if (!libHandle) {
+ ALOGW("%s(), dlopen %s failed, dlerror = %s",
+ __FUNCTION__, AUDIO_BT_LIB_PATH, dlerror());
+ }
+ }
+
+ if (libHandle) {
+ ALOGD("%s(), mtk_bt_op dlsym", __FUNCTION__);
+ mtk_bt_op = (int (*)(bt_mtk_opcode_t, void *))dlsym(libHandle, "mtk_bt_op");
+ if (!mtk_bt_op) {
+ ALOGW("%s(), mtk_bt_op dlsym failed, dlerror = %s", __FUNCTION__, dlerror());
+ }
+ }
+
+ if (libHandle && mtk_bt_op) {
+ // get bt info
+ for (int trycnt = 1; trycnt <= 10; trycnt++) {
+ ALOGD("%s(), mtk_bt_op dlsym BT_MTK_OP_AUDIO_GET_CONFIG, trycnt=%d", __FUNCTION__, trycnt);
+ ret = mtk_bt_op(BT_MTK_OP_AUDIO_GET_CONFIG, &result);
+ //result->param.audio_config.hw_if
+ ALOGD("%s(), query BT info status = %d", __FUNCTION__, ret);
+ if (ret < 0) { //if (result.status == false)
+ ALOGE("%s(), query BT info fail!! sleep 100 ms & try it again", __FUNCTION__);
+ usleep(100 * 1000);
+ } else {
+ //mBTAudioInfo.hw_if = result.param.audio_conf.hw_if;
+ //mBTAudioInfo.sample_rate = result.param.audio_conf.sample_rate;
+ //mBTAudioInfo.sync_format = result.param.audio_conf.sync_format;
+ //mBTAudioInfo.bit_len = result.param.audio_conf.bit_len;
+ mBTAudioInfo.hw_if = result.audio_conf.hw_if;
+ mBTAudioInfo.sample_rate = result.audio_conf.sample_rate;
+ mBTAudioInfo.sync_format = result.audio_conf.sync_format;
+ mBTAudioInfo.bit_len = result.audio_conf.bit_len;
+ break;
+ }
+ }
+ } else {
+#ifdef SW_BTCVSD_ENABLE
+ mBTAudioInfo.hw_if = CVSD_REMOVAL;
+#else
+ mBTAudioInfo.hw_if = MERGE_INTERFACE;
+#endif
+ mBTAudioInfo.sample_rate = SYNC_8K;
+ mBTAudioInfo.sync_format = SHORT_FRAME;
+ mBTAudioInfo.bit_len = 0;
+ }
+
+ // close lib
+ if (libHandle) {
+ if (dlclose(libHandle)) {
+ ALOGE("%s(), dlclose failed, dlerror = %s", __FUNCTION__, dlerror());
+ }
+ }
+
+ ALOGD("%s(), hw_if=%d, sample_rate=%d, sync_format=%d, bit_len=%d", __FUNCTION__,
+ mBTAudioInfo.hw_if, mBTAudioInfo.sample_rate, mBTAudioInfo.sync_format, mBTAudioInfo.bit_len);
+
+ return NO_ERROR;
+}
+
+bool WCNChipController::IsFMMergeInterfaceSupported() {
+ if (!mPlatformSupportFM) {
+ return false;
+ }
+
+ if (mInitAudioFMInfoFlag == false) { InitAudioFMInfo(); }
+
+#if defined(MTK_FM_SUPPORT)
+ ALOGV("%s(), mFmAudioInfo.aud_path = %s", __FUNCTION__, kFmAudPathName[mFmAudioInfo.aud_path]);
+ ASSERT(mFmAudioInfo.aud_path != FM_AUD_ERR);
+ return (mFmAudioInfo.aud_path == FM_AUD_MRGIF) ? true : false;
+#else // no FM
+ return false;
+#endif
+}
+
+bool WCNChipController::IsBTMergeInterfaceSupported() {
+ ALOGD("%s(), mPlatformSupportFM=%d, mInitAudioBTInfoFlag =%d",
+ __FUNCTION__, mPlatformSupportFM, mInitAudioBTInfoFlag);
+
+ if (!mPlatformSupportFM) {
+ return false;
+ }
+
+ if (mInitAudioBTInfoFlag == false) { InitAudioBTInfo(); }
+
+#if defined(MTK_BT_SUPPORT)
+ ALOGD("%s(), BTChipHWInterface() = %d", __FUNCTION__, BTChipHWInterface());
+ return (BTChipHWInterface() == MERGE_INTERFACE) ? true : false;
+#else // no BT
+ return false;
+#endif
+}
+
+
+bool WCNChipController::IsFmChipPadSelConnSys() {
+ if (!mPlatformSupportFM) {
+ return false;
+ }
+
+#if defined(MTK_FM_SUPPORT)
+ if (mInitAudioFMInfoFlag == false) { InitAudioFMInfo(); }
+
+ ALOGD("%s(), mFmAudioInfo.i2s_pad = %s", __FUNCTION__, kFmI2sPadName[mFmAudioInfo.i2s_pad]);
+ ASSERT(mFmAudioInfo.i2s_pad != FM_I2S_PAD_ERR);
+
+ return (mFmAudioInfo.i2s_pad == FM_I2S_PAD_CONN) ? true : false;
+#else
+ return false; // default FM signal goes through IO_MUX
+#endif
+}
+
+bool WCNChipController::IsFmChipUseSlaveMode() {
+ if (!mPlatformSupportFM) {
+ return false;
+ }
+
+#if defined(MTK_FM_SUPPORT)
+ if (mInitAudioFMInfoFlag == false) { InitAudioFMInfo(); }
+
+ ALOGD("%s(), mFmAudioInfo.i2s_info.mode = %s", __FUNCTION__, kFmI2sModeName[mFmAudioInfo.i2s_info.mode]);
+ ASSERT(mFmAudioInfo.i2s_info.mode != FM_I2S_MODE_ERR);
+
+ return (mFmAudioInfo.i2s_info.mode == FM_I2S_SLAVE) ? true : false;
+#else
+ return true; // default FM I2S slave mode, Audio I2S master mode
+#endif
+}
+
+uint32_t WCNChipController::GetFmChipSamplingRate() {
+ if (!mPlatformSupportFM) {
+ return 44100;
+ }
+
+#if defined(MTK_FM_SUPPORT)
+ if (mInitAudioFMInfoFlag == false) { InitAudioFMInfo(); }
+
+ ALOGD("%s(), mFmAudioInfo.i2s_info.rate = %s, return %d", __FUNCTION__,
+ kFmI2sSampleRateName[mFmAudioInfo.i2s_info.rate],
+ kFmI2sSampleRateMapNum[mFmAudioInfo.i2s_info.rate]);
+ ASSERT(mFmAudioInfo.i2s_info.rate != FM_I2S_SR_ERR);
+
+ return kFmI2sSampleRateMapNum[mFmAudioInfo.i2s_info.rate];
+#else
+ return 44100; // default setting FM chip sampling rate 44100 Hz
+#endif
+}
+
+uint32_t WCNChipController::BTChipHWInterface() {
+ if (mInitAudioBTInfoFlag == false) { InitAudioBTInfo(); }
+
+#if defined(MTK_BT_SUPPORT)
+ return mBTAudioInfo.hw_if;
+#else
+#if defined(SW_BTCVSD_ENABLE)
+ return CVSD_REMOVAL; // 0: PCM, 1: I2S, 2: MERGE_INTERFACE, 3: CVSD_REMOVAL
+#else
+ return MERGE_INTERFACE; // 0: PCM, 1: I2S, 2: MERGE_INTERFACE, 3: CVSD_REMOVAL
+#endif
+
+#endif
+}
+
+bool WCNChipController::BTUseCVSDRemoval() {
+ if (mInitAudioBTInfoFlag == false) { InitAudioBTInfo(); }
+
+ return (BTChipHWInterface() == CVSD_REMOVAL) ? true : false;
+}
+
+uint32_t WCNChipController::BTChipSamplingRate() {
+#if defined(MTK_BT_SUPPORT)
+ if (mInitAudioBTInfoFlag == false) { InitAudioBTInfo(); }
+ return mBTAudioInfo.sample_rate; //0:SYNC_8K, 1: SYNC_16K
+#else
+ return SYNC_8K; // default setting is NB 8k
+#endif
+}
+
+uint32_t WCNChipController::BTChipSamplingRateNumber() {
+ return (BTChipSamplingRate() == SYNC_8K) ? 8000 : 16000;
+}
+
+uint32_t WCNChipController::BTChipSyncFormat() {
+#if defined(MTK_BT_SUPPORT)
+ if (mInitAudioBTInfoFlag == false) { InitAudioBTInfo(); }
+ return mBTAudioInfo.sync_format; //0:SHORT_FRAME, 1: LONG_FRAME
+#else
+ return 0; // default setting is SHORT_FRAME
+#endif
+}
+
+uint32_t WCNChipController::BTChipSyncLength() {
+#if defined(MTK_BT_SUPPORT)
+ if (mInitAudioBTInfoFlag == false) { InitAudioBTInfo(); }
+ return mBTAudioInfo.bit_len;
+#else
+ return 0; // default setting is 0
+#endif
+}
+
+uint32_t WCNChipController::BTChipSecurityHiLo() {
+ return 0; // WCN does not provide this property
+}
+
+
+void WCNChipController::SetBTCurrentSamplingRateNumber(const uint32_t sample_rate) {
+ ALOGD("%s(), mBTCurrentSamplingRateNumber: %d => %d", __FUNCTION__, mBTCurrentSamplingRateNumber, sample_rate);
+ ASSERT(sample_rate == 8000 || sample_rate == 16000);
+ mBTCurrentSamplingRateNumber = sample_rate;
+}
+
+uint32_t WCNChipController::GetBTCurrentSamplingRateNumber() {
+ return mBTCurrentSamplingRateNumber;
+}
+
+bool WCNChipController::IsSupportFM() {
+ // Don't Change this
+ return mPlatformSupportFM;
+}
+
+bool WCNChipController::IsCustomizedPlatformSupportFM() {
+ // Customer could modify the return value by other methods
+ return true;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/audio_hw_hal.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/audio_hw_hal.cpp
new file mode 100644
index 0000000..956c091
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/aud_drv/audio_hw_hal.cpp
@@ -0,0 +1,1353 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+ * Copyright (C) 2011 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 "mtk_audio_hw_hal"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+//#include <hardware/audio.h>
+#include <hardware/audio_mtk.h>
+#include <media/AudioParameter.h>
+
+#include <hardware_legacy/AudioMTKHardwareInterface.h>
+
+#include "AudioType.h"
+#include "AudioDeviceInt.h"
+#include "AudioTypeExt.h"
+#include <sys/time.h>
+#include <utils/Log.h>
+#include <cutils/properties.h>
+#include <utils/String16.h>
+#include <utils/threads.h>
+#include <pthread.h>
+#include <string>
+#include <libladder.h>
+
+namespace android {
+
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+#define CALLSTACK() \
+ { \
+ ALOGD("CALL STACK : - %s", __FUNCTION__); \
+ std::string stackString; \
+ UnwindCurThreadBT(&stackString); \
+ ALOGD("\t%s", stackString.c_str()); \
+ }
+#define AUDIO_HAL_FUNCTION_MIN_NS (10000000) // 10 ms
+#define AUDIO_HAL_FUNCTION_READ_NS (80000000) // 80 ms
+#define AUDIO_HAL_FUNCTION_WRITE_NS (80000000) // 80 ms
+#define AUDIO_HAL_FUNCTION_CREATEPATCH_NS (80000000) // 80 ms
+#define AUDIO_HAL_FUNCTION_SETMODE_NS (80000000) // 80 ms
+class AudioAutoTimeProfile {
+public:
+ inline AudioAutoTimeProfile(const char *kFuncName): mBeginTime(0), mEndTime(0), mTotalTime(0), mThresholdTime(AUDIO_HAL_FUNCTION_MIN_NS) {
+ s8 = String8(kFuncName);
+ mBeginTime = systemTime();
+ }
+ inline AudioAutoTimeProfile(const char *kFuncName, nsecs_t WarningNsec): mBeginTime(0), mEndTime(0), mTotalTime(0), mThresholdTime(AUDIO_HAL_FUNCTION_MIN_NS) {
+ if (WarningNsec > mThresholdTime) {
+ mThresholdTime = WarningNsec;
+ }
+ s8 = String8(kFuncName);
+ mBeginTime = systemTime();
+ }
+ inline ~AudioAutoTimeProfile() {
+ mEndTime = systemTime();
+ mTotalTime = mEndTime - mBeginTime;
+ if (mTotalTime >= mThresholdTime) {
+ ALOGD("mtkAudProfile %" PRId64 " ms @ %s", mTotalTime / 1000000, s8.string());
+ if (mDumpStack > 0) {
+ CALLSTACK();
+ }
+ }
+ }
+ static int mDumpStack;
+private:
+ nsecs_t mBeginTime;
+ nsecs_t mEndTime;
+ nsecs_t mTotalTime;
+ nsecs_t mThresholdTime;;
+ String8 s8;
+};
+
+int AudioAutoTimeProfile::mDumpStack = 0;
+#endif
+
+/** HIDL Client usage and singleton Audio HAL Instance**/
+static uint32_t gAudioHALRefCountByClient = 0;
+static pthread_mutex_t gHwInstanceLock = PTHREAD_MUTEX_INITIALIZER;
+
+extern "C" {
+
+ struct legacy_audio_module {
+ struct audio_module module;
+ };
+
+ struct legacy_audio_device {
+ struct audio_hw_device_mtk device;
+
+ AudioMTKHardwareInterface *hwif;
+ };
+
+ struct legacy_stream_out {
+ struct audio_stream_out stream;
+
+ AudioMTKStreamOutInterface *legacy_out;
+ };
+
+ struct legacy_stream_in {
+ struct audio_stream_in stream;
+
+ AudioMTKStreamInInterface *legacy_in;
+ };
+
+ /** audio_stream_out implementation **/
+ static uint32_t out_get_sample_rate(const struct audio_stream *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->sampleRate();
+ }
+
+ static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate __unused) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement this */
+ return 0;
+ }
+
+ static size_t out_get_buffer_size(const struct audio_stream *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->bufferSize();
+ }
+
+ static audio_channel_mask_t out_get_channels(const struct audio_stream *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return (audio_channel_mask_t) out->legacy_out->channels();
+ }
+
+ static audio_format_t out_get_format(const struct audio_stream *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ // legacy API, don't change return type
+ return (audio_format_t) out->legacy_out->format();
+ }
+
+ static int out_set_format(struct audio_stream *stream, audio_format_t format __unused) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement me */
+ return 0;
+ }
+
+ static int out_standby(struct audio_stream *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ return out->legacy_out->standby(false);
+ }
+
+ static int out_dump(const struct audio_stream *stream, int fd) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ Vector<String16> args;
+ return out->legacy_out->dump(fd, args);
+ }
+
+ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ int val;
+ String8 s8 = String8(kvpairs);
+ AudioParameter parms = AudioParameter(String8(kvpairs));
+
+ return out->legacy_out->setParameters(s8);
+ }
+
+ static char *out_get_parameters(const struct audio_stream *stream, const char *keys) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ String8 s8;
+ int val;
+
+ s8 = out->legacy_out->getParameters(String8(keys));
+
+ AudioParameter parms = AudioParameter(s8);
+
+ return strdup(s8.string());
+ }
+
+ static uint32_t out_get_latency(const struct audio_stream_out *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->latency();
+ }
+
+ static int out_set_volume(struct audio_stream_out *stream, float left,
+ float right) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ return out->legacy_out->setVolume(left, right);
+ }
+
+ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
+ size_t bytes) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__, AUDIO_HAL_FUNCTION_WRITE_NS);
+#endif
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ return out->legacy_out->write(buffer, bytes);
+ }
+
+ static int out_drain(struct audio_stream_out *stream, audio_drain_type_t type) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ return out->legacy_out->drain(type);
+ }
+
+ static int out_pause(struct audio_stream_out *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ return out->legacy_out->pause();
+ }
+
+ static int out_resume(struct audio_stream_out *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ return out->legacy_out->resume();
+ }
+
+ static int out_flush(struct audio_stream_out *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ return out->legacy_out->flush();
+ }
+
+ static int out_get_render_position(const struct audio_stream_out *stream,
+ uint32_t *dsp_frames) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->getRenderPosition(dsp_frames);
+ }
+
+ static int out_get_next_write_timestamp(const struct audio_stream_out *stream,
+ int64_t *timestamp) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->getNextWriteTimestamp(timestamp);
+ }
+
+ static int out_set_callback(struct audio_stream_out *stream,
+ stream_callback_t callback, void *cookie) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+#if 1
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->setCallBack(callback, cookie);
+#else
+ return -EINVAL;
+#endif
+ }
+
+ static int out_get_presentation_position(const struct audio_stream_out *stream,
+ uint64_t *frames, struct timespec *timestamp) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+#if 1
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->getPresentationPosition(frames, timestamp);
+#else
+ return -EINVAL;
+#endif
+ }
+
+ static void out_update_source_metadata(struct audio_stream_out *stream,
+ const struct source_metadata* source_metadata) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->updateSourceMetadata(source_metadata);
+ }
+
+ static int out_add_audio_effect(const struct audio_stream *stream __unused, effect_handle_t effect __unused) {
+ return -EINVAL;
+ }
+
+ static int out_remove_audio_effect(const struct audio_stream *stream __unused, effect_handle_t effect __unused) {
+ return -EINVAL;
+ }
+
+ static int out_start(const struct audio_stream_out *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->start();
+ }
+
+ static int out_stop(const struct audio_stream_out *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->stop();
+ }
+
+ static int out_create_mmap_buffer(const struct audio_stream_out *stream,
+ int32_t min_size_frames, struct audio_mmap_buffer_info *info) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->createMmapBuffer(min_size_frames, info);
+ }
+
+ static int out_get_mmap_position(const struct audio_stream_out *stream,
+ struct audio_mmap_position *position) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->getMmapPosition(position);
+ }
+
+ /** audio_stream_in implementation **/
+ static uint32_t in_get_sample_rate(const struct audio_stream *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->sampleRate();
+ }
+
+ static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate __unused) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement this */
+ return 0;
+ }
+
+ static size_t in_get_buffer_size(const struct audio_stream *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->bufferSize();
+ }
+
+ static audio_channel_mask_t in_get_channels(const struct audio_stream *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return (audio_channel_mask_t) in->legacy_in->channels();
+ }
+
+ static audio_format_t in_get_format(const struct audio_stream *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ // legacy API, don't change return type
+ return (audio_format_t) in->legacy_in->format();
+ }
+
+ static int in_set_format(struct audio_stream *stream, audio_format_t format __unused) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement me */
+ return 0;
+ }
+
+ static int in_standby(struct audio_stream *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_stream_in *in = reinterpret_cast<struct legacy_stream_in *>(stream);
+ return in->legacy_in->standby(false);
+ }
+
+ static int in_dump(const struct audio_stream *stream, int fd) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ Vector<String16> args;
+ return in->legacy_in->dump(fd, args);
+ }
+
+ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+ int val;
+ AudioParameter parms = AudioParameter(String8(kvpairs));
+ String8 s8 = String8(kvpairs);
+
+ return in->legacy_in->setParameters(s8);
+ }
+
+ static char *in_get_parameters(const struct audio_stream *stream,
+ const char *keys) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ String8 s8;
+ int val;
+
+ s8 = in->legacy_in->getParameters(String8(keys));
+
+ AudioParameter parms = AudioParameter(s8);
+
+ return strdup(s8.string());
+ }
+
+ static int in_set_gain(struct audio_stream_in *stream, float gain) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+ return in->legacy_in->setGain(gain);
+ }
+
+ static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
+ size_t bytes) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__, AUDIO_HAL_FUNCTION_READ_NS);
+#endif
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+ return in->legacy_in->read(buffer, bytes);
+ }
+
+ static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+ return in->legacy_in->getInputFramesLost();
+ }
+
+ static int in_get_capture_position(const struct audio_stream_in *stream,
+ int64_t *frames, int64_t *time) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->getCapturePosition(frames, time);
+ }
+
+ static int in_get_active_microphones(const struct audio_stream_in *stream,
+ struct audio_microphone_characteristic_t *mic_array,
+ size_t *mic_count) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->getActiveMicrophones(mic_array, mic_count);
+ }
+
+ static void in_update_sink_metadata(struct audio_stream_in *stream,
+ const struct sink_metadata *sink_metadata) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->updateSinkMetadata(sink_metadata);
+ }
+
+ static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->addAudioEffect(effect);
+ }
+
+ static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->removeAudioEffect(effect);
+ }
+
+ static int in_start(const struct audio_stream_in *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->start();
+ }
+
+ static int in_stop(const struct audio_stream_in *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->stop();
+ }
+
+ static int in_create_mmap_buffer(const struct audio_stream_in *stream,
+ int32_t min_size_frames, struct audio_mmap_buffer_info *info) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->createMmapBuffer(min_size_frames, info);
+ }
+
+ static int in_get_mmap_position(const struct audio_stream_in *stream,
+ struct audio_mmap_position *position) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->getMmapPosition(position);
+ }
+
+ /** audio_hw_device implementation **/
+ static inline struct legacy_audio_device *to_ladev(struct audio_hw_device *dev) {
+ return reinterpret_cast<struct legacy_audio_device *>(dev);
+ }
+
+ static inline const struct legacy_audio_device *to_cladev(const struct audio_hw_device *dev) {
+ return reinterpret_cast<const struct legacy_audio_device *>(dev);
+ }
+
+ static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev __unused) {
+ /* XXX: The old AudioHardwareInterface interface is not smart enough to
+ * tell us this, so we'll lie and basically tell AF that we support the
+ * below input/output devices and cross our fingers. To do things properly,
+ * audio hardware interfaces that need advanced features (like this) should
+ * convert to the new HAL interface and not use this wrapper. */
+
+ return (/* OUT */
+ AUDIO_DEVICE_OUT_EARPIECE |
+ AUDIO_DEVICE_OUT_SPEAKER |
+ AUDIO_DEVICE_OUT_WIRED_HEADSET |
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+ AUDIO_DEVICE_OUT_AUX_DIGITAL |
+ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
+ AUDIO_DEVICE_OUT_ALL_SCO |
+ AUDIO_DEVICE_OUT_FM |
+ AUDIO_DEVICE_OUT_DEFAULT |
+ /* IN */
+ AUDIO_DEVICE_IN_COMMUNICATION |
+ AUDIO_DEVICE_IN_AMBIENT |
+ AUDIO_DEVICE_IN_BUILTIN_MIC |
+ AUDIO_DEVICE_IN_WIRED_HEADSET |
+ AUDIO_DEVICE_IN_AUX_DIGITAL |
+ AUDIO_DEVICE_IN_VOICE_CALL |
+ AUDIO_DEVICE_IN_BACK_MIC |
+ AUDIO_DEVICE_IN_ALL_SCO |
+ AUDIO_DEVICE_IN_FM_TUNER |
+ AUDIO_DEVICE_IN_DEFAULT);
+ }
+
+ static int adev_init_check(const struct audio_hw_device *dev) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_audio_device *ladev = to_cladev(dev);
+
+ return ladev->hwif->initCheck();
+ }
+
+ static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->setVoiceVolume(volume);
+ }
+
+ static int adev_set_master_volume(struct audio_hw_device *dev, float volume) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->setMasterVolume(volume);
+ }
+
+ static int adev_get_master_volume(struct audio_hw_device *dev, float *volume) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->getMasterVolume(volume);
+ }
+
+ static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__, AUDIO_HAL_FUNCTION_SETMODE_NS);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ // as this is the legacy API, don't change it to use audio_mode_t instead of int
+ return ladev->hwif->setMode((int) mode);
+ }
+
+ static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->setMicMute(state);
+ }
+
+ static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_audio_device *ladev = to_cladev(dev);
+ return ladev->hwif->getMicMute(state);
+ }
+
+ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->setParameters(String8(kvpairs));
+ }
+
+ static char *adev_get_parameters(const struct audio_hw_device *dev,
+ const char *keys) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_audio_device *ladev = to_cladev(dev);
+ String8 s8;
+
+ s8 = ladev->hwif->getParameters(String8(keys));
+ return strdup(s8.string());
+ }
+
+ static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
+ const struct audio_config *config) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_audio_device *ladev = to_cladev(dev);
+ return ladev->hwif->getInputBufferSize(config->sample_rate, (int) config->format,
+ popcount(config->channel_mask));
+ }
+
+ 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) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ status_t status = (status_t) handle;
+ struct legacy_stream_out *out;
+ int ret;
+
+ out = (struct legacy_stream_out *)calloc(1, sizeof(*out));
+ if (!out) {
+ return -ENOMEM;
+ }
+
+ out->legacy_out = ladev->hwif->openOutputStreamWithFlags(devices, flags,
+ (int *) &config->format,
+ &config->channel_mask,
+ &config->sample_rate, &status);
+ if (!out->legacy_out) {
+ ret = status;
+ goto err_open;
+ }
+
+ out->stream.common.get_sample_rate = out_get_sample_rate;
+ out->stream.common.set_sample_rate = out_set_sample_rate;
+ out->stream.common.get_buffer_size = out_get_buffer_size;
+ out->stream.common.get_channels = out_get_channels;
+ out->stream.common.get_format = out_get_format;
+ out->stream.common.set_format = out_set_format;
+ out->stream.common.standby = out_standby;
+ out->stream.common.dump = out_dump;
+ out->stream.common.set_parameters = out_set_parameters;
+ out->stream.common.get_parameters = out_get_parameters;
+ out->stream.common.add_audio_effect = out_add_audio_effect;
+ out->stream.common.remove_audio_effect = out_remove_audio_effect;
+ out->stream.get_latency = out_get_latency;
+ out->stream.set_volume = out_set_volume;
+ out->stream.write = out_write;
+ out->stream.get_render_position = out_get_render_position;
+ out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
+
+ out->stream.set_callback = out_set_callback;
+ out->stream.get_presentation_position = out_get_presentation_position;
+
+ out->stream.update_source_metadata = out_update_source_metadata;
+
+ out->stream.pause = out_pause;
+ out->stream.resume = out_resume;
+ out->stream.drain = out_drain;
+ out->stream.flush = out_flush;
+
+ // AAudio MMAP
+ if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
+ out->stream.start = out_start;
+ out->stream.stop = out_stop;
+ out->stream.create_mmap_buffer = out_create_mmap_buffer;
+ out->stream.get_mmap_position = out_get_mmap_position;
+ }
+
+ *stream_out = &out->stream;
+ return 0;
+
+err_open:
+ free(out);
+ *stream_out = NULL;
+ return ret;
+ }
+
+ static void adev_close_output_stream(struct audio_hw_device *dev,
+ struct audio_stream_out *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ struct legacy_stream_out *out = reinterpret_cast<struct legacy_stream_out *>(stream);
+
+ ladev->hwif->closeOutputStream(out->legacy_out);
+ free(out);
+ }
+
+ /** This method creates and opens the audio hardware input 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*/) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ status_t status = (status_t) handle;;
+ struct legacy_stream_in *in;
+ int ret;
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyInputSource), source);
+ in = (struct legacy_stream_in *)calloc(1, sizeof(*in));
+ if (!in) {
+ return -ENOMEM;
+ }
+
+#ifdef UPLINK_LOW_LATENCY
+ in->legacy_in = ladev->hwif->openInputStreamWithFlags(devices, (int *) &config->format,
+ &config->channel_mask, &config->sample_rate,
+ &status, (audio_in_acoustics_t)0, flags);
+#else
+ in->legacy_in = ladev->hwif->openInputStream(devices, (int *) &config->format,
+ &config->channel_mask, &config->sample_rate,
+ &status, (audio_in_acoustics_t)0);
+#endif
+ if (!in->legacy_in) {
+ ret = status;
+ goto err_open;
+ }
+ in->legacy_in->setParameters(param.toString());
+ in->stream.common.get_sample_rate = in_get_sample_rate;
+ 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;
+ 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;
+ 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;
+ in->stream.get_capture_position = in_get_capture_position;
+
+ in->stream.get_active_microphones = in_get_active_microphones;
+ in->stream.update_sink_metadata = in_update_sink_metadata;
+
+ // AAudio MMAP
+ if (flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) {
+ in->stream.start = in_start;
+ in->stream.stop = in_stop;
+ in->stream.create_mmap_buffer = in_create_mmap_buffer;
+ in->stream.get_mmap_position = in_get_mmap_position;
+ }
+
+ *stream_in = &in->stream;
+ return 0;
+
+err_open:
+ free(in);
+ *stream_in = NULL;
+ return ret;
+ }
+
+ //-----------------------------------------------------------------
+ static int adev_set_emparameter(struct audio_hw_device *dev, void *ptr, int len) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->SetEMParameter(ptr, len);
+ }
+
+ static int adev_get_emparameter(struct audio_hw_device *dev, void *ptr, int len) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->GetEMParameter(ptr, len);
+ }
+
+ static int adev_set_audiocommand(struct audio_hw_device *dev, int par1, int par2) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->SetAudioCommand(par1, par2);
+ }
+
+ static int adev_get_audiocommand(struct audio_hw_device *dev, int par1) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->GetAudioCommand(par1);
+ }
+
+ static int adev_set_audiodata(struct audio_hw_device *dev, int par1, size_t len, void *ptr) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->SetAudioData(par1, len, ptr);
+ }
+
+ static int adev_get_audiodata(struct audio_hw_device *dev, int par1, size_t len, void *ptr) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->GetAudioData(par1, len, ptr);
+ }
+
+#if 0
+ static int adev_set_acf_previewparameter(struct audio_hw_device *dev, void *ptr, int len) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->SetACFPreviewParameter(ptr, len);
+ }
+
+ static int adev_set_hcf_previewparameter(struct audio_hw_device *dev, void *ptr, int len) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->SetHCFPreviewParameter(ptr, len);
+ }
+#endif
+
+ static int adev_xway_play_start(struct audio_hw_device *dev, int sample_rate) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->xWayPlay_Start(sample_rate);
+ }
+
+ static int adev_xway_play_stop(struct audio_hw_device *dev) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->xWayPlay_Stop();
+ }
+
+ static int adev_xway_play_write(struct audio_hw_device *dev, void *buffer, int size_bytes) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->xWayPlay_Write(buffer, size_bytes);
+ }
+
+ static int adev_xway_getfreebuffercount(struct audio_hw_device *dev) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->xWayPlay_GetFreeBufferCount();
+ }
+
+ static int adev_xway_rec_start(struct audio_hw_device *dev, int smple_rate) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->xWayRec_Start(smple_rate);
+ }
+
+ static int adev_xway_rec_stop(struct audio_hw_device *dev) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->xWayRec_Stop();
+ }
+
+ static int adev_xway_rec_read(struct audio_hw_device *dev, void *buffer, int size_bytes) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->xWayRec_Read(buffer, size_bytes);
+ }
+
+ //add by wendy
+ static int adev_read_ref_from_ring(struct audio_hw_device *dev, void *buf, uint32_t datasz, void *dltime) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->ReadRefFromRing(buf, datasz, dltime);
+ }
+ static int adev_get_vow_ul_time(struct audio_hw_device *dev, void *ultime) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->GetVoiceUnlockULTime(ultime);
+ }
+
+ static int adev_set_vow_src_sample_rate(struct audio_hw_device *dev, uint32_t rate, uint32_t channel) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->SetVoiceUnlockSRC(rate, channel);
+ }
+ static bool adev_start_vow_dl(struct audio_hw_device *dev) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->startVoiceUnlockDL();
+ }
+ static bool adev_stop_vow_dl(struct audio_hw_device *dev) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->stopVoiceUnlockDL();
+ }
+#if 0
+ static void adev_freeVoiceUnlockDLInstance(struct audio_hw_device *dev) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->freeVoiceUnlockDLInstance();
+
+ }
+ static int adev_GetVoiceUnlockDLLatency(struct audio_hw_device *dev) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->GetVoiceUnlockDLLatency();
+
+ }
+#endif
+ static bool adev_get_vow_dl_instance(struct audio_hw_device *dev) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->getVoiceUnlockDLInstance();
+
+ }
+ //-------------------------------------------------------------------------
+
+ static void adev_close_input_stream(struct audio_hw_device *dev,
+ struct audio_stream_in *stream) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+
+ ladev->hwif->closeInputStream(in->legacy_in);
+ free(in);
+ }
+
+ static int adev_get_microphones(const struct audio_hw_device *dev,
+ struct audio_microphone_characteristic_t *mic_array,
+ size_t *mic_count) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_audio_device *ladev = to_cladev(dev);
+ return ladev->hwif->getMicrophones(mic_array, mic_count);
+ }
+
+ static int adev_dump(const struct audio_hw_device *dev, int fd) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ const struct legacy_audio_device *ladev = to_cladev(dev);
+ Vector<String16> args;
+
+ return ladev->hwif->dumpState(fd, args);
+ }
+
+ 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) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__, AUDIO_HAL_FUNCTION_CREATEPATCH_NS);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->createAudioPatch(num_sources, sources, num_sinks, sinks, handle);
+ }
+
+ static int adev_release_audio_patch(struct audio_hw_device *dev,
+ audio_patch_handle_t handle) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__, AUDIO_HAL_FUNCTION_CREATEPATCH_NS);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->releaseAudioPatch(handle);
+ }
+
+ static int adev_get_audio_port(struct audio_hw_device *dev,
+ struct audio_port *port) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->getAudioPort(port);
+ }
+
+ static int adev_set_audio_port_config(struct audio_hw_device *dev,
+ const struct audio_port_config *config) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->setAudioPortConfig(config);
+ }
+
+ static int adev_setup_parameters_callback(struct audio_hw_device *dev,
+ device_parameters_callback_t callback, void *cookie) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->setupParametersCallback(callback, cookie);
+ }
+
+ static int adev_set_audio_parameters_changed_callback(struct audio_hw_device *dev,
+ device_audio_parameter_changed_callback_t callback, void *cookie) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->setAudioParameterChangedCallback(callback, cookie);
+ }
+
+ static int adev_clear_audio_parameters_changed_callback(struct audio_hw_device *dev, void *cookie) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->clearAudioParameterChangedCallback(cookie);
+ }
+
+ static int legacy_adev_close(hw_device_t *device) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct audio_hw_device *hwdev =
+ reinterpret_cast<struct audio_hw_device *>(device);
+ struct legacy_audio_device *ladev = to_ladev(hwdev);
+
+ if (!ladev) {
+ return 0;
+ }
+
+ if (ladev->hwif) {
+ uint32_t tempcount;
+ pthread_mutex_lock(&gHwInstanceLock);
+ gAudioHALRefCountByClient--;
+ ALOGD("gAudioHALRefCountByClient - %d", gAudioHALRefCountByClient);
+ tempcount = gAudioHALRefCountByClient;
+ if (tempcount == 0) {
+ delete ladev->hwif;
+ }
+ ladev->hwif = NULL;
+ pthread_mutex_unlock(&gHwInstanceLock);
+ }
+
+ free(ladev);
+ return 0;
+ }
+
+ static int legacy_adev_open(const hw_module_t *module, const char *name,
+ hw_device_t **device) {
+#ifdef AUDIO_HAL_PROFILE_ENTRY_FUNCTION
+ char value[PROPERTY_VALUE_MAX];
+ property_get("vendor.audio.hal.callstack", value, "0");
+ AudioAutoTimeProfile::mDumpStack = atoi(value);
+ AudioAutoTimeProfile _p(__func__);
+#endif
+ struct legacy_audio_device *ladev;
+ int ret;
+
+ if (strncmp(name, AUDIO_HARDWARE_INTERFACE, strlen(AUDIO_HARDWARE_INTERFACE) + 1) != 0) {
+ return -EINVAL;
+ }
+
+ ladev = (struct legacy_audio_device *)calloc(1, sizeof(*ladev));
+ if (!ladev) {
+ return -ENOMEM;
+ }
+
+ ladev->device.common.tag = HARDWARE_DEVICE_TAG;
+#ifdef MTK_SUPPORT_AUDIO_DEVICE_API3
+ ladev->device.common.version = AUDIO_DEVICE_API_VERSION_3_0;
+#else
+ ladev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
+#endif
+ ladev->device.common.module = const_cast<hw_module_t *>(module);
+ ladev->device.common.close = legacy_adev_close;
+
+ ladev->device.get_supported_devices = adev_get_supported_devices;
+ ladev->device.init_check = adev_init_check;
+ ladev->device.set_voice_volume = adev_set_voice_volume;
+ ladev->device.set_master_volume = adev_set_master_volume;
+ ladev->device.get_master_volume = adev_get_master_volume;
+ ladev->device.set_mode = adev_set_mode;
+ ladev->device.set_mic_mute = adev_set_mic_mute;
+ ladev->device.get_mic_mute = adev_get_mic_mute;
+ ladev->device.set_parameters = adev_set_parameters;
+ ladev->device.get_parameters = adev_get_parameters;
+ ladev->device.get_input_buffer_size = adev_get_input_buffer_size;
+ ladev->device.open_output_stream = adev_open_output_stream;
+ ladev->device.close_output_stream = adev_close_output_stream;
+ ladev->device.open_input_stream = adev_open_input_stream;
+ ladev->device.close_input_stream = adev_close_input_stream;
+
+ ladev->device.get_microphones = adev_get_microphones;
+
+ ladev->device.dump = adev_dump;
+
+ ladev->device.create_audio_patch = adev_create_audio_patch;
+ ladev->device.release_audio_patch = adev_release_audio_patch;
+ ladev->device.get_audio_port = adev_get_audio_port;
+ ladev->device.set_audio_port_config = adev_set_audio_port_config;
+
+#if 0 // Don't use them from Android N
+ ladev->device.SetEMParameter = adev_set_emparameter;
+ ladev->device.GetEMParameter = adev_get_emparameter;
+ ladev->device.SetAudioCommand = adev_set_audiocommand;
+ ladev->device.GetAudioCommand = adev_get_audiocommand;
+ ladev->device.SetAudioData = adev_set_audiodata;
+ ladev->device.GetAudioData = adev_get_audiodata;
+
+ ladev->device.SetACFPreviewParameter = adev_set_acf_previewparameter;
+ ladev->device.SetHCFPreviewParameter = adev_set_hcf_previewparameter;
+#endif
+ ladev->device.xway_play_start = adev_xway_play_start;
+ ladev->device.xway_play_stop = adev_xway_play_stop;
+ ladev->device.xway_play_write = adev_xway_play_write;
+ ladev->device.xway_getfreebuffercount = adev_xway_getfreebuffercount;
+ ladev->device.xway_rec_start = adev_xway_rec_start;
+ ladev->device.xway_rec_stop = adev_xway_rec_stop;
+ ladev->device.xway_rec_read = adev_xway_rec_read;
+ //added by wendy
+ ladev->device.read_ref_from_ring = adev_read_ref_from_ring;
+ ladev->device.get_vow_ul_time = adev_get_vow_ul_time;
+ ladev->device.set_vow_src_sample_rate = adev_set_vow_src_sample_rate;
+ ladev->device.start_vow_dl = adev_start_vow_dl;
+ ladev->device.stop_vow_dl = adev_stop_vow_dl;
+ ladev->device.get_vow_dl_instance = adev_get_vow_dl_instance;
+ // added for HIDL extend
+ ladev->device.setup_parameters_callback = adev_setup_parameters_callback;
+ ladev->device.set_audio_parameter_changed_callback = adev_set_audio_parameters_changed_callback;
+ ladev->device.clear_audio_parameter_changed_callback = adev_clear_audio_parameters_changed_callback;
+
+ pthread_mutex_lock(&gHwInstanceLock);
+ ladev->hwif = createMTKAudioHardware();
+ if (!ladev->hwif) {
+ pthread_mutex_unlock(&gHwInstanceLock);
+ ret = -EIO;
+ free(ladev);
+ return ret;
+ } else {
+ gAudioHALRefCountByClient++;
+ ALOGD("gAudioHALRefCountByClient + %d", gAudioHALRefCountByClient);
+ pthread_mutex_unlock(&gHwInstanceLock);
+ }
+
+ *device = &ladev->device.common;
+
+ return 0;
+ }
+
+ static struct hw_module_methods_t legacy_audio_module_methods = {
+ .open = legacy_adev_open
+ };
+
+ struct legacy_audio_module HAL_MODULE_INFO_SYM = {
+ .module = {
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = AUDIO_HARDWARE_MODULE_ID,
+ .name = "MTK Audio HW HAL",
+ .author = "MTK",
+ .methods = &legacy_audio_module_methods,
+ .dso = NULL,
+ .reserved = {0},
+ },
+ },
+ };
+
+}; // extern "C"
+
+};
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioALSASpeechPhoneCallController.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioALSASpeechPhoneCallController.h
new file mode 100644
index 0000000..e282b08
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioALSASpeechPhoneCallController.h
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ALSA_SPEECH_PHONE_CALL_CONTROLLER_H
+#define ANDROID_AUDIO_ALSA_SPEECH_PHONE_CALL_CONTROLLER_H
+
+#include <tinyalsa/asoundlib.h>
+#include <media/AudioParameter.h>
+
+#include <AudioType.h>
+#include "SpeechType.h"
+
+#include <AudioLock.h>
+#include "AudioVolumeInterface.h"
+#include "SpeechDriverInterface.h"
+#include "AudioTypeExt.h"
+
+namespace android {
+
+class AudioALSAHardwareResourceManager;
+class AudioALSAStreamManager;
+class SpeechDriverFactory;
+class AudioBTCVSDControl;
+class AudioALSAVolumeController;
+
+
+
+class AudioALSASpeechPhoneCallController {
+public:
+ virtual ~AudioALSASpeechPhoneCallController();
+
+ static AudioALSASpeechPhoneCallController *getInstance();
+
+ virtual audio_devices_t getInputDeviceForPhoneCall(const audio_devices_t output_devices);
+
+ virtual status_t open(const audio_mode_t audio_mode,
+ const audio_devices_t output_devices,
+ const audio_devices_t input_device);
+ virtual status_t close();
+ virtual status_t routing(const audio_devices_t new_output_devices, const audio_devices_t new_input_device);
+ virtual audio_devices_t getAdjustedInputDevice();
+ virtual audio_devices_t getOutputDevice();
+
+ virtual bool checkSideToneFilterNeedOn(const audio_devices_t output_device) const;
+
+ /**
+ * TTY & RTT
+ */
+ virtual bool checkTtyNeedOn() const;
+ inline TtyModeType getTtyMode() const { return mTtyMode; }
+ virtual status_t setTtyMode(const TtyModeType ttMode);
+ virtual int setRttCallType(const int rttCallType);
+
+ inline unsigned int getSampleRate() const { return mConfig.rate; }
+
+ virtual void setVtNeedOn(const bool vt_on);
+ virtual void setMicMute(const bool mute_on);
+
+ virtual void setBTMode(const int mode);
+ virtual void setBtSpkDevice(const bool flag);
+ virtual void setDlMute(const bool mute_on);
+ virtual void setUlMute(const bool mute_on);
+ virtual void getRFInfo();
+ virtual status_t setParam(const String8 &keyParamPairs);
+ inline bool isAudioTaste() { return bAudioTaste; };
+ inline uint32_t getSpeechDVT_SampleRate() { return mSpeechDVT_SampleRate; }
+ inline uint32_t getSpeechDVT_MD_IDX() { return mSpeechDVT_MD_IDX; }
+
+ virtual void muteDlCodecForShutterSound(const bool mute_on);
+ virtual void updateVolume();
+ virtual bool checkReopen(const modem_index_t rilMappedMDIdx);
+ virtual int setPhoneId(const phone_id_t phoneId);
+
+ inline bool isModeInPhoneCall() {
+ return (mAudioMode == AUDIO_MODE_IN_CALL);
+ }
+ inline phone_id_t getPhoneId() { return mPhoneId; };
+ inline modem_index_t getIdxMDByPhoneId(uint8_t PhoneId) { return mIdxMDByPhoneId[PhoneId]; }
+ /**
+ * Speech Feature config
+ */
+ virtual int updateSpeechFeature(const SpeechFeatureType speechFeatureType, bool enable);
+ virtual bool getSpeechFeatureStatus(const SpeechFeatureType speechFeatureType);
+
+protected:
+ AudioALSASpeechPhoneCallController();
+
+ /**
+ * init audio hardware
+ */
+ virtual status_t init();
+
+ inline uint32_t calculateSampleRate(const bool bt_device_on) {
+#if defined(SPH_SR32K)
+ return (bt_device_on == false) ? 32000 : (mBTMode == 0) ? 8000 : 16000;
+#elif defined(SPH_SR48K)
+ return (bt_device_on == false) ? 48000 : (mBTMode == 0) ? 8000 : 16000;
+#else
+ return (bt_device_on == false) ? 16000 : (mBTMode == 0) ? 8000 : 16000;
+#endif
+ }
+ AudioALSAHardwareResourceManager *mHardwareResourceManager;
+ AudioALSAStreamManager *mStreamManager;
+ AudioVolumeInterface *mAudioALSAVolumeController;
+
+ SpeechDriverFactory *mSpeechDriverFactory;
+ AudioBTCVSDControl *mAudioBTCVSDControl;
+
+ AudioLock mLock;
+ AudioLock mCheckOpenLock;
+ audio_mode_t mAudioMode;
+ bool mMicMute;
+ bool mDlMute;
+ bool mUlMute;
+ bool mVtNeedOn;
+ bool bAudioTaste;
+ TtyModeType mTtyMode;
+ audio_devices_t mInputDevice;//original device
+ audio_devices_t mOutputDevice;//original device
+ audio_devices_t mAdjustedInDev;
+ audio_devices_t mAdjustedOutDev;
+ bool mIsBtSpkDevice;
+ int mBTMode; // BT mode, 0:NB, 1:WB
+ modem_index_t mIdxMD; // Modem Index, 0:MD1, 1:MD2, 2: MD3
+ struct pcm_config mConfig;
+ struct pcm *mPcmIn;
+ struct pcm *mPcmOut;
+ String8 mApTurnOnSequence;
+ String8 mApTurnOnSequence2;
+ uint16_t mRfInfo, mRfMode, mASRCNeedOn;
+ uint32_t mSpeechDVT_SampleRate;
+ uint32_t mSpeechDVT_MD_IDX;
+
+private:
+ static AudioALSASpeechPhoneCallController *mSpeechPhoneCallController; // singleton
+
+ modem_index_t updatePhysicalModemIdx(const audio_mode_t audio_mode);
+ void muteDlUlForRouting(const int muteCtrl);
+ virtual int setTtyInOutDevice();
+ virtual int adjustTtyInOutDevice();
+
+ bool mIsSidetoneEnable;
+ phone_id_t mPhoneId;
+ modem_index_t mIdxMDByPhoneId[NUM_PHONE_ID];
+
+ /*
+ * flag of dynamic enable verbose/debug log
+ */
+ int mLogEnable;
+
+ /**
+ * pmic reset(debug for bring up)
+ */
+ static void *pmicResetThread(void *arg);
+ pthread_t hPmicResetThread;
+ bool mIsPmicResetThreadEnable;
+ AudioLock mPmicResetLock;
+
+ /**
+ * DL Codec mute while shutter sound playback
+ */
+ static void *muteDlCodecForShutterSoundThread(void *arg);
+ pthread_t hMuteDlCodecForShutterSoundThread;
+ bool mMuteDlCodecForShutterSoundThreadEnable;
+
+ AudioLock mMuteDlCodecForShutterSoundLock;
+ uint32_t mMuteDlCodecForShutterSoundCount;
+ bool mIsMuteDlCodec;
+
+ /**
+ * DL/UL mute for routing
+ */
+ static void *muteDlUlForRoutingThread(void *arg);
+ pthread_t mMuteDlUlForRoutingThread;
+ bool mMuteDlUlForRoutingThreadEnable;
+ AudioLock mMuteDlUlForRoutingLock;
+ int mMuteDlUlForRoutingState;
+ int mMuteDlUlForRoutingCtrl;
+
+ /**
+ * RTT
+ */
+ int mRttCallType;
+ int mRttMode;
+
+ /**
+ * Super Volume
+ */
+ bool mSuperVolumeEnable;
+
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_ALSA_SPEECH_PHONE_CALL_CONTROLLER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioAssert.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioAssert.h
new file mode 100644
index 0000000..5271622
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioAssert.h
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_ASSERT_H
+#define ANDROID_AUDIO_ASSERT_H
+
+#include <string.h>
+
+#include <log/log.h>
+
+#ifdef ASSERT
+#undef ASSERT
+#endif
+
+#ifdef WARNING
+#undef WARNING
+#endif
+
+#ifdef ASSERT_OPT
+#undef ASSERT_OPT
+#endif
+
+#ifdef ASSERT_FT
+#undef ASSERT_FT
+#endif
+
+#ifdef WARNING_OPT
+#undef WARNING_OPT
+#endif
+
+#ifdef WARNING_FT
+#undef WARNING_FT
+#endif
+
+
+#ifdef HAVE_AEE_FEATURE
+#include <aee.h>
+#define audio_wrap_aee_exception(x...) aee_system_exception(x)
+#define audio_wrap_aee_warning(x...) aee_system_warning(x)
+#else
+#define audio_wrap_aee_exception(x...)
+#define audio_wrap_aee_warning(x...)
+#endif /* end of HAVE_AEE_FEATURE */
+
+
+#define ASSERT_OPT(exp, db_opt) \
+ do { \
+ if (!(exp)) { \
+ ALOGE("AUD_ASSERT("#exp") fail: \"" __FILE__ "\", %uL", __LINE__); \
+ audio_wrap_aee_exception("[Audio]", NULL, (db_opt), " %s, %uL", \
+ strrchr(__FILE__, '/') + 1, __LINE__); \
+ } \
+ } while(0)
+
+
+#define ASSERT(exp) ASSERT_OPT(exp, DB_OPT_DEFAULT)
+#define ASSERT_FT(exp) ASSERT_OPT(exp, DB_OPT_DEFAULT | DB_OPT_FTRACE)
+
+
+
+#define WARNING_OPT(string, db_opt) \
+ do { \
+ ALOGW("AUD_WARNING(" string"): \"" __FILE__ "\", %uL", __LINE__); \
+ audio_wrap_aee_warning("[Audio]", NULL, (db_opt), string"! %s, %uL", \
+ strrchr(__FILE__, '/') + 1, __LINE__); \
+ } while(0)
+
+
+#define WARNING(string) WARNING_OPT(string, DB_OPT_DEFAULT)
+#define WARNING_FT(string) WARNING_OPT(string, DB_OPT_DEFAULT | DB_OPT_FTRACE)
+
+
+
+#endif /* end of ANDROID_AUDIO_ASSERT_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioCustEncryptClient.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioCustEncryptClient.h
new file mode 100644
index 0000000..7ac14b5
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioCustEncryptClient.h
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+/*******************************************************************************
+ *
+ * Filename:
+ * ---------
+ * AudioCustEncryptClient.h
+ *
+ * Project:
+ * --------
+ * Android
+ *
+ * Description:
+ * ------------
+ * This file a client for AudioCustEncrypt
+ *
+ * Author:
+ * -------
+ * Tina Tsai
+ *
+ *******************************************************************************/
+#ifndef _AUDIO_CUST_ENCRYPT_CLIENT_H_
+#define _AUDIO_CUST_ENCRYPT_CLIENT_H_
+#include <dlfcn.h>
+#include "AudioUtility.h"
+#include <AudioLock.h>
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include "AudioCustEncrypt.h"
+
+namespace android {
+
+class AudioCustEncryptClient {
+public:
+ virtual ~AudioCustEncryptClient();
+
+ static AudioCustEncryptClient *GetInstance(void);
+
+ int (*Initial)(void);
+ int (*EncryptProcess)(char *TargetBuf, char *SourceBuf, uint16_t SourceByte);
+ int (*DecryptProcess)(char *TargetBuf, char *SourceBuf, uint16_t SourceByte);
+
+protected:
+ AudioCustEncryptClient();
+
+ AudioLock mMutex;
+
+private:
+ void Init(void);
+ void Deinit(void);
+ static AudioCustEncryptClient *mAudioCustEncryptClient; // singleton
+
+ void *handle;
+ short acpOpsInited;
+};
+
+}
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioCustParamClient.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioCustParamClient.h
new file mode 100644
index 0000000..b78d5dc
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioCustParamClient.h
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef _AUDIO_CUST_PARAM_CLIENT_H_
+#define _AUDIO_CUST_PARAM_CLIENT_H_
+#include <dlfcn.h>
+#include "AudioUtility.h"
+#include <AudioLock.h>
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include "AudioCustParam.h"
+
+namespace android {
+
+struct AudioDeviceParam {
+ int numMicSupport;
+};
+
+class AudioCustParamClient {
+public:
+ virtual ~AudioCustParamClient();
+
+ static AudioCustParamClient *GetInstance(void);
+
+
+ uint32_t (*QueryFeatureSupportInfo)(void);
+ // NB speech parameters
+ int (*GetNBSpeechParamFromNVRam)(AUDIO_CUSTOM_PARAM_STRUCT *pSphParamNB);
+ int (*SetNBSpeechParamToNVRam)(AUDIO_CUSTOM_PARAM_STRUCT *pSphParamNB);
+
+ // Dual mic speech parameters
+ int (*GetDualMicSpeechParamFromNVRam)(AUDIO_CUSTOM_EXTRA_PARAM_STRUCT *pSphParamDualMic);
+ int (*SetDualMicSpeechParamToNVRam)(AUDIO_CUSTOM_EXTRA_PARAM_STRUCT *pSphParamDualMic);
+
+ // WB speech parameters
+ int (*GetWBSpeechParamFromNVRam)(AUDIO_CUSTOM_WB_PARAM_STRUCT *pSphParamWB);
+ int (*SetWBSpeechParamToNVRam)(AUDIO_CUSTOM_WB_PARAM_STRUCT *pSphParamWB);
+
+ // Med param parameter
+ int (*GetMedParamFromNV)(AUDIO_PARAM_MED_STRUCT *pPara);
+ int (*SetMedParamToNV)(AUDIO_PARAM_MED_STRUCT *pPara);
+
+ // VolumeVer1 parameter
+ int (*GetVolumeVer1ParamFromNV)(AUDIO_VER1_CUSTOM_VOLUME_STRUCT *pPara);
+ int (*SetVolumeVer1ParamToNV)(AUDIO_VER1_CUSTOM_VOLUME_STRUCT *pPara);
+
+ // Audio Custom Paramete
+ int (*GetAudioCustomParamFromNV)(AUDIO_VOLUME_CUSTOM_STRUCT *pPara);
+ int (*SetAudioCustomParamToNV)(AUDIO_VOLUME_CUSTOM_STRUCT *pPara);
+
+ // AudioGainTable Parameter
+ int (*GetAudioGainTableParamFromNV)(AUDIO_GAIN_TABLE_STRUCT *pPara);
+ int (*SetAudioGainTableParamToNV)(AUDIO_GAIN_TABLE_STRUCT *pPara);
+
+ // Audio HD record parameters
+ int (*GetHdRecordParamFromNV)(AUDIO_HD_RECORD_PARAM_STRUCT *pPara);
+ int (*SetHdRecordParamToNV)(AUDIO_HD_RECORD_PARAM_STRUCT *pPara);
+
+ // Audio HD record scene table
+ int (*GetHdRecordSceneTableFromNV)(AUDIO_HD_RECORD_SCENE_TABLE_STRUCT *pPara);
+ int (*SetHdRecordSceneTableToNV)(AUDIO_HD_RECORD_SCENE_TABLE_STRUCT *pPara);
+
+ // Audio VoIP Parameters
+ int (*GetAudioVoIPParamFromNV)(AUDIO_VOIP_PARAM_STRUCT *pPara);
+ int (*SetAudioVoIPParamToNV)(AUDIO_VOIP_PARAM_STRUCT *pPara);
+
+ // Audio HFP Parameters
+ int (*GetAudioHFPParamFromNV)(AUDIO_HFP_PARAM_STRUCT *pPara);
+ int (*SetAudioHFPParamToNV)(AUDIO_HFP_PARAM_STRUCT *pPara);
+
+ // MagiConference Call parameters
+ int (*GetMagiConSpeechParamFromNVRam)(AUDIO_CUSTOM_MAGI_CONFERENCE_STRUCT *pSphParamMagiCon);
+ int (*SetMagiConSpeechParamToNVRam)(AUDIO_CUSTOM_MAGI_CONFERENCE_STRUCT *pSphParamMagiCon);
+
+ // HAC parameters
+ int (*GetHACSpeechParamFromNVRam)(AUDIO_CUSTOM_HAC_PARAM_STRUCT *pSphParamHAC);
+ int (*SetHACSpeechParamToNVRam)(AUDIO_CUSTOM_HAC_PARAM_STRUCT *pSphParamHAC);
+
+ // Speech Loopback parameters
+ int (*GetNBSpeechLpbkParamFromNVRam)(AUDIO_CUSTOM_SPEECH_LPBK_PARAM_STRUCT *pSphParamNBLpbk);
+ int (*SetNBSpeechLpbkParamToNVRam)(AUDIO_CUSTOM_SPEECH_LPBK_PARAM_STRUCT *pSphParamNBLpbk);
+
+ // BT Gain parameter
+ int (*GetAudioBTGainParamFromNV)(AUDIO_BT_GAIN_STRUCT *pParaBT);
+ int (*SetAudioBTGainParamToNV)(AUDIO_BT_GAIN_STRUCT *pParaBT);
+
+ // param query
+ int getNumMicSupport(void);
+
+protected:
+ AudioCustParamClient();
+
+ AudioLock mMutex;
+
+private:
+ void init(void);
+ void deinit(void);
+
+ void initParam(void);
+ static AudioCustParamClient *mAudioCustParamClient; // singleton
+
+ void *handle;
+ short acpOpsInited;
+
+ // param
+ struct AudioDeviceParam mDeviceParam;
+
+ // param function pointer
+ int (*mGetNumMicSupport)(void);
+};
+
+}
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioDef.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioDef.h
new file mode 100644
index 0000000..6bf2051
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioDef.h
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIODEF_H
+#define ANDROID_AUDIODEF_H
+
+// define this to enalbe pc emualtoe
+//#define PC_EMULATION
+
+#define ENABLE_LOG_HARDWARE
+#define ENABLE_LOG_STREAMOUT
+#define ENABLE_LOG_STREAMIN
+#define ENABLE_LOG_VOLUMECONTROLLER
+#define ENABLE_LOG_RESOURCEMANAGER
+#define ENABLE_LOG_ANA
+#define ENABLE_LOG_AFE
+#define ENABLE_LOG_AUDIOFLINGER
+#define ENABLE_LOG_SPEECHCONTROL
+
+#define ENABLE_LOG_AUDIOPOLICYSERVICE
+#define ENABLE_LOG_AUDIOPOLICYANAGER
+#define ENABLE_LOG_A2DPINTERFACE
+#define ENABLE_LOG_AUDIO_MIXER
+#define ENABLE_LOG_I2S
+#define ENABLE_LOG_I2SSTREAMIN
+
+#endif
\ No newline at end of file
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioDspStreamManager.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioDspStreamManager.h
new file mode 100644
index 0000000..924a89b
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioDspStreamManager.h
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_DSP_STREAM_MANAGER_H
+#define ANDROID_AUDIO_DSP_STREAM_MANAGER_H
+
+#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+#ifdef MTK_BASIC_PACKAGE
+#include "AudioTypeExt.h"
+#endif
+
+#include <hardware_legacy/AudioMTKHardwareInterface.h>
+
+#include <tinyalsa/asoundlib.h>
+#include "AudioType.h"
+#include "AudioLock.h"
+#include "AudioPolicyParameters.h"
+#include "AudioDspType.h"
+
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+struct aurisys_lib_manager_t;
+struct aurisys_dsp_config_t;
+struct aurisys_gain_config_t;
+#endif
+
+
+namespace android {
+
+class AudioALSAPlaybackHandlerBase;
+class AudioALSACaptureHandlerBase;
+class AudioMessengerIPI;
+
+class AudioDspStreamManager {
+public:
+ virtual ~AudioDspStreamManager();
+ static AudioDspStreamManager *getInstance();
+
+ int addPlaybackHandler(AudioALSAPlaybackHandlerBase *playbackHandler);
+ int removePlaybackHandler(AudioALSAPlaybackHandlerBase *playbackHandler);
+
+ int addCaptureHandler(AudioALSACaptureHandlerBase *captureHandler);
+ int removeCaptureHandler(AudioALSACaptureHandlerBase *captureHandler);
+
+ int dumpPlaybackHandler(void);
+ int dumpCaptureHandler(void);
+
+ unsigned int getUlLatency(void);
+ unsigned int getDlLatency(void);
+ unsigned int getA2dpPcmLatency(void);
+ bool getDspTaskPlaybackStatus(void);
+ bool getDspTaskA2DPStatus(void);
+ int setAfeInDspShareMem(bool condition);
+ int setAfeOutDspShareMem(unsigned int flag, bool condition);
+ int setStreamInState(bool condition);
+ int setStreamOutState(unsigned int flag, bool condition);
+
+ /* get audio dsp support stream */
+ int getDspOutHandlerEnable(unsigned int flag);
+ int getDspInHandlerEnable(unsigned int flag);
+ int getDspPlaybackEnable(void);
+ int getDspA2DPEnable(void);
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ void CreateAurisysLibManager(
+ struct aurisys_lib_manager_t **manager,
+ struct aurisys_dsp_config_t **config,
+ const uint8_t task_scene,
+ const uint32_t aurisys_scenario,
+ const uint8_t arsi_process_type,
+ const uint32_t audio_mode,
+ const struct stream_attribute_t *attribute_in,
+ const struct stream_attribute_t *attribute_out,
+ const struct stream_attribute_t *attribute_ref,
+ const struct aurisys_gain_config_t *gain_config);
+ void DestroyAurisysLibManager(
+ struct aurisys_lib_manager_t **manager,
+ struct aurisys_dsp_config_t **config,
+ const uint8_t task_scene);
+#endif
+
+
+private:
+ /**
+ * singleton pattern
+ */
+ AudioDspStreamManager();
+ static AudioDspStreamManager *mDspStreamManager;
+ AudioMessengerIPI *mAudioMessengerIPI;
+
+ /*
+ * function to set pcm config and open pcmDumpThreadCreated
+ */
+ int checkPlaybackStatus(void);
+ int startPlaybackTask(AudioALSAPlaybackHandlerBase *playbackHandler);
+ int stopPlaybackTask(void);
+ int triggerDsp(unsigned int task_scene, int data_type);
+
+ bool dataPasstoDsp(AudioALSAPlaybackHandlerBase *Base);
+
+ int setAfeDspShareMem(bool condition);
+ int doRecoveryState();
+ int setStreamState(bool condition);
+ int setDspRuntimeEn(bool condition);
+ int setDspA2DPRuntimeEn(bool condition);
+ int setA2DPStreamState(bool condition);
+ int setA2dpDspShareMem(bool condition);
+
+ int checkA2DPTaskStatus(void);
+ bool dataPasstoA2DPTask(AudioALSAPlaybackHandlerBase *Base);
+ int startA2DPTask(AudioALSAPlaybackHandlerBase *Base);
+ int stopA2DPTask(AudioALSAPlaybackHandlerBase *Base);
+ void startDSPTaskUL(void);
+ void stopDSPTaskUL(void);
+ void openPCMDumpA2DP(AudioALSAPlaybackHandlerBase *playbackHandler);
+ void closePCMDumpA2DP(AudioALSAPlaybackHandlerBase *playbackHandler);
+
+ int mDspA2DPStreamState;
+ int mDspA2DPIndex;
+ int mDspDataProviderIndex;
+ struct pcm *mDspA2DPPcm;
+ struct pcm *mDspDataProviderPcm;
+ bool mDspTaskA2DPActive;
+
+ /**
+ * stream manager lock
+ */
+ AudioLock mLock;
+
+ /**
+ * stream playback/capture handler vector
+ */
+ KeyedVector<unsigned long long, AudioALSAPlaybackHandlerBase *> mPlaybackHandlerVector;
+ KeyedVector<unsigned long long, AudioALSACaptureHandlerBase *> mCaptureHandlerVector;
+
+ /*
+ * pcm for capture pcm and playback pcmDumpThreadCreated
+ */
+ struct pcm_config mPlaybackUlConfig;
+ struct pcm *mPlaybackUlPcm;
+ int mPlaybackUlindex;
+ struct pcm_config mPlaybackDlConfig;
+ struct pcm *mPlaybackDlPcm;
+ int mPlaybackDlindex;
+ struct pcm_config mDspConfig;
+ struct pcm *mDspPcm;
+ int mDspIndex;
+ bool mDspTaskPlaybackActive;
+ unsigned int multiplier;
+
+ /* dsp stream state */
+ int mDspStreamState;
+ int mStreamCardIndex;
+
+ /* dsp ap interconnection to device */
+ String8 mApTurnOnSequence;
+ String8 mApTurnOnSequence2;
+
+ /* Mixer*/
+ struct mixer *mMixer;
+
+ // a2dp pcm dump
+ FILE *mPCMDumpFileDSP;
+ uint32_t mDumpFileNumDSP;
+
+#ifdef MTK_AURISYS_FRAMEWORK_SUPPORT
+ struct aurisys_lib_manager_t *mAurisysLibManagerPlayback;
+ struct aurisys_dsp_config_t *mAurisysDspConfigPlayback;
+#endif
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_AUDIO_DSP_STREAM_MANAGER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioEventThreadManager.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioEventThreadManager.h
new file mode 100644
index 0000000..94e37cd
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioEventThreadManager.h
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_EVENT_THREAD_MANAGER_H
+#define AUDIO_EVENT_THREAD_MANAGER_H
+
+#include <vector>
+#include <pthread.h>
+#include <AudioLock.h>
+
+namespace android {
+
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+enum AudioEventType {
+ AUDIO_EVENT_PHONECALL_REOPEN,
+ AUDIO_EVENT_SPEECH_PARAM_CHANGE,
+ AUDIO_EVENT_ECALL_INDICATION,
+ AUDIO_EVENT_ECALL_RX,
+ NUM_AUDIO_EVENT_PHONE
+};
+
+/**
+ * callback function prototype
+ */
+typedef void(*CallbackFunc)(int, void *, void *);
+
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+class AudioEventThread;
+
+/*
+ * =============================================================================
+ * public function
+ * =============================================================================
+ */
+
+class AudioEventThreadManager {
+public:
+ /**
+ * get instance's pointer
+ */
+ static AudioEventThreadManager *getInstance();
+
+ int registerCallback(AudioEventType audioEventType, CallbackFunc callbackFunc, void *regArg);
+ int unregisterCallback(AudioEventType audioEventType, CallbackFunc callbackFunc, void *regArg);
+ int unregisterCallback(AudioEventType audioEventType);
+ int notifyCallback(AudioEventType audioEventType, void *arg);
+
+private:
+ AudioEventThreadManager() {};
+ virtual ~AudioEventThreadManager();
+ /**
+ * singleton pattern
+ */
+ static AudioEventThreadManager *uniqueAudioEventThreadManager;
+
+ std::vector<AudioEventThread *> mEventThreads;
+ AudioEventThread *getAudioEventThread(AudioEventType audioEventType);
+ bool hasAudioEventThread(AudioEventType audioEventType);
+};
+
+
+
+} /* end of namespace android */
+
+#endif /* end of AUDIO_EVENT_THREAD_MANAGER_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioFtmBase.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioFtmBase.h
new file mode 100644
index 0000000..cf873f6
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioFtmBase.h
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_FTM_BASE_H
+#define ANDROID_AUDIO_FTM_BASE_H
+
+#include <sys/types.h>
+
+namespace android {
+
+enum FMTX_Command {
+ FREQ_NONE = 0,
+ FREQ_1K_HZ,
+ FREQ_2K_HZ,
+ FREQ_3K_HZ,
+ FREQ_4K_HZ,
+ FREQ_5K_HZ,
+ FREQ_6K_HZ,
+ FREQ_7K_HZ,
+ FREQ_8K_HZ,
+ FREQ_9K_HZ,
+ FREQ_10K_HZ,
+ FREQ_11K_HZ,
+ FREQ_12K_HZ,
+ FREQ_13K_HZ,
+ FREQ_14K_HZ,
+ FREQ_15K_HZ
+};
+
+
+enum UL_SAMPLERATE_INDEX {
+ UPLINK8K = 0,
+ UPLINK16K,
+ UPLINK32K,
+ UPLINK48K,
+ UPLINK_UNDEF
+};
+
+enum select_mic_type {
+ SELECT_MIC_DEFAULT,
+ SELECT_MIC1,
+ SELECT_MIC2,
+ SELECT_MIC3,
+ SELECT_MIC4,
+ SELECT_MIC5,
+ SELECT_MIC_TYPE_MAX,
+};
+
+// for afe loopback
+#define MIC1_OFF 0
+#define MIC1_ON 1
+#define MIC2_OFF 2
+#define MIC2_ON 3
+#define MIC3_OFF 4
+#define MIC3_ON 5
+#define MIC4_OFF 6
+#define MIC4_ON 7
+
+
+// for acoustic loopback
+#define ACOUSTIC_STATUS -1
+#define DUAL_MIC_WITHOUT_DMNR_ACS_OFF 0
+#define DUAL_MIC_WITHOUT_DMNR_ACS_ON 1
+#define DUAL_MIC_WITH_DMNR_ACS_OFF 2
+#define DUAL_MIC_WITH_DMNR_ACS_ON 3
+
+
+class AudioFtmBaseVirtual {
+public:
+ virtual ~AudioFtmBaseVirtual() {};
+ /// Codec
+ virtual void Audio_Set_Speaker_Vol(int level) = 0;
+ virtual void Audio_Set_Speaker_On(int Channel) = 0;
+ virtual void Audio_Set_Speaker_Off(int Channel) = 0;
+ virtual void Audio_Set_HeadPhone_On(int Channel) = 0;
+ virtual void Audio_Set_HeadPhone_Off(int Channel) = 0;
+ virtual void Audio_Set_Earpiece_On() = 0;
+ virtual void Audio_Set_Earpiece_Off() = 0;
+
+
+ /// for factory mode & Meta mode (Analog part)
+ virtual void FTM_AnaLpk_on(void) = 0;
+ virtual void FTM_AnaLpk_off(void) = 0;
+
+ virtual int SineGenTest(char sinegen_test) = 0;
+
+ /// Output device test
+ virtual int RecieverTest(char receiver_test) = 0;
+ virtual int LouderSPKTest(char left_channel, char right_channel) = 0;
+ virtual int EarphoneTest(char bEnable) = 0;
+ virtual int EarphoneTestLR(char bLR) = 0;
+
+ /// Input device test
+ virtual int SpecificBuildInMicTest(char type) = 0;
+
+ /// Speaker over current test
+ virtual int Audio_READ_SPK_OC_STA(void) = 0;
+ virtual int LouderSPKOCTest(char left_channel, char right_channel) = 0;
+
+
+ /// Loopback // TODO: Add in platform!!!
+ virtual int PhoneMic_Receiver_Loopback(char echoflag) = 0;
+ virtual int PhoneMic_EarphoneLR_Loopback(char echoflag) = 0;
+ virtual int PhoneMic_SpkLR_Loopback(char echoflag) = 0;
+ virtual int HeadsetMic_EarphoneLR_Loopback(char bEnable, char bHeadsetMic) = 0;
+ virtual int HeadsetMic_SpkLR_Loopback(char echoflag) = 0;
+ virtual int HeadsetMic_Receiver_Loopback(char bEnable, char bHeadsetMic) = 0;
+
+ virtual int PhoneMic_Receiver_Acoustic_Loopback(int Acoustic_Type, int *Acoustic_Status_Flag, int bHeadset_Output) = 0;
+
+
+ /// FM / mATV
+ virtual int FMLoopbackTest(char bEnable) = 0;
+
+ virtual int Audio_FM_I2S_Play(char bEnable) = 0;
+ virtual int Audio_MATV_I2S_Play(int enable_flag) = 0;
+ virtual int Audio_FMTX_Play(bool Enable, unsigned int Freq) = 0;
+
+ virtual int ATV_AudPlay_On(void) = 0;
+ virtual int ATV_AudPlay_Off(void) = 0;
+ virtual unsigned int ATV_AudioWrite(void *buffer, unsigned int bytes) = 0;
+
+
+ /// HDMI
+ virtual int HDMI_SineGenPlayback(bool bEnable, int dSamplingRate) = 0;
+
+
+ /// Vibration Speaker // MTK_VIBSPK_SUPPORT??
+ virtual int SetVibSpkCalibrationParam(void *cali_param) = 0;
+ virtual uint32_t GetVibSpkCalibrationStatus() = 0;
+ virtual void SetVibSpkEnable(bool enable, uint32_t freq) = 0;
+ virtual void SetVibSpkRampControl(uint8_t rampcontrol) = 0;
+
+ virtual bool ReadAuxadcData(int channel, int *value) = 0;
+ virtual void SetStreamOutPostProcessBypass(bool flag) = 0;
+
+ // speaker calibration for SmartPa
+ virtual bool SpeakerCalibration(int calibStage) = 0;
+};
+
+
+class AudioFtmBase: public AudioFtmBaseVirtual {
+public:
+ virtual ~AudioFtmBase();
+ static AudioFtmBase *createAudioFtmInstance();
+
+ /// Codec
+ virtual void Audio_Set_Speaker_Vol(int level);
+ virtual void Audio_Set_Speaker_On(int Channel);
+ virtual void Audio_Set_Speaker_Off(int Channel);
+ virtual void Audio_Set_HeadPhone_On(int Channel);
+ virtual void Audio_Set_HeadPhone_Off(int Channel);
+ virtual void Audio_Set_Earpiece_On();
+ virtual void Audio_Set_Earpiece_Off();
+
+
+ /// for factory mode & Meta mode (Analog part)
+ virtual void FTM_AnaLpk_on(void);
+ virtual void FTM_AnaLpk_off(void);
+
+
+ virtual int SineGenTest(char sinegen_test);
+
+ /// Output device test
+ virtual int RecieverTest(char receiver_test);
+ virtual int LouderSPKTest(char left_channel, char right_channel);
+ virtual int EarphoneTest(char bEnable);
+ virtual int EarphoneTestLR(char bLR);
+
+ /// Input device test
+ virtual int SpecificBuildInMicTest(char type);
+
+ /// Speaker over current test
+ virtual int Audio_READ_SPK_OC_STA(void);
+ virtual int LouderSPKOCTest(char left_channel, char right_channel);
+
+
+ /// Loopback // TODO: Add in platform!!!
+ virtual int PhoneMic_Receiver_Loopback(char echoflag);
+ virtual int PhoneMic_EarphoneLR_Loopback(char echoflag);
+ virtual int PhoneMic_SpkLR_Loopback(char echoflag);
+ virtual int HeadsetMic_EarphoneLR_Loopback(char bEnable, char bHeadsetMic);
+ virtual int HeadsetMic_SpkLR_Loopback(char echoflag);
+ virtual int HeadsetMic_Receiver_Loopback(char bEnable, char bHeadsetMic);
+
+ virtual int PhoneMic_Receiver_Acoustic_Loopback(int Acoustic_Type, int *Acoustic_Status_Flag, int bHeadset_Output);
+
+
+ /// FM / mATV
+ virtual int FMLoopbackTest(char bEnable);
+
+ virtual int Audio_FM_I2S_Play(char bEnable);
+ virtual int Audio_MATV_I2S_Play(int enable_flag);
+ virtual int Audio_FMTX_Play(bool Enable, unsigned int Freq);
+
+ virtual int ATV_AudPlay_On(void);
+ virtual int ATV_AudPlay_Off(void);
+ virtual unsigned int ATV_AudioWrite(void *buffer, unsigned int bytes);
+
+
+ /// HDMI
+ virtual int HDMI_SineGenPlayback(bool bEnable, int dSamplingRate);
+
+
+ /// Vibration Speaker // MTK_VIBSPK_SUPPORT??
+ virtual int SetVibSpkCalibrationParam(void *cali_param);
+ virtual uint32_t GetVibSpkCalibrationStatus();
+ virtual void SetVibSpkEnable(bool enable, uint32_t freq);
+ virtual void SetVibSpkRampControl(uint8_t rampcontrol);
+
+ virtual bool ReadAuxadcData(int channel, int *value);
+ virtual void SetStreamOutPostProcessBypass(bool flag);
+
+ // speaker calibration for SmartPa
+ virtual bool SpeakerCalibration(int calibStage);
+
+protected:
+ AudioFtmBase();
+
+};
+
+}; // end namespace android
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+android::AudioFtmBaseVirtual *pfuncGetAudioFtmByDL(void);
+#ifdef __cplusplus
+}
+#endif
+
+typedef android::AudioFtmBaseVirtual *create_AudioFtm(void);
+
+#endif // end of ANDROID_AUDIO_FTM_BASE_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioMTKDec.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioMTKDec.h
new file mode 100644
index 0000000..ea0287f
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioMTKDec.h
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_MTK_DEC_H
+#define AUDIO_MTK_DEC_H
+
+#include <sys/types.h>
+#include "mp3dec_exp.h"
+#include "AudioType.h"
+#include <AudioLock.h>
+
+#ifndef uint32_t
+typedef unsigned int uint32;
+#endif
+
+
+namespace android {
+
+
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define MP3_SYNC 0xe0ff
+
+const int mp3_sample_rates[3][3] = {
+ {44100, 48000, 32000}, /* MPEG-1 */
+ {22050, 24000, 16000}, /* MPEG-2 */
+ {11025, 12000, 8000}, /* MPEG-2.5 */
+};
+
+const int mp3_bit_rates[3][3][15] = {
+ {
+ /* MPEG-1 */
+ { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448}, /* Layer 1 */
+ { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384}, /* Layer 2 */
+ { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320}, /* Layer 3 */
+ },
+ {
+ /* MPEG-2 */
+ { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256}, /* Layer 1 */
+ { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}, /* Layer 2 */
+ { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}, /* Layer 3 */
+ },
+ {
+ /* MPEG-2.5 */
+ { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256}, /* Layer 1 */
+ { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}, /* Layer 2 */
+ { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}, /* Layer 3 */
+ },
+};
+
+enum mpeg_version {
+ MPEG1 = 0,
+ MPEG2 = 1,
+ MPEG25 = 2
+};
+
+enum mp3_stereo_mode {
+ STEREO = 0x00,
+ JOINT = 0x01,
+ DUAL = 0x02,
+ MONO = 0x03
+};
+
+#if defined(__cplusplus)
+}
+#endif
+
+
+typedef struct {
+Mp3dec_handle *handle;
+int32_t workingbuf_size1;
+int32_t workingbuf_size2;
+int32_t min_bs_size;
+int32_t pcm_size;
+void *working_buf1;
+void *working_buf2;
+void *pcm_buf;
+} mp3DecEngine;
+
+typedef struct mp3_header {
+uint16_t sync;
+uint8_t format1;
+uint8_t format2;
+};
+
+class AudioMTKDecHandlerBase {
+public:
+AudioMTKDecHandlerBase();
+virtual ~AudioMTKDecHandlerBase() = 0;
+
+virtual bool InitAudioDecoder() = 0;
+virtual void DeinitAudioDecoder() = 0;
+virtual int32_t ParseAudioHeader(int8_t *inputBsbuf) = 0;
+virtual int32_t DecodeAudio(int8_t *inputBsbuf, int8_t *outputPcmbuf, int32_t BsbufSize) = 0;
+virtual int32_t PcmbufferSize() = 0;
+virtual int32_t BsbufferSize() = 0;
+};
+
+
+#define MTK_OUTPUT_BUFFER_SIZE_MP3 4608
+
+
+class AudioMTKDecHandlerMP3 : public AudioMTKDecHandlerBase {
+public:
+AudioMTKDecHandlerMP3();
+~AudioMTKDecHandlerMP3();
+virtual bool InitAudioDecoder();
+virtual void DeinitAudioDecoder();
+virtual int32_t ParseAudioHeader(int8_t *inputBsbuf);
+virtual int32_t DecodeAudio(int8_t *inputBsbuf, int8_t *outputPcmbuf, int32_t BsbufSize);
+virtual int32_t PcmbufferSize();
+virtual int32_t BsbufferSize();
+
+
+private:
+mp3DecEngine *mMp3Dec;
+uint32_t mBitRate;
+uint32_t mChannel;
+bool mMp3InitFlag;
+uint32_t mSampleRate;
+int32_t mBSBuffSize;
+uint32_t mBufferLength;
+bool mEndFlag;
+bool mIsEndOfStream;
+};
+
+}
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioMTKFilter.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioMTKFilter.h
new file mode 100644
index 0000000..fda46b2
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioMTKFilter.h
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_MTK_FILTER_PROCESS_H
+#define AUDIO_MTK_FILTER_PROCESS_H
+
+#include <sys/types.h>
+
+#include "MtkAudioComponent.h"
+//#if defined(MTK_VIBSPK_SUPPORT)
+#include "AudioCompFltCustParam.h"
+#include "AudioVIBSPKControl.h"
+//#endif
+
+#ifndef uint32_t
+typedef unsigned int uint32;
+#endif
+
+
+namespace android {
+
+class AudioMTKFilter {
+public:
+ AudioMTKFilter(AudioCompFltType_t type,
+ AudioComFltMode_t mode,
+ uint32_t sampleRate,
+ uint32_t channel,
+ uint32_t format,
+ size_t bufferSize);
+ ~AudioMTKFilter();
+ void start(bool bFirstDataWrite = false);;
+ void stop();
+ void pause();
+ void resume();
+ bool isStart();
+ bool isActive();
+ void setParameter(void *param);
+ uint32_t process(void *inBuffer, uint32_t bytes, void *outBuffer, uint32_t outBytes = 0);
+ void setParameter2Sub(void *param);
+ void setOutputGain(int32_t gain, uint32_t ramp_sample_cnt);
+ void setFilterParam(unsigned int fc, unsigned int bw, int th);
+ status_t init();
+ bool bIsZeroCoeff;
+private:
+ AudioMTKFilter(const AudioMTKFilter &);
+ AudioMTKFilter &operator=(const AudioMTKFilter &);
+ AudioCompFltType_t mType;
+ AudioComFltMode_t mMode;
+ uint32_t mSampleTate;
+ uint32_t mChannel;
+ uint32_t mFormat;
+ size_t mBufferSize;
+ MtkAudioLoudBase *mFilter;
+ bool mStart;
+ bool mActive;
+ mutable Mutex mLock;
+};
+
+class AudioMTKFilter_VibSpkAddTone {
+public:
+ AudioMTKFilter_VibSpkAddTone(uint32_t sampleRate,
+ uint32_t channel,
+ uint32_t format,
+ size_t bufferSize);
+ status_t init();
+ ~AudioMTKFilter_VibSpkAddTone();
+ size_t DoVibSignal2DLProcess(void *outbuffer, void *src2DLbuffer, size_t bytes);
+private:
+ void deinit();
+ MtkAudioBitConverterBase *mShifter_to_1_31_VIBSPK;
+ AudioVIBSPKControl *mVibSpk;
+ uint32_t mVibSpkFreq;
+ bool mVibSpkEnable;
+ uint8_t *mVIBSPKToneBuffer;//always 16bit
+ uint8_t *mVIBSPKToneWorkBuffer;
+ uint32_t mChannels;
+ uint32_t mSampleRate;
+ uint32_t mFormat;
+ size_t mBufferSize;
+};
+
+class AudioMTKFilterManager {
+public:
+ AudioMTKFilterManager(uint32_t sampleRate,
+ uint32_t channel,
+ uint32_t format,
+ size_t bufferSize);
+ ~AudioMTKFilterManager();
+ void start(bool bFirstDataWrite = false);
+ void stop();
+ bool isParamFixed();
+ void setDevice(uint32_t devices);
+ void setParamFixed(bool flag);
+ void setParameter(uint32_t type, void *param);
+ bool isFilterStart(uint32_t type);
+ uint32_t process(void *inBuffer, uint32_t bytes, void *outBuffer, uint32_t outBytes = 0);
+ void setSpkOutputGain(int32_t gain, uint32_t ramp_sample_cnt);
+ void setSpkFilterParam(unsigned int fc, unsigned int bw, int th);
+ status_t init(uint32_t flags = 0);
+private:
+ AudioMTKFilterManager(const AudioMTKFilterManager &);
+ AudioMTKFilterManager &operator=(const AudioMTKFilterManager &);
+ void deinit();
+ uint32_t mSamplerate;
+ uint32_t mChannel;
+ uint32_t mFormat;
+ size_t mBufferSize;
+ bool mFixedParam;
+ AudioMTKFilter *mSpeakerFilter;
+ AudioMTKFilter *mHeadphoneFilter;
+ AudioMTKFilter *mEnhanceFilter;
+ //#if defined(MTK_VIBSPK_SUPPORT)
+ AudioMTKFilter *mVIBSPKFilter;
+ AudioMTKFilter_VibSpkAddTone *mVibspkAddToneFilter;
+ //#endif
+ uint8_t *mBuffer;
+ uint32_t mDevices;
+};
+
+}
+
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioMTKHardwareCommand.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioMTKHardwareCommand.h
new file mode 100644
index 0000000..fb72b5d
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioMTKHardwareCommand.h
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_MTK_HARDWARE_COMMAND_H
+#define ANDROID_AUDIO_MTK_HARDWARE_COMMAND_H
+
+enum AudioCommand {
+ AUDIOCOMMAND_NONE = 0,
+ OUTPUTFIRINDEX = 0x1,
+ MEDDATA = 0x3,
+ GETAUDIOCUSTOMDATASIZE = 0x5,
+ AUDIOCUSTOMDATA = 0x6,
+ VOIP_PARAMETER = 0x7,
+ HFP_PARAMETER = 0x8,
+ HD_RECORD_PARAMETER = 0x9,
+ HD_RECORD_SCENE_TABLE = 0xA,
+
+ // use for MED output FIR
+ NORMALOUTPUTFIRINDEX = 0x20,
+ HEADSETOUTPUTFIRINDEX = 0x21,
+ SPEAKEROUTPUTFIRINDEX = 0x22,
+
+ DUAL_MIC_PARAMETER = 0x31,
+
+ WB_SPEECH_PARAMETER = 0x41,
+ NB_SPEECH_LPBK_PARAMETER = 0x42,
+ NB_SPEECH_PARAMETER = 0x43,
+
+ LOAD_VOLUME_SETTING = 0x50,
+ DUMP_AUDIO_AEE_CHECK = 0x5E,
+ // used for Speech Logger
+ SPEECH_VM_ENABLE = 0x60,
+ // used for Audio Logger
+ DUMP_AUDIO_DEBUG_INFO = 0x62,
+ DUMP_AUDIO_STREAM_OUT = 0x63,
+ DUMP_AUDIO_MIXER_BUF = 0x65,
+ DUMP_AUDIO_TRACK_BUF = 0x67,
+ DUMP_A2DP_STREAM_OUT = 0x69,
+ DUMP_AUDIO_STREAM_IN = 0x6B,
+ DUMP_IDLE_VM_RECORD = 0x6D,
+ // for audio taste tool
+ AUD_TASTE_TUNING = 0x70,
+ HOOK_FM_DEVICE_CALLBACK = 0x71,
+ UNHOOK_FM_DEVICE_CALLBACK = 0x72,
+ HOOK_BESLOUDNESS_CONTROL_CALLBACK = 0x73,
+ UNHOOK_BESLOUDNESS_CONTROL_CALLBACK = 0x74,
+ //AP side Speech logger
+ DUMP_AP_SPEECH_EPL = 0xA0,
+ MagiASR_TEST_ENABLE = 0xA2,
+ AECREC_TEST_ENABLE = 0xA4,
+ SPEECH_MAGICON_PARAMETER = 0xC1,
+ SPEECH_HAC_PARAMETER = 0xD1,
+
+ // volume
+ AUDIO_VER1_DATA = 0x101,
+ GET_AUDIO_POLICY_VOL_FROM_VER1_DATA = 0x102,
+ GET_AUDIO_SCENE_GAIN_TABLE = 0x103,
+ GET_AUDIO_NON_SCENE_GAIN_TABLE = 0x104,
+ // used for voice ui and unlock
+ VOICE_RECOG_CUST_PARAM = 0x200,
+ VOICE_RECOG_FIR_COEF = 0x201,
+ VOICE_RECOG_GAIN = 0x202,
+
+ // used for vibration spk calibration
+ CURRENT_SENSOR_ENABLE = 0x210,
+ CURRENT_SENSOR_RESET = 0x211,
+
+ // used for spk monitor temperature control
+ SPEAKER_MONITOR_TEMP_UPPER_BOUND = 0x220,
+ SPEAKER_MONITOR_TEMP_LOWER_BOUND = 0x221,
+
+ // used for drc parameters
+ AUDIO_DRC_MUSIC_PARAMETER = 0x230,
+ AUDIO_DRC_RINGTONE_PARAMETER = 0x231,
+
+ GET_TC1_DISP = 0x500,
+ GET_BT_NREC_DISP = 0x501,
+ TEST_AUDIODATA = 0x502
+};
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioMTKHeadsetMessager.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioMTKHeadsetMessager.h
new file mode 100644
index 0000000..2e5f8d8
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioMTKHeadsetMessager.h
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+
+/*****************************************************************************
+* Copyright Statement:
+* --------------------
+* This software is protected by Copyright and the information contained
+* herein is confidential. The software may not be copied and the information
+* contained herein may not be used or disclosed except with the written
+* permission of MediaTek Inc. (C) 2009
+*
+* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
+* NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
+* SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
+*
+* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
+* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
+* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
+* LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
+* RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
+* THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
+*
+*****************************************************************************/
+
+#ifndef _AUDIO_HEADSET_MESSAGE_H_
+#define _AUDIO_HEADSET_MESSAGE_H_
+
+/*****************************************************************************
+* E X T E R N A L R E F E R E N C E S
+******************************************************************************
+*/
+#include "AudioDef.h"
+#include <sys/ioctl.h>
+
+/*****************************************************************************
+* C O N S T A N T S
+******************************************************************************
+*/
+
+#define ACCDET_IOC_MAGIC 'A'
+#define ACCDET_INIT _IO(ACCDET_IOC_MAGIC,0) // call wehn first time
+#define SET_CALL_STATE _IO(ACCDET_IOC_MAGIC,1) // when state is changing , tell headset driver.
+#define GET_BUTTON_STATUS _IO(ACCDET_IOC_MAGIC,2) // ioctl to get hook button state.
+
+static const char *HEADSET_PATH = "/dev/accdet";
+static const char *YUSUHEADSET_STAUTS_PATH = "/sys/bus/platform/drivers/Accdet_Driver/state";
+
+namespace android {
+
+/*****************************************************************************
+* F U N C T I O N D E F I N I T I O N
+******************************************************************************
+*/
+class AudioMTKHeadSetMessager {
+public:
+ static AudioMTKHeadSetMessager *getInstance();
+ bool Get_headset_info(void);
+
+ bool isEarphonePlugged(); // w/o headset mic
+ bool isHeadsetPlugged(); // w headset mic
+
+ bool SetHeadInit(void);
+ void SetHeadSetState(int state);
+
+private:
+ static AudioMTKHeadSetMessager *UniqueHeadsetInstance;
+ // private constructor
+ AudioMTKHeadSetMessager();
+ AudioMTKHeadSetMessager(const AudioMTKHeadSetMessager &); // intentionally undefined
+ AudioMTKHeadSetMessager &operator=(const AudioMTKHeadSetMessager &); // intentionally undefined
+
+ pthread_t hHeadsetReadThread;
+};
+
+}; // namespace android
+
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioPolicyParameters.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioPolicyParameters.h
new file mode 100644
index 0000000..e743509
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioPolicyParameters.h
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_POLICY_PARAMETERS_H
+#define ANDROID_AUDIO_POLICY_PARAMETERS_H
+
+enum PolicyParameters {
+ POLICY_LOAD_VOLUME = 0,
+ POLICY_SET_FM_SPEAKER,
+ POLICY_CHECK_FM_PRIMARY_KEY_ROUTING,
+ POLICY_SET_FM_PRESTOP,
+ POLICY_SET_A2DP_FORCE_IGNORE,
+ POLICY_SET_FM_TX_ENABLE,
+ POLICY_SET_FM_RX_FORCE_DISABLE_TX,
+ POLICY_SET_LOSSLESS_BT_STATUS,
+ POLICY_SET_CROSSMOUNT_LOCAL_PLAYBACK, //For MTK_CROSSMOUNT_SUPPORT
+ POLICY_SET_CROSSMOUNT_MIC_LOCAL_PLAYBACK, //For MTK_CROSSMOUNT_SUPPORT
+ POLICY_SET_TTY_MODE,
+ POLICY_SET_HDMI_CHANNEL_SUPPORT, // for MTK_HDMI_MULTI_CHANNEL_SUPPORT
+ POLICY_SET_NUM_HS_POLE,
+ POLICY_SET_AUDIO_RATE,
+ POLICY_SET_SCENE_GAIN,
+#if defined(MTK_HIFIAUDIO_SUPPORT)
+ POLICY_SET_HIFI_STATE,
+#endif
+ POLICY_SET_A2DP_CODEC,
+ POLICY_SET_BT_VGS_SETTING,
+};
+
+enum FMStatus {
+ FM_STATE_STOP = 0,
+ FM_STATE_PLAY,
+ FM_STATE_PRESTOP,
+ FM_STATE_PRESTOP_WITH_MUTE,
+};
+enum a2dp_codec {
+ A2DP_CODEC_ERROR = -1,
+ A2DP_CODEC_APTX = 0,
+ A2DP_CODEC_LDAC = 1,
+ A2DP_CODEC_SBC = 2,
+ A2DP_CODEC_AAC = 3,
+ A2DP_CODEC_NUM,
+};
+
+//! BESLOUDNESS_CONTROL_CALLBACK_STRUCT interface
+/*!
+this structure is hold for flinger callback funtion
+*/
+typedef struct _BESLOUDNESS_CONTROL_CALLBACK_STRUCT {
+ void (*callback)(void *data);
+} BESLOUDNESS_CONTROL_CALLBACK_STRUCT;
+
+#endif // end of ANDROID_AUDIO_POLICY_PARAMETERS_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioToolkit.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioToolkit.h
new file mode 100644
index 0000000..6b8a3b4
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioToolkit.h
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_TOOLKIT_H
+#define AUDIO_TOOLKIT_H
+#include <utils/String8.h>
+
+/*
+ this function should implement the basic function for debug information
+ or basic function proviede to audio hardware modules
+*/
+
+namespace android {
+//-------Base64 operation
+size_t Base64_OutputSize(bool bEncode, size_t input_length);
+size_t Base64_Encode(const unsigned char *data_input, char *data_encoded, size_t input_length);
+size_t Base64_Decode(const char *data_input, unsigned char *data_decoded, size_t input_length);
+status_t AudioToolKit_GetDecodedData(String8 strPara, size_t len, void *ptr);
+
+}
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioUtility.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioUtility.h
new file mode 100644
index 0000000..0b7d214
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioUtility.h
@@ -0,0 +1,427 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_UTILITY_H
+#define AUDIO_UTILITY_H
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "AudioDef.h"
+#include "AudioType.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <sched.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+#include <utils/SortedVector.h>
+#include <time.h>
+#include <cutils/atomic.h>
+
+#if defined(PC_EMULATION)
+#include "Windows.h"
+#include "WinBase.h"
+#else
+#include <cutils/atomic.h>
+
+#include <log/log.h>
+#include <cutils/properties.h>
+#endif
+
+#include <tinyalsa/asoundlib.h>
+#include "MtkAudioComponent.h"
+#include "audio_custom_exp.h"
+#if !defined(MTK_YOCTO_AUDIO)
+#include "AudioCompFltCustParam.h"
+#endif
+
+/*
+ this function should implement the basic function for debug information
+ or basic function proviede to audio hardware modules
+*/
+
+struct audio_ringbuf_t;
+
+
+namespace android {
+#define MAX_DUMP_NUM (1024)
+
+enum {
+ AUDIO_LOG_HARDWARE = 1,
+ AUDIO_LOG_A2DPHARDWARE,
+ AUDIO_LOG_STREAMOUT,
+ AUDIO_LOG_STREAMIN,
+ AUDIO_LOG_I2SSTREAMIN,
+ AUDIO_LOG_VOLUMECONTROLLER,
+ AUDIO_LOG_RESOURCEMANAGER,
+ AUDIO_LOG_AUDIODEVCE,
+ AUDIO_LOG_ANALOG,
+ AUDIO_LOG_DIGITAL,
+ AUDIO_LOG_AUDIOFLINGER,
+ AUDIO_LOG_SPEECHCONTROL,
+ AUDIO_LOG_AUDIOPOLICYSERVICE,
+ AUDIO_LOG_AUDIOPOLICYANAGER,
+ AUDIO_LOG_AUDIOMIXER
+};
+
+enum {
+ AUDIO_SUPPORT_DMIC = 1,
+ AUDIO_SUPPORT_2IN1_SPEAKER,
+ AUDIO_SUPPORT_VIBRATION_SPEAKER,
+ AUDIO_SUPPORT_EXTERNAL_BUILTIN_MIC,
+ AUDIO_SUPPORT_EXTERNAL_ECHO_REFERENCE,
+ AUDIO_SUPPORT_VOW_DUAL_MIC,
+};
+
+enum {
+ AUDIO_SPK_INVALID = -1,
+ AUDIO_SPK_INTAMP,
+ AUDIO_SPK_EXTAMP_LO,
+ AUDIO_SPK_EXTAMP_HP,
+ AUDIO_SPK_2_IN_1,
+ AUDIO_SPK_3_IN_1,
+};
+
+enum {
+ AUDIO_I2S_INVALID = -1,
+ AUDIO_I2S0,
+ AUDIO_I2S1,
+ AUDIO_I2S2,
+ AUDIO_I2S3,
+ AUDIO_I2S5,
+};
+
+static enum pcm_format pcm_format_from_audio_format(audio_format_t format) {
+ switch (format) {
+#ifdef HAVE_BIG_ENDIAN
+ case AUDIO_FORMAT_PCM_16_BIT:
+ return PCM_FORMAT_S16_BE;
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ return PCM_FORMAT_S24_3BE;
+ case AUDIO_FORMAT_PCM_32_BIT:
+ return PCM_FORMAT_S32_BE;
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ return PCM_FORMAT_S24_BE;
+#else
+ case AUDIO_FORMAT_PCM_16_BIT:
+ return PCM_FORMAT_S16_LE;
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ return PCM_FORMAT_S24_3LE;
+ case AUDIO_FORMAT_PCM_32_BIT:
+ return PCM_FORMAT_S32_LE;
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ return PCM_FORMAT_S24_LE;
+#endif
+ case AUDIO_FORMAT_PCM_FLOAT: /* there is no equivalent for float */
+ default:
+ LOG_ALWAYS_FATAL("pcm_format_from_audio_format: invalid audio format %#x", format);
+ return PCM_FORMAT_S16_LE;//0; will build error in hardware/audio_alsaops.h
+ }
+}
+
+/* Converts pcm_format to audio_format.
+ * Parameters:
+ * format the pcm_format to convert
+ *
+ * Logs a fatal error if format is not a valid convertible pcm_format.
+ */
+static audio_format_t audio_format_from_pcm_format(enum pcm_format format) {
+ switch (format) {
+#ifdef HAVE_BIG_ENDIAN
+ case PCM_FORMAT_S16_BE:
+ return AUDIO_FORMAT_PCM_16_BIT;
+ case PCM_FORMAT_S24_3BE:
+ return AUDIO_FORMAT_PCM_24_BIT_PACKED;
+ case PCM_FORMAT_S24_BE:
+ return AUDIO_FORMAT_PCM_8_24_BIT;
+ case PCM_FORMAT_S32_BE:
+ return AUDIO_FORMAT_PCM_32_BIT;
+#else
+ case PCM_FORMAT_S16_LE:
+ return AUDIO_FORMAT_PCM_16_BIT;
+ case PCM_FORMAT_S24_3LE:
+ return AUDIO_FORMAT_PCM_24_BIT_PACKED;
+ case PCM_FORMAT_S24_LE:
+ return AUDIO_FORMAT_PCM_8_24_BIT;
+ case PCM_FORMAT_S32_LE:
+ return AUDIO_FORMAT_PCM_32_BIT;
+#endif
+ default:
+ LOG_ALWAYS_FATAL("audio_format_from_pcm_format: invalid pcm format %#x", format);
+ return AUDIO_FORMAT_DEFAULT;//0; will build error in hardware/audio_alsaops.h
+ }
+}
+
+class AudioTimeStamp {
+public:
+ AudioTimeStamp();
+ ~AudioTimeStamp();
+ void SetSystemTimeValid(const char str);
+private:
+ struct timespec systemtime[30];
+ String8 TimeString[30];
+ const int MaxRecord = 30;
+ int index;
+};
+
+#define RING_BUF_SIZE_OFFSET 8
+struct RingBuf {
+ char *pBufBase;
+ char *pRead;
+ char *pWrite;
+ char *pBufEnd;
+ int bufLen;
+
+ RingBuf() : pBufBase(NULL), pRead(NULL), pWrite(NULL), pBufEnd(NULL), bufLen(0) {}
+};
+
+
+struct WriteSmoother;
+
+extern const char *audio_dump_path;
+extern const char *streamout_ori;
+extern const char *streamout_ori_propty;
+extern const char *streamout_dcr;
+extern const char *streamout_dcr_propty;
+
+extern const char *streamout_s2m;
+extern const char *streamout_s2m_propty;
+extern const char *streamout_acf;
+extern const char *streamout_acf_propty;
+extern const char *streamout_hcf;
+extern const char *streamout_hcf_propty;
+
+extern const char *streamout;
+extern const char *streamoutfinal;
+extern const char *streamout_propty;
+extern const char *aud_dumpftrace_dbg_propty;
+extern const char *streaminIVCPMIn;
+extern const char *streaminIVIn;
+extern const char *streamout_vibsignal;
+extern const char *streamout_notch;
+extern const char *streamoutdsp_propty;
+extern const char *a2dpdsp_propty;
+
+extern const char *streaminmanager;
+extern const char *streamin;;
+extern const char *streaminOri;
+extern const char *streaminI2S;
+extern const char *streaminDAIBT;
+extern const char *streaminSpk;
+extern const char *streaminSpk_propty;
+extern const char *capture_data_provider;
+
+extern const char *streamin_propty;
+extern const char *streamin_epl_propty;
+extern const char *streamindsp_propty;
+
+extern const char *allow_low_latency_propty;
+extern const char *streamhfp_propty;
+extern const char *allow_offload_propty;
+extern const char *streaminlog_propty;
+
+extern bool bDumpStreamOutFlg;
+extern bool bDumpStreamInFlg;
+
+
+int AudiocheckAndCreateDirectory(const char *pC);
+FILE *AudioOpendumpPCMFile(const char *filepath, const char *propty);
+void AudioCloseDumpPCMFile(FILE *file);
+void AudioDumpPCMData(void *buffer, uint32_t bytes, FILE *file);
+timespec GetSystemTime(bool print = 0);
+unsigned long long TimeDifference(struct timespec time1, struct timespec time2);
+bool generateVmDumpByEpl(const char *eplPath, const char *vmPath);
+
+//-------ring buffer operation
+int RingBuf_getDataCount(const RingBuf *RingBuf1);
+int RingBuf_getFreeSpace(const RingBuf *RingBuf1);
+void RingBuf_copyToLinear(char *buf, RingBuf *RingBuf1, int count);
+void RingBuf_copyFromLinear(RingBuf *RingBuf1, const char *buf, int count);
+void RingBuf_fillZero(RingBuf *RingBuf1, int count);
+void RingBuf_copyEmpty(RingBuf *RingBuft, RingBuf *RingBufs);
+int RingBuf_copyFromRingBuf(RingBuf *RingBuft, RingBuf *RingBufs, int count);
+void RingBuf_writeDataValue(RingBuf *RingBuf1, const int value, const int count);
+int RingBuf_discardData(RingBuf *ringBuf, int count);
+int RingBuf_checkDataCrossBoundary(const RingBuf *ringBuf, int count);
+
+void RingBuf_copyFromLinearSRC(void *pSrcHdl, RingBuf *RingBuft, char *buf, int num, int srt, int srs);
+void RingBuf_copyEmptySRC(void *pSrcHdl, RingBuf *RingBuft, const RingBuf *RingBufs, int srt, int srs);
+
+void RingBuf_dynamicChangeBufSize(struct RingBuf *ringBuf, uint32_t count);
+
+
+/**
+ * write smoother
+ */
+struct WriteSmoother *createWriteSmoother(void);
+
+void doWriteSmoother(
+ struct WriteSmoother *smoother,
+ const uint64_t bufferTimeUs,
+ const uint64_t safeFrameCount); // at least keep # frames in buf
+
+void updateWriteSmootherTime( // for suspend, update time only
+ struct WriteSmoother *smoother,
+ const uint64_t bufferTimeUs);
+
+void destroyWriteSmoother(struct WriteSmoother **smoother);
+
+
+
+short clamp16(int sample);
+
+BCV_PCM_FORMAT get_bcv_pcm_format(audio_format_t source, audio_format_t target);
+
+size_t getSizePerFrame(audio_format_t fmt, unsigned int numChannel);
+uint32_t getPeriodBufSize(const stream_attribute_t *attribute, uint32_t period_time_ms);
+uint64_t getBufferLatencyMs(const stream_attribute_t *attribute, uint64_t bytes);
+uint64_t getBufferLatencyUs(const stream_attribute_t *attribute, uint64_t bytes);
+
+
+void CVSDLoopbackGetWriteBuffer(uint8_t **buffer, uint32_t *buf_len);
+void CVSDLoopbackGetReadBuffer(uint8_t **buffer, uint32_t *buf_len);
+void CVSDLoopbackReadDataDone(uint32_t len);
+void CVSDLoopbackWriteDataDone(uint32_t len);
+void CVSDLoopbackResetBuffer(void);
+int32_t CVSDLoopbackGetFreeSpace(void);
+int32_t CVSDLoopbackGetDataCount(void);
+
+bool IsAudioSupportFeature(int dFeatureOption);
+
+bool isBtSpkDevice(audio_devices_t devices);
+
+uint32_t GetMicDeviceMode(uint32_t mic_category);
+unsigned int FormatTransfer(int SourceFormat, int TargetFormat, void *Buffer, unsigned int mReadBufferSize);
+int InFactoryMode();
+int In64bitsProcess();
+
+void calculateTimeStampByFrames(struct timespec startTime, uint32_t mTotalCaptureFrameSize, stream_attribute_t streamAttribute, struct timespec *newTimeStamp);
+void calculateTimeStampByBytes(struct timespec startTime, uint32_t totalBufferSize, stream_attribute_t streamAttribute, struct timespec *newTimeStamp);
+void adjustTimeStamp(struct timespec *startTime, int delayMs);
+uint32_t convertMsToBytes(const uint32_t ms, const stream_attribute_t *streamAttribute);
+
+void collectPlatformOutputFlags(audio_output_flags_t flag);
+bool platformIsolatedDeepBuffer();
+bool isIsolatedDeepBuffer(const audio_output_flags_t flag);
+
+unsigned int wordSizeAlign(unsigned int inSize);
+
+/**
+ * newMtkAudioBitConverter(uint32_t sampling_rate, uint32_t channel_num, BCV_PCM_FORMAT format)
+ * Using dlopen/dlsym to new MtkAudioBitConverterBase object
+ */
+MtkAudioBitConverterBase *newMtkAudioBitConverter(uint32_t sampling_rate, uint32_t channel_num, BCV_PCM_FORMAT format);
+
+/**
+ * newMtkAudioSrc(uint32_t input_SR, uint32_t input_channel_num, uint32_t output_SR, uint32_t output_channel_num, SRC_PCM_FORMAT format)
+ * Using dlopen/dlsym to new MtkAudioSrcBase object
+ */
+MtkAudioSrcBase *newMtkAudioSrc(uint32_t input_SR, uint32_t input_channel_num, uint32_t output_SR, uint32_t output_channel_num, SRC_PCM_FORMAT format);
+
+/**
+ * newMtkAudioLoud(uint32_t eFLTtype)
+ * Using dlopen/dlsym to new MtkAudioLoudBase object
+ */
+MtkAudioLoudBase *newMtkAudioLoud(uint32_t eFLTtype);
+
+/**
+ * newMtkDcRemove(void)
+ * Using dlopen/dlsym to new MtkAudioDcRemoveBase object
+ */
+MtkAudioDcRemoveBase *newMtkDcRemove(void);
+
+/**
+ * deleteMtkAudioBitConverter(MtkAudioBitConverterBase* pObject)
+ * Using dlopen/dlsym to delete MtkAudioBitConverterBase object
+ */
+void deleteMtkAudioBitConverter(MtkAudioBitConverterBase *pObject);
+
+/**
+ * deleteMtkAudioSrc(MtkAudioSrcBase* pObject)
+ * Using dlopen/dlsym to delete MtkAudioSrcBase object
+ */
+void deleteMtkAudioSrc(MtkAudioSrcBase *pObject);
+
+/**
+ * newMtkAudioLoud(uint32_t eFLTtype)
+ * Using dlopen/dlsym to new MtkAudioLoudBase object
+ */
+void deleteMtkAudioLoud(MtkAudioLoudBase *pObject);
+
+/**
+ * deleteMtkDcRemove(MtkAudioDcRemoveBase *pObject)
+ * Using dlopen/dlsym to delete MtkAudioDcRemoveBase object
+ */
+void deleteMtkDcRemove(MtkAudioDcRemoveBase *pObject);
+
+#if !defined(MTK_YOCTO_AUDIO)
+/**
+ * setAudioCompFltCustParam(AudioCompFltType_t eFLTtype, AUDIO_ACF_CUSTOM_PARAM_STRUCT *audioParam)
+ * Using dlopen/dlsym to set Audio Parameters
+ */
+int setAudioCompFltCustParam(AudioCompFltType_t eFLTtype, AUDIO_ACF_CUSTOM_PARAM_STRUCT *audioParam);
+
+/**
+ * getAudioCompFltCustParam(AudioCompFltType_t eFLTtype, AUDIO_ACF_CUSTOM_PARAM_STRUCT *audioParam)
+ * Using dlopen/dlsym to get Audio Parameters
+ */
+int getAudioCompFltCustParam(AudioCompFltType_t eFLTtype, AUDIO_ACF_CUSTOM_PARAM_STRUCT *audioParam, const char *custScene = NULL);
+#endif
+/**
+ * SpeechMemCpy(void *dest, void *src, size_t n)
+ * use to replace memcpy on CCCI raw memory
+ */
+void SpeechMemCpy(void *dest, void *src, size_t n);
+
+
+/**
+ * safe version of strncpy
+ */
+char *audio_strncpy(char *target, const char *source, size_t target_size);
+
+
+/**
+ * safe version of strncat
+ */
+char *audio_strncat(char *target, const char *source, size_t target_size);
+
+
+/**
+ * PowerHAL hint control
+ */
+enum PowerHalHint {
+ POWERHAL_LATENCY_DL = 0,
+ POWERHAL_LATENCY_UL = 1,
+ POWERHAL_POWER_DL = 2,
+ POWERHAL_DISABLE_WIFI_POWER_SAVE = 3
+};
+
+void initPowerHal();
+bool getPowerHal();
+void power_hal_hint(PowerHalHint hint, bool enable);
+
+void setNeedAEETimeoutFlg(bool state);
+bool getNeedAEETimeoutFlg();
+
+/**
+ * audio sched_setscheduler
+ */
+
+int audio_sched_setschedule(pid_t pid, int policy, int sched_priority);
+
+/**
+ * Get MicInfo
+ */
+bool getMicInfo(audio_microphone_characteristic_t *micArray, size_t *micCount);
+void dumpMicInfo(struct audio_microphone_characteristic_t *micArray, size_t micCount);
+bool findEnumByString(const struct enum_to_str_table *table, const char *str, uint32_t *enumVal);
+
+
+
+}
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioVIBSPKCoeff.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioVIBSPKCoeff.h
new file mode 100644
index 0000000..3c0a82b
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioVIBSPKCoeff.h
@@ -0,0 +1,1551 @@
+// SPDX-License-Identifier: MediaTekProprietary
+//#if defined(MTK_VIBSPK_SUPPORT)
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_141 \
+ { \
+ /* filter 0 */ \
+ 0x3DBB848F, 0x3DBB7B7A, 0xC4670000, /* 48000 */ \
+ 0x3DBC848F, 0x3DBC7B78, 0xC4670000, /* 44100 */ \
+ 0x3C838705, 0x3C837A05, 0xC5C10000, /* 32000 */ \
+ 0x3B768929, 0x3B7677C6, 0xC7CF0000, /* 24000 */ \
+ 0x3B788929, 0x3B7877BE, 0xC7CF0000, /* 22050 */ \
+ 0x39EC8C55, 0x39EC7504, 0xCA2F0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3DBB848F, 0x3DBB7B4C, 0xC4860000, /* 48000 */ \
+ 0x3DBC848F, 0x3DBC7B48, 0xC4860000, /* 44100 */ \
+ 0x3C838705, 0x3C83779A, 0xC7EE0000, /* 32000 */ \
+ 0x3B768929, 0x3B767566, 0xC9D50000, /* 24000 */ \
+ 0x3B788929, 0x3B787554, 0xC9D50000, /* 22050 */ \
+ 0x39EC8C55, 0x39EC7162, 0xCD140000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_144 \
+ { \
+ /* filter 0 */ \
+ 0x3DBB848F, 0x3DBB7B7A, 0xC4670000, /* 48000 */ \
+ 0x3DBC848F, 0x3DBC7B78, 0xC4670000, /* 44100 */ \
+ 0x3C848705, 0x3C847A05, 0xC5C10000, /* 32000 */ \
+ 0x3B768929, 0x3B7677C6, 0xC7CF0000, /* 24000 */ \
+ 0x3B788929, 0x3B7877BE, 0xC7CF0000, /* 22050 */ \
+ 0x39ED8C55, 0x39ED7504, 0xCA2F0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3DBB848F, 0x3DBB7B4C, 0xC4860000, /* 48000 */ \
+ 0x3DBC848F, 0x3DBC7B48, 0xC4860000, /* 44100 */ \
+ 0x3C848705, 0x3C84779A, 0xC7EE0000, /* 32000 */ \
+ 0x3B768929, 0x3B767566, 0xC9D50000, /* 24000 */ \
+ 0x3B788929, 0x3B787554, 0xC9D50000, /* 22050 */ \
+ 0x39ED8C55, 0x39ED7162, 0xCD140000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_147 \
+ { \
+ /* filter 0 */ \
+ 0x3DBB848F, 0x3DBB7B7A, 0xC4670000, /* 48000 */ \
+ 0x3DBC848F, 0x3DBC7B78, 0xC4670000, /* 44100 */ \
+ 0x3C848705, 0x3C847A05, 0xC5C10000, /* 32000 */ \
+ 0x3B778929, 0x3B7777C6, 0xC7CF0000, /* 24000 */ \
+ 0x3B798929, 0x3B7977BE, 0xC7CF0000, /* 22050 */ \
+ 0x39EE8C55, 0x39EE7504, 0xCA2F0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3DBB848F, 0x3DBB7B4C, 0xC4860000, /* 48000 */ \
+ 0x3DBC848F, 0x3DBC7B48, 0xC4860000, /* 44100 */ \
+ 0x3C848705, 0x3C84779A, 0xC7EE0000, /* 32000 */ \
+ 0x3B778929, 0x3B777566, 0xC9D50000, /* 24000 */ \
+ 0x3B798929, 0x3B797554, 0xC9D50000, /* 22050 */ \
+ 0x39EE8C55, 0x39EE7162, 0xCD140000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_150 \
+ { \
+ /* filter 0 */ \
+ 0x3DBC848F, 0x3DBC7B7A, 0xC4670000, /* 48000 */ \
+ 0x3DBC848F, 0x3DBC7B78, 0xC4670000, /* 44100 */ \
+ 0x3C848705, 0x3C847A05, 0xC5C10000, /* 32000 */ \
+ 0x3B778929, 0x3B7777C6, 0xC7CF0000, /* 24000 */ \
+ 0x3B798929, 0x3B7977BE, 0xC7CF0000, /* 22050 */ \
+ 0x39EF8C55, 0x39EF7504, 0xCA2F0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3DBC848F, 0x3DBC7B4C, 0xC4860000, /* 48000 */ \
+ 0x3DBC848F, 0x3DBC7B48, 0xC4860000, /* 44100 */ \
+ 0x3C848705, 0x3C84779A, 0xC7EE0000, /* 32000 */ \
+ 0x3B778929, 0x3B777566, 0xC9D50000, /* 24000 */ \
+ 0x3B798929, 0x3B797554, 0xC9D50000, /* 22050 */ \
+ 0x39EF8C55, 0x39EF7162, 0xCD140000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_153 \
+ { \
+ /* filter 0 */ \
+ 0x3DEA8433, 0x3DEA7D5C, 0xC2880000, /* 48000 */ \
+ 0x3DC6847C, 0x3DC67CB5, 0xC3280000, /* 44100 */ \
+ 0x3CF0862E, 0x3CF07BFC, 0xC3C80000, /* 32000 */ \
+ 0x3B818917, 0x3B817A92, 0xC5040000, /* 24000 */ \
+ 0x3B3489B4, 0x3B34793D, 0xC63D0000, /* 22050 */ \
+ 0x39928D10, 0x3992765F, 0xC8A50000, /* 16000 */ \
+ \
+ /* filter 1 */ \
+ 0x3DEA8433, 0x3DEA7A1A, 0xC5A10000, /* 48000 */ \
+ 0x3DC6847C, 0x3DC67A14, 0xC5A10000, /* 44100 */ \
+ 0x3CF0862E, 0x3CF07761, 0xC80C0000, /* 32000 */ \
+ 0x3B818917, 0x3B8172B0, 0xCC280000, /* 24000 */ \
+ 0x3B3489B4, 0x3B347298, 0xCC280000, /* 22050 */ \
+ 0x39928D10, 0x39926E3F, 0xCF8E0000, /* 16000 */ \
+ }
+
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_156 \
+ { \
+ /* filter 0 */ \
+ 0x3DEA8433, 0x3DEA7D5C, 0xC2880000, /* 48000 */ \
+ 0x3DC6847C, 0x3DC67CB5, 0xC3280000, /* 44100 */ \
+ 0x3CF0862E, 0x3CF07BFC, 0xC3C80000, /* 32000 */ \
+ 0x3B818917, 0x3B817A92, 0xC5040000, /* 24000 */ \
+ 0x3B3589B4, 0x3B35793D, 0xC63D0000, /* 22050 */ \
+ 0x39948D10, 0x3994765F, 0xC8A50000, /* 16000 */ \
+ \
+ /* filter 1 */ \
+ 0x3DEA8433, 0x3DEA7A1A, 0xC5A10000, /* 48000 */ \
+ 0x3DC6847C, 0x3DC67A14, 0xC5A10000, /* 44100 */ \
+ 0x3CF0862E, 0x3CF07761, 0xC80C0000, /* 32000 */ \
+ 0x3B818917, 0x3B8172B0, 0xCC280000, /* 24000 */ \
+ 0x3B3589B4, 0x3B357298, 0xCC280000, /* 22050 */ \
+ 0x39948D10, 0x39946E3F, 0xCF8E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_159 \
+ { \
+ /* filter 0 */ \
+ 0x3DEA8433, 0x3DEA7D5C, 0xC2880000, /* 48000 */ \
+ 0x3DC6847C, 0x3DC67CB5, 0xC3280000, /* 44100 */ \
+ 0x3CF1862E, 0x3CF17BFC, 0xC3C80000, /* 32000 */ \
+ 0x3B828917, 0x3B827A92, 0xC5040000, /* 24000 */ \
+ 0x3B3689B4, 0x3B36793D, 0xC63D0000, /* 22050 */ \
+ 0x39958D10, 0x3995765F, 0xC8A50000, /* 16000 */ \
+ \
+ /* filter 1 */ \
+ 0x3DEA8433, 0x3DEA7A1A, 0xC5A10000, /* 48000 */ \
+ 0x3DC6847C, 0x3DC67A14, 0xC5A10000, /* 44100 */ \
+ 0x3CF1862E, 0x3CF17761, 0xC80C0000, /* 32000 */ \
+ 0x3B828917, 0x3B8272B0, 0xCC280000, /* 24000 */ \
+ 0x3B3689B4, 0x3B367298, 0xCC280000, /* 22050 */ \
+ 0x39958D10, 0x39956E3F, 0xCF8E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_162 \
+ { \
+ /* filter 0 */ \
+ 0x3DEA8433, 0x3DEA7D5C, 0xC2880000, /* 48000 */ \
+ 0x3DC6847C, 0x3DC67CB5, 0xC3280000, /* 44100 */ \
+ 0x3CF1862E, 0x3CF17BFC, 0xC3C80000, /* 32000 */ \
+ 0x3B828917, 0x3B827A92, 0xC5040000, /* 24000 */ \
+ 0x3B3689B4, 0x3B36793D, 0xC63D0000, /* 22050 */ \
+ 0x39958D10, 0x3995765F, 0xC8A50000, /* 16000 */ \
+ \
+ /* filter 1 */ \
+ 0x3DEA8433, 0x3DEA7A1A, 0xC5A10000, /* 48000 */ \
+ 0x3DC6847C, 0x3DC67A14, 0xC5A10000, /* 44100 */ \
+ 0x3CF1862E, 0x3CF17761, 0xC80C0000, /* 32000 */ \
+ 0x3B828917, 0x3B8272B0, 0xCC280000, /* 24000 */ \
+ 0x3B3689B4, 0x3B367298, 0xCC280000, /* 22050 */ \
+ 0x39958D10, 0x39956E3F, 0xCF8E0000, /* 16000 */ \
+ }
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_165 \
+ { \
+ /* filter 0 */ \
+ 0x3DEA8433, 0x3DEA7D5C, 0xC2880000, /* 48000 */ \
+ 0x3DC6847C, 0x3DC67CB5, 0xC3280000, /* 44100 */ \
+ 0x3CF1862E, 0x3CF17BFC, 0xC3C80000, /* 32000 */ \
+ 0x3B838917, 0x3B837A92, 0xC5040000, /* 24000 */ \
+ 0x3B3789B4, 0x3B37793D, 0xC63D0000, /* 22050 */ \
+ 0x39968D10, 0x3996765F, 0xC8A50000, /* 16000 */ \
+ \
+ /* filter 1 */ \
+ 0x3DEA8433, 0x3DEA7A1A, 0xC5A10000, /* 48000 */ \
+ 0x3DC6847C, 0x3DC67A14, 0xC5A10000, /* 44100 */ \
+ 0x3CF1862E, 0x3CF17761, 0xC80C0000, /* 32000 */ \
+ 0x3B838917, 0x3B8372B0, 0xCC280000, /* 24000 */ \
+ 0x3B3789B4, 0x3B377298, 0xCC280000, /* 22050 */ \
+ 0x39968D10, 0x39966E3F, 0xCF8E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_168 \
+ { \
+ /* filter 0 */ \
+ 0x3DEA8433, 0x3DEA7D5C, 0xC2880000, /* 48000 */ \
+ 0x3DC6847C, 0x3DC67CB5, 0xC3280000, /* 44100 */ \
+ 0x3CF1862E, 0x3CF17BFC, 0xC3C80000, /* 32000 */ \
+ 0x3B838917, 0x3B837A92, 0xC5040000, /* 24000 */ \
+ 0x3B3789B4, 0x3B37793D, 0xC63D0000, /* 22050 */ \
+ 0x39988D10, 0x3998765F, 0xC8A50000, /* 16000 */ \
+ \
+ /* filter 1 */ \
+ 0x3DEA8433, 0x3DEA7A12, 0xC5A10000, /* 48000 */ \
+ 0x3DC6847C, 0x3DC67A0A, 0xC5A10000, /* 44100 */ \
+ 0x3CF1862E, 0x3CF1774F, 0xC80C0000, /* 32000 */ \
+ 0x3B838917, 0x3B8372B0, 0xCC280000, /* 24000 */ \
+ 0x3B3789B4, 0x3B377298, 0xCC280000, /* 22050 */ \
+ 0x39988D10, 0x39986E3F, 0xCF8E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_171 \
+ { \
+ /* filter 0 */ \
+ 0x3DEB8433, 0x3DEB7D5C, 0xC2880000, /* 48000 */ \
+ 0x3DC7847C, 0x3DC77CB5, 0xC3280000, /* 44100 */ \
+ 0x3CF2862E, 0x3CF27BFC, 0xC3C80000, /* 32000 */ \
+ 0x3B848917, 0x3B847A92, 0xC5040000, /* 24000 */ \
+ 0x3B3889B4, 0x3B38793D, 0xC63D0000, /* 22050 */ \
+ 0x39998D10, 0x3999765F, 0xC8A50000, /* 16000 */ \
+ \
+ /* filter 1 */ \
+ 0x3DEB8433, 0x3DEB7A12, 0xC5A10000, /* 48000 */ \
+ 0x3DC7847C, 0x3DC77A0A, 0xC5A10000, /* 44100 */ \
+ 0x3CF2862E, 0x3CF2774F, 0xC80C0000, /* 32000 */ \
+ 0x3B848917, 0x3B8472B0, 0xCC280000, /* 24000 */ \
+ 0x3B3889B4, 0x3B387298, 0xCC280000, /* 22050 */ \
+ 0x39998D10, 0x39996E3F, 0xCF8E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_174 \
+ { \
+ /* filter 0 */ \
+ 0x3DEB8433, 0x3DEB7D5C, 0xC2880000, /* 48000 */ \
+ 0x3DC7847C, 0x3DC77CB5, 0xC3280000, /* 44100 */ \
+ 0x3CF2862E, 0x3CF27BFC, 0xC3C80000, /* 32000 */ \
+ 0x3B858917, 0x3B857A92, 0xC5040000, /* 24000 */ \
+ 0x3B3889B4, 0x3B38793D, 0xC63D0000, /* 22050 */ \
+ 0x399A8D10, 0x399A765F, 0xC8A50000, /* 16000 */ \
+ \
+ /* filter 1 */ \
+ 0x3DEB8433, 0x3DEB7A12, 0xC5A10000, /* 48000 */ \
+ 0x3DC7847C, 0x3DC77A0A, 0xC5A10000, /* 44100 */ \
+ 0x3CF2862E, 0x3CF2774F, 0xC80C0000, /* 32000 */ \
+ 0x3B858917, 0x3B8572B0, 0xCC280000, /* 24000 */ \
+ 0x3B3889B4, 0x3B387298, 0xCC280000, /* 22050 */ \
+ 0x399A8D10, 0x399A6E3F, 0xCF8E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_177 \
+ { \
+ /* filter 0 */ \
+ 0x3DEA8434, 0x3DEA7D5D, 0xC2890000, /* 48000 */ \
+ 0x3DC7847D, 0x3DC77CB5, 0xC3290000, /* 44100 */ \
+ 0x3CF2862F, 0x3CF27BFC, 0xC3C80000, /* 32000 */ \
+ 0x3B858918, 0x3B857A93, 0xC5050000, /* 24000 */ \
+ 0x3B3989B5, 0x3B39793E, 0xC63D0000, /* 22050 */ \
+ 0x399C8D10, 0x399C765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3DEA8434, 0x3DEA7A1B, 0xC5A10000, /* 48000 */ \
+ 0x3DC7847D, 0x3DC77A14, 0xC5A10000, /* 44100 */ \
+ 0x3CF2862F, 0x3CF27762, 0xC80D0000, /* 32000 */ \
+ 0x3B858918, 0x3B8572B0, 0xCC290000, /* 24000 */ \
+ 0x3B3989B5, 0x3B397298, 0xCC290000, /* 22050 */ \
+ 0x399C8D10, 0x399C6E40, 0xCF8F0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_180 \
+ { \
+ /* filter 0 */ \
+ 0x3DEA8434, 0x3DEA7D5D, 0xC2890000, /* 48000 */ \
+ 0x3DC7847D, 0x3DC77CB5, 0xC3290000, /* 44100 */ \
+ 0x3CF2862F, 0x3CF27BFC, 0xC3C80000, /* 32000 */ \
+ 0x3B858918, 0x3B857A93, 0xC5050000, /* 24000 */ \
+ 0x3B3989B5, 0x3B39793E, 0xC63D0000, /* 22050 */ \
+ 0x399D8D10, 0x399D765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3DEA8434, 0x3DEA7A1B, 0xC5A10000, /* 48000 */ \
+ 0x3DC7847D, 0x3DC77A14, 0xC5A10000, /* 44100 */ \
+ 0x3CF2862F, 0x3CF27762, 0xC80D0000, /* 32000 */ \
+ 0x3B858918, 0x3B8572B0, 0xCC290000, /* 24000 */ \
+ 0x3B3989B5, 0x3B397298, 0xCC290000, /* 22050 */ \
+ 0x399D8D10, 0x399D6E40, 0xCF8F0000, /* 16000 */ \
+ }
+
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_183 \
+ { \
+ /* filter 0 */ \
+ 0x3DEB8434, 0x3DEB7D5D, 0xC2890000, /* 48000 */ \
+ 0x3DC7847D, 0x3DC77CB5, 0xC3290000, /* 44100 */ \
+ 0x3CF3862F, 0x3CF37BFC, 0xC3C80000, /* 32000 */ \
+ 0x3B868918, 0x3B867A93, 0xC5050000, /* 24000 */ \
+ 0x3B3A89B5, 0x3B3A793E, 0xC63D0000, /* 22050 */ \
+ 0x399E8D10, 0x399E765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3DEB8434, 0x3DEB7A1B, 0xC5A10000, /* 48000 */ \
+ 0x3DC7847D, 0x3DC77A14, 0xC5A10000, /* 44100 */ \
+ 0x3CF3862F, 0x3CF37762, 0xC80D0000, /* 32000 */ \
+ 0x3B868918, 0x3B8672B0, 0xCC290000, /* 24000 */ \
+ 0x3B3A89B5, 0x3B3A7298, 0xCC290000, /* 22050 */ \
+ 0x399E8D10, 0x399E6E40, 0xCF8F0000, /* 16000 */ \
+ }
+
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_186 \
+ { \
+ /* filter 0 */ \
+ 0x3DEB8434, 0x3DEB7D5D, 0xC2890000, /* 48000 */ \
+ 0x3DC7847D, 0x3DC77CB5, 0xC3290000, /* 44100 */ \
+ 0x3CF3862F, 0x3CF37BFC, 0xC3C80000, /* 32000 */ \
+ 0x3B868918, 0x3B867A93, 0xC5050000, /* 24000 */ \
+ 0x3B3B89B5, 0x3B3B793E, 0xC63D0000, /* 22050 */ \
+ 0x399F8D10, 0x399F765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3DEB8434, 0x3DEB7A1B, 0xC5A10000, /* 48000 */ \
+ 0x3DC7847D, 0x3DC77A14, 0xC5A10000, /* 44100 */ \
+ 0x3CF3862F, 0x3CF37762, 0xC80D0000, /* 32000 */ \
+ 0x3B868918, 0x3B8672B0, 0xCC290000, /* 24000 */ \
+ 0x3B3B89B5, 0x3B3B7298, 0xCC290000, /* 22050 */ \
+ 0x399F8D10, 0x399F6E40, 0xCF8F0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_189 \
+ { \
+ /* filter 0 */ \
+ 0x3DEB8434, 0x3DEB7D5D, 0xC2890000, /* 48000 */ \
+ 0x3DC7847D, 0x3DC77CB5, 0xC3290000, /* 44100 */ \
+ 0x3CF3862F, 0x3CF37BFC, 0xC3C80000, /* 32000 */ \
+ 0x3B878918, 0x3B877A93, 0xC5050000, /* 24000 */ \
+ 0x3B3C89B5, 0x3B3C793E, 0xC63D0000, /* 22050 */ \
+ 0x39A18D10, 0x39A1765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3DEB8434, 0x3DEB7A1B, 0xC5A10000, /* 48000 */ \
+ 0x3DC7847D, 0x3DC77A14, 0xC5A10000, /* 44100 */ \
+ 0x3CF3862F, 0x3CF37762, 0xC80D0000, /* 32000 */ \
+ 0x3B878918, 0x3B8772B0, 0xCC290000, /* 24000 */ \
+ 0x3B3C89B5, 0x3B3C7298, 0xCC290000, /* 22050 */ \
+ 0x39A18D10, 0x39A16E40, 0xCF8F0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_192 \
+ { \
+ /* filter 0 */ \
+ 0x3E1083EB, 0x3E107D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE38446, 0x3DE37CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1885E7, 0x3D187BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C4A8794, 0x3C4A7A93, 0xC5050000, /* 24000 */ \
+ 0x3BD1888B, 0x3BD1793E, 0xC63D0000, /* 22050 */ \
+ 0x3A338BEF, 0x3A33765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1083EB, 0x3E107ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE38446, 0x3DE37AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1885E7, 0x3D187805, 0xC7730000, /* 32000 */ \
+ 0x3C4A8794, 0x3C4A75E0, 0xC93D0000, /* 24000 */ \
+ 0x3BD1888B, 0x3BD17524, 0xC9D50000, /* 22050 */ \
+ 0x3A338BEF, 0x3A3370C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_195 \
+ { \
+ /* filter 0 */ \
+ 0x3E1083EB, 0x3E107D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE38446, 0x3DE37CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1885E7, 0x3D187BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C4A8794, 0x3C4A7A93, 0xC5050000, /* 24000 */ \
+ 0x3BD2888B, 0x3BD2793E, 0xC63D0000, /* 22050 */ \
+ 0x3A348BEF, 0x3A34765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1083EB, 0x3E107ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE38446, 0x3DE37AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1885E7, 0x3D187805, 0xC7730000, /* 32000 */ \
+ 0x3C4A8794, 0x3C4A75E0, 0xC93D0000, /* 24000 */ \
+ 0x3BD2888B, 0x3BD27524, 0xC9D50000, /* 22050 */ \
+ 0x3A348BEF, 0x3A3470C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_198 \
+ { \
+ /* filter 0 */ \
+ 0x3E1083EB, 0x3E107D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE38446, 0x3DE37CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1885E7, 0x3D187BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C4B8794, 0x3C4B7A93, 0xC5050000, /* 24000 */ \
+ 0x3BD3888B, 0x3BD3793E, 0xC63D0000, /* 22050 */ \
+ 0x3A368BEF, 0x3A36765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1083EB, 0x3E107ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE38446, 0x3DE37AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1885E7, 0x3D187805, 0xC7730000, /* 32000 */ \
+ 0x3C4B8794, 0x3C4B75E0, 0xC93D0000, /* 24000 */ \
+ 0x3BD3888B, 0x3BD37524, 0xC9D50000, /* 22050 */ \
+ 0x3A368BEF, 0x3A3670C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_201 \
+ { \
+ /* filter 0 */ \
+ 0x3E1083EB, 0x3E107D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE38446, 0x3DE37CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1985E7, 0x3D197BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C4C8794, 0x3C4C7A93, 0xC5050000, /* 24000 */ \
+ 0x3BD4888B, 0x3BD4793E, 0xC63D0000, /* 22050 */ \
+ 0x3A378BEF, 0x3A37765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1083EB, 0x3E107ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE38446, 0x3DE37AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1985E7, 0x3D197805, 0xC7730000, /* 32000 */ \
+ 0x3C4C8794, 0x3C4C75E0, 0xC93D0000, /* 24000 */ \
+ 0x3BD4888B, 0x3BD47524, 0xC9D50000, /* 22050 */ \
+ 0x3A378BEF, 0x3A3770C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_204 \
+ { \
+ /* filter 0 */ \
+ 0x3E1083EB, 0x3E107D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE48446, 0x3DE47CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1985E7, 0x3D197BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C4C8794, 0x3C4C7A93, 0xC5050000, /* 24000 */ \
+ 0x3BD4888B, 0x3BD4793E, 0xC63D0000, /* 22050 */ \
+ 0x3A388BEF, 0x3A38765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1083EB, 0x3E107ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE48446, 0x3DE47AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1985E7, 0x3D197805, 0xC7730000, /* 32000 */ \
+ 0x3C4C8794, 0x3C4C75E0, 0xC93D0000, /* 24000 */ \
+ 0x3BD4888B, 0x3BD47524, 0xC9D50000, /* 22050 */ \
+ 0x3A388BEF, 0x3A3870C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_207 \
+ { \
+ /* filter 0 */ \
+ 0x3E1083EB, 0x3E107D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE48446, 0x3DE47CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1A85E7, 0x3D1A7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C4D8794, 0x3C4D7A93, 0xC5050000, /* 24000 */ \
+ 0x3BD5888B, 0x3BD5793E, 0xC63D0000, /* 22050 */ \
+ 0x3A3A8BEF, 0x3A3A765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1083EB, 0x3E107ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE48446, 0x3DE47AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1A85E7, 0x3D1A7805, 0xC7730000, /* 32000 */ \
+ 0x3C4D8794, 0x3C4D75E0, 0xC93D0000, /* 24000 */ \
+ 0x3BD5888B, 0x3BD57524, 0xC9D50000, /* 22050 */ \
+ 0x3A3A8BEF, 0x3A3A70C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_210 \
+ { \
+ /* filter 0 */ \
+ 0x3E1183EB, 0x3E117D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE48446, 0x3DE47CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1A85E7, 0x3D1A7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C4D8794, 0x3C4D7A93, 0xC5050000, /* 24000 */ \
+ 0x3BD6888B, 0x3BD6793E, 0xC63D0000, /* 22050 */ \
+ 0x3A3B8BEF, 0x3A3B765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1183EB, 0x3E117ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE48446, 0x3DE47AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1A85E7, 0x3D1A7805, 0xC7730000, /* 32000 */ \
+ 0x3C4D8794, 0x3C4D75E0, 0xC93D0000, /* 24000 */ \
+ 0x3BD6888B, 0x3BD67524, 0xC9D50000, /* 22050 */ \
+ 0x3A3B8BEF, 0x3A3B70C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_213 \
+ { \
+ /* filter 0 */ \
+ 0x3E1183EB, 0x3E117D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE48446, 0x3DE47CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1A85E7, 0x3D1A7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C4E8794, 0x3C4E7A93, 0xC5050000, /* 24000 */ \
+ 0x3BD7888B, 0x3BD7793E, 0xC63D0000, /* 22050 */ \
+ 0x3A3D8BEF, 0x3A3D765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1183EB, 0x3E117ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE48446, 0x3DE47AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1A85E7, 0x3D1A7805, 0xC7730000, /* 32000 */ \
+ 0x3C4E8794, 0x3C4E75E0, 0xC93D0000, /* 24000 */ \
+ 0x3BD7888B, 0x3BD77524, 0xC9D50000, /* 22050 */ \
+ 0x3A3D8BEF, 0x3A3D70C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_216 \
+ { \
+ /* filter 0 */ \
+ 0x3E1183EB, 0x3E117D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE48446, 0x3DE47CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1B85E7, 0x3D1B7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C4F8794, 0x3C4F7A93, 0xC5050000, /* 24000 */ \
+ 0x3BD7888B, 0x3BD7793E, 0xC63D0000, /* 22050 */ \
+ 0x3A3E8BEF, 0x3A3E765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1183EB, 0x3E117ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE48446, 0x3DE47AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1B85E7, 0x3D1B7805, 0xC7730000, /* 32000 */ \
+ 0x3C4F8794, 0x3C4F75E0, 0xC93D0000, /* 24000 */ \
+ 0x3BD7888B, 0x3BD77524, 0xC9D50000, /* 22050 */ \
+ 0x3A3E8BEF, 0x3A3E70C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_219 \
+ { \
+ /* filter 0 */ \
+ 0x3E1183EB, 0x3E117D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE58446, 0x3DE57CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1B85E7, 0x3D1B7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C508794, 0x3C507A93, 0xC5050000, /* 24000 */ \
+ 0x3BD8888B, 0x3BD8793E, 0xC63D0000, /* 22050 */ \
+ 0x3A408BEF, 0x3A40765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1183EB, 0x3E117ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE58446, 0x3DE57AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1B85E7, 0x3D1B7805, 0xC7730000, /* 32000 */ \
+ 0x3C508794, 0x3C5075E0, 0xC93D0000, /* 24000 */ \
+ 0x3BD8888B, 0x3BD87524, 0xC9D50000, /* 22050 */ \
+ 0x3A408BEF, 0x3A4070C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_222 \
+ { \
+ /* filter 0 */ \
+ 0x3E1183EB, 0x3E117D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE58446, 0x3DE57CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1B85E7, 0x3D1B7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C508794, 0x3C507A93, 0xC5050000, /* 24000 */ \
+ 0x3BD9888B, 0x3BD9793E, 0xC63D0000, /* 22050 */ \
+ 0x3A418BEF, 0x3A41765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1183EB, 0x3E117ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE58446, 0x3DE57AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1B85E7, 0x3D1B7805, 0xC7730000, /* 32000 */ \
+ 0x3C508794, 0x3C5075E0, 0xC93D0000, /* 24000 */ \
+ 0x3BD9888B, 0x3BD97524, 0xC9D50000, /* 22050 */ \
+ 0x3A418BEF, 0x3A4170C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_225 \
+ { \
+ /* filter 0 */ \
+ 0x3E1183EB, 0x3E117D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE58446, 0x3DE57CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1C85E7, 0x3D1C7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C518794, 0x3C517A93, 0xC5050000, /* 24000 */ \
+ 0x3BDA888B, 0x3BDA793E, 0xC63D0000, /* 22050 */ \
+ 0x3A438BEF, 0x3A43765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1183EB, 0x3E117ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE58446, 0x3DE57AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1C85E7, 0x3D1C7805, 0xC7730000, /* 32000 */ \
+ 0x3C518794, 0x3C5175E0, 0xC93D0000, /* 24000 */ \
+ 0x3BDA888B, 0x3BDA7524, 0xC9D50000, /* 22050 */ \
+ 0x3A438BEF, 0x3A4370C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_228 \
+ { \
+ /* filter 0 */ \
+ 0x3E1283EB, 0x3E127D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE58446, 0x3DE57CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1C85E7, 0x3D1C7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C528794, 0x3C527A93, 0xC5050000, /* 24000 */ \
+ 0x3BDB888B, 0x3BDB793E, 0xC63D0000, /* 22050 */ \
+ 0x3A448BEF, 0x3A44765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1283EB, 0x3E127ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE58446, 0x3DE57AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1C85E7, 0x3D1C7805, 0xC7730000, /* 32000 */ \
+ 0x3C528794, 0x3C5275E0, 0xC93D0000, /* 24000 */ \
+ 0x3BDB888B, 0x3BDB7524, 0xC9D50000, /* 22050 */ \
+ 0x3A448BEF, 0x3A4470C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_231 \
+ { \
+ /* filter 0 */ \
+ 0x3E1283EB, 0x3E127D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE58446, 0x3DE57CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1D85E7, 0x3D1D7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C528794, 0x3C527A93, 0xC5050000, /* 24000 */ \
+ 0x3BDC888B, 0x3BDC793E, 0xC63D0000, /* 22050 */ \
+ 0x3A468BEF, 0x3A46765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1283EB, 0x3E127ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE58446, 0x3DE57AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1D85E7, 0x3D1D7805, 0xC7730000, /* 32000 */ \
+ 0x3C528794, 0x3C5275E0, 0xC93D0000, /* 24000 */ \
+ 0x3BDC888B, 0x3BDC7524, 0xC9D50000, /* 22050 */ \
+ 0x3A468BEF, 0x3A4670C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_234 \
+ { \
+ /* filter 0 */ \
+ 0x3E1283EB, 0x3E127D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE68446, 0x3DE67CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1D85E7, 0x3D1D7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C538794, 0x3C537A93, 0xC5050000, /* 24000 */ \
+ 0x3BDC888B, 0x3BDC793E, 0xC63D0000, /* 22050 */ \
+ 0x3A488BEF, 0x3A48765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1283EB, 0x3E127ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE68446, 0x3DE67AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1D85E7, 0x3D1D7805, 0xC7730000, /* 32000 */ \
+ 0x3C538794, 0x3C5375E0, 0xC93D0000, /* 24000 */ \
+ 0x3BDC888B, 0x3BDC7524, 0xC9D50000, /* 22050 */ \
+ 0x3A488BEF, 0x3A4870C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_237 \
+ { \
+ /* filter 0 */ \
+ 0x3E1283EB, 0x3E127D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE68446, 0x3DE67CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1E85E7, 0x3D1E7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C548794, 0x3C547A93, 0xC5050000, /* 24000 */ \
+ 0x3BDD888B, 0x3BDD793E, 0xC63D0000, /* 22050 */ \
+ 0x3A498BEF, 0x3A49765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1283EB, 0x3E127ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE68446, 0x3DE67AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1E85E7, 0x3D1E7805, 0xC7730000, /* 32000 */ \
+ 0x3C548794, 0x3C5475E0, 0xC93D0000, /* 24000 */ \
+ 0x3BDD888B, 0x3BDD7524, 0xC9D50000, /* 22050 */ \
+ 0x3A498BEF, 0x3A4970C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_240 \
+ { \
+ /* filter 0 */ \
+ 0x3E1283EB, 0x3E127D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE68446, 0x3DE67CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1E85E7, 0x3D1E7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C558794, 0x3C557A93, 0xC5050000, /* 24000 */ \
+ 0x3BDE888B, 0x3BDE793E, 0xC63D0000, /* 22050 */ \
+ 0x3A4B8BEF, 0x3A4B765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1283EB, 0x3E127ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE68446, 0x3DE67AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1E85E7, 0x3D1E7805, 0xC7730000, /* 32000 */ \
+ 0x3C558794, 0x3C5575E0, 0xC93D0000, /* 24000 */ \
+ 0x3BDE888B, 0x3BDE7524, 0xC9D50000, /* 22050 */ \
+ 0x3A4B8BEF, 0x3A4B70C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_243 \
+ { \
+ /* filter 0 */ \
+ 0x3E1383EB, 0x3E137D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE68446, 0x3DE67CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1E85E7, 0x3D1E7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C558794, 0x3C557A93, 0xC5050000, /* 24000 */ \
+ 0x3BDF888B, 0x3BDF793E, 0xC63D0000, /* 22050 */ \
+ 0x3A4D8BEF, 0x3A4D765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1383EB, 0x3E137ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE68446, 0x3DE67AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1E85E7, 0x3D1E7805, 0xC7730000, /* 32000 */ \
+ 0x3C558794, 0x3C5575E0, 0xC93D0000, /* 24000 */ \
+ 0x3BDF888B, 0x3BDF7524, 0xC9D50000, /* 22050 */ \
+ 0x3A4D8BEF, 0x3A4D70C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_246 \
+ { \
+ /* filter 0 */ \
+ 0x3E1383EB, 0x3E137D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE78446, 0x3DE77CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1F85E7, 0x3D1F7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C568794, 0x3C567A93, 0xC5050000, /* 24000 */ \
+ 0x3BE0888B, 0x3BE0793E, 0xC63D0000, /* 22050 */ \
+ 0x3A4E8BEF, 0x3A4E765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1383EB, 0x3E137ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE78446, 0x3DE77AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1F85E7, 0x3D1F7805, 0xC7730000, /* 32000 */ \
+ 0x3C568794, 0x3C5675E0, 0xC93D0000, /* 24000 */ \
+ 0x3BE0888B, 0x3BE07524, 0xC9D50000, /* 22050 */ \
+ 0x3A4E8BEF, 0x3A4E70C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_249 \
+ { \
+ /* filter 0 */ \
+ 0x3E1383EB, 0x3E137D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE78446, 0x3DE77CB5, 0xC3290000, /* 44100 */ \
+ 0x3D1F85E7, 0x3D1F7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C578794, 0x3C577A93, 0xC5050000, /* 24000 */ \
+ 0x3BE1888B, 0x3BE1793E, 0xC63D0000, /* 22050 */ \
+ 0x3A478C00, 0x3A47765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1383EB, 0x3E137ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE78446, 0x3DE77AB8, 0xC5050000, /* 44100 */ \
+ 0x3D1F85E7, 0x3D1F7805, 0xC7730000, /* 32000 */ \
+ 0x3C578794, 0x3C5775E0, 0xC93D0000, /* 24000 */ \
+ 0x3BE1888B, 0x3BE17524, 0xC9D50000, /* 22050 */ \
+ 0x3A478C00, 0x3A4770C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_252 \
+ { \
+ /* filter 0 */ \
+ 0x3E1383EB, 0x3E137D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE78446, 0x3DE77CB5, 0xC3290000, /* 44100 */ \
+ 0x3D2085E7, 0x3D207BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C588794, 0x3C587A93, 0xC5050000, /* 24000 */ \
+ 0x3BE2888B, 0x3BE2793E, 0xC63D0000, /* 22050 */ \
+ 0x3A498C00, 0x3A49765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1383EB, 0x3E137ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE78446, 0x3DE77AB8, 0xC5050000, /* 44100 */ \
+ 0x3D2085E7, 0x3D207805, 0xC7730000, /* 32000 */ \
+ 0x3C588794, 0x3C5875E0, 0xC93D0000, /* 24000 */ \
+ 0x3BE2888B, 0x3BE27524, 0xC9D50000, /* 22050 */ \
+ 0x3A498C00, 0x3A4970C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_255 \
+ { \
+ /* filter 0 */ \
+ 0x3E1383EB, 0x3E137D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE78446, 0x3DE77CB5, 0xC3290000, /* 44100 */ \
+ 0x3D2085E7, 0x3D207BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C598794, 0x3C597A93, 0xC5050000, /* 24000 */ \
+ 0x3BE3888B, 0x3BE3793E, 0xC63D0000, /* 22050 */ \
+ 0x3A4B8C00, 0x3A4B765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1383EB, 0x3E137ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE78446, 0x3DE77AB8, 0xC5050000, /* 44100 */ \
+ 0x3D2085E7, 0x3D207805, 0xC7730000, /* 32000 */ \
+ 0x3C598794, 0x3C5975E0, 0xC93D0000, /* 24000 */ \
+ 0x3BE3888B, 0x3BE37524, 0xC9D50000, /* 22050 */ \
+ 0x3A4B8C00, 0x3A4B70C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_258 \
+ { \
+ /* filter 0 */ \
+ 0x3E1483EB, 0x3E147D5D, 0xC2890000, /* 48000 */ \
+ 0x3DE88446, 0x3DE87CB5, 0xC3290000, /* 44100 */ \
+ 0x3D2185E7, 0x3D217BFC, 0xC3C80000, /* 32000 */ \
+ 0x3C598794, 0x3C597A93, 0xC5050000, /* 24000 */ \
+ 0x3BE4888B, 0x3BE4793E, 0xC63D0000, /* 22050 */ \
+ 0x3A4D8C00, 0x3A4D765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E1483EB, 0x3E147ABE, 0xC5050000, /* 48000 */ \
+ 0x3DE88446, 0x3DE87AB8, 0xC5050000, /* 44100 */ \
+ 0x3D2185E7, 0x3D217805, 0xC7730000, /* 32000 */ \
+ 0x3C598794, 0x3C5975E0, 0xC93D0000, /* 24000 */ \
+ 0x3BE4888B, 0x3BE47524, 0xC9D50000, /* 22050 */ \
+ 0x3A4D8C00, 0x3A4D70C9, 0xCD4E0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_261 \
+ { \
+ /* filter 0 */ \
+ 0x3E798321, 0x3E797D5D, 0xC2890000, /* 48000 */ \
+ 0x3E56836B, 0x3E567CB5, 0xC3290000, /* 44100 */ \
+ 0x3DBB84B3, 0x3DBB7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3CFB8653, 0x3CFB7A93, 0xC5050000, /* 24000 */ \
+ 0x3CA88705, 0x3CA8793E, 0xC63D0000, /* 22050 */ \
+ 0x3B7E89A3, 0x3B7E765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E798321, 0x3E797C68, 0xC3690000, /* 48000 */ \
+ 0x3E56836B, 0x3E567C61, 0xC3690000, /* 44100 */ \
+ 0x3DBB84B3, 0x3DBB7A93, 0xC5050000, /* 32000 */ \
+ 0x3CFB8653, 0x3CFB786C, 0xC6D90000, /* 24000 */ \
+ 0x3CA88705, 0x3CA87853, 0xC6D90000, /* 22050 */ \
+ 0x3B7E89A3, 0x3B7E75DA, 0xC8A50000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_264 \
+ { \
+ /* filter 0 */ \
+ 0x3E798321, 0x3E797D5D, 0xC2890000, /* 48000 */ \
+ 0x3E56836B, 0x3E567CB5, 0xC3290000, /* 44100 */ \
+ 0x3DBC84B3, 0x3DBC7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3CFC8653, 0x3CFC7A93, 0xC5050000, /* 24000 */ \
+ 0x3CA98705, 0x3CA9793E, 0xC63D0000, /* 22050 */ \
+ 0x3B8089A3, 0x3B80765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E798321, 0x3E797C68, 0xC3690000, /* 48000 */ \
+ 0x3E56836B, 0x3E567C61, 0xC3690000, /* 44100 */ \
+ 0x3DBC84B3, 0x3DBC7A93, 0xC5050000, /* 32000 */ \
+ 0x3CFC8653, 0x3CFC786C, 0xC6D90000, /* 24000 */ \
+ 0x3CA98705, 0x3CA97853, 0xC6D90000, /* 22050 */ \
+ 0x3B8089A3, 0x3B8075DA, 0xC8A50000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_267 \
+ { \
+ /* filter 0 */ \
+ 0x3E798321, 0x3E797D5D, 0xC2890000, /* 48000 */ \
+ 0x3E56836B, 0x3E567CB5, 0xC3290000, /* 44100 */ \
+ 0x3DBC84B3, 0x3DBC7BFC, 0xC3C80000, /* 32000 */ \
+ 0x3CFD8653, 0x3CFD7A93, 0xC5050000, /* 24000 */ \
+ 0x3CAA8705, 0x3CAA793E, 0xC63D0000, /* 22050 */ \
+ 0x3B8289A3, 0x3B82765F, 0xC8A50000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E798321, 0x3E797C68, 0xC3690000, /* 48000 */ \
+ 0x3E56836B, 0x3E567C61, 0xC3690000, /* 44100 */ \
+ 0x3DBC84B3, 0x3DBC7A93, 0xC5050000, /* 32000 */ \
+ 0x3CFD8653, 0x3CFD786C, 0xC6D90000, /* 24000 */ \
+ 0x3CAA8705, 0x3CAA7853, 0xC6D90000, /* 22050 */ \
+ 0x3B8289A3, 0x3B8275DA, 0xC8A50000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_270 \
+ { \
+ /* filter 0 */ \
+ 0x3E42838F, 0x3E427DFC, 0xC1E80000, /* 48000 */ \
+ 0x3DF28434, 0x3DF27CB0, 0xC3290000, /* 44100 */ \
+ 0x3D3585C3, 0x3D357B90, 0xC4280000, /* 32000 */ \
+ 0x3C5487A5, 0x3C5479DD, 0xC5A10000, /* 24000 */ \
+ 0x3BDF889D, 0x3BDF7885, 0xC6D90000, /* 22050 */ \
+ 0x3A6E8BCD, 0x3A6E7594, 0xC93D0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E42838F, 0x3E427AB6, 0xC5050000, /* 48000 */ \
+ 0x3DF28434, 0x3DF27AAE, 0xC5050000, /* 44100 */ \
+ 0x3D3585C3, 0x3D357896, 0xC6D90000, /* 32000 */ \
+ 0x3C5487A5, 0x3C547663, 0xC8A50000, /* 24000 */ \
+ 0x3BDF889D, 0x3BDF75A2, 0xC93D0000, /* 22050 */ \
+ 0x3A6E8BCD, 0x3A6E71C8, 0xCC290000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_273 \
+ { \
+ /* filter 0 */ \
+ 0x3E43838F, 0x3E437DFC, 0xC1E80000, /* 48000 */ \
+ 0x3DF28434, 0x3DF27CB0, 0xC3290000, /* 44100 */ \
+ 0x3D3585C3, 0x3D357B90, 0xC4280000, /* 32000 */ \
+ 0x3C5587A5, 0x3C5579DD, 0xC5A10000, /* 24000 */ \
+ 0x3BE0889D, 0x3BE07885, 0xC6D90000, /* 22050 */ \
+ 0x3A708BCD, 0x3A707594, 0xC93D0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E43838F, 0x3E437AB6, 0xC5050000, /* 48000 */ \
+ 0x3DF28434, 0x3DF27AAE, 0xC5050000, /* 44100 */ \
+ 0x3D3585C3, 0x3D357896, 0xC6D90000, /* 32000 */ \
+ 0x3C5587A5, 0x3C557663, 0xC8A50000, /* 24000 */ \
+ 0x3BE0889D, 0x3BE075A2, 0xC93D0000, /* 22050 */ \
+ 0x3A708BCD, 0x3A7071C8, 0xCC290000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_276 \
+ { \
+ /* filter 0 */ \
+ 0x3E43838F, 0x3E437DFC, 0xC1E80000, /* 48000 */ \
+ 0x3DF28434, 0x3DF27CB0, 0xC3290000, /* 44100 */ \
+ 0x3D3685C3, 0x3D367B90, 0xC4280000, /* 32000 */ \
+ 0x3C5687A5, 0x3C5679DD, 0xC5A10000, /* 24000 */ \
+ 0x3BE1889D, 0x3BE17885, 0xC6D90000, /* 22050 */ \
+ 0x3A728BCD, 0x3A727594, 0xC93D0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E43838F, 0x3E437AB6, 0xC5050000, /* 48000 */ \
+ 0x3DF28434, 0x3DF27AAE, 0xC5050000, /* 44100 */ \
+ 0x3D3685C3, 0x3D367896, 0xC6D90000, /* 32000 */ \
+ 0x3C5687A5, 0x3C567663, 0xC8A50000, /* 24000 */ \
+ 0x3BE1889D, 0x3BE175A2, 0xC93D0000, /* 22050 */ \
+ 0x3A728BCD, 0x3A7271C8, 0xCC290000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_279 \
+ { \
+ /* filter 0 */ \
+ 0x3E43838F, 0x3E437DFC, 0xC1E80000, /* 48000 */ \
+ 0x3DF38434, 0x3DF37CB0, 0xC3290000, /* 44100 */ \
+ 0x3D3685C3, 0x3D367B90, 0xC4280000, /* 32000 */ \
+ 0x3C5687A5, 0x3C5679DD, 0xC5A10000, /* 24000 */ \
+ 0x3BE2889D, 0x3BE27885, 0xC6D90000, /* 22050 */ \
+ 0x3A6B8BDE, 0x3A6B7594, 0xC93D0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E43838F, 0x3E437AB6, 0xC5050000, /* 48000 */ \
+ 0x3DF38434, 0x3DF37AAE, 0xC5050000, /* 44100 */ \
+ 0x3D3685C3, 0x3D367896, 0xC6D90000, /* 32000 */ \
+ 0x3C5687A5, 0x3C567663, 0xC8A50000, /* 24000 */ \
+ 0x3BE2889D, 0x3BE275A2, 0xC93D0000, /* 22050 */ \
+ 0x3A6B8BDE, 0x3A6B71C8, 0xCC290000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_282 \
+ { \
+ /* filter 0 */ \
+ 0x3E43838F, 0x3E437DFC, 0xC1E80000, /* 48000 */ \
+ 0x3DF38434, 0x3DF37CB0, 0xC3290000, /* 44100 */ \
+ 0x3D3785C3, 0x3D377B90, 0xC4280000, /* 32000 */ \
+ 0x3C5787A5, 0x3C5779DD, 0xC5A10000, /* 24000 */ \
+ 0x3BDA88AE, 0x3BDA7885, 0xC6D90000, /* 22050 */ \
+ 0x3A6D8BDE, 0x3A6D7594, 0xC93D0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E43838F, 0x3E437AB6, 0xC5050000, /* 48000 */ \
+ 0x3DF38434, 0x3DF37AAE, 0xC5050000, /* 44100 */ \
+ 0x3D3785C3, 0x3D377896, 0xC6D90000, /* 32000 */ \
+ 0x3C5787A5, 0x3C577663, 0xC8A50000, /* 24000 */ \
+ 0x3BDA88AE, 0x3BDA75A2, 0xC93D0000, /* 22050 */ \
+ 0x3A6D8BDE, 0x3A6D71C8, 0xCC290000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_285 \
+ { \
+ /* filter 0 */ \
+ 0x3E44838F, 0x3E447DFC, 0xC1E80000, /* 48000 */ \
+ 0x3DF38434, 0x3DF37CB0, 0xC3290000, /* 44100 */ \
+ 0x3D3785C3, 0x3D377B90, 0xC4280000, /* 32000 */ \
+ 0x3C5887A5, 0x3C5879DD, 0xC5A10000, /* 24000 */ \
+ 0x3BDB88AE, 0x3BDB7885, 0xC6D90000, /* 22050 */ \
+ 0x3A6F8BDE, 0x3A6F7594, 0xC93D0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E44838F, 0x3E447AB6, 0xC5050000, /* 48000 */ \
+ 0x3DF38434, 0x3DF37AAE, 0xC5050000, /* 44100 */ \
+ 0x3D3785C3, 0x3D377896, 0xC6D90000, /* 32000 */ \
+ 0x3C5887A5, 0x3C587663, 0xC8A50000, /* 24000 */ \
+ 0x3BDB88AE, 0x3BDB75A2, 0xC93D0000, /* 22050 */ \
+ 0x3A6F8BDE, 0x3A6F71C8, 0xCC290000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_288 \
+ { \
+ /* filter 0 */ \
+ 0x3E44838F, 0x3E447DFC, 0xC1E80000, /* 48000 */ \
+ 0x3DF38434, 0x3DF37CB0, 0xC3290000, /* 44100 */ \
+ 0x3D3885C3, 0x3D387B90, 0xC4280000, /* 32000 */ \
+ 0x3C5987A5, 0x3C5979DD, 0xC5A10000, /* 24000 */ \
+ 0x3BDC88AE, 0x3BDC7885, 0xC6D90000, /* 22050 */ \
+ 0x3A718BDE, 0x3A717594, 0xC93D0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E44838F, 0x3E447AB6, 0xC5050000, /* 48000 */ \
+ 0x3DF38434, 0x3DF37AAE, 0xC5050000, /* 44100 */ \
+ 0x3D3885C3, 0x3D387896, 0xC6D90000, /* 32000 */ \
+ 0x3C5987A5, 0x3C597663, 0xC8A50000, /* 24000 */ \
+ 0x3BDC88AE, 0x3BDC75A2, 0xC93D0000, /* 22050 */ \
+ 0x3A718BDE, 0x3A7171C8, 0xCC290000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_291 \
+ { \
+ /* filter 0 */ \
+ 0x3E44838F, 0x3E447DFC, 0xC1E80000, /* 48000 */ \
+ 0x3DF48434, 0x3DF47CB0, 0xC3290000, /* 44100 */ \
+ 0x3D3885C3, 0x3D387B90, 0xC4280000, /* 32000 */ \
+ 0x3C5A87A5, 0x3C5A79DD, 0xC5A10000, /* 24000 */ \
+ 0x3BDE88AE, 0x3BDE7885, 0xC6D90000, /* 22050 */ \
+ 0x3A738BDE, 0x3A737594, 0xC93D0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E44838F, 0x3E447AB6, 0xC5050000, /* 48000 */ \
+ 0x3DF48434, 0x3DF47AAE, 0xC5050000, /* 44100 */ \
+ 0x3D3885C3, 0x3D387896, 0xC6D90000, /* 32000 */ \
+ 0x3C5A87A5, 0x3C5A7663, 0xC8A50000, /* 24000 */ \
+ 0x3BDE88AE, 0x3BDE75A2, 0xC93D0000, /* 22050 */ \
+ 0x3A738BDE, 0x3A7371C8, 0xCC290000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_294 \
+ { \
+ /* filter 0 */ \
+ 0x3E44838F, 0x3E447DFC, 0xC1E80000, /* 48000 */ \
+ 0x3DF48434, 0x3DF47CB0, 0xC3290000, /* 44100 */ \
+ 0x3D3985C3, 0x3D397B90, 0xC4280000, /* 32000 */ \
+ 0x3C5B87A5, 0x3C5B79DD, 0xC5A10000, /* 24000 */ \
+ 0x3BDF88AE, 0x3BDF7885, 0xC6D90000, /* 22050 */ \
+ 0x3A758BDE, 0x3A757594, 0xC93D0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E44838F, 0x3E447AB6, 0xC5050000, /* 48000 */ \
+ 0x3DF48434, 0x3DF47AAE, 0xC5050000, /* 44100 */ \
+ 0x3D3985C3, 0x3D397896, 0xC6D90000, /* 32000 */ \
+ 0x3C5B87A5, 0x3C5B7663, 0xC8A50000, /* 24000 */ \
+ 0x3BDF88AE, 0x3BDF75A2, 0xC93D0000, /* 22050 */ \
+ 0x3A758BDE, 0x3A7571C8, 0xCC290000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_297 \
+ { \
+ /* filter 0 */ \
+ 0x3E698346, 0x3E697E3D, 0xC1A70000, /* 48000 */ \
+ 0x3E2283D9, 0x3E227D12, 0xC2C90000, /* 44100 */ \
+ 0x3D5D857B, 0x3D5D7BD1, 0xC3E80000, /* 32000 */ \
+ 0x3C778770, 0x3C777A1E, 0xC5630000, /* 24000 */ \
+ 0x3C038868, 0x3C0378C6, 0xC69B0000, /* 22050 */ \
+ 0x3A918BAA, 0x3A9175D5, 0xC9010000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E698346, 0x3E697B18, 0xC4A60000, /* 48000 */ \
+ 0x3E2283D9, 0x3E227B10, 0xC4A60000, /* 44100 */ \
+ 0x3D5D857B, 0x3D5D78F8, 0xC67C0000, /* 32000 */ \
+ 0x3C778770, 0x3C7776A4, 0xC8680000, /* 24000 */ \
+ 0x3C038868, 0x3C0375E3, 0xC9010000, /* 22050 */ \
+ 0x3A918BAA, 0x3A917209, 0xCBEE0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_300 \
+ { \
+ /* filter 0 */ \
+ 0x3E698346, 0x3E697E3D, 0xC1A70000, /* 48000 */ \
+ 0x3E2283D9, 0x3E227D12, 0xC2C90000, /* 44100 */ \
+ 0x3D5E857B, 0x3D5E7BD1, 0xC3E80000, /* 32000 */ \
+ 0x3C788770, 0x3C787A1E, 0xC5630000, /* 24000 */ \
+ 0x3C048868, 0x3C0478C6, 0xC69B0000, /* 22050 */ \
+ 0x3A938BAA, 0x3A9375D5, 0xC9010000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E698346, 0x3E697B18, 0xC4A60000, /* 48000 */ \
+ 0x3E2283D9, 0x3E227B10, 0xC4A60000, /* 44100 */ \
+ 0x3D5E857B, 0x3D5E78F8, 0xC67C0000, /* 32000 */ \
+ 0x3C788770, 0x3C7876A4, 0xC8680000, /* 24000 */ \
+ 0x3C048868, 0x3C0475E3, 0xC9010000, /* 22050 */ \
+ 0x3A938BAA, 0x3A937209, 0xCBEE0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_303 \
+ { \
+ /* filter 0 */ \
+ 0x3E6A8346, 0x3E6A7E3D, 0xC1A70000, /* 48000 */ \
+ 0x3E2383D9, 0x3E237D12, 0xC2C90000, /* 44100 */ \
+ 0x3D5E857B, 0x3D5E7BD1, 0xC3E80000, /* 32000 */ \
+ 0x3C798770, 0x3C797A1E, 0xC5630000, /* 24000 */ \
+ 0x3C058868, 0x3C0578C6, 0xC69B0000, /* 22050 */ \
+ 0x3A958BAA, 0x3A9575D5, 0xC9010000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E6A8346, 0x3E6A7B18, 0xC4A60000, /* 48000 */ \
+ 0x3E2383D9, 0x3E237B10, 0xC4A60000, /* 44100 */ \
+ 0x3D5E857B, 0x3D5E78F8, 0xC67C0000, /* 32000 */ \
+ 0x3C798770, 0x3C7976A4, 0xC8680000, /* 24000 */ \
+ 0x3C058868, 0x3C0575E3, 0xC9010000, /* 22050 */ \
+ 0x3A958BAA, 0x3A957209, 0xCBEE0000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_306 \
+ { \
+ /* filter 0 */ \
+ 0x3E3383B4, 0x3E337CF6, 0xC2E90000, /* 48000 */ \
+ 0x3E7F8321, 0x3E7F7D95, 0xC2490000, /* 44100 */ \
+ 0x3DC384B3, 0x3DC37C75, 0xC3490000, /* 32000 */ \
+ 0x3D098653, 0x3D097AC2, 0xC4C60000, /* 24000 */ \
+ 0x3CCA86E2, 0x3CCA798A, 0xC5E00000, /* 22050 */ \
+ 0x3BD1893B, 0x3BD17860, 0xC69B0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E3383B4, 0x3E337B9B, 0xC4280000, /* 48000 */ \
+ 0x3E7F8321, 0x3E7F7C16, 0xC3A80000, /* 44100 */ \
+ 0x3DC384B3, 0x3DC379FE, 0xC5820000, /* 32000 */ \
+ 0x3D098653, 0x3D09784C, 0xC6D90000, /* 24000 */ \
+ 0x3CCA86E2, 0x3CCA786E, 0xC69B0000, /* 22050 */ \
+ 0x3BD1893B, 0x3BD17490, 0xC9980000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_309 \
+ { \
+ /* filter 0 */ \
+ 0x3E3383B4, 0x3E337CF6, 0xC2E90000, /* 48000 */ \
+ 0x3E7F8321, 0x3E7F7D95, 0xC2490000, /* 44100 */ \
+ 0x3DC384B3, 0x3DC37C75, 0xC3490000, /* 32000 */ \
+ 0x3D0A8653, 0x3D0A7AC2, 0xC4C60000, /* 24000 */ \
+ 0x3CCB86E2, 0x3CCB798A, 0xC5E00000, /* 22050 */ \
+ 0x3BD3893B, 0x3BD37860, 0xC69B0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E3383B4, 0x3E337B9B, 0xC4280000, /* 48000 */ \
+ 0x3E7F8321, 0x3E7F7C16, 0xC3A80000, /* 44100 */ \
+ 0x3DC384B3, 0x3DC379FE, 0xC5820000, /* 32000 */ \
+ 0x3D0A8653, 0x3D0A784C, 0xC6D90000, /* 24000 */ \
+ 0x3CCB86E2, 0x3CCB786E, 0xC69B0000, /* 22050 */ \
+ 0x3BD3893B, 0x3BD37490, 0xC9980000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_312 \
+ { \
+ /* filter 0 */ \
+ 0x3E3383B4, 0x3E337CF6, 0xC2E90000, /* 48000 */ \
+ 0x3E7F8321, 0x3E7F7D95, 0xC2490000, /* 44100 */ \
+ 0x3DC484B3, 0x3DC47C75, 0xC3490000, /* 32000 */ \
+ 0x3D0B8653, 0x3D0B7AC2, 0xC4C60000, /* 24000 */ \
+ 0x3CCD86E2, 0x3CCD798A, 0xC5E00000, /* 22050 */ \
+ 0x3BD5893B, 0x3BD57860, 0xC69B0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E3383B4, 0x3E337B9B, 0xC4280000, /* 48000 */ \
+ 0x3E7F8321, 0x3E7F7C16, 0xC3A80000, /* 44100 */ \
+ 0x3DC484B3, 0x3DC479FE, 0xC5820000, /* 32000 */ \
+ 0x3D0B8653, 0x3D0B784C, 0xC6D90000, /* 24000 */ \
+ 0x3CCD86E2, 0x3CCD786E, 0xC69B0000, /* 22050 */ \
+ 0x3BD5893B, 0x3BD57490, 0xC9980000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_315 \
+ { \
+ /* filter 0 */ \
+ 0x3E7D8321, 0x3E7D7D99, 0xC2490000, /* 48000 */ \
+ 0x3E808321, 0x3E807D95, 0xC2490000, /* 44100 */ \
+ 0x3DC584B3, 0x3DC57C75, 0xC3490000, /* 32000 */ \
+ 0x3D0C8653, 0x3D0C7AC2, 0xC4C60000, /* 24000 */ \
+ 0x3CCE86E2, 0x3CCE798A, 0xC5E00000, /* 22050 */ \
+ 0x3BD8893B, 0x3BD87860, 0xC69B0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E7D8321, 0x3E7D7C1E, 0xC3A80000, /* 48000 */ \
+ 0x3E808321, 0x3E807C16, 0xC3A80000, /* 44100 */ \
+ 0x3DC584B3, 0x3DC579FE, 0xC5820000, /* 32000 */ \
+ 0x3D0C8653, 0x3D0C784C, 0xC6D90000, /* 24000 */ \
+ 0x3CCE86E2, 0x3CCE786E, 0xC69B0000, /* 22050 */ \
+ 0x3BD8893B, 0x3BD87490, 0xC9980000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_318 \
+ { \
+ /* filter 0 */ \
+ 0x3E7D8321, 0x3E7D7D99, 0xC2490000, /* 48000 */ \
+ 0x3E808321, 0x3E807D95, 0xC2490000, /* 44100 */ \
+ 0x3DC584B3, 0x3DC57C75, 0xC3490000, /* 32000 */ \
+ 0x3D0D8653, 0x3D0D7AC2, 0xC4C60000, /* 24000 */ \
+ 0x3CCF86E2, 0x3CCF798A, 0xC5E00000, /* 22050 */ \
+ 0x3BD1894C, 0x3BD17860, 0xC69B0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E7D8321, 0x3E7D7C1E, 0xC3A80000, /* 48000 */ \
+ 0x3E808321, 0x3E807C16, 0xC3A80000, /* 44100 */ \
+ 0x3DC584B3, 0x3DC579FE, 0xC5820000, /* 32000 */ \
+ 0x3D0D8653, 0x3D0D784C, 0xC6D90000, /* 24000 */ \
+ 0x3CCF86E2, 0x3CCF786E, 0xC69B0000, /* 22050 */ \
+ 0x3BD1894C, 0x3BD17490, 0xC9980000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_321 \
+ { \
+ /* filter 0 */ \
+ 0x3E7E8321, 0x3E7E7D99, 0xC2490000, /* 48000 */ \
+ 0x3E808321, 0x3E807D95, 0xC2490000, /* 44100 */ \
+ 0x3DC684B3, 0x3DC67C75, 0xC3490000, /* 32000 */ \
+ 0x3D0E8653, 0x3D0E7AC2, 0xC4C60000, /* 24000 */ \
+ 0x3CD086E2, 0x3CD0798A, 0xC5E00000, /* 22050 */ \
+ 0x3BD3894C, 0x3BD37860, 0xC69B0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E7E8321, 0x3E7E7C1E, 0xC3A80000, /* 48000 */ \
+ 0x3E808321, 0x3E807C16, 0xC3A80000, /* 44100 */ \
+ 0x3DC684B3, 0x3DC679FE, 0xC5820000, /* 32000 */ \
+ 0x3D0E8653, 0x3D0E784C, 0xC6D90000, /* 24000 */ \
+ 0x3CD086E2, 0x3CD0786E, 0xC69B0000, /* 22050 */ \
+ 0x3BD3894C, 0x3BD37490, 0xC9980000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_324 \
+ { \
+ /* filter 0 */ \
+ 0x3E7E8321, 0x3E7E7D99, 0xC2490000, /* 48000 */ \
+ 0x3E808321, 0x3E807D95, 0xC2490000, /* 44100 */ \
+ 0x3DC684B3, 0x3DC67C75, 0xC3490000, /* 32000 */ \
+ 0x3D068665, 0x3D067AC2, 0xC4C60000, /* 24000 */ \
+ 0x3CD186E2, 0x3CD1798A, 0xC5E00000, /* 22050 */ \
+ 0x3BD6894C, 0x3BD67860, 0xC69B0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E7E8321, 0x3E7E7C1E, 0xC3A80000, /* 48000 */ \
+ 0x3E808321, 0x3E807C16, 0xC3A80000, /* 44100 */ \
+ 0x3DC684B3, 0x3DC679FE, 0xC5820000, /* 32000 */ \
+ 0x3D068665, 0x3D06784C, 0xC6D90000, /* 24000 */ \
+ 0x3CD186E2, 0x3CD1786E, 0xC69B0000, /* 22050 */ \
+ 0x3BD6894C, 0x3BD67490, 0xC9980000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_327 \
+ { \
+ /* filter 0 */ \
+ 0x3E7E8321, 0x3E7E7D99, 0xC2490000, /* 48000 */ \
+ 0x3E818321, 0x3E817D95, 0xC2490000, /* 44100 */ \
+ 0x3DC784B3, 0x3DC77C75, 0xC3490000, /* 32000 */ \
+ 0x3D078665, 0x3D077AC2, 0xC4C60000, /* 24000 */ \
+ 0x3CD386E2, 0x3CD3798A, 0xC5E00000, /* 22050 */ \
+ 0x3BD8894C, 0x3BD87860, 0xC69B0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E7E8321, 0x3E7E7C1E, 0xC3A80000, /* 48000 */ \
+ 0x3E818321, 0x3E817C16, 0xC3A80000, /* 44100 */ \
+ 0x3DC784B3, 0x3DC779FE, 0xC5820000, /* 32000 */ \
+ 0x3D078665, 0x3D07784C, 0xC6D90000, /* 24000 */ \
+ 0x3CD386E2, 0x3CD3786E, 0xC69B0000, /* 22050 */ \
+ 0x3BD8894C, 0x3BD87490, 0xC9980000, /* 16000 */ \
+ }
+
+#define DEFAULT_AUD_VIBR_LOUDNESS_FILTER_COEF_330 \
+ { \
+ /* filter 0 */ \
+ 0x3E7E8321, 0x3E7E7D99, 0xC2490000, /* 48000 */ \
+ 0x3E818321, 0x3E817D95, 0xC2490000, /* 44100 */ \
+ 0x3DC784B3, 0x3DC77C75, 0xC3490000, /* 32000 */ \
+ 0x3D088665, 0x3D087AC2, 0xC4C60000, /* 24000 */ \
+ 0x3CD486E2, 0x3CD4798A, 0xC5E00000, /* 22050 */ \
+ 0x3BDA894C, 0x3BDA7860, 0xC69B0000, /* 16000 */ \
+ /* filter 1 */ \
+ 0x3E7E8321, 0x3E7E7C1E, 0xC3A80000, /* 48000 */ \
+ 0x3E818321, 0x3E817C16, 0xC3A80000, /* 44100 */ \
+ 0x3DC784B3, 0x3DC779FE, 0xC5820000, /* 32000 */ \
+ 0x3D088665, 0x3D08784C, 0xC6D90000, /* 24000 */ \
+ 0x3CD486E2, 0x3CD4786E, 0xC69B0000, /* 22050 */ \
+ 0x3BDA894C, 0x3BDA7490, 0xC9980000, /* 16000 */ \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_141 \
+ { \
+ -7708, 15855, 7980, -15936, 7980, -7788, 15939, 8180, -16337, 8180, \
+ -7948, 16104, 8190, -16353, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_144 \
+ { \
+ -7708, 15855, 7980, -15935, 7980, -7788, 15939, 8180, -16336, 8180, \
+ -7948, 16104, 8190, -16352, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_147 \
+ { \
+ -7708, 15855, 7980, -15934, 7980, -7788, 15939, 8180, -16335, 8180, \
+ -7948, 16104, 8190, -16351, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_150 \
+ { \
+ -7708, 15855, 7980, -15933, 7980, -7788, 15939, 8180, -16334, 8180, \
+ -7948, 16104, 8190, -16350, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_153 \
+ { \
+ -7708, 15855, 7980, -15931, 7980, -7788, 15939, 8180, -16332, 8180, \
+ -7948, 16104, 8190, -16348, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_156 \
+ { \
+ -7708, 15854, 7980, -15930, 7980, -7788, 15938, 8180, -16331, 8180, \
+ -7948, 16104, 8190, -16347, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_159 \
+ { \
+ -7708, 15853, 7980, -15929, 7980, -7788, 15937, 8180, -16330, 8180, \
+ -7948, 16103, 8190, -16346, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_162 \
+ { \
+ -7708, 15852, 7979, -15926, 7979, -7788, 15936, 8179, -16327, 8179, \
+ -7948, 16102, 8189, -16343, 8189 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_165 \
+ { \
+ -7708, 15851, 7978, -15923, 7978, -7788, 15935, 8178, -16324, 8178, \
+ -7868, 16109, 8188, -16340, 8188 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_168 \
+ { \
+ -7708, 15851, 7980, -15925, 7980, -7788, 15935, 8180, -16326, 8180, \
+ -7948, 16100, 8190, -16342, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_171 \
+ { \
+ -7708, 15850, 7980, -15924, 7980, -7788, 15934, 8180, -16325, 8180, \
+ -7948, 16099, 8190, -16341, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_174 \
+ { \
+ -7708, 15849, 7981, -15925, 7981, -7788, 15933, 8181, -16326, 8181, \
+ -7948, 16098, 8191, -16342, 8191 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_177 \
+ { \
+ -7708, 15855, 8050, -16058, 8050, -7788, 15938, 8192, -16343, 8192, \
+ -7997, 16151, 8187, -16335, 8187 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_180 \
+ { \
+ -7708, 15855, 8050, -16057, 8050, -7788, 15938, 8192, -16342, 8192, \
+ -8061, 16217, 8187, -16334, 8187 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_183 \
+ { \
+ -7708, 15855, 8050, -16056, 8050, -7788, 15938, 8192, -16341, 8192, \
+ -8061, 16217, 8187, -16333, 8187 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_186 \
+ { \
+ -7676, 15822, 8050, -16054, 8050, -7788, 15938, 8192, -16339, 8192, \
+ -8029, 16184, 8187, -16331, 8187 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_189 \
+ { \
+ -7708, 15855, 8050, -16053, 8050, -7788, 15938, 8192, -16338, 8192, \
+ -8061, 16217, 8187, -16330, 8187 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_192 \
+ { \
+ -7708, 15855, 8050, -16051, 8050, -7788, 15938, 8192, -16336, 8192, \
+ -8061, 16217, 8187, -16328, 8187 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_195 \
+ { \
+ -7393, 15528, 8050, -16049, 8050, -7788, 15938, 8192, -16334, 8192, \
+ -8061, 16217, 8187, -16326, 8187 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_198 \
+ { \
+ -7393, 15528, 8050, -16048, 8050, -7788, 15938, 8192, -16334, 8192, \
+ -8061, 16217, 8187, -16326, 8187 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_201 \
+ { \
+ -7238, 15365, 8050, -16046, 8050, -7788, 15938, 8192, -16332, 8192, \
+ -8078, 16233, 8187, -16324, 8187 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_204 \
+ { \
+ -7238, 15365, 8050, -16045, 8050, -7836, 15987, 8192, -16331, 8192, \
+ -8078, 16233, 8187, -16323, 8187 \
+ }
+
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_207 \
+ { \
+ -7238, 15365, 8050, -16043, 8050, -7836, 15987, 8192, -16329, 8192, \
+ -8078, 16233, 8187, -16321, 8187 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_210 \
+ { \
+ -7085, 15202, 8050, -16041, 8050, -7836, 15987, 8192, -16327, 8192, \
+ -8078, 16233, 8187, -16319, 8187 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_213 \
+ { \
+ -7085, 15202, 8050, -16040, 8050, -7676, 15824, 8192, -16326, 8192, \
+ -8078, 16233, 8187, -16318, 8187 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_216 \
+ { \
+ -7085, 15202, 8050, -16038, 8050, -7676, 15824, 8192, -16324, 8192, \
+ -8078, 16233, 8187, -16316, 8187 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_219 \
+ { \
+ -6934, 15038, 8050, -16037, 8050, -7581, 15660, 8192, -16323, 8192, \
+ -8110, 16266, 8187, -16315, 8187 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_222 \
+ { \
+ -6934, 15038, 8050, -16035, 8050, -7581, 15726, 8192, -16321, 8192, \
+ -8078, 16233, 8187, -16313, 8187 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_225 \
+ { \
+ -7393, 15519, 7980, -15987, 7980, -7788, 15930, 8180, -16298, 8180, \
+ -8061, 16210, 8190, -16313, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_228 \
+ { \
+ -7393, 15519, 7980, -15895, 7980, -7788, 15930, 8180, -16296, 8180, \
+ -8061, 16210, 8190, -16311, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_231 \
+ { \
+ -6934, 15029, 7980, -15893, 7980, -7471, 15603, 8180, -16294, 8180, \
+ -8061, 16210, 8190, -16309, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_234 \
+ { \
+ -6934, 15029, 7980, -15891, 7980, -7471, 15603, 8180, -16292, 8180, \
+ -8061, 16210, 8190, -16307, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_237 \
+ { \
+ -6934, 15029, 7980, -15889, 7980, -7471, 15603, 8180, -16290, 8180, \
+ -8061, 16210, 8190, -16305, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_240 \
+ { \
+ -6636, 14703, 7980, -15888, 7980, -7471, 15603, 8180, -16289, 8180, \
+ -8061, 16208, 8190, -16304, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_243 \
+ { \
+ -6636, 14703, 7980, -15886, 7980, -7471, 15603, 8180, -16287, 8180, \
+ -8061, 16208, 8190, -16302, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_246 \
+ { \
+ -6636, 14703, 7980, -15885, 7980, -7471, 15603, 8180, -16286, 8180, \
+ -8061, 16208, 8190, -16301, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_249 \
+ { \
+ -6636, 14703, 7980, -15884, 7980, -7471, 15603, 8180, -16285, 8180, \
+ -8061, 16208, 8190, -16300, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_252 \
+ { \
+ -6636, 14703, 7980, -15882, 7980, -7471, 15603, 8180, -16283, 8180, \
+ -8061, 16208, 8190, -16297, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_255 \
+ { \
+ -6636, 14703, 7980, -15879, 7980, -7471, 15603, 8180, -16280, 8180, \
+ -8061, 16208, 8190, -16294, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_258 \
+ { \
+ -6606, 14670, 7980, -15877, 7980, -7409, 15538, 8180, -16278, 8180, \
+ -8061, 16208, 8190, -16292, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_261 \
+ { \
+ -6606, 14670, 7980, -15875, 7980, -7409, 15538, 8180, -16276, 8180, \
+ -8061, 16208, 8190, -16290, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_264 \
+ { \
+ -6606, 14670, 7980, -15874, 7980, -7409, 15538, 8180, -16275, 8180, \
+ -8061, 16208, 8190, -16289, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_267 \
+ { \
+ -6489, 14539, 7980, -15872, 7980, -7409, 15538, 8180, -16273, 8180, \
+ -8061, 16208, 8190, -16287, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_270 \
+ { \
+ -6489, 14539, 7980, -15871, 7980, -7409, 15538, 8180, -16272, 8180, \
+ -8061, 16208, 8190, -16286, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_273 \
+ { \
+ -6489, 14540, 7980, -15868, 7980, -7409, 15538, 8180, -16269, 8180, \
+ -8061, 16208, 8190, -16283, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_276 \
+ { \
+ -6489, 14540, 7980, -15867, 7980, -7409, 15538, 8180, -16268, 8180, \
+ -8061, 16208, 8190, -16281, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_279 \
+ { \
+ -6344, 14377, 7980, -15866, 7980, -7409, 15538, 8180, -16267, 8180, \
+ -8061, 16208, 8190, -16280, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_282 \
+ { \
+ -6344, 14377, 7980, -15864, 7980, -7409, 15538, 8180, -16265, 8180, \
+ -8061, 16208, 8190, -16278, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_285 \
+ { \
+ -6344, 14377, 7980, -15862, 7980, -7409, 15538, 8180, -16263, 8180, \
+ -8061, 16208, 8190, -16276, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_288 \
+ { \
+ -6344, 14377, 7980, -15860, 7980, -7409, 15538, 8180, -16261, 8180, \
+ -8061, 16208, 8190, -16274, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_291 \
+ { \
+ -6344, 14377, 7980, -15859, 7980, -7409, 15538, 8180, -16260, 8180, \
+ -8061, 16208, 8190, -16273, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_294 \
+ { \
+ -6344, 14377, 7980, -15857, 7980, -7409, 15538, 8180, -16258, 8180, \
+ -8061, 16208, 8190, -16271, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_297 \
+ { \
+ -6344, 14377, 7980, -15854, 7980, -7409, 15538, 8180, -16255, 8180, \
+ -8061, 16208, 8190, -16268, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_300 \
+ { \
+ -6489, 14540, 7980, -15852, 7980, -7409, 15538, 8180, -16253, 8180, \
+ -8061, 16208, 8190, -16266, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_303 \
+ { \
+ -6489, 14540, 7980, -15850, 7980, -7409, 15538, 8180, -16251, 8180, \
+ -8061, 16208, 8190, -16264, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_306 \
+ { \
+ -6489, 14540, 7980, -15848, 7980, -7409, 15538, 8180, -16249, 8180, \
+ -8061, 16208, 8190, -16262, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_309 \
+ { \
+ -6489, 14540, 7980, -15845, 7980, -7409, 15538, 8180, -16247, 8180, \
+ -8061, 16208, 8190, -16259, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_312 \
+ { \
+ -6489, 14540, 7980, -15843, 7980, -7409, 15538, 8180, -16245, 8180, \
+ -8061, 16208, 8190, -16256, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_315 \
+ { \
+ -6489, 14540, 7980, -15840, 7980, -7409, 15538, 8180, -16242, 8180, \
+ -8061, 16208, 8190, -16253, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_318 \
+ { \
+ -6489, 14540, 7980, -15837, 7980, -7409, 15538, 8180, -16239, 8180, \
+ -8061, 16208, 8190, -16250, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_321 \
+ { \
+ -6489, 14540, 7980, -15835, 7980, -7409, 15538, 8180, -16237, 8180, \
+ -8061, 16208, 8190, -16247, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_324 \
+ { \
+ -6489, 14540, 7980, -15833, 7980, -7409, 15538, 8180, -16235, 8180, \
+ -8061, 16208, 8190, -16245, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_327 \
+ { \
+ -6489, 14540, 7980, -15831, 7980, -7409, 15538, 8180, -16233, 8180, \
+ -8061, 16208, 8190, -16242, 8190 \
+ }
+
+#define DEFAULT_SPH_VIBR_FILTER_COEF_330 \
+ { \
+ -6489, 14540, 7980, -15829, 7980, -7409, 15538, 8180, -16231, 8180, \
+ -8061, 16208, 8190, -16240, 8190 \
+ }
+
+//#endif
\ No newline at end of file
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioVIBSPKControl.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioVIBSPKControl.h
new file mode 100644
index 0000000..7ada91d
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/AudioVIBSPKControl.h
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef _AUDIO_VIBSPK_CONTROL_H_
+#define _AUDIO_VIBSPK_CONTROL_H_
+
+
+#include <utils/Log.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+#include <utils/String8.h>
+
+#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+#include <utils/Vector.h>
+
+#include "AudioVIBSPKCoeff.h"
+#include "audio_custom_exp.h"
+
+namespace android {
+#define DELTA_FREQ 5
+#define MOD_FREQ 15
+#define VIB_DIGITAL_GAIN 16384
+#define VIB_RAMPSTEP 16
+#define VIBSPK_SPH_PARAM_SIZE 15
+#define VIBSPK_AUD_PARAM_SIZE 36
+#define VIBSPK_FILTER_NUM 64
+#define VIBSPK_FREQ_LOWBOUND 141
+#define VIBSPK_FILTER_FREQSTEP 3
+
+#define VIBSPK_CALIBRATION_DONE 0x7777
+#define VIBSPK_SETDEFAULT_VALUE 0x8888
+
+
+
+const int16_t SPH_VIBR_FILTER_COEF_Table[VIBSPK_FILTER_NUM][VIBSPK_SPH_PARAM_SIZE] = {
+ DEFAULT_SPH_VIBR_FILTER_COEF_141,
+ DEFAULT_SPH_VIBR_FILTER_COEF_144,
+ DEFAULT_SPH_VIBR_FILTER_COEF_147,
+ DEFAULT_SPH_VIBR_FILTER_COEF_150,
+ DEFAULT_SPH_VIBR_FILTER_COEF_153,
+ DEFAULT_SPH_VIBR_FILTER_COEF_156,
+ DEFAULT_SPH_VIBR_FILTER_COEF_159,
+ DEFAULT_SPH_VIBR_FILTER_COEF_162,
+ DEFAULT_SPH_VIBR_FILTER_COEF_165,
+ DEFAULT_SPH_VIBR_FILTER_COEF_168,
+ DEFAULT_SPH_VIBR_FILTER_COEF_171,
+ DEFAULT_SPH_VIBR_FILTER_COEF_174,
+ DEFAULT_SPH_VIBR_FILTER_COEF_177,
+ DEFAULT_SPH_VIBR_FILTER_COEF_180,
+ DEFAULT_SPH_VIBR_FILTER_COEF_183,
+ DEFAULT_SPH_VIBR_FILTER_COEF_186,
+ DEFAULT_SPH_VIBR_FILTER_COEF_189,
+ DEFAULT_SPH_VIBR_FILTER_COEF_192,
+ DEFAULT_SPH_VIBR_FILTER_COEF_195,
+ DEFAULT_SPH_VIBR_FILTER_COEF_198,
+ DEFAULT_SPH_VIBR_FILTER_COEF_201,
+ DEFAULT_SPH_VIBR_FILTER_COEF_204,
+ DEFAULT_SPH_VIBR_FILTER_COEF_207,
+ DEFAULT_SPH_VIBR_FILTER_COEF_210,
+ DEFAULT_SPH_VIBR_FILTER_COEF_213,
+ DEFAULT_SPH_VIBR_FILTER_COEF_216,
+ DEFAULT_SPH_VIBR_FILTER_COEF_219,
+ DEFAULT_SPH_VIBR_FILTER_COEF_222,
+ DEFAULT_SPH_VIBR_FILTER_COEF_225,
+ DEFAULT_SPH_VIBR_FILTER_COEF_228,
+ DEFAULT_SPH_VIBR_FILTER_COEF_231,
+ DEFAULT_SPH_VIBR_FILTER_COEF_234,
+ DEFAULT_SPH_VIBR_FILTER_COEF_237,
+ DEFAULT_SPH_VIBR_FILTER_COEF_240,
+ DEFAULT_SPH_VIBR_FILTER_COEF_243,
+ DEFAULT_SPH_VIBR_FILTER_COEF_246,
+ DEFAULT_SPH_VIBR_FILTER_COEF_249,
+ DEFAULT_SPH_VIBR_FILTER_COEF_252,
+ DEFAULT_SPH_VIBR_FILTER_COEF_255,
+ DEFAULT_SPH_VIBR_FILTER_COEF_258,
+ DEFAULT_SPH_VIBR_FILTER_COEF_261,
+ DEFAULT_SPH_VIBR_FILTER_COEF_264,
+ DEFAULT_SPH_VIBR_FILTER_COEF_267,
+ DEFAULT_SPH_VIBR_FILTER_COEF_270,
+ DEFAULT_SPH_VIBR_FILTER_COEF_273,
+ DEFAULT_SPH_VIBR_FILTER_COEF_276,
+ DEFAULT_SPH_VIBR_FILTER_COEF_279,
+ DEFAULT_SPH_VIBR_FILTER_COEF_282,
+ DEFAULT_SPH_VIBR_FILTER_COEF_285,
+ DEFAULT_SPH_VIBR_FILTER_COEF_288,
+ DEFAULT_SPH_VIBR_FILTER_COEF_291,
+ DEFAULT_SPH_VIBR_FILTER_COEF_294,
+ DEFAULT_SPH_VIBR_FILTER_COEF_297,
+ DEFAULT_SPH_VIBR_FILTER_COEF_300,
+ DEFAULT_SPH_VIBR_FILTER_COEF_303,
+ DEFAULT_SPH_VIBR_FILTER_COEF_306,
+ DEFAULT_SPH_VIBR_FILTER_COEF_309,
+ DEFAULT_SPH_VIBR_FILTER_COEF_312,
+ DEFAULT_SPH_VIBR_FILTER_COEF_315,
+ DEFAULT_SPH_VIBR_FILTER_COEF_318,
+ DEFAULT_SPH_VIBR_FILTER_COEF_321,
+ DEFAULT_SPH_VIBR_FILTER_COEF_324,
+ DEFAULT_SPH_VIBR_FILTER_COEF_327,
+ DEFAULT_SPH_VIBR_FILTER_COEF_330,
+};
+
+typedef struct {
+ short pParam[15];
+ bool flag2in1;
+} PARAM_VIBSPK;
+
+#ifndef VIBSPK_DEFAULT_FREQ
+#define VIBSPK_DEFAULT_FREQ (156) //141~330 Hz
+#endif
+
+
+
+class AudioVIBSPKVsgGen {
+public:
+ static AudioVIBSPKVsgGen *getInstance();
+ void freeInstance();
+ uint32_t Process(uint32_t size, void *buffer, uint16_t channels, uint8_t rampcontrol, int32_t gain);
+ void vsgDeInit();
+ void vsgInit(int32_t samplerate, int32_t center_freq, int32_t mod_freq, int32_t delta_freq);
+ uint8_t mRampControl; //0--none, 1--rampdown, 2--rampup
+
+private:
+ AudioVIBSPKVsgGen();
+ ~AudioVIBSPKVsgGen();
+ int16_t SineGen(int16_t cur_ph, int16_t ph_st);
+ int16_t mCenter_Freq;
+ int16_t mDelta_Freq;
+ int16_t mMod_Freq;
+ int16_t mCenter_Phase;
+ int16_t mCenter_PhaseInc;
+ int16_t mCenter_PhaseStat;
+ int16_t mMod_Phase;
+ int16_t mMod_PhaseInc;
+ int16_t mMod_PhaseStat;
+ uint16_t mMod_Idx;
+ int16_t mGain;
+ static AudioVIBSPKVsgGen *UniqueAudioVIBSPKVsgGen;
+
+}; //AudioVIBSPKVsgGen
+
+
+class AudioVIBSPKControl {
+public:
+ static AudioVIBSPKControl *getInstance();
+ void freeInstance();
+ void setVibSpkEnable(bool enable);
+ bool getVibSpkEnable(void);
+ void setParameters(int32_t rate, int32_t center_freq, int32_t mod_freq, int32_t delta_freq);
+ void VibSpkProcess(uint32_t size, void *buffer, uint32_t channels);
+ void VibSpkRampControl(uint8_t rampcontrol);
+ void setVibSpkGain(int32_t MaxVolume, int32_t MinVolume, int32_t VolumeRange);
+ int16_t getVibSpkGain(void);
+private:
+ AudioVIBSPKControl();
+ ~AudioVIBSPKControl();
+ Mutex mMutex;
+ int32_t mSampleRate;
+ int32_t mCenterFreq;
+ int32_t mModFreq;
+ int32_t mDeltaFreq;
+ int32_t mDigitalGain;
+ AudioVIBSPKVsgGen *mVsg;
+ bool mEnable;
+ static AudioVIBSPKControl *UniqueAudioVIBSPKControl;
+ uint8_t mRampControl; //0--none, 1--rampdown, 2--rampup
+}; //AudioVIBSPKControl
+
+} //namespace android
+
+#endif //_AUDIO_VIBSPK_CONTROL_H_
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/MTKPrimaryDevicesHalClientInterface.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/MTKPrimaryDevicesHalClientInterface.h
new file mode 100644
index 0000000..69150b7
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/MTKPrimaryDevicesHalClientInterface.h
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+* Copyright (C) 2017 MediaTek Inc.
+* Modification based on code covered by the mentioned copyright
+* and/or permission notice(s).
+*/
+/*
+ * 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.
+ * 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 MTK_HARDWARE_PRIMARY_DEVICES_HAL_CLIENT_H
+#define MTK_HARDWARE_PRIMARY_DEVICES_HAL_CLIENT_H
+
+#include <media/AudioParameter.h>
+#include <utils/Errors.h>
+#include <utils/Mutex.h>
+
+namespace android {
+
+class MTKPrimaryDevicesHalClient {
+public:
+ static MTKPrimaryDevicesHalClient *getInstance();
+
+ virtual status_t setParameters(const String8 &keyValuePairs) = 0;
+
+ virtual String8 getParameters(const String8 &keys) = 0;
+
+ virtual ~MTKPrimaryDevicesHalClient() {}
+
+ static status_t destroyInstance();
+
+};
+
+} // namespace android
+
+#endif // MTK_HARDWARE_PRIMARY_DEVICES_HAL_CLIENT_H
\ No newline at end of file
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechBGSPlayer.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechBGSPlayer.h
new file mode 100644
index 0000000..6aa8cfe
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechBGSPlayer.h
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_BACKGROUND_SOUND_PLAYER_H
+#define ANDROID_SPEECH_BACKGROUND_SOUND_PLAYER_H
+
+#include <pthread.h>
+#include "AudioType.h"
+#include "AudioUtility.h"
+#include "MtkAudioComponent.h"
+#include <AudioLock.h>
+
+namespace android {
+// for debug
+//#define DUMP_BGS_DATA
+//#define DUMP_BGS_BLI_BUF
+//#define BGS_USE_SINE_WAVE
+
+
+#if defined(SPH_SR48K) || defined(SPH_SR32K)
+#define BGS_TARGET_SAMPLE_RATE (32000)
+#else
+#define BGS_TARGET_SAMPLE_RATE (16000)
+#endif
+
+// BGS ring buffer
+#define MODEM_FRAME_MS (20)
+#define BGS_KEEP_NUM_FRAME (4)
+#define BGS_EXTRA_NUM_FRAME (3)
+
+#if BGS_KEEP_NUM_FRAME < BGS_EXTRA_NUM_FRAME
+#error BGS_KEEP_NUM_FRAME >= BGS_EXTRA_NUM_FRAME
+#endif
+
+// pcm_16_bit * 1ch * sample rate * ms
+#define BGS_PERIOD_SIZE \
+ ((2 * 1 * BGS_TARGET_SAMPLE_RATE * MODEM_FRAME_MS) / 1000)
+
+#define BGS_PLAY_BUFFER_LEN \
+ ((BGS_PERIOD_SIZE * BGS_KEEP_NUM_FRAME) + RING_BUF_SIZE_OFFSET)
+
+
+enum { /* uint32_t: bgs_log_level_t */ /* PROPERTY_KEY_BGS_LOG_LEVEL */
+ BGS_LOG_LEVEL_PLAYBACK_HANDLER = 1,
+ BGS_LOG_LEVEL_MODEM = 2,
+ BGS_LOG_LEVEL_BGS = 4
+};
+
+bool getBGSLogEnableByLevel(const uint32_t bgs_log_level); /* bgs_log_level_t */
+
+
+/*=============================================================================
+ * Class definition
+ *===========================================================================*/
+
+class BGSPlayer;
+class SpeechDriverInterface;
+class MtkAudioSrcBase;
+
+class BGSPlayBuffer {
+public:
+ bool isBufferEnough(void);
+
+private:
+ BGSPlayBuffer();
+ virtual ~BGSPlayBuffer(); // only destroied by friend class BGSPlayer
+ friend class BGSPlayer;
+ status_t InitBGSPlayBuffer(BGSPlayer *playPointer, uint32_t sampleRate, uint32_t chNum, int32_t mFormat);
+ uint32_t Write(char *buf, uint32_t num);
+ bool IsBGSBlisrcDumpEnable();
+
+ int32_t mFormat;
+ RingBuf mRingBuf;
+ MtkAudioSrcBase *mBliSrc;
+ char *mBliOutputLinearBuffer;
+
+ AudioLock mBGSPlayBufferRuningMutex;
+ AudioLock mBGSPlayBufferMutex;
+
+ bool mExitRequest;
+
+ bool mIsBGSBlisrcDumpEnable;
+ FILE *pDumpFile;
+};
+
+class BGSPlayer {
+public:
+ virtual ~BGSPlayer();
+
+ static BGSPlayer *GetInstance();
+ BGSPlayBuffer *CreateBGSPlayBuffer(uint32_t sampleRate, uint32_t chNum, int32_t format);
+ void DestroyBGSPlayBuffer(BGSPlayBuffer *pBGSPlayBuffer);
+ bool Open(SpeechDriverInterface *pSpeechDriver, uint8_t uplink_gain, uint8_t downlink_gain);
+ bool Close();
+ bool IsBGSDumpEnable();
+ uint32_t Write(BGSPlayBuffer *pBGSPlayBuffer, void *buf, uint32_t num);
+ uint32_t PutData(BGSPlayBuffer *pBGSPlayBuffer, char *target_ptr, uint16_t num_data_request);
+ uint16_t PutDataToSpeaker(char *target_ptr, uint16_t num_data_request);
+
+
+private:
+ BGSPlayer();
+
+ static BGSPlayer *mBGSPlayer; // singleton
+ SpeechDriverInterface *mSpeechDriver;
+ SortedVector<BGSPlayBuffer *> mBGSPlayBufferVector;
+ char *mBufBaseTemp;
+
+ AudioLock mBGSPlayBufferVectorLock;
+ AudioLock mCountLock;
+ uint16_t mCount;
+
+ bool mIsBGSDumpEnable;
+ FILE *pDumpFile;
+
+ uint16_t mBgsPeriodSize;
+ uint16_t mUnderflowCount;
+};
+
+
+} // end namespace android
+
+#endif //ANDROID_SPEECH_BACKGROUND_SOUND_PLAYER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechCCCIType.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechCCCIType.h
new file mode 100644
index 0000000..d3f282e
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechCCCIType.h
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef SPEECH_CCCI_TYPE_H
+#define SPEECH_CCCI_TYPE_H
+
+#include <stdint.h>
+#include <system/audio.h>
+
+namespace android {
+
+/*
+ * =============================================================================
+ * MACRO
+ * =============================================================================
+ */
+
+#define CCCI_MAX_BUF_SIZE (3456)
+
+#define CCCI_MAILBOX_SIZE (16) /* sizeof(ccci_mail_box_t) */
+#define CCCI_MAX_AP_PAYLOAD_HEADER_SIZE (6)
+#define CCCI_MAX_MD_PAYLOAD_HEADER_SIZE (10)
+#define CCCI_MAX_AP_PAYLOAD_DATA_SIZE (CCCI_MAX_BUF_SIZE - CCCI_MAILBOX_SIZE - CCCI_MAX_AP_PAYLOAD_HEADER_SIZE)
+#define CCCI_MAX_MD_PAYLOAD_DATA_SIZE (CCCI_MAX_BUF_SIZE - CCCI_MAILBOX_SIZE - CCCI_MAX_MD_PAYLOAD_HEADER_SIZE)
+
+#define CCCI_MAILBOX_MAGIC (0xFFFFFFFF)
+
+#define CCCI_AP_PAYLOAD_SYNC (0xA2A2)
+#define CCCI_MD_PAYLOAD_SYNC (0x1234) /* 0x2A2A is old lagecy code */
+
+
+#define MAX_SIZE_OF_ONE_FRAME (16) /* 32-bits * 4ch */
+
+}
+#endif // end of SPEECH_CCCI_TYPE_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechConfig.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechConfig.h
new file mode 100644
index 0000000..ecd54a6
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechConfig.h
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef _SPEECH_CONFIG_H_
+#define _SPEECH_CONFIG_H_
+
+/*
+ * =============================================================================
+ * external references
+ * =============================================================================
+ */
+#include <vector>
+#include <AudioParamParser.h>
+#include "SpeechFeatureDef.h"
+
+namespace android {
+
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+struct SPEECH_PARAM_SUPPORT_STRUCT;
+struct SPEECH_NETWORK_STRUCT;
+
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+
+enum DRIVER_PARAM_TYPE {
+ DRIVER_PARAM_COMMON_PAR,
+ DRIVER_PARAM_DEBUG_INFO,
+ NUM_DRIVER_PARAM
+};
+
+/*
+ * =============================================================================
+ * class
+ * =============================================================================
+ */
+
+class SpeechConfig {
+public:
+ virtual ~SpeechConfig();
+ static SpeechConfig *getInstance();
+ bool getSpeechParamSupport(const SpeechFeatureType featureType);
+ int getBtDelayTime(const char *btDeviceName);
+ char *getNameForEachSpeechNetwork(unsigned char bitIndex);
+ int getEchoRefParam(uint8_t *usbDelayMs);
+ int getDriverParam(uint8_t paramType, void *paramBuf);
+
+protected:
+
+private:
+ SpeechConfig();
+ static SpeechConfig *uniqueSpeechConfig;
+ AppHandle *mAppHandle;
+
+ void init();
+ void initAppParser();
+ void initFeatureSupport();
+ int initSpeechNetwork();
+ uint16_t sizeByteParaData(uint16_t dataType, uint16_t arraySize);
+ int speechDataDump(char *dumpBuf,
+ const char *nameXml,
+ const Param *param);
+
+ uint8_t mNumSpeechNetwork, mSpeechParamVerFirst, mSpeechParamVerLast;
+ SPEECH_NETWORK_STRUCT *mListSpeechNetwork;
+ SPEECH_NETWORK_STRUCT *mNameForEachSpeechNetwork;
+ SPEECH_PARAM_SUPPORT_STRUCT *mSphParamSupport;
+
+
+}; //SpeechConfig
+
+} //namespace android
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDataEncrypter.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDataEncrypter.h
new file mode 100644
index 0000000..c3856dd
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDataEncrypter.h
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_DATA_ENCRYPTER_H
+#define ANDROID_SPEECH_DATA_ENCRYPTER_H
+
+#include "AudioType.h"
+#include "AudioUtility.h"
+
+#include "AudioCustEncryptClient.h"
+
+namespace android {
+
+/***********************************************************
+* SpeechDataEncrypter Interface - SpeechDataEncrypter
+***********************************************************/
+
+class SpeechDataEncrypter {
+public:
+ virtual ~SpeechDataEncrypter();
+
+ static SpeechDataEncrypter *GetInstance();
+
+ int Start();
+ int Stop();
+
+ void SetEnableStatus(bool bEnable);
+ bool GetEnableStatus();
+ bool GetDumpStatus();
+ bool GetStartStatus();
+ uint16_t Encryption(char *TargetBuf, char *SourceBuf, const uint16_t SourceByte);
+ uint16_t Decryption(char *TargetBuf, char *SourceBuf, const uint16_t SourceByte);
+
+private:
+ SpeechDataEncrypter();
+ static SpeechDataEncrypter *mSpeechDataEncrypter; // singleton
+ AudioCustEncryptClient *mAudioCustEncryptClient;
+
+ int GetDelay();
+ AudioLock mMutexDL;
+ AudioLock mMutexUL;
+
+
+ bool mEnabled;
+ bool mDumpEnabled;
+ bool mStarted;
+ pthread_mutex_t mSpeechDataEncrypter_ULMutex; // Mutex to protect internal buffer
+ pthread_mutex_t mSpeechDataEncrypter_DLMutex; // Mutex to protect internal buffer
+
+ FILE *pPreEncDumpFile;
+ FILE *pPostEncDumpFile;
+ FILE *pPreDecDumpFile;
+ FILE *pPostDecDumpFile;
+ /*
+ * flag of dynamic enable verbose/debug log
+ */
+ int mLogEnable;
+
+};
+
+
+}; // namespace android
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDriverDummy.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDriverDummy.h
new file mode 100644
index 0000000..eb913d8
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDriverDummy.h
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_DRIVER_DUMMY_H
+#define ANDROID_SPEECH_DRIVER_DUMMY_H
+
+#include "SpeechDriverInterface.h"
+
+namespace android {
+
+class SpeechDriverDummy : public SpeechDriverInterface {
+public:
+ SpeechDriverDummy(modem_index_t modem_index);
+ virtual ~SpeechDriverDummy();
+
+ /**
+ * speech control
+ */
+ virtual status_t SetSpeechMode(const audio_devices_t input_device, const audio_devices_t output_device);
+ virtual status_t SpeechOn();
+ virtual status_t SpeechOff();
+ virtual status_t VideoTelephonyOn();
+ virtual status_t VideoTelephonyOff();
+ virtual status_t SpeechRouterOn();
+ virtual status_t SpeechRouterOff();
+ virtual status_t setMDVolumeIndex(int stream, int device, int index);
+
+
+ /**
+ * record control
+ */
+ virtual status_t recordOn();
+ virtual status_t recordOff();
+ virtual status_t recordOn(SpcRecordTypeStruct typeRecord);
+ virtual status_t recordOff(SpcRecordTypeStruct typeRecord);
+ virtual status_t setPcmRecordType(SpcRecordTypeStruct typeRecord);
+
+ virtual status_t VoiceMemoRecordOn();
+ virtual status_t VoiceMemoRecordOff();
+
+ virtual uint16_t GetRecordSampleRate() const;
+ virtual uint16_t GetRecordChannelNumber() const;
+
+
+ /**
+ * background sound control
+ */
+ virtual status_t BGSoundOn();
+ virtual status_t BGSoundConfig(uint8_t ul_gain, uint8_t dl_gain);
+ virtual status_t BGSoundOff();
+
+
+ /**
+ * pcm 2 way
+ */
+ virtual status_t PCM2WayOn(const bool wideband_on);
+ virtual status_t PCM2WayOff();
+
+
+ /**
+ * tty ctm control
+ */
+ virtual status_t TtyCtmOn();
+ virtual status_t TtyCtmOff();
+
+
+ /**
+ * acoustic loopback
+ */
+ virtual status_t SetAcousticLoopback(bool loopback_on);
+ virtual status_t SetAcousticLoopbackBtCodec(bool enable_codec);
+
+ virtual status_t SetAcousticLoopbackDelayFrames(int32_t delay_frames);
+ virtual status_t setLpbkFlag(bool enableLpbk __unused) { return -ENOSYS; }
+
+ /**
+ * Modem Audio DVT and Debug
+ */
+ virtual status_t SetModemLoopbackPoint(uint16_t loopback_point);
+
+ /**
+ * volume control
+ */
+ virtual status_t SetDownlinkGain(int16_t gain);
+ virtual status_t SetEnh1DownlinkGain(int16_t gain);
+ virtual status_t SetUplinkGain(int16_t gain);
+ virtual status_t SetDownlinkMute(bool mute_on);
+ virtual status_t SetUplinkMute(bool mute_on);
+ virtual status_t SetUplinkSourceMute(bool mute_on);
+ virtual status_t SetSidetoneGain(int16_t gain);
+ virtual status_t SetDownlinkMuteCodec(bool mute_on);
+
+ /**
+ * device related config
+ */
+ virtual status_t SetModemSideSamplingRate(uint16_t sample_rate);
+
+ /**
+ * speech enhancement control
+ */
+ virtual status_t SetSpeechEnhancement(bool enhance_on);
+ virtual status_t SetSpeechEnhancementMask(const sph_enh_mask_struct_t &mask);
+
+ virtual status_t SetBtHeadsetNrecOn(const bool bt_headset_nrec_on);
+
+
+ /**
+ * check whether modem is ready.
+ */
+ virtual bool CheckModemIsReady();
+
+
+
+protected:
+ /**
+ * recover status (speech/record/bgs/vt/p2w/tty)
+ */
+ virtual void RecoverModemSideStatusToInitState();
+
+
+
+private:
+ SpeechDriverDummy() {}
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_SPEECH_DRIVER_DUMMY_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDriverFactory.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDriverFactory.h
new file mode 100644
index 0000000..6bc66e6
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDriverFactory.h
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_DRIVER_FACTORY_H
+#define ANDROID_SPEECH_DRIVER_FACTORY_H
+
+#include <utils/Vector.h>
+#include "AudioType.h"
+#include "SpeechDriverInterface.h"
+
+namespace android {
+class SpeechDriverFactory {
+public:
+ virtual ~SpeechDriverFactory();
+
+ static SpeechDriverFactory *GetInstance();
+
+ SpeechDriverInterface *GetSpeechDriver();
+ SpeechDriverInterface *GetSpeechDriverByIndex(const modem_index_t modem_index);
+
+ modem_index_t GetActiveModemIndex() const;
+ status_t SetActiveModemIndex(const modem_index_t modem_index);
+ status_t SetActiveModemIndexByAudioMode(const audio_mode_t audio_mode);
+
+protected:
+ SpeechDriverFactory();
+
+ /**
+ * sub factory class can override this function
+ * to create types of speech driver instances
+ */
+ virtual status_t CreateSpeechDriverInstances();
+ virtual status_t DestroySpeechDriverInstances();
+
+
+ /**
+ * centralized management of speech drivers
+ */
+ modem_index_t mActiveModemIndex;
+
+ SpeechDriverInterface *mSpeechDriver1; // for modem 1
+ SpeechDriverInterface *mSpeechDriver2; // for modem 2
+ SpeechDriverInterface *mSpeechDriverExternal; // for modem External
+
+private:
+ /**
+ * singleton pattern
+ */
+ static SpeechDriverFactory *mSpeechDriverFactory;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_SPEECH_DRIVER_FACTORY_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDriverInterface.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDriverInterface.h
new file mode 100644
index 0000000..fa8da2c
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDriverInterface.h
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_DRIVER_INTERFACE_H
+#define ANDROID_SPEECH_DRIVER_INTERFACE_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <utils/threads.h>
+#include <log/log.h>
+#include <system/audio.h>
+
+#include "AudioAssert.h"
+#include "SpeechType.h"
+
+
+
+namespace android {
+
+
+const int16_t kUnreasonableGainValue = 0x8000;
+
+class SpeechDriverInterface {
+public:
+ virtual ~SpeechDriverInterface() {}
+
+ /**
+ * speech control
+ */
+ virtual status_t SetSpeechMode(const audio_devices_t input_device, const audio_devices_t output_device) = 0;
+ virtual status_t SpeechOn() = 0;
+ virtual status_t SpeechOff() = 0;
+ virtual status_t VideoTelephonyOn() = 0;
+ virtual status_t VideoTelephonyOff() = 0;
+ virtual status_t SpeechRouterOn() = 0;
+ virtual status_t SpeechRouterOff() = 0;
+ virtual status_t setMDVolumeIndex(int value, int device, int index) = 0;
+
+
+ /**
+ * record control
+ */
+ virtual status_t recordOn() = 0;
+ virtual status_t recordOff() = 0;
+
+ virtual status_t VoiceMemoRecordOn() = 0;
+ virtual status_t VoiceMemoRecordOff() = 0;
+
+ virtual uint16_t GetRecordSampleRate() const = 0;
+ virtual uint16_t GetRecordChannelNumber() const = 0;
+
+ virtual status_t recordOn(SpcRecordTypeStruct typeRecord) = 0;
+ virtual status_t recordOff(SpcRecordTypeStruct typeRecord) = 0;
+
+ virtual status_t setPcmRecordType(SpcRecordTypeStruct typeRecord) = 0;
+
+
+ /**
+ * background sound control
+ */
+ virtual status_t BGSoundOn() = 0;
+ virtual status_t BGSoundConfig(uint8_t ul_gain, uint8_t dl_gain) = 0;
+ virtual status_t BGSoundOff() = 0;
+
+
+ /**
+ * pcm 2 way
+ */
+ virtual status_t PCM2WayPlayOn() { return -ENOSYS; }
+ virtual status_t PCM2WayPlayOff() { return -ENOSYS; }
+ virtual status_t PCM2WayRecordOn() { return -ENOSYS; }
+ virtual status_t PCM2WayRecordOff() { return -ENOSYS; }
+ virtual status_t PCM2WayOn(const bool wideband_on) = 0;
+ virtual status_t PCM2WayOff() = 0;
+
+
+ /**
+ * voice mixer on/off
+ */
+ virtual status_t pcmMixerOn() { return -ENOSYS; }
+ virtual status_t pcmMixerOff() { return -ENOSYS; }
+ virtual status_t pcmMixerConfig(const uint8_t direction __unused, const uint8_t mixType __unused) {
+ return -ENOSYS;
+ }
+
+
+ /**
+ * tty ctm control
+ */
+ virtual status_t TtyCtmOn() = 0;
+ virtual status_t TtyCtmOff() = 0;
+ virtual status_t TtyCtmDebugOn(bool tty_debug_flag __unused) { return 0; }
+ virtual int setTtyMode(const TtyModeType ttyMode) {
+ ALOGD("%s(), ttyMode = %d, old mTtyMode = %d", __FUNCTION__, ttyMode, mTtyMode);
+ mTtyMode = ttyMode;
+ return 0;
+ }
+
+ /**
+ * rtt control
+ */
+ virtual int RttConfig(int rttMode __unused) { return -ENOSYS; }
+
+ /**
+ * acoustic loopback
+ */
+ virtual status_t SetAcousticLoopback(bool loopback_on) = 0;
+ virtual status_t SetAcousticLoopbackBtCodec(bool enable_codec) = 0;
+
+ virtual status_t SetAcousticLoopbackDelayFrames(int32_t delay_frames) = 0;
+ virtual status_t setLpbkFlag(bool enableLpbk) = 0;
+
+ /**
+ * Modem Audio DVT and Debug
+ */
+ virtual status_t SetModemLoopbackPoint(uint16_t loopback_point) = 0;
+
+ /**
+ * encryption
+ */
+ virtual status_t SetEncryption(bool encryption_on __unused) { return -ENOSYS; }
+
+ /**
+ * volume control
+ */
+ /**
+ * param gain: data range is 0~0xFF00, which is mapping to 0dB to -64dB
+ * The effective interval is 0.25dB by data +/- 1
+ */
+ virtual status_t SetDownlinkGain(int16_t gain) = 0;
+ int16_t GetDownlinkGain(void) { return mDownlinkGain; }
+
+ virtual status_t SetEnh1DownlinkGain(int16_t gain) = 0;
+ int16_t GetEnh1DownlinkGain(void) { return mDownlinkenh1Gain; }
+
+ /**
+ * param gain: data range is 0~120, which is mapping to 0dB to 30dB
+ * The effective interval is 1dB by data +/- 4
+ */
+ virtual status_t SetUplinkGain(int16_t gain) = 0;
+
+ virtual status_t SetDownlinkMute(bool mute_on) = 0;
+ virtual status_t SetUplinkMute(bool mute_on) = 0;
+ virtual status_t SetUplinkSourceMute(bool mute_on) = 0;
+
+ virtual status_t SetSidetoneGain(int16_t gain) = 0;
+ virtual status_t SetDSPSidetoneFilter(const bool dsp_stf_on __unused) { return NO_INIT; }
+ virtual status_t SetDownlinkMuteCodec(bool mute_on) = 0;
+
+
+ /**
+ * device related config
+ */
+ virtual status_t SetModemSideSamplingRate(uint16_t sample_rate) = 0;
+ virtual status_t switchBTMode(uint32_t sample_rate __unused) { return -ENOSYS; }
+ virtual void setBTMode(const int mode __unused) { return; }
+ virtual void setBtSpkDevice(const bool flag __unused) { return; }
+
+
+ /**
+ * speech enhancement control
+ */
+ virtual void SetForceDisableSpeechEnhancement(bool force_disable_on) { mForceDisableSpeechEnhancement = force_disable_on; }
+ virtual status_t SetSpeechEnhancement(bool enhance_on) = 0;
+ virtual status_t SetSpeechEnhancementMask(const sph_enh_mask_struct_t &mask) = 0;
+
+ virtual status_t SetBtHeadsetNrecOn(const bool bt_headset_nrec_on) = 0;
+
+
+ /**
+ * speech enhancement parameters setting
+ */
+ virtual status_t SetNBSpeechParameters(const void *pSphParamNB __unused) { return -ENOSYS; }
+ virtual status_t SetDualMicSpeechParameters(const void *pSphParamDualMic __unused) { return -ENOSYS; }
+ virtual status_t SetMagiConSpeechParameters(const void *pSphParamMagiCon __unused) { return -ENOSYS; }
+ virtual status_t SetHACSpeechParameters(const void *pSphParamHAC __unused) { return -ENOSYS; }
+ virtual status_t SetWBSpeechParameters(const void *pSphParamWB __unused) { return -ENOSYS; }
+
+ virtual status_t GetVibSpkParam(void *eVibSpkParam __unused) { return -ENOSYS; }
+ virtual status_t SetVibSpkParam(void *eVibSpkParam __unused) { return -ENOSYS; }
+
+ virtual status_t SetDynamicSpeechParameters(const int type __unused, const void *param_arg __unused) { return -ENOSYS; }
+ virtual int updateSpeechFeature(const SpeechFeatureType featureType __unused, const bool flagOn __unused) { return -ENOSYS; }
+ virtual int setParameter(const char *keyParameter __unused) { return -ENOSYS; }
+ virtual const char *getParameter(const char *keyParameter __unused) { return NULL; }
+
+ /**
+ * check whether modem is ready.
+ */
+ virtual bool CheckModemIsReady() = 0;
+
+ /** ecall */
+ virtual status_t eCallIvsSwitch(bool enable) { return -ENOSYS; }
+ virtual status_t eCallIvsSend() { return -ENOSYS; }
+ virtual status_t eCallPsapSwitch(bool enable) { return -ENOSYS; }
+ virtual status_t eCallPsapSend() { return -ENOSYS; }
+ virtual status_t eCallCtrlSeqSwitch(bool enable) { return -ENOSYS; }
+ virtual status_t eCallMsd(void *data, uint16_t len) { return -ENOSYS; }
+ virtual status_t eCallTxCtrlParam(void *data, uint16_t len) { return -ENOSYS; }
+
+ /**
+ * get AP side modem function status
+ */
+ inline bool GetApSideModemStatus(const modem_status_mask_t modem_status_mask) {
+ return ((mApSideModemStatus & modem_status_mask) > 0);
+ }
+
+
+ /**
+ * speech driver synchronization
+ */
+ void WaitUntilSignaledOrTimeout(unsigned milisecond) { mMutex.lock(); mCondition.waitRelative(mMutex, milliseconds(milisecond)); mMutex.unlock(); }
+ void Signal() { mMutex.lock(); mCondition.signal(); mMutex.unlock();}
+ virtual void SetWarningTone(int toneid __unused) { return; }
+ virtual void StopWarningTone() {return;}
+
+
+ void setBtHeadsetName(const char *bt_headset_name) {
+ if (bt_headset_name != NULL && strlen(bt_headset_name) > 0) {
+ ALOGV("%s(), mBtHeadsetName: %s => %s", __FUNCTION__, mBtHeadsetName, bt_headset_name);
+ strncpy(mBtHeadsetName, bt_headset_name, sizeof(mBtHeadsetName) - 1);
+ }
+ }
+
+
+
+protected:
+ SpeechDriverInterface() {
+ CleanGainValueAndMuteStatus();
+ mPCM2WayState = 0;
+ mApSideModemStatus = 0;
+ mRecordSampleRateType = RECORD_SAMPLE_RATE_08K;
+ mRecordChannelType = RECORD_CHANNEL_MONO;
+ mRecordType.direction = RECORD_TYPE_MIX;
+ mRecordType.dlPosition= RECORD_POS_DL_END;
+
+ mBtHeadsetNrecOn = true;
+ mAcousticLoopbackDelayFrames = 0;
+ mForceDisableSpeechEnhancement = false;
+ mUseBtCodec = true;
+ mModemIndex = MODEM_1;
+ mVolumeIndex = 0;
+ mTtyMode = AUD_TTY_OFF;
+
+ memset(mBtHeadsetName, 0, sizeof(mBtHeadsetName));
+ }
+
+
+ /**
+ * recover modem side status (speech/record/bgs/vt/p2w/tty)
+ */
+ virtual void RecoverModemSideStatusToInitState() = 0;
+
+
+ /**
+ * Clean gain value and mute status
+ */
+ virtual void CleanGainValueAndMuteStatus() {
+ mDownlinkGain = kUnreasonableGainValue;
+ mDownlinkenh1Gain = kUnreasonableGainValue;
+ mUplinkGain = kUnreasonableGainValue;
+ mSideToneGain = kUnreasonableGainValue;
+ mUplinkMuteOn = false;
+ mUplinkSourceMuteOn = false;
+ mDownlinkMuteOn = false;
+ ALOGD("%s(), mUplinkMuteOn %d", __FUNCTION__, mUplinkMuteOn);
+ }
+
+
+ /**
+ * set/reset AP side modem function status
+ */
+ inline void SetApSideModemStatus(const modem_status_mask_t modem_status_mask) {
+ Mutex::Autolock _l(mUpdateApSideModemStatusLock);
+ ASSERT(GetApSideModemStatus(modem_status_mask) == false);
+ mApSideModemStatus |= modem_status_mask;
+ }
+ inline void ResetApSideModemStatus(const modem_status_mask_t modem_status_mask) {
+ Mutex::Autolock _l(mUpdateApSideModemStatusLock);
+ ASSERT(GetApSideModemStatus(modem_status_mask) == true);
+ mApSideModemStatus &= (~modem_status_mask);
+ }
+
+
+ /**
+ * check AP side modem function status
+ */
+ inline void CheckApSideModemStatusAllOffOrDie() {
+ if (mApSideModemStatus != 0) {
+ ALOGE("%s(), mApSideModemStatus 0x%x != 0",
+ __FUNCTION__, mApSideModemStatus);
+ ASSERT(mApSideModemStatus == 0);
+ }
+ }
+
+
+ /**
+ * class variables
+ */
+ modem_index_t mModemIndex;
+
+ int16_t mDownlinkGain;
+ int16_t mDownlinkenh1Gain;
+ int16_t mUplinkGain;
+ int16_t mSideToneGain;
+
+ bool mDownlinkMuteOn;
+ bool mUplinkMuteOn;
+ bool mUplinkSourceMuteOn;
+
+ uint32_t mPCM2WayState; // value |= pcmnway_format_t
+
+ // Modem function status : not the modem real status but AP side control status
+ uint32_t mApSideModemStatus; // value |= modem_status_mask_t
+
+ bool mForceDisableSpeechEnhancement;
+
+ Mutex mMutex;
+ Condition mCondition;
+ Mutex mUpdateApSideModemStatusLock;
+
+ // Record capability
+ record_sample_rate_t mRecordSampleRateType;
+ record_channel_t mRecordChannelType;
+ SpcRecordTypeStruct mRecordType;
+
+ //for BT SW BT CVSD loopback test
+ bool mUseBtCodec;
+
+ // BT Headset NREC
+ bool mBtHeadsetNrecOn;
+
+ // loopback delay frames (1 frame = 20 ms)
+ uint32_t mAcousticLoopbackDelayFrames;
+
+ // volume index
+ int16_t mVolumeIndex;
+
+ char mBtHeadsetName[128];
+
+ /* TTY Mode */
+ TtyModeType mTtyMode;
+
+};
+
+
+
+} // end namespace android
+
+#endif // end of ANDROID_SPEECH_DRIVER_INTERFACE_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDriverLAD.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDriverLAD.h
new file mode 100644
index 0000000..e21e521
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDriverLAD.h
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_DRIVER_LAD_H
+#define ANDROID_SPEECH_DRIVER_LAD_H
+
+#include "SpeechDriverInterface.h"
+#include <AudioLock.h>
+#include "AudioUtility.h"
+
+namespace android {
+
+class SpeechMessengerInterface;
+
+class SpeechDriverLAD : public SpeechDriverInterface {
+public:
+ virtual ~SpeechDriverLAD();
+
+
+ /**
+ * get instance's pointer
+ */
+ static SpeechDriverLAD *GetInstance(modem_index_t modem_index);
+
+
+ /**
+ * speech control
+ */
+ virtual speech_mode_t GetSpeechModeByOutputDevice(const audio_devices_t output_device); // only available for LAD
+ virtual status_t SetSpeechMode(const audio_devices_t input_device, const audio_devices_t output_device);
+ virtual status_t SpeechOn();
+ virtual status_t SpeechOff();
+ virtual status_t VideoTelephonyOn();
+ virtual status_t VideoTelephonyOff();
+ virtual status_t SpeechRouterOn();
+ virtual status_t SpeechRouterOff();
+
+ virtual status_t setMDVolumeIndex(int stream, int device, int index);
+
+ /**
+ * record control
+ */
+ virtual status_t recordOn();
+ virtual status_t recordOff();
+ virtual status_t recordOn(SpcRecordTypeStruct typeRecord);
+ virtual status_t recordOff(SpcRecordTypeStruct typeRecord);
+ virtual status_t setPcmRecordType(SpcRecordTypeStruct typeRecord);
+
+ virtual status_t VoiceMemoRecordOn();
+ virtual status_t VoiceMemoRecordOff();
+
+ virtual uint16_t GetRecordSampleRate() const;
+ virtual uint16_t GetRecordChannelNumber() const;
+
+
+ /**
+ * background sound control
+ */
+ virtual status_t BGSoundOn();
+ virtual status_t BGSoundConfig(uint8_t ul_gain, uint8_t dl_gain);
+ virtual status_t BGSoundOff();
+
+
+ /**
+ * pcm 2 way
+ */
+ virtual status_t PCM2WayOn(const bool wideband_on);
+ virtual status_t PCM2WayOff();
+
+
+ /**
+ * tty ctm control
+ */
+ virtual status_t TtyCtmOn();
+ virtual status_t TtyCtmOff();
+ virtual status_t TtyCtmDebugOn(bool tty_debug_flag);
+ virtual int setTtyMode(const TtyModeType ttyMode);
+
+ /**
+ * rtt control
+ */
+ virtual int RttConfig(int rttMode);
+
+ /**
+ * acoustic loopback
+ */
+ virtual status_t SetAcousticLoopback(bool loopback_on);
+ virtual status_t SetAcousticLoopbackBtCodec(bool enable_codec);
+
+ virtual status_t SetAcousticLoopbackDelayFrames(int32_t delay_frames);
+ virtual status_t setLpbkFlag(bool enableLpbk);
+
+ /**
+ * Modem Audio DVT and Debug
+ */
+ virtual status_t SetModemLoopbackPoint(uint16_t loopback_point);
+
+ /**
+ * encryption
+ */
+ virtual status_t SetEncryption(bool encryption_on);
+
+ /**
+ * volume control
+ */
+ virtual status_t SetDownlinkGain(int16_t gain);
+ virtual status_t SetEnh1DownlinkGain(int16_t gain);
+ virtual status_t SetUplinkGain(int16_t gain);
+ virtual status_t SetDownlinkMute(bool mute_on);
+ virtual status_t SetUplinkMute(bool mute_on);
+ virtual status_t SetUplinkSourceMute(bool mute_on);
+ virtual status_t SetSidetoneGain(int16_t gain);
+ virtual status_t SetDSPSidetoneFilter(const bool dsp_stf_on);
+ virtual status_t SetDownlinkMuteCodec(bool mute_on);
+
+
+ /**
+ * device related config
+ */
+ virtual status_t SetModemSideSamplingRate(uint16_t sample_rate);
+
+
+ /**
+ * speech enhancement control
+ */
+ virtual status_t SetSpeechEnhancement(bool enhance_on);
+ virtual status_t SetSpeechEnhancementMask(const sph_enh_mask_struct_t &mask);
+
+ virtual status_t SetBtHeadsetNrecOn(const bool bt_headset_nrec_on);
+
+
+ /**
+ * speech enhancement parameters setting
+ */
+ virtual status_t SetAllSpeechEnhancementInfoToModem(); // only available for LAD
+
+ virtual status_t SetVariousKindsOfSpeechParameters(const void *param, const uint16_t data_length, const uint16_t ccci_message_id); // only available for LAD
+
+ virtual status_t SetNBSpeechParameters(const void *pSphParamNB);
+ virtual status_t SetDualMicSpeechParameters(const void *pSphParamDualMic);
+ virtual status_t SetMagiConSpeechParameters(const void *pSphParamMagiCon);
+ virtual status_t SetHACSpeechParameters(const void *pSphParamHAC);
+ virtual status_t SetWBSpeechParameters(const void *pSphParamWB);
+
+ virtual status_t GetVibSpkParam(void *eVibSpkParam);
+ virtual status_t SetVibSpkParam(void *eVibSpkParam);
+
+ virtual status_t GetSmartpaParam(void *eParamSmartpa);
+ virtual status_t SetSmartpaParam(void *eParamSmartpa);
+
+ virtual status_t SetDynamicSpeechParameters(const int type, const void *param_arg);
+
+
+ /**
+ * check whether modem is ready.
+ */
+ virtual bool CheckModemIsReady();
+ virtual int updateParam(int audioTypeUpdate);
+
+
+protected:
+ SpeechDriverLAD() {}
+ SpeechDriverLAD(modem_index_t modem_index);
+
+
+ /**
+ * recover status (speech/record/bgs/vt/p2w/tty)
+ */
+ virtual void RecoverModemSideStatusToInitState();
+
+
+ /**
+ * CCCI Messenger
+ */
+ SpeechMessengerInterface *pCCCI;
+
+
+ /**
+ * Speech Mode
+ */
+ speech_mode_t mSpeechMode;
+
+ /**
+ * RTT Mode
+ */
+ int mRttMode;
+
+ /**
+ * lock
+ */
+ AudioLock mLock;
+
+ /**
+ * loopback
+ */
+ bool mIsLpbk;
+
+private:
+ /**
+ * singleton pattern
+ */
+ static SpeechDriverLAD *mLad1;
+ static SpeechDriverLAD *mLad2;
+ static SpeechDriverLAD *mLad3;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_SPEECH_DRIVER_LAD_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDriverNormal.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDriverNormal.h
new file mode 100644
index 0000000..663e373
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechDriverNormal.h
@@ -0,0 +1,360 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_DRIVER_NORMAL_H
+#define ANDROID_SPEECH_DRIVER_NORMAL_H
+
+#include "SpeechDriverInterface.h"
+
+#include <pthread.h>
+
+#include <AudioLock.h>
+
+#include "SpeechType.h"
+#include "SpeechParserType.h"
+
+
+namespace android {
+
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+
+class SpeechMessageQueue;
+class SpeechMessengerNormal;
+
+
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+
+
+/*
+ * =============================================================================
+ * class
+ * =============================================================================
+ */
+
+class SpeechDriverNormal : public SpeechDriverInterface {
+public:
+ /** virtual dtor */
+ virtual ~SpeechDriverNormal();
+
+ /** singleton */
+ static SpeechDriverNormal *GetInstance(modem_index_t modem_index);
+
+
+ /** speech */
+ virtual status_t SetModemSideSamplingRate(uint16_t sample_rate);
+ virtual status_t switchBTMode(uint32_t sample_rate);
+ virtual void setBTMode(const int mode);
+ virtual void setBtSpkDevice(const bool flag);
+ virtual status_t SetSpeechMode(const audio_devices_t input_device, const audio_devices_t output_device);
+ virtual status_t SpeechOn();
+ virtual status_t SpeechOff();
+ virtual status_t VideoTelephonyOn();
+ virtual status_t VideoTelephonyOff();
+ virtual status_t SpeechRouterOn();
+ virtual status_t SpeechRouterOff();
+ virtual status_t setMDVolumeIndex(int stream, int device, int index);
+
+
+ /** record */
+ virtual status_t recordOn() { return -ENOSYS; }
+ virtual status_t recordOff() { return -ENOSYS; }
+
+ virtual status_t VoiceMemoRecordOn();
+ virtual status_t VoiceMemoRecordOff();
+
+ virtual uint16_t GetRecordSampleRate() const;
+ virtual uint16_t GetRecordChannelNumber() const;
+
+ virtual status_t recordOn(SpcRecordTypeStruct typeRecord);
+ virtual status_t recordOff(SpcRecordTypeStruct typeRecord);
+
+ virtual status_t setPcmRecordType(SpcRecordTypeStruct typeRecord);
+
+
+ /** background sound */
+ virtual status_t BGSoundOn();
+ virtual status_t BGSoundConfig(uint8_t ul_gain, uint8_t dl_gain);
+ virtual status_t BGSoundOff();
+
+
+ /** pcm 2 way */
+ virtual status_t PCM2WayOn(const bool wideband_on);
+ virtual status_t PCM2WayOff();
+
+ /** voice mixer on/off */
+ virtual status_t pcmMixerOn();
+ virtual status_t pcmMixerOff();
+ virtual status_t pcmMixerConfig(const uint8_t direction, const uint8_t mixType);
+
+
+ /** tty ctm */
+ virtual status_t TtyCtmOn();
+ virtual status_t TtyCtmOff();
+ virtual status_t TtyCtmDebugOn(bool tty_debug_flag);
+
+ /** rtt */
+ virtual int RttConfig(int rttMode);
+
+ /** acoustic loopback */
+ virtual status_t SetAcousticLoopback(bool loopback_on);
+ virtual status_t SetAcousticLoopbackBtCodec(bool enable_codec);
+
+ virtual status_t SetAcousticLoopbackDelayFrames(int32_t delay_frames);
+ virtual status_t setLpbkFlag(bool enableLpbk __unused) { return -ENOSYS; }
+
+ /**
+ * Modem Audio DVT and Debug
+ */
+ virtual status_t SetModemLoopbackPoint(uint16_t loopback_point);
+
+
+ /** volume */
+ virtual status_t SetDownlinkGain(int16_t gain);
+ virtual status_t SetEnh1DownlinkGain(int16_t gain);
+ virtual status_t SetUplinkGain(int16_t gain);
+ virtual status_t SetDownlinkMute(bool mute_on);
+ virtual status_t SetUplinkMute(bool mute_on);
+ virtual status_t SetUplinkSourceMute(bool mute_on);
+ virtual status_t SetSidetoneGain(int16_t gain __unused) { return -ENOSYS; }
+ virtual status_t SetDSPSidetoneFilter(const bool dsp_stf_on __unused) { return -ENOSYS; }
+ virtual status_t SetDownlinkMuteCodec(bool mute_on);
+
+
+ /** speech enhancement */
+ virtual status_t SetSpeechEnhancement(bool enhance_on);
+ virtual status_t SetSpeechEnhancementMask(const sph_enh_mask_struct_t &mask);
+ virtual uint16_t speechEnhancementMaskWrapper(const uint32_t enh_dynamic_mask);
+
+ virtual status_t SetBtHeadsetNrecOn(const bool bt_headset_nrec_on);
+
+
+ /** speech enhancement parameters setting */
+ virtual int updateSpeechParam(const SpeechScenario scenario);
+ virtual int updateSpeechFeature(const SpeechFeatureType featureType, const bool flagOn);
+ virtual int setParameter(const char *keyParameter);
+ virtual const char *getParameter(const char *keyParameter);
+
+ virtual status_t GetVibSpkParam(void *eVibSpkParam);
+ virtual status_t SetVibSpkParam(void *eVibSpkParam);
+
+ virtual status_t GetSmartpaParam(void *eParamSmartpa);
+ virtual status_t SetSmartpaParam(void *eParamSmartpa);
+
+
+ /** check whether modem is ready */
+ virtual bool CheckModemIsReady();
+
+ /** ecall */
+ virtual status_t eCallIvsSwitch(bool enable);
+ virtual status_t eCallIvsSend() ;
+ virtual status_t eCallPsapSwitch(bool enable);
+ virtual status_t eCallPsapSend();
+ virtual status_t eCallCtrlSeqSwitch(bool enable);
+ virtual status_t eCallMsd(void *data, uint16_t len);
+ virtual status_t eCallTxCtrlParam(void *data, uint16_t len);
+ virtual status_t eCallInfo();
+ virtual status_t eCallRxCtrl();
+
+ /* ecall */
+ spcEcallRXCtrlDataStruct mEcallRXCtrlData;
+ spcEcallIndicationStruct mEcallIndication;
+
+protected:
+ /** hide ctor */
+ SpeechDriverNormal() {}
+ SpeechDriverNormal(modem_index_t modem_index);
+
+
+ /** recover status (speech/record/bgs/vt/p2w/tty) */
+ virtual void RecoverModemSideStatusToInitState();
+
+ /** delay time */
+ virtual int getBtDelayTime(uint16_t *p_bt_delay_ms);
+ virtual int getUsbDelayTime(uint8_t *usbDelayMs);
+ virtual int getDriverParam(uint8_t paramType, void *paramBuf);
+
+
+ virtual int configSpeechInfo(sph_info_t *p_sph_info);
+
+ virtual int configMailBox(
+ sph_msg_t *p_sph_msg,
+ uint16_t msg_id,
+ uint16_t param_16bit,
+ uint32_t param_32bit);
+
+
+ virtual int configPayload(
+ sph_msg_t *p_sph_msg,
+ uint16_t msg_id,
+ uint16_t data_type,
+ void *data_buf,
+ uint16_t data_size);
+
+ virtual int sendSpeechMessageToQueue(sph_msg_t *p_sph_msg);
+
+ virtual int sendSpeechMessageAckToQueue(sph_msg_t *p_sph_msg);
+
+ static int sendSpeechMessageToModemWrapper(void *arg, sph_msg_t *p_sph_msg);
+ virtual int sendSpeechMessageToModem(sph_msg_t *p_sph_msg);
+
+ static int errorHandleSpeechMessageWrapper(void *arg, sph_msg_t *p_sph_msg);
+ virtual int errorHandleSpeechMessage(sph_msg_t *p_sph_msg);
+
+
+ virtual int sendMailbox(sph_msg_t *p_sph_msg,
+ uint16_t msg_id,
+ uint16_t param_16bit,
+ uint32_t param_32bit);
+
+ virtual int sendPayload(sph_msg_t *p_sph_msg,
+ uint16_t msg_id,
+ uint16_t data_type,
+ void *data_buf,
+ uint16_t data_size);
+
+
+ virtual int readSpeechMessageFromModem(sph_msg_t *p_sph_msg);
+
+
+ AudioLock mReadMessageLock;
+
+
+ /* not speech on/off but new/delete */
+ virtual void createThreads();
+ virtual void joinThreads();
+ bool mEnableThread;
+
+ static void *readSpeechMessageThread(void *arg);
+ pthread_t hReadSpeechMessageThread;
+ bool mReadMsgThreadCreated;
+ AudioLock mReadMsgThreadCreatedLock;
+
+
+ /* speech on/off */
+ virtual void createThreadsDuringSpeech();
+ virtual void joinThreadsDuringSpeech();
+ bool mEnableThreadDuringSpeech;
+
+ static void *modemStatusMonitorThread(void *arg);
+ pthread_t hModemStatusMonitorThread;
+ AudioLock mModemStatusMonitorThreadLock;
+
+ virtual int parseRawRecordPcmBuffer(void *raw_buf, void *parsed_buf, uint16_t *p_data_size);
+
+ virtual int processModemMessage(sph_msg_t *p_sph_msg);
+ virtual int processModemAckMessage(sph_msg_t *p_sph_msg);
+ virtual int processModemControlMessage(sph_msg_t *p_sph_msg);
+ virtual int processModemDataMessage(sph_msg_t *p_sph_msg);
+
+ virtual void processModemEPOF();
+ virtual void processModemAlive(sph_msg_t *sphMsg);
+ virtual void processNetworkCodecInfo(sph_msg_t *p_sph_msg);
+
+
+ SpeechMessengerNormal *mSpeechMessenger;
+
+
+ uint8_t mSampleRateEnum;
+
+
+ SpeechMessageQueue *mSpeechMessageQueue;
+ AudioLock mWaitAckLock;
+
+
+ bool getModemSideModemStatus(const modem_status_mask_t modem_status_mask) const;
+ void setModemSideModemStatus(const modem_status_mask_t modem_status_mask);
+ void resetModemSideModemStatus(const modem_status_mask_t modem_status_mask);
+ void cleanAllModemSideModemStatus();
+
+
+ virtual int parseSpeechParam(const SpeechScenario scenario);
+ virtual int writeAllSpeechParametersToModem(uint32_t *p_length, uint32_t *p_index);
+
+
+ uint32_t mModemSideModemStatus; // value |= modem_status_mask_t
+ AudioLock mModemSideModemStatusLock;
+
+
+ virtual int SpeechOnByApplication(const uint8_t application);
+ virtual int SpeechOffByApplication(const uint8_t application);
+ bool isSpeechApplicationOn() { return (mApplication != SPH_APPLICATION_INVALID); }
+
+ uint32_t kMaxApPayloadDataSize;
+ uint32_t kMaxMdPayloadDataSize;
+
+ void *mBgsBuf;
+ void *mVmRecBuf;
+ void *mRawRecBuf;
+ void *mParsedRecBuf;
+ void *mP2WUlBuf;
+ void *mP2WDlBuf;
+ void *mTtyDebugBuf;
+ void *mPcmMixerUlBuf;
+ void *mPcmMixerDlBuf;
+
+ uint8_t mApplication;
+ speech_mode_t mSpeechMode;
+ audio_devices_t mInputDevice;
+ audio_devices_t mOutputDevice;
+ bool isBtSpkDevice;
+ int mBTMode; // BT mode, 0:NB, 1:WB
+
+ AudioLock mRecordTypeLock;
+ AudioLock mSpeechParamLock;
+ AudioLock mFeatureMaskLock;
+
+ bool mTtyDebugEnable;
+
+ bool mApResetDuringSpeech;
+ bool mModemResetDuringSpeech;
+ bool mModemDead;
+ AudioLock mModemDeadLock;
+
+
+ /* loopback delay frames (1 frame = 20 ms) */
+ uint8_t mModemLoopbackDelayFrames;
+
+ /* RTT Mode */
+ int mRttMode;
+
+ /* to handle the case that ap crash before get ack */
+ virtual void waitModemAckAfterApDie();
+ bool mNeedWaitModemAckAfterApDie;
+ AudioLock mWaitModemAckAfterApDieLock;
+
+
+ /* keep ap need-ack control msg after send to md */
+ void setApWaitAckMsgID(sph_msg_t *p_sph_msg);
+ void resetApWaitAckMsgID();
+ uint16_t mApWaitAckMsgID;
+ AudioLock mApWaitAckMsgIDLock;
+
+ /* Speech Parser */
+ SpeechDataBufType mSpeechParam;
+ SpeechParserAttribute mSpeechParserAttribute;
+ MdAliveInfo mMdAliveInfo;
+ bool mIsParseFail;
+ uint8_t mPcmMixerTypeDl;
+ uint8_t mPcmMixerTypeUl;
+
+ /* BT config */
+ bool mIsBTSwitchConfig;
+
+private:
+ /** singleton */
+ static SpeechDriverNormal *mSpeechDriver;
+
+ int updateFeatureMask(const SpeechFeatureType featureType, const bool flagOn);
+
+};
+
+} /* end of namespace android */
+
+#endif /* end of ANDROID_SPEECH_DRIVER_NORMAL_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechEcallController.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechEcallController.h
new file mode 100644
index 0000000..e0f835a
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechEcallController.h
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef SPEECH_ECALL_CONTROLLER_H
+#define SPEECH_ECALL_CONTROLLER_H
+
+namespace android {
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+class SpeechEcallController {
+public:
+ SpeechEcallController();
+ /** virtual dtor */
+ virtual ~SpeechEcallController();
+
+};
+
+} /* end of namespace android */
+
+#endif /* end of SPEECH_ECALL_CONTROLLER_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechEnhancementController.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechEnhancementController.h
new file mode 100644
index 0000000..c79048f
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechEnhancementController.h
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_ENHANCEMENT_CONTROLLER_H
+#define ANDROID_SPEECH_ENHANCEMENT_CONTROLLER_H
+
+#include "AudioType.h"
+#include "SpeechType.h"
+
+#if !defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+#include "AudioCustParamClient.h"
+#endif
+
+namespace android {
+class SpeechEnhancementController {
+public:
+ static SpeechEnhancementController *GetInstance();
+
+ virtual ~SpeechEnhancementController();
+
+#if !defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ /**
+ * speech enhancement parameters setting
+ */
+ status_t SetNBSpeechParametersToAllModem(const AUDIO_CUSTOM_PARAM_STRUCT *pSphParamNB);
+ status_t SetDualMicSpeechParametersToAllModem(const AUDIO_CUSTOM_EXTRA_PARAM_STRUCT *pSphParamDualMic);
+ //#if defined(MTK_WB_SPEECH_SUPPORT)
+ status_t SetWBSpeechParametersToAllModem(const AUDIO_CUSTOM_WB_PARAM_STRUCT *pSphParamWB);
+ //#endif
+ status_t SetMagiConSpeechParametersToAllModem(const AUDIO_CUSTOM_MAGI_CONFERENCE_STRUCT *pSphParamMagiCon);
+ status_t SetHACSpeechParametersToAllModem(const AUDIO_CUSTOM_HAC_PARAM_STRUCT *pSphParamHAC);
+ status_t SetNBSpeechLpbkParametersToAllModem(const AUDIO_CUSTOM_PARAM_STRUCT *pSphParamNB, AUDIO_CUSTOM_SPEECH_LPBK_PARAM_STRUCT *pSphParamNBLpbk);
+#endif
+
+ /**
+ * speech enhancement functions on/off
+ */
+ sph_enh_mask_struct_t GetSpeechEnhancementMask() const { return mSpeechEnhancementMask; }
+ status_t SetSpeechEnhancementMaskToAllModem(const sph_enh_mask_struct_t &mask);
+
+ bool GetDynamicMask(const sph_enh_dynamic_mask_t dynamic_mask_type) const { return ((mSpeechEnhancementMask.dynamic_func & dynamic_mask_type) > 0); }
+ status_t SetDynamicMaskOnToAllModem(const sph_enh_dynamic_mask_t dynamic_mask_type, const bool new_flag_on);
+
+
+ bool GetMagicConferenceCallOn() const { return mMagicConferenceCallOn; }
+ void SetMagicConferenceCallOn(const bool magic_conference_call_on);
+
+ bool GetHACOn() const { return mHACOn; }
+ void SetHACOn(const bool hac_on);
+
+ status_t SetBtHeadsetNrecOnMaskOn(sph_enh_mask_struct_t *ori_mask, const sph_enh_dynamic_mask_t dynamic_mask_type, const bool new_flag_on);
+ void SetBtHeadsetNrecOnToAllModem(const bool bt_headset_nrec_on);
+ void SetSMNROn(void);
+ bool GetBtHeadsetNrecOn(void);
+
+private:
+ SpeechEnhancementController();
+ static SpeechEnhancementController *mSpeechEnhancementController; // singleton
+
+ sph_enh_mask_struct_t mSpeechEnhancementMask;
+
+ bool mMagicConferenceCallOn;
+ bool mHACOn;
+
+ bool mBtHeadsetNrecOn;
+ bool mSMNROn;
+};
+
+
+} // end namespace android
+
+#endif // end of ANDROID_SPEECH_ENHANCEMENT_CONTROLLER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechExtMemCCCI.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechExtMemCCCI.h
new file mode 100644
index 0000000..56b4210
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechExtMemCCCI.h
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_EXTMEM_CCCI_H
+#define ANDROID_SPEECH_EXTMEM_CCCI_H
+
+#include "SpeechType.h"
+
+#include <AudioLock.h>
+namespace android {
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+struct region_info_t;
+struct sph_shm_region_t;
+struct sph_shm_t;
+
+class SpeechExtMemCCCI {
+public:
+ SpeechExtMemCCCI();
+ /** virtual dtor */
+ virtual ~SpeechExtMemCCCI();
+
+ /** implementation according to different platform */
+
+ virtual int resetShareMemoryIndex();
+
+
+ virtual int writeSphParamToShareMemory(const void *p_sph_param,
+ uint32_t sph_param_length,
+ uint32_t *p_write_idx);
+
+
+ virtual int writeApDataToShareMemory(const void *data_buf,
+ uint16_t data_type,
+ uint16_t data_size,
+ uint16_t *p_payload_length,
+ uint32_t *p_write_idx);
+
+
+ virtual int readMdDataFromShareMemory(void *p_data_buf,
+ uint16_t *p_data_type,
+ uint16_t *p_data_size,
+ uint16_t payload_length,
+ uint32_t read_idx);
+
+ virtual int openShareMemory(const modem_index_t modem_index);
+ virtual int closeShareMemory();
+
+ virtual int formatShareMemory();
+ virtual bool checkModemAlive();
+
+private:
+ modem_index_t mModemIndex;
+ int mCcciShareMemoryHandler;
+ AudioLock mShareMemoryHandlerLock;
+
+ unsigned char *mShareMemoryBase;
+ unsigned int mShareMemoryLength;
+
+ sph_shm_t *mShareMemory;//shm struc
+ AudioLock mShareMemoryLock;//lock for shm struc
+
+ AudioLock mShareMemorySpeechParamLock;
+ AudioLock mShareMemoryApDataLock;
+ AudioLock mShareMemoryMdDataLock;
+
+ uint32_t shm_region_data_count(region_info_t *p_region);
+ uint32_t shm_region_free_space(region_info_t *p_region);
+ void shm_region_write_from_linear(region_info_t *p_region,
+ const void *linear_buf,
+ uint32_t count);
+ void shm_region_read_to_linear(void *linear_buf,
+ region_info_t *p_region,
+ uint32_t count);
+
+};
+
+} /* end of namespace android */
+
+#endif /* end of ANDROID_SPEECH_EXTMEM_CCCI_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechExtMemUSIP.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechExtMemUSIP.h
new file mode 100644
index 0000000..4d9d3d3
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechExtMemUSIP.h
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_EXTMEM_USIP_H
+#define ANDROID_SPEECH_EXTMEM_USIP_H
+
+#include "SpeechType.h"
+#include <AudioLock.h>
+
+namespace android {
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+struct region_info_t;
+struct sph_usip_shm_t;
+
+/*
+ * =============================================================================
+ * class
+ * =============================================================================
+ */
+class SpeechExtMemUSIP {
+public:
+ SpeechExtMemUSIP();
+ /** virtual dtor */
+ virtual ~SpeechExtMemUSIP();
+
+ /** implementation according to different platform */
+
+ virtual int resetShareMemoryIndex();
+ virtual int writeSphParamToShareMemory(const void *p_sph_param,
+ uint32_t sph_param_length,
+ uint32_t *p_write_idx);
+ virtual int openShareMemory(const modem_index_t modem_index);
+ virtual int closeShareMemory();
+ virtual int formatShareMemory();
+
+private:
+ modem_index_t mModemIndex;
+ int mCcciShareMemoryHandler;
+ AudioLock mShareMemoryHandlerLock;
+
+ unsigned char *mShareMemoryBase;
+ unsigned int mShareMemoryLength;
+
+ sph_usip_shm_t *mShareMemory;
+ AudioLock mShareMemoryLock;
+
+ region_info_t* mSpeechParamRegion;
+
+ uint32_t shm_region_data_count(region_info_t *p_region);
+ uint32_t shm_region_free_space(region_info_t *p_region);
+ void shm_region_write_from_linear(region_info_t *p_region,
+ const void *linear_buf,
+ uint32_t count);
+ void shm_region_read_to_linear(void *linear_buf,
+ region_info_t *p_region,
+ uint32_t count);
+ int updateWriteIndex(region_info_t *p_region, uint32_t count);
+
+};
+
+} /* end of namespace android */
+
+#endif /* end of ANDROID_SPEECH_EXTMEM_USIP_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechFeatureDef.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechFeatureDef.h
new file mode 100644
index 0000000..e84b3e1
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechFeatureDef.h
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef SPEECH_FEATURE_DEF_H
+#define SPEECH_FEATURE_DEF_H
+
+#include <stdint.h>
+
+/*
+ * =============================================================================
+ * enum
+ * =============================================================================
+ */
+
+enum TtyModeType {
+ AUD_TTY_OFF = 0,
+ AUD_TTY_FULL = 1,
+ AUD_TTY_VCO = 2,
+ AUD_TTY_HCO = 4,
+ AUD_TTY_ERR = -1
+};
+
+/** speech feature type for switch on/off , max 15*/
+enum SpeechFeatureType {
+ SPEECH_FEATURE_LOOPBACK = 0,
+ SPEECH_FEATURE_BTNREC = 1,
+ SPEECH_FEATURE_DMNR = 2,
+ SPEECH_FEATURE_LSPK_DMNR = 3,
+ SPEECH_FEATURE_HAC = 4,
+ SPEECH_FEATURE_SUPERVOLUME = 5,
+ NUM_SPEECH_FEATURE
+};
+#endif // end of SPEECH_FEATURE_DEF_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechLoopbackController.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechLoopbackController.h
new file mode 100644
index 0000000..52803e5
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechLoopbackController.h
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_LOOPBACK_CONTROLLER_H
+#define ANDROID_SPEECH_LOOPBACK_CONTROLLER_H
+
+#include "SpeechPhoneCallController.h"
+
+namespace android {
+
+class SpeechLoopbackController : public SpeechPhoneCallController { // class adaptor pattern
+public:
+ virtual ~SpeechLoopbackController();
+
+ static SpeechLoopbackController *GetInstance();
+
+ status_t OpenModemLoopbackControlFlow(const modem_index_t modem_index, const audio_devices_t input_device, const audio_devices_t output_device);
+ status_t CloseModemLoopbackControlFlow(const modem_index_t modem_index);
+ status_t SetModemBTCodec(bool enable_codec);
+
+protected:
+ SpeechLoopbackController();
+
+ float mVoiceVolumeCopy;
+
+private:
+ static SpeechLoopbackController *mSpeechLoopbackController; // singleton
+
+ //for BT SW BT CVSD loopback test
+ bool mUseBtCodec;
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_SPEECH_LOOPBACK_CONTROLLER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechMessageID.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechMessageID.h
new file mode 100644
index 0000000..c9b992a
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechMessageID.h
@@ -0,0 +1,320 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_MESSAGE_ID_H
+#define ANDROID_SPEECH_MESSAGE_ID_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+namespace android {
+
+
+/**
+ * =============================================================================
+ * ref
+ * =============================================================================
+ */
+
+struct sph_msg_t;
+
+
+/**
+ * =============================================================================
+ * Speech Message ID
+ * =============================================================================
+ */
+
+typedef uint16_t sph_msg_id_t;
+
+enum { /* sph_msg_id_t */
+ /**
+ * =========================================================================
+ * AP to Modem
+ * =========================================================================
+ */
+ MSG_A2M_SPH_DL_DIGIT_VOLUME = 0x2F00,
+ MSG_A2M_SPH_UL_DIGIT_VOLUME = 0x2F01,
+ MSG_A2M_MUTE_SPH_UL = 0x2F02,
+ MSG_A2M_MUTE_SPH_DL = 0x2F03,
+ MSG_A2M_SIDETONE_VOLUME = 0x2F04, // 93 removed
+ MSG_A2M_SPH_DL_ENH_REF_DIGIT_VOLUME = 0x2F05,
+ MSG_A2M_SIDETONE_CONFIG = 0x2F06, // 93 removed // Using modem SW STF or not
+ //MSG_A2M_MUTE_SPH_UL_ENH_RESULT = 0x2F07, // not used
+ MSG_A2M_MUTE_SPH_UL_SOURCE = 0x2F08,
+ MSG_A2M_MUTE_SPH_DL_CODEC = 0x2F09,
+
+ MSG_A2M_SET_SAMPLE_RATE = 0x2F10, // 93 removed
+ //MSG_A2M_SET_DUAL_MIC = 0x2F11, // 93 removed
+ MSG_A2M_SET_BT_DELAY_TIME = 0x2F12, // 93 removed
+ MSG_A2M_SET_LPBK_POINT_DVT = 0x2F13,
+
+ MSG_A2M_SPH_ON = 0x2F20,
+ MSG_A2M_SPH_OFF = 0x2F21,
+ MSG_A2M_SET_SPH_MODE = 0x2F22, // 93 removed, but may comeback with customize
+ MSG_A2M_CTRL_SPH_ENH = 0x2F23,
+ MSG_A2M_CONFIG_SPH_ENH = 0x2F24, // 93 removed
+ MSG_A2M_SET_ACOUSTIC_LOOPBACK = 0x2F25, // 93 removed
+ //MSG_A2M_PRINT_SPH_PARAM = 0x2F26, // 93 removed
+ //MSG_A2M_SPH_ON_FOR_HOLD_CALL = 0x2F27, // 93 removed // speech on with mute, for call hold use, no any other application can be turn on
+ //MSG_A2M_SPH_ON_FOR_DACA = 0x2F28, // 93 removed
+ MSG_A2M_SPH_ROUTER_ON = 0x2F29, // 93 removed // PCM wrouter on for enhancement and other application path.
+ MSG_A2M_SPH_ENCRYPTION = 0x2F2A,
+ MSG_A2M_SPH_DEV_CHANGE = 0x2F2B,
+ MSG_A2M_ENH_CTRL_SUPPORT = 0x2F2C,
+
+ MSG_A2M_PNW_ON = 0x2F30,
+ MSG_A2M_PNW_OFF = 0x2F31,
+ MSG_A2M_RECORD_ON = 0x2F32, // 93 removed
+ MSG_A2M_RECORD_OFF = 0x2F33, // 93 removed
+ //MSG_A2M_DMNR_RECPLAY_ON = 0x2F34, // 93 removed // not use in MT6582
+ //MSG_A2M_DMNR_RECPLAY_OFF = 0x2F35, // 93 removed // not use in MT6582
+ //MSG_A2M_DMNR_REC_ONLY_ON = 0x2F36, // 93 removed // not use in MT6582
+ //MSG_A2M_DMNR_REC_ONLY_OFF = 0x2F37, // 93 removed // not use in MT6582
+ MSG_A2M_PCM_REC_ON = 0x2F38, // 93 removed
+ MSG_A2M_PCM_REC_OFF = 0x2F39, // 93 removed
+ MSG_A2M_VM_REC_ON = 0x2F3A,
+ MSG_A2M_VM_REC_OFF = 0x2F3B,
+ MSG_A2M_RECORD_RAW_PCM_ON = 0x2F3C,
+ MSG_A2M_RECORD_RAW_PCM_OFF = 0x2F3D,
+ MSG_A2M_PCMMIXER_ON = 0x2F3E,
+ MSG_A2M_PCMMIXER_OFF = 0x2F3F,
+
+ MSG_A2M_CTM_ON = 0x2F40,
+ MSG_A2M_CTM_OFF = 0x2F41,
+ MSG_A2M_CTM_DUMP_DEBUG_FILE = 0x2F42,
+ MSG_A2M_BGSND_ON = 0x2F43,
+ MSG_A2M_BGSND_OFF = 0x2F44,
+ MSG_A2M_BGSND_CONFIG = 0x2F45,
+ MSG_A2M_RTT_CONFIG = 0x2F46,
+ MSG_A2M_PCMMIXER_CONFIG = 0x2F47,
+
+ MSG_A2M_PNW_DL_DATA_NOTIFY = 0x2F50,
+ MSG_A2M_BGSND_DATA_NOTIFY = 0x2F51,
+ MSG_A2M_CTM_DATA_NOTIFY = 0x2F52, // ?? removed
+ //MSG_A2M_DACA_UL_DATA_NOTIFY = 0x2F53, // 93 removed
+ MSG_A2M_SPH_UL_ENCRYPTION = 0x2F55,
+ MSG_A2M_SPH_DL_DECRYPTION = 0x2F56,
+ MSG_A2M_PCMMIXER_DL_DATA_NOTIFY = 0x2F57,
+ MSG_A2M_PCMMIXER_UL_DATA_NOTIFY = 0x2F58,
+
+ MSG_A2M_PNW_UL_DATA_READ_ACK = 0x2F60,
+ MSG_A2M_REC_DATA_READ_ACK = 0x2F61, // 93 removed
+ MSG_A2M_CTM_DEBUG_DATA_READ_ACK = 0x2F62,
+ MSG_A2M_PCM_REC_DATA_READ_ACK = 0x2F63, // 93 removed
+ MSG_A2M_VM_REC_DATA_READ_ACK = 0x2F64,
+ //MSG_A2M_DACA_DL_DATA_READ_ACK = 0x2F65, // 93 removed
+ MSG_A2M_RAW_PCM_REC_DATA_READ_ACK = 0x2F66,
+ MSG_A2M_CUST_DUMP_READ_ACK = 0x2F67,
+
+ MSG_A2M_EM_DATA_REQUEST_ACK = 0x2F70, // 93 removed, MD no need
+ MSG_A2M_EM_NB = 0x2F71, // 91 removed
+ MSG_A2M_EM_DMNR = 0x2F72, // 91 removed
+ MSG_A2M_EM_WB = 0x2F73, // 91 removed
+ MSG_A2M_EM_MAGICON = 0x2F74, // 91 removed
+ MSG_A2M_NETWORK_STATUS_ACK = 0x2F75, // modem no need
+ //MSG_A2M_QUERY_RF_INFO = 0x2F76, // only for 6595/6795 Async FIFO
+ MSG_A2M_EM_HAC = 0x2F77, // 91 removed
+ MSG_A2M_EPOF_ACK = 0x2F78,
+ MSG_A2M_EM_DYNAMIC_SPH = 0x2F79,
+ MSG_A2M_SPH_ENH_CORE = 0x2F7A, // 93 removed // opendsp 1, speech_dsp 2
+ MSG_A2M_DYNAMIC_PAR_IN_STRUCT_SHM = 0x2F7B,
+
+ MSG_A2M_VIBSPK_PARAMETER = 0x2F80,
+ MSG_A2M_SMARTPA_PARAMETER = 0x2F81, // 93 removed
+
+ MSG_A2M_NW_CODEC_INFO_READ_ACK = 0x2F90,
+
+ MSG_A2M_MD_ALIVE_ACK_BACK = 0x2FA0,
+
+ MSG_A2M_IVS_SWITCH = 0x2FB0,
+ MSG_A2M_PSAP_SWITCH = 0x2FB1,
+ MSG_A2M_IVS_SEND = 0x2FB2,
+ MSG_A2M_PSAP_SEND = 0x2FB3,
+ MSG_A2M_ECALL_CTL_SEQ_SWITCH = 0x2FB4,
+ MSG_A2M_ECALL_HANDSHAKE_INFO_READ_ACK = 0x2FB5,
+ MSG_A2M_ECALL_MSD = 0x2FB6,
+ MSG_A2M_ECALL_TX_CTRL_PAR = 0x2FB7,
+ MSG_A2M_ECALL_RX_CTRL_READ_ACK = 0x2FB8,
+
+
+ /**
+ * =========================================================================
+ * Modem to AP
+ * =========================================================================
+ */
+ //MSG_M2A_SPH_DL_DIGIT_VOLUME_ACK = 0x8000 | MSG_A2M_SPH_DL_DIGIT_VOLUME, // AP no need
+ //MSG_M2A_SPH_UL_DIGIT_VOLUME_ACK = 0x8000 | MSG_A2M_SPH_UL_DIGIT_VOLUME, // AP no need
+ MSG_M2A_MUTE_SPH_UL_ACK = 0x8000 | MSG_A2M_MUTE_SPH_UL,
+ MSG_M2A_MUTE_SPH_DL_ACK = 0x8000 | MSG_A2M_MUTE_SPH_DL,
+ //MSG_M2A_SIDETONE_VOLUME_ACK = 0x8000 | MSG_A2M_SIDETONE_VOLUME, // AP no need
+ //MSG_M2A_SPH_DL_ENH_REF_DIGIT_VOLUME_ACK = 0x8000 | MSG_A2M_SPH_DL_ENH_REF_DIGIT_VOLUME, // AP no need
+ //MSG_M2A_SIDETONE_CONFIG_ACK = 0x8000 | MSG_A2M_SIDETONE_CONFIG, // AP no need
+ //MSG_M2A_MUTE_SPH_UL_ENH_RESULT_ACK = 0x8000 | MSG_A2M_MUTE_SPH_UL_ENH_RESULT, // AP no need
+ MSG_M2A_MUTE_SPH_UL_SOURCE_ACK = 0x8000 | MSG_A2M_MUTE_SPH_UL_SOURCE,
+ //MSG_M2A_MUTE_SPH_DL_CODEC_ACK = 0x8000 | MSG_A2M_MUTE_SPH_DL_CODEC, // AP no need
+
+
+ //MSG_M2A_SET_SAMPLE_RATE_ACK = 0x8000 | MSG_A2M_SET_SAMPLE_RATE, // AP no need
+ //MSG_M2A_SET_DUAL_MIC_ACK = 0x8000 | MSG_A2M_SET_DUAL_MIC, // AP no need
+ //MSG_M2A_SET_BT_DELAY_TIME_ACK = 0x8000 | MSG_A2M_SET_BT_DELAY_TIME, // AP no need
+ //MSG_M2A_SET_LPBK_POINT_DVT_ACK = 0x8000 | MSG_A2M_SET_LPBK_POINT_DVT, // AP no need
+
+
+ MSG_M2A_SPH_ON_ACK = 0x8000 | MSG_A2M_SPH_ON,
+ MSG_M2A_SPH_OFF_ACK = 0x8000 | MSG_A2M_SPH_OFF,
+ MSG_M2A_SET_SPH_MODE_ACK = 0x8000 | MSG_A2M_SET_SPH_MODE,
+ //MSG_M2A_CTRL_SPH_ENH_ACK = 0x8000 | MSG_A2M_CTRL_SPH_ENH, // AP no need
+ //MSG_M2A_CONFIG_SPH_ENH_ACK = 0x8000 | MSG_A2M_CONFIG_SPH_ENH, // AP no need
+ MSG_M2A_SET_ACOUSTIC_LOOPBACK_ACK = 0x8000 | MSG_A2M_SET_ACOUSTIC_LOOPBACK,
+ //MSG_M2A_PRINT_SPH_PARAM_ACK = 0x8000 | MSG_A2M_PRINT_SPH_PARAM,
+ //MSG_M2A_SPH_ON_FOR_HOLD_CALL_ACK = 0x8000 | MSG_A2M_SPH_ON_FOR_HOLD_CALL,
+ //MSG_M2A_SPH_ON_FOR_DACA_ACK = 0x8000 | MSG_A2M_SPH_ON_FOR_DACA,
+ MSG_M2A_SPH_ROUTER_ON_ACK = 0x8000 | MSG_A2M_SPH_ROUTER_ON,
+ MSG_M2A_SPH_ENCRYPTION_ACK = 0x8000 | MSG_A2M_SPH_ENCRYPTION,
+ MSG_M2A_SPH_DEV_CHANGE_ACK = 0x8000 | MSG_A2M_SPH_DEV_CHANGE,
+ //MSG_M2A_ENH_CTRL_SUPPORT = 0x8000 | MSG_A2M_ENH_CTRL_SUPPORT, // AP no need
+
+
+ MSG_M2A_PNW_ON_ACK = 0x8000 | MSG_A2M_PNW_ON,
+ MSG_M2A_PNW_OFF_ACK = 0x8000 | MSG_A2M_PNW_OFF,
+ MSG_M2A_RECORD_ON_ACK = 0x8000 | MSG_A2M_RECORD_ON,
+ MSG_M2A_RECORD_OFF_ACK = 0x8000 | MSG_A2M_RECORD_OFF,
+ //MSG_M2A_DMNR_RECPLAY_ON_ACK = 0x8000 | MSG_A2M_DMNR_RECPLAY_ON,
+ //MSG_M2A_DMNR_RECPLAY_OFF_ACK = 0x8000 | MSG_A2M_DMNR_RECPLAY_OFF,
+ //MSG_M2A_DMNR_REC_ONLY_ON_ACK = 0x8000 | MSG_A2M_DMNR_REC_ONLY_ON,
+ //MSG_M2A_DMNR_REC_ONLY_OFF_ACK = 0x8000 | MSG_A2M_DMNR_REC_ONLY_OFF,
+ MSG_M2A_PCM_REC_ON_ACK = 0x8000 | MSG_A2M_PCM_REC_ON,
+ MSG_M2A_PCM_REC_OFF_ACK = 0x8000 | MSG_A2M_PCM_REC_OFF,
+ MSG_M2A_VM_REC_ON_ACK = 0x8000 | MSG_A2M_VM_REC_ON,
+ MSG_M2A_VM_REC_OFF_ACK = 0x8000 | MSG_A2M_VM_REC_OFF,
+ MSG_M2A_RECORD_RAW_PCM_ON_ACK = 0x8000 | MSG_A2M_RECORD_RAW_PCM_ON,
+ MSG_M2A_RECORD_RAW_PCM_OFF_ACK = 0x8000 | MSG_A2M_RECORD_RAW_PCM_OFF,
+ MSG_M2A_PCMMIXER_ON_ACK = 0x8000 | MSG_A2M_PCMMIXER_ON,
+ MSG_M2A_PCMMIXER_OFF_ACK = 0x8000 | MSG_A2M_PCMMIXER_OFF,
+
+ MSG_M2A_CTM_ON_ACK = 0x8000 | MSG_A2M_CTM_ON,
+ MSG_M2A_CTM_OFF_ACK = 0x8000 | MSG_A2M_CTM_OFF,
+ //MSG_M2A_CTM_DUMP_DEBUG_FILE_ACK = 0x8000 | MSG_A2M_CTM_DUMP_DEBUG_FILE, // AP no need
+ MSG_M2A_BGSND_ON_ACK = 0x8000 | MSG_A2M_BGSND_ON,
+ MSG_M2A_BGSND_OFF_ACK = 0x8000 | MSG_A2M_BGSND_OFF,
+ //MSG_M2A_BGSND_CONFIG_ACK = 0x8000 | MSG_A2M_BGSND_CONFIG,
+ //MSG_M2A_RTT_CONFIG_ACK = 0x8000 | MSG_A2M_RTT_CONFIG, // AP no need
+ MSG_M2A_PCMMIXER_CONFIG_ACK = 0x8000 | MSG_A2M_PCMMIXER_CONFIG,
+
+ MSG_M2A_PNW_DL_DATA_REQUEST = 0x8000 | MSG_A2M_PNW_DL_DATA_NOTIFY,
+ MSG_M2A_BGSND_DATA_REQUEST = 0x8000 | MSG_A2M_BGSND_DATA_NOTIFY,
+ MSG_M2A_CTM_DATA_REQUEST = 0x8000 | MSG_A2M_CTM_DATA_NOTIFY,
+ //MSG_M2A_DACA_UL_DATA_REQUEST = 0x8000 | MSG_A2M_DACA_UL_DATA_NOTIFY,
+ MSG_M2A_SPH_UL_ENCRYPTION = 0x8000 | MSG_A2M_SPH_UL_ENCRYPTION,
+ MSG_M2A_SPH_DL_DECRYPTION = 0x8000 | MSG_A2M_SPH_DL_DECRYPTION,
+ MSG_M2A_PCMMIXER_DL_DATA_REQUEST = 0x8000 | MSG_A2M_PCMMIXER_DL_DATA_NOTIFY,
+ MSG_M2A_PCMMIXER_UL_DATA_REQUEST = 0x8000 | MSG_A2M_PCMMIXER_UL_DATA_NOTIFY,
+
+ MSG_M2A_PNW_UL_DATA_NOTIFY = 0x8000 | MSG_A2M_PNW_UL_DATA_READ_ACK,
+ //MSG_M2A_REC_DATA_NOTIFY = 0x8000 | MSG_A2M_REC_DATA_READ_ACK,
+ MSG_M2A_CTM_DEBUG_DATA_NOTIFY = 0x8000 | MSG_A2M_CTM_DEBUG_DATA_READ_ACK,
+ MSG_M2A_PCM_REC_DATA_NOTIFY = 0x8000 | MSG_A2M_PCM_REC_DATA_READ_ACK,
+ MSG_M2A_VM_REC_DATA_NOTIFY = 0x8000 | MSG_A2M_VM_REC_DATA_READ_ACK,
+ //MSG_M2A_DACA_DL_DATA_NOTIFY = 0x8000 | MSG_A2M_DACA_DL_DATA_READ_ACK,
+ MSG_M2A_RAW_PCM_REC_DATA_NOTIFY = 0x8000 | MSG_A2M_RAW_PCM_REC_DATA_READ_ACK,
+ MSG_M2A_CUST_DUMP_NOTIFY = 0x8000 | MSG_A2M_CUST_DUMP_READ_ACK,
+
+ MSG_M2A_EM_DATA_REQUEST = 0x8000 | MSG_A2M_EM_DATA_REQUEST_ACK,
+ MSG_M2A_EM_NB_ACK = 0x8000 | MSG_A2M_EM_NB,
+ MSG_M2A_EM_DMNR_ACK = 0x8000 | MSG_A2M_EM_DMNR,
+ MSG_M2A_EM_WB_ACK = 0x8000 | MSG_A2M_EM_WB,
+ MSG_M2A_EM_MAGICON_ACK = 0x8000 | MSG_A2M_EM_MAGICON,
+ MSG_M2A_NETWORK_STATUS_NOTIFY = 0x8000 | MSG_A2M_NETWORK_STATUS_ACK,
+ //MSG_M2A_QUERY_RF_INFO_ACK = 0x8000 | MSG_A2M_QUERY_RF_INFO,
+ MSG_M2A_EM_HAC_ACK = 0x8000 | MSG_A2M_EM_HAC,
+ MSG_M2A_EPOF_NOTIFY = 0x8000 | MSG_A2M_EPOF_ACK,
+ MSG_M2A_EM_DYNAMIC_SPH_ACK = 0x8000 | MSG_A2M_EM_DYNAMIC_SPH,
+ MSG_M2A_SPH_ENH_CORE_ACK = 0x8000 | MSG_A2M_SPH_ENH_CORE,
+ MSG_M2A_DYNAMIC_PAR_IN_STRUCT_SHM_ACK = 0x8000 | MSG_A2M_DYNAMIC_PAR_IN_STRUCT_SHM,
+
+ MSG_M2A_VIBSPK_PARAMETER_ACK = 0x8000 | MSG_A2M_VIBSPK_PARAMETER,
+ MSG_M2A_SMARTPA_PARAMETER_ACK = 0x8000 | MSG_A2M_SMARTPA_PARAMETER,
+
+ MSG_M2A_NW_CODEC_INFO_NOTIFY = 0x8000 | MSG_A2M_NW_CODEC_INFO_READ_ACK,
+
+ MSG_M2A_MD_ALIVE = 0x8000 | MSG_A2M_MD_ALIVE_ACK_BACK,
+
+ MSG_M2A_IVS_SWITCH_ACK = 0x8000 | MSG_A2M_IVS_SWITCH,
+ MSG_M2A_PSAP_SWITCH_ACK = 0x8000 | MSG_A2M_PSAP_SWITCH,
+ MSG_M2A_ECALL_CTL_SEQ_SWITCH_ACK = 0x8000 | MSG_A2M_ECALL_CTL_SEQ_SWITCH,
+ MSG_M2A_ECALL_HANDSHAKE_INFO = 0x8000 | MSG_A2M_ECALL_HANDSHAKE_INFO_READ_ACK,
+ MSG_M2A_ECALL_MSD_ACK = 0x8000 | MSG_A2M_ECALL_MSD,
+ MSG_M2A_ECALL_TX_CTRL_PAR_ACK = 0x8000 | MSG_A2M_ECALL_TX_CTRL_PAR,
+ MSG_M2A_ECALL_RX_CTRL_PAR_NOTIFY = 0x8000 | MSG_A2M_ECALL_RX_CTRL_READ_ACK,
+};
+
+
+
+/**
+ * =============================================================================
+ * sph_msg_handshake_t
+ * =============================================================================
+ */
+
+typedef uint8_t sph_msg_handshake_t;
+
+enum { /* sph_msg_handshake_t */
+ /* AP -> Modem */
+ SPH_MSG_HANDSHAKE_AP_CTRL_BYPASS_ACK = 0x00, /* wait in quque(v), block queue(x) */
+ SPH_MSG_HANDSHAKE_AP_CTRL_NEED_ACK = 0x01, /* wait in quque(v), block queue(v) */
+
+ SPH_MSG_HANDSHAKE_AP_ACK_BACK_MD_CTRL = 0x11, /* ack to modem */
+
+ SPH_MSG_HANDSHAKE_AP_NOTIFY_DATA = 0x20, /* write ap data to modem */
+ SPH_MSG_HANDSHAKE_AP_READ_DATA_DONE = 0x21, /* read md data done */
+
+
+ /* MD -> AP */
+ SPH_MSG_HANDSHAKE_MD_ACK_BACK_AP_CTRL = 0x81, /* ack to ap */
+
+ SPH_MSG_HANDSHAKE_MD_CTRL_BYPASS_ACK = 0x90,
+ SPH_MSG_HANDSHAKE_MD_CTRL_NEED_ACK = 0x91,
+
+
+ SPH_MSG_HANDSHAKE_MD_REQUEST_DATA = 0xA0, /* modem need ap data */
+ SPH_MSG_HANDSHAKE_MD_NOTIFY_DATA = 0xA1, /* modem offer md data */
+
+ /* default */
+ SPH_MSG_HANDSHAKE_INVALID = 0xFF
+};
+
+
+uint16_t getSyncType(const uint16_t msg_id);
+
+
+/**
+ * =============================================================================
+ * utility
+ * =============================================================================
+ */
+
+bool isApMsgBypassQueue(const struct sph_msg_t *p_sph_msg);
+
+bool isApNeedAck(const struct sph_msg_t *p_sph_msg);
+bool isMdAckBack(const struct sph_msg_t *p_sph_msg);
+
+
+bool isApMsg(const struct sph_msg_t *p_sph_msg);
+
+bool isMdMsg(const struct sph_msg_t *p_sph_msg);
+
+int makeFakeMdAckMsgFromApMsg(struct sph_msg_t *p_sph_msg);
+
+bool isAckMessageInPair(const struct sph_msg_t *p_sph_msg,
+ const struct sph_msg_t *p_sph_msg_ack);
+
+bool isAckMessageInPairByID(const uint16_t ap_msg_id, const uint16_t md_msg_id);
+
+uint32_t getBlockThreadTimeMsByID(struct sph_msg_t *p_sph_msg);
+
+bool isNeedDumpMsg(const struct sph_msg_t *p_sph_msg);
+
+
+} /* end namespace android */
+
+#endif /* end of ANDROID_SPEECH_MESSAGE_ID_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechMessageQueue.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechMessageQueue.h
new file mode 100644
index 0000000..834e0d4
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechMessageQueue.h
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_MESSAGE_QUEUE_H
+#define ANDROID_SPEECH_MESSAGE_QUEUE_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <pthread.h>
+
+#include <AudioLock.h>
+
+
+namespace android {
+
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+
+struct sph_msg_t;
+
+
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+
+/* callback to send msg to modem */
+typedef int (*send_message_wrapper_fp_t)(void *arg, sph_msg_t *p_sph_msg);
+
+/* callback to msg error handle */
+typedef int (*error_handle_message_wrapper_fp_t)(void *arg, sph_msg_t *p_sph_msg);
+
+
+/*
+ * =============================================================================
+ * public function
+ * =============================================================================
+ */
+
+class SpeechQueueElement;
+
+
+class SpeechMessageQueue {
+public:
+ SpeechMessageQueue(
+ send_message_wrapper_fp_t send_message_wrapper,
+ error_handle_message_wrapper_fp_t error_handle_message_wrapper,
+ void *wrapper_arg);
+ virtual ~SpeechMessageQueue();
+
+ int sendSpeechMessageToQueue(sph_msg_t *p_sph_msg,
+ const uint32_t block_thread_ms);
+
+ int sendSpeechMessageAckToQueue(sph_msg_t *p_sph_msg_ack);
+ void notifyQueueToStopWaitingAck();
+ inline void resetStopWaitAckFlag() { mStopWaitAck = false; }
+
+
+
+private:
+ SpeechMessageQueue() {}
+
+ bool checkQueueEmpty() const;
+ bool checkQueueToBeFull() const;
+ bool checkQueueIndexValid(const uint32_t index) const;
+
+ uint32_t getQueueSize() const;
+ uint32_t getQueueNumElements() const;
+
+ int pushElement(sph_msg_t *p_sph_msg, uint32_t *idx_msg);
+ int popElement();
+ int frontElement(sph_msg_t **pp_sph_msg, uint32_t *idx_msg);
+
+ int waitUntilElementProcessDone(const uint32_t idx_msg, const uint32_t ms);
+ int signalElementProcessDone(const uint32_t idx_msg);
+
+ int waitUntilModemAckBack(sph_msg_t *p_sph_msg, uint32_t idx_msg);
+
+
+ int getQueueElementUntilPushed(sph_msg_t **pp_sph_msg, uint32_t *idx_msg);
+
+ bool mEnableThread; /* not speech on/off but new/delete status */
+ static void *processElementThread(void *arg);
+ pthread_t hProcessElementThread;
+
+ int sendSpeechMessage(sph_msg_t *p_sph_msg);
+ int errorHandleSpeechMessage(sph_msg_t *p_sph_msg);
+
+
+ AudioLock mQueueLock;
+ SpeechQueueElement *mQueue;
+ uint32_t mQueueSize;
+ uint32_t mQueueIndexRead;
+ uint32_t mQueueIndexWrite;
+
+
+ AudioLock mWaitAckLock;
+
+ bool mWaitAckFlag;
+ bool mStopWaitAck;
+ sph_msg_t *mSphMsgAck;
+
+
+ send_message_wrapper_fp_t sendMessageWrapper;
+ error_handle_message_wrapper_fp_t errorHandleMessageWrapper;
+ void *mWrapperArg;
+};
+
+
+
+} /* end of namespace android */
+
+#endif /* end of ANDROID_SPEECH_MESSAGE_QUEUE_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechMessengerInterface.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechMessengerInterface.h
new file mode 100644
index 0000000..d227d52
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechMessengerInterface.h
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_MESSAGE_INTERFACE_H
+#define ANDROID_SPEECH_MESSAGE_INTERFACE_H
+
+#include <pthread.h>
+
+#include "AudioType.h"
+#include "SpeechType.h"
+#include "AudioUtility.h"
+
+#include "SpeechBGSPlayer.h"
+#include "SpeechPcm2way.h"
+
+#include <SpeechMessageID.h>
+
+
+
+namespace android {
+
+#define CCCI_BUF_HEADER_SIZE 16
+//EEMCS MTU 3584-128 = 3456 byte
+#define CCCI_MAX_PAYLOAD_DATA_BYTE 3434 //(3456-16)-6
+#define CCCI_MAX_PAYLOAD_SIZE 860 //(3456-16)/4 = 860
+#define CCCI_MAX_PAYLOAD_BYTE 3440 //(3456-16)/4 = 860
+/** CCCI buffer structure */
+typedef struct {
+ uint32_t magic;
+ uint32_t message; // message[31:16] = id, message[15:0] = parameters
+ uint32_t channel;
+ uint32_t reserved;
+ uint32_t payload[CCCI_MAX_PAYLOAD_SIZE];
+} ccci_buff_t;
+/** CCCI driver & ioctl */
+
+/** CCCI message need/no need ack type */
+enum ccci_message_ack_t {
+ MESSAGE_BYPASS_ACK = 0,
+ MESSAGE_NEED_ACK = 1,
+ MESSAGE_CANCELED = 8
+};
+
+/** CCCI message queue structure */
+typedef struct ccci_queue_element_t {
+ ccci_buff_t ccci_buff;
+ ccci_message_ack_t ack_type;
+} ccci_queue_element_t;
+
+
+/** Speech parameter ack type */
+enum speech_param_ack_t {
+ NB_SPEECH_PARAM = 0,
+ DMNR_SPEECH_PARAM,
+ WB_SPEECH_PARAM,
+ MAGICON_SPEECH_PARAM,
+ HAC_SPEECH_PARAM,
+ DYNAMIC_SPH_PARAM,
+ NUM_SPEECH_PARAM_ACK_TYPE
+};
+
+
+/** CCCI share buffer related infomation */
+const size_t CCCI_SHARE_BUFF_HEADER_LEN = 6;
+const size_t CCCI_PAYLOAD_BUFF_HEADER_LEN = 10;
+const size_t CCCI_RAW_PCM_BUFF_HEADER_LEN = 8;
+#define CCCI_SHAREBUF_GUARD_LENGTH 32
+
+enum share_buff_sync_t {
+ CCCI_A2M_SHARE_BUFF_HEADER_SYNC = 0xA2A2,
+ CCCI_M2A_SHARE_BUFF_HEADER_SYNC = 0x2A2A,
+ EEMCS_M2A_SHARE_BUFF_HEADER_SYNC = 0x1234
+};
+
+
+enum speech_band_info_t {
+ SPEECH_NARROW_BAND = 0,
+ SPEECH_WIDEBAND,
+ SPEECH_SUPER_WIDBAND,
+ SPEECH_FULL_BAND,
+};
+
+
+//For VT case, the CCCI message for every 20ms, UL/DL have 2 CCCI message (Put to Speaker / Get from Mic)
+//For BGS off ack message, the worst case maybe pending 150 ms. And for other change device control. (BGSoff,2WAY off,SPH off,...)
+//The total message maybe > 20 for this period. So enlarge the total CCCI message queue.
+//For the CCCI queue in CCCI kernel driver, the size is 60.
+//For the CCCI queue in Modem side, the size is 32.
+//Modem side would keep on optimized the BGS off ack period.
+const size_t CCCI_MAX_QUEUE_NUM = 60;
+
+//BGSound use MAX 2026 bytes for 16K SR(2020+6 bytes)
+//MAX Payload size 3440 bytes
+// payload length inculde 6 byte sync words and data size
+#ifdef CCCI_FORCE_USE
+const size_t A2M_SHARED_BUFFER_BGS_DATA_SIZE = 2026;
+const size_t A2M_SHARED_BUFFER_P2W_DL_DATA_SIZE = PCM2WAY_PLAY_BUFFER_WB_LEN;
+#else
+const size_t A2M_SHARED_BUFFER_BGS_DATA_SIZE = CCCI_MAX_PAYLOAD_BYTE;
+const size_t A2M_SHARED_BUFFER_P2W_DL_DATA_SIZE = CCCI_MAX_PAYLOAD_BYTE;
+#endif
+const size_t A2M_SHARED_BUFFER_BGS_DATA_BASE = 0;
+const size_t A2M_SHARED_BUFFER_BGS_DATA_END = A2M_SHARED_BUFFER_BGS_DATA_BASE + CCCI_SHARE_BUFF_HEADER_LEN + A2M_SHARED_BUFFER_BGS_DATA_SIZE;
+
+// PCM2WAY playback use MAX 640 bytes for 16K SR( 640+6 bytes)
+const size_t A2M_SHARED_BUFFER_P2W_DL_DATA_BASE = A2M_SHARED_BUFFER_BGS_DATA_END;
+const size_t A2M_SHARED_BUFFER_P2W_DL_DATA_END = A2M_SHARED_BUFFER_P2W_DL_DATA_BASE + CCCI_SHARE_BUFF_HEADER_LEN + A2M_SHARED_BUFFER_P2W_DL_DATA_SIZE;
+
+// Speech enhacement parameters use MAX 640 bytes for WB Param( 2919+6 bytes)
+const size_t A2M_SHARED_BUFFER_SPH_PARAM_BASE = A2M_SHARED_BUFFER_P2W_DL_DATA_END;
+const size_t A2M_SHARED_BUFFER_SPH_PARAM_SIZE = CCCI_MAX_PAYLOAD_BYTE;
+
+//UL DL Encryptor
+const size_t A2M_SHARED_BUFFER_ULDL_DATA_SIZE = 1024;
+const size_t A2M_SHARED_BUFFER_ULENC_SOURCE_BASE = 0;
+const size_t A2M_SHARED_BUFFER_ULENC_TARGET_BASE = A2M_SHARED_BUFFER_ULENC_SOURCE_BASE + A2M_SHARED_BUFFER_ULDL_DATA_SIZE;
+const size_t A2M_SHARED_BUFFER_DLDEC_SOURCE_BASE = A2M_SHARED_BUFFER_ULENC_TARGET_BASE + A2M_SHARED_BUFFER_ULDL_DATA_SIZE;
+const size_t A2M_SHARED_BUFFER_DLDEC_TARGET_BASE = A2M_SHARED_BUFFER_DLDEC_SOURCE_BASE + A2M_SHARED_BUFFER_ULDL_DATA_SIZE;
+
+/* CCCI Message ID */
+const uint32_t CCCI_MSG_A2M_BASE = 0x2F00;
+const uint32_t CCCI_MSG_M2A_BASE = 0xAF00;
+
+class SpeechMessengerInterface {
+public:
+ virtual ~SpeechMessengerInterface() {}
+ virtual status_t Initial() = 0;
+ virtual status_t Deinitial() = 0;
+ virtual bool A2MBufLock() = 0;
+ virtual void A2MBufUnLock() = 0;
+
+ virtual status_t WaitUntilModemReady() = 0;
+
+ virtual ccci_buff_t InitCcciMailbox(uint16_t id, uint16_t param_16bit, uint32_t param_32bit) = 0;
+ virtual status_t SendMessageInQueue(ccci_buff_t ccci_buff) = 0;
+
+ inline uint32_t GetA2MShareBufLen() const { return mA2MShareBufLen; }
+ inline char *GetA2MShareBufBase() const { return mA2MShareBufBase; }
+
+ inline uint8_t SetShareBufHeader(uint16_t *ptr16, uint16_t sync, share_buff_data_type_t type, uint16_t length) const {
+ ptr16[0] = sync;
+ ptr16[1] = type;
+ ptr16[2] = length;
+ return CCCI_SHARE_BUFF_HEADER_LEN; // 3 * sizeof(uint16_t);
+ }
+ inline uint32_t GetM2AShareBufLen() const { return mM2AShareBufLen; }
+ inline char *GetM2AShareBufBase() const { return mM2AShareBufBase; }
+ virtual uint16_t GetM2AShareBufSyncWord(const ccci_buff_t &ccci_buff) = 0;
+ virtual uint16_t GetM2AShareBufDataType(const ccci_buff_t &ccci_buff) = 0;
+ virtual uint16_t GetM2AShareBufDataLength(const ccci_buff_t &ccci_buff) = 0;
+
+ inline bool WasModemReset() const { return mWasModemReset;}
+ inline void ResetWasModemReset(bool val) {
+ mWasModemReset = val;
+ return;
+ }
+
+ /**
+ * get modem side modem function status
+ */
+ virtual bool GetModemSideModemStatus(const modem_status_mask_t modem_status_mask) const = 0;
+
+
+ /**
+ * check whether modem side get all necessary speech enhancement parameters here
+ */
+ virtual bool CheckSpeechParamAckAllArrival() = 0;
+
+
+ /**
+ * check whether modem is ready. (if w/o SIM && phone_2 => modem sleep)
+ */
+ virtual bool CheckModemIsReady() = 0;
+
+ /**
+ * check whether modem audio is ready from reset.
+ */
+ virtual bool GetMDResetFlag() = 0;
+
+ /**
+ * set raw record type.
+ */
+ virtual status_t setPcmRecordType(SpcRecordTypeStruct typeRecord) = 0;
+
+#ifdef USE_CCCI_SHARE_BUFFER
+ virtual void InitA2MRawParaRingBuffer() = 0;
+ virtual status_t GetA2MRawParaRingBuffer(uint16_t *offset, uint16_t *avail) = 0;
+ virtual status_t AdvanceA2MRawParaRingBuffer(int datalength) = 0;
+ virtual status_t WriteA2MRawParaRingBuffer(char *data, int datalength) = 0;
+#endif
+
+protected:
+ virtual char GetModemCurrentStatus() = 0;
+
+ virtual uint16_t GetMessageID(const ccci_buff_t &ccci_buff) = 0;
+ virtual uint16_t GetMessageParam(const ccci_buff_t &ccci_buff) = 0;
+
+ virtual uint16_t GetMessageLength(const ccci_buff_t &ccci_buff) = 0;
+ virtual uint16_t GetMessageOffset(const ccci_buff_t &ccci_buff) = 0;
+ virtual bool CheckOffsetAndLength(const ccci_buff_t &ccci_buff) = 0;
+
+ virtual ccci_message_ack_t JudgeAckOfMsg(const uint16_t message_id) = 0;
+
+ virtual bool IsModemFunctionOnOffMessage(const uint16_t message_id) = 0;
+
+ virtual status_t SendMessage(const ccci_buff_t &ccci_buff) = 0;
+ virtual status_t ReadMessage(ccci_buff_t &ccci_buff) = 0;
+ virtual void SendMsgFailErrorHandling(const ccci_buff_t &ccci_buff) = 0;
+
+ virtual RingBuf GetM2AUplinkRingBuffer(const ccci_buff_t &ccci_buff) = 0;
+
+ virtual status_t CreateReadingThread() = 0;
+ virtual status_t CreateSendSphParaThread() = 0;
+
+ // for message queue
+ virtual uint32_t GetQueueCount() const = 0;
+ virtual status_t ConsumeMessageInQueue() = 0;
+ virtual bool MDReset_CheckMessageInQueue() = 0;
+
+ virtual void ResetSpeechParamAckCount() = 0;
+ virtual void AddSpeechParamAckCount(speech_param_ack_t type) = 0;
+
+
+ /**
+ * set/reset AP side modem function status
+ */
+
+ virtual void SetModemSideModemStatus(const modem_status_mask_t modem_status_mask) = 0;
+ virtual void ResetModemSideModemStatus(const modem_status_mask_t modem_status_mask) = 0;
+
+ // lock
+ virtual bool SpeechParamLock() = 0;
+ virtual void SpeechParamUnLock() = 0;
+
+ // share buffer base and len
+ uint32_t mA2MShareBufLen;
+ uint32_t mM2AShareBufLen;
+
+ char *mA2MShareBufBase;
+ char *mM2AShareBufBase;
+
+ char *mA2MShareBufEnd;
+ char *mM2AShareBufEnd;
+
+ RingBuf mM2AShareBuf;
+ bool mWasModemReset;
+};
+
+
+} // end namespace android
+
+#endif // end of ANDROID_SPEECH_MESSAGE_INTERFACE_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechMessengerNormal.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechMessengerNormal.h
new file mode 100644
index 0000000..5b7d6be
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechMessengerNormal.h
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_MESSENGER_NORMAL_H
+#define ANDROID_SPEECH_MESSENGER_NORMAL_H
+
+#include <stdint.h>
+
+#include <SpeechType.h>
+
+#include <AudioLock.h>
+
+
+namespace android {
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+
+struct ccci_msg_t;
+class SpeechShareMemBase;
+
+
+/*
+ * =============================================================================
+ * class
+ * =============================================================================
+ */
+
+class SpeechMessengerNormal {
+public:
+ SpeechMessengerNormal(const modem_index_t modem_index);
+ virtual ~SpeechMessengerNormal();
+
+ virtual bool checkModemReady();
+ virtual bool checkModemAlive();
+
+
+ virtual uint32_t getMaxApPayloadDataSize();
+ virtual uint32_t getMaxMdPayloadDataSize();
+
+ virtual int sendSpeechMessage(sph_msg_t *p_sph_msg);
+ virtual int readSpeechMessage(sph_msg_t *p_sph_msg);
+
+ virtual int resetShareMemoryIndex();
+
+
+ virtual int writeSphParamToShareMemory(const void *p_sph_param,
+ uint32_t sph_param_length,
+ uint32_t *p_write_idx);
+
+
+ virtual int writeApDataToShareMemory(const void *data_buf,
+ uint16_t data_type,
+ uint16_t data_size,
+ uint16_t *p_payload_length,
+ uint32_t *p_write_idx);
+
+
+ virtual int readMdDataFromShareMemory(void *p_data_buf,
+ uint16_t *p_data_type,
+ uint16_t *p_data_size,
+ uint16_t payload_length,
+ uint32_t read_idx);
+ virtual int getShareMemoryType();
+
+protected:
+ SpeechMessengerNormal() {}
+
+
+ virtual int openCcciDriver();
+ virtual int closeCcciDriver();
+
+ virtual int openShareMemory();
+ virtual int closeShareMemory();
+
+ virtual int checkCcciStatusAndRecovery();
+
+ virtual int formatShareMemory();
+ static void *formatShareMemoryThread(void *arg);
+ pthread_t hFormatShareMemoryThread;
+
+ virtual int speechMessageToCcciMessage(sph_msg_t *p_sph_msg, ccci_msg_t *p_ccci_msg);
+ virtual int ccciMessageToSpeechMessage(ccci_msg_t *p_ccci_msg, sph_msg_t *p_sph_msg);
+
+
+ modem_index_t mModemIndex;
+
+
+ int mCcciDeviceHandler;
+ int mCcciShareMemoryHandler;
+ AudioLock mCcciHandlerLock;
+ AudioLock mShareMemoryHandlerLock;
+
+ ccci_msg_t *mCcciMsgSend;
+ AudioLock mCcciMsgSendLock;
+
+
+ ccci_msg_t *mCcciMsgRead;
+ AudioLock mCcciMsgReadLock;
+
+ SpeechShareMemBase *mSpeechShareMem;
+
+
+};
+
+} /* end namespace android */
+
+#endif /* end of ANDROID_SPEECH_MESSENGER_NORMAL_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechParserBase.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechParserBase.h
new file mode 100644
index 0000000..c022646
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechParserBase.h
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_PARSER_BASE_H
+#define ANDROID_SPEECH_PARSER_BASE_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include "SpeechParserType.h"
+
+
+namespace android {
+
+/*
+ * =============================================================================
+ * class
+ * =============================================================================
+ */
+
+class SpeechParserBase {
+public:
+ virtual ~SpeechParserBase() {}
+
+ /**
+ * get instance's pointer
+ */
+ static SpeechParserBase *getInstance();
+
+ /**
+ * =========================================================================
+ * @brief Parsing param file to get parameters into pOutBuf
+ *
+ * @param speechParserAttribute: the attribute for parser
+ * @param pOutBuf: the output buffer
+ * @param sizeByteOutBuf: the size byte of output buffer
+ *
+ * @return int
+ * =========================================================================
+ */
+ virtual int getParamBuffer(SpeechParserAttribute speechParserAttribute, SpeechDataBufType *outBuf) = 0;
+
+ /**
+ * =========================================================================
+ * @brief set keyString string to library
+ *
+ * @param keyString the "key=value" string
+ * @param sizeKeyString the size byte of string
+ *
+ * @return int
+ * =========================================================================
+ */
+ virtual int setKeyValuePair(const SpeechStringBufType *keyValuePair) = 0;
+
+ /**
+ * =========================================================================
+ * @brief get keyString string from library
+ *
+ * @param keyString there is only "key" when input,
+ and then library need rewrite "key=value" to keyString
+ * @param sizeKeyString the size byte of string
+ *
+ * @return int
+ * =========================================================================
+ */
+ virtual int getKeyValuePair(SpeechStringBufType *keyValuePair) = 0;
+
+ /**
+ * =========================================================================
+ * @brief update phone call status from driver
+ *
+ * @param callOn: the phone call status: true(On), false(Off)
+ *
+ * @return int
+ * =========================================================================
+ */
+ virtual int updatePhoneCallStatus(bool callOn) = 0;
+
+ bool mCallOn;
+
+protected:
+ SpeechParserAttribute mSpeechParserAttribute;
+ SpeechParserBase() {
+ mCallOn = false;
+ mSpeechParserAttribute.inputDevice = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ mSpeechParserAttribute.outputDevice = AUDIO_DEVICE_OUT_EARPIECE;
+ mSpeechParserAttribute.idxVolume = 3;
+ mSpeechParserAttribute.driverScenario = SPEECH_SCENARIO_SPEECH_ON;
+ mSpeechParserAttribute.ttyMode = AUD_TTY_OFF;
+ mSpeechParserAttribute.speechFeatureOn = 0;
+ mParamBuf = NULL;
+ mParamBufSize = 0;
+ }
+ void *mParamBuf;
+ uint32_t mParamBufSize;
+
+private:
+ /**
+ * singleton pattern
+ */
+ static SpeechParserBase *uniqueSpeechParser;
+
+};
+
+
+
+} // end namespace android
+
+#endif // end of ANDROID_SPEECH_PARSER_BASE_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechParserGen93.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechParserGen93.h
new file mode 100644
index 0000000..6345fcd
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechParserGen93.h
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef _SPEECH_PARSER_GEN93_H_
+#define _SPEECH_PARSER_GEN93_H_
+
+#include "AudioType.h"
+#include "SpeechType.h"
+#include <vector>
+#include <AudioParamParser.h>
+#include "SpeechParserBase.h"
+
+namespace android {
+
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+
+struct SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT;
+struct SPEECH_ECHOREF_PARAM_STRUCT;
+struct AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT;
+struct SPEECH_PARAM_INFO_STRUCT;
+struct SPEECH_PARAM_SUPPORT_STRUCT;
+struct SPEECH_NETWORK_STRUCT;
+
+enum speech_type_dynamic_param_t {
+ AUDIO_TYPE_SPEECH = 0,
+ AUDIO_TYPE_SPEECH_DMNR = 1,
+ AUDIO_TYPE_SPEECH_GENERAL = 2,
+ AUDIO_TYPE_SPEECH_MAGICLARITY = 3,
+ AUDIO_TYPE_SPEECH_NETWORK = 4,
+ AUDIO_TYPE_SPEECH_ECHOREF = 5,
+ AUDIO_TYPE_SPEECH_DEREVERB = 6,
+
+
+ NUM_AUDIO_TYPE_SPEECH_TYPE /* the #types of speech_type_dynamic_param_t */
+};
+
+/*
+ * =============================================================================
+ * class
+ * =============================================================================
+ */
+
+class SpeechParserGen93 : public SpeechParserBase {
+
+public:
+ virtual ~SpeechParserGen93();
+
+ /**
+ * get instance's pointer
+ */
+ static SpeechParserGen93 *getInstance();
+
+ /**
+ * =========================================================================
+ * @brief Parsing param file to get parameters into pOutBuf
+ *
+ * @param speechParserAttribute: the attribute for parser
+ * @param pOutBuf: the output buffer
+ * @param sizeByteOutBuf: the size byte of output buffer
+ *
+ * @return int
+ * =========================================================================
+ */
+ virtual int getParamBuffer(SpeechParserAttribute speechParserAttribute, SpeechDataBufType *outBuf);
+
+ /**
+ * =========================================================================
+ * @brief set keyString string to library
+ *
+ * @param keyString the "key=value" string
+ * @param sizeKeyString the size byte of string
+ *
+ * @return int
+ * =========================================================================
+ */
+ virtual int setKeyValuePair(const SpeechStringBufType *keyValuePair);
+
+ /**
+ * =========================================================================
+ * @brief get keyString string from library
+ *
+ * @param keyString there is only "key" when input,
+ and then library need rewrite "key=value" to keyString
+ * @param sizeKeyString the size byte of string
+ *
+ * @return int
+ * =========================================================================
+ */
+ virtual int getKeyValuePair(SpeechStringBufType *keyValuePair);
+
+ /**
+ * =========================================================================
+ * @brief update phone call status from driver
+ *
+ * @param callOn: the phone call status: true(On), false(Off)
+ *
+ * @return int
+ * =========================================================================
+ */
+ virtual int updatePhoneCallStatus(bool callOn);
+
+ speech_type_dynamic_param_t mIdxAudioType;
+ std::vector<speech_type_dynamic_param_t> mChangedXMLQueue;
+
+protected:
+ SpeechParserGen93();
+ SpeechParserAttribute mSpeechParserAttribute;
+
+private:
+ /**
+ * singleton pattern
+ */
+ static SpeechParserGen93 *uniqueSpeechParser;
+ AppHandle *mAppHandle;
+ int getSpeechProfile(const SpeechParserAttribute speechParserAttribute);
+ int getDeverbProfile(const SpeechParserAttribute speechParserAttribute);
+
+ void init();
+ void initAppParser();
+ void deInit();
+
+ /*original api end*/
+ int getSpeechParamUnit(char *packedParamUnit);
+ int getGeneralParamUnit(char *bufParamUnit);
+ int getMagiClarityParamUnit(char *bufParamUnit);
+ int getDmnrParamUnit(char *bufParamUnit);
+ int getDereverbParamUnit(char *bufParamUnit);
+ /*original api end*/
+
+ status_t getSpeechParamFromAppParser(uint16_t speechTypeIndex, AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT *paramLayerInfo, char *packedParamUnit, uint16_t *sizeByteTotal);
+ uint16_t sizeByteParaData(uint16_t dataType, uint16_t arraySize);
+ status_t speechDataDump(char *bufDump, uint16_t speechTypeIndex, const char *nameParam, const char *speechParamData);
+ status_t setMDParamUnitHdr(speech_type_dynamic_param_t idxAudioType, SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT *paramUnitHdr, uint16_t configValue);
+ uint16_t setMDParamDataHdr(SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT paramUnitHdr, const char *cateBandName, const char *cateNetworkName);
+ int initSpeechNetwork(void);
+
+ SPEECH_PARAM_INFO_STRUCT *mSphParamInfo;
+ SPEECH_NETWORK_STRUCT *mListSpeechNetwork;
+ uint8_t mNumSpeechNetwork, mSpeechParamVerFirst, mSpeechParamVerLast, mNumSpeechParam;
+ SPEECH_NETWORK_STRUCT *mNameForEachSpeechNetwork;
+ SPEECH_PARAM_SUPPORT_STRUCT *mSphParamSupport;
+ speech_mode_t getSpeechModeByOutputDevice(const audio_devices_t output_device);
+ uint32_t getMaxBufferSize();
+ bool getFeatureOn(const SpeechFeatureType featureType);
+
+}; //SpeechParserLegacy
+
+} //namespace android
+
+#endif //_SPEECH_PARSER_GEN93_H_
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechParserGen95.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechParserGen95.h
new file mode 100644
index 0000000..18fd625
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechParserGen95.h
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_PARSER_GEN95_H
+#define ANDROID_SPEECH_PARSER_GEN95_H
+
+#include "SpeechParserBase.h"
+#include <vector>
+
+namespace android {
+
+/*
+ * =============================================================================
+ * class
+ * =============================================================================
+ */
+
+class SpeechParserGen95 : public SpeechParserBase {
+
+
+public:
+ virtual ~SpeechParserGen95();
+
+ /**
+ * get instance's pointer
+ */
+ static SpeechParserGen95 *getInstance();
+
+ /**
+ * =========================================================================
+ * @brief Parsing param file to get parameters into pOutBuf
+ *
+ * @param speechParserAttribute: the attribute for parser
+ * @param pOutBuf: the output buffer
+ * @param sizeByteOutBuf: the size byte of output buffer
+ *
+ * @return int
+ * =========================================================================
+ */
+ virtual int getParamBuffer(SpeechParserAttribute speechParserAttribute, SpeechDataBufType *outBuf);
+
+ /**
+ * =========================================================================
+ * @brief set keyString string to library
+ *
+ * @param keyString the "key=value" string
+ * @param sizeKeyString the size byte of string
+ *
+ * @return int
+ * =========================================================================
+ */
+ virtual int setKeyValuePair(const SpeechStringBufType *keyValuePair);
+
+ /**
+ * =========================================================================
+ * @brief get keyString string from library
+ *
+ * @param keyString there is only "key" when input,
+ and then library need rewrite "key=value" to keyString
+ * @param sizeKeyString the size byte of string
+ *
+ * @return int
+ * =========================================================================
+ */
+ virtual int getKeyValuePair(SpeechStringBufType *keyValuePair);
+
+ /**
+ * =========================================================================
+ * @brief update phone call status from driver
+ *
+ * @param callOn: the phone call status: true(On), false(Off)
+ *
+ * @return int
+ * =========================================================================
+ */
+ virtual int updatePhoneCallStatus(bool callOn);
+
+ char* mMonitoredXmlName;
+ std::vector<char*> mChangedXMLQueue;
+
+protected:
+ SpeechParserGen95();
+ SpeechParserAttribute mSpeechParserAttribute;
+
+private:
+ /**
+ * singleton pattern
+ */
+ static SpeechParserGen95 *uniqueSpeechParser;
+
+ uint32_t getMaxBufferSize();
+};
+
+
+
+} // end namespace android
+
+#endif // end of ANDROID_SPEECH_PARSER_GEN95_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechParserType.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechParserType.h
new file mode 100644
index 0000000..9013b16
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechParserType.h
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef SPEECH_PARSER_TYPE_H
+#define SPEECH_PARSER_TYPE_H
+
+#include <stdint.h>
+#include <system/audio.h>
+#include "SpeechFeatureDef.h"
+
+namespace android {
+
+/*
+ * =============================================================================
+ * MACRO
+ * =============================================================================
+ */
+#define MAX_SPEECH_PARSER_KEY_LEN (512)
+#define SPEECH_PARSER_SET_KEY_PREFIX "SPEECH_PARSER_SET_PARAM"
+#define SPEECH_PARSER_GET_KEY_PREFIX "SPEECH_PARSER_GET_PARAM"
+/** driver usage */
+#define SPEECH_PARSER_MD_VERSION "MDVERSION"
+/** parser usage */
+#define SPEECH_PARSER_PARAMBUF_SIZE "PARAMBUF_SIZE"
+
+/*
+ * =============================================================================
+ * enum
+ * =============================================================================
+ */
+
+enum SpeechScenario {
+ SPEECH_SCENARIO_SPEECH_ON = 0,
+ SPEECH_SCENARIO_PARAM_CHANGE = 1,
+ SPEECH_SCENARIO_DEVICE_CHANGE = 2,
+ SPEECH_SCENARIO_VOLUME_CHANGE = 3,
+ SPEECH_SCENARIO_FEATURE_CHANGE = 4,
+ NUM_SPEECH_SCENARIO
+};
+
+/*
+ * =============================================================================
+ * struct definition
+ * =============================================================================
+ */
+
+/** char string buffer */
+typedef struct {
+ uint32_t memorySize; /* 0 <= string_size < memory_size */
+ uint32_t stringSize; /* string_size = strlen(p_string); */
+ union {
+ char *stringAddr; /* string address */
+ uint32_t dummy[2]; /* reserve for 64 bits pointer only */
+ };
+} SpeechStringBufType; /* sizeof(): 16 bytes */
+
+
+/** data buffer (speech parameters */
+typedef struct {
+ uint32_t memorySize; /* buffer size (memory) */
+ uint32_t dataSize; /* 0 <= data_size <= memory_size */
+ union {
+ void *bufferAddr; /* memory address */
+ uint32_t dummy[2]; /* reserve for 64 bits pointer only */
+ };
+} SpeechDataBufType; /* sizeof(): 16 bytes */
+
+
+/** driver environment attribute for speech parser */
+typedef struct {
+ audio_devices_t inputDevice;
+ audio_devices_t outputDevice;
+ unsigned int idxVolume;
+ SpeechScenario driverScenario;
+ TtyModeType ttyMode;
+ uint16_t speechFeatureOn;
+ uint8_t __reserve_at_48byte[16];
+} SpeechParserAttribute; /* sizeof(): 48 bytes */
+
+}
+#endif // end of SPEECH_PARSER_TYPE_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechPcm2way.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechPcm2way.h
new file mode 100644
index 0000000..623bc06
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechPcm2way.h
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_PCM2WAY_H
+#define ANDROID_SPEECH_PCM2WAY_H
+
+#include <pthread.h>
+
+#include "AudioType.h"
+#include "AudioUtility.h"
+
+#include <AudioLock.h>
+
+namespace android {
+// for debug
+//#define PLAY2WAY_USE_SINE_WAVE
+
+#define PCM2WAY_PLAY_BUFFER_NB_LEN (320) // Mono * PCM-16Bit * 8000(hz) * 20(ms) = 320 bytes
+#define PCM2WAY_PLAY_BUFFER_WB_LEN (640) // Mono * PCM-16Bit * 16000(hz) * 20(ms) = 640 bytes
+#define PCM2WAY_PLAY_BUFFER_SWB_LEN (1280) // Mono * PCM-16Bit * 32000(hz) * 20(ms) = 1280 bytes
+
+/***********************************************************
+* PCM2WAY Interface - Play2Way
+***********************************************************/
+
+class Play2Way {
+public:
+ virtual ~Play2Way();
+
+ static Play2Way *GetInstance();
+
+ int Start();
+ int Stop();
+ int Write(void *buffer, int size_bytes);
+ int GetFreeBufferCount(void);
+ uint16_t PutDataToSpeaker(char *target_ptr, uint16_t num_data_request);
+
+private:
+ Play2Way();
+
+ static Play2Way *mPlay2Way; // singleton
+
+ bool mPlay2WayStarted;
+ RingBuf m_OutputBuf; // Internal Output Buffer for Put Data to Modem via Receive(Speaker)
+ AudioLock mPlay2WayLock; // Mutex to protect internal buffer
+ bool mIsPlay2WayDumpEnable;
+ FILE *pPlay2WayDumpFile;
+};
+
+/***********************************************************
+* PCM2WAY Interface - Record2Way
+***********************************************************/
+class Record2Way {
+public:
+ virtual ~Record2Way();
+
+ static Record2Way *GetInstance();
+
+ int Start();
+ int Stop();
+ int Read(void *buffer, int size_bytes);
+ int GetBufferDataCount(void);
+ void GetDataFromMicrophone(RingBuf ul_ring_buf);
+
+private:
+ Record2Way();
+
+ static Record2Way *mRecord2Way; // singleton
+
+ bool m_Rec2Way_Started;
+ RingBuf m_InputBuf; // Internal Input Buffer for Get From Microphone Data
+ AudioLock mRec2WayLock; // Mutex to protect internal buffer
+ bool mIsRecord2WayDumpEnable;
+ FILE *pRecord2WayDumpFile;
+};
+
+
+
+}; // namespace android
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechShareMemBase.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechShareMemBase.h
new file mode 100644
index 0000000..2d545e7
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechShareMemBase.h
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_SHAREMEM_BASE_H
+#define ANDROID_SPEECH_SHAREMEM_BASE_H
+
+#include "SpeechType.h"
+
+
+namespace android {
+
+/*
+ * =============================================================================
+ * class
+ * =============================================================================
+ */
+
+class SpeechShareMemBase {
+public:
+ static SpeechShareMemBase *createInstance();
+ static SpeechShareMemBase *destroyInstance(SpeechShareMemBase *speechShareMem);
+ /** virtual dtor */
+ virtual ~SpeechShareMemBase() {}
+
+ /** implementation according to different platform */
+
+ virtual int resetShareMemoryIndex() = 0;
+
+ virtual int writeSphParamToShareMemory(const void *p_sph_param,
+ uint32_t sph_param_length,
+ uint32_t *p_write_idx) = 0;
+
+ virtual int writeApDataToShareMemory(const void *data_buf,
+ uint16_t data_type,
+ uint16_t data_size,
+ uint16_t *p_payload_length,
+ uint32_t *p_write_idx) = 0;
+
+ virtual int readMdDataFromShareMemory(void *p_data_buf,
+ uint16_t *p_data_type,
+ uint16_t *p_data_size,
+ uint16_t payload_length,
+ uint32_t read_idx) = 0;
+
+ virtual int openShareMemory(const modem_index_t modem_index) = 0;
+ virtual int closeShareMemory() = 0;
+ virtual int formatShareMemory() = 0;
+ virtual bool checkModemAlive() = 0;
+ virtual int getShareMemoryType() = 0;
+
+protected:
+ SpeechShareMemBase();
+ modem_index_t mModemIndex;
+ int mCcciShareMemoryHandler;
+
+ unsigned char *mShareMemoryBase;
+ unsigned int mShareMemoryLength;
+
+private:
+ static SpeechShareMemBase *uniqueSpeechShareMem;
+
+};
+
+} /* end of namespace android */
+
+#endif /* end of ANDROID_SPEECH_SHAREMEM_BASE_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechShareMemGen93.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechShareMemGen93.h
new file mode 100644
index 0000000..66c50ad
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechShareMemGen93.h
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_SHAREMEM_GEN93_H
+#define ANDROID_SPEECH_SHAREMEM_GEN93_H
+
+#include "SpeechShareMemBase.h"
+
+namespace android {
+
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+class SpeechExtMemCCCI;
+
+class SpeechShareMemGen93 : public SpeechShareMemBase {
+
+public:
+ SpeechShareMemGen93();
+ /** virtual dtor */
+ virtual ~SpeechShareMemGen93();
+
+ /** implementation according to different platform */
+
+ virtual int resetShareMemoryIndex();
+
+ virtual int writeSphParamToShareMemory(const void *p_sph_param,
+ uint32_t sph_param_length,
+ uint32_t *p_write_idx);
+
+ virtual int writeApDataToShareMemory(const void *data_buf,
+ uint16_t data_type,
+ uint16_t data_size,
+ uint16_t *p_payload_length,
+ uint32_t *p_write_idx);
+
+ virtual int readMdDataFromShareMemory(void *p_data_buf,
+ uint16_t *p_data_type,
+ uint16_t *p_data_size,
+ uint16_t payload_length,
+ uint32_t read_idx);
+
+ virtual int openShareMemory(const modem_index_t modem_index);
+ virtual int closeShareMemory();
+ virtual int formatShareMemory();
+ virtual bool checkModemAlive();
+ virtual int getShareMemoryType();
+
+private:
+ SpeechExtMemCCCI *mSpeechExtMemCCCI;
+
+};
+
+} /* end of namespace android */
+
+#endif /* end of ANDROID_SPEECH_SHAREMEM_GEN93_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechShareMemGen95.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechShareMemGen95.h
new file mode 100644
index 0000000..9a73127
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechShareMemGen95.h
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_SHAREMEM_GEN95_H
+#define ANDROID_SPEECH_SHAREMEM_GEN95_H
+
+#include "SpeechShareMemBase.h"
+
+namespace android {
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+class SpeechExtMemCCCI;
+class SpeechExtMemUSIP;
+
+/*
+ * =============================================================================
+ * class
+ * =============================================================================
+ */
+
+class SpeechShareMemGen95 : public SpeechShareMemBase {
+
+public:
+ SpeechShareMemGen95();
+ /** virtual dtor */
+ virtual ~SpeechShareMemGen95();
+
+ /** implementation according to different platform */
+
+ virtual int resetShareMemoryIndex();
+
+ virtual int writeSphParamToShareMemory(const void *p_sph_param,
+ uint32_t sph_param_length,
+ uint32_t *p_write_idx);
+
+ virtual int writeApDataToShareMemory(const void *data_buf,
+ uint16_t data_type,
+ uint16_t data_size,
+ uint16_t *p_payload_length,
+ uint32_t *p_write_idx);
+
+ virtual int readMdDataFromShareMemory(void *p_data_buf,
+ uint16_t *p_data_type,
+ uint16_t *p_data_size,
+ uint16_t payload_length,
+ uint32_t read_idx);
+
+ virtual int openShareMemory(const modem_index_t modem_index);
+ virtual int closeShareMemory();
+ virtual int formatShareMemory();
+ virtual bool checkModemAlive();
+ virtual int getShareMemoryType();
+
+private:
+ SpeechExtMemCCCI *mSpeechExtMemCCCI;
+ SpeechExtMemUSIP *mSpeechExtMemUSIP;
+
+};
+
+} /* end of namespace android */
+
+#endif /* end of ANDROID_SPEECH_SHAREMEM_GEN95_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechType.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechType.h
new file mode 100644
index 0000000..f26a2b0
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechType.h
@@ -0,0 +1,464 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_TYPE_H
+#define ANDROID_SPEECH_TYPE_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "SpeechFeatureDef.h"
+
+namespace android {
+
+#ifdef SLOGV
+#undef SLOGV
+#endif
+
+#if 0 // for speech debug usage
+#define SLOGV(x...) ALOGD(x)
+#else
+#define SLOGV(x...) ALOGV(x)
+#endif
+
+
+
+enum modem_index_t {
+ MODEM_1 = 0,
+ MODEM_2 = 1,
+ MODEM_EXTERNAL = 2,
+ NUM_MODEM
+};
+
+enum phone_id_t {
+ PHONE_ID_INVALID = -1,
+ PHONE_ID_0 = 0,
+ PHONE_ID_1 = 1,
+ NUM_PHONE_ID
+};
+
+/** CCCI modem status */
+typedef uint8_t modem_status_t;
+
+enum { /* modem_status_t */
+ MODEM_STATUS_INVALID = 0, // Boot stage 0 -> Means MD Does NOT run
+ MODEM_STATUS_INIT = 1, // Boot stage 1 -> Means MD begin to run, but not ready
+ MODEM_STATUS_READY = 2, // Boot stage 2 -> Means MD is ready
+ MODEM_STATUS_EXPT = 3 // MD exception -> Means EE occur
+};
+
+enum modem_status_mask_t {
+ SPEECH_STATUS_MASK = (1 << 0),
+ RECORD_STATUS_MASK = (1 << 1),
+ BGS_STATUS_MASK = (1 << 2),
+ P2W_STATUS_MASK = (1 << 3),
+ TTY_STATUS_MASK = (1 << 4),
+ VT_STATUS_MASK = (1 << 5),
+ LOOPBACK_STATUS_MASK = (1 << 6),
+ VM_RECORD_STATUS_MASK = (1 << 7),
+ SPEECH_ROUTER_STATUS_MASK = (1 << 8),
+ RAW_RECORD_STATUS_MASK = (1 << 9),
+ PCM_MIXER_STATUS_MASK = (1 << 10),
+};
+
+enum speech_mode_t {
+ SPEECH_MODE_NORMAL = 0,
+ SPEECH_MODE_EARPHONE = 1,
+ SPEECH_MODE_LOUD_SPEAKER = 2,
+ SPEECH_MODE_BT_EARPHONE = 3,
+ SPEECH_MODE_BT_CORDLESS = 4,
+ SPEECH_MODE_BT_CARKIT = 5,
+ SPEECH_MODE_MAGIC_CON_CALL = 6,
+ SPEECH_MODE_PRESERVED_2 = 7,
+ SPEECH_MODE_HAC = 8,
+ SPEECH_MODE_USB_AUDIO = 9,
+ SPEECH_MODE_NO_CONNECT = 10
+};
+
+enum phone_call_mode_t {
+ RAT_2G_MODE = 0, // 2G phone call
+ RAT_3G_MODE = 1, // 3G phone call // for both 2G/3G phone call, set mode as 2G. Modem side can query 2G/3G phone call.
+ RAT_3G324M_MODE = 2, // VT phone call
+};
+
+enum rf_mode_t {
+ RF_2G_MODE = (0xF << 0), // 2G RF index
+ RF_3G_MODE = (0xF << 4), // 3G RF index
+ RF_4G_MODE = (0xF << 8), // 4G RF index
+ RF_5G_MODE = (0xF << 12), // 5G RF index
+};
+
+
+enum ctm_interface_t { // L1 CTM Interface
+ DIRECT_MODE = 0,
+ BAUDOT_MODE = 1
+};
+
+
+enum record_format_t {
+ RECORD_FORMAT_PCM = 0,
+ RECORD_FORMAT_VM = 1,
+ RECORD_FORMAT_DUAL_MIC_VM = 2,
+ RECORD_FORMAT_CTM_4WAY = 3,
+};
+
+enum record_sample_rate_t {
+ RECORD_SAMPLE_RATE_08K = 0,
+ RECORD_SAMPLE_RATE_16K = 1,
+ RECORD_SAMPLE_RATE_32K = 2,
+ RECORD_SAMPLE_RATE_48K = 3
+};
+
+enum record_channel_t {
+ RECORD_CHANNEL_MONO = 0,
+ RECORD_CHANNEL_STEREO = 1
+};
+
+enum RecordType {
+ RECORD_TYPE_UL = 0,
+ RECORD_TYPE_DL = 1,
+ RECORD_TYPE_MIX = 2,
+ RECORD_TYPE_MAX
+};
+
+// downlink record position in dsp, default 0
+enum RecordPositionDlType {
+ RECORD_POS_DL_END = 0,
+ RECORD_POS_DL_AFTER_ENH = 1,
+ RECORD_POS_DL_HEAD = 2,
+ RECORD_POS_DL_MAX
+};
+
+struct SpcRecordTypeStruct {
+ enum RecordType direction;// record type
+ enum RecordPositionDlType dlPosition;// dl record position
+};
+
+// define for dual mic pcm2way format
+enum dualmic_pcm2way_format_t {
+ P2W_FORMAT_NORMAL = 0,
+ P2W_FORMAT_VOIP = 1,
+ P2W_FORMAT_NB_CAL = 2, // NB calibration
+ P2W_FORMAT_WB_CAL = 3, // WB calibration
+};
+
+enum pcmnway_format_t {
+ SPC_PNW_MSG_BUFFER_SE = (1 << 0), // Bit 0, PCM4WAY_PutToSE
+ SPC_PNW_MSG_BUFFER_SPK = (1 << 1), // Bit 1, PCM4WAY_PutToSpk
+ SPC_PNW_MSG_BUFFER_MIC = (1 << 2), // Bit 2, PCM4WAY_GetFromMic
+ SPC_PNW_MSG_BUFFER_SD = (1 << 3), // Bit 3, PCM4WAY_GetFromSD
+};
+
+enum {
+ PCM_DIRECTION_DOWNLINK,
+ PCM_DIRECTION_UPLINK
+};
+
+// speech enhancement function mask(before 92 modem)
+// This is the power on/off setting of enhancement. Most of the case, it should be totally on.
+enum sph_enh_main_mask_t {
+ //SPH_ENH_MAIN_MASK_ES = (1 << 0),
+ SPH_ENH_MAIN_MASK_AEC = (1 << 1),
+ SPH_ENH_MAIN_MASK_EES = (1 << 2),
+ SPH_ENH_MAIN_MASK_ULNR = (1 << 3), // VCE depends on this
+ SPH_ENH_MAIN_MASK_DLNR = (1 << 4), // VCE depends on this
+ SPH_ENH_MAIN_MASK_TDNC = (1 << 5),
+ SPH_ENH_MAIN_MASK_DMNR = (1 << 6), // Enable only when phone with dual mic
+ SPH_ENH_MAIN_MASK_AGC = (1 << 7), //SPH_ENH_MAIN_MASK_SIDETONE = (1 << 7),
+ SPH_ENH_MAIN_MASK_ALL = 0xFFFF
+};
+
+// speech enhancement function dynamic mask(before 92 modem)
+// This is the dynamic switch to decided the enhancment output.
+enum sph_enh_dynamic_mask_t {
+ SPH_ENH_DYNAMIC_MASK_DMNR = (1 << 0), // for receiver
+ SPH_ENH_DYNAMIC_MASK_VCE = (1 << 1),
+ SPH_ENH_DYNAMIC_MASK_BWE = (1 << 2),
+ SPH_ENH_DYNAMIC_MASK_DLNR = (1 << 3), // ==> SAL_ENH_DYNAMIC_DLNR_MUX, bit 4
+ SPH_ENH_DYNAMIC_MASK_ULNR = (1 << 4), // ==> SAL_ENH_DYNAMIC_DLNR_MUX, bit 5
+ SPH_ENH_DYNAMIC_MASK_LSPK_DMNR = (1 << 5), // for loud SPEAKER_AMP
+ SPH_ENH_DYNAMIC_MASK_SIDEKEY_DGAIN = (1 << 6), // ==> SAL_ENH_DYNAMIC_SIDEKEYCTRL_DGAIN_MUX, bit 7
+ SPH_ENH_DYNAMIC_MASK_DLNR_INIT_CTRL = (1 << 7), // ==> SAL_ENH_DYNAMIC_DL_NR_INIT_CTRL_MUX, bit 8
+ SPH_ENH_DYNAMIC_MASK_AEC = (1 << 8), // ==> SAL_ENH_DYNAMIC_AEC_MUX, bit 9
+ SPH_ENH_DYNAMIC_MASK_DE_REVERB = (1 << 9),
+
+ SPH_ENH_DYNAMIC_MASK_ALL = 0xFFFFFFFF
+};
+
+typedef struct {
+ uint16_t main_func; // ES,AEC,EES,ULNR,DLNR,TDNC,DMNR,SIDETONE, ...
+ uint32_t dynamic_func; // DMNR,VCE,BWE,
+} sph_enh_mask_struct_t;
+
+
+
+// speech enhancement function dynamic mask(after 93 modem)
+enum { /* sph_enh_dynamic_ctrl_t */
+ SPH_ENH_DYNAMIC_CTRL_MASK_DMNR = (1 << 0),
+ SPH_ENH_DYNAMIC_CTRL_MASK_TDNC = (1 << 1),
+ SPH_ENH_DYNAMIC_CTRL_MASK_MAGIC_CONFERENCE = (1 << 2),
+ SPH_ENH_DYNAMIC_CTRL_MASK_DE_REVERB = (1 << 3),
+
+ /* max 16 bit !! */
+ SPH_ENH_DYNAMIC_CTRL_MASK_MAX = (1 << 15)
+};
+
+typedef uint16_t sph_enh_dynamic_ctrl_t;
+
+
+
+typedef struct spcRAWPCMBufInfoStruct {
+ //UL sample rate, please refer PCM_REC_SAMPLE_RATE_IDX
+ uint16_t u16ULFreq;
+ //UL length in byte
+ uint16_t u16ULLength;
+ //DL sample rate, please refer PCM_REC_SAMPLE_RATE_IDX
+ uint16_t u16DLFreq;
+ //DL length in byte
+ uint16_t u16DLLength;
+} spcRAWPCMBufInfo;
+
+typedef struct spcApRAWPCMBufHdrStruct {
+ uint16_t u16SyncWord;
+ uint16_t u16RawPcmDir;
+ uint16_t u16Freq;
+ uint16_t u16Length;
+ uint16_t u16Channel;
+ uint16_t u16BitFormat;
+} spcApRAWPCMBufHdr;
+
+#define SPC_PROP_CODEC_LEN 92
+
+typedef struct {
+ char codecInfo[SPC_PROP_CODEC_LEN];
+ char codecOp[SPC_PROP_CODEC_LEN];
+} spcCodecInfoStruct;
+
+typedef struct {
+ uint32_t header;
+ uint32_t data;
+} spcEcallIndicationStruct;
+
+typedef struct {
+ void *data;
+ uint32_t size;
+} spcEcallRXCtrlDataStruct;
+
+enum share_buff_data_type_t {
+ SHARE_BUFF_DATA_TYPE_PCM_FillSE = 0,
+ SHARE_BUFF_DATA_TYPE_PCM_FillSpk = 1,
+ SHARE_BUFF_DATA_TYPE_PCM_GetFromMic = 2,
+ SHARE_BUFF_DATA_TYPE_PCM_GetfromSD = 3,
+ SHARE_BUFF_DATA_TYPE_CCCI_VM_TYPE = 4,
+ SHARE_BUFF_DATA_TYPE_CCCI_PCM_TYPE = 5,
+ SHARE_BUFF_DATA_TYPE_CCCI_BGS_TYPE = 6,
+ SHARE_BUFF_DATA_TYPE_CCCI_EM_PARAM = 7,
+ SHARE_BUFF_DATA_TYPE_CCCI_CTM_UL_IN = 8,
+ SHARE_BUFF_DATA_TYPE_CCCI_CTM_DL_IN = 9,
+ SHARE_BUFF_DATA_TYPE_CCCI_CTM_UL_OUT = 10,
+ SHARE_BUFF_DATA_TYPE_CCCI_CTM_DL_OUT = 11,
+ SHARE_BUFF_DATA_TYPE_CCCI_VIBSPK_PARAM = 12,
+
+ SHARE_BUFF_DATA_TYPE_CCCI_SMARTPA_PARAM = 15,
+ SHARE_BUFF_DATA_TYPE_CCCI_MAGICON_PARAM = 16,
+ SHARE_BUFF_DATA_TYPE_CCCI_HAC_PARAM = 17,
+ SHARE_BUFF_DATA_TYPE_CCCI_RAW_PCM_TYPE = 18,
+ SHARE_BUFF_DATA_TYPE_CCCI_DYNAMIC_PARAM_TYPE = 19,
+ SHARE_BUFF_DATA_TYPE_CCCI_NW_CODEC_INFO = 20,
+ SHARE_BUFF_DATA_TYPE_CCCI_STRMBUF_TYPE_CUST_DUMP = 21,
+ SHARE_BUFF_DATA_TYPE_CCCI_UL_ENC = 22,
+ SHARE_BUFF_DATA_TYPE_CCCI_DL_DEC = 23,
+ SHARE_BUFF_DATA_TYPE_CCCI_ECALL_MSD_TYPE = 24,
+ SHARE_BUFF_DATA_TYPE_CCCI_SPH_INFO = 25,
+ SHARE_BUFF_DATA_TYPE_CCCI_MD_ALIVE_INFO = 26,
+ SHARE_BUFF_DATA_TYPE_CCCI_PCM_MIXER_DL = 27,
+ SHARE_BUFF_DATA_TYPE_CCCI_MAX_TYPE
+};
+
+
+typedef struct _AUDIO_CUSTOM_HAC_SPEECH_PARAM_STRUCT {
+ /* speech enhancement */
+ uint16_t speech_hac_mode_nb_para[16];
+ /* WB speech enhancement */
+ uint16_t speech_hac_mode_wb_para[16];
+ /* speech input FIR */
+ int16_t sph_hac_in_fir[45];
+ /* speech output FIR */
+ int16_t sph_hac_out_fir[45];
+
+ /* WB speech input FIR */
+ int16_t sph_hac_wb_in_fir[90];
+ /* WB speech output FIR */
+ int16_t sph_hac_wb_out_fir[90];
+ /* mic volume setting */
+
+} AUDIO_CUSTOM_HAC_SPEECH_PARAM_STRUCT;
+
+
+/*
+ * =============================================================================
+ * speech on/routing/tuning payload
+ * =============================================================================
+ */
+
+enum {
+ SPH_APPLICATION_NORMAL,
+ SPH_APPLICATION_VT_CALL,
+ SPH_APPLICATION_LOOPBACK,
+ SPH_APPLICATION_ROUTER,
+ SPH_APPLICATION_DACA,
+ SPH_APPLICATION_HOLD_CALL,
+ SPH_APPLICATION_ENCRYPTION,
+
+ SPH_APPLICATION_INVALID = 0xFF
+};
+
+typedef uint8_t sph_application_t;
+
+
+enum {
+ SPH_BT_OFF,
+ SPH_BT_PCM, /* via Modem PCM hardware */
+ SPH_BT_CVSD_MSBC, /* not use now, keep for MD legacy */
+ SPH_BT_CVSD, /* via software BT CVSD codec */
+ SPH_BT_MSBC /* via software BT MSBC codec */
+};
+
+typedef uint8_t sph_bt_info_t;
+
+
+enum {
+ SPH_SAMPLE_RATE_08K,
+ SPH_SAMPLE_RATE_16K,
+ SPH_SAMPLE_RATE_32K,
+ SPH_SAMPLE_RATE_48K
+};
+
+typedef uint8_t sph_sample_rate_t;
+
+
+enum {
+ SPH_PARAM_VIA_PAYLOAD, /* speech param is written in payload (0x2F79) */
+ SPH_PARAM_VIA_SHM_CCCI, /* speech param is written in share memory from ccci */
+ SPH_PARAM_VIA_SHM_USIP /* speech param is written in share memory for ap/md/usip accessed */
+};
+
+typedef uint8_t sph_param_path_t;
+
+
+enum {
+ SPH_EXT_DEV_INFO_DEFULAT = 0,
+ SPH_EXT_DEV_INFO_VIBRATION_RECEIVER, /* vibration receiver (3-in-1) */
+ SPH_EXT_DEV_INFO_VIBRATION_SPEAKER, /* vibration speaker (2-in-1 or 3-in-1) */
+ SPH_EXT_DEV_INFO_SMARTPA_SPEAKER, /* speaker with smart-PA which need echo reference path */
+ SPH_EXT_DEV_INFO_SMARTPA_VIBRATION_SPEAKER, /* vibration speaker with smart-PA which need echo reference path */
+ SPH_EXT_DEV_INFO_USB_AUDIO, /* usb audio device, which needs echo reference path */
+ SPH_EXT_DEV_INFO_EARPHONE /* earphone audio device */
+};
+
+typedef uint16_t sph_ext_dev_info_t;
+
+
+enum {
+ SPH_LOOPBACK_INFO_FLAG_DISABLE_BT_CODEC = (1 << 0), /* 0'b == BT Loopback with BT codec / 1'b == BT Loopback without BT Codec, only support when SPH_BTINFO_BT_CVSD_MSBC */
+ SPH_LOOPBACK_INFO_FLAG_DELAY_SETTING = (1 << 1), /* delay setting for normal loopback, i.e. speech mode is not BT cases. 0==Use modem default delay value/ 1== use AP gives delay value in loopback_delay */
+};
+
+typedef uint8_t sph_loopback_info_flag_t;
+
+enum {
+ SPH_PARAM_INVALID = 0,
+ SPH_PARAM_VALID,
+ SPH_PARAM_PREVIOUS_VALID
+};
+
+typedef struct sph_info_t {
+ uint8_t application; /* sph_application_t */
+ uint8_t bt_info; /* sph_bt_info_t */
+ uint8_t sample_rate_enum; /* sph_sample_rate_t */
+ uint8_t opendsp_flag; /* 0: internal SPE, 1: OpenDSP */
+
+ uint8_t sph_param_path; /* sph_param_path_t */
+ uint8_t sph_param_valid; /* SPH_PARAM_VIA_SHM only. 0: invalid, 1: valid, 2: previous valid */
+ uint16_t sph_param_length; /* Max 65535 bytes */
+ uint16_t sph_param_index; /* Max 65535 bytes */
+
+ uint16_t ext_dev_info; /* sph_ext_dev_info_t */
+
+ uint8_t loopback_flag; /* sph_loopback_info_flag_t */
+ uint8_t loopback_delay; /* unit is 20ms */
+
+ uint16_t echo_ref_delay_ms; /* echo reference data delay, unit is ms */ /* SPH_BT_CVSD_MSBC only */
+ uint8_t mic_delay_ms; /* UL0 data delay, unit is ms */ /* SPH_EXT_DEV_INFO_SMARTPA_SPEAKER & SPH_EXT_DEV_INFO_SMARTPA_VIBRATION_SPEAKER only */
+
+ uint8_t __reserve_at_18byte;
+ uint16_t enh_dynamic_ctrl; /* sph_enh_dynamic_ctrl_t */
+ uint32_t sph_param_usip_length; /* Max 4294967295 bytes */
+ uint32_t sph_param_usip_index; /* Max 4294967295 bytes */
+ uint16_t drv_common_param[12]; /* param for driver/scheduler */
+ uint16_t drv_debug_info[16]; /* param for driver/scheduler */
+ uint8_t smartPA_config;
+ uint8_t dtmf_removal_flag;
+
+ uint8_t __reserve_at_128byte[42];
+} sph_info_t; /* 128 bytes */
+
+#define SIZE_OF_SPH_INFO (128)
+
+
+typedef struct MdAliveInfo {
+ uint16_t headerMdVersion; /* header type for ap/md header sync */
+ uint16_t mdVersion; /* MD version */
+
+ uint8_t __reserve_at_32byte[28];
+} MdAliveInfo; /* 32 bytes */
+
+#define SIZE_OF_MD_ALIVE_INFO (32)
+
+enum SphShmType {
+ SPH_SHM_AP_DATA = 1,
+ SPH_SHM_MD_DATA = 2,
+ SPH_SHM_SPEECH_PARAM = 3
+};
+
+
+/*
+ * =============================================================================
+ * share memory
+ * =============================================================================
+ */
+
+typedef uint8_t sph_msg_buffer_t;
+
+enum { /* sph_msg_buffer_t */
+ SPH_MSG_BUFFER_TYPE_MAILBOX,
+ SPH_MSG_BUFFER_TYPE_PAYLOAD
+};
+
+
+typedef struct sph_msg_t {
+ uint8_t buffer_type; /* sph_msg_buffer_t */
+ uint16_t msg_id; /* sph_msg_id_t */
+
+ /* only for SPH_MSG_BUFFER_TYPE_MAILBOX */
+ union {
+ uint16_t param_16bit;
+ uint16_t length; /* the data length in share memory xxx region */
+ };
+
+ union {
+ uint32_t param_32bit;
+ uint32_t rw_index; /* the read/write index in share memory xxx region */
+ };
+
+
+ /* only for SPH_MSG_BUFFER_TYPE_PAYLOAD */
+ uint16_t payload_data_type; /* share_buff_data_type_t */
+ uint16_t payload_data_size; /* data size without header */
+ void *payload_data_addr; /* must free at the end */
+ uint16_t payload_data_idx; /* only for modem payload */
+ uint16_t payload_data_total_idx; /* only for modem payload */
+} sph_msg_t;
+
+
+} // end namespace android
+
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechUtility.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechUtility.h
new file mode 100644
index 0000000..61a19a8
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechUtility.h
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_UTILITY_H
+#define ANDROID_SPEECH_UTILITY_H
+
+#include <stdint.h>
+#include <string.h>
+
+#include <errno.h>
+
+#include <sys/prctl.h> /* for prctl & PR_SET_NAME */
+#include <sys/resource.h> /* for PRIO_PROCESS */
+
+#include <audio_log.h>
+
+#include <SpeechType.h>
+#if defined(MTK_YOCTO_AUDIO)
+#include <sys/syscall.h>
+#include <sys/types.h>
+#define gettid() syscall(__NR_gettid)
+#endif
+
+
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#define PROPERTY_KEY_MAX 64
+#define PROPERTY_VALUE_MAX 96
+#define PROPERTY_FULL_MAX PROPERTY_KEY_MAX+PROPERTY_VALUE_MAX
+
+namespace android {
+
+
+/*
+ * =============================================================================
+ * typedeh
+ * =============================================================================
+ */
+
+/** all on => "adb shell setprop af.speech.log.mask 7" */
+typedef uint32_t sph_log_level_mask_t;
+
+enum { /* sph_log_level_mask_t */
+ SPH_LOG_LEVEL_MASK_DEBUG = (1 << 0),
+ SPH_LOG_LEVEL_MASK_VERBOSE = (1 << 1),
+ SPH_LOG_LEVEL_MASK_TRASH = (1 << 2)
+};
+
+
+/*
+ * =============================================================================
+ * CCCI control
+ * =============================================================================
+ */
+
+// instead of include <hardware/ccci_intf.h>, only for platform after 93MD to reduce memory
+#define CCCI_IOC_MAGIC 'C'
+#define CCCI_IOC_GET_MD_STATE _IOR(CCCI_IOC_MAGIC, 1, unsigned int)
+#define CCCI_IOC_SMEM_BASE _IOR(CCCI_IOC_MAGIC, 48, unsigned int)
+#define CCCI_IOC_SMEM_LEN _IOR(CCCI_IOC_MAGIC, 49, unsigned int)
+
+#define CCCI_DEV_NODE_DRIVER "/dev/ccci_aud"
+#define CCCI_DEV_NODE_SMEM "/dev/ccci_raw_audio"
+
+
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+
+struct sph_msg_t;
+
+
+/*
+ * =============================================================================
+ * utility
+ * =============================================================================
+ */
+
+void sph_memcpy(void *des, const void *src, uint32_t size);
+void sph_memset(void *dest, uint8_t value, uint32_t size);
+
+uint32_t get_uint32_from_mixctrl(const char *property_name);
+void set_uint32_to_mixctrl(const char *property_name, const uint32_t value);
+
+uint32_t get_uint32_from_property(const char *property_name);
+void set_uint32_to_property(const char *property_name, const uint32_t value);
+
+void get_string_from_property(const char *property_name, char *string, const uint32_t string_size);
+void set_string_to_property(const char *property_name, const char *string);
+
+uint32_t get_uint32_from_uci(const char *property_name);
+void set_uint32_to_uci(const char *property_name, const uint32_t value);
+
+void reload_property();
+
+int property_reload_tmp();
+int property_get_tmp(const char *key, char *value, const char *default_value);
+int property_set_tmp(const char *key, const char *value);
+
+
+uint16_t sph_sample_rate_enum_to_value(const sph_sample_rate_t sample_rate_enum);
+sph_sample_rate_t sph_sample_rate_value_to_enum(const uint16_t sample_rate_value);
+
+
+void dynamic_speech_log(uint32_t sph_log_level_mask, const char *function_name, const char *message, ...);
+
+/* CCCI */
+int speech_ccci_smem_put(int fd, unsigned char *address, unsigned int length);
+int speech_ccci_smem_get(unsigned char **address, unsigned int *length);
+
+
+#define SPH_LOG_D(fmt, arg...) \
+ dynamic_speech_log(SPH_LOG_LEVEL_MASK_DEBUG, __FILE__, fmt, ##arg)
+
+#define SPH_LOG_V(fmt, arg...) \
+ dynamic_speech_log(SPH_LOG_LEVEL_MASK_VERBOSE, __FILE__, fmt, ##arg)
+
+#define SPH_LOG_T(fmt, arg...) \
+ dynamic_speech_log(SPH_LOG_LEVEL_MASK_TRASH, __FILE__, fmt, ##arg)
+
+#ifdef SLOG_ENG
+#undef SLOG_ENG
+#endif
+
+#ifdef CONFIG_MT_ENG_BUILD
+#define SLOG_ENG ALOGD
+#else
+#define SLOG_ENG ALOGV
+#endif
+
+
+#define PRINT_SPH_MSG(ALOGX, description, p_sph_msg) \
+ do { \
+ if (description == NULL || (p_sph_msg) == NULL) { \
+ break; \
+ } \
+ if ((p_sph_msg)->buffer_type == SPH_MSG_BUFFER_TYPE_MAILBOX) { \
+ ALOGX("%s(), %s, id: 0x%x, param16: 0x%x, param32: 0x%x", \
+ __FUNCTION__, description, \
+ (p_sph_msg)->msg_id, (p_sph_msg)->param_16bit, (p_sph_msg)->param_32bit); \
+ } else if ((p_sph_msg)->buffer_type == SPH_MSG_BUFFER_TYPE_PAYLOAD) { \
+ ALOGX("%s(), %s, id: 0x%x, type: %d, size: %u, addr: %p", \
+ __FUNCTION__, description, \
+ (p_sph_msg)->msg_id, (p_sph_msg)->payload_data_type, \
+ (p_sph_msg)->payload_data_size, (p_sph_msg)->payload_data_addr); \
+ } else { \
+ ALOGW("%s(), buffer_type %d not supporty!!", \
+ __FUNCTION__, (p_sph_msg)->buffer_type); \
+ } \
+ } while (0)
+
+
+
+#define CONFIG_THREAD(thread_name, android_priority) \
+ do { \
+ snprintf(thread_name, sizeof(thread_name), "%s_%d_%d", __FUNCTION__, getpid(), gettid()); \
+ prctl(PR_SET_NAME, (unsigned long)thread_name, 0, 0, 0); \
+ int retval = setpriority(PRIO_PROCESS, 0, android_priority); \
+ if (retval != 0) { \
+ ALOGE("thread %s created. setpriority %s failed!! errno: %d, retval: %d", \
+ thread_name, #android_priority, errno, retval); \
+ } else { \
+ SLOG_ENG("thread %s created. setpriority %s done", \
+ thread_name, #android_priority); \
+ } \
+ } while(0)
+
+
+
+} /* end namespace android */
+
+#endif /* end of ANDROID_SPEECH_UTILITY_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechVoiceMixer.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechVoiceMixer.h
new file mode 100644
index 0000000..da0ef3d
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/SpeechVoiceMixer.h
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_SPEECH_VOICEMIXER_H
+#define ANDROID_SPEECH_VOICEMIXER_H
+
+#include <pthread.h>
+#include "AudioType.h"
+#include "AudioUtility.h"
+#include "MtkAudioComponent.h"
+#include <AudioLock.h>
+
+namespace android {
+bool getLogEnableByLevel(const uint32_t logLevel); /* VOICEMIXER_log_level_t */
+
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+class VoiceMixerPlayer;
+class SpeechDriverInterface;
+
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+#define VOICEMIXER_TARGET_SAMPLE_RATE (32000)
+#define MODEM_FRAME_MS (20)
+
+// pcm_16_bit * 1ch * sample rate * ms
+#define VOICEMIXER_PERIOD_SIZE \
+ ((2 * 1 * VOICEMIXER_TARGET_SAMPLE_RATE * MODEM_FRAME_MS) / 1000)
+#define VOICEMIXER_KEEP_NUM_FRAME (4)
+
+#define VOICEMIXER_PLAY_BUFFER_LEN \
+ ((VOICEMIXER_PERIOD_SIZE * VOICEMIXER_KEEP_NUM_FRAME) + RING_BUF_SIZE_OFFSET)
+
+enum { /* uint32_t: VOICEMIXER_log_level_t */ /* PROPERTY_KEY_VOICEMIXER_LOG_LEVEL */
+ VOICEMIXER_LOG_LEVEL_PLAYBACK_HANDLER = 1,
+ VOICEMIXER_LOG_LEVEL_MODEM = 2,
+ VOICEMIXER_LOG_LEVEL_PLAYER = 4
+};
+
+/*
+ * =============================================================================
+ * class
+ * =============================================================================
+ */
+class VoiceMixerPlayBuffer {
+public:
+ bool isBufferEnough(void);
+
+private:
+ VoiceMixerPlayBuffer();
+ virtual ~VoiceMixerPlayBuffer(); // only destroied by friend class VoiceMixerPlayer
+ friend class VoiceMixerPlayer;
+ status_t initPlayBuffer(VoiceMixerPlayer *playPointer,
+ uint32_t sampleRate,
+ uint32_t chNum,
+ int32_t mFormat);
+ uint32_t write(char *buf, uint32_t num);
+ bool isBlisrcDumpEnable();
+
+ int32_t mFormat;
+ RingBuf mRingBuf;
+ MtkAudioSrcBase *mBliSrc;
+ char *mBliOutputLinearBuffer;
+
+ AudioLock mPlayBufferRuningMutex;
+ AudioLock mPlayBufferMutex;
+
+ bool mExitRequest;
+
+ bool mIsBlisrcDumpEnable;
+ FILE *pDumpFile;
+};
+
+
+class VoiceMixerPlayer {
+public:
+ virtual ~VoiceMixerPlayer();
+ static VoiceMixerPlayer *getInstance();
+ VoiceMixerPlayBuffer *createPlayBuffer(uint32_t sampleRate, uint32_t chNum, int32_t format);
+ void destroyPlayBuffer(VoiceMixerPlayBuffer *pVoiceMixerPlayBuffer);
+ bool open(SpeechDriverInterface *pSpeechDriver, uint8_t mixTypeDl);
+ bool close();
+ bool configMixType(SpeechDriverInterface *pSpeechDriver, uint8_t mixTypeDl);
+ uint32_t write(VoiceMixerPlayBuffer *pVoiceMixerPlayBuffer, void *buf, uint32_t num);
+ uint32_t putData(VoiceMixerPlayBuffer *pVoiceMixerPlayBuffer,
+ char *targetBuf,
+ uint16_t numDataRequest);
+ uint16_t putDataToSpeaker(char *targetBuf, uint16_t numDataRequest);
+ inline uint8_t getDlMixType() { return mMixTypeDl; }
+ uint8_t mMixTypeDl;
+
+private:
+ VoiceMixerPlayer();
+ static VoiceMixerPlayer *mVoiceMixerPlayer; // singleton
+ SpeechDriverInterface *mSpeechDriver;
+ SortedVector<VoiceMixerPlayBuffer *> mPlayBufferVector;
+ char *mBufBaseTemp;
+
+ AudioLock mPlayBufferVectorLock;
+ AudioLock mCountLock;
+
+ uint16_t mCount;
+ uint16_t mPeriodSize;
+ uint16_t mUnderflowCount;
+ bool mIsDumpEnable;
+ FILE *pDumpFile;
+};
+
+} // end namespace android
+
+#endif //ANDROID_SPEECH_VOICEMIXER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/WCNChipController.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/WCNChipController.h
new file mode 100644
index 0000000..975486c
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/WCNChipController.h
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_WCN_CHIP_CONTROLLER_H
+#define ANDROID_WCN_CHIP_CONTROLLER_H
+
+#include "AudioType.h"
+#include <linux/fm.h>
+
+#include <utils/threads.h>
+
+namespace android {
+
+class WCNChipController {
+public:
+ virtual ~WCNChipController();
+
+ static WCNChipController *GetInstance();
+
+ virtual bool GetFmChipPowerInfo();
+
+ virtual status_t SetFmChipVolume(const uint32_t fm_chip_volume);
+ virtual status_t SetFmChipSampleRate(const uint32_t sample_rate);
+
+
+ virtual status_t InitAudioFMInfo();
+ virtual status_t InitAudioBTInfo();
+
+ virtual bool IsFMMergeInterfaceSupported();
+ virtual bool IsBTMergeInterfaceSupported();
+
+ virtual bool IsFmChipPadSelConnSys();
+ virtual bool IsFmChipUseSlaveMode();
+ virtual uint32_t GetFmChipSamplingRate();
+
+
+ virtual uint32_t BTChipHWInterface();
+ virtual bool BTUseCVSDRemoval();
+
+ virtual uint32_t BTChipSamplingRate();
+ virtual uint32_t BTChipSamplingRateNumber();
+
+ virtual uint32_t BTChipSyncFormat();
+ virtual uint32_t BTChipSyncLength();
+ virtual uint32_t BTChipSecurityHiLo();
+
+
+ // might be configured to 8k/16k according to bt device.
+ virtual void SetBTCurrentSamplingRateNumber(const uint32_t sample_rate);
+ virtual uint32_t GetBTCurrentSamplingRateNumber();
+ virtual bool IsSupportFM();
+
+protected:
+ WCNChipController();
+
+ Mutex mLock;
+
+ bool mInitAudioFMInfoFlag;
+ bool mInitAudioBTInfoFlag;
+ bool mPlatformSupportFM;
+ fm_audio_info_t mFmAudioInfo;
+ //AUDIO_CONFIG mBTAudioInfo;
+
+ uint32_t mBTCurrentSamplingRateNumber;
+
+
+
+private:
+ static WCNChipController *mWCNChipController; // singleton
+ bool IsCustomizedPlatformSupportFM();
+};
+
+} // end namespace android
+
+#endif // end of ANDROID_WCN_CHIP_CONTROLLER_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/hardware/AudioCustomVolume.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/hardware/AudioCustomVolume.h
new file mode 100644
index 0000000..4fa4c58
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/hardware/AudioCustomVolume.h
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIOCUSTOMVOLUME_H
+#define ANDROID_AUDIOCUSTOMVOLUME_H
+#include <CFG_AUDIO_File.h>
+#include <AudioMTKHardwareCommand.h>
+
+namespace android {
+
+#define CUSTOM_VOICE_VOLUME_MAX (160)
+#define CUSTOM_VOICE_ONEDB_STEP (4)
+#define CUSTOM_VOLUME_REV_1 (0x01)
+
+//#ifndef GET_AUDIO_POLICY_VOL_FROM_VER1_DATA
+//#define GET_AUDIO_POLICY_VOL_FROM_VER1_DATA (0x102)
+//#endif
+
+const float fBPerStep = 0.25f;
+const float fCUSTOM_VOLUME_MAPPING_STEP = 256.0f;
+const float fBConvert = -fBPerStep * 2.302585093f / 20.0f;
+const float fBConvertInverse = 1.0f / fBConvert;
+
+
+enum CustomVolumeMode {
+ CUSTOM_VOLUME_NORMAL_MODE = 0,
+ CUSTOM_VOLUME_HEADSET_MODE,
+ CUSTOM_VOLUME_SPEAKER_MODE,
+ CUSTOM_VOLUME_HEADSET_SPEAKER_MODE,
+ CUSTOM_NUM_OF_VOL_MODE
+};
+
+enum CustomVolumeType {
+ CUSTOM_VOL_TYPE_VOICE_CALL = 0,
+ CUSTOM_VOL_TYPE_SYSTEM,
+ CUSTOM_VOL_TYPE_RING,
+ CUSTOM_VOL_TYPE_MUSIC,
+ CUSTOM_VOL_TYPE_ALARM,
+ CUSTOM_VOL_TYPE_NOTIFICATION,
+ CUSTOM_VOL_TYPE_BLUETOOTH_SCO,
+ CUSTOM_VOL_TYPE_ENFORCED_AUDIBLE,
+ CUSTOM_VOL_TYPE_DTMF,
+ CUSTOM_VOL_TYPE_TTS,
+ CUSTOM_VOL_TYPE_ACCESSIBILITY,
+ CUSTOM_VOL_TYPE_REROUTING,
+ CUSTOM_VOL_TYPE_PATCH,
+ CUSTOM_VOL_TYPE_SIP,
+ CUSTOM_NUM_OF_VOL_TYPE
+};
+
+
+#define CUSTOM_AUDIO_MAX_VOLUME_STEP (AUDIO_MAX_VOLUME_STEP)
+
+const unsigned char audiovolume_dtmf[NUM_OF_VOL_MODE][AUDIO_MAX_VOLUME_STEP] = {
+ {128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184},
+ {128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184},
+ {128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184},
+ {128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184}
+};
+
+const unsigned char audiovolume_system[NUM_OF_VOL_MODE][AUDIO_MAX_VOLUME_STEP] = {
+ {144, 152, 176, 184, 192, 200, 208, 216, 224, 232, 240, 244, 248, 252, 255},
+ {144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232, 240, 248, 255},
+ {168, 176, 184, 192, 200, 208, 216, 224, 232, 236, 240, 244, 248, 252, 255},
+ {168, 176, 184, 192, 200, 208, 216, 224, 232, 236, 240, 244, 248, 252, 255}
+};
+
+const unsigned char audiovolume_rerouting[NUM_OF_VOL_MODE][AUDIO_MAX_VOLUME_STEP] = {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+};
+
+const unsigned char audiovolume_patch[NUM_OF_VOL_MODE][AUDIO_MAX_VOLUME_STEP] = {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+};
+
+const unsigned char audiovolume_tts_nonspeaker[NUM_OF_VOL_MODE][AUDIO_MAX_VOLUME_STEP] = {
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
+
+typedef struct _AUDIO_CUSTOM_VOLUME_STRUCT {
+ unsigned char bRev;
+ unsigned char bReady;
+ unsigned char audiovolume_steamtype[CUSTOM_NUM_OF_VOL_TYPE][CUSTOM_NUM_OF_VOL_MODE][CUSTOM_AUDIO_MAX_VOLUME_STEP];
+ unsigned char audiovolume_level[CUSTOM_NUM_OF_VOL_TYPE];
+} AUDIO_CUSTOM_VOLUME_STRUCT;
+
+}
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/hardware/audio_mtk.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/hardware/audio_mtk.h
new file mode 100644
index 0000000..19578a6
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/hardware/audio_mtk.h
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef ANDROID_AUDIO_HAL_INTERFACE_MTK_H
+#define ANDROID_AUDIO_HAL_INTERFACE_MTK_H
+
+#define AUDIO_PARAMETER_KEY_TIME_STRETCH "time_stretch"
+#define AUDIO_PARAMETER_KEY_HDMI_BITWIDCH "HDMI_bitwidth"
+#define AUDIO_PARAMETER_KEY_HDMI_CHANNEL "HDMI_channel"
+#define AUDIO_PARAMETER_KEY_HDMI_MAXSAMPLERATE "HDMI_maxsamplingrate"
+#define AUDIO_PARAMETER_KEY_BESSURROUND_ONOFF "BesSurround_OnOff"
+#define AUDIO_PARAMETER_KEY_BESSURROUND_MODE "BesSurround_Mode"
+
+#define AUDIO_PARAMETER_KEY_HDMI_MAXSAMPLERATE "HDMI_maxsamplingrate"
+#define AUDIO_PARAMETER_KEY_BESSURROUND_ONOFF "BesSurround_OnOff"
+#define AUDIO_PARAMETER_KEY_BESSURROUND_MODE "BesSurround_Mode"
+#define AUDIO_PARAMETER_KEY_BESAUDEN_ONOFF "SetMusicPlusStatus"
+
+#define AUDIO_PARAMETER_KEY_ROUTING_TO_NONE "ROUTING_TO_NONE"
+#define AUDIO_PARAMETER_KEY_FM_DIRECT_CONTROL "FM_DIRECT_CONTROL"
+
+#define AUDIO_PARAMETER_KEY_OFFLOAD_AUDIO_STANDBY_WHEN_MUTE "OffloadAudio_Do_Standby_When_Mute"
+#define AUDIO_PARAMETER_KEY_OFFLOAD_AUDIO_CHECK_SUPPORT "OffloadAudio_Check_Support"
+
+
+#include <hardware/audio.h>
+
+typedef enum {
+ DEVICE_CBK_EVENT_SETPARAMETERS,
+} device_parameters_callback_event_t;
+
+typedef struct audio_hw_device_set_parameters_callback {
+ int paramchar_len;
+ char paramchar[1024];
+} audio_hw_device_set_parameters_callback_t;
+
+
+typedef int (*device_parameters_callback_t)(device_parameters_callback_event_t event, audio_hw_device_set_parameters_callback_t *param, void *cookie);
+typedef int (*device_audio_parameter_changed_callback_t)(const char *param, void *cookie);
+
+
+struct audio_hw_device_mtk: audio_hw_device {
+
+ int (*xway_play_start)(struct audio_hw_device *dev, int sample_rate);
+ int (*xway_play_stop)(struct audio_hw_device *dev);
+ int (*xway_play_write)(struct audio_hw_device *dev, void *buffer, int size_bytes);
+ int (*xway_getfreebuffercount)(struct audio_hw_device *dev);
+ int (*xway_rec_start)(struct audio_hw_device *dev, int smple_rate);
+ int (*xway_rec_stop)(struct audio_hw_device *dev);
+ int (*xway_rec_read)(struct audio_hw_device *dev, void *buffer, int size_bytes);
+
+ int (*read_ref_from_ring)(struct audio_hw_device *dev, void *buf, uint32_t datasz, void *dltime);
+ int (*get_vow_ul_time)(struct audio_hw_device *dev, void *ultime);
+ int (*set_vow_src_sample_rate)(struct audio_hw_device *dev, uint32_t rate, uint32_t channel);
+ bool (*start_vow_dl)(struct audio_hw_device *dev);
+ bool (*stop_vow_dl)(struct audio_hw_device *dev);
+ bool (*get_vow_dl_instance)(struct audio_hw_device *dev);
+
+ int (*setup_parameters_callback)(struct audio_hw_device *dev, device_parameters_callback_t callback, void *cookie);
+ int (*set_audio_parameter_changed_callback)(struct audio_hw_device *dev, device_audio_parameter_changed_callback_t callback, void *cookie);
+ int (*clear_audio_parameter_changed_callback)(struct audio_hw_device *dev, void *cookie);
+};
+typedef struct audio_hw_device_mtk audio_hw_device_mtk_t;
+
+#endif // ANDROID_AUDIO_HAL_INTERFACE_MTK_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/hardware/audio_policy_mtk.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/hardware/audio_policy_mtk.h
new file mode 100644
index 0000000..5a55f85
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/hardware/audio_policy_mtk.h
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+ * Copyright (C) 2011 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_POLICY_INTERFACE_MTK_H
+#define AUDIO_POLICY_INTERFACE_MTK_H
+
+#include <hardware/audio_policy.h>
+
+struct audio_policy_mtk: audio_policy {
+ // struct audio_policy legacy_audio_policy;
+ int (*set_policy_parameters)(struct audio_policy *pol, int par1, int par2, int par3, int par4);
+
+ /* indicates to the audio policy manager that the output starts being used
+ * by corresponding stream and samplerate. */
+ int (*start_output_samplerate)(struct audio_policy *pol,
+ audio_io_handle_t output,
+ audio_stream_type_t stream,
+ int session, int samplerate);
+ /* indicates to the audio policy manager that the output starts being used
+ * by corresponding stream and samplerate. */
+ int (*stop_output_samplerate)(struct audio_policy *pol,
+ audio_io_handle_t output,
+ audio_stream_type_t stream,
+ int session, int samplerate);
+};
+
+#endif // AUDIO_POLICY_INTERFACE_MTK_H
\ No newline at end of file
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/hardware_legacy/AudioMTKHardwareInterface.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/hardware_legacy/AudioMTKHardwareInterface.h
new file mode 100644
index 0000000..c1334ff
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/hardware_legacy/AudioMTKHardwareInterface.h
@@ -0,0 +1,457 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef ANDROID_AUDIO_MTK_HARDWARE_INTERFACE_H
+#define ANDROID_AUDIO_MTK_HARDWARE_INTERFACE_H
+
+//#include <SpeechControlInterface.h>
+
+//! AudioMTKHardwareInterface interface
+/*!
+ this class is hold extension of android default hardwareinterface
+*/
+#include <utils/Errors.h>
+#include <utils/Vector.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+#include <utils/RefBase.h>
+
+#include <hardware/audio.h>
+
+#include <hardware/AudioCustomVolume.h>
+#include <hardware/audio_mtk.h>
+#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioOffload.h>
+
+using android::status_t;
+using namespace android;
+
+class AudioMTKStreamOutInterface {
+public:
+ virtual ~AudioMTKStreamOutInterface() = 0;
+
+ /** return audio sampling rate in hz - eg. 44100 */
+ virtual uint32_t sampleRate() const = 0;
+
+ /** returns size of output buffer - eg. 4800 */
+ virtual size_t bufferSize() const = 0;
+
+ /**
+ * returns the output channel mask
+ */
+ virtual uint32_t channels() const = 0;
+
+ /**
+ * return audio format in 8bit or 16bit PCM format -
+ * eg. AUDIO_FORMAT_PCM_16_BIT
+ */
+ virtual int format() const = 0;
+
+ /**
+ * return the frame size (number of bytes per sample).
+ */
+ uint32_t frameSize() const {
+ return audio_channel_count_from_out_mask(channels()) *
+ ((format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(int8_t));
+ }
+
+ /**
+ * return the audio hardware driver latency in milli seconds.
+ */
+ virtual uint32_t latency() = 0;
+
+ /**
+ * Use this method in situations where audio mixing is done in the
+ * hardware. This method serves as a direct interface with hardware,
+ * allowing you to directly set the volume as apposed to via the framework.
+ * This method might produce multiple PCM outputs or hardware accelerated
+ * codecs, such as MP3 or AAC.
+ */
+ virtual status_t setVolume(float left, float right) = 0;
+
+ /** write audio buffer to driver. Returns number of bytes written */
+ virtual ssize_t write(const void *buffer, size_t bytes) = 0;
+
+ /**
+ * Put the audio hardware output into standby mode. Returns
+ * status based on include/utils/Errors.h
+ */
+ // "standby" is used by framework to close stream out.
+ virtual status_t standby(bool halRequest = true) = 0;
+ // "standbyStreamOut" is used by HAL to close stream out.
+ virtual status_t standbyStreamOut(bool halRequest = true) = 0;
+
+ /** dump the state of the audio output device */
+ virtual status_t dump(int fd, const android::Vector<android::String16> &args) = 0;
+
+ // set/get audio output parameters. The function accepts a list of parameters
+ // key value pairs in the form: key1=value1;key2=value2;...
+ // Some keys are reserved for standard parameters (See AudioParameter class).
+ // If the implementation does not accept a parameter change while the output is
+ // active but the parameter is acceptable otherwise, it must return INVALID_OPERATION.
+ // The audio flinger will put the output in standby and then change the parameter value.
+ virtual status_t setParameters(const android::String8 &keyValuePairs) = 0;
+ virtual android::String8 getParameters(const android::String8 &keys) = 0;
+
+ // return the number of audio frames written by the audio dsp to DAC since
+ // the output has exited standby
+ virtual status_t getRenderPosition(uint32_t *dspFrames) = 0;
+
+ /**
+ * get the local time at which the next write to the audio driver will be
+ * presented
+ */
+ virtual status_t getNextWriteTimestamp(int64_t *timestamp) = 0;
+
+ /**
+ * Return a recent count of the number of audio frames presented to an external observer.
+ */
+ virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp) = 0;
+
+ /**
+ * Called when the metadata of the stream's source has been changed.
+ * @param source_metadata Description of the audio that is played by the clients.
+ */
+ virtual void updateSourceMetadata(const struct source_metadata* source_metadata) = 0;
+
+ virtual status_t setCallBack(stream_callback_t callback, void *cookie) = 0;
+ virtual int pause() = 0;
+ virtual int resume() = 0;
+ virtual int drain(audio_drain_type_t type) = 0;
+
+ virtual int flush() = 0;
+
+ /**
+ * AAudio MMAP
+ */
+ virtual status_t start() = 0;
+ virtual status_t stop() = 0;
+ virtual status_t createMmapBuffer(int32_t min_size_frames,
+ struct audio_mmap_buffer_info *info) = 0;
+ virtual status_t getMmapPosition(struct audio_mmap_position *position) = 0;
+};
+
+class AudioMTKStreamInInterface {
+public:
+ virtual ~AudioMTKStreamInInterface() = 0;
+
+ /** return audio sampling rate in hz - eg. 44100 */
+ virtual uint32_t sampleRate() const = 0;
+
+ /** return the input buffer size allowed by audio driver */
+ virtual size_t bufferSize() const = 0;
+
+ /** return input channel mask */
+ virtual uint32_t channels() const = 0;
+
+ /**
+ * return audio format in 8bit or 16bit PCM format -
+ * eg. AUDIO_FORMAT_PCM_16_BIT
+ */
+ virtual int format() const = 0;
+
+ /**
+ * return the frame size (number of bytes per sample).
+ */
+ uint32_t frameSize() const {
+ return audio_channel_count_from_in_mask(channels()) *
+ ((format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(int8_t));
+ }
+
+ /** set the input gain for the audio driver. This method is for
+ * for future use */
+ virtual status_t setGain(float gain) = 0;
+
+ /** read audio buffer in from audio driver */
+ virtual ssize_t read(void *buffer, ssize_t bytes) = 0;
+
+ /** dump the state of the audio input device */
+ virtual status_t dump(int fd, const android::Vector<android::String16> &args) = 0;
+
+ /**
+ * Put the audio hardware input into standby mode. Returns
+ * status based on include/utils/Errors.h
+ */
+ virtual status_t standby(bool halRequest = true) = 0;
+
+ // set/get audio input parameters. The function accepts a list of parameters
+ // key value pairs in the form: key1=value1;key2=value2;...
+ // Some keys are reserved for standard parameters (See AudioParameter class).
+ // If the implementation does not accept a parameter change while the output is
+ // active but the parameter is acceptable otherwise, it must return INVALID_OPERATION.
+ // The audio flinger will put the input in standby and then change the parameter value.
+ virtual status_t setParameters(const android::String8 &keyValuePairs) = 0;
+ virtual android::String8 getParameters(const android::String8 &keys) = 0;
+
+
+ // Return the number of input frames lost in the audio driver since the last call of this function.
+ // Audio driver is expected to reset the value to 0 and restart counting upon returning the current value by this function call.
+ // Such loss typically occurs when the user space process is blocked longer than the capacity of audio driver buffers.
+ // Unit: the number of input audio frames
+ virtual unsigned int getInputFramesLost() const = 0;
+
+ virtual status_t addAudioEffect(effect_handle_t effect) = 0;
+ virtual status_t removeAudioEffect(effect_handle_t effect) = 0;
+
+ virtual int getCapturePosition(int64_t *frames, int64_t *time) = 0;
+
+ /**
+ * Called by the framework to read active microphones
+ *
+ * \param[in] stream the stream object.
+ * \param[out] mic_array Pointer to first element on array with microphone info
+ * \param[out] mic_count When called, this holds the value of the max number of elements
+ * allowed in the mic_array. The actual number of elements written
+ * is returned here.
+ * if mic_count is passed as zero, mic_array will not be populated,
+ * and mic_count will return the actual number of active microphones.
+ *
+ * \return 0 if the microphone array is successfully filled.
+ * -ENOSYS if there is an error filling the data
+ */
+ virtual int getActiveMicrophones(struct audio_microphone_characteristic_t *mic_array, size_t *mic_count) = 0;
+
+ /**
+ * Called when the metadata of the stream's sink has been changed.
+ * @param sink_metadata Description of the audio that is recorded by the clients.
+ */
+ virtual void updateSinkMetadata(const struct sink_metadata *sink_metadata) = 0;
+
+
+ /**
+ * AAudio MMAP
+ */
+ virtual status_t start() = 0;
+ virtual status_t stop() = 0;
+ virtual status_t createMmapBuffer(int32_t min_size_frames,
+ struct audio_mmap_buffer_info *info) = 0;
+ virtual status_t getMmapPosition(struct audio_mmap_position *position) = 0;
+
+};
+
+class AudioMTKHardwareInterface {
+public:
+ virtual ~AudioMTKHardwareInterface() { }
+
+ /**
+ * check to see if the audio hardware interface has been initialized.
+ * return status based on values defined in include/utils/Errors.h
+ */
+ virtual status_t initCheck() = 0;
+
+ /** set the audio volume of a voice call. Range is between 0.0 and 1.0 */
+ virtual status_t setVoiceVolume(float volume) = 0;
+
+ /**
+ * set the audio volume for all audio activities other than voice call.
+ * Range between 0.0 and 1.0. If any value other than NO_ERROR is returned,
+ * the software mixer will emulate this capability.
+ */
+ virtual status_t setMasterVolume(float volume) = 0;
+
+ /**
+ * Get the current master volume value for the HAL, if the HAL supports
+ * master volume control. AudioFlinger will query this value from the
+ * primary audio HAL when the service starts and use the value for setting
+ * the initial master volume across all HALs.
+ */
+ virtual status_t getMasterVolume(float *volume) = 0;
+
+ /**
+ * setMode is called when the audio mode changes. NORMAL mode is for
+ * standard audio playback, RINGTONE when a ringtone is playing, and IN_CALL
+ * when a call is in progress.
+ */
+ virtual status_t setMode(int mode) = 0;
+
+ // mic mute
+ virtual status_t setMicMute(bool state) = 0;
+ virtual status_t getMicMute(bool *state) = 0;
+
+ // set/get global audio parameters
+ virtual status_t setParameters(const android::String8 &keyValuePairs) = 0;
+ virtual android::String8 getParameters(const android::String8 &keys) = 0;
+
+ // Returns audio input buffer size according to parameters passed or 0 if one of the
+ // parameters is not supported
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount) = 0;
+
+ /** This method creates and opens the audio hardware output stream */
+ virtual AudioMTKStreamOutInterface *openOutputStream(uint32_t devices,
+ int *format = 0,
+ uint32_t *channels = 0,
+ uint32_t *sampleRate = 0,
+ status_t *status = 0) = 0;
+ virtual AudioMTKStreamOutInterface *openOutputStreamWithFlags(uint32_t devices,
+ audio_output_flags_t flags = (audio_output_flags_t)0,
+ int *format = 0,
+ uint32_t *channels = 0,
+ uint32_t *sampleRate = 0,
+ status_t *status = 0) = 0;
+ virtual void closeOutputStream(AudioMTKStreamOutInterface *out) = 0;
+
+ /** This method creates and opens the audio hardware input stream */
+ virtual AudioMTKStreamInInterface *openInputStream(
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
+ status_t *status,
+ audio_in_acoustics_t acoustics) = 0;
+
+ // for open input stream with flag
+ virtual AudioMTKStreamInInterface *openInputStreamWithFlags(
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
+ status_t *status,
+ audio_in_acoustics_t acoustics,
+ audio_input_flags_t flags = (audio_input_flags_t)0) {
+ ALOGV("%s(), flags %d", __FUNCTION__, flags);
+ return openInputStream(devices, format, channels, sampleRate, status, acoustics);
+ }
+
+ virtual void closeInputStream(AudioMTKStreamInInterface *in) = 0;
+
+ /**
+ * Called by the framework to read available microphones characteristics.
+ *
+ * \param[in] dev the hw_device object.
+ * \param[out] mic_array Pointer to first element on array with microphone info
+ * \param[out] mic_count When called, this holds the value of the max number of elements
+ * allowed in the mic_array. The actual number of elements written
+ * is returned here.
+ * if mic_count is passed as zero, mic_array will not be populated,
+ * and mic_count will return the actual number of microphones in the
+ * system.
+ *
+ * \return 0 if the microphone array is successfully filled.
+ * -ENOSYS if there is an error filling the data
+ */
+ virtual int getMicrophones(struct audio_microphone_characteristic_t *mic_array, size_t *mic_count) = 0;
+
+ /**This method dumps the state of the audio hardware */
+ virtual status_t dumpState(int fd, const android::Vector<android::String16> &args) = 0;
+
+ virtual status_t setMasterMute(bool muted) = 0;
+
+ virtual int createAudioPatch(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) = 0;
+
+ virtual int releaseAudioPatch(audio_patch_handle_t handle) = 0;
+
+ virtual int getAudioPort(struct audio_port *port) = 0;
+
+ virtual int setAudioPortConfig(const struct audio_port_config *config) = 0;
+
+ /**
+ * SetEMParamete, set em parameters to audioahrdware
+ * @param ptr
+ * @param len
+ * @return status
+ */
+ virtual status_t SetEMParameter(void *ptr, int len) = 0;
+
+ /**
+ * GetEMParameter, get em parameters to audioahrdware
+ * @param ptr
+ * @param len
+ * @return status
+ */
+ virtual status_t GetEMParameter(void *ptr, int len) = 0;
+
+ /**
+ * SetAudioCommand, base on par1 and par2
+ * @param par1
+ * @param par2
+ * @return status
+ */
+ virtual status_t SetAudioCommand(int par1, int par2) = 0;
+
+ /**
+ * GetAudioCommand, base on par1
+ * @param par1
+ * @return status
+ */
+ virtual status_t GetAudioCommand(int par1) = 0;
+
+ /**
+ * SetAudioData
+ * @param par1
+ * @param len
+ * @param ptr
+ * @return status
+ */
+ virtual status_t SetAudioData(int par1, size_t len, void *ptr) = 0;
+
+ /**
+ * GetAudioData
+ * @param par1
+ * @param len
+ * @param ptr
+ * @return status
+ */
+ virtual status_t GetAudioData(int par1, size_t len, void *ptr) = 0;
+
+ /**
+ * set ACF Preview parameter , thoiis function only temporary replace coefficient
+ * @param ptr
+ * @param len
+ * @return status
+ */
+ virtual status_t SetACFPreviewParameter(void *ptr, int len) = 0;
+
+ /**
+ * set HCF Preview parameter , thoiis function only temporary replace coefficient
+ * @param ptr
+ * @param len
+ * @return status
+ */
+ virtual status_t SetHCFPreviewParameter(void *ptr, int len) = 0;
+
+ /////////////////////////////////////////////////////////////////////////
+ // for PCMxWay Interface API
+ /////////////////////////////////////////////////////////////////////////
+ virtual int xWayPlay_Start(int sample_rate) = 0;
+ virtual int xWayPlay_Stop(void) = 0;
+ virtual int xWayPlay_Write(void *buffer, int size_bytes) = 0;
+ virtual int xWayPlay_GetFreeBufferCount(void) = 0;
+ virtual int xWayRec_Start(int sample_rate) = 0;
+ virtual int xWayRec_Stop(void) = 0;
+ virtual int xWayRec_Read(void *buffer, int size_bytes) = 0;
+
+ //added by wendy
+ virtual int ReadRefFromRing(void *buf, uint32_t datasz, void *DLtime) = 0;
+ virtual int GetVoiceUnlockULTime(void *DLtime) = 0;
+ virtual int SetVoiceUnlockSRC(uint32_t outSR, uint32_t outChannel) = 0;
+ virtual bool startVoiceUnlockDL() = 0;
+ virtual bool stopVoiceUnlockDL() = 0;
+ virtual void freeVoiceUnlockDLInstance() = 0;
+ virtual int GetVoiceUnlockDLLatency() = 0;
+ virtual bool getVoiceUnlockDLInstance() = 0;
+
+ static AudioMTKHardwareInterface *create();
+
+ virtual status_t GetAudioCustomVol(android::AUDIO_CUSTOM_VOLUME_STRUCT *pAudioCustomVol, int dStructLen) = 0;
+
+ virtual int setupParametersCallback(device_parameters_callback_t callback, void *cookie) = 0;
+
+ virtual int setAudioParameterChangedCallback(device_audio_parameter_changed_callback_t callback, void *cookie) = 0;
+
+ virtual int clearAudioParameterChangedCallback(void *cookie) = 0;
+ virtual void setBluetoothAudioOffloadParam(const sp<::android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost>& hostIf,
+ const ::android::hardware::bluetooth::a2dp::V1_0::CodecConfiguration& codecConfig,
+ bool on) = 0;
+ virtual void setA2dpSuspendStatus(int status) = 0;
+
+protected:
+ virtual status_t dump(int fd, const android::Vector<android::String16> &args) = 0;
+
+};
+
+extern "C" AudioMTKHardwareInterface *createMTKAudioHardware(void);
+
+typedef AudioMTKHardwareInterface *create_AudioMTKHw(void);
+
+#endif
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/hardware_legacy/AudioMTKPolicyInterface.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/hardware_legacy/AudioMTKPolicyInterface.h
new file mode 100644
index 0000000..d005601
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/include/hardware_legacy/AudioMTKPolicyInterface.h
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIOPOLICYINTERFACE_MTK_H
+#define ANDROID_AUDIOPOLICYINTERFACE_MTK_H
+
+#include <hardware_legacy/AudioPolicyInterface.h>
+
+namespace android_audio_legacy {
+using android::Vector;
+using android::String8;
+using android::ToneGenerator;
+
+// ----------------------------------------------------------------------------
+
+// The AudioPolicyInterface and AudioPolicyClientInterface classes define the communication interfaces
+// between the platform specific audio policy manager and Android generic audio policy manager.
+// The platform specific audio policy manager must implement methods of the AudioPolicyInterface class.
+// This implementation makes use of the AudioPolicyClientInterface to control the activity and
+// configuration of audio input and output streams.
+//
+// The platform specific audio policy manager is in charge of the audio routing and volume control
+// policies for a given platform.
+// The main roles of this module are:
+// - keep track of current system state (removable device connections, phone state, user requests...).
+// System state changes and user actions are notified to audio policy manager with methods of the AudioPolicyInterface.
+// - process getOutput() queries received when AudioTrack objects are created: Those queries
+// return a handler on an output that has been selected, configured and opened by the audio policy manager and that
+// must be used by the AudioTrack when registering to the AudioFlinger with the createTrack() method.
+// When the AudioTrack object is released, a putOutput() query is received and the audio policy manager can decide
+// to close or reconfigure the output depending on other streams using this output and current system state.
+// - similarly process getInput() and putInput() queries received from AudioRecord objects and configure audio inputs.
+// - process volume control requests: the stream volume is converted from an index value (received from UI) to a float value
+// applicable to each output as a function of platform specific settings and current output route (destination device). It
+// also make sure that streams are not muted if not allowed (e.g. camera shutter sound in some countries).
+//
+// The platform specific audio policy manager is provided as a shared library by platform vendors (as for libaudio.so)
+// and is linked with libaudioflinger.so
+
+
+// Audio Policy Manager Interface
+class AudioMTKPolicyInterface: public AudioPolicyInterface {
+public:
+ virtual ~AudioMTKPolicyInterface() {}
+ virtual status_t SetPolicyManagerParameters(int par1, int par2, int par3, int par4) = 0;
+};
+
+extern "C" AudioMTKPolicyInterface *createAudioMTKPolicyManager(AudioPolicyClientInterface *clientInterface);
+extern "C" void destroyAudioMTKPolicyManager(AudioMTKPolicyInterface *interface);
+
+
+}; // namespace android
+
+#endif // ANDROID_AUDIOPOLICYINTERFACE_MTK_H
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/AudioALSASpeechPhoneCallController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/AudioALSASpeechPhoneCallController.cpp
new file mode 100644
index 0000000..97b1f4a
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/AudioALSASpeechPhoneCallController.cpp
@@ -0,0 +1,1979 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioALSASpeechPhoneCallController"
+#include <AudioALSASpeechPhoneCallController.h>
+
+#include <cutils/properties.h>
+
+#include <pthread.h>
+#include <utils/threads.h>
+
+#include <hardware_legacy/power.h>
+
+#include <SpeechUtility.h>
+
+#include <AudioALSAHardwareResourceManager.h>
+#include <AudioALSAStreamManager.h>
+
+#include <AudioVolumeFactory.h>
+#include <SpeechDriverFactory.h>
+
+#include <SpeechEnhancementController.h>
+#include <SpeechPcm2way.h>
+#include <SpeechBGSPlayer.h>
+#include <SpeechVMRecorder.h>
+#include <WCNChipController.h>
+#include <AudioALSADriverUtility.h>
+#include <AudioALSADeviceParser.h>
+
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+#include <SpeechConfig.h>
+#include <AudioALSAParamTuner.h>
+#if !defined(MTK_COMBO_MODEM_SUPPORT)
+#include <SpeechParamParser.h>
+#endif
+#endif
+
+#if defined(MTK_AUDIO_KS)
+#include <AudioALSADeviceConfigManager.h>
+#include <AudioSmartPaController.h>
+#endif
+
+#if defined(MTK_AURISYS_PHONE_CALL_SUPPORT)
+#include <audio_task.h>
+#include <AudioMessengerIPI.h>
+#endif
+#if defined(SPH_VCL_SUPPORT)
+#include <SpeechVoiceCustomLogger.h>
+#endif
+#if defined(MTK_SPEECH_ENCRYPTION_SUPPORT)
+#include <SpeechDataEncrypter.h>
+#endif
+
+#if defined(MTK_USB_PHONECALL)
+#include <AudioUSBPhoneCallController.h>
+#endif
+
+#if defined(MTK_AUDIO_SMARTPASCP_SUPPORT)
+#include <AudioSCPPhoneCallController.h>
+#endif
+// refer to /alps/vendor/mediatek/proprietary/hardware/ril/libratconfig/ratconfig.c
+#define CDMA "C"
+
+
+namespace android {
+
+/*==============================================================================
+ * Property keys
+ *============================================================================*/
+static const char *PROPERTY_KEY_MIC_MUTE_ON = "vendor.audiohal.recovery.mic_mute_on";
+static const char *PROPERTY_KEY_DL_MUTE_ON = "vendor.audiohal.recovery.dl_mute_on";
+static const char *PROPERTY_KEY_UL_MUTE_ON = "vendor.audiohal.recovery.ul_mute_on";
+static const char *PROPERTY_KEY_PHONE1_MD = "vendor.audiohal.recovery.phone1.md";
+static const char *PROPERTY_KEY_PHONE2_MD = "vendor.audiohal.recovery.phone2.md";
+static const char *PROPERTY_KEY_FOREGROUND_PHONE_ID = "vendor.audiohal.recovery.phone_id";
+
+static const char WAKELOCK_NAME[] = "EXT_MD_AUDIO_WAKELOCK";
+
+
+#define DEFAULT_WAIT_SHUTTER_SOUND_UNMUTE_MS (1000) /* 1 sec */
+#define DEFAULT_WAIT_ROUTING_UNMUTE_MS (150) /* 150ms */
+#define DEFAULT_WAIT_PMIC_RESET_MS (1000) /* 1 sec */
+
+enum {
+ SPH_MUTE_THREAD_STATE_IDLE,
+ SPH_MUTE_THREAD_STATE_WAIT
+};
+
+enum {
+ SPH_MUTE_CTRL_IDLE,
+ SPH_MUTE_CTRL_ROUTING_START,
+ SPH_MUTE_CTRL_ROUTING_END,
+ SPH_MUTE_CTRL_VOLUME_UPDATE
+};
+
+enum {
+ RTT_CALL_TYPE_CS = 0,
+ RTT_CALL_TYPE_RTT = 1,
+ RTT_CALL_TYPE_PS = 2,
+ RTT_CALL_TYPE_CS_NO_TTY = 3
+};
+
+enum {
+ AUD_RTT_OFF = 0,
+ AUD_RTT_ON = 1
+};
+
+static struct mixer *mMixer;
+
+#if !defined (MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+static void setTtyEnhancementMask(TtyModeType ttMode);
+#endif
+/*==============================================================================
+ * Singleton Pattern
+ *============================================================================*/
+
+AudioALSASpeechPhoneCallController *AudioALSASpeechPhoneCallController::mSpeechPhoneCallController = NULL;
+AudioALSASpeechPhoneCallController *AudioALSASpeechPhoneCallController::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (mSpeechPhoneCallController == NULL) {
+ mSpeechPhoneCallController = new AudioALSASpeechPhoneCallController();
+ }
+ ASSERT(mSpeechPhoneCallController != NULL);
+ return mSpeechPhoneCallController;
+}
+
+
+
+/*==============================================================================
+ * Constructor / Destructor / Init / Deinit
+ *============================================================================*/
+
+AudioALSASpeechPhoneCallController::AudioALSASpeechPhoneCallController() :
+ mHardwareResourceManager(AudioALSAHardwareResourceManager::getInstance()),
+ mStreamManager(NULL),
+ mAudioALSAVolumeController(AudioVolumeFactory::CreateAudioVolumeController()),
+ mSpeechDriverFactory(SpeechDriverFactory::GetInstance()),
+ mAudioBTCVSDControl(NULL),
+ mAudioMode(AUDIO_MODE_NORMAL),
+ mMicMute(false),
+ mVtNeedOn(false),
+ bAudioTaste(false),
+ mTtyMode(AUD_TTY_OFF),
+ mInputDevice(AUDIO_DEVICE_NONE),
+ mOutputDevice(AUDIO_DEVICE_NONE),
+ mAdjustedInDev(AUDIO_DEVICE_NONE),
+ mAdjustedOutDev(AUDIO_DEVICE_NONE),
+ mIsBtSpkDevice(false),
+ mBTMode(0),
+ mIdxMD(MODEM_1),
+ mPcmIn(NULL),
+ mPcmOut(NULL),
+ mRfInfo(0),
+ mRfMode(0),
+ mASRCNeedOn(0),
+ mSpeechDVT_SampleRate(0),
+ mSpeechDVT_MD_IDX(0),
+ mIsSidetoneEnable(false),
+ hPmicResetThread(0),
+ mIsPmicResetThreadEnable(false),
+ hMuteDlCodecForShutterSoundThread(0),
+ mMuteDlCodecForShutterSoundThreadEnable(false),
+ mMuteDlCodecForShutterSoundCount(0),
+ mIsMuteDlCodec(false),
+ mMuteDlUlForRoutingThread(0),
+ mMuteDlUlForRoutingThreadEnable(false),
+ mMuteDlUlForRoutingState(SPH_MUTE_THREAD_STATE_IDLE),
+ mMuteDlUlForRoutingCtrl(SPH_MUTE_CTRL_IDLE),
+ mRttCallType(RTT_CALL_TYPE_CS),
+ mRttMode(AUD_RTT_OFF),
+ mSuperVolumeEnable(false) {
+
+ mLogEnable = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);
+ // check need mute mic or not after kill mediaserver
+ mMicMute = get_uint32_from_mixctrl(PROPERTY_KEY_MIC_MUTE_ON);
+
+ // Need Mute DL Voice
+ mDlMute = get_uint32_from_mixctrl(PROPERTY_KEY_DL_MUTE_ON);
+
+ // Need Mute UL Voice
+ mUlMute = get_uint32_from_mixctrl(PROPERTY_KEY_UL_MUTE_ON);
+
+ //"0": default 0
+ mPhoneId = (phone_id_t)get_uint32_from_mixctrl(PROPERTY_KEY_FOREGROUND_PHONE_ID);
+
+ //"0": default MD1
+ mIdxMDByPhoneId[0] = (get_uint32_from_mixctrl(PROPERTY_KEY_PHONE1_MD) == 0) ? MODEM_1 : MODEM_EXTERNAL;
+
+ //"0": default MD1
+ mIdxMDByPhoneId[1] = (get_uint32_from_mixctrl(PROPERTY_KEY_PHONE2_MD) == 0) ? MODEM_1 : MODEM_EXTERNAL;
+
+ mMixer = AudioALSADriverUtility::getInstance()->getMixer();
+ ASSERT(mMixer != NULL);
+ // initialize mConfig
+ memset((void *)&mConfig, 0, sizeof(pcm_config));
+
+}
+
+AudioALSASpeechPhoneCallController::~AudioALSASpeechPhoneCallController() {
+
+}
+
+bool AudioALSASpeechPhoneCallController::checkTtyNeedOn() const {
+ return (mTtyMode != AUD_TTY_OFF && mVtNeedOn == false && mTtyMode != AUD_TTY_ERR &&
+#if defined(MTK_RTT_SUPPORT)
+ mRttCallType == RTT_CALL_TYPE_CS &&
+#endif
+ (!audio_is_bluetooth_sco_device(mOutputDevice)));
+}
+
+bool AudioALSASpeechPhoneCallController::checkSideToneFilterNeedOn(const audio_devices_t output_device) const {
+ // TTY do not use STMF. Open only for earphone & receiver when side tone != 0.
+ return ((checkTtyNeedOn() == false) &&
+ //disable the condition, turn on sidetone without check the gain value
+ // (mAudioALSAVolumeController->GetSideToneGain(output_device) != 0) &&
+ (output_device == AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+ output_device == AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+ output_device == AUDIO_DEVICE_OUT_EARPIECE));
+}
+
+status_t AudioALSASpeechPhoneCallController::init() {
+ return NO_ERROR;
+}
+
+
+audio_devices_t AudioALSASpeechPhoneCallController::getInputDeviceForPhoneCall(const audio_devices_t output_devices) {
+ audio_devices_t input_device;
+
+ switch (output_devices) {
+ case AUDIO_DEVICE_OUT_WIRED_HEADSET: {
+ if (mTtyMode == AUD_TTY_VCO) {
+ input_device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ ALOGD("%s(), headset, TTY_VCO, input_device(0x%x)", __FUNCTION__, input_device);
+ } else {
+ input_device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ }
+ break;
+ }
+ case AUDIO_DEVICE_OUT_EARPIECE:
+ case AUDIO_DEVICE_OUT_WIRED_HEADPHONE: {
+ input_device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ break;
+ }
+ case AUDIO_DEVICE_OUT_SPEAKER: {
+ if (mTtyMode == AUD_TTY_HCO || mTtyMode == AUD_TTY_FULL) {
+ input_device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ ALOGD("%s(), speaker, mTtyMode(%d), input_device(0x%x)", __FUNCTION__, mTtyMode, input_device);
+ } else {
+ if (USE_REFMIC_IN_LOUDSPK == 1) {
+ input_device = AUDIO_DEVICE_IN_BACK_MIC;
+ } else {
+ input_device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ }
+ }
+ break;
+ }
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT: {
+ input_device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ break;
+ }
+#if defined(MTK_USB_PHONECALL)
+ case AUDIO_DEVICE_OUT_USB_DEVICE: {
+ input_device = AudioUSBPhoneCallController::getInstance()->getUSBCallInDevice();
+ break;
+ }
+#endif
+ default: {
+ ALOGW("%s(), no support such output_devices(0x%x), "
+ "default use AUDIO_DEVICE_IN_BUILTIN_MIC(0x%x) as input_device",
+ __FUNCTION__, output_devices, AUDIO_DEVICE_IN_BUILTIN_MIC);
+ input_device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ break;
+ }
+ }
+
+ return input_device;
+}
+
+status_t AudioALSASpeechPhoneCallController::open(const audio_mode_t audio_mode,
+ const audio_devices_t output_devices,
+ const audio_devices_t input_device) {
+ AL_AUTOLOCK(mLock);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+ AL_AUTOLOCK(mCheckOpenLock);
+
+ ALOGD("%s(+), mAudioMode: %d => %d, output_devices: 0x%x, input_device: 0x%x",
+ __FUNCTION__, mAudioMode, audio_mode, output_devices, input_device);
+
+ int PcmInIdx = 0;
+ int PcmOutIdx = 0;
+ int CardIndex = 0;
+ uint32_t sample_rate = 0;
+
+ mLogEnable = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);
+
+ // set speech driver instance
+ if (bAudioTaste) {
+ mIdxMD = MODEM_1;
+ } else {
+ modem_index_t modem_index_property = updatePhysicalModemIdx(audio_mode);
+ mIdxMD = modem_index_property;
+ }
+
+ hMuteDlCodecForShutterSoundThread = 0;
+ mMuteDlCodecForShutterSoundCount = 0;
+ mMuteDlCodecForShutterSoundThreadEnable = true;
+ mIsMuteDlCodec = false;
+ int ret = pthread_create(&hMuteDlCodecForShutterSoundThread, NULL,
+ AudioALSASpeechPhoneCallController::muteDlCodecForShutterSoundThread,
+ (void *)this);
+ ASSERT(ret == 0);
+
+ mMuteDlUlForRoutingThread = 0;
+ mMuteDlUlForRoutingThreadEnable = true;
+ mMuteDlUlForRoutingState = SPH_MUTE_THREAD_STATE_IDLE;
+ ret = pthread_create(&mMuteDlUlForRoutingThread, NULL,
+ AudioALSASpeechPhoneCallController::muteDlUlForRoutingThread,
+ (void *)this);
+ ASSERT(ret == 0);
+
+ mSpeechDriverFactory->SetActiveModemIndex(mIdxMD);
+ char isC2kSupported[PROPERTY_VALUE_MAX];
+ property_get("ro.boot.opt_ps1_rat", isC2kSupported, "0"); //"0": default not support
+
+ if (strstr(isC2kSupported, CDMA) == NULL) {
+ // wake lock for external modem
+ if (mIdxMD == MODEM_EXTERNAL) {
+ int ret = acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKELOCK_NAME);
+ }
+ }
+#if defined(MTK_AURISYS_PHONE_CALL_SUPPORT)
+ /* Load task scene when opening */
+ AudioMessengerIPI::getInstance()->loadTaskScene(TASK_SCENE_PHONE_CALL);
+#endif
+ SpeechDriverInterface *pSpeechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ mOutputDevice = output_devices;
+ mInputDevice = input_device;
+ if (checkTtyNeedOn() == true) {
+ adjustTtyInOutDevice();
+ } else {
+ mAdjustedOutDev = mOutputDevice;
+ mAdjustedInDev = mInputDevice;
+ }
+
+ // check BT device
+ const bool bt_device_on = audio_is_bluetooth_sco_device(mAdjustedOutDev);
+ if (mSpeechDVT_SampleRate != 0) {
+ sample_rate = mSpeechDVT_SampleRate;
+ ALOGD("%s(), SpeechDVT sample_rate = %d", __FUNCTION__, sample_rate);
+ } else {
+ sample_rate = calculateSampleRate(bt_device_on);
+ }
+
+
+ //--- here to test pcm interface platform driver_attach
+ if (bt_device_on) {
+ if (WCNChipController::GetInstance()->IsBTMergeInterfaceSupported() == true) {
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = 1;
+ mConfig.rate = sample_rate;
+ mConfig.period_size = 4096;
+ mConfig.period_count = 2;
+ mConfig.format = PCM_FORMAT_S16_LE;
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+ ALOGE_IF(mPcmOut != NULL, "%s(), mPcmOut = %p", __FUNCTION__, mPcmOut);
+ ASSERT(mPcmOut == NULL);
+
+ if (mIdxMD == MODEM_EXTERNAL || mIdxMD == MODEM_2) {
+ PcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceMD2BT);
+ CardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVoiceMD2BT);
+ mPcmOut = pcm_open(CardIndex, PcmOutIdx, PCM_OUT, &mConfig);
+ } else {
+ PcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceMD1BT);
+ CardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVoiceMD1BT);
+ mPcmOut = pcm_open(CardIndex, PcmOutIdx, PCM_OUT, &mConfig);
+ }
+
+ ALOGD_IF(mPcmOut == NULL, "%s(), mPcmOut = %p, PcmOutIdx = %d, CardIndex = %d",
+ __FUNCTION__, mPcmOut, PcmOutIdx, CardIndex);
+ ASSERT(mPcmOut != NULL);
+ pcm_start(mPcmOut);
+ }
+#if defined(MTK_USB_PHONECALL)
+ } else if (AudioUSBPhoneCallController::getInstance()->isForceUSBCall() ||
+ mAdjustedOutDev == AUDIO_DEVICE_OUT_USB_DEVICE) {
+ AudioUSBPhoneCallController::getInstance()->enable(sample_rate);
+#endif
+#if defined(MTK_AUDIO_KS) && defined(MTK_AUDIO_SMARTPASCP_SUPPORT)
+ } else if (AudioSCPPhoneCallController::getInstance()->isSupportPhonecall(mAdjustedOutDev)) {
+ AudioSCPPhoneCallController::getInstance()->enable(sample_rate, mAdjustedInDev);
+#endif
+ } else {
+ ALOGE_IF(mPcmIn != NULL, "%s(), mPcmIn = %p", __FUNCTION__, mPcmIn);
+ ALOGE_IF(mPcmOut != NULL, "%s(), mPcmOut = %p", __FUNCTION__, mPcmOut);
+ ASSERT(mPcmIn == NULL && mPcmOut == NULL);
+
+#if defined(MTK_VOICE_ULTRA)
+ if (mAdjustedOutDev == AUDIO_DEVICE_OUT_EARPIECE) {
+ PcmInIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceUltra);
+ PcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceUltra);
+ CardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVoiceUltra);
+ String8 mixer_ctl_name;
+ if (mIdxMD == MODEM_EXTERNAL || mIdxMD == MODEM_2) {
+ mixer_ctl_name = "md2";
+ } else {
+ mixer_ctl_name = "md1";
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Ultra_Modem_Select"),
+ mixer_ctl_name.string())) {
+ ALOGE("Error: Ultra_Modem_Select invalid value");
+ }
+ // use pcm out to set memif, ultrasound, downlink
+ enum pcm_format memifFormat = PCM_FORMAT_S16_LE; // or PCM_FORMAT_S32_LE
+ unsigned int ultraRate = 96000;
+ unsigned int msPerPeriod = 10; // note: max sram is 48k
+
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = 1;
+ mConfig.rate = ultraRate;
+ mConfig.period_size = (ultraRate * msPerPeriod) / 1000;
+ mConfig.period_count = 2;
+ mConfig.format = memifFormat;
+
+ mPcmOut = pcm_open(CardIndex, PcmOutIdx, PCM_OUT, &mConfig);
+
+ // use pcm in to set modem, uplink
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = 2;
+ mConfig.rate = sample_rate;
+ mConfig.period_size = 1024;
+ mConfig.period_count = 2;
+ mConfig.format = PCM_FORMAT_S16_LE;
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+ mPcmIn = pcm_open(CardIndex, PcmInIdx, PCM_IN, &mConfig);
+ } else
+#endif
+ {
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = 2;
+ mConfig.rate = sample_rate;
+ mConfig.period_size = 1024;
+ mConfig.period_count = 2;
+ mConfig.format = PCM_FORMAT_S16_LE;
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+
+#if defined(MTK_AUDIO_KS)
+ mConfig.stop_threshold = ~(0U);
+ if ((mAdjustedOutDev & AUDIO_DEVICE_OUT_SPEAKER) &&
+ AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence((mIdxMD == MODEM_EXTERNAL || mIdxMD == MODEM_2) ?
+ AUDIO_CTL_MD2_TO_I2S : AUDIO_CTL_MD1_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+
+ if (popcount(mAdjustedOutDev) > 1) {
+ mApTurnOnSequence2 = (mIdxMD == MODEM_EXTERNAL || mIdxMD == MODEM_2) ?
+ AUDIO_CTL_MD2_TO_ADDA_DL : AUDIO_CTL_MD1_TO_ADDA_DL;
+ }
+ } else {
+ mApTurnOnSequence = (mIdxMD == MODEM_EXTERNAL || mIdxMD == MODEM_2) ?
+ AUDIO_CTL_MD2_TO_ADDA_DL : AUDIO_CTL_MD1_TO_ADDA_DL;
+ }
+
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence2);
+ }
+
+ PcmInIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessSpeech);
+ PcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessSpeech);
+ CardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmHostlessSpeech);
+#else
+ if (mIdxMD == MODEM_EXTERNAL || mIdxMD == MODEM_2) {
+ PcmInIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceMD2);
+ PcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceMD2);
+ CardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVoiceMD2);
+ } else {
+ PcmInIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceMD1);
+ PcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceMD1);
+ CardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVoiceMD1);
+ }
+#endif
+ mPcmIn = pcm_open(CardIndex, PcmInIdx, PCM_IN, &mConfig);
+ mConfig.channels = 2;
+ mPcmOut = pcm_open(CardIndex, PcmOutIdx, PCM_OUT, &mConfig);
+ }
+ ALOGD_IF(mPcmIn == NULL, "%s(), mPcmIn = %p, PcmInIdx = %d, CardIndex = %d",
+ __FUNCTION__, mPcmIn, PcmInIdx, CardIndex);
+ ALOGD_IF(mPcmOut == NULL, "%s(), mPcmOut = %p, PcmOutIdx = %d, CardIndex = %d",
+ __FUNCTION__, mPcmOut, PcmOutIdx, CardIndex);
+ ASSERT(mPcmIn != NULL && mPcmOut != NULL);
+
+#if !defined(MTK_AUDIO_KS)
+ pcm_start(mPcmIn);
+#endif
+ pcm_start(mPcmOut);
+
+#if !defined(MTK_AUDIO_KS) && defined(MTK_AUDIO_SMARTPASCP_SUPPORT)
+ if (AudioSCPPhoneCallController::getInstance()->isSupportPhonecall(mAdjustedOutDev)) {
+ AudioSCPPhoneCallController::getInstance()->enable(sample_rate, mAdjustedInDev);
+ }
+#endif
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Speech_MD_USAGE"), "On")) {
+ ALOGE("Error: Speech_MD invalid value");
+ }
+
+ if (checkTtyNeedOn() == true) {
+ setTtyInOutDevice();
+ } else {
+
+ // Set PMIC digital/analog part - uplink has pop, open first
+#if defined(MTK_USB_PHONECALL)
+ if (!AudioUSBPhoneCallController::getInstance()->isEnable()) {
+ mHardwareResourceManager->startInputDevice(mAdjustedInDev);
+ }
+#else
+ mHardwareResourceManager->startInputDevice(mAdjustedInDev);
+#endif
+ }
+
+#if defined(MTK_AUDIO_KS)
+ // after start input device
+ if (mPcmIn) {
+ pcm_start(mPcmIn);
+ }
+#endif
+
+ // start Side Tone Filter
+ if (checkSideToneFilterNeedOn(mAdjustedOutDev) == true) {
+ mHardwareResourceManager->EnableSideToneFilter(true);
+ mIsSidetoneEnable = true;
+ }
+#if defined(MTK_SPEECH_ENCRYPTION_SUPPORT)
+ if (SpeechDataEncrypter::GetInstance()->GetEnableStatus()) {
+ SpeechDataEncrypter::GetInstance()->Start();
+ }
+#endif
+
+ // Set MD side sampling rate
+ pSpeechDriver->SetModemSideSamplingRate(sample_rate);
+
+ // Set speech mode
+ if (checkTtyNeedOn() == false) {
+#if defined(MTK_USB_PHONECALL)
+ if (AudioUSBPhoneCallController::getInstance()->isForceUSBCall()) {
+ pSpeechDriver->SetSpeechMode(mAdjustedInDev, AUDIO_DEVICE_OUT_USB_DEVICE);
+ } else {
+ pSpeechDriver->SetSpeechMode(mAdjustedInDev, mAdjustedOutDev);
+ }
+
+ if (!AudioUSBPhoneCallController::getInstance()->isEnable()) {
+ mHardwareResourceManager->startOutputDevice(mAdjustedOutDev, sample_rate);
+ }
+#else
+ pSpeechDriver->SetSpeechMode(mAdjustedInDev, mAdjustedOutDev);
+ mHardwareResourceManager->startOutputDevice(mAdjustedOutDev, sample_rate);
+#endif
+ }
+
+ // Speech/VT on
+ if (mVtNeedOn == true) {
+ pSpeechDriver->VideoTelephonyOn();
+
+ // trun on P2W for Video Telephony
+ bool wideband_on = false; // VT default use Narrow Band (8k), modem side will SRC to 16K
+ pSpeechDriver->PCM2WayOn(wideband_on);
+ } else {
+ pSpeechDriver->SpeechOn();
+
+ // turn on TTY
+ if (checkTtyNeedOn() == true) {
+ pSpeechDriver->TtyCtmOn();
+#if !defined (MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ setTtyEnhancementMask(mTtyMode);
+#endif
+ }
+ }
+ // for the case that customized app set mute before speech on
+ pSpeechDriver->SetUplinkMute(mMicMute);
+
+#if defined(MTK_RTT_SUPPORT)
+ pSpeechDriver->RttConfig(mRttMode);
+#endif
+
+#if defined(SPH_VCL_SUPPORT)
+ // check VCL need open
+ SpeechVoiceCustomLogger *pSpeechVoiceCustomLogger = SpeechVoiceCustomLogger::GetInstance();
+ if (pSpeechVoiceCustomLogger->UpdateVCLSwitch() == true) {
+ pSpeechVoiceCustomLogger->Open();
+ }
+#endif
+
+#if defined(SPEECH_PMIC_RESET_ACC) || defined(SPEECH_PMIC_RESET_DCC)
+ hPmicResetThread = 0;
+ AL_LOCK(mPmicResetLock);
+ mIsPmicResetThreadEnable = true;
+ AL_UNLOCK(mPmicResetLock);
+ ret = pthread_create(&hPmicResetThread, NULL,
+ AudioALSASpeechPhoneCallController::pmicResetThread,
+ (void *)this);
+ ASSERT(ret == 0);
+#endif
+
+ // check VM need open
+ SpeechVMRecorder *pSpeechVMRecorder = SpeechVMRecorder::getInstance();
+ if (pSpeechVMRecorder->getVmConfig() == SPEECH_VM_SPEECH) {
+ pSpeechVMRecorder->open();
+ }
+
+ mAudioMode = audio_mode;
+
+ ALOGD("%s(-), mAudioMode: %d, mIdxMD: %d, bt_device_on: %d, sample_rate: %u"
+ ", isC2kSupported: %s"
+ ", CardIndex: %d, PcmInIdx: %d, PcmOutIdx: %d, mPcmIn: %p, mPcmOut: %p",
+ __FUNCTION__, mAudioMode, mIdxMD, bt_device_on, sample_rate,
+ isC2kSupported,
+ CardIndex, PcmInIdx, PcmOutIdx, mPcmIn, mPcmOut);
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSASpeechPhoneCallController::close() {
+ AL_AUTOLOCK(mLock);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+ ALOGD("%s(), mAudioMode: %d => 0", __FUNCTION__, mAudioMode);
+
+ const modem_index_t modem_index = mSpeechDriverFactory->GetActiveModemIndex();
+ const audio_devices_t old_output_device = mHardwareResourceManager->getOutputDevice();
+
+ // Get current active speech driver
+ SpeechDriverInterface *pSpeechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ pSpeechDriver->SetUplinkMute(true);
+#if defined(MTK_SPEECH_ENCRYPTION_SUPPORT)
+ if (SpeechDataEncrypter::GetInstance()->GetStartStatus()) {
+ SpeechDataEncrypter::GetInstance()->Stop();
+ }
+#endif
+
+ // check VM need close
+ SpeechVMRecorder *pSpeechVMRecorder = SpeechVMRecorder::getInstance();
+ if (pSpeechVMRecorder->getVMRecordStatus() == true) {
+ pSpeechVMRecorder->close();
+ }
+
+#if defined(SPH_VCL_SUPPORT)
+ // check VCL need open
+ SpeechVoiceCustomLogger *pSpeechVoiceCustomLogger = SpeechVoiceCustomLogger::GetInstance();
+ if (pSpeechVoiceCustomLogger->GetVCLRecordStatus() == true) {
+ pSpeechVoiceCustomLogger->Close();
+ }
+#endif
+
+ struct mixer_ctl *ctl;
+ enum mixer_ctl_type type;
+ unsigned int num_values;
+
+#if defined(MTK_USB_PHONECALL)
+ if (!AudioUSBPhoneCallController::getInstance()->isEnable())
+#endif
+ {
+ mHardwareResourceManager->stopOutputDevice();
+
+ // Stop Side Tone Filter
+ if (mIsSidetoneEnable) {
+ mHardwareResourceManager->EnableSideToneFilter(false);
+ mIsSidetoneEnable = false;
+ }
+ }
+ // Stop MODEM_PCM
+ if (mPcmIn != NULL) {
+ pcm_stop(mPcmIn);
+ pcm_close(mPcmIn);
+ mPcmIn = NULL;
+ }
+
+ if (mPcmOut != NULL) {
+ pcm_stop(mPcmOut);
+ pcm_close(mPcmOut);
+ mPcmOut = NULL;
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence2);
+ mApTurnOnSequence2.clear();
+ }
+#endif
+ }
+
+#if defined(MTK_USB_PHONECALL)
+ if (!AudioUSBPhoneCallController::getInstance()->isEnable()) {
+ mHardwareResourceManager->stopInputDevice(mAdjustedInDev);
+ mAdjustedInDev = AUDIO_DEVICE_NONE;
+ } else {
+ AudioUSBPhoneCallController::getInstance()->disable();
+ }
+#else
+ mHardwareResourceManager->stopInputDevice(mAdjustedInDev);
+ mAdjustedInDev = AUDIO_DEVICE_NONE;
+#endif
+ mAdjustedOutDev = AUDIO_DEVICE_NONE;
+
+#if defined(MTK_AUDIO_SMARTPASCP_SUPPORT)
+ if (AudioSCPPhoneCallController::getInstance()->isEnable()) {
+ AudioSCPPhoneCallController::getInstance()->disable();
+ }
+#endif
+ // terminated pmic reset thread
+ if (mIsPmicResetThreadEnable == true) {
+ AL_LOCK(mPmicResetLock);
+ mIsPmicResetThreadEnable = false;
+ AL_SIGNAL(mPmicResetLock);
+ AL_UNLOCK(mPmicResetLock);
+
+ pthread_join(hPmicResetThread, NULL);
+ }
+
+ // terminated shutter sound thread
+ if (mMuteDlCodecForShutterSoundThreadEnable == true) {
+ AL_LOCK(mMuteDlCodecForShutterSoundLock);
+ mMuteDlCodecForShutterSoundThreadEnable = false;
+ AL_SIGNAL(mMuteDlCodecForShutterSoundLock);
+ AL_UNLOCK(mMuteDlCodecForShutterSoundLock);
+
+ pthread_join(hMuteDlCodecForShutterSoundThread, NULL);
+ }
+
+ // terminated mute for routing thread
+ if (mMuteDlUlForRoutingThreadEnable == true) {
+ AL_LOCK(mMuteDlUlForRoutingLock);
+ mMuteDlUlForRoutingThreadEnable = false;
+ AL_SIGNAL(mMuteDlUlForRoutingLock);
+ AL_UNLOCK(mMuteDlUlForRoutingLock);
+
+ pthread_join(mMuteDlUlForRoutingThread, NULL);
+ }
+
+#if defined(MTK_RTT_SUPPORT)
+ pSpeechDriver->RttConfig(AUD_RTT_OFF);
+#endif
+
+ // Speech/VT off
+ if (pSpeechDriver->GetApSideModemStatus(VT_STATUS_MASK) == true) {
+ pSpeechDriver->PCM2WayOff();
+ pSpeechDriver->VideoTelephonyOff();
+ } else if (pSpeechDriver->GetApSideModemStatus(SPEECH_STATUS_MASK) == true) {
+ if (pSpeechDriver->GetApSideModemStatus(TTY_STATUS_MASK) == true) {
+ pSpeechDriver->TtyCtmOff();
+
+#if !defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ pSpeechDriver->SetSpeechEnhancement(true);
+ pSpeechDriver->SetSpeechEnhancementMask(SpeechEnhancementController::GetInstance()->GetSpeechEnhancementMask());
+#endif
+ }
+ pSpeechDriver->SpeechOff();
+ } else {
+ ALOGE("%s(), mAudioMode = %d, Speech & VT are already closed!!", __FUNCTION__, mAudioMode);
+ ASSERT(pSpeechDriver->GetApSideModemStatus(VT_STATUS_MASK) == true ||
+ pSpeechDriver->GetApSideModemStatus(SPEECH_STATUS_MASK) == true);
+ }
+
+ // clean VT status
+ if (mVtNeedOn == true) {
+ ALOGD("%s(), Set mVtNeedOn = false", __FUNCTION__);
+ mVtNeedOn = false;
+ }
+ pSpeechDriver->SetUplinkMute(mMicMute);
+
+ char isC2kSupported[PROPERTY_VALUE_MAX];
+ property_get("ro.boot.opt_ps1_rat", isC2kSupported, "0"); //"0": default not support
+
+ if (strstr(isC2kSupported, CDMA) == NULL) {
+ // wake lock for external modem
+ if (mIdxMD == MODEM_EXTERNAL) {
+ int ret = release_wake_lock(WAKELOCK_NAME);
+ }
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Speech_MD_USAGE"), "Off")) {
+ ALOGE("Error: Speech_MD_USAGE invalid value");
+ }
+
+ mAudioMode = AUDIO_MODE_NORMAL; // TODO(Harvey): default value? VoIP?
+ mOutputDevice = mAdjustedOutDev;
+ mInputDevice = mAdjustedInDev;
+
+ return NO_ERROR;
+}
+
+
+status_t AudioALSASpeechPhoneCallController::routing(const audio_devices_t new_output_devices,
+ const audio_devices_t new_input_device) {
+ AL_AUTOLOCK(mLock);
+ AL_AUTOLOCK(*AudioALSADriverUtility::getInstance()->getStreamSramDramLock());
+
+ ALOGD("%s(+), mAudioMode: %d, mIdxMD: %d, new_output_devices: 0x%x, new_input_device: 0x%x",
+ __FUNCTION__, mAudioMode, mIdxMD, new_output_devices, new_input_device);
+
+ const modem_index_t modem_index = mSpeechDriverFactory->GetActiveModemIndex();
+ const audio_devices_t old_output_device = mHardwareResourceManager->getOutputDevice();
+
+ // Get current active speech driver
+ SpeechDriverInterface *pSpeechDriver = mSpeechDriverFactory->GetSpeechDriver();
+
+ int PcmInIdx = 0;
+ int PcmOutIdx = 0;
+ int CardIndex = 0;
+
+ // Mute during device change.
+ muteDlUlForRouting(SPH_MUTE_CTRL_ROUTING_START);
+
+#if defined(MTK_USB_PHONECALL)
+ if (!AudioUSBPhoneCallController::getInstance()->isEnable())
+#endif
+ {
+ // Stop PMIC digital/analog part - downlink
+ mHardwareResourceManager->stopOutputDevice();
+
+ // Stop Side Tone Filter
+ if (mIsSidetoneEnable) {
+ mHardwareResourceManager->EnableSideToneFilter(false);
+ mIsSidetoneEnable = false;
+ }
+
+ // Stop MODEM_PCM
+ //mAudioDigitalInstance->SetModemPcmEnable(modem_index, false);
+
+ // Stop PMIC digital/analog part - uplink
+ mHardwareResourceManager->stopInputDevice(mAdjustedInDev);
+ mAdjustedInDev = AUDIO_DEVICE_NONE;
+
+ }
+
+ // Stop AP side digital part
+ if (pSpeechDriver->GetApSideModemStatus(TTY_STATUS_MASK) == true) {
+ pSpeechDriver->TtyCtmOff();
+ }
+
+ // Get new device
+ mOutputDevice = new_output_devices;
+ mInputDevice = new_input_device;
+ if (checkTtyNeedOn() == true) {
+ adjustTtyInOutDevice();
+ } else {
+ mAdjustedOutDev = mOutputDevice;
+ mAdjustedInDev = mInputDevice;
+ }
+
+
+ // Check BT device
+ const bool bt_device_on = audio_is_bluetooth_sco_device(mAdjustedOutDev);
+ uint32_t sample_rate = 0;
+ if (mSpeechDVT_SampleRate != 0) {
+ sample_rate = mSpeechDVT_SampleRate;
+ ALOGD("%s(), SpeechDVT sample_rate = %d", __FUNCTION__, sample_rate);
+ } else {
+ sample_rate = calculateSampleRate(bt_device_on);
+ }
+
+ //close previous device
+ if (mPcmIn != NULL) {
+ pcm_stop(mPcmIn);
+ pcm_close(mPcmIn);
+ mPcmIn = NULL;
+ }
+
+ if (mPcmOut != NULL) {
+ pcm_stop(mPcmOut);
+ pcm_close(mPcmOut);
+ mPcmOut = NULL;
+
+#if defined(MTK_AUDIO_KS)
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence);
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnoffSequenceByName(mApTurnOnSequence2);
+ mApTurnOnSequence2.clear();
+ }
+#endif
+ }
+
+#if defined(MTK_USB_PHONECALL)
+ if (AudioUSBPhoneCallController::getInstance()->isEnable()) {
+ AudioUSBPhoneCallController::getInstance()->disable();
+ }
+#endif
+#if defined(MTK_AUDIO_SMARTPASCP_SUPPORT)
+ if (AudioSCPPhoneCallController::getInstance()->isEnable()) {
+ AudioSCPPhoneCallController::getInstance()->disable();
+ }
+#endif
+ if (bt_device_on) {
+ if (WCNChipController::GetInstance()->IsBTMergeInterfaceSupported() == true) {
+ //open bt sco device
+ memset(&mConfig, 0, sizeof(mConfig));
+
+ mConfig.channels = 1;
+ mConfig.rate = sample_rate;
+ mConfig.period_size = 4096;
+ mConfig.period_count = 2;
+ mConfig.format = PCM_FORMAT_S16_LE;
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+
+ ALOGE_IF(mPcmOut != NULL, "%s(), mPcmOut = %p", __FUNCTION__, mPcmOut);
+ ASSERT(mPcmOut == NULL);
+
+ if (mIdxMD == MODEM_EXTERNAL || mIdxMD == MODEM_2) {
+ PcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceMD2BT);
+ CardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVoiceMD2BT);
+ mPcmOut = pcm_open(CardIndex, PcmOutIdx, PCM_OUT, &mConfig);
+ } else {
+ PcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceMD1BT);
+ CardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVoiceMD1BT);
+ mPcmOut = pcm_open(CardIndex, PcmOutIdx, PCM_OUT, &mConfig);
+ }
+ ALOGD_IF(mPcmOut == NULL, "%s(), mPcmOut = %p, PcmOutIdx = %d, CardIndex = %d",
+ __FUNCTION__, mPcmOut, PcmOutIdx, CardIndex);
+ ASSERT(mPcmOut != NULL);
+
+ pcm_start(mPcmOut);
+ }
+#if defined(MTK_USB_PHONECALL)
+ } else if (AudioUSBPhoneCallController::getInstance()->isForceUSBCall() ||
+ mAdjustedOutDev == AUDIO_DEVICE_OUT_USB_DEVICE) {
+ AudioUSBPhoneCallController::getInstance()->enable(sample_rate);
+#endif
+#if defined(MTK_AUDIO_KS) && defined(MTK_AUDIO_SMARTPASCP_SUPPORT)
+ } else if (AudioSCPPhoneCallController::getInstance()->isSupportPhonecall(new_output_devices)) {
+ AudioSCPPhoneCallController::getInstance()->enable(sample_rate, new_input_device);
+#endif
+ } else {
+#if defined(MTK_VOICE_ULTRA)
+ if (mAdjustedOutDev == AUDIO_DEVICE_OUT_EARPIECE) {
+ PcmInIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceUltra);
+ PcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceUltra);
+ CardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVoiceUltra);
+ String8 mixer_ctl_name;
+ if (mIdxMD == MODEM_EXTERNAL || mIdxMD == MODEM_2) {
+ mixer_ctl_name = "md2";
+ } else {
+ mixer_ctl_name = "md1";
+ }
+
+ if (mixer_ctl_set_enum_by_string(mixer_get_ctl_by_name(mMixer, "Ultra_Modem_Select"),
+ mixer_ctl_name.string())) {
+ ALOGE("Error: Ultra_Modem_Select invalid value");
+ }
+
+ ALOGE_IF(mPcmIn != NULL, "%s(), mPcmIn = %p", __FUNCTION__, mPcmIn);
+ ALOGE_IF(mPcmOut != NULL, "%s(), mPcmOut = %p", __FUNCTION__, mPcmOut);
+ ASSERT(mPcmIn == NULL && mPcmOut == NULL);
+
+ // use pcm out to set memif, ultrasound, downlink
+ enum pcm_format memifFormat = PCM_FORMAT_S16_LE; // or PCM_FORMAT_S32_LE
+ unsigned int ultraRate = 96000;
+ unsigned int msPerPeriod = 10; // note: max sram is 48k
+
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = 1;
+ mConfig.rate = ultraRate;
+ mConfig.period_size = (ultraRate * msPerPeriod) / 1000;
+ mConfig.period_count = 2;
+ mConfig.format = memifFormat;
+
+ mPcmOut = pcm_open(CardIndex, PcmOutIdx, PCM_OUT, &mConfig);
+
+ // use pcm in to set modem, uplink
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = 2;
+ mConfig.rate = sample_rate; // modem rate
+ mConfig.period_size = 1024;
+ mConfig.period_count = 2;
+ mConfig.format = PCM_FORMAT_S16_LE;
+
+ mPcmIn = pcm_open(CardIndex, PcmInIdx, PCM_IN, &mConfig);
+ } else
+#endif
+ {
+ memset(&mConfig, 0, sizeof(mConfig));
+ mConfig.channels = 2;
+ mConfig.rate = sample_rate;
+ mConfig.period_size = 1024;
+ mConfig.period_count = 2;
+ mConfig.format = PCM_FORMAT_S16_LE;
+ mConfig.start_threshold = 0;
+ mConfig.stop_threshold = 0;
+ mConfig.silence_threshold = 0;
+
+#if defined(MTK_AUDIO_KS)
+ mConfig.stop_threshold = ~(0U);
+ if ((mAdjustedOutDev & AUDIO_DEVICE_OUT_SPEAKER) &&
+ AudioSmartPaController::getInstance()->isSmartPAUsed()) {
+ mApTurnOnSequence = AudioSmartPaController::getInstance()->getI2sSequence((mIdxMD == MODEM_EXTERNAL || mIdxMD == MODEM_2) ?
+ AUDIO_CTL_MD2_TO_I2S : AUDIO_CTL_MD1_TO_I2S);
+ AudioSmartPaController::getInstance()->setI2sOutHD(true);
+
+ if (popcount(mAdjustedOutDev) > 1) {
+ mApTurnOnSequence2 = (mIdxMD == MODEM_EXTERNAL || mIdxMD == MODEM_2) ?
+ AUDIO_CTL_MD2_TO_ADDA_DL : AUDIO_CTL_MD1_TO_ADDA_DL;
+ }
+ } else {
+ mApTurnOnSequence = (mIdxMD == MODEM_EXTERNAL || mIdxMD == MODEM_2) ?
+ AUDIO_CTL_MD2_TO_ADDA_DL : AUDIO_CTL_MD1_TO_ADDA_DL;
+ }
+
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence);
+ if (!mApTurnOnSequence2.isEmpty()) {
+ AudioALSADeviceConfigManager::getInstance()->ApplyDeviceTurnonSequenceByName(mApTurnOnSequence2);
+ }
+
+ PcmInIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessSpeech);
+ PcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmHostlessSpeech);
+ CardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmHostlessSpeech);
+#else
+ if (mIdxMD == MODEM_EXTERNAL || mIdxMD == MODEM_2) {
+ PcmInIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceMD2);
+ PcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceMD2);
+ CardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVoiceMD2);
+ } else {
+ PcmInIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceMD1);
+ PcmOutIdx = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmVoiceMD1);
+ CardIndex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmVoiceMD1);
+ }
+#endif
+ ALOGE_IF(mPcmIn != NULL, "%s(), mPcmIn = %p", __FUNCTION__, mPcmIn);
+ ALOGE_IF(mPcmOut != NULL, "%s(), mPcmOut = %p", __FUNCTION__, mPcmOut);
+ ASSERT(mPcmIn == NULL && mPcmOut == NULL);
+ mPcmIn = pcm_open(CardIndex, PcmInIdx, PCM_IN, &mConfig);
+
+ mConfig.channels = 2;
+ mPcmOut = pcm_open(CardIndex, PcmOutIdx, PCM_OUT, &mConfig);
+ }
+ ALOGD_IF(mPcmIn == NULL, "%s(), mPcmIn = %p, PcmInIdx = %d, CardIndex = %d",
+ __FUNCTION__, mPcmIn, PcmInIdx, CardIndex);
+ ALOGD_IF(mPcmOut == NULL, "%s(), mPcmOut = %p, PcmOutIdx = %d, CardIndex = %d",
+ __FUNCTION__, mPcmOut, PcmOutIdx, CardIndex);
+ ASSERT(mPcmIn != NULL && mPcmOut != NULL);
+
+#if !defined(MTK_AUDIO_KS)
+ pcm_start(mPcmIn);
+#endif
+ pcm_start(mPcmOut);
+
+#if defined(MTK_AUDIO_SMARTPASCP_SUPPORT)
+ if (AudioSCPPhoneCallController::getInstance()->isSupportPhonecall(new_output_devices)) {
+ AudioSCPPhoneCallController::getInstance()->enable(sample_rate, new_input_device);
+ }
+#endif
+ }
+
+ // Set new device
+ if (checkTtyNeedOn() == true) {
+ setTtyInOutDevice();
+#if !defined (MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ setTtyEnhancementMask(mTtyMode);
+#endif
+ } else {
+#if defined(MTK_USB_PHONECALL)
+ if (!AudioUSBPhoneCallController::getInstance()->isEnable())
+#endif
+ {
+ // Set PMIC digital/analog part - uplink has pop, open first
+ mHardwareResourceManager->startInputDevice(mAdjustedInDev);
+
+ // Set PMIC digital/analog part - DL need trim code.
+ mHardwareResourceManager->startOutputDevice(mAdjustedOutDev, sample_rate);
+ }
+ }
+
+#if defined(MTK_AUDIO_KS)
+ // after start input device
+ if (mPcmIn) {
+ pcm_start(mPcmIn);
+ }
+#endif
+
+ // start Side Tone Filter
+ if (checkSideToneFilterNeedOn(mAdjustedOutDev) == true) {
+ mHardwareResourceManager->EnableSideToneFilter(true);
+ mIsSidetoneEnable = true;
+ }
+
+ // Set MD side sampling rate
+ pSpeechDriver->SetModemSideSamplingRate(sample_rate);
+
+ // Set speech mode
+ if (checkTtyNeedOn() == false) {
+ pSpeechDriver->SetSpeechMode(mAdjustedInDev, mAdjustedOutDev);
+ } else {
+ pSpeechDriver->TtyCtmOn();
+ }
+
+ // Need recover mute state, trigger to wait for timeout unmute
+ muteDlUlForRouting(SPH_MUTE_CTRL_ROUTING_END);
+
+ ALOGD("%s(-), mHardwareResourceManager output_devices: 0x%x, input_device: 0x%x"
+ ", bt_device_on: %d, sample_rate: %u"
+ ", CardIndex: %d, PcmInIdx: %d, PcmOutIdx: %d, mPcmIn: %p, mPcmOut: %p",
+ __FUNCTION__,
+ mHardwareResourceManager->getOutputDevice(),
+ mHardwareResourceManager->getInputDevice(),
+ bt_device_on, sample_rate,
+ CardIndex, PcmInIdx, PcmOutIdx, mPcmIn, mPcmOut);
+
+ return NO_ERROR;
+}
+
+audio_devices_t AudioALSASpeechPhoneCallController::getAdjustedInputDevice() {
+ AL_AUTOLOCK(mLock);
+ return mAdjustedInDev;
+}
+
+audio_devices_t AudioALSASpeechPhoneCallController::getOutputDevice() {
+ AL_AUTOLOCK(mLock);
+ return mOutputDevice;
+}
+
+status_t AudioALSASpeechPhoneCallController::setTtyMode(const TtyModeType ttMode) {
+ ALOGD("+%s(), mTtyMode = %d, new tty mode = %d", __FUNCTION__, mTtyMode, ttMode);
+
+#if defined(MTK_TTY_SUPPORT)
+ SpeechDriverInterface *pSpeechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ TtyModeType preTtyMode = mTtyMode;
+ if (mTtyMode != ttMode) {
+ mTtyMode = ttMode;
+ pSpeechDriver->setTtyMode(mTtyMode);
+ }
+#if defined(MTK_RTT_SUPPORT)
+ if (mRttCallType != RTT_CALL_TYPE_CS) {
+ if ((pSpeechDriver->GetApSideModemStatus(SPEECH_STATUS_MASK) == true) &&
+ (pSpeechDriver->GetApSideModemStatus(TTY_STATUS_MASK) == true)) {
+ //force disable TTY during call
+ pSpeechDriver->SetUplinkMute(true);
+ pSpeechDriver->TtyCtmOff();
+ routing(mOutputDevice, mInputDevice);//use original devices
+ mAudioALSAVolumeController->setVoiceVolume(mAudioALSAVolumeController->getVoiceVolume(),
+ AudioALSAStreamManager::getInstance()->getModeForGain(),
+ mAdjustedOutDev);
+ pSpeechDriver->SetUplinkMute(mMicMute);
+ ALOGD("-%s(), mRttCallType =%d, mTtyMode = %d, force TTY_OFF", __FUNCTION__, mRttCallType, mTtyMode);
+ }
+ } else if ((pSpeechDriver->GetApSideModemStatus(SPEECH_STATUS_MASK) == true) &&
+ (mTtyMode != AUD_TTY_OFF) && (mTtyMode != AUD_TTY_ERR) &&
+ (pSpeechDriver->GetApSideModemStatus(TTY_STATUS_MASK) == false)) {
+ //recover TTY during call
+ pSpeechDriver->SetUplinkMute(true);
+ pSpeechDriver->TtyCtmOn();
+ routing(mOutputDevice, mInputDevice);//use original devices
+ mAudioALSAVolumeController->setVoiceVolume(mAudioALSAVolumeController->getVoiceVolume(),
+ AudioALSAStreamManager::getInstance()->getModeForGain(),
+ mAdjustedOutDev);
+ pSpeechDriver->SetUplinkMute(mMicMute);
+ ALOGD("-%s(), mRttCallType =%d, mTtyMode = %d, recover TTY from TTY_OFF",
+ __FUNCTION__, mRttCallType, mTtyMode);
+ } else
+#endif
+ {
+ if (preTtyMode != ttMode) {
+ if (pSpeechDriver->GetApSideModemStatus(VT_STATUS_MASK) == false &&
+ pSpeechDriver->GetApSideModemStatus(SPEECH_STATUS_MASK) == true) {
+ pSpeechDriver->SetUplinkMute(true);
+ if (pSpeechDriver->GetApSideModemStatus(TTY_STATUS_MASK) == true) {
+ pSpeechDriver->TtyCtmOff();
+ }
+ //"NG:mHardwareResourceManager->getOutputDevice()->HCO->off use main mic
+ routing(mOutputDevice, mInputDevice);//use original devices
+
+ if ((mTtyMode != AUD_TTY_OFF) && (mTtyMode != AUD_TTY_ERR) &&
+ (pSpeechDriver->GetApSideModemStatus(TTY_STATUS_MASK) == false)) {
+ pSpeechDriver->TtyCtmOn();
+ }
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ else {
+ mAudioALSAVolumeController->setVoiceVolume(mAudioALSAVolumeController->getVoiceVolume(),
+ AudioALSAStreamManager::getInstance()->getModeForGain(),
+ mAdjustedOutDev);
+ }
+#else
+ setTtyEnhancementMask(mTtyMode);
+#endif
+ pSpeechDriver->SetUplinkMute(mMicMute);
+ }
+ }
+ ALOGD("-%s(), mTtyMode = %d", __FUNCTION__, mTtyMode);
+ }
+#endif
+ return NO_ERROR;
+}
+
+int AudioALSASpeechPhoneCallController::setTtyInOutDevice() {
+ int gainMicTty = Normal_Mic;
+ audio_devices_t sphModeOutDev = mAdjustedOutDev;
+ ALOGV("+%s(), mTtyMode = %d", __FUNCTION__, mTtyMode);
+
+ SpeechDriverInterface *pSpeechDriver = mSpeechDriverFactory->GetSpeechDriver();
+#if defined(MTK_TTY_SUPPORT)
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ pSpeechDriver->setTtyMode(mTtyMode);
+#endif
+ mHardwareResourceManager->startOutputDevice(mAdjustedOutDev, mConfig.rate);
+ mHardwareResourceManager->startInputDevice(mAdjustedInDev);
+
+ switch (mTtyMode) {
+ case AUD_TTY_VCO:
+ if (mOutputDevice & AUDIO_DEVICE_OUT_SPEAKER) {
+ gainMicTty = Handfree_Mic;
+ sphModeOutDev = AUDIO_DEVICE_OUT_SPEAKER;
+ } else if ((mOutputDevice == AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+ (mOutputDevice == AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+ gainMicTty = Normal_Mic;
+ sphModeOutDev = AUDIO_DEVICE_OUT_EARPIECE;
+ } else {
+ gainMicTty = Normal_Mic;
+ }
+ break;
+
+ case AUD_TTY_HCO:
+ if (mOutputDevice & AUDIO_DEVICE_OUT_SPEAKER) {
+ gainMicTty = TTY_CTM_Mic;
+ sphModeOutDev = AUDIO_DEVICE_OUT_SPEAKER;
+ } else if ((mOutputDevice == AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+ (mOutputDevice == AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+ gainMicTty = TTY_CTM_Mic;
+ } else {
+ gainMicTty = Normal_Mic;
+ }
+ break;
+
+ case AUD_TTY_FULL:
+ if (mOutputDevice & AUDIO_DEVICE_OUT_SPEAKER) {
+ gainMicTty = TTY_CTM_Mic;
+ sphModeOutDev = AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ } else if ((mOutputDevice == AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+ (mOutputDevice == AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+ gainMicTty = TTY_CTM_Mic;
+ sphModeOutDev = AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ } else {
+ gainMicTty = Normal_Mic;
+ }
+ break;
+
+ default:
+ break;
+ }
+ pSpeechDriver->SetSpeechMode(mAdjustedInDev, sphModeOutDev);
+ mAudioALSAVolumeController->ApplyMicGain(gainMicTty, AudioALSAStreamManager::getInstance()->getModeForGain());
+
+#if !defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ mAudioALSAVolumeController->setVoiceVolume(mAudioALSAVolumeController->getVoiceVolume(),
+ AudioALSAStreamManager::getInstance()->getModeForGain(),
+ mAdjustedOutDev);
+#endif
+
+#endif
+ ALOGD("%s(), mTtyMode(%d), gainMicTty(%d), mAdjustedOutDev(0x%x), sphModeOutDev(0x%x)",
+ __FUNCTION__, mTtyMode, gainMicTty, mAdjustedOutDev, sphModeOutDev);
+ return NO_ERROR;
+}
+
+
+int AudioALSASpeechPhoneCallController::adjustTtyInOutDevice() {
+ bool isOutDevSpk = false;
+ ALOGV("+%s(), mOutputDevice = 0x%x, mTtyMode = %d", __FUNCTION__, mOutputDevice, mTtyMode);
+ mAdjustedOutDev = mOutputDevice;
+ mAdjustedInDev = getInputDeviceForPhoneCall(mAdjustedOutDev);
+#if defined(MTK_TTY_SUPPORT)
+ if (mOutputDevice == AUDIO_DEVICE_NONE) {
+ mAdjustedOutDev = AUDIO_DEVICE_OUT_DEFAULT;
+ mAdjustedInDev = getInputDeviceForPhoneCall(mAdjustedOutDev);
+ return NO_ERROR;
+ }
+ switch (mTtyMode) {
+ case AUD_TTY_VCO:
+ if ((isOutDevSpk = mOutputDevice & AUDIO_DEVICE_OUT_SPEAKER) ||
+ (mOutputDevice == AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+ (mOutputDevice == AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+ if (isOutDevSpk) {
+ ALOGD("%s(), speaker, TTY_VCO", __FUNCTION__);
+ } else {
+ ALOGD("%s(), headset, TTY_VCO", __FUNCTION__);
+ }
+#if defined(ENABLE_EXT_DAC) || defined(ALL_USING_VOICEBUFFER_INCALL)
+ mAdjustedOutDev = AUDIO_DEVICE_OUT_EARPIECE;
+#else
+ mAdjustedOutDev = AUDIO_DEVICE_OUT_WIRED_HEADSET;
+#endif
+ mAdjustedInDev = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+
+ case AUD_TTY_HCO:
+ if (mOutputDevice & AUDIO_DEVICE_OUT_SPEAKER) {
+ ALOGD("%s(), speaker, TTY_HCO", __FUNCTION__);
+#if defined(ENABLE_EXT_DAC) || defined(ALL_USING_VOICEBUFFER_INCALL)
+ mAdjustedOutDev = AUDIO_DEVICE_OUT_EARPIECE;
+#else
+ mAdjustedOutDev = AUDIO_DEVICE_OUT_SPEAKER;
+#endif
+ mAdjustedInDev = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ } else if ((mOutputDevice == AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+ (mOutputDevice == AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+ ALOGD("%s(), headset, TTY_HCO", __FUNCTION__);
+ mAdjustedOutDev = AUDIO_DEVICE_OUT_EARPIECE;
+ mAdjustedInDev = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ }
+ break;
+ case AUD_TTY_FULL:
+ if ((isOutDevSpk = mOutputDevice & AUDIO_DEVICE_OUT_SPEAKER) ||
+ (mOutputDevice == AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+ (mOutputDevice == AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+ if (isOutDevSpk) {
+ ALOGD("%s(), speaker, TTY_FULL", __FUNCTION__);
+ } else {
+ ALOGD("%s(), headset, TTY_FULL", __FUNCTION__);
+ }
+#if defined(ENABLE_EXT_DAC) || defined(ALL_USING_VOICEBUFFER_INCALL)
+ mAdjustedOutDev = AUDIO_DEVICE_OUT_EARPIECE;
+#else
+ mAdjustedOutDev = AUDIO_DEVICE_OUT_WIRED_HEADSET;
+#endif
+ mAdjustedInDev = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ }
+ break;
+ default:
+ break;
+ }
+#endif
+ ALOGD("%s(), mTtyMode(%d), mOutputDevice(0x%x), mAdjustedInDev(0x%x), mAdjustedOutDev(0x%x)",
+ __FUNCTION__, mTtyMode, mOutputDevice, mAdjustedInDev, mAdjustedOutDev);
+ return NO_ERROR;
+}
+
+int AudioALSASpeechPhoneCallController::setRttCallType(const int rttCallType) {
+#if defined(MTK_RTT_SUPPORT)
+ ALOGD("+%s(), mRttCallType = %d, new rttCallType = %d", __FUNCTION__, mRttCallType, rttCallType);
+ if (mRttCallType != rttCallType) {
+ SpeechDriverInterface *pSpeechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ switch (rttCallType) {
+ case RTT_CALL_TYPE_RTT:
+ mRttMode = AUD_RTT_ON;
+ mRttCallType = rttCallType;
+ setTtyMode((const TtyModeType) mTtyMode);
+ if (pSpeechDriver->GetApSideModemStatus(SPEECH_STATUS_MASK)) {
+ pSpeechDriver->RttConfig(mRttMode);
+ }
+ break;
+
+ case RTT_CALL_TYPE_CS:
+ case RTT_CALL_TYPE_PS:
+ case RTT_CALL_TYPE_CS_NO_TTY:
+ mRttMode = AUD_RTT_OFF;
+ mRttCallType = rttCallType;
+ setTtyMode((const TtyModeType) mTtyMode);
+ if (pSpeechDriver->GetApSideModemStatus(SPEECH_STATUS_MASK)) {
+ pSpeechDriver->RttConfig(mRttMode);
+ }
+ break;
+
+ default:
+ ALOGE("%s(): Invalid rttCallType(%d)", __FUNCTION__, rttCallType);
+ break;
+ }
+ }
+ ALOGD("-%s(): mRttCallType = %d, mRttMode = %d", __FUNCTION__, mRttCallType, mRttMode);
+ return NO_ERROR;
+#else
+ ALOGW("%s(), rttCallType = %d, NOT Supported!", __FUNCTION__, rttCallType);
+ return INVALID_OPERATION;
+#endif
+
+}
+
+void AudioALSASpeechPhoneCallController::setVtNeedOn(const bool vt_on) {
+ ALOGD("%s(), new vt_on = %d, old mVtNeedOn = %d", __FUNCTION__, vt_on, mVtNeedOn);
+ AL_AUTOLOCK(mLock);
+
+ mVtNeedOn = vt_on;
+}
+
+void AudioALSASpeechPhoneCallController::setMicMute(const bool mute_on) {
+ AL_AUTOLOCK(mLock);
+ AL_AUTOLOCK(mMuteDlUlForRoutingLock);
+
+ mMicMute = mute_on;
+ mSpeechDriverFactory->GetSpeechDriver()->SetUplinkMute(mute_on);
+
+ set_uint32_to_mixctrl(PROPERTY_KEY_MIC_MUTE_ON, mute_on);
+}
+
+void AudioALSASpeechPhoneCallController::setDlMute(const bool mute_on) {
+ ALOGD("%s(), mDlMute: %d => %d", __FUNCTION__, mDlMute, mute_on);
+ AL_AUTOLOCK(mLock);
+ AL_AUTOLOCK(mMuteDlUlForRoutingLock);
+
+ mDlMute = mute_on;
+ mSpeechDriverFactory->GetSpeechDriver()->SetDownlinkMute(mute_on);
+
+ set_uint32_to_mixctrl(PROPERTY_KEY_DL_MUTE_ON, mute_on);
+}
+
+void AudioALSASpeechPhoneCallController::setUlMute(const bool mute_on) {
+ ALOGD("%s(), mUlMute: %d => %d", __FUNCTION__, mUlMute, mute_on);
+ AL_AUTOLOCK(mLock);
+ AL_AUTOLOCK(mMuteDlUlForRoutingLock);
+
+ mUlMute = mute_on;
+ mSpeechDriverFactory->GetSpeechDriver()->SetUplinkSourceMute(mute_on);
+
+ set_uint32_to_mixctrl(PROPERTY_KEY_UL_MUTE_ON, mute_on);
+}
+
+void AudioALSASpeechPhoneCallController::setBTMode(const int mode) {
+ ALOGD("%s(), mBTMode: %d => %d", __FUNCTION__, mBTMode, mode);
+ AL_AUTOLOCK(mLock);
+
+ mSpeechDriverFactory->GetSpeechDriver()->setBTMode(mode);
+
+ if (mBTMode != mode) {
+ mBTMode = mode;
+
+ if (isModeInPhoneCall() &&
+ (audio_is_bluetooth_sco_device(mOutputDevice) || mIsBtSpkDevice == true)) {
+ uint32_t sample_rate = calculateSampleRate(true);
+ mSpeechDriverFactory->GetSpeechDriver()->switchBTMode(sample_rate);
+ }
+ }
+}
+
+
+void AudioALSASpeechPhoneCallController::setBtSpkDevice(const bool flag) {
+ ALOGD("%s(), mIsBtSpkDevice: %d => %d", __FUNCTION__, mIsBtSpkDevice, flag);
+
+ mIsBtSpkDevice = flag;
+ mSpeechDriverFactory->GetSpeechDriver()->setBtSpkDevice(flag);
+}
+
+
+void AudioALSASpeechPhoneCallController::getRFInfo() {
+ WARNING("Not implement yet!!");
+}
+
+
+modem_index_t AudioALSASpeechPhoneCallController::updatePhysicalModemIdx(const audio_mode_t audio_mode) {
+#if defined(MTK_COMBO_MODEM_SUPPORT)
+ (void)audio_mode;
+ return MODEM_1;
+#else
+ modem_index_t modem_index = MODEM_1;
+
+ if (mSpeechDVT_MD_IDX == 0) {
+ modem_index = mIdxMDByPhoneId[mPhoneId];
+ ALOGD("%s(), audio_mode(%d), mPhoneId(%d), modem_index=%d",
+ __FUNCTION__, audio_mode, mPhoneId, modem_index);
+ } else {
+ switch (mSpeechDVT_MD_IDX) {
+ case 1: {
+ modem_index = MODEM_1;
+ break;
+ }
+ case 2: {
+ modem_index = MODEM_EXTERNAL;
+ break;
+ }
+ default: {
+ modem_index = MODEM_1;
+ break;
+ }
+ }
+ ALOGD("%s(), SpeechDVT_MD_IDX = %d, modem_index=%d",
+ __FUNCTION__, mSpeechDVT_MD_IDX, modem_index);
+ }
+ return modem_index;
+#endif
+}
+
+int AudioALSASpeechPhoneCallController::setPhoneId(const phone_id_t phoneId) {
+#if !defined(MTK_COMBO_MODEM_SUPPORT)
+ ALOGD("+%s(), mPhoneId = %d, new phoneId = %d", __FUNCTION__, mPhoneId, phoneId);
+#endif
+ if (phoneId != mPhoneId) {
+ if (phoneId == PHONE_ID_0 || phoneId == PHONE_ID_1) {
+ mPhoneId = phoneId;
+ set_uint32_to_mixctrl(PROPERTY_KEY_FOREGROUND_PHONE_ID, mPhoneId);
+#if !defined(MTK_COMBO_MODEM_SUPPORT)
+ ALOGD("-%s(), mPhoneId = %d", __FUNCTION__, mPhoneId);
+#endif
+ } else {
+ ALOGW("-%s(), Invalid %d. return. mPhoneId = %d", __FUNCTION__, phoneId, mPhoneId);
+ }
+ }
+ return NO_ERROR;
+}
+
+/**
+ * check if Phone Call need reopen according to RIL mapped modem
+ */
+bool AudioALSASpeechPhoneCallController::checkReopen(const modem_index_t rilMappedMDIdx) {
+ AL_AUTOLOCK(mCheckOpenLock);
+ bool needReopen = false;
+ bool isSpeechOpen = mSpeechDriverFactory->GetSpeechDriver()->GetApSideModemStatus(SPEECH_STATUS_MASK);
+ modem_index_t activeMDIdx = mSpeechDriverFactory->GetActiveModemIndex();
+ if (isSpeechOpen) {
+ //check modem index
+ if (activeMDIdx != rilMappedMDIdx) {
+ needReopen = true;
+ }
+ }
+ ALOGD("%s(), needReopen(%d), MDIdx(%d->%d), isSpeechOpen(%d)",
+ __FUNCTION__, needReopen, activeMDIdx, rilMappedMDIdx, isSpeechOpen);
+ return needReopen;
+}
+
+status_t AudioALSASpeechPhoneCallController::setParam(const String8 &keyParamPairs) {
+ ALOGD("+%s(): %s", __FUNCTION__, keyParamPairs.string());
+ AudioParameter param = AudioParameter(keyParamPairs);
+ int value;
+ String8 ValueParam;
+
+ if (param.getInt(String8("AudioTaste"), value) == NO_ERROR) {
+ param.remove(String8("AudioTaste"));
+ bAudioTaste = (value == 1) ? true : false;
+
+ ALOGD("%s(): bAudioTaste = %d", __FUNCTION__, bAudioTaste);
+ } else if (param.getInt(String8("SpeechDVT_SampleRate"), value) == NO_ERROR) {
+ param.remove(String8("SpeechDVT_SampleRate"));
+ mSpeechDVT_SampleRate = value;
+
+ ALOGD("%s(): mSpeechDVT_SampleRate = %d", __FUNCTION__, mSpeechDVT_SampleRate);
+ } else if (param.getInt(String8("SpeechDVT_MD_IDX"), value) == NO_ERROR) {
+ param.remove(String8("SpeechDVT_MD_IDX"));
+ mSpeechDVT_MD_IDX = value;
+
+ ALOGD("%s(): mSpeechDVT_MD_IDX = %d", __FUNCTION__, mSpeechDVT_MD_IDX);
+ } else if (param.get(String8("Phone1Modem"), ValueParam) == NO_ERROR) {
+ param.remove(String8("Phone1Modem"));
+ if (ValueParam.string() != NULL) {
+ if (strcmp(ValueParam.string(), "MD1") == 0) {
+ mIdxMDByPhoneId[0] = MODEM_1;
+ } else if (strcmp(ValueParam.string(), "MD3") == 0) {
+ mIdxMDByPhoneId[0] = MODEM_EXTERNAL;
+ } else {
+ ALOGW("%s(), %s, Invalid MD Index. return", __FUNCTION__, ValueParam.string());
+ }
+ set_uint32_to_mixctrl(PROPERTY_KEY_PHONE1_MD, mIdxMDByPhoneId[0]);
+ }
+ } else if (param.get(String8("Phone2Modem"), ValueParam) == NO_ERROR) {
+ param.remove(String8("Phone2Modem"));
+ if (ValueParam.string() != NULL) {
+ if (strcmp(ValueParam.string(), "MD1") == 0) {
+ mIdxMDByPhoneId[1] = MODEM_1;
+ } else if (strcmp(ValueParam.string(), "MD3") == 0) {
+ mIdxMDByPhoneId[1] = MODEM_EXTERNAL;
+ } else {
+ ALOGW("%s(), %s, Invalid MD Index. return", __FUNCTION__, ValueParam.string());
+ }
+ set_uint32_to_mixctrl(PROPERTY_KEY_PHONE2_MD, mIdxMDByPhoneId[1]);
+ }
+ }
+ ALOGD("-%s(): %s", __FUNCTION__, keyParamPairs.string());
+ return NO_ERROR;
+}
+
+status_t AudioALSASpeechPhoneCallController::updateSpeechFeature(const SpeechFeatureType speechFeatureType,
+ bool enable) {
+
+#if defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+ switch (speechFeatureType) {
+ case SPEECH_FEATURE_SUPERVOLUME:
+ if (SpeechConfig::getInstance()->getSpeechParamSupport(speechFeatureType)) {//PARSE BY DRIVER
+ ALOGD("%s(), Super Volume(%d -> %d)", __FUNCTION__, mSuperVolumeEnable, enable);
+ if (mSuperVolumeEnable != enable) {
+
+#if defined(MTK_COMBO_MODEM_SUPPORT)
+ SpeechDriverInterface *pSpeechDriver = SpeechDriverFactory::GetInstance()->GetSpeechDriver();
+ pSpeechDriver->updateSpeechFeature(SPEECH_FEATURE_SUPERVOLUME, enable);
+#else
+ if (enable) {
+ SpeechParamParser::getInstance()->SetParamInfo(String8("ParamSphSV=1;"));
+ } else {
+ SpeechParamParser::getInstance()->SetParamInfo(String8("ParamSphSV=0;"));
+ }
+#endif
+ mSuperVolumeEnable = enable;
+ }
+ }
+ break;
+ default:
+ ALOGD("%s() speechFeatureType(%d) NOT Supported!", __FUNCTION__, speechFeatureType);
+ return INVALID_OPERATION;
+ }
+ return NO_ERROR;
+
+#else
+ (void)enable;
+ (void)speechFeatureType;
+ ALOGD("%s() NOT Supported!", __FUNCTION__);
+ return INVALID_OPERATION;
+#endif
+}
+
+bool AudioALSASpeechPhoneCallController::getSpeechFeatureStatus(const SpeechFeatureType speechFeatureType) {
+ bool status = false;
+ switch (speechFeatureType) {
+ case SPEECH_FEATURE_SUPERVOLUME:
+ ALOGV("%s(), mSuperVolumeEnable=%d", __FUNCTION__, mSuperVolumeEnable);
+ status = mSuperVolumeEnable;
+ break;
+ default:
+ ALOGW("%s() speechFeatureType(%d) NOT Supported!", __FUNCTION__, speechFeatureType);
+ break;
+ }
+ return status;
+}
+
+
+#if !defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+void setTtyEnhancementMask(TtyModeType ttMode) {
+ ALOGD("+%s, ttMode=%d, mOutputDevice=%d", __FUNCTION__, ttMode, mOutputDevice);
+ SpeechDriverInterface *pSpeechDriver = SpeechDriverFactory::GetInstance()->GetSpeechDriver();
+ sph_enh_mask_struct_t sphMask;
+ if (ttMode == AUD_TTY_VCO) {
+ if (mOutputDevice == AUDIO_DEVICE_OUT_SPEAKER) {
+ //handfree mic
+ sphMask.main_func = SPH_ENH_MAIN_MASK_AEC |
+ SPH_ENH_MAIN_MASK_EES |
+ SPH_ENH_MAIN_MASK_ULNR |
+ SPH_ENH_MAIN_MASK_TDNC |
+ SPH_ENH_MAIN_MASK_DMNR |
+ SPH_ENH_MAIN_MASK_AGC;
+ sphMask.dynamic_func = (SPH_ENH_DYNAMIC_MASK_ALL & (~SPH_ENH_DYNAMIC_MASK_SIDEKEY_DGAIN));
+ pSpeechDriver->SetSpeechMode(AUDIO_DEVICE_IN_DEFAULT, AUDIO_DEVICE_OUT_SPEAKER);
+ } else if ((mOutputDevice == AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+ (mOutputDevice == AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+ //handset mic
+ sphMask.main_func = SPH_ENH_MAIN_MASK_AEC |
+ SPH_ENH_MAIN_MASK_EES |
+ SPH_ENH_MAIN_MASK_ULNR |
+ SPH_ENH_MAIN_MASK_TDNC |
+ SPH_ENH_MAIN_MASK_DMNR |
+ SPH_ENH_MAIN_MASK_AGC;
+ sphMask.dynamic_func = (SPH_ENH_DYNAMIC_MASK_ALL & (~SPH_ENH_DYNAMIC_MASK_SIDEKEY_DGAIN));
+ pSpeechDriver->SetSpeechMode(AUDIO_DEVICE_IN_DEFAULT, AUDIO_DEVICE_OUT_EARPIECE);
+ }
+ } else if (ttMode == AUD_TTY_HCO) {
+ if (mOutputDevice == AUDIO_DEVICE_OUT_SPEAKER) {
+ // handfree speaker
+ sphMask.main_func = SPH_ENH_MAIN_MASK_DLNR;
+ sphMask.dynamic_func = (SPH_ENH_DYNAMIC_MASK_ALL & (~SPH_ENH_DYNAMIC_MASK_SIDEKEY_DGAIN));
+ pSpeechDriver->SetSpeechMode(AUDIO_DEVICE_IN_DEFAULT, AUDIO_DEVICE_OUT_SPEAKER);
+ } else if ((mOutputDevice == AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+ (routing_device == AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+ // handset receiver
+ sphMask.main_func = SPH_ENH_MAIN_MASK_DLNR;
+ sphMask.dynamic_func = (SPH_ENH_DYNAMIC_MASK_ALL & (~SPH_ENH_DYNAMIC_MASK_SIDEKEY_DGAIN));
+ pSpeechDriver->SetSpeechMode(AUDIO_DEVICE_IN_DEFAULT, AUDIO_DEVICE_OUT_EARPIECE);
+ }
+ } else if (ttMode == AUD_TTY_FULL) {
+ pSpeechDriver->SetSpeechEnhancement(false);
+ ALOGD("-%s, disable speech enhancement", __FUNCTION__);
+ return;
+ } else if (ttMode == AUD_TTY_OFF) {
+ pSpeechDriver->SetSpeechEnhancement(true);
+ pSpeechDriver->SetSpeechEnhancementMask(SpeechEnhancementController::GetInstance()->GetSpeechEnhancementMask());
+ ALOGD("-%s, recover all speech enhancement", __FUNCTION__);
+ return;
+ }
+
+ pSpeechDriver->SetSpeechEnhancement(true);
+ pSpeechDriver->SetSpeechEnhancementMask(sphMask);
+ ALOGD("-%s, main_func=0x%x, dynamic_func=0x%x", __FUNCTION__, sphMask.main_func, sphMask.dynamic_func);
+
+}
+#endif
+
+void *AudioALSASpeechPhoneCallController::pmicResetThread(void *arg) {
+ AudioALSASpeechPhoneCallController *call_controller = NULL;
+ AudioLock *lock = NULL;
+ struct mixer_ctl *mixerCtrl = NULL;
+
+ char thread_name[128] = {0};
+ int retvalWait = 0;
+ int retMixerCtrl = 0;
+
+ CONFIG_THREAD(thread_name, ANDROID_PRIORITY_AUDIO);
+
+ call_controller = static_cast<AudioALSASpeechPhoneCallController *>(arg);
+ if (call_controller == NULL) {
+ ALOGE("%s(), call_controller is NULL!!", __FUNCTION__);
+ goto PMIC_RESET_THREAD_DONE;
+ }
+ mixerCtrl = mixer_get_ctl_by_name(mMixer, "PMIC_REG_CLEAR");
+ if (mixerCtrl == NULL) {
+ ALOGE("%s(), mixerCtrl is NULL!!", __FUNCTION__);
+ goto PMIC_RESET_THREAD_DONE;
+ }
+
+ lock = &call_controller->mPmicResetLock;
+ AL_LOCK(lock);
+ ALOGD("%s() started, mIsPmicResetThreadEnable(%d)",
+ thread_name, call_controller->mIsPmicResetThreadEnable);
+
+ while (call_controller->mIsPmicResetThreadEnable == true) {
+ retvalWait = AL_WAIT_MS(lock, DEFAULT_WAIT_PMIC_RESET_MS);
+ if (retvalWait == -ETIMEDOUT) { //1s time out, do pmic reset
+#if defined(SPEECH_PMIC_RESET_ACC)
+ retMixerCtrl = mixer_ctl_set_enum_by_string(mixerCtrl, "ACC");
+#elif defined(SPEECH_PMIC_RESET_DCC)
+ retMixerCtrl = mixer_ctl_set_enum_by_string(mixerCtrl, "DCC");
+#endif
+ if (retMixerCtrl) {
+ ALOGE("%s(), Error: PMIC_REG_CLEAR invalid value", thread_name);
+ } else {
+ ALOGD("%s(), do PMIC_REG_CLEAR every 1sec, mIsPmicResetThreadEnable(%d)",
+ thread_name, call_controller->mIsPmicResetThreadEnable);
+ }
+ }
+ }
+ AL_UNLOCK(lock);
+
+PMIC_RESET_THREAD_DONE:
+ if (call_controller == NULL) {
+ ALOGE("%s() terminated", thread_name);
+ } else {
+ ALOGD("%s() terminated, mIsPmicResetThreadEnable(%d)",
+ thread_name, call_controller->mIsPmicResetThreadEnable);
+ }
+ pthread_exit(NULL);
+ return NULL;
+}
+
+
+void AudioALSASpeechPhoneCallController::muteDlCodecForShutterSound(const bool mute_on) {
+ ALOGD("%s(), mMuteDlCodecForShutterSoundCount: %u, do mute_on: %d",
+ __FUNCTION__, mMuteDlCodecForShutterSoundCount, mute_on);
+
+ SpeechDriverInterface *pSpeechDriver = mSpeechDriverFactory->GetSpeechDriver();
+
+ if (pSpeechDriver->GetApSideModemStatus(SPEECH_STATUS_MASK) == false &&
+ pSpeechDriver->GetApSideModemStatus(VT_STATUS_MASK) == false) {
+ ALOGW("%s(), speech off!! do nothing!!", __FUNCTION__);
+ return;
+ }
+
+ AL_LOCK(mMuteDlCodecForShutterSoundLock);
+
+ if (mute_on == true) {
+ if (mMuteDlCodecForShutterSoundCount == 0) {
+ if (mIsMuteDlCodec == false) {
+ pSpeechDriver->SetDownlinkMuteCodec(true);
+ mIsMuteDlCodec = true;
+ } else {
+ AL_SIGNAL(mMuteDlCodecForShutterSoundLock); // cancel wait & mute
+ }
+ }
+ mMuteDlCodecForShutterSoundCount++;
+ } else { // unmute
+ if (mMuteDlCodecForShutterSoundCount == 0) {
+ WARNING("BGS unmute DL Codec not in pair!!");
+ } else {
+ mMuteDlCodecForShutterSoundCount--;
+ if (mMuteDlCodecForShutterSoundCount == 0) {
+ AL_SIGNAL(mMuteDlCodecForShutterSoundLock); // notify to wait & mute
+ }
+ }
+ }
+
+ AL_UNLOCK(mMuteDlCodecForShutterSoundLock);
+
+}
+
+
+void *AudioALSASpeechPhoneCallController::muteDlCodecForShutterSoundThread(void *arg) {
+ AudioALSASpeechPhoneCallController *call_controller = NULL;
+ SpeechDriverInterface *pSpeechDriver = NULL;
+ AudioLock *lock = NULL;
+
+ char thread_name[128] = {0};
+ int retval = 0;
+
+ CONFIG_THREAD(thread_name, ANDROID_PRIORITY_AUDIO);
+
+ call_controller = static_cast<AudioALSASpeechPhoneCallController *>(arg);
+ if (call_controller == NULL) {
+ ALOGE("%s(), call_controller is NULL!!", __FUNCTION__);
+ goto MUTE_DL_CODEC_FOR_SHUTTER_SOUND_THREAD_DONE;
+ }
+
+ lock = &call_controller->mMuteDlCodecForShutterSoundLock;
+
+ AL_LOCK(lock);
+
+ while (call_controller->mMuteDlCodecForShutterSoundThreadEnable == true) {
+ // sleep until signal comes
+ AL_WAIT_NO_TIMEOUT(lock);
+
+ // debug
+ ALOGD("%s(), count: %u, mute: %d, start to wait & mute", __FUNCTION__,
+ call_controller->mMuteDlCodecForShutterSoundCount,
+ call_controller->mIsMuteDlCodec);
+
+ // wait and then unmute
+ if (call_controller->mMuteDlCodecForShutterSoundCount == 0 &&
+ call_controller->mIsMuteDlCodec == true) {
+ retval = AL_WAIT_MS(lock, DEFAULT_WAIT_SHUTTER_SOUND_UNMUTE_MS);
+ if (call_controller->mMuteDlCodecForShutterSoundCount == 0 &&
+ call_controller->mIsMuteDlCodec == true) { // double check
+ ALOGD("%s(), count: %u, mute: %d, do mute DL codec", __FUNCTION__,
+ call_controller->mMuteDlCodecForShutterSoundCount,
+ call_controller->mIsMuteDlCodec);
+ pSpeechDriver = call_controller->mSpeechDriverFactory->GetSpeechDriver();
+ pSpeechDriver->SetDownlinkMuteCodec(false);
+ call_controller->mIsMuteDlCodec = false;
+ } else {
+ ALOGD("%s(), count: %u, mute: %d, mute canceled, retval: %d", __FUNCTION__,
+ call_controller->mMuteDlCodecForShutterSoundCount,
+ call_controller->mIsMuteDlCodec, retval);
+ }
+ }
+
+ }
+
+ AL_UNLOCK(lock);
+
+MUTE_DL_CODEC_FOR_SHUTTER_SOUND_THREAD_DONE:
+ ALOGV("%s terminated", thread_name);
+ pthread_exit(NULL);
+ return NULL;
+}
+
+void AudioALSASpeechPhoneCallController::updateVolume() {
+ muteDlUlForRouting(SPH_MUTE_CTRL_VOLUME_UPDATE);
+}
+
+void AudioALSASpeechPhoneCallController::muteDlUlForRouting(const int muteCtrl) {
+ ALOGD_IF(mLogEnable, "%s(), do mute_ctrl: %d, mMuteDlUlForRoutingState: %d, routing output device = 0x%x",
+ __FUNCTION__, muteCtrl, mMuteDlUlForRoutingState, mHardwareResourceManager->getOutputDevice());
+
+ SpeechDriverInterface *pSpeechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ if (pSpeechDriver->GetApSideModemStatus(SPEECH_STATUS_MASK) == false) {
+ ALOGW("%s(), speech off!! do nothing!!", __FUNCTION__);
+ return;
+ }
+
+ AL_LOCK(mMuteDlUlForRoutingLock);
+ mMuteDlUlForRoutingCtrl = muteCtrl;
+
+ switch (mMuteDlUlForRoutingCtrl) {
+ case SPH_MUTE_CTRL_ROUTING_START:
+ if (mMuteDlUlForRoutingState != SPH_MUTE_THREAD_STATE_WAIT) {
+ pSpeechDriver = mSpeechDriverFactory->GetSpeechDriver();
+ pSpeechDriver->SetDownlinkMute(true);
+ pSpeechDriver->SetUplinkMute(true);
+ pSpeechDriver->SetUplinkSourceMute(true); // avoid hw pop
+ ALOGD_IF(mLogEnable, "%s(), mMuteDlUlForRoutingCtrl = %d, mMuteDlUlForRoutingState = %d, "
+ "do mute only",
+ __FUNCTION__, mMuteDlUlForRoutingCtrl, mMuteDlUlForRoutingState);
+ } else {
+ ALOGD_IF(mLogEnable, "%s(), mMuteDlUlForRoutingCtrl = %d, mMuteDlUlForRoutingState = %d, "
+ "do mute and stop waiting",
+ __FUNCTION__, mMuteDlUlForRoutingCtrl, mMuteDlUlForRoutingState);
+ AL_SIGNAL(mMuteDlUlForRoutingLock);
+ }
+ break;
+
+ case SPH_MUTE_CTRL_ROUTING_END:
+ ALOGD_IF(mLogEnable, "%s(), mMuteDlUlForRoutingCtrl = %d, trigger thread, routing output device = 0x%x",
+ __FUNCTION__, mMuteDlUlForRoutingCtrl, mHardwareResourceManager->getOutputDevice());
+ AL_SIGNAL(mMuteDlUlForRoutingLock); // notify to wait & mute
+ break;
+
+ case SPH_MUTE_CTRL_VOLUME_UPDATE:
+ if (mMuteDlUlForRoutingState == SPH_MUTE_THREAD_STATE_WAIT) {
+ ALOGD_IF(mLogEnable, "%s(), mMuteDlUlForRoutingCtrl = %d, mMuteDlUlForRoutingState = %d, "
+ "do unmute directly",
+ __FUNCTION__, mMuteDlUlForRoutingCtrl, mMuteDlUlForRoutingState);
+ AL_SIGNAL(mMuteDlUlForRoutingLock); // notify to mute directly
+ }
+ break;
+
+ case SPH_MUTE_CTRL_IDLE:
+ default:
+ ALOGD_IF(mLogEnable, "%s(), mMuteDlUlForRoutingCtrl = %d, mMuteDlUlForRoutingState = %d",
+ __FUNCTION__, mMuteDlUlForRoutingCtrl, mMuteDlUlForRoutingState);
+ break;
+ }
+
+ AL_UNLOCK(mMuteDlUlForRoutingLock);
+}
+
+void *AudioALSASpeechPhoneCallController::muteDlUlForRoutingThread(void *arg) {
+ AudioALSASpeechPhoneCallController *call_controller = NULL;
+ SpeechDriverInterface *pSpeechDriver = NULL;
+ AudioLock *lock = NULL;
+
+ char thread_name[128] = {0};
+ int retvalWait = 0;
+
+ CONFIG_THREAD(thread_name, ANDROID_PRIORITY_AUDIO);
+
+ call_controller = static_cast<AudioALSASpeechPhoneCallController *>(arg);
+ if (call_controller == NULL) {
+ ALOGE("%s(), call_controller is NULL!!", __FUNCTION__);
+ goto MUTE_DL_UL_FOR_ROUTING_THREAD_DONE;
+ }
+
+ lock = &call_controller->mMuteDlUlForRoutingLock;
+ call_controller->mMuteDlUlForRoutingState = SPH_MUTE_THREAD_STATE_IDLE;
+
+ AL_LOCK(lock);
+
+ while (call_controller->mMuteDlUlForRoutingThreadEnable == true) {
+ // sleep until signal comes
+ AL_WAIT_NO_TIMEOUT(lock);
+
+ // debug
+ ALOGD_IF(call_controller->mLogEnable, "%s(), Ctrl: %d, State: %d, start to wait & mute", __FUNCTION__,
+ call_controller->mMuteDlUlForRoutingCtrl,
+ call_controller->mMuteDlUlForRoutingState);
+
+ // wait and then recover to current mute status
+ if (call_controller->mMuteDlUlForRoutingCtrl == SPH_MUTE_CTRL_ROUTING_END) {
+ call_controller->mMuteDlUlForRoutingState = SPH_MUTE_THREAD_STATE_WAIT;
+ retvalWait = AL_WAIT_MS(lock, DEFAULT_WAIT_ROUTING_UNMUTE_MS);
+ call_controller->mMuteDlUlForRoutingState = SPH_MUTE_THREAD_STATE_IDLE;
+
+ if (retvalWait == -ETIMEDOUT) { //time out, do unmute
+ pSpeechDriver = call_controller->mSpeechDriverFactory->GetSpeechDriver();
+ pSpeechDriver->SetUplinkSourceMute(call_controller->mUlMute);
+ pSpeechDriver->SetUplinkMute(call_controller->mMicMute);
+ pSpeechDriver->SetDownlinkMute(call_controller->mDlMute);
+ ALOGD("%s(), Ctrl: %d, State: %d, wait retval(%d), wait %dms and unmute", __FUNCTION__,
+ call_controller->mMuteDlUlForRoutingCtrl,
+ call_controller->mMuteDlUlForRoutingState,
+ retvalWait, DEFAULT_WAIT_ROUTING_UNMUTE_MS);
+
+ } else {//disturb wait
+ if (call_controller->mMuteDlUlForRoutingCtrl == SPH_MUTE_CTRL_ROUTING_START) {
+ //break wait
+ ALOGD_IF(call_controller->mLogEnable, "%s(), Ctrl: %d, State: %d, wait retval(%d), break waiting, "
+ "keep routing mute", __FUNCTION__,
+ call_controller->mMuteDlUlForRoutingCtrl,
+ call_controller->mMuteDlUlForRoutingState, retvalWait);
+ } else if (call_controller->mMuteDlUlForRoutingCtrl == SPH_MUTE_CTRL_VOLUME_UPDATE) {
+ pSpeechDriver = call_controller->mSpeechDriverFactory->GetSpeechDriver();
+ pSpeechDriver->SetUplinkSourceMute(call_controller->mUlMute);
+ pSpeechDriver->SetUplinkMute(call_controller->mMicMute);
+ pSpeechDriver->SetDownlinkMute(call_controller->mDlMute);
+ ALOGD("%s(), Ctrl: %d, State: %d, wait retval(%d), unmute directly", __FUNCTION__,
+ call_controller->mMuteDlUlForRoutingCtrl,
+ call_controller->mMuteDlUlForRoutingState, retvalWait);
+ }
+ }
+ }
+ }
+
+ AL_UNLOCK(lock);
+
+MUTE_DL_UL_FOR_ROUTING_THREAD_DONE:
+ ALOGV("%s terminated", thread_name);
+ pthread_exit(NULL);
+ return NULL;
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechBGSPlayer.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechBGSPlayer.cpp
new file mode 100644
index 0000000..3ee351c
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechBGSPlayer.cpp
@@ -0,0 +1,596 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "BGSPlayBuffer"
+#include "SpeechBGSPlayer.h"
+#include <sys/time.h>
+#include <utils/threads.h>
+#include <audio_utils/primitives.h>
+#include "SpeechDriverInterface.h"
+#include <SpeechUtility.h>
+#include <audio_dump_path.h>
+
+#ifndef bgs_msleep
+#define bgs_msleep(ms) usleep((ms)*1000)
+#endif
+#define BGS_RETRY_TIMES 5
+//Maximum Latency between two modem data request: 200ms
+//AP sould fill data to buffer in 60ms while receiving request
+
+namespace android {
+/*==============================================================================
+ * Property keys
+ *============================================================================*/
+// property name exceed original max length PROPERTY_KEY_MAX in system/core/include/cutils/Properties.h
+// use pointer instead
+const char *PROPERTY_KEY_BGS_DUMP_ON = "persist.vendor.audiohal.bgs_dump_on";
+const char *PROPERTY_KEY_BGS_BLISRC_DUMP_ON = "persist.vendor.audiohal.bgs_blisrc_dump_on";
+const char *PROPERTY_KEY_BGS_LOG_LEVEL = "persist.vendor.audiohal.speech.bgs.log";
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+#define BGS_CHANNEL_NUM (1)
+
+// PROPERTY_KEY_BGS_DUMP_ON
+// BGSPlayer::PutDataToSpeaker()
+static char kFileNameBGS[128] = {0};
+
+// PROPERTY_KEY_BGS_BLISRC_DUMP_ON
+// BGSPlayBuffer::Write()
+// before SRC, same as AudioALSAPlaybackHandlerVoice dump
+static char kFileNameBGSBlisrc[128] = {0};
+
+static const uint32_t kMaxSizeOfFileName = 128;
+static uint32_t kSizeOfPrefixFileNameBGS = 0;
+static uint32_t kSizeOfPrefixFileNameBGSBlisrc = 0;
+
+#ifdef BGS_USE_SINE_WAVE
+static const uint16_t table_1k_tone_16000_hz[] = {
+ 0x0000, 0x30FC, 0x5A82, 0x7641,
+ 0x7FFF, 0x7641, 0x5A82, 0x30FB,
+ 0x0001, 0xCF05, 0xA57E, 0x89C0,
+ 0x8001, 0x89BF, 0xA57E, 0xCF05
+};
+static const uint32_t kSizeSinewaveTable = sizeof(table_1k_tone_16000_hz);
+#endif
+
+static uint32_t gBGSLogLevel;
+
+
+/*==============================================================================
+ * Implementation
+ *============================================================================*/
+
+bool getBGSLogEnableByLevel(const uint32_t bgs_log_level) {
+ return ((gBGSLogLevel & bgs_log_level) != 0);
+}
+
+
+BGSPlayBuffer::BGSPlayBuffer() :
+ mExitRequest(false) {
+
+ mFormat = AUDIO_FORMAT_DEFAULT;
+ mRingBuf.pBufBase = NULL;
+ mRingBuf.bufLen = 0;
+ mRingBuf.pRead = NULL;
+ mRingBuf.pWrite = NULL;
+ mRingBuf.pBufEnd = NULL;
+ mBliSrc = NULL;
+ mIsBGSBlisrcDumpEnable = false;
+ mBliOutputLinearBuffer = NULL;
+ pDumpFile = NULL;
+}
+
+bool BGSPlayBuffer::IsBGSBlisrcDumpEnable() {
+ // BGS Dump before Blisrc system property
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_BGS_BLISRC_DUMP_ON, property_value, "0"); //"0": default off
+ if (property_value[0] == '1') {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+status_t BGSPlayBuffer::InitBGSPlayBuffer(BGSPlayer *playPointer,
+ uint32_t sampleRate,
+ uint32_t chNum,
+ int32_t format) {
+ ALOGV("InitBGSPlayBuffer sampleRate=%d, ch=%d, format=%d", sampleRate, chNum, format);
+ (void)playPointer;
+ // keep the format
+ ASSERT(format == AUDIO_FORMAT_PCM_16_BIT);
+ mFormat = format;
+
+ // set internal ring buffer
+ mRingBuf.pBufBase = new char[BGS_PLAY_BUFFER_LEN];
+ mRingBuf.bufLen = BGS_PLAY_BUFFER_LEN;
+ mRingBuf.pRead = mRingBuf.pBufBase;
+ mRingBuf.pWrite = mRingBuf.pBufBase + (BGS_EXTRA_NUM_FRAME * BGS_PERIOD_SIZE);
+ memset((void *)mRingBuf.pBufBase, 0, mRingBuf.bufLen);
+
+
+ ALOGV("%s(), pBufBase: %p, pRead: 0x%x, pWrite: 0x%x, bufLen:%u", __FUNCTION__,
+ mRingBuf.pBufBase, (int)(mRingBuf.pRead - mRingBuf.pBufBase), (int)(mRingBuf.pWrite - mRingBuf.pBufBase), mRingBuf.bufLen);
+
+ sprintf(kFileNameBGS, "%s%s", LOG_PATH_AUDIO_DUMP, "BGS");
+ kSizeOfPrefixFileNameBGS = strlen(kFileNameBGS) - 1;
+ sprintf(kFileNameBGSBlisrc, "%s%s", LOG_PATH_AUDIO_DUMP, "BGS_before_Blisrc");
+ kSizeOfPrefixFileNameBGSBlisrc = strlen(kFileNameBGSBlisrc) - 1;
+
+ mIsBGSBlisrcDumpEnable = IsBGSBlisrcDumpEnable();
+ if (mIsBGSBlisrcDumpEnable) {
+ char fileNameBGSBlisrc[kMaxSizeOfFileName];
+ memset((void *)fileNameBGSBlisrc, 0, kMaxSizeOfFileName);
+
+ time_t rawtime;
+ time(&rawtime);
+ struct tm *timeinfo = localtime(&rawtime);
+ audio_strncpy(fileNameBGSBlisrc, kFileNameBGSBlisrc, kMaxSizeOfFileName);
+ strftime(fileNameBGSBlisrc + kSizeOfPrefixFileNameBGSBlisrc, kMaxSizeOfFileName - kSizeOfPrefixFileNameBGSBlisrc - 1, "_%Y_%m_%d_%H%M%S.pcm", timeinfo);
+ if (pDumpFile == NULL) {
+ AudiocheckAndCreateDirectory(fileNameBGSBlisrc);
+ pDumpFile = fopen(fileNameBGSBlisrc, "wb");
+ }
+ if (pDumpFile == NULL) {
+ ALOGW("%s(), Fail to open %s", __FUNCTION__, fileNameBGSBlisrc);
+ } else {
+ ALOGD("%s(), open %s", __FUNCTION__, fileNameBGSBlisrc);
+ }
+ }
+ // set blisrc
+ mBliSrc = newMtkAudioSrc(sampleRate, chNum, BGS_TARGET_SAMPLE_RATE, BGS_CHANNEL_NUM, SRC_IN_Q1P15_OUT_Q1P15);
+ mBliSrc->open();
+
+ ASSERT(mBliSrc != NULL);
+
+ // set blisrc converted buffer
+ mBliOutputLinearBuffer = new char[BGS_PLAY_BUFFER_LEN];
+ ALOGV("%s(), mBliOutputLinearBuffer = %p, size = %u", __FUNCTION__, mBliOutputLinearBuffer, BGS_PLAY_BUFFER_LEN);
+
+ return NO_ERROR;
+}
+
+BGSPlayBuffer::~BGSPlayBuffer() {
+ mExitRequest = true;
+
+ AL_LOCK(mBGSPlayBufferRuningMutex);
+ AL_LOCK(mBGSPlayBufferMutex);
+
+ // delete blisrc handler buffer
+ if (mBliSrc) {
+ mBliSrc->close();
+ deleteMtkAudioSrc(mBliSrc);
+ mBliSrc = NULL;
+ }
+
+ // delete blisrc converted buffer
+ delete[] mBliOutputLinearBuffer;
+
+ // delete internal ring buffer
+ delete[] mRingBuf.pBufBase;
+
+ if (pDumpFile != NULL) {
+ fclose(pDumpFile);
+ pDumpFile = NULL;
+ }
+
+ AL_SIGNAL(mBGSPlayBufferMutex);
+ AL_UNLOCK(mBGSPlayBufferMutex);
+ AL_UNLOCK(mBGSPlayBufferRuningMutex);
+}
+
+uint32_t BGSPlayBuffer::Write(char *buf, uint32_t num) {
+ // lock
+ AL_LOCK(mBGSPlayBufferRuningMutex);
+ AL_LOCK(mBGSPlayBufferMutex);
+
+ ALOGV("%s(), num = %u", __FUNCTION__, num);
+
+ if (mIsBGSBlisrcDumpEnable) {
+ if (pDumpFile != NULL) {
+ fwrite(buf, sizeof(char), num, pDumpFile);
+ }
+ }
+ uint32_t leftCount = num;
+ uint16_t dataCountInBuf = 0;
+ uint32_t tryCount = 0;
+ while (tryCount < BGS_RETRY_TIMES && !mExitRequest) { // max mLatency = 200, max sleep (20 * 10) ms here
+ // BLISRC: output buffer: buf => local buffer: mRingBuf
+ if (leftCount > 0) {
+ // get free space in ring buffer
+ uint32_t outCount = RingBuf_getFreeSpace(&mRingBuf);
+
+ // do conversion
+ ASSERT(mBliSrc != NULL);
+ uint32_t consumed = leftCount;
+ mBliSrc->process((int16_t *)buf, &leftCount, (int16_t *)mBliOutputLinearBuffer, &outCount);
+ consumed -= leftCount;
+
+ buf += consumed;
+ ALOGV("%s(), buf consumed = %u, leftCount = %u, outCount = %u",
+ __FUNCTION__, consumed, leftCount, outCount);
+
+ // copy converted data to ring buffer //TODO(Harvey): try to reduce additional one memcpy here
+ RingBuf_copyFromLinear(&mRingBuf, mBliOutputLinearBuffer, outCount);
+ if (getBGSLogEnableByLevel(BGS_LOG_LEVEL_BGS)) {
+ ALOGD("%s(), pRead: 0x%x, pWrite: 0x%x, leftCount: %u, dataCount: %u",
+ __FUNCTION__,
+ (int)(mRingBuf.pRead - mRingBuf.pBufBase),
+ (int)(mRingBuf.pWrite - mRingBuf.pBufBase),
+ leftCount,
+ RingBuf_getDataCount(&mRingBuf));
+ }
+ }
+
+ // leave while loop
+ if (leftCount <= 0) {
+ break;
+ }
+
+ // wait modem side to retrieve data
+ int retval = AL_WAIT_MS(mBGSPlayBufferMutex, 40);
+ if (!mExitRequest) {
+ dataCountInBuf = RingBuf_getDataCount(&mRingBuf);
+ }
+ if (retval != 0) {
+ ALOGV("%s(), tryCount = %u, leftCount = %u, dataCountInBuf = %u",
+ __FUNCTION__, tryCount, leftCount, dataCountInBuf);
+ tryCount++;
+ }
+
+ }
+
+ // leave warning message if need
+ if (leftCount != 0) {
+ dataCountInBuf = RingBuf_getDataCount(&mRingBuf);
+ ALOGW("%s(), still leftCount = %u, dataCountInBuf = %u", __FUNCTION__, leftCount, dataCountInBuf);
+ }
+
+ // unlock
+ AL_UNLOCK(mBGSPlayBufferMutex);
+ AL_UNLOCK(mBGSPlayBufferRuningMutex);
+
+ return num - leftCount;
+}
+
+
+bool BGSPlayBuffer::isBufferEnough(void) {
+ uint16_t dataCountInBuf = 0;
+
+ dataCountInBuf = RingBuf_getDataCount(&mRingBuf);
+ if (dataCountInBuf < (BGS_PERIOD_SIZE * BGS_EXTRA_NUM_FRAME)) {
+ return false;
+ }
+
+ return true;
+}
+
+
+
+//*****************************************************************************************
+//--------------------------for LAD Player------------------------------------------
+//*****************************************************************************************
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "BGSPlayer"
+
+BGSPlayer *BGSPlayer::mBGSPlayer = NULL;
+BGSPlayer *BGSPlayer::GetInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+
+ if (mBGSPlayer == NULL) {
+ mBGSPlayer = new BGSPlayer();
+ }
+ ASSERT(mBGSPlayer != NULL);
+ return mBGSPlayer;
+}
+
+BGSPlayer::BGSPlayer() {
+ // initial all table entry to zero, means non of them are occupied
+ mCount = 0;
+ mBufBaseTemp = new char[BGS_PLAY_BUFFER_LEN];
+ mSpeechDriver = NULL;
+ mIsBGSDumpEnable = false;
+ pDumpFile = NULL;
+ mBgsPeriodSize = 0;
+ mUnderflowCount = 0;
+}
+
+BGSPlayer::~BGSPlayer() {
+ AL_AUTOLOCK(mBGSPlayBufferVectorLock);
+
+ size_t count = mBGSPlayBufferVector.size();
+ for (size_t i = 0 ; i < count ; i++) {
+ BGSPlayBuffer *pBGSPlayBuffer = mBGSPlayBufferVector.itemAt(i);
+ delete pBGSPlayBuffer;
+ }
+ mBGSPlayBufferVector.clear();
+
+ delete[] mBufBaseTemp;
+
+ if (pDumpFile != NULL) {
+ fclose(pDumpFile);
+ pDumpFile = NULL;
+ }
+}
+
+BGSPlayBuffer *BGSPlayer::CreateBGSPlayBuffer(uint32_t sampleRate, uint32_t chNum, int32_t format) {
+ ALOGV("CreateBGSPlayBuffer sampleRate=%u, ch=%u, format=%d", sampleRate, chNum, format);
+
+ // protection
+ ASSERT(format == AUDIO_FORMAT_PCM_16_BIT);
+
+ // create BGSPlayBuffer
+ BGSPlayBuffer *pBGSPlayBuffer = new BGSPlayBuffer();
+ pBGSPlayBuffer->InitBGSPlayBuffer(this, sampleRate, chNum, format);
+
+ AL_LOCK(mBGSPlayBufferVectorLock);
+ mBGSPlayBufferVector.add(pBGSPlayBuffer);
+ AL_UNLOCK(mBGSPlayBufferVectorLock);
+
+ return pBGSPlayBuffer;
+}
+
+bool BGSPlayer::IsBGSDumpEnable() {
+ // BGS Dump system property
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_BGS_DUMP_ON, property_value, "0"); //"0": default off
+ if (property_value[0] == '1') {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+uint32_t BGSPlayer::Write(BGSPlayBuffer *pBGSPlayBuffer, void *buf, uint32_t num) {
+ ASSERT(pBGSPlayBuffer != NULL);
+ return pBGSPlayBuffer->Write((char *)buf, num);
+}
+
+void BGSPlayer::DestroyBGSPlayBuffer(BGSPlayBuffer *pBGSPlayBuffer) {
+ ASSERT(pBGSPlayBuffer != NULL);
+
+ AL_LOCK(mBGSPlayBufferVectorLock);
+ mBGSPlayBufferVector.remove(pBGSPlayBuffer);
+ AL_UNLOCK(mBGSPlayBufferVectorLock);
+
+ delete pBGSPlayBuffer;
+}
+
+bool BGSPlayer::Open(SpeechDriverInterface *pSpeechDriver, uint8_t uplink_gain, uint8_t downlink_gain) {
+ AL_AUTOLOCK(mCountLock);
+
+ if (NULL != mSpeechDriver && mSpeechDriver != pSpeechDriver) {
+ ALOGE("BGSPlayer can't support differ SpeechDriver");
+ return false;
+ }
+
+ mCount++;
+ if (1 != mCount) {
+ SLOG_ENG("%s(), already open. mCount %d", __FUNCTION__, mCount);
+ return true;
+ }
+
+ mBgsPeriodSize = BGS_PERIOD_SIZE;
+
+ mUnderflowCount = 0;
+
+ SLOG_ENG("%s(), first open, mCount %d, mBgsPeriodSize: %u",
+ __FUNCTION__, mCount, mBgsPeriodSize);
+
+ // get Speech Driver (to open/close BGS)
+ mSpeechDriver = pSpeechDriver;
+ mIsBGSDumpEnable = IsBGSDumpEnable();
+
+ gBGSLogLevel = get_uint32_from_uci(PROPERTY_KEY_BGS_LOG_LEVEL);
+
+ if (mIsBGSDumpEnable) {
+ char fileNameBGS[kMaxSizeOfFileName];
+ memset((void *)fileNameBGS, 0, kMaxSizeOfFileName);
+
+ time_t rawtime;
+ time(&rawtime);
+ struct tm *timeinfo = localtime(&rawtime);
+ audio_strncpy(fileNameBGS, kFileNameBGS, kMaxSizeOfFileName);
+ strftime(fileNameBGS + kSizeOfPrefixFileNameBGS, kMaxSizeOfFileName - kSizeOfPrefixFileNameBGS - 1, "_%Y_%m_%d_%H%M%S.pcm", timeinfo);
+ if (pDumpFile == NULL) {
+ AudiocheckAndCreateDirectory(fileNameBGS);
+ pDumpFile = fopen(fileNameBGS, "wb");
+ }
+ if (pDumpFile == NULL) {
+ ALOGW("%s(), Fail to open %s", __FUNCTION__, fileNameBGS);
+ } else {
+ ALOGD("%s(), open %s", __FUNCTION__, fileNameBGS);
+ }
+ }
+
+ //turn on background sound
+ mSpeechDriver->BGSoundOn();
+
+ //recover the UL gain
+ //backup Background Sound UL and DL gain
+ //bcs we set them to zero when normal recording
+ //we need to set it back when phone call recording
+ mSpeechDriver->BGSoundConfig(uplink_gain, downlink_gain);
+
+ return true;
+}
+
+uint32_t BGSPlayer::PutData(BGSPlayBuffer *pBGSPlayBuffer, char *target_ptr, uint16_t num_data_request) {
+ uint16_t write_count = 0;
+
+ if (pBGSPlayBuffer == NULL) {
+ ALOGW("%s(), pBGSPlayBuffer == NULL, return 0.", __FUNCTION__);
+ return 0;
+ }
+
+ AL_LOCK(pBGSPlayBuffer->mBGSPlayBufferMutex);
+
+ // check data count in pBGSPlayBuffer
+ uint16_t dataCountInBuf = RingBuf_getDataCount(&pBGSPlayBuffer->mRingBuf);
+ if (dataCountInBuf == 0) { // no data in buffer, just return 0
+ ALOGV("%s(), dataCountInBuf == 0, return 0.", __FUNCTION__);
+ AL_UNLOCK(pBGSPlayBuffer->mBGSPlayBufferMutex);
+ return 0;
+ }
+
+ write_count = (dataCountInBuf >= num_data_request) ? num_data_request : dataCountInBuf;
+
+ // copy to share buffer
+ RingBuf_copyToLinear(target_ptr, &pBGSPlayBuffer->mRingBuf, write_count);
+ if (getBGSLogEnableByLevel(BGS_LOG_LEVEL_BGS)) {
+ ALOGD("%s(), pRead: 0x%x, pWrite: 0x%x, write_count:%u, remain dataCount:%u",
+ __FUNCTION__,
+ (int)(pBGSPlayBuffer->mRingBuf.pRead - pBGSPlayBuffer->mRingBuf.pBufBase),
+ (int)(pBGSPlayBuffer->mRingBuf.pWrite - pBGSPlayBuffer->mRingBuf.pBufBase),
+ write_count,
+ RingBuf_getDataCount(&pBGSPlayBuffer->mRingBuf));
+ }
+
+ AL_SIGNAL(pBGSPlayBuffer->mBGSPlayBufferMutex);
+ AL_UNLOCK(pBGSPlayBuffer->mBGSPlayBufferMutex);
+
+ return write_count;
+}
+
+uint16_t BGSPlayer::PutDataToSpeaker(char *target_ptr, uint16_t num_data_request) {
+ uint16_t write_count = 0;
+ uint16_t numFrames = 0;
+ uint16_t needFrames = 0;
+
+
+#ifndef BGS_USE_SINE_WAVE
+ AL_AUTOLOCK(mBGSPlayBufferVectorLock);
+
+ size_t count = mBGSPlayBufferVector.size();
+
+ if (count == 0) {
+ ALOGW("%s(), mBGSPlayBufferVector == NULL, return 0.", __FUNCTION__);
+ return 0;
+ }
+
+ uint16_t dataCountInBuf, dataCountInBufMin = 65535;
+ for (size_t i = 0 ; i < count ; i++) {
+ BGSPlayBuffer *pBGSPlayBuffer = mBGSPlayBufferVector.itemAt(i);
+
+ AL_LOCK(pBGSPlayBuffer->mBGSPlayBufferMutex);
+ dataCountInBuf = RingBuf_getDataCount(&pBGSPlayBuffer->mRingBuf);
+ AL_UNLOCK(pBGSPlayBuffer->mBGSPlayBufferMutex);
+
+ if (dataCountInBuf < dataCountInBufMin) {
+ dataCountInBufMin = dataCountInBuf;
+ }
+ }
+
+ // check data count in pBGSPlayBuffer
+ if (dataCountInBufMin < mBgsPeriodSize) { // data not enough in buffer, just return 0
+ ALOGE("%s(), dataCountInBufMin: %d!! num_data_request %d, underflow!!",
+ __FUNCTION__, dataCountInBufMin, num_data_request);
+ mUnderflowCount++;
+ return 0;
+ }
+ if (num_data_request < mBgsPeriodSize) { // modem still have enough data...
+ ALOGW("%s(), dataCountInBufMin: %d, num_data_request %d, modem have enough data",
+ __FUNCTION__, dataCountInBufMin, num_data_request);
+ return 0;
+ }
+
+
+ write_count = (dataCountInBufMin >= num_data_request) ? num_data_request : dataCountInBufMin;
+
+ // align frame size
+ if (mUnderflowCount == 0) { // offer 1 frame to modem per time
+ write_count = mBgsPeriodSize;
+ } else { // underflow before!! offer underflow cnt + 1 frame to modem
+ numFrames = write_count / mBgsPeriodSize;
+ needFrames = mUnderflowCount + 1;
+ if (numFrames >= needFrames) {
+ write_count = needFrames * mBgsPeriodSize;
+ mUnderflowCount = 0;
+ } else {
+ write_count = numFrames * mBgsPeriodSize;
+ mUnderflowCount -= (numFrames - 1);
+ }
+ }
+
+ memset(target_ptr, 0, num_data_request);
+ for (size_t i = 0 ; i < count ; i++) {
+ BGSPlayBuffer *pBGSPlayBuffer = mBGSPlayBufferVector.itemAt(i);
+ if (count == 1) {
+ PutData(pBGSPlayBuffer, target_ptr, write_count);
+ continue;
+ }
+ PutData(pBGSPlayBuffer, mBufBaseTemp, write_count);
+
+ // mixer
+ int16_t *in = (int16_t *)mBufBaseTemp;
+ int16_t *out = (int16_t *)target_ptr;
+ int16_t frameCnt = write_count / BGS_CHANNEL_NUM / audio_bytes_per_sample(AUDIO_FORMAT_PCM_16_BIT);
+ for (int16_t j = 0; j < frameCnt; j++) {
+ out[j] = clamp16((int32_t)out[j] + (int32_t)in[j]);
+ }
+ }
+#else
+ static uint32_t i4Count = 0;
+ uint32_t current_count = 0, remain_count = 0;
+ char *tmp_ptr = NULL;
+
+ remain_count = write_count = num_data_request;
+ tmp_ptr = target_ptr;
+
+ if (remain_count > (kSizeSinewaveTable - i4Count)) {
+ memcpy(tmp_ptr, table_1k_tone_16000_hz + (i4Count >> 1), kSizeSinewaveTable - i4Count);
+ tmp_ptr += (kSizeSinewaveTable - i4Count);
+ remain_count -= (kSizeSinewaveTable - i4Count);
+ i4Count = 0;
+ }
+ while (remain_count > kSizeSinewaveTable) {
+ memcpy(tmp_ptr, table_1k_tone_16000_hz, kSizeSinewaveTable);
+ tmp_ptr += kSizeSinewaveTable;
+ remain_count -= kSizeSinewaveTable;
+ }
+ if (remain_count > 0) {
+ memcpy(tmp_ptr, table_1k_tone_16000_hz, remain_count);
+ i4Count = remain_count;
+ }
+#endif
+
+ if (mIsBGSDumpEnable) {
+ if (pDumpFile != NULL) {
+ fwrite(target_ptr, sizeof(char), write_count, pDumpFile);
+ }
+ }
+ return write_count;
+}
+
+
+bool BGSPlayer::Close() {
+ AL_AUTOLOCK(mCountLock);
+
+ mCount--;
+ if (0 != mCount) {
+ SLOG_ENG("%s, has other user, return. mCount %d", __FUNCTION__, mCount);
+ return true;
+ }
+
+ SLOG_ENG("%s(), mCount %d, stop", __FUNCTION__, mCount);
+
+ // tell modem side to close BGS
+ mSpeechDriver->BGSoundOff();
+ mSpeechDriver = NULL;
+
+ if (pDumpFile != NULL) {
+ fclose(pDumpFile);
+ pDumpFile = NULL;
+ }
+ return true;
+}
+
+}; // namespace android
+
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechConfig.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechConfig.cpp
new file mode 100644
index 0000000..5486a18
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechConfig.cpp
@@ -0,0 +1,518 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechConfig"
+#include <SpeechConfig.h>
+#include <utstring.h>
+#include <utils/Log.h>
+#include <inttypes.h>
+
+#include <AudioUtility.h>//Mutex/assert
+#include <audio_memory_control.h>
+
+
+namespace android {
+
+#define SPH_DUMP_STR_SIZE (500)
+#define SPH_PARAM_UNIT_DUMP_STR_SIZE (1024)
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+struct SPEECH_PARAM_SUPPORT_STRUCT {
+ bool isNetworkSupport;
+ bool isTTYSupport;
+ bool isSuperVolumeSupport;
+
+ SPEECH_PARAM_SUPPORT_STRUCT() : isNetworkSupport(0), isTTYSupport(0),
+ isSuperVolumeSupport(0) {}
+};
+
+struct SPEECH_NETWORK_STRUCT {
+ char name[128];
+ uint16_t supportBit;//4
+
+ SPEECH_NETWORK_STRUCT() : name(), supportBit(0) {}
+};
+
+struct SPEECH_ECHOREF_PARAM_STRUCT {
+ /* speech common parameters */
+ unsigned short speech_common_para[3];
+
+ SPEECH_ECHOREF_PARAM_STRUCT() : speech_common_para() {}
+};
+
+enum PARAM_PRINT_FORMAT_TYPE {
+ PARAM_PRINT_FORMAT_HEX,
+ PARAM_PRINT_FORMAT_DEC,
+ NUM_PARAM_PRINT_FORMAT
+};
+
+/*
+ * =============================================================================
+ * Singleton Pattern
+ * =============================================================================
+ */
+SpeechConfig *SpeechConfig::uniqueSpeechConfig = NULL;
+
+
+SpeechConfig *SpeechConfig::getInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+ ALOGV("%s()", __FUNCTION__);
+
+ if (uniqueSpeechConfig == NULL) {
+ uniqueSpeechConfig = new SpeechConfig();
+ }
+ ASSERT(uniqueSpeechConfig != NULL);
+ return uniqueSpeechConfig;
+}
+
+/*
+ * =============================================================================
+ * class implementation
+ * =============================================================================
+ */
+SpeechConfig::SpeechConfig() {
+ ALOGD("%s()", __FUNCTION__);
+ mAppHandle = NULL;
+ mSpeechParamVerFirst = 0;
+ mSpeechParamVerLast = 0;
+
+ mSphParamSupport = NULL;
+ mListSpeechNetwork = NULL;
+ mNameForEachSpeechNetwork = NULL;
+ AUDIO_ALLOC_STRUCT(SPEECH_PARAM_SUPPORT_STRUCT, mSphParamSupport);
+ AUDIO_ALLOC_STRUCT_ARRAY(SPEECH_NETWORK_STRUCT, 12, mListSpeechNetwork);
+ AUDIO_ALLOC_STRUCT_ARRAY(SPEECH_NETWORK_STRUCT, 12, mNameForEachSpeechNetwork);
+
+ init();
+}
+
+SpeechConfig::~SpeechConfig() {
+ ALOGD("%s()", __FUNCTION__);
+ AUDIO_FREE_POINTER(mNameForEachSpeechNetwork);
+ AUDIO_FREE_POINTER(mListSpeechNetwork);
+ AUDIO_FREE_POINTER(mSphParamSupport);
+
+}
+
+void SpeechConfig::init() {
+ ALOGD("%s()", __FUNCTION__);
+ initAppParser();
+ initSpeechNetwork();
+ initFeatureSupport();
+
+}
+
+void SpeechConfig::initFeatureSupport() {
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ } else {
+ const char *strSphVersion = appOps->appHandleGetFeatureOptionValue(mAppHandle, "SPH_PARAM_VERSION");
+ if (strSphVersion != NULL) {
+ sscanf(strSphVersion, "%" SCNd8 ".%" SCNd8, &mSpeechParamVerFirst, &mSpeechParamVerLast);
+ switch (mSpeechParamVerFirst) {
+ case 2:
+ mSphParamSupport->isNetworkSupport = true;
+ break;
+ case 1:
+ mSphParamSupport->isNetworkSupport = true;
+ break;
+ default:
+ mSphParamSupport->isNetworkSupport = false;
+ break;
+ }
+ } else {
+ mSpeechParamVerFirst = 0;
+ mSpeechParamVerLast = 0;
+ mSphParamSupport->isNetworkSupport = false;
+ }
+
+ const char *strSphSV = appOps->appHandleGetFeatureOptionValue(mAppHandle, "SPH_PARAM_SV");
+ if (strSphSV != NULL) {
+ if (strcmp(strSphSV, "yes") == 0) {
+ mSphParamSupport->isSuperVolumeSupport = true;
+ } else {
+ mSphParamSupport->isSuperVolumeSupport = false;
+ }
+ } else {
+ mSphParamSupport->isSuperVolumeSupport = false;
+ }
+ }
+ ALOGD("%s(), SPH_PARAM_VERSION(%x.%x), Network(%d), SuperVolume(%d)",
+ __FUNCTION__, mSpeechParamVerFirst, mSpeechParamVerLast,
+ mSphParamSupport->isNetworkSupport,
+ mSphParamSupport->isSuperVolumeSupport);
+}
+
+
+/*==============================================================================
+ * SpeechConfig Imeplementation
+ *============================================================================*/
+bool SpeechConfig::getSpeechParamSupport(const SpeechFeatureType featureType) {
+ bool isSupport = false;
+ switch (featureType) {
+ case SPEECH_FEATURE_SUPERVOLUME:
+ isSupport = mSphParamSupport->isSuperVolumeSupport;
+ break;
+ default:
+ ALOGD("%s() SpeechFeatureType(%d) NOT Supported!", __FUNCTION__, featureType);
+ }
+ return isSupport;
+}
+
+void SpeechConfig::initAppParser() {
+ /* Init AppHandle */
+ ALOGD("+%s() appHandleGetInstance", __FUNCTION__);
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return;
+ }
+ mAppHandle = appOps->appHandleGetInstance();
+ ALOGD("-%s() appHandleRegXmlChangedCb", __FUNCTION__);
+
+}
+
+int SpeechConfig::initSpeechNetwork() {
+
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL || mAppHandle == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return -ENODEV;
+ } else {
+
+ /* Query AudioType */
+ AudioType *audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, "SpeechNetwork");
+
+ //-----------
+ //parse layer
+ CategoryType *categoryNetwork = appOps->audioTypeGetCategoryTypeByName(audioType, "Network");
+ mNumSpeechNetwork = appOps->categoryTypeGetNumOfCategory(categoryNetwork);
+
+ //for speech param dump
+ char *bufParamDump = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(bufParamDump, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+ snprintf(bufParamDump, SPH_DUMP_STR_SIZE, "xml(%s),", "SpeechNetwork");
+
+ /* Query the ParamUnit */
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+ //parse network
+ for (int idxNetwork = 0; idxNetwork < mNumSpeechNetwork; idxNetwork++) {
+ Category *CateNetwork = appOps->categoryTypeGetCategoryByIndex(categoryNetwork, idxNetwork);
+ audio_strncpy(mListSpeechNetwork[idxNetwork].name, CateNetwork->name, 128);
+ String8 categoryPath("Network,");
+ categoryPath += CateNetwork->name;
+
+ ParamUnit *paramUnit = appOps->audioTypeGetParamUnit(audioType, categoryPath.string());
+ if (!paramUnit) {
+ appOps->audioTypeUnlock(audioType);
+ ALOGE("%s() can't find paramUnit, Assert!!! audioType=%s, categoryPath=%s",
+ __FUNCTION__, audioType->name, categoryPath.string());
+ if (bufParamDump != NULL) {
+ delete[] bufParamDump;
+ }
+ ASSERT(0);
+ return 0;
+ }
+
+ Param *param = appOps->paramUnitGetParamByName(paramUnit, "speech_network_support");
+ ASSERT(param);
+
+ mListSpeechNetwork[idxNetwork].supportBit = *(uint16_t *)param->data;
+
+ char dumpByNetworkName[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(dumpByNetworkName, SPH_DUMP_STR_SIZE, " %s=0x%x,", mListSpeechNetwork[idxNetwork].name,
+ mListSpeechNetwork[idxNetwork].supportBit);
+ audio_strncat(bufParamDump, dumpByNetworkName, SPH_DUMP_STR_SIZE);
+ }
+ appOps->audioTypeUnlock(audioType);
+ //--------------------------------------------------------------------------------
+ if (bufParamDump != NULL) {
+ if (bufParamDump[0] != 0) {
+ ALOGD("%s(), %s", __FUNCTION__, bufParamDump);
+ }
+ memset(bufParamDump, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+ }
+
+ //init the Name mapping table for each SpeechNetwork
+ bool isNetworkFound = false;
+ for (int bitIndex = 0; bitIndex < 12; bitIndex++) {
+ isNetworkFound = false;
+ for (int idxNetwork = 0; idxNetwork < mNumSpeechNetwork; idxNetwork++) {
+ if (((mListSpeechNetwork[idxNetwork].supportBit >> bitIndex) & 1) == 1) {
+ audio_strncpy(mNameForEachSpeechNetwork[bitIndex].name, mListSpeechNetwork[idxNetwork].name, 128);
+ isNetworkFound = true;
+ break;
+ }
+ }
+ if (!isNetworkFound) {
+ audio_strncpy(mNameForEachSpeechNetwork[bitIndex].name, mListSpeechNetwork[0].name, 128);
+ }
+ char dumpByNetworkBit[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(dumpByNetworkBit, SPH_DUMP_STR_SIZE, "[%d]=%s,", bitIndex,
+ mNameForEachSpeechNetwork[bitIndex].name);
+ audio_strncat(bufParamDump, dumpByNetworkBit, SPH_DUMP_STR_SIZE);
+ }
+ if (bufParamDump != NULL) {
+ if (bufParamDump[0] != 0) {
+ ALOGD("%s(), Bit%s", __FUNCTION__, bufParamDump);
+ }
+ delete[] bufParamDump;
+ }
+ }
+ return 0;
+
+}
+
+char *SpeechConfig::getNameForEachSpeechNetwork(unsigned char bitIndex) {
+ ALOGD("%s(), mNameForEachSpeechNetwork[%d].name = %s",
+ __FUNCTION__, bitIndex, mNameForEachSpeechNetwork[bitIndex].name);
+ return mNameForEachSpeechNetwork[bitIndex].name;
+}
+
+int SpeechConfig::getBtDelayTime(const char *btDeviceName) {
+ int btDelayMs = 0;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL || btDeviceName == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return -ENODEV;
+ } else {
+ /* Get the BT device delay parameter */
+ AudioType *audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, "BtInfo");
+ if (audioType) {
+ String8 categoryPath("BT headset,");
+ categoryPath += btDeviceName;
+
+ ParamUnit *paramUnit = appOps->audioTypeGetParamUnit(audioType, categoryPath.string());
+ ASSERT(paramUnit);
+
+ Param *param = appOps->paramUnitGetParamByName(paramUnit, "voice_cp_delay_ms");
+ ASSERT(param);
+
+ btDelayMs = *(int *)param->data;
+ }
+ ALOGD("%s(), btDeviceName=%s, btDelayMs=%d", __FUNCTION__, btDeviceName, btDelayMs);
+ return btDelayMs;
+ }
+}
+
+
+int SpeechConfig::getEchoRefParam(uint8_t *usbDelayMs) {
+ uint16_t sizeByteParam = 0, numDevice, size = 0;
+ char paramBuf[32] = {0};
+
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL || mAppHandle == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return -ENODEV;
+ } else {
+ /* Query AudioType */
+ AudioType *audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, "SpeechEchoRef");
+ CategoryType *categoryDevice = appOps->audioTypeGetCategoryTypeByName(audioType, "Device");
+ numDevice = appOps->categoryTypeGetNumOfCategory(categoryDevice);
+
+ /* Query the ParamUnit */
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+ //parse network
+ for (int idxDevice = 0; idxDevice < numDevice; idxDevice++) {
+ Category *cateDevice = appOps->categoryTypeGetCategoryByIndex(categoryDevice, idxDevice);
+ String8 categoryPath("Device,");
+ categoryPath += cateDevice->name;
+
+ ParamUnit *paramUnit = appOps->audioTypeGetParamUnit(audioType, categoryPath.string());
+ if (!paramUnit) {
+ appOps->audioTypeUnlock(audioType);
+ ALOGE("%s() can't find paramUnit, Assert!!! audioType=%s, categoryPath=%s",
+ __FUNCTION__, audioType->name, categoryPath.string());
+ ASSERT(0);
+ return 0;
+ }
+
+ Param *param = appOps->paramUnitGetParamByName(paramUnit, "EchoRef_para");
+ ASSERT(param);
+
+ appOps->audioTypeUnlock(audioType);
+
+ sizeByteParam = sizeByteParaData((DATA_TYPE)param->paramInfo->dataType, param->arraySize);
+ memcpy(paramBuf + size, param->data, sizeByteParam);
+ size += sizeByteParam;
+
+ }
+ ALOGD("%s(), xml(%s), total size(b)=%d", __FUNCTION__, "SpeechEchoRef", size);
+ SPEECH_ECHOREF_PARAM_STRUCT *echoRefParam = NULL;
+ echoRefParam = (SPEECH_ECHOREF_PARAM_STRUCT *)paramBuf;
+ ALOGV("%s(), %d, 0x%x, %d", __FUNCTION__,
+ echoRefParam->speech_common_para[0],
+ echoRefParam->speech_common_para[1],
+ echoRefParam->speech_common_para[2]);
+
+ *usbDelayMs = echoRefParam->speech_common_para[1] & 0xFF;
+
+ }
+ return 0;
+
+}
+
+
+int SpeechConfig::getDriverParam(uint8_t paramType, void *paramBuf) {
+ uint16_t sizeByteParam = 0, size = 0;
+ const char *paramName[] = {
+ "speech_common_para",
+ "debug_info"
+ };
+
+ if (paramType >= NUM_DRIVER_PARAM) {
+ ALOGE("%s(), invalid paramType(%d)!!!", __FUNCTION__, paramType);
+ return -EINVAL;
+ }
+
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL || mAppHandle == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return -ENODEV;
+ } else {
+ /* Query AudioType */
+ AudioType *audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, "SpeechGeneral");
+ CategoryType *categoryDevice = appOps->audioTypeGetCategoryTypeByName(audioType, "CategoryLayer");
+
+ /* Query the ParamUnit */
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+ String8 categoryPath("CategoryLayer,Common");
+
+ ParamUnit *paramUnit = appOps->audioTypeGetParamUnit(audioType, categoryPath.string());
+ if (!paramUnit) {
+ appOps->audioTypeUnlock(audioType);
+ ALOGE("%s() can't find paramUnit, Assert!!! audioType=%s, categoryPath=%s",
+ __FUNCTION__, audioType->name, categoryPath.string());
+ ASSERT(0);
+ return 0;
+ }
+ //for speech param dump
+ char *bufParamDump = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(bufParamDump, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+ snprintf(bufParamDump, SPH_DUMP_STR_SIZE, "xml(%s),(path=%s,id=%d):", "SpeechGeneral",
+ categoryPath.string(), paramUnit->paramId);
+ //--------------------------------------------------------------------------------
+ Param *param = appOps->paramUnitGetParamByName(paramUnit, paramName[paramType]);
+ ASSERT(param);
+ sizeByteParam = sizeByteParaData((DATA_TYPE)param->paramInfo->dataType, param->arraySize);
+ memcpy(paramBuf, param->data, sizeByteParam);
+ size += sizeByteParam;
+ speechDataDump(bufParamDump, "SpeechGeneral", param);
+ appOps->audioTypeUnlock(audioType);
+ //--------------------------------------------------------------------------------
+ if (bufParamDump != NULL) {
+ if (bufParamDump[0] != 0) {
+ ALOGD("%s(),%s total size(b)=%d", __FUNCTION__, bufParamDump, size);
+ }
+ delete[] bufParamDump;
+ }
+ }
+ return 0;
+}
+
+
+int SpeechConfig::speechDataDump(char *dumpBuf,
+ const char *nameXml,
+ const Param *param) {
+ if (dumpBuf == NULL) {
+ ALOGE("%s(), dumpBuf is NULL!!!", __FUNCTION__);
+ return -ENOMEM;
+ }
+ if (nameXml == NULL) {
+ ALOGE("%s(), name of Xml is NULL!!!", __FUNCTION__);
+ return -EINVAL;
+ }
+ if (nameXml == NULL) {
+ ALOGE("%s(), xml(%s), name of param is NULL!!!", __FUNCTION__, param->name);
+ return -EINVAL;
+ }
+
+ char sphDumpStr[SPH_DUMP_STR_SIZE] = {0};
+ int idxDump = 0, sizeUShortDump = 0, sizeByteParam = 0, printFormat = PARAM_PRINT_FORMAT_DEC;
+ //speech parameter dump
+ if (strcmp(nameXml, "SpeechGeneral") == 0) {
+ sizeByteParam = sizeByteParaData((DATA_TYPE)param->paramInfo->dataType, param->arraySize);
+ sizeUShortDump = sizeByteParam>>1;
+ } else if (strcmp(nameXml, "SpeechEchoRef") == 0) {
+ if (strcmp(param->name, "EchoRef_para") == 0) {
+ sizeUShortDump = 3;
+ }
+ }
+
+ snprintf(sphDumpStr, SPH_DUMP_STR_SIZE, "%s[%d]=", param->name, sizeUShortDump);
+
+ for (idxDump = 0; idxDump < sizeUShortDump; idxDump++) {
+ char sphDumpTemp[100] = {0};
+ if (printFormat == PARAM_PRINT_FORMAT_DEC) {
+ snprintf(sphDumpTemp, 100, "[%d]%d,", idxDump, *((uint16_t *)param->data + idxDump));
+// } else {
+// snprintf(sphDumpTemp, 100, "[%d]0x%x,", idxDump, *((uint16_t *)param->data + idxDump));
+ }
+ audio_strncat(sphDumpStr, sphDumpTemp, SPH_DUMP_STR_SIZE);
+ }
+
+ if (idxDump != 0) {
+ audio_strncat(dumpBuf, sphDumpStr, SPH_DUMP_STR_SIZE);
+ }
+ return NO_ERROR;
+}
+
+
+uint16_t SpeechConfig::sizeByteParaData(uint16_t dataType, uint16_t arraySize) {
+ uint16_t sizeUnit = 4;
+ switch (dataType) {
+ case TYPE_INT:
+ sizeUnit = 4;
+ break;
+ case TYPE_UINT:
+ sizeUnit = 4;
+ break;
+ case TYPE_FLOAT:
+ sizeUnit = 4;
+ break;
+ case TYPE_BYTE_ARRAY:
+ sizeUnit = arraySize;
+ break;
+ case TYPE_UBYTE_ARRAY:
+ sizeUnit = arraySize;
+ break;
+ case TYPE_SHORT_ARRAY:
+ sizeUnit = arraySize << 1;
+ break;
+ case TYPE_USHORT_ARRAY:
+ sizeUnit = arraySize << 1;
+ break;
+ case TYPE_INT_ARRAY:
+ sizeUnit = arraySize << 2;
+ break;
+ case TYPE_UINT_ARRAY:
+ sizeUnit = arraySize << 2;
+ break;
+ default:
+ ALOGE("%s(), Not an available dataType(%d)", __FUNCTION__, dataType);
+ break;
+
+ }
+
+ ALOGV("%s(), arraySize=%d, sizeUnit=%d", __FUNCTION__, arraySize, sizeUnit);
+
+ return sizeUnit;
+
+
+}
+
+}
+
+//namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechDataEncrypter.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechDataEncrypter.cpp
new file mode 100644
index 0000000..abba109
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechDataEncrypter.cpp
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechDataEncrypter"
+#include <unistd.h>
+#include <sys/time.h>
+#include <string.h>
+#include "SpeechType.h"
+#include "SpeechDriverFactory.h"
+
+#include "SpeechDataEncrypter.h"
+
+/*****************************************************************************
+* MACRO
+******************************************************************************
+*/
+
+//#define FORCE_ENABLE_ENCRYPT
+//#define FORCE_ENABLE_DUMP
+//#define DELAY_SIMULATION
+
+//#define DUMP_PRE_ENCRYPT
+//#define DUMP_POST_ENCRYPT
+//#define DUMP_PRE_DECRYPT
+//#define DUMP_POST_DECRYPT
+
+/*****************************************************************************
+* C O N S T A N T S
+******************************************************************************
+*/
+static const char kPrefixOfFileName[] = "/data/vendor/audiohal/audio_dump/SpeechData";
+static const uint32_t kSizeOfPrefixOfFileName = sizeof(kPrefixOfFileName) - 1;
+static const uint32_t kMaxSizeOfFileName = 128;
+
+/*==============================================================================
+ * Property keys
+ *============================================================================*/
+const char* PROPERTY_KEY_SDE_DUMP_ON = "persist.vendor.audiohal.sph_enc_dump_on";
+const char* PROPERTY_KEY_SDE_DELAY = "persist.vendor.audiohal.sph_enc_delay";
+
+namespace android {
+
+/***********************************************************
+*
+* SpeechDataEncrypter Interface
+*
+***********************************************************/
+SpeechDataEncrypter *SpeechDataEncrypter::mSpeechDataEncrypter = NULL;
+SpeechDataEncrypter *SpeechDataEncrypter::GetInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+
+ if (mSpeechDataEncrypter == NULL) {
+ mSpeechDataEncrypter = new SpeechDataEncrypter();
+ }
+ ASSERT(mSpeechDataEncrypter != NULL);
+ return mSpeechDataEncrypter;
+}
+
+SpeechDataEncrypter::SpeechDataEncrypter() {
+ mEnabled = false;
+ mDumpEnabled = false;
+ mStarted = false;
+ pPreEncDumpFile = NULL;
+ pPostEncDumpFile = NULL;
+ pPreDecDumpFile = NULL;
+ pPostDecDumpFile = NULL;
+ mAudioCustEncryptClient = NULL;
+ mAudioCustEncryptClient = AudioCustEncryptClient::GetInstance();
+ mLogEnable = 0;
+
+ ALOGD("+%s() mAudioCustEncryptClient->Initial()", __FUNCTION__);
+
+ mAudioCustEncryptClient->Initial();
+
+ ALOGD("-%s() mAudioCustEncryptClient->Initial()", __FUNCTION__);
+}
+
+SpeechDataEncrypter::~SpeechDataEncrypter() {
+ Stop();
+ mAudioCustEncryptClient = NULL;
+}
+
+int SpeechDataEncrypter::Start() {
+ ALOGD("%s()", __FUNCTION__);
+ mLogEnable = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);
+
+ if (mStarted) {
+ ALOGW("%s() is already started", __FUNCTION__);
+
+ } else {
+ AL_LOCK(mMutexDL);
+
+ if (mDumpEnabled) {
+ char dump_file_path_enc_pre[kMaxSizeOfFileName];
+ char dump_file_path_enc_post[kMaxSizeOfFileName];
+ char dump_file_path_dec_pre[kMaxSizeOfFileName];
+ char dump_file_path_dec_post[kMaxSizeOfFileName];
+ memset((void *)dump_file_path_enc_pre, 0, kMaxSizeOfFileName);
+ memset((void *)dump_file_path_enc_post, 0, kMaxSizeOfFileName);
+ memset((void *)dump_file_path_dec_pre, 0, kMaxSizeOfFileName);
+ memset((void *)dump_file_path_dec_post, 0, kMaxSizeOfFileName);
+ time_t rawtime;
+ time(&rawtime);
+ struct tm *timeinfo = localtime(&rawtime);
+ strftime(dump_file_path_enc_pre, kMaxSizeOfFileName, "/data/vendor/audiohal/audio_dump/%Y_%m_%d_%H%M%S_EncPre.dump", timeinfo);
+ strftime(dump_file_path_enc_post, kMaxSizeOfFileName, "/data/vendor/audiohal/audio_dump/%Y_%m_%d_%H%M%S_EncPost.dump", timeinfo);
+ strftime(dump_file_path_dec_pre, kMaxSizeOfFileName, "/data/vendor/audiohal/audio_dump/%Y_%m_%d_%H%M%S_DecPre.dump", timeinfo);
+ strftime(dump_file_path_dec_post, kMaxSizeOfFileName, "/data/vendor/audiohal/audio_dump/%Y_%m_%d_%H%M%S_DecPost.dump", timeinfo);
+#ifdef DUMP_PRE_ENCRYPT
+ if (pPreEncDumpFile == NULL) {
+ AudiocheckAndCreateDirectory(dump_file_path_enc_pre);
+ pPreEncDumpFile = fopen(dump_file_path_enc_pre, "wb");
+ }
+ if (pPreEncDumpFile == NULL) {
+ ALOGW("%s() Fail to Open \"%s\"", __FUNCTION__, dump_file_path_enc_pre);
+ } else {
+ ALOGD("%s(), Open: \"%s\"", __FUNCTION__, dump_file_path_enc_pre);
+ }
+#endif
+#ifdef DUMP_POST_ENCRYPT
+ if (pPostEncDumpFile == NULL) {
+ AudiocheckAndCreateDirectory(dump_file_path_enc_post);
+ pPostEncDumpFile = fopen(dump_file_path_enc_post, "wb");
+ }
+ if (pPostEncDumpFile == NULL) {
+ ALOGW("%s() Fail to Open \"%s\"", __FUNCTION__, dump_file_path_enc_post);
+ } else {
+ ALOGD("%s(), Open \"%s\"", __FUNCTION__, dump_file_path_enc_post);
+ }
+
+#endif
+#ifdef DUMP_PRE_DECRYPT
+ if (pPreDecDumpFile == NULL) {
+ AudiocheckAndCreateDirectory(dump_file_path_dec_pre);
+ pPreDecDumpFile = fopen(dump_file_path_dec_pre, "wb");
+ }
+ if (pPreDecDumpFile == NULL) {
+ ALOGW("%s() Fail to Open \"%s\"", __FUNCTION__, dump_file_path_dec_pre);
+ } else {
+ ALOGD("%s(), Open: \"%s\"", __FUNCTION__, dump_file_path_dec_pre);
+ }
+#endif
+#ifdef DUMP_POST_DECRYPT
+ if (pPostDecDumpFile == NULL) {
+ AudiocheckAndCreateDirectory(dump_file_path_dec_post);
+ pPostDecDumpFile = fopen(dump_file_path_dec_post, "wb");
+ }
+ if (pPostDecDumpFile == NULL) {
+ ALOGW("%s() Fail to Open \"%s\"", __FUNCTION__, dump_file_path_dec_post);
+ } else {
+ ALOGD("%s(), Open: \"%s\"", __FUNCTION__, dump_file_path_dec_post);
+ }
+#endif
+
+ }
+ AL_UNLOCK(mMutexDL);
+ mStarted = true;
+ SpeechDriverFactory::GetInstance()->GetSpeechDriver()->SetEncryption(true);
+ }
+ return true;
+}
+
+int SpeechDataEncrypter::Stop() {
+ ALOGD("%s()", __FUNCTION__);
+ if (!mStarted) {
+ ALOGW("%s() is already stopped", __FUNCTION__);
+ } else {
+ AL_LOCK(mMutexDL);
+
+ mStarted = false;
+
+
+ if (mDumpEnabled) {
+#ifdef DUMP_PRE_ENCRYPT
+ if (pPreEncDumpFile != NULL) {
+ fclose(pPreEncDumpFile);
+ } else {
+ ALOGW("%s(), pPreEncDumpFile == NULL!!!!!", __FUNCTION__);
+ }
+#endif
+#ifdef DUMP_POST_ENCRYPT
+ if (pPostEncDumpFile != NULL) {
+ fclose(pPostEncDumpFile);
+ } else {
+ ALOGW("%s(), pPostEncDumpFile == NULL!!!!!", __FUNCTION__);
+ }
+#endif
+#ifdef DUMP_PRE_DECRYPT
+ if (pPreDecDumpFile != NULL) {
+ fclose(pPreDecDumpFile);
+ } else {
+ ALOGW("%s(), pPreDecDumpFile == NULL!!!!!", __FUNCTION__);
+ }
+#endif
+#ifdef DUMP_POST_DECRYPT
+ if (pPostDecDumpFile != NULL) {
+ fclose(pPostDecDumpFile);
+ } else {
+ ALOGW("%s(), pPostDecDumpFile == NULL!!!!!", __FUNCTION__);
+ }
+#endif
+ }
+ AL_UNLOCK(mMutexDL);
+ }
+ return true;
+}
+
+void SpeechDataEncrypter::SetEnableStatus(bool bEnable) {
+ if (mEnabled != bEnable) {
+ ALOGD("%s(), ori mEnabled=%d, set value=%d", __FUNCTION__, mEnabled, bEnable);
+ SpeechDriverFactory *pSpeechDriverFactory = SpeechDriverFactory::GetInstance();
+ SpeechDriverInterface *pSpeechDriver = NULL;
+ mEnabled = bEnable;
+ for (int modem_index = MODEM_1; modem_index < NUM_MODEM; modem_index++) {
+ pSpeechDriver = pSpeechDriverFactory->GetSpeechDriverByIndex((modem_index_t)modem_index);
+ if (pSpeechDriver != NULL) { // Might be single talk and some speech driver is NULL
+ pSpeechDriver->SetEncryption(mEnabled);
+ }
+ }
+ } else {
+ ALOGW("%s(), mEnabled == bEnable(%d) return.", __FUNCTION__, bEnable);
+ }
+}
+
+bool SpeechDataEncrypter::GetEnableStatus() {
+#ifdef FORCE_ENABLE_ENCRYPT
+ ALOGD("%s(), Force enable", __FUNCTION__);
+ return true;
+#else
+ ALOGD("%s(), mEnabled=%d", __FUNCTION__, mEnabled);
+ return mEnabled;
+#endif
+}
+
+bool SpeechDataEncrypter::GetStartStatus() {
+ ALOGD("-%s(), mStarted=%d", __FUNCTION__, mStarted);
+ return mStarted;
+}
+
+bool SpeechDataEncrypter::GetDumpStatus() {
+#if defined(FORCE_ENABLE_DUMP)
+ mDumpEnabled = true;
+#else
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_SDE_DUMP_ON, property_value, "0"); //"0": default off
+ mDumpEnabled = (property_value[0] == '0') ? false : true;
+#endif
+ ALOGD("-%s(), mDumpEnabled=%d", __FUNCTION__, mDumpEnabled);
+ return mDumpEnabled;
+}
+
+int SpeechDataEncrypter::GetDelay() {
+#ifdef DELAY_SIMULATION
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_SDE_DELAY, property_value, "0"); //"0": default off
+ int DelayMS = atoi(property_value);
+ ALOGD("%s(), DelayMS=%d", __FUNCTION__, DelayMS);
+ return DelayMS;
+#else
+ return 0;
+#endif
+}
+
+uint16_t SpeechDataEncrypter::Encryption(char *TargetBuf, char *SourceBuf, const uint16_t SourceByte) {
+ uint16_t TargetByte = 0;
+
+ ALOGD("+%s(), SourceByte= %d", __FUNCTION__, SourceByte);
+ struct timespec entertime;
+ struct timespec leavetime;
+ unsigned long long timediffns = 0;
+ entertime = GetSystemTime();
+ AL_LOCK(mMutexUL);
+
+ ALOGD_IF(mLogEnable, "+%s(), SourceByte= %d, SourceBuf[0] = 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x", __FUNCTION__, SourceByte, *SourceBuf, *(SourceBuf + 1), *(SourceBuf + 2), *(SourceBuf + 3), *(SourceBuf + 4), *(SourceBuf + 5), *(SourceBuf + 6), *(SourceBuf + 7));
+ //do encrypt
+ TargetByte = AudioCustEncryptClient::GetInstance()->EncryptProcess(TargetBuf, SourceBuf, SourceByte);
+ ALOGD_IF(mLogEnable, "-%s(), SourceByte= %d, TargetByte= %d, TargetBuf[0] = 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x", __FUNCTION__, SourceByte, TargetByte, *TargetBuf, *(TargetBuf + 1), *(TargetBuf + 2), *(TargetBuf + 3), *(TargetBuf + 4), *(TargetBuf + 5), *(TargetBuf + 6), *(TargetBuf + 7));
+
+ if (mDumpEnabled) {
+#ifdef DUMP_PRE_ENCRYPT
+ if (pPreEncDumpFile != NULL) {
+ fwrite(SourceBuf, sizeof(char), SourceByte, pPreEncDumpFile);
+ } else {
+ ALOGW("%s(), pPreEncDumpFile == NULL!!!!!", __FUNCTION__);
+ }
+
+#endif
+#ifdef DUMP_POST_ENCRYPT
+ if (pPostEncDumpFile != NULL) {
+ fwrite(TargetBuf, sizeof(char), TargetByte, pPostEncDumpFile);
+ } else {
+ ALOGW("%s(), pPostEncDumpFile == NULL!!!!!", __FUNCTION__);
+ }
+#endif
+
+ }
+ leavetime = GetSystemTime();
+
+ timediffns = TimeDifference(leavetime, entertime);
+ ALOGD_IF(mLogEnable, "-%s(), SourceByte= %d, TargetByte= %d, process time=%lld(ns)", __FUNCTION__, SourceByte, TargetByte, timediffns);
+
+ AL_UNLOCK(mMutexUL);
+ int DelayMS = GetDelay();
+ if (DelayMS != 0) {
+ ALOGD("%s(), delay %d ms", __FUNCTION__, DelayMS);
+
+ usleep(DelayMS * 1000);
+ }
+ return TargetByte;
+}
+
+uint16_t SpeechDataEncrypter::Decryption(char *TargetBuf, char *SourceBuf, const uint16_t SourceByte) {
+ uint16_t TargetByte = 0;
+ struct timespec entertime;
+ struct timespec leavetime;
+ unsigned long long timediffns = 0;
+ entertime = GetSystemTime();
+
+
+ AL_LOCK(mMutexDL);
+ ALOGD_IF(mLogEnable, "+%s(), SourceByte= %d, SourceBuf[0] = 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x", __FUNCTION__, SourceByte, *SourceBuf, *(SourceBuf + 1), *(SourceBuf + 2), *(SourceBuf + 3), *(SourceBuf + 4), *(SourceBuf + 5), *(SourceBuf + 6), *(SourceBuf + 7));
+ TargetByte = AudioCustEncryptClient::GetInstance()->DecryptProcess(TargetBuf, SourceBuf, SourceByte);
+ ALOGD_IF(mLogEnable, "-%s(), SourceByte= %d, TargetByte= %d, TargetBuf[0] = 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x", __FUNCTION__, SourceByte, TargetByte, *TargetBuf, *(TargetBuf + 1), *(TargetBuf + 2), *(TargetBuf + 3), *(TargetBuf + 4), *(TargetBuf + 5), *(TargetBuf + 6), *(TargetBuf + 7));
+
+ if (mDumpEnabled) {
+#ifdef DUMP_PRE_DECRYPT
+ if (pPreDecDumpFile != NULL) {
+ fwrite(SourceBuf, sizeof(char), SourceByte, pPreDecDumpFile);
+ } else {
+ ALOGW("%s(), pPreDecDumpFile == NULL!!!!!", __FUNCTION__);
+ }
+
+#endif
+#ifdef DUMP_POST_DECRYPT
+ if (pPostDecDumpFile != NULL) {
+ fwrite(TargetBuf, sizeof(char), TargetByte, pPostDecDumpFile);
+ } else {
+ ALOGW("%s(), pPostDecDumpFile == NULL!!!!!", __FUNCTION__);
+ }
+#endif
+
+ }
+ leavetime = GetSystemTime();
+
+ timediffns = TimeDifference(leavetime, entertime);
+ ALOGD_IF(mLogEnable, "-%s(), SourceByte= %d, TargetByte= %d, process time=%lld(ns)", __FUNCTION__, SourceByte, TargetByte, timediffns);
+
+ AL_UNLOCK(mMutexDL);
+ int DelayMS = GetDelay();
+ if (DelayMS != 0) {
+ ALOGD("%s(), delay %d ms", __FUNCTION__, DelayMS);
+ usleep(DelayMS * 1000);
+ }
+
+ return TargetByte;
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechDriverDummy.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechDriverDummy.cpp
new file mode 100644
index 0000000..06e60a4
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechDriverDummy.cpp
@@ -0,0 +1,314 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechDriverDummy"
+#include <SpeechDriverDummy.h>
+#include <utils/threads.h>
+
+namespace android {
+
+/*==============================================================================
+ * Constructor / Destructor / Init / Deinit
+ *============================================================================*/
+
+SpeechDriverDummy::SpeechDriverDummy(modem_index_t modem_index) {
+ ALOGW("%s(), modem_index = %d", __FUNCTION__, modem_index);
+}
+
+SpeechDriverDummy::~SpeechDriverDummy() {
+ ALOGW("%s()", __FUNCTION__);
+}
+
+/*==============================================================================
+ * Speech Control
+ *============================================================================*/
+
+status_t SpeechDriverDummy::SetSpeechMode(const audio_devices_t input_device, const audio_devices_t output_device) {
+ ALOGW("%s(), input_device = 0x%x, output_device = 0x%x", __FUNCTION__, input_device, output_device);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::setMDVolumeIndex(int stream, int device, int index) {
+ ALOGV("+%s() stream=%d, device=%d, index=%d", __FUNCTION__, stream, device, index);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::SpeechOn() {
+ ALOGW("%s()", __FUNCTION__);
+ CheckApSideModemStatusAllOffOrDie();
+ SetApSideModemStatus(SPEECH_STATUS_MASK);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::SpeechOff() {
+ ALOGW("%s()", __FUNCTION__);
+ ResetApSideModemStatus(SPEECH_STATUS_MASK);
+ CheckApSideModemStatusAllOffOrDie();
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::VideoTelephonyOn() {
+ ALOGW("%s()", __FUNCTION__);
+ CheckApSideModemStatusAllOffOrDie();
+ SetApSideModemStatus(VT_STATUS_MASK);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::VideoTelephonyOff() {
+ ALOGW("%s()", __FUNCTION__);
+ ResetApSideModemStatus(VT_STATUS_MASK);
+ CheckApSideModemStatusAllOffOrDie();
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::SpeechRouterOn() {
+ ALOGW("%s()", __FUNCTION__);
+ CheckApSideModemStatusAllOffOrDie();
+ SetApSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::SpeechRouterOff() {
+ ALOGW("%s()", __FUNCTION__);
+ ResetApSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+ CheckApSideModemStatusAllOffOrDie();
+ return INVALID_OPERATION;
+}
+
+/*==============================================================================
+ * Recording Control
+ *============================================================================*/
+
+status_t SpeechDriverDummy::recordOn() {
+ ALOGW("%s()", __FUNCTION__);
+ SetApSideModemStatus(RECORD_STATUS_MASK);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::recordOn(SpcRecordTypeStruct typeRecord) {
+ ALOGW("%s() typeRecord=%d", __FUNCTION__, typeRecord.direction);
+ SetApSideModemStatus(RAW_RECORD_STATUS_MASK);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::recordOff() {
+ ALOGW("%s()", __FUNCTION__);
+ ResetApSideModemStatus(RECORD_STATUS_MASK);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::recordOff(SpcRecordTypeStruct typeRecord) {
+ ALOGW("%s() typeRecord=%d", __FUNCTION__, typeRecord.direction);
+ ResetApSideModemStatus(RAW_RECORD_STATUS_MASK);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::setPcmRecordType(SpcRecordTypeStruct typeRecord) {
+ ALOGW("%s() typeRecord=%d", __FUNCTION__, typeRecord.direction);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::VoiceMemoRecordOn() {
+ ALOGW("%s()", __FUNCTION__);
+ SetApSideModemStatus(VM_RECORD_STATUS_MASK);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::VoiceMemoRecordOff() {
+ ALOGW("%s()", __FUNCTION__);
+ ResetApSideModemStatus(VM_RECORD_STATUS_MASK);
+ return INVALID_OPERATION;
+}
+
+uint16_t SpeechDriverDummy::GetRecordSampleRate() const {
+ ALOGW("%s(), num_sample_rate = 8000", __FUNCTION__);
+ return 8000;
+}
+
+uint16_t SpeechDriverDummy::GetRecordChannelNumber() const {
+ ALOGW("%s(), num_channel = 1", __FUNCTION__);
+ return 1;
+}
+
+/*==============================================================================
+ * Background Sound
+ *============================================================================*/
+
+status_t SpeechDriverDummy::BGSoundOn() {
+ ALOGW("%s()", __FUNCTION__);
+ SetApSideModemStatus(BGS_STATUS_MASK);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::BGSoundConfig(uint8_t ul_gain, uint8_t dl_gain) {
+ ALOGW("%s(), ul_gain = 0x%x, dl_gain = 0x%x", __FUNCTION__, ul_gain, dl_gain);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::BGSoundOff() {
+ ALOGW("%s()", __FUNCTION__);
+ ResetApSideModemStatus(BGS_STATUS_MASK);
+ return INVALID_OPERATION;
+}
+
+/*==============================================================================
+ * PCM 2 Way
+ *============================================================================*/
+
+status_t SpeechDriverDummy::PCM2WayOn(const bool wideband_on) {
+ ALOGW("%s() wideband_on=%d", __FUNCTION__, wideband_on);
+ SetApSideModemStatus(P2W_STATUS_MASK);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::PCM2WayOff() {
+ ALOGW("%s()", __FUNCTION__);
+ ResetApSideModemStatus(P2W_STATUS_MASK);
+ return INVALID_OPERATION;
+}
+
+
+/*==============================================================================
+ * TTY-CTM Control
+ *============================================================================*/
+status_t SpeechDriverDummy::TtyCtmOn() {
+ ALOGW("%s()", __FUNCTION__);
+ SetApSideModemStatus(TTY_STATUS_MASK);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::TtyCtmOff() {
+ ALOGW("%s()", __FUNCTION__);
+ ResetApSideModemStatus(TTY_STATUS_MASK);
+ return INVALID_OPERATION;
+}
+
+/*==============================================================================
+ * Modem Audio DVT and Debug
+ *============================================================================*/
+
+status_t SpeechDriverDummy::SetModemLoopbackPoint(uint16_t loopback_point) {
+ ALOGW("%s(), loopback_point = %d", __FUNCTION__, loopback_point);
+ return INVALID_OPERATION;
+}
+
+
+/*==============================================================================
+ * Acoustic Loopback
+ *============================================================================*/
+
+status_t SpeechDriverDummy::SetAcousticLoopback(bool loopback_on) {
+ ALOGW("%s(), loopback_on = %d", __FUNCTION__, loopback_on);
+
+ if (loopback_on == true) {
+ CheckApSideModemStatusAllOffOrDie();
+ SetApSideModemStatus(LOOPBACK_STATUS_MASK);
+ } else {
+ ResetApSideModemStatus(LOOPBACK_STATUS_MASK);
+ CheckApSideModemStatusAllOffOrDie();
+ }
+
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::SetAcousticLoopbackBtCodec(bool enable_codec) {
+ ALOGW("%s(), enable_codec = %d", __FUNCTION__, enable_codec);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::SetAcousticLoopbackDelayFrames(int32_t delay_frames) {
+ ALOGW("%s(), delay_frames = %d", __FUNCTION__, delay_frames);
+ return INVALID_OPERATION;
+}
+
+/*==============================================================================
+ * Volume Control
+ *============================================================================*/
+
+status_t SpeechDriverDummy::SetDownlinkGain(int16_t gain) {
+ ALOGW("%s(), gain = 0x%x, old mDownlinkGain = 0x%x", __FUNCTION__, gain, mDownlinkGain);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::SetEnh1DownlinkGain(int16_t gain) {
+ ALOGW("%s(), gain = 0x%x, old SetEnh1DownlinkGain = 0x%x", __FUNCTION__, gain, mDownlinkenh1Gain);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::SetUplinkGain(int16_t gain) {
+ ALOGW("%s(), gain = 0x%x, old mUplinkGain = 0x%x", __FUNCTION__, gain, mUplinkGain);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::SetDownlinkMute(bool mute_on) {
+ ALOGW("%s(), mute_on = %d, old mDownlinkMuteOn = %d", __FUNCTION__, mute_on, mDownlinkMuteOn);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::SetDownlinkMuteCodec(bool mute_on) {
+ ALOGW("%s(), mute_on = %d, old mDownlinkMuteOn = %d", __FUNCTION__, mute_on, mDownlinkMuteOn);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::SetUplinkMute(bool mute_on) {
+ ALOGW("%s(), mute_on = %d, old mUplinkMuteOn = %d", __FUNCTION__, mute_on, mUplinkMuteOn);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::SetUplinkSourceMute(bool mute_on) {
+ ALOGW("%s(), mute_on = %d, old mUplinkSourceMuteOn = %d", __FUNCTION__, mute_on, mUplinkSourceMuteOn);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::SetSidetoneGain(int16_t gain) {
+ ALOGW("%s(), gain = 0x%x, old mSideToneGain = 0x%x", __FUNCTION__, gain, mSideToneGain);
+ return INVALID_OPERATION;
+}
+
+/*==============================================================================
+ * Device related Config
+ *============================================================================*/
+
+status_t SpeechDriverDummy::SetModemSideSamplingRate(uint16_t sample_rate) {
+ ALOGW("%s(), sample_rate = %d", __FUNCTION__, sample_rate);
+ return INVALID_OPERATION;
+}
+
+/*==============================================================================
+ * Speech Enhancement Control
+ *============================================================================*/
+status_t SpeechDriverDummy::SetSpeechEnhancement(bool enhance_on) {
+ ALOGW("%s(), enhance_on = %d", __FUNCTION__, enhance_on);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::SetSpeechEnhancementMask(const sph_enh_mask_struct_t &mask) {
+ ALOGW("%s(), main_func = 0x%x, dynamic_func = 0x%x", __FUNCTION__, mask.main_func, mask.dynamic_func);
+ return INVALID_OPERATION;
+}
+
+status_t SpeechDriverDummy::SetBtHeadsetNrecOn(const bool bt_headset_nrec_on) {
+ ALOGW("%s(), bt_headset_nrec_on = %d", __FUNCTION__, bt_headset_nrec_on);
+ return INVALID_OPERATION;
+}
+
+/*==============================================================================
+ * Recover State
+ *============================================================================*/
+
+void SpeechDriverDummy::RecoverModemSideStatusToInitState() {
+ ALOGW("%s()", __FUNCTION__);
+}
+
+/*==============================================================================
+ * Check Modem Status
+ *============================================================================*/
+bool SpeechDriverDummy::CheckModemIsReady() {
+ ALOGW("%s()", __FUNCTION__);
+ return false;
+};
+
+
+} // end of namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechDriverFactory.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechDriverFactory.cpp
new file mode 100644
index 0000000..b0addb2
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechDriverFactory.cpp
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "SpeechDriverFactory.h"
+#include "SpeechType.h"
+#include "SpeechDriverInterface.h"
+#include "SpeechDriverDummy.h"
+#include <SpeechDriverNormal.h>
+#include "SpeechDriverLAD.h"
+#include "AudioUtility.h"
+#include <SpeechUtility.h>
+
+#include <utils/threads.h>
+#include "AudioTypeExt.h"
+
+#ifdef MTK_AURISYS_PHONE_CALL_SUPPORT
+#include "SpeechDriverOpenDSP.h"
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechDriverFactory"
+
+// refer to /alps/vendor/mediatek/proprietary/hardware/ril/libratconfig/ratconfig.c
+#define CDMA "C"
+
+
+namespace android {
+
+SpeechDriverFactory *SpeechDriverFactory::mSpeechDriverFactory = NULL;
+SpeechDriverFactory *SpeechDriverFactory::GetInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+ ALOGV("%s()", __FUNCTION__);
+
+ if (mSpeechDriverFactory == NULL) {
+ mSpeechDriverFactory = new SpeechDriverFactory();
+ }
+ ASSERT(mSpeechDriverFactory != NULL);
+ return mSpeechDriverFactory;
+}
+
+SpeechDriverFactory::SpeechDriverFactory() {
+ ALOGV("%s()", __FUNCTION__);
+
+ mSpeechDriver1 = NULL;
+ mSpeechDriver2 = NULL;
+ mSpeechDriverExternal = NULL;
+
+ uint32 isMd1Support = 1;//get_uint32_from_property("ro.boot.opt_md1_support");
+
+ if (isMd1Support > 0) {
+ mActiveModemIndex = MODEM_1; // default use modem 1
+ } else {
+ char isC2kSupport[PROPERTY_VALUE_MAX] = {0};
+
+ //get_string_from_property("ro.boot.opt_ps1_rat", isC2kSupport, PROPERTY_VALUE_MAX);
+ if (strstr(isC2kSupport, CDMA) != NULL) {
+ ALOGD("%s(), isC2kSupport = %s", __FUNCTION__, isC2kSupport);
+ mActiveModemIndex = MODEM_EXTERNAL; // if modem evdo(c2k),default use modem external
+ } else {
+ ALOGW("mActiveModemIndex default use modem 1 !!");
+ mActiveModemIndex = MODEM_1; // dummy speech driver, default modem 1
+ }
+ }
+
+ CreateSpeechDriverInstances();
+
+ ALOGD("-%s(), mActiveModemIndex = %d", __FUNCTION__, mActiveModemIndex);
+}
+status_t SpeechDriverFactory::CreateSpeechDriverInstances() {
+
+#if defined(MTK_SPEECH_DUMMY)
+ ALOGW("%s(), Create SpeechDriverDummy for MODEM_1", __FUNCTION__);
+ mSpeechDriver1 = new SpeechDriverDummy(MODEM_1);
+
+ ALOGW("%s(), Create SpeechDriverDummy for MODEM_2", __FUNCTION__);
+ mSpeechDriver2 = new SpeechDriverDummy(MODEM_2);
+
+ ALOGW("%s(), Create SpeechDriverDummy for MODEM_EXTERNAL", __FUNCTION__);
+ mSpeechDriverExternal = new SpeechDriverDummy(MODEM_EXTERNAL);
+ return NO_ERROR;
+#endif // end of MTK_SPEECH_DUMMY
+
+#if defined(MTK_COMBO_MODEM_SUPPORT)
+ if (InFactoryMode()) {
+ ALOGD("%s(), factory mode!! create dummy driver", __FUNCTION__);
+ mSpeechDriver1 = new SpeechDriverDummy(MODEM_1);
+ mSpeechDriver2 = new SpeechDriverDummy(MODEM_2);
+ mSpeechDriverExternal = new SpeechDriverDummy(MODEM_EXTERNAL);
+ return NO_ERROR;
+ }
+
+
+#ifdef MTK_AURISYS_PHONE_CALL_SUPPORT
+ ALOGD("Create SpeechDriverOpenDSP for MODEM_1");
+ mSpeechDriver1 = SpeechDriverOpenDSP::GetInstance(MODEM_1);
+#else
+ ALOGD("Create SpeechDriverNormal for MODEM_1");
+ mSpeechDriver1 = SpeechDriverNormal::GetInstance(MODEM_1);
+#endif // end of MTK_AURISYS_PHONE_CALL_SUPPORT
+
+
+ ALOGW("Create SpeechDriverDummy for MODEM_2");
+ mSpeechDriver2 = new SpeechDriverDummy(MODEM_2);
+
+ ALOGW("Create SpeechDriverDummy for MODEM_EXTERNAL");
+ mSpeechDriverExternal = new SpeechDriverDummy(MODEM_EXTERNAL);
+#else
+
+
+ uint32 isMd1Support = 1;//get_uint32_from_property("ro.boot.opt_md1_support");
+
+ ALOGD("%s(), isMd1Support = %d", __FUNCTION__, isMd1Support);
+ if (isMd1Support > 0) {
+ // for internal modem_1, always return LAD
+ ALOGD("Create SpeechDriverLAD for MODEM_1");
+ mSpeechDriver1 = SpeechDriverLAD::GetInstance(MODEM_1);
+ } else {
+ ALOGW("Create SpeechDriverDummy for MODEM_1");
+ mSpeechDriver1 = new SpeechDriverDummy(MODEM_1);
+
+ }
+ char isC2kSupport[PROPERTY_VALUE_MAX] = {0};
+
+ //get_string_from_property("ro.boot.opt_ps1_rat", isC2kSupport, PROPERTY_VALUE_MAX);
+ if (strstr(isC2kSupport, CDMA) != NULL) {
+ ALOGD("%s(), isC2kSupport = %s", __FUNCTION__, isC2kSupport);
+ ALOGD("Create SpeechDriverEVDO for MODEM_EXTERNAL");
+ mSpeechDriverExternal = SpeechDriverLAD::GetInstance(MODEM_EXTERNAL);
+ } else {
+ ALOGW("Create SpeechDriverDummy for MODEM_EXTERNAL");
+ mSpeechDriverExternal = new SpeechDriverDummy(MODEM_EXTERNAL);
+ }
+#endif // end of MTK_COMBO_MODEM_SUPPORT
+
+ return NO_ERROR;
+}
+
+status_t SpeechDriverFactory::DestroySpeechDriverInstances() {
+ if (mSpeechDriver1 != NULL) {
+ delete mSpeechDriver1;
+ mSpeechDriver1 = NULL;
+ }
+
+ if (mSpeechDriver2 != NULL) {
+ delete mSpeechDriver2;
+ mSpeechDriver2 = NULL;
+ }
+
+ if (mSpeechDriverExternal != NULL) {
+ delete mSpeechDriverExternal;
+ mSpeechDriverExternal = NULL;
+ }
+ return NO_ERROR;
+}
+
+SpeechDriverFactory::~SpeechDriverFactory() {
+ DestroySpeechDriverInstances();
+}
+
+SpeechDriverInterface *SpeechDriverFactory::GetSpeechDriver() {
+ SpeechDriverInterface *pSpeechDriver = NULL;
+ ALOGV("%s(), mActiveModemIndex=%d", __FUNCTION__, mActiveModemIndex);
+
+ switch (mActiveModemIndex) {
+ case MODEM_1:
+ pSpeechDriver = mSpeechDriver1;
+ break;
+ case MODEM_2:
+ pSpeechDriver = mSpeechDriver2;
+ break;
+ case MODEM_EXTERNAL:
+ pSpeechDriver = mSpeechDriverExternal;
+ break;
+ default:
+ ALOGE("%s: no such modem index %d", __FUNCTION__, mActiveModemIndex);
+ break;
+ }
+
+ ASSERT(pSpeechDriver != NULL);
+ return pSpeechDriver;
+}
+
+/**
+ * NO GUARANTEE that the returned pointer is not NULL!!
+ * Be careful to use this function!!
+ */
+SpeechDriverInterface *SpeechDriverFactory::GetSpeechDriverByIndex(const modem_index_t modem_index) {
+ SpeechDriverInterface *pSpeechDriver = NULL;
+ ALOGD("%s(), modem_index=%d", __FUNCTION__, modem_index);
+
+ switch (modem_index) {
+ case MODEM_1:
+ pSpeechDriver = mSpeechDriver1;
+ break;
+ case MODEM_2:
+ pSpeechDriver = mSpeechDriver2;
+ break;
+ case MODEM_EXTERNAL:
+ pSpeechDriver = mSpeechDriverExternal;
+ break;
+ default:
+ ALOGE("%s: no such modem index %d", __FUNCTION__, modem_index);
+ break;
+ }
+
+ return pSpeechDriver;
+}
+
+
+modem_index_t SpeechDriverFactory::GetActiveModemIndex() const {
+ return mActiveModemIndex;
+}
+
+status_t SpeechDriverFactory::SetActiveModemIndex(const modem_index_t modem_index) {
+#if !defined(MTK_COMBO_MODEM_SUPPORT)
+ ALOGD("%s(), old modem index = %d, new modem index = %d", __FUNCTION__, mActiveModemIndex, modem_index);
+#endif
+ mActiveModemIndex = modem_index;
+ return NO_ERROR;
+}
+
+
+status_t SpeechDriverFactory::SetActiveModemIndexByAudioMode(const audio_mode_t audio_mode) {
+ status_t return_status = NO_ERROR;
+
+#if !defined(MTK_COMBO_MODEM_SUPPORT)
+ ALOGD("%s(), audio_mode = %d", __FUNCTION__, audio_mode);
+#endif
+
+ switch (audio_mode) {
+ case AUDIO_MODE_IN_CALL:
+ return_status = SetActiveModemIndex(MODEM_1);
+ break;
+ default:
+ ALOGE("%s() mode(%d) is neither MODE_IN_CALL nor MODE_IN_CALL_2!!", __FUNCTION__, audio_mode);
+ return_status = INVALID_OPERATION;
+ break;
+ }
+ return return_status;
+}
+
+
+} // end of namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechDriverNormal.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechDriverNormal.cpp
new file mode 100644
index 0000000..e6e6e24
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechDriverNormal.cpp
@@ -0,0 +1,3459 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <SpeechDriverNormal.h>
+
+#include <string.h>
+
+#include <errno.h>
+
+#include <pthread.h>
+
+#include <utils/threads.h> /* for ANDROID_PRIORITY_AUDIO */
+
+#include <cutils/properties.h> /* for PROPERTY_KEY_MAX */
+
+#include <system/audio.h>
+
+#include <audio_time.h>
+
+#include <AudioLock.h>
+
+#include <SpeechUtility.h>
+#include <AudioUtility.h>
+
+#include <SpeechMessageID.h>
+
+
+#include <SpeechMessageQueue.h>
+#include <SpeechMessengerNormal.h>
+
+
+#include <AudioVolumeFactory.h>
+#include <SpeechBGSPlayer.h>
+#include <SpeechVMRecorder.h>
+#include <SpeechPcm2way.h>
+#if !defined(MTK_YOCTO_AUDIO)
+#include <SpeechDataProcessingHandler.h>
+#endif
+
+#include <SpeechParserBase.h>
+#include <SpeechConfig.h>
+
+#include <SpeechEnhancementController.h>
+
+#include <WCNChipController.h>
+
+#include <AudioALSAHardwareResourceManager.h>
+
+#if !defined(MTK_YOCTO_AUDIO)
+#include <AudioSmartPaController.h>
+#include <AudioVIBSPKControl.h>
+#endif
+
+#include <AudioEventThreadManager.h>
+#include <tinyalsa/asoundlib.h> // for mixctrl
+#if defined(MTK_SPEECH_VOICE_MIXER_SUPPORT)
+#include <SpeechVoiceMixer.h>
+#endif
+
+#if defined(MTK_SPEECH_ECALL_SUPPORT)
+#include <SpeechEcallController.h>
+#endif
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechDriverNormal"
+
+namespace android {
+
+
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+
+#define USE_DEDICATED_LOOPBACK_DELAY_FRAMES (true)
+#define MAX_LOOPBACK_DELAY_FRAMES (64)
+#define DEFAULT_LOOPBACK_DELAY_FRAMES (12) /* 12 frames => 240 ms */
+
+#define MAX_SPEECH_AUTO_LOCK_TIMEOUT_MS (3000)
+
+#define TEMP_CCCI_MD_PAYLOAD_SYNC (0x1234)
+
+
+#define MAX_VM_RECORD_SIZE (0x4000) // 7500 * 2 => 16K
+#define MAX_RAW_RECORD_SIZE (0x1000) // 1924 * 2 => 4K
+#define MAX_PNW_UL_SIZE (0x800) // 960 * 2 => 2K
+#define MAX_TTY_DEBUG_SIZE (0x200) // 160 * 2 => 512 bytes
+#if defined(MTK_SPEECH_VOICE_MIXER_SUPPORT)
+#define MAX_PCMMIXER_UL_SIZE (0x800) // 960 * 2 => 2K
+#endif
+
+#define MAX_PARSED_RECORD_SIZE (MAX_RAW_RECORD_SIZE)
+
+#define MAX_MSG_PROCESS_TIME_MS (10)
+
+#define SPH_DUMP_STR_SIZE (1024)
+
+#define MAX_SPEECH_ECALL_BUF_LEN (1600)
+/*
+ * =============================================================================
+ * global
+ * =============================================================================
+ */
+
+/* keep modem status to recovery when audioserver die */
+static const char *kPropertyKeyModemEPOF = "vendor.audiohal.modem_1.epof";
+static const char *kPropertyKeyModemStatus = "vendor.audiohal.modem_1.status";
+static const char *kPropertyKeyWaitAckMsgId = "vendor.audiohal.wait.ack.msgid";
+
+/* from MSG_M2A_NETWORK_STATUS_NOTIFY */
+static const char *kPropertyKeyRfMode = "vendor.audiohal.rf_mode";
+
+/* from MSG_M2A_NW_CODEC_INFO_NOTIFY */
+static const char *kPropertyKeyRilSphCodecInfo = "vendor.audiohal.ril.speech.codec.info";
+static const char *kPropertyKeyRilHdVoiceStatus = "vendor.audiohal.ril.hd.voice.status";
+
+static char keyStringBuf[MAX_SPEECH_PARSER_KEY_LEN];
+
+/*
+ * =============================================================================
+ * Callback
+ * =============================================================================
+ */
+
+static void callbackSpeechParamChange(int audioEventType, void *caller, void *arg) {
+ ALOGD("%s(), audioEventType = %d, caller(%p), arg(%p)",
+ __FUNCTION__, audioEventType, caller, arg);
+
+ SpeechDriverNormal *pSpeechDriver = NULL;
+ pSpeechDriver = static_cast<SpeechDriverNormal *>(caller);
+ if (pSpeechDriver == NULL) {
+ ALOGE("%s(), pSpeechDriver is NULL!!", __FUNCTION__);
+ return;
+ }
+ pSpeechDriver->updateSpeechParam(SPEECH_SCENARIO_PARAM_CHANGE);
+}
+
+/*
+ * =============================================================================
+ * Singleton Pattern
+ * =============================================================================
+ */
+
+SpeechDriverNormal *SpeechDriverNormal::mSpeechDriver = NULL;
+
+SpeechDriverNormal *SpeechDriverNormal::GetInstance(modem_index_t modem_index) {
+ static AudioLock mGetInstanceLock;
+
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ if (modem_index != MODEM_1) {
+ ALOGE("%s(), modem_index %d not support!!", __FUNCTION__, modem_index);
+ ASSERT(modem_index == MODEM_1);
+ return NULL;
+ }
+
+ if (mSpeechDriver == NULL) {
+ mSpeechDriver = new SpeechDriverNormal(modem_index);
+ }
+ return mSpeechDriver;
+}
+
+
+
+/*==============================================================================
+ * Constructor / Destructor / Init / Deinit
+ *============================================================================*/
+
+SpeechDriverNormal::SpeechDriverNormal(modem_index_t modem_index) {
+ mModemIndex = modem_index;
+
+ // initialize buffer pointer
+ mBgsBuf = NULL;
+ mVmRecBuf = NULL;
+ mRawRecBuf = NULL;
+ mParsedRecBuf = NULL;
+ mP2WUlBuf = NULL;
+ mP2WDlBuf = NULL;
+ mTtyDebugBuf = NULL;
+
+ reload_property();
+ mSpeechMessenger = new SpeechMessengerNormal(mModemIndex);
+ if (mSpeechMessenger == NULL) {
+ ALOGE("%s(), mSpeechMessenger == NULL!!", __FUNCTION__);
+ } else {
+ if (get_uint32_from_mixctrl(kPropertyKeyModemEPOF) != 0) {
+ if (mSpeechMessenger->checkModemAlive() == true) {
+ ALOGD("%s(), md alive, reset EPOF", __FUNCTION__);
+ set_uint32_to_mixctrl(kPropertyKeyModemEPOF, 0);
+ }
+ }
+
+ kMaxApPayloadDataSize = mSpeechMessenger->getMaxApPayloadDataSize();
+ kMaxMdPayloadDataSize = mSpeechMessenger->getMaxMdPayloadDataSize();
+
+ AUDIO_ALLOC_BUFFER(mBgsBuf, kMaxApPayloadDataSize);
+ AUDIO_ALLOC_BUFFER(mRawRecBuf, MAX_RAW_RECORD_SIZE);
+ AUDIO_ALLOC_BUFFER(mParsedRecBuf, MAX_PARSED_RECORD_SIZE);
+ }
+
+ mSampleRateEnum = SPH_SAMPLE_RATE_32K;
+
+ mApplication = SPH_APPLICATION_INVALID;
+ mSpeechMode = SPEECH_MODE_NORMAL;
+ mInputDevice = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ mOutputDevice = AUDIO_DEVICE_OUT_EARPIECE;
+
+ mModemLoopbackDelayFrames = DEFAULT_LOOPBACK_DELAY_FRAMES;
+
+
+ // Record capability
+ mRecordSampleRateType = RECORD_SAMPLE_RATE_08K;
+ mRecordChannelType = RECORD_CHANNEL_MONO;
+ mRecordType.direction = RECORD_TYPE_MIX;
+#ifdef MTK_PHONE_CALL_RECORD_VOICE_ONLY
+ mRecordType.dlPosition = RECORD_POS_DL_AFTER_ENH;
+#else
+ mRecordType.dlPosition = RECORD_POS_DL_END;
+#endif
+ mVolumeIndex = 0x3;
+
+ mTtyDebugEnable = false;
+ mApResetDuringSpeech = false;
+ mModemResetDuringSpeech = false;
+ mModemDead = false;
+ mNeedWaitModemAckAfterApDie = false;
+ mReadMsgThreadCreated = false;
+
+
+ // init var
+ mEnableThread = false;
+ mEnableThreadDuringSpeech = false;
+
+ hReadSpeechMessageThread = 0;
+ hModemStatusMonitorThread = 0;
+
+ isBtSpkDevice = false;
+ mBTMode = 0;
+
+ // BT Headset NREC
+ mBtHeadsetNrecOn = SpeechEnhancementController::GetInstance()->GetBtHeadsetNrecOn();
+
+ // RTT
+ mRttMode = 0;
+
+ memset(&mMdAliveInfo, 0, sizeof(MdAliveInfo));
+ mMdAliveInfo.mdVersion = 0;
+ mIsParseFail = false;
+ mIsBTSwitchConfig = false;
+ //Parser Attribute
+ mSpeechParserAttribute.inputDevice = mInputDevice;
+ mSpeechParserAttribute.outputDevice = mOutputDevice;
+ mSpeechParserAttribute.idxVolume = 3;
+ mSpeechParserAttribute.driverScenario = SPEECH_SCENARIO_SPEECH_ON;
+ mSpeechParserAttribute.ttyMode = mTtyMode;
+ if (AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport() >= 2) {
+#if defined(MTK_INCALL_HANDSFREE_DMNR)
+ mSpeechParserAttribute.speechFeatureOn = 6;
+#else
+ mSpeechParserAttribute.speechFeatureOn = 4;
+#endif
+ } else {
+ mSpeechParserAttribute.speechFeatureOn = 0;
+ }
+ mSpeechParam.dataSize = 0;
+ mSpeechParam.memorySize = 0;
+ mSpeechParam.bufferAddr = NULL;
+ static char ecallRxCtrlData[MAX_SPEECH_ECALL_BUF_LEN];
+
+ /* ecall */
+ mEcallRXCtrlData.size = 0;
+ AUDIO_ALLOC_BUFFER(mEcallRXCtrlData.data, MAX_SPEECH_ECALL_BUF_LEN);
+
+ mSpeechMessageQueue = new SpeechMessageQueue(sendSpeechMessageToModemWrapper,
+ errorHandleSpeechMessageWrapper,
+ this);
+
+ // initial modem side modem status
+ mModemSideModemStatus = get_uint32_from_mixctrl(kPropertyKeyModemStatus);
+ mPcmMixerTypeDl = VOICE_MIXER_TYPE_MIX;
+ mPcmMixerTypeUl = VOICE_MIXER_TYPE_MIX;
+
+ // check if any msg is waiting ack after audioserver crash
+ mApWaitAckMsgID = get_uint32_from_mixctrl(kPropertyKeyWaitAckMsgId);
+
+ if (mModemSideModemStatus || mApWaitAckMsgID) {
+ mApResetDuringSpeech = true;
+ }
+ if (mApWaitAckMsgID) {
+ mNeedWaitModemAckAfterApDie = true;
+ }
+
+ createThreads();
+ RecoverModemSideStatusToInitState();
+ AudioEventThreadManager::getInstance()->registerCallback(AUDIO_EVENT_SPEECH_PARAM_CHANGE, callbackSpeechParamChange, this);
+#if defined(MTK_SPEECH_ECALL_SUPPORT)
+ SpeechEcallController* ecallController = new SpeechEcallController();
+#endif
+
+}
+
+
+SpeechDriverNormal::~SpeechDriverNormal() {
+ joinThreads();
+
+ if (mSpeechMessageQueue) {
+ delete mSpeechMessageQueue;
+ mSpeechMessageQueue = NULL;
+ }
+
+ AUDIO_FREE_POINTER(mBgsBuf);
+ AUDIO_FREE_POINTER(mRawRecBuf);
+ AUDIO_FREE_POINTER(mParsedRecBuf);
+
+}
+
+
+/*==============================================================================
+ * modem status
+ *============================================================================*/
+
+bool SpeechDriverNormal::getModemSideModemStatus(
+ const modem_status_mask_t modem_status_mask) const {
+ return ((mModemSideModemStatus & modem_status_mask) > 0);
+}
+
+
+void SpeechDriverNormal::setModemSideModemStatus(const modem_status_mask_t modem_status_mask) {
+ AL_AUTOLOCK(mModemSideModemStatusLock);
+
+ if (getModemSideModemStatus(modem_status_mask) == true) {
+ ALOGE("%s(), modem_status_mask: 0x%x already enabled!!", __FUNCTION__, modem_status_mask);
+ ASSERT(getModemSideModemStatus(modem_status_mask) == false);
+ return;
+ }
+
+ mModemSideModemStatus |= modem_status_mask;
+
+ // save mModemSideModemStatus in kernel to avoid medieserver die
+ set_uint32_to_mixctrl(kPropertyKeyModemStatus, mModemSideModemStatus);
+}
+
+
+void SpeechDriverNormal::resetModemSideModemStatus(const modem_status_mask_t modem_status_mask) {
+ AL_AUTOLOCK(mModemSideModemStatusLock);
+
+ if (getModemSideModemStatus(modem_status_mask) == false) {
+ ALOGE("%s(), modem status:0x%x, modem_status_mask: 0x%x not enabled!!",
+ __FUNCTION__, mModemSideModemStatus, modem_status_mask);
+ ASSERT(getModemSideModemStatus(modem_status_mask) == true);
+ return;
+ }
+
+ mModemSideModemStatus &= (~modem_status_mask);
+
+ // save mModemSideModemStatus in kernel to avoid medieserver die
+ set_uint32_to_mixctrl(kPropertyKeyModemStatus, mModemSideModemStatus);
+
+}
+
+
+void SpeechDriverNormal::cleanAllModemSideModemStatus() {
+ AL_AUTOLOCK(mModemSideModemStatusLock);
+
+ ALOGD("%s(), mModemSideModemStatus: 0x%x to be clean", __FUNCTION__, mModemSideModemStatus);
+ mModemSideModemStatus = 0;
+
+ set_uint32_to_mixctrl(kPropertyKeyModemStatus, mModemSideModemStatus);
+
+}
+
+
+/*==============================================================================
+ * AP to MD control msg need ack
+ *============================================================================*/
+
+void SpeechDriverNormal::setApWaitAckMsgID(sph_msg_t *p_sph_msg) {
+ struct timespec ts_start;
+ struct timespec ts_stop;
+ uint64_t time_diff_msg1 = 0, time_diff_msg2 = 0;
+ uint32_t currentApToMdNeedAckMsgId;
+
+ audio_get_timespec_monotonic(&ts_start);
+
+ // check if previous wait ack msg already reset
+ currentApToMdNeedAckMsgId = get_uint32_from_mixctrl(kPropertyKeyWaitAckMsgId);
+
+ audio_get_timespec_monotonic(&ts_stop);
+ time_diff_msg1 = get_time_diff_ms(&ts_start, &ts_stop);
+ if (currentApToMdNeedAckMsgId != 0) {
+ ALOGW("%s(), previous wait ack msg:0x%x not reset! current msg:0x%x",
+ __FUNCTION__, currentApToMdNeedAckMsgId, p_sph_msg->msg_id);
+ WARNING("previous wait ack msg not reset");
+ }
+ mApWaitAckMsgID = p_sph_msg->msg_id;
+
+ audio_get_timespec_monotonic(&ts_start);
+
+ set_uint32_to_mixctrl(kPropertyKeyWaitAckMsgId, mApWaitAckMsgID);
+
+ audio_get_timespec_monotonic(&ts_stop);
+ time_diff_msg2 = get_time_diff_ms(&ts_start, &ts_stop);
+ if ((time_diff_msg1 + time_diff_msg2) >= 1000) {
+ ALOGE("%s(),msg_id:0x%x, mixer_ctl_get_value %ju ms, mixer_ctl_set_value %ju ms ",
+ __FUNCTION__, p_sph_msg->msg_id, time_diff_msg1, time_diff_msg2);
+ }
+}
+
+
+void SpeechDriverNormal::resetApWaitAckMsgID() {
+ struct timespec ts_start;
+ struct timespec ts_stop;
+ uint64_t time_diff_msg;
+ // reset wait ack msg mictrl
+ mApWaitAckMsgID = 0;
+ audio_get_timespec_monotonic(&ts_start);
+
+ set_uint32_to_mixctrl(kPropertyKeyWaitAckMsgId, 0);
+
+ audio_get_timespec_monotonic(&ts_stop);
+ time_diff_msg = get_time_diff_ms(&ts_start, &ts_stop);
+ if (time_diff_msg >= 1000) {
+ ALOGE("%s(), mixer_ctl_set_value %ju ms ", __FUNCTION__, time_diff_msg);
+ }
+}
+
+
+/*==============================================================================
+ * msg
+ *============================================================================*/
+
+int SpeechDriverNormal::configSpeechInfo(sph_info_t *p_sph_info) {
+ int retval = 0;
+ uint32_t lenSphParam = 0, idxSphParam = 0;
+
+ if (p_sph_info == NULL) {
+ return -EFAULT;
+ }
+
+ ASSERT(sizeof(sph_info_t) == SIZE_OF_SPH_INFO);
+ memset(p_sph_info, 0, sizeof(sph_info_t));
+
+ /* application */
+ p_sph_info->application = mApplication;
+
+ /* bt_info */
+ const bool bt_device_on = audio_is_bluetooth_sco_device(mOutputDevice);
+ if (bt_device_on == false) {
+ if (isBtSpkDevice) { /* BT Speaker dual path*/
+ if (WCNChipController::GetInstance()->IsBTMergeInterfaceSupported() == true) {
+ p_sph_info->bt_info = SPH_BT_OFF;
+ } else {
+ p_sph_info->bt_info = (mBTMode == 0) ? SPH_BT_CVSD : SPH_BT_MSBC;
+ }
+ } else {
+ p_sph_info->bt_info = SPH_BT_OFF;
+ }
+ } else {
+ if (WCNChipController::GetInstance()->IsBTMergeInterfaceSupported() == true) {
+ p_sph_info->bt_info = SPH_BT_PCM;
+ } else {
+ p_sph_info->bt_info = (mBTMode == 0) ? SPH_BT_CVSD : SPH_BT_MSBC;
+ }
+ }
+
+ /* sample_rate_enum */
+ p_sph_info->sample_rate_enum = mSampleRateEnum;
+
+ /* param */
+#if defined(MTK_AURISYS_PHONE_CALL_SUPPORT)
+ p_sph_info->opendsp_flag = true;
+#else
+ p_sph_info->opendsp_flag = false;
+#endif
+
+ if (mIsBTSwitchConfig) {
+ p_sph_info->sph_param_valid = SPH_PARAM_PREVIOUS_VALID;
+ } else if (mIsParseFail) {
+ p_sph_info->sph_param_valid = SPH_PARAM_INVALID; /* md use default data*/
+ } else {
+#if defined(MTK_AURISYS_PHONE_CALL_SUPPORT)
+ p_sph_info->sph_param_path = SPH_PARAM_VIA_PAYLOAD;
+ p_sph_info->sph_param_valid = SPH_PARAM_INVALID; /* bypass sph param for opendsp */
+ p_sph_info->sph_param_length = 0;
+ p_sph_info->sph_param_index = 0;
+ p_sph_info->sph_param_usip_length = 0;
+ p_sph_info->sph_param_usip_index = 0;
+
+#else
+ retval = writeAllSpeechParametersToModem(&lenSphParam, &idxSphParam);
+
+ if (retval == 0) {
+ p_sph_info->sph_param_path = mSpeechMessenger->getShareMemoryType();
+
+#if defined(MTK_SPEECH_USIP_EMI_SUPPORT)
+ p_sph_info->sph_param_usip_index = idxSphParam;
+ p_sph_info->sph_param_usip_length = lenSphParam;
+ p_sph_info->sph_param_length = 0;
+ p_sph_info->sph_param_index = 0;
+#else
+ p_sph_info->sph_param_index = (uint16_t)idxSphParam;
+ p_sph_info->sph_param_length = lenSphParam;
+ p_sph_info->sph_param_usip_length = 0;
+ p_sph_info->sph_param_usip_index = 0;
+#endif
+
+ if (lenSphParam == 0) {
+#if defined(MTK_SPEECH_USIP_EMI_SUPPORT)
+ p_sph_info->sph_param_valid = SPH_PARAM_PREVIOUS_VALID; /* md use previous data */
+#else
+ p_sph_info->sph_param_valid = SPH_PARAM_INVALID; /* md use default data*/
+#endif
+ } else {
+ p_sph_info->sph_param_valid = SPH_PARAM_VALID;
+ }
+ } else {
+ p_sph_info->sph_param_path = SPH_PARAM_VIA_PAYLOAD;
+ p_sph_info->sph_param_valid = SPH_PARAM_INVALID;
+ p_sph_info->sph_param_length = 0;
+ p_sph_info->sph_param_index = 0;
+ p_sph_info->sph_param_usip_length = 0;
+ p_sph_info->sph_param_usip_index = 0;
+ }
+#endif
+ }
+
+ /* ext_dev_info */
+ switch (mOutputDevice) {
+#ifdef MTK_AUDIO_SPEAKER_PATH_3_IN_1
+ case AUDIO_DEVICE_OUT_EARPIECE:
+ p_sph_info->ext_dev_info = SPH_EXT_DEV_INFO_VIBRATION_RECEIVER;
+ break;
+#endif
+ case AUDIO_DEVICE_OUT_SPEAKER:
+#if !defined(MTK_YOCTO_AUDIO)
+ if (AudioSmartPaController::getInstance()->isSmartPAUsed() &&
+ !AudioSmartPaController::getInstance()->isBypassSwDspSpkProtect()) {
+#if defined(MTK_AUDIO_SPEAKER_PATH_2_IN_1) || defined(MTK_AUDIO_SPEAKER_PATH_3_IN_1)
+ p_sph_info->ext_dev_info = SPH_EXT_DEV_INFO_SMARTPA_VIBRATION_SPEAKER;
+#else
+ p_sph_info->ext_dev_info = SPH_EXT_DEV_INFO_SMARTPA_SPEAKER;
+#endif
+ } else
+#endif
+ {
+#if defined(MTK_AUDIO_SPEAKER_PATH_2_IN_1) || defined(MTK_AUDIO_SPEAKER_PATH_3_IN_1)
+ p_sph_info->ext_dev_info = SPH_EXT_DEV_INFO_VIBRATION_SPEAKER;
+#else
+ p_sph_info->ext_dev_info = SPH_EXT_DEV_INFO_DEFULAT;
+#endif /* end of MTK_AUDIO_SPEAKER_PATH_2_IN_1 || MTK_AUDIO_SPEAKER_PATH_3_IN_1 */
+ }
+ break;
+#ifdef MTK_USB_PHONECALL
+ case AUDIO_DEVICE_OUT_USB_DEVICE:
+ p_sph_info->ext_dev_info = SPH_EXT_DEV_INFO_USB_AUDIO;
+ break;
+#endif
+ case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+ case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+ p_sph_info->ext_dev_info = SPH_EXT_DEV_INFO_EARPHONE;
+ break;
+ default:
+ p_sph_info->ext_dev_info = SPH_EXT_DEV_INFO_DEFULAT;
+ break;
+ }
+
+
+ /* loopback */
+ if (p_sph_info->application != SPH_APPLICATION_LOOPBACK) {
+ p_sph_info->loopback_flag = 0;
+ p_sph_info->loopback_delay = 0;
+ } else {
+ p_sph_info->loopback_flag = 0;
+ /* bt codec */
+ if (mUseBtCodec == false) {
+ p_sph_info->loopback_flag |= SPH_LOOPBACK_INFO_FLAG_DISABLE_BT_CODEC;
+ }
+ /* delay ms */
+ if (USE_DEDICATED_LOOPBACK_DELAY_FRAMES == true) {
+ p_sph_info->loopback_flag |= SPH_LOOPBACK_INFO_FLAG_DELAY_SETTING;
+ p_sph_info->loopback_delay = mModemLoopbackDelayFrames;
+ } else {
+ p_sph_info->loopback_delay = 0;
+ }
+ }
+
+
+ /* echo_ref_delay_ms */
+ if (p_sph_info->bt_info == SPH_BT_CVSD_MSBC) {
+ if (mBtHeadsetNrecOn == false) {
+ p_sph_info->echo_ref_delay_ms = 0;
+ } else {
+ getBtDelayTime(&p_sph_info->echo_ref_delay_ms);
+ }
+ }
+ ASSERT(p_sph_info->echo_ref_delay_ms <= 256); /* modem limitation */
+
+ /* mic_delay_ms */
+ switch (p_sph_info->ext_dev_info) {
+#if !defined(MTK_YOCTO_AUDIO)
+ case SPH_EXT_DEV_INFO_SMARTPA_SPEAKER:
+ case SPH_EXT_DEV_INFO_SMARTPA_VIBRATION_SPEAKER:
+ if (AudioSmartPaController::getInstance()->isSmartPAUsed() &&
+ !AudioSmartPaController::getInstance()->isBypassSwDspSpkProtect()) {
+ p_sph_info->mic_delay_ms = AudioSmartPaController::getInstance()->getSmartPaDelayUs() / 1000;
+ } else {
+ p_sph_info->mic_delay_ms = 0;
+ }
+ break;
+#endif
+#ifdef MTK_USB_PHONECALL
+ case SPH_EXT_DEV_INFO_USB_AUDIO:
+ getUsbDelayTime(&p_sph_info->mic_delay_ms);
+ break;
+#endif
+ default:
+ p_sph_info->mic_delay_ms = 0;
+ }
+ ASSERT(p_sph_info->mic_delay_ms <= 64); /* modem limitation */
+
+ /* driver param */
+#if defined(MTK_SPEECH_USIP_EMI_SUPPORT)
+ getDriverParam(DRIVER_PARAM_COMMON_PAR, &p_sph_info->drv_common_param);
+ getDriverParam(DRIVER_PARAM_DEBUG_INFO, &p_sph_info->drv_debug_info);
+#endif
+
+ /* speech enhancement function dynamic mask */
+ sph_enh_mask_struct_t mask = SpeechEnhancementController::GetInstance()->GetSpeechEnhancementMask();
+ p_sph_info->enh_dynamic_ctrl = speechEnhancementMaskWrapper(mask.dynamic_func);
+
+#if defined(MTK_DTMF_REMOVAL_SUPPORT)
+ p_sph_info->dtmf_removal_flag = true;
+#else
+ p_sph_info->dtmf_removal_flag = false;
+#endif
+
+ /* dump info */
+ ALOGD("%s(), app: %d, bt: %d, rate enum: %d, opendsp: %d, path: %d, param emi valid: %d, param size: 0x%x, "
+ "param index: 0x%x, ext_dev_info: %d, loopback_flag: 0x%x, loopback_delay: %d, aec delay: %d, mic delay: %d"
+ "enh_dynamic_ctrl: 0x%x, usip param size: 0x%x, usip param index: 0x%x, com par[0]: %d, debug info[0]: %d, "
+ "dtmf_removal_flag: %d",
+ __FUNCTION__,
+ p_sph_info->application,
+ p_sph_info->bt_info,
+ p_sph_info->sample_rate_enum,
+ p_sph_info->opendsp_flag,
+ p_sph_info->sph_param_path,
+ p_sph_info->sph_param_valid,
+ p_sph_info->sph_param_length,
+ p_sph_info->sph_param_index,
+ p_sph_info->ext_dev_info,
+ p_sph_info->loopback_flag,
+ p_sph_info->loopback_delay,
+ p_sph_info->echo_ref_delay_ms,
+ p_sph_info->mic_delay_ms,
+ p_sph_info->enh_dynamic_ctrl,
+ p_sph_info->sph_param_usip_length,
+ p_sph_info->sph_param_usip_index,
+ p_sph_info->drv_common_param[0],
+ p_sph_info->drv_debug_info[0],
+ p_sph_info->dtmf_removal_flag);
+
+ return 0;
+}
+
+
+int SpeechDriverNormal::configMailBox(
+ sph_msg_t *p_sph_msg,
+ uint16_t msg_id,
+ uint16_t param_16bit,
+ uint32_t param_32bit) {
+
+ if (p_sph_msg == NULL) {
+ return -EFAULT;
+ }
+
+ memset(p_sph_msg, 0, sizeof(sph_msg_t));
+
+ p_sph_msg->buffer_type = SPH_MSG_BUFFER_TYPE_MAILBOX;
+ p_sph_msg->msg_id = msg_id;
+ p_sph_msg->param_16bit = param_16bit;
+ p_sph_msg->param_32bit = param_32bit;
+
+ return 0;
+}
+
+
+int SpeechDriverNormal::configPayload(
+ sph_msg_t *p_sph_msg,
+ uint16_t msg_id,
+ uint16_t data_type,
+ void *data_addr,
+ uint16_t data_size) {
+
+ if (p_sph_msg == NULL) {
+ return -EFAULT;
+ }
+
+ memset(p_sph_msg, 0, sizeof(sph_msg_t));
+
+ p_sph_msg->buffer_type = SPH_MSG_BUFFER_TYPE_PAYLOAD;
+ p_sph_msg->msg_id = msg_id;
+
+ p_sph_msg->payload_data_type = data_type;
+ p_sph_msg->payload_data_size = data_size;
+ p_sph_msg->payload_data_addr = data_addr;
+
+ return 0;
+}
+
+
+int SpeechDriverNormal::sendMailbox(sph_msg_t *p_sph_msg,
+ uint16_t msg_id,
+ uint16_t param_16bit,
+ uint32_t param_32bit) {
+ configMailBox(p_sph_msg, msg_id, param_16bit, param_32bit);
+ if (isApMsgBypassQueue(p_sph_msg) == true) {
+ return sendSpeechMessageToModem(p_sph_msg);
+ } else {
+ return sendSpeechMessageToQueue(p_sph_msg);
+ }
+}
+
+
+int SpeechDriverNormal::sendPayload(sph_msg_t *p_sph_msg,
+ uint16_t msg_id,
+ uint16_t data_type,
+ void *data_buf,
+ uint16_t data_size) {
+ configPayload(p_sph_msg, msg_id, data_type, data_buf, data_size);
+ if (isApMsgBypassQueue(p_sph_msg) == true) {
+ return sendSpeechMessageToModem(p_sph_msg);
+ } else {
+ return sendSpeechMessageToQueue(p_sph_msg);
+ }
+}
+
+
+/*==============================================================================
+ * queue
+ *============================================================================*/
+
+int SpeechDriverNormal::sendSpeechMessageToQueue(sph_msg_t *p_sph_msg) {
+
+ /* error handling */
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ if (mSpeechMessageQueue == NULL) {
+ ALOGW("%s(), mSpeechMessageQueue == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ uint32_t block_thread_ms = getBlockThreadTimeMsByID(p_sph_msg);
+ return mSpeechMessageQueue->sendSpeechMessageToQueue(p_sph_msg, block_thread_ms);
+}
+
+
+int SpeechDriverNormal::sendSpeechMessageAckToQueue(sph_msg_t *p_sph_msg) {
+
+ /* error handling */
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ if (isMdAckBack(p_sph_msg) == false) {
+ ALOGW("%s(), isMdAckBack(0x%x) failed!! return", __FUNCTION__, p_sph_msg->msg_id);
+ return -EFAULT;
+ }
+
+ if (mSpeechMessageQueue == NULL) {
+ ALOGW("%s(), mSpeechMessageQueue == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ return mSpeechMessageQueue->sendSpeechMessageAckToQueue(p_sph_msg);
+}
+
+
+int SpeechDriverNormal::sendSpeechMessageToModemWrapper(void *arg, sph_msg_t *p_sph_msg) {
+ SpeechDriverNormal *pSpeechDriver = static_cast<SpeechDriverNormal *>(arg);
+
+ if (pSpeechDriver == NULL) {
+ ALOGE("%s(), static_cast failed!!", __FUNCTION__);
+ return -EMEDIUMTYPE;
+ }
+
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ return pSpeechDriver->sendSpeechMessageToModem(p_sph_msg);
+}
+
+
+int SpeechDriverNormal::sendSpeechMessageToModem(sph_msg_t *p_sph_msg) {
+ /* only config modem error state here to using lock to protect it */
+ static AudioLock send_message_lock;
+ static bool b_epof = (get_uint32_from_mixctrl(kPropertyKeyModemEPOF) != 0);
+ static bool b_modem_crash_during_call = false;
+ static bool b_during_call = false;
+
+ struct timespec ts_start;
+ struct timespec ts_stop;
+ uint64_t time_diff_msg = 0;
+
+ int retval = 0;
+
+ AL_AUTOLOCK_MS(send_message_lock, MAX_SPEECH_AUTO_LOCK_TIMEOUT_MS);
+
+ /* error handling */
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ if (mSpeechMessenger == NULL) {
+ ALOGW("%s(), mSpeechMessenger == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ AL_LOCK(mApWaitAckMsgIDLock);
+ /* send message to modem */
+ if ((b_epof == true || b_modem_crash_during_call == true || mModemResetDuringSpeech == true) &&
+ p_sph_msg->msg_id != MSG_A2M_MD_ALIVE_ACK_BACK) {
+ ALOGW("%s(), b_epof: %d, b_modem_crash_during_call: %d, mModemResetDuringSpeech: %d!! bypass msg 0x%x", __FUNCTION__,
+ b_epof, b_modem_crash_during_call, mModemResetDuringSpeech, p_sph_msg->msg_id);
+ retval = -EPIPE;
+ } else {
+ retval = mSpeechMessenger->sendSpeechMessage(p_sph_msg);
+ }
+
+ if (retval == 0) {
+ if (isNeedDumpMsg(p_sph_msg) == true) {
+ PRINT_SPH_MSG(ALOGD, "send msg done", p_sph_msg);
+ } else {
+ PRINT_SPH_MSG(SPH_LOG_D, "send msg done", p_sph_msg);
+ }
+ } else if (retval != 0) {
+ PRINT_SPH_MSG(ALOGE, "send msg failed!!", p_sph_msg);
+ /* notate whether modem crashed during phone call or not */
+ /* cannot use GetApSideModemStatus because need lock protect it */
+ }
+
+ /* ctrl msg need ack, keep in property */
+ if (retval == 0 && isApNeedAck(p_sph_msg) == true) {
+ setApWaitAckMsgID(p_sph_msg);
+ }
+ AL_UNLOCK(mApWaitAckMsgIDLock);
+
+ /* config modem state for error handling */
+ switch (p_sph_msg->msg_id) {
+ case MSG_A2M_SPH_ON:
+ b_during_call = true;
+ break;
+ case MSG_A2M_SPH_OFF:
+ /* this call is end, suppose modem will be recovered before next call */
+ b_modem_crash_during_call = false;
+ b_during_call = false;
+ break;
+ case MSG_A2M_EPOF_ACK:
+ /* enable EPOF only after EPOF ack is sent to modem!! */
+ b_epof = true;
+ set_uint32_to_mixctrl(kPropertyKeyModemEPOF, b_epof);
+ break;
+ case MSG_A2M_MD_ALIVE_ACK_BACK:
+ /* disable EPOF */
+ b_epof = false;
+ set_uint32_to_mixctrl(kPropertyKeyModemEPOF, b_epof);
+ break;
+ default:
+ break;
+ }
+
+ if (retval != 0 && b_during_call == true) {
+ b_modem_crash_during_call = true;
+ }
+ return retval;
+}
+
+
+int SpeechDriverNormal::errorHandleSpeechMessageWrapper(void *arg, sph_msg_t *p_sph_msg) {
+ SpeechDriverNormal *pSpeechDriver = static_cast<SpeechDriverNormal *>(arg);
+
+ if (pSpeechDriver == NULL) {
+ ALOGE("%s(), static_cast failed!!", __FUNCTION__);
+ return -EMEDIUMTYPE;
+ }
+
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ return pSpeechDriver->errorHandleSpeechMessage(p_sph_msg);
+}
+
+
+int SpeechDriverNormal::errorHandleSpeechMessage(sph_msg_t *p_sph_msg) {
+ /* error handling */
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ int retval = 0;
+
+ if (getSyncType(p_sph_msg->msg_id) != SPH_MSG_HANDSHAKE_AP_CTRL_NEED_ACK) {
+ PRINT_SPH_MSG(ALOGD, "no need ack. return", p_sph_msg);
+ return 0;
+ }
+
+ retval = makeFakeMdAckMsgFromApMsg(p_sph_msg);
+ if (retval != 0) {
+ PRINT_SPH_MSG(ALOGW, "make fake modem ack error!! return", p_sph_msg);
+ return retval;
+ }
+
+ PRINT_SPH_MSG(ALOGD, "make fake modem ack", p_sph_msg);
+ retval = processModemAckMessage(p_sph_msg);
+
+ return retval;
+}
+
+
+int SpeechDriverNormal::readSpeechMessageFromModem(sph_msg_t *p_sph_msg) {
+ int retval = 0;
+
+ AL_AUTOLOCK_MS(mReadMessageLock, MAX_SPEECH_AUTO_LOCK_TIMEOUT_MS);
+
+ /* error handling */
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ if (mSpeechMessenger == NULL) {
+ ALOGW("%s(), mSpeechMessenger == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ SPH_LOG_D("%s(+)", __FUNCTION__);
+ retval = mSpeechMessenger->readSpeechMessage(p_sph_msg);
+ SPH_LOG_D("%s(-), msg id 0x%x", __FUNCTION__, p_sph_msg->msg_id);
+
+ return retval;
+}
+
+
+/*==============================================================================
+ * thread
+ *============================================================================*/
+
+void SpeechDriverNormal::createThreads() {
+ int ret = 0;
+
+ mEnableThread = true;
+ ret = pthread_create(&hReadSpeechMessageThread, NULL,
+ SpeechDriverNormal::readSpeechMessageThread,
+ (void *)this);
+ ASSERT(ret == 0);
+}
+
+
+void SpeechDriverNormal::joinThreads() {
+ mEnableThread = false;
+
+ pthread_join(hReadSpeechMessageThread, NULL);
+}
+
+
+void *SpeechDriverNormal::readSpeechMessageThread(void *arg) {
+ SpeechDriverNormal *pSpeechDriver = NULL;
+ sph_msg_t sph_msg;
+ int retval = 0;
+
+ char thread_name[128] = {0};
+ CONFIG_THREAD(thread_name, ANDROID_PRIORITY_AUDIO);
+
+ pSpeechDriver = static_cast<SpeechDriverNormal *>(arg);
+ if (pSpeechDriver == NULL) {
+ ALOGE("%s(), NULL!! pSpeechDriver %p", __FUNCTION__, pSpeechDriver);
+ goto READ_MSG_THREAD_DONE;
+ }
+
+ AL_LOCK(pSpeechDriver->mReadMsgThreadCreatedLock);
+ pSpeechDriver->mReadMsgThreadCreated = true;
+ // signal ap recovery process
+ if (pSpeechDriver->mNeedWaitModemAckAfterApDie == true) {
+ AL_SIGNAL(pSpeechDriver->mReadMsgThreadCreatedLock);
+ }
+ AL_UNLOCK(pSpeechDriver->mReadMsgThreadCreatedLock);
+
+ while (pSpeechDriver->mEnableThread == true) {
+ /* wait until modem message comes */
+ memset(&sph_msg, 0, sizeof(sph_msg_t));
+ retval = pSpeechDriver->readSpeechMessageFromModem(&sph_msg);
+ if (retval != 0) {
+ ALOGV("%s(), readSpeechMessageFromModem failed!!", __FUNCTION__);
+ usleep(100 * 1000);
+ continue;
+ }
+ pSpeechDriver->processModemMessage(&sph_msg);
+ }
+
+
+READ_MSG_THREAD_DONE:
+ ALOGV("%s terminated", thread_name);
+ pthread_exit(NULL);
+ pSpeechDriver->mReadMsgThreadCreated = false;
+ return NULL;
+}
+
+
+void SpeechDriverNormal::createThreadsDuringSpeech() {
+ int ret = 0;
+
+ mEnableThreadDuringSpeech = true;
+ ret = pthread_create(&hModemStatusMonitorThread, NULL,
+ SpeechDriverNormal::modemStatusMonitorThread,
+ (void *)this);
+ ASSERT(ret == 0);
+}
+
+
+void SpeechDriverNormal::joinThreadsDuringSpeech() {
+ if (mEnableThreadDuringSpeech == true) {
+ AL_LOCK_MS(mModemStatusMonitorThreadLock, MAX_SPEECH_AUTO_LOCK_TIMEOUT_MS);
+ mEnableThreadDuringSpeech = false;
+ AL_SIGNAL(mModemStatusMonitorThreadLock);
+ AL_UNLOCK(mModemStatusMonitorThreadLock);
+
+ pthread_join(hModemStatusMonitorThread, NULL);
+ }
+}
+
+
+void *SpeechDriverNormal::modemStatusMonitorThread(void *arg) {
+ SpeechDriverNormal *pSpeechDriver = NULL;
+ SpeechMessageQueue *pSpeechMessageQueue = NULL;
+
+ int retval = 0;
+
+ char thread_name[128] = {0};
+ CONFIG_THREAD(thread_name, ANDROID_PRIORITY_AUDIO);
+
+ pSpeechDriver = static_cast<SpeechDriverNormal *>(arg);
+
+ if (pSpeechDriver == NULL) {
+ ALOGE("%s(), NULL!! pSpeechDriver %p", __FUNCTION__, pSpeechDriver);
+ goto MODEM_STATUS_MONITOR_THREAD_DONE;
+ }
+
+ pSpeechMessageQueue = pSpeechDriver->mSpeechMessageQueue;
+ if (pSpeechMessageQueue == NULL) {
+ ALOGE("%s(), NULL!! pSpeechMessageQueue %p", __FUNCTION__, pSpeechMessageQueue);
+ goto MODEM_STATUS_MONITOR_THREAD_DONE;
+ }
+
+ while (pSpeechDriver->mEnableThreadDuringSpeech == true) {
+ if (pSpeechDriver->CheckModemIsReady() == false) {
+ ALOGW("%s(), modem status error!! notify queue", __FUNCTION__);
+
+ AL_LOCK(pSpeechDriver->mModemDeadLock);
+ pSpeechDriver->mModemDead = true;
+ pSpeechDriver->mModemResetDuringSpeech = true;
+ pSpeechMessageQueue->notifyQueueToStopWaitingAck();
+ AL_UNLOCK(pSpeechDriver->mModemDeadLock);
+ break;
+ }
+
+ AL_LOCK_MS(pSpeechDriver->mModemStatusMonitorThreadLock, MAX_SPEECH_AUTO_LOCK_TIMEOUT_MS);
+ AL_WAIT_MS(pSpeechDriver->mModemStatusMonitorThreadLock, 200); // check status each 200 ms
+ AL_UNLOCK(pSpeechDriver->mModemStatusMonitorThreadLock);
+ }
+
+
+MODEM_STATUS_MONITOR_THREAD_DONE:
+ ALOGV("%s terminated", thread_name);
+ pthread_exit(NULL);
+ return NULL;
+}
+
+
+/*==============================================================================
+ * process msg
+ *============================================================================*/
+
+int SpeechDriverNormal::processModemMessage(sph_msg_t *p_sph_msg) {
+ struct timespec ts_start;
+ struct timespec ts_stop;
+ uint64_t time_diff_msg = 0;
+
+ int retval = 0;
+
+ /* error handling */
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ /* get time for start */
+ audio_get_timespec_monotonic(&ts_start);
+
+ /* process modem message */
+ switch (getSyncType(p_sph_msg->msg_id)) {
+ case SPH_MSG_HANDSHAKE_MD_ACK_BACK_AP_CTRL:
+ AL_LOCK(mModemDeadLock);
+ if (mModemDead) {
+ ALOGW("%s(), modem is dead, do not process msg:0x%x", __FUNCTION__, p_sph_msg->msg_id);
+ AL_UNLOCK(mModemDeadLock);
+ break;
+ }
+ retval = processModemAckMessage(p_sph_msg);
+ /* check need wait ack after ap die */
+ if (mNeedWaitModemAckAfterApDie) {
+ mNeedWaitModemAckAfterApDie = false;
+ /* notify waitModemAckAfterApDie */
+ AL_LOCK(mWaitModemAckAfterApDieLock);
+ AL_SIGNAL(mWaitModemAckAfterApDieLock);
+ AL_UNLOCK(mWaitModemAckAfterApDieLock);
+ } else { /* notify message queue */
+ sendSpeechMessageAckToQueue(p_sph_msg);
+ }
+ AL_UNLOCK(mModemDeadLock);
+ break;
+ case SPH_MSG_HANDSHAKE_MD_CTRL_BYPASS_ACK:
+ case SPH_MSG_HANDSHAKE_MD_CTRL_NEED_ACK:
+ retval = processModemControlMessage(p_sph_msg);
+ break;
+ case SPH_MSG_HANDSHAKE_MD_REQUEST_DATA:
+ case SPH_MSG_HANDSHAKE_MD_NOTIFY_DATA:
+ retval = processModemDataMessage(p_sph_msg);
+ break;
+ default:
+ ALOGW("%s(), p_sph_msg->msg_id 0x%x not support!!", __FUNCTION__, p_sph_msg->msg_id);
+ retval = -EINVAL;
+ }
+
+ /* get time for stop */
+ audio_get_timespec_monotonic(&ts_stop);
+ time_diff_msg = get_time_diff_ms(&ts_start, &ts_stop);
+ if (time_diff_msg >= MAX_MSG_PROCESS_TIME_MS) {
+ ALOGW("%s(), msg 0x%x process time %ju ms is too long", __FUNCTION__,
+ p_sph_msg->msg_id, time_diff_msg);
+ }
+
+ /* NOTICE: Must copy payload/modem data before return!! */
+ return retval;
+}
+
+
+int SpeechDriverNormal::processModemAckMessage(sph_msg_t *p_sph_msg) {
+ AL_LOCK(mApWaitAckMsgIDLock);
+ if (mApWaitAckMsgID > 0) {
+ // if ack match waitAckMsg, reset property
+ if (isAckMessageInPairByID(mApWaitAckMsgID, p_sph_msg->msg_id)) {
+ resetApWaitAckMsgID();
+ ALOGV("%s(), reset property, ack:0x%x ", __FUNCTION__, p_sph_msg->msg_id);
+ } else {
+ ALOGW("%s(), ack:0x%x not in pair with msg:0x%x!", __FUNCTION__,
+ p_sph_msg->msg_id, mApWaitAckMsgID);
+ WARNING("ack not in pair with msg!");
+ }
+ }
+ AL_UNLOCK(mApWaitAckMsgIDLock);
+ /* config modem status */
+ switch (p_sph_msg->msg_id) {
+ case MSG_M2A_MUTE_SPH_UL_ACK:
+ break;
+ case MSG_M2A_MUTE_SPH_DL_ACK:
+ break;
+ case MSG_M2A_MUTE_SPH_UL_SOURCE_ACK:
+ break;
+ case MSG_M2A_SPH_ON_ACK:
+ setModemSideModemStatus(SPEECH_STATUS_MASK);
+ break;
+ case MSG_M2A_SPH_OFF_ACK:
+ if (mSpeechMessenger != NULL) { mSpeechMessenger->resetShareMemoryIndex(); }
+ joinThreadsDuringSpeech();
+ mSpeechMessageQueue->resetStopWaitAckFlag();
+ resetModemSideModemStatus(SPEECH_STATUS_MASK);
+ set_string_to_property(kPropertyKeyRilSphCodecInfo, "");
+ set_string_to_property(kPropertyKeyRilHdVoiceStatus, "");
+ break;
+ case MSG_M2A_SPH_DEV_CHANGE_ACK:
+ break;
+ case MSG_M2A_PNW_ON_ACK:
+ setModemSideModemStatus(P2W_STATUS_MASK);
+ break;
+ case MSG_M2A_PNW_OFF_ACK:
+ resetModemSideModemStatus(P2W_STATUS_MASK);
+ break;
+ case MSG_M2A_VM_REC_ON_ACK:
+ setModemSideModemStatus(VM_RECORD_STATUS_MASK);
+ break;
+ case MSG_M2A_VM_REC_OFF_ACK:
+ resetModemSideModemStatus(VM_RECORD_STATUS_MASK);
+ break;
+ case MSG_M2A_RECORD_RAW_PCM_ON_ACK:
+ setModemSideModemStatus(RAW_RECORD_STATUS_MASK);
+ break;
+ case MSG_M2A_RECORD_RAW_PCM_OFF_ACK:
+ resetModemSideModemStatus(RAW_RECORD_STATUS_MASK);
+ break;
+ case MSG_M2A_CTM_ON_ACK:
+ setModemSideModemStatus(TTY_STATUS_MASK);
+ break;
+ case MSG_M2A_CTM_OFF_ACK:
+ resetModemSideModemStatus(TTY_STATUS_MASK);
+ break;
+ case MSG_M2A_BGSND_ON_ACK:
+ setModemSideModemStatus(BGS_STATUS_MASK);
+ break;
+ case MSG_M2A_BGSND_OFF_ACK:
+ resetModemSideModemStatus(BGS_STATUS_MASK);
+ break;
+ case MSG_M2A_EM_DYNAMIC_SPH_ACK:
+ break;
+ case MSG_M2A_DYNAMIC_PAR_IN_STRUCT_SHM_ACK:
+ break;
+ case MSG_M2A_VIBSPK_PARAMETER_ACK:
+ break;
+ case MSG_M2A_SMARTPA_PARAMETER_ACK:
+ break;
+ case MSG_M2A_PCMMIXER_ON_ACK:
+ setModemSideModemStatus(PCM_MIXER_STATUS_MASK);
+ break;
+ case MSG_M2A_PCMMIXER_OFF_ACK:
+ resetModemSideModemStatus(PCM_MIXER_STATUS_MASK);
+ break;
+ case MSG_M2A_ECALL_CTL_SEQ_SWITCH_ACK:
+ case MSG_M2A_IVS_SWITCH_ACK:
+ case MSG_M2A_PSAP_SWITCH_ACK:
+ case MSG_M2A_ECALL_MSD_ACK:
+ case MSG_M2A_ECALL_TX_CTRL_PAR_ACK:
+ break;
+
+ default:
+ ALOGE("%s(), not supported msg_id 0x%x", __FUNCTION__, p_sph_msg->msg_id);
+ }
+
+ return 0;
+}
+
+
+void SpeechDriverNormal::processModemEPOF() {
+ /* send EPOF ack to modem */
+ sph_msg_t sph_msg;
+ sendMailbox(&sph_msg, MSG_A2M_EPOF_ACK, 0, 0);
+
+ /* notify queue */
+ if (mSpeechMessageQueue != NULL) { mSpeechMessageQueue->notifyQueueToStopWaitingAck(); }
+}
+
+
+void SpeechDriverNormal::processModemAlive(sph_msg_t *sphMsg) {
+#if defined(MTK_SPEECH_USIP_EMI_SUPPORT)
+ MdAliveInfo mdAliveInfo;
+ MdAliveInfo *pMdAliveInfo = NULL;
+
+ uint16_t dataType = 0;
+ uint16_t dataSize = 0;
+
+ int retval = 0;
+
+ /* error handling */
+ if (sphMsg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return;
+ }
+ ALOGD("%s(), buffer_type=0x%x, length=0x%x, read_idx=0x%x",
+ __FUNCTION__, sphMsg->buffer_type, sphMsg->length, sphMsg->rw_index);
+
+ if (sphMsg->buffer_type == SPH_MSG_BUFFER_TYPE_MAILBOX) { // via share memory
+ dataSize = sizeof(MdAliveInfo);
+ retval = mSpeechMessenger->readMdDataFromShareMemory(
+ &mdAliveInfo,
+ &dataType,
+ &dataSize,
+ sphMsg->length,
+ sphMsg->rw_index);
+ if (retval != 0) {
+ PRINT_SPH_MSG(ALOGW, "get share memory md data failed!! drop it", sphMsg);
+ return;
+ }
+ pMdAliveInfo = &mdAliveInfo;
+ } else if (sphMsg->buffer_type == SPH_MSG_BUFFER_TYPE_PAYLOAD) { // via payload
+ ASSERT(sphMsg->payload_data_idx == sphMsg->payload_data_total_idx);
+
+ pMdAliveInfo = (MdAliveInfo *)sphMsg->payload_data_addr;
+ dataType = sphMsg->payload_data_type;
+ dataSize = sphMsg->payload_data_size;
+ } else {
+ PRINT_SPH_MSG(ALOGW, "bad buffer_type!!", sphMsg);
+ return;
+ }
+
+ /* check value */
+ if (dataType != SHARE_BUFF_DATA_TYPE_CCCI_MD_ALIVE_INFO) {
+ PRINT_SPH_MSG(ALOGE, "bad data_type!!", sphMsg);
+ WARNING("bad data_type!!");
+ return;
+ }
+
+ if (dataSize != sizeof(MdAliveInfo)) {
+ PRINT_SPH_MSG(ALOGE, "bad data_size!!", sphMsg);
+ WARNING("bad data_size!!");
+ return;
+ }
+ memcpy(&mMdAliveInfo, pMdAliveInfo, sizeof(MdAliveInfo));
+ /* set network info in property */
+ ALOGD("%s(), headerMdVersion: 0x%x, mdVersion: 0x%x",
+ __FUNCTION__,
+ mMdAliveInfo.headerMdVersion,
+ mMdAliveInfo.mdVersion);
+#else
+ (void) sphMsg;
+#endif
+
+ /* set mStopWaitAck when EPOF and reset when MD alive */
+ if (mSpeechMessageQueue != NULL) { mSpeechMessageQueue->resetStopWaitAckFlag(); }
+
+ /* send alive ack to modem */
+ sph_msg_t sph_msg;
+ sendMailbox(&sph_msg, MSG_A2M_MD_ALIVE_ACK_BACK, 0, 0);
+ //notify event to do reopen voice call
+ if (GetApSideModemStatus(SPEECH_STATUS_MASK)) {
+ AudioEventThreadManager::getInstance()->notifyCallback(AUDIO_EVENT_PHONECALL_REOPEN, this);
+ }
+}
+
+
+void SpeechDriverNormal::processNetworkCodecInfo(sph_msg_t *p_sph_msg) {
+ spcCodecInfoStruct codec_info;
+ spcCodecInfoStruct *p_codec_info = NULL;
+
+ uint16_t data_type = 0;
+ uint16_t data_size = 0;
+
+ int retval = 0;
+
+ /* error handling */
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return;
+ }
+
+ if (mApResetDuringSpeech == true) {
+ PRINT_SPH_MSG(ALOGW, "mApResetDuringSpeech == true!! drop md data", p_sph_msg);
+ return;
+ }
+
+
+ if (p_sph_msg->buffer_type == SPH_MSG_BUFFER_TYPE_MAILBOX) { // via share memory
+ data_size = sizeof(spcCodecInfoStruct);
+ retval = mSpeechMessenger->readMdDataFromShareMemory(
+ &codec_info,
+ &data_type,
+ &data_size,
+ p_sph_msg->length,
+ p_sph_msg->rw_index);
+ if (retval != 0) {
+ PRINT_SPH_MSG(ALOGW, "get share memory md data failed!! drop it", p_sph_msg);
+ return;
+ }
+
+ p_codec_info = &codec_info;
+ } else if (p_sph_msg->buffer_type == SPH_MSG_BUFFER_TYPE_PAYLOAD) { // via payload
+ ASSERT(p_sph_msg->payload_data_idx == p_sph_msg->payload_data_total_idx);
+
+ p_codec_info = (spcCodecInfoStruct *)p_sph_msg->payload_data_addr;
+ data_type = p_sph_msg->payload_data_type;
+ data_size = p_sph_msg->payload_data_size;
+ } else {
+ PRINT_SPH_MSG(ALOGW, "bad buffer_type!!", p_sph_msg);
+ return;
+ }
+
+ /* check value */
+ if (data_type != SHARE_BUFF_DATA_TYPE_CCCI_NW_CODEC_INFO) {
+ PRINT_SPH_MSG(ALOGE, "bad data_type!!", p_sph_msg);
+ WARNING("bad data_type!!");
+ return;
+ }
+
+ if (data_size != sizeof(spcCodecInfoStruct)) {
+ PRINT_SPH_MSG(ALOGE, "bad data_size!!", p_sph_msg);
+ WARNING("bad data_size!!");
+ return;
+ }
+
+ /* set network info in property */
+ ALOGD("%s(), length: 0x%x, rw_index: 0x%x, %s: \"%s\", %s: \"%s\"",
+ __FUNCTION__,
+ p_sph_msg->length,
+ p_sph_msg->rw_index,
+ kPropertyKeyRilSphCodecInfo, p_codec_info->codecInfo,
+ kPropertyKeyRilHdVoiceStatus, p_codec_info->codecOp);
+ set_string_to_property(kPropertyKeyRilSphCodecInfo, p_codec_info->codecInfo);
+ set_string_to_property(kPropertyKeyRilHdVoiceStatus, p_codec_info->codecOp);
+
+ /* send read ack to modem */
+ sph_msg_t sph_msg;
+ sendMailbox(&sph_msg, MSG_A2M_NW_CODEC_INFO_READ_ACK, 0, 0);
+}
+
+
+int SpeechDriverNormal::processModemControlMessage(sph_msg_t *p_sph_msg) {
+ switch (p_sph_msg->msg_id) {
+ case MSG_M2A_EPOF_NOTIFY: /* need ack */
+ PRINT_SPH_MSG(ALOGD, "EPOF!!", p_sph_msg);
+ processModemEPOF();
+ break;
+ case MSG_M2A_MD_ALIVE: /* need ack */
+ PRINT_SPH_MSG(ALOGD, "MD Alive", p_sph_msg);
+ mModemDead = false;
+ processModemAlive(p_sph_msg);
+ break;
+ case MSG_M2A_EM_DATA_REQUEST: /* bypass ack */
+ break; /* lagecy control, do nothing after 93 modem */
+ case MSG_M2A_NETWORK_STATUS_NOTIFY: /* bypass ack */
+ ALOGV("%s(), %s: %d", __FUNCTION__, kPropertyKeyRfMode, p_sph_msg->param_16bit);
+ set_uint32_to_property(kPropertyKeyRfMode, p_sph_msg->param_16bit);
+#ifdef MTK_AUDIO_GAIN_TABLE // speech network type change
+ AudioVolumeFactory::CreateAudioVolumeController()->speechNetworkChange(p_sph_msg->param_16bit);
+#endif
+ break;
+ case MSG_M2A_NW_CODEC_INFO_NOTIFY: /* need ack */
+ processNetworkCodecInfo(p_sph_msg);
+ break;
+#if defined(MTK_SPEECH_ECALL_SUPPORT)
+ case MSG_M2A_ECALL_HANDSHAKE_INFO:
+ ALOGD("%s(), msg_id:0x%x ", __FUNCTION__, p_sph_msg->msg_id);
+ ALOGD("%s(), msg_id:0x%d ", __FUNCTION__, p_sph_msg->param_16bit);
+
+ if (p_sph_msg->param_16bit == 0xE1) {
+ usleep(10 * 1000); /* 10 ms */
+ }
+
+ mEcallIndication.header = p_sph_msg->param_16bit;
+ mEcallIndication.data = p_sph_msg->param_32bit;
+
+ AudioEventThreadManager::getInstance()->notifyCallback(AUDIO_EVENT_ECALL_INDICATION, this);
+ break;
+#endif
+
+ default:
+ ALOGE("%s(), not supported msg_id 0x%x", __FUNCTION__, p_sph_msg->msg_id);
+ }
+
+ return 0;
+}
+
+
+int SpeechDriverNormal::parseRawRecordPcmBuffer(void *raw_buf, void *parsed_buf, uint16_t *p_data_size) {
+ spcRAWPCMBufInfo header_RawPcmBufInfo;
+ spcApRAWPCMBufHdr header_ApRawPcmBuf;
+
+ uint16_t BytesCopied = 0;
+ uint16_t BytesToCopy = 0;
+
+ char *PtrTarget = NULL;
+ char *PtrSource = NULL;
+
+ int retval = 0;
+
+ // share buffer header
+ memcpy(&header_RawPcmBufInfo, raw_buf, sizeof(spcRAWPCMBufInfo));
+ PtrTarget = (char *)parsed_buf;
+
+ AL_AUTOLOCK(mRecordTypeLock);
+ switch (mRecordType.direction) {
+ case RECORD_TYPE_UL:
+ header_ApRawPcmBuf.u16SyncWord = TEMP_CCCI_MD_PAYLOAD_SYNC;
+ header_ApRawPcmBuf.u16RawPcmDir = RECORD_TYPE_UL;
+ header_ApRawPcmBuf.u16Freq = sph_sample_rate_enum_to_value(header_RawPcmBufInfo.u16ULFreq);
+ header_ApRawPcmBuf.u16Length = header_RawPcmBufInfo.u16ULLength;
+ header_ApRawPcmBuf.u16Channel = 1;
+ header_ApRawPcmBuf.u16BitFormat = AUDIO_FORMAT_PCM_16_BIT;
+
+ // uplink raw pcm header
+ memcpy(PtrTarget, &header_ApRawPcmBuf, sizeof(spcApRAWPCMBufHdr));
+ BytesCopied = sizeof(spcApRAWPCMBufHdr);
+
+ //uplink raw pcm
+ PtrTarget = (char *)parsed_buf + BytesCopied;
+ PtrSource = (char *)raw_buf + sizeof(spcRAWPCMBufInfo);
+ BytesToCopy = header_RawPcmBufInfo.u16ULLength;
+ memcpy(PtrTarget, PtrSource, BytesToCopy);
+ BytesCopied += BytesToCopy;
+ break;
+ case RECORD_TYPE_DL:
+ header_ApRawPcmBuf.u16SyncWord = TEMP_CCCI_MD_PAYLOAD_SYNC;
+ header_ApRawPcmBuf.u16RawPcmDir = RECORD_TYPE_DL;
+ header_ApRawPcmBuf.u16Freq = sph_sample_rate_enum_to_value(header_RawPcmBufInfo.u16DLFreq);
+ header_ApRawPcmBuf.u16Length = header_RawPcmBufInfo.u16DLLength;
+ header_ApRawPcmBuf.u16Channel = 1;
+ header_ApRawPcmBuf.u16BitFormat = AUDIO_FORMAT_PCM_16_BIT;
+
+ // downlink raw pcm header
+ memcpy(PtrTarget, &header_ApRawPcmBuf, sizeof(spcApRAWPCMBufHdr));
+ BytesCopied = sizeof(spcApRAWPCMBufHdr);
+
+ // downlink raw pcm
+ PtrTarget = (char *)parsed_buf + BytesCopied;
+ PtrSource = (char *)raw_buf + sizeof(spcRAWPCMBufInfo) + header_RawPcmBufInfo.u16ULLength;
+ BytesToCopy = header_RawPcmBufInfo.u16DLLength;
+ memcpy(PtrTarget, PtrSource, BytesToCopy);
+ BytesCopied += BytesToCopy;
+ break;
+ case RECORD_TYPE_MIX:
+ header_ApRawPcmBuf.u16SyncWord = TEMP_CCCI_MD_PAYLOAD_SYNC;
+ header_ApRawPcmBuf.u16RawPcmDir = RECORD_TYPE_UL;
+ header_ApRawPcmBuf.u16Freq = sph_sample_rate_enum_to_value(header_RawPcmBufInfo.u16ULFreq);
+ header_ApRawPcmBuf.u16Length = header_RawPcmBufInfo.u16ULLength;
+ header_ApRawPcmBuf.u16Channel = 1;
+ header_ApRawPcmBuf.u16BitFormat = AUDIO_FORMAT_PCM_16_BIT;
+
+ //uplink raw pcm header
+ memcpy(PtrTarget, &header_ApRawPcmBuf, sizeof(spcApRAWPCMBufHdr));
+ BytesCopied = sizeof(spcApRAWPCMBufHdr);
+
+ //uplink raw pcm
+ PtrTarget = (char *)parsed_buf + BytesCopied;
+ PtrSource = (char *)raw_buf + sizeof(spcRAWPCMBufInfo);
+ BytesToCopy = header_RawPcmBufInfo.u16ULLength;
+ memcpy(PtrTarget, PtrSource, BytesToCopy);
+ BytesCopied += BytesToCopy;
+
+ PtrTarget = (char *)parsed_buf + BytesCopied;
+
+ //downlink raw pcm header
+ header_ApRawPcmBuf.u16RawPcmDir = RECORD_TYPE_DL;
+ header_ApRawPcmBuf.u16Freq = sph_sample_rate_enum_to_value(header_RawPcmBufInfo.u16DLFreq);
+ header_ApRawPcmBuf.u16Length = header_RawPcmBufInfo.u16DLLength;
+ memcpy(PtrTarget, &header_ApRawPcmBuf, sizeof(spcApRAWPCMBufHdr));
+ BytesCopied += sizeof(spcApRAWPCMBufHdr);
+
+ //downlink raw pcm
+ PtrTarget = (char *)parsed_buf + BytesCopied;
+ PtrSource = (char *)raw_buf + sizeof(spcRAWPCMBufInfo) + header_RawPcmBufInfo.u16ULLength;
+ BytesToCopy = header_RawPcmBufInfo.u16DLLength;
+ memcpy(PtrTarget, PtrSource, BytesToCopy);
+ BytesCopied += BytesToCopy;
+ break;
+ default:
+ ALOGW("%s(), mRecordType direction %d error!!", __FUNCTION__, mRecordType.direction);
+ retval = -EINVAL;
+ BytesCopied = 0;
+ break;
+ }
+
+ if (BytesCopied > *p_data_size) {
+ ALOGW("%s(), BytesCopied %u > parsed_buf size %u!!", __FUNCTION__,
+ BytesCopied, *p_data_size);
+ *p_data_size = 0;
+ WARNING("-EOVERFLOW");
+ return -EOVERFLOW;
+ }
+
+
+ *p_data_size = BytesCopied;
+
+ return retval;
+}
+
+static void dropMdDataInShareMemory(SpeechMessengerNormal *messenger, sph_msg_t *p_sph_msg) {
+ uint8_t dummy_md_data[p_sph_msg->length];
+ uint16_t data_type = 0;
+ uint16_t data_size = 0;
+
+ int retval = 0;
+
+ if (p_sph_msg->buffer_type == SPH_MSG_BUFFER_TYPE_MAILBOX) { // via share memory
+ data_size = p_sph_msg->length;
+ retval = messenger->readMdDataFromShareMemory(
+ dummy_md_data,
+ &data_type,
+ &data_size,
+ p_sph_msg->length,
+ p_sph_msg->rw_index);
+ if (retval != 0) {
+ PRINT_SPH_MSG(ALOGW, "get share memory md data failed!!", p_sph_msg);
+ }
+ }
+}
+
+int SpeechDriverNormal::processModemDataMessage(sph_msg_t *p_sph_msg) {
+ /* error handling */
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ if (mSpeechMessenger == NULL) {
+ ALOGW("%s(), mSpeechMessenger == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+
+ if (mApResetDuringSpeech == true) {
+ PRINT_SPH_MSG(ALOGW, "mApResetDuringSpeech == true!! drop md data", p_sph_msg);
+ return -ERESTART;
+ }
+
+ static BGSPlayer *pBGSPlayer = BGSPlayer::GetInstance();
+ static SpeechVMRecorder *pSpeechVMRecorder = SpeechVMRecorder::getInstance();
+#if !defined(MTK_YOCTO_AUDIO)
+ static SpeechDataProcessingHandler *pSpeechDataProcessingHandler = SpeechDataProcessingHandler::getInstance();
+#endif
+ static Record2Way *pRecord2Way = Record2Way::GetInstance();
+ static Play2Way *pPlay2Way = Play2Way::GetInstance();
+#if defined(MTK_SPEECH_VOICE_MIXER_SUPPORT)
+ static VoiceMixerPlayer *voiceMixerPlayer = VoiceMixerPlayer::getInstance();
+#endif
+
+ struct timespec ts_start;
+ struct timespec ts_stop;
+
+ uint64_t time_diff_shm = 0;
+ uint64_t time_diff_vm = 0;
+
+ sph_msg_t sph_msg;
+
+ uint16_t num_data_request = 0;
+
+ uint16_t data_type = 0;
+ uint16_t data_size = 0;
+ uint16_t payload_length = 0;
+ uint32_t write_idx = 0;
+
+ RingBuf ringbuf;
+
+ int retval = 0;
+
+
+ /* TODO: add class */
+ switch (p_sph_msg->msg_id) {
+ case MSG_M2A_BGSND_DATA_REQUEST: {
+ // fill playback data
+ if (getModemSideModemStatus(BGS_STATUS_MASK) == false) {
+ PRINT_SPH_MSG(ALOGW, "md bgs off now!! break", p_sph_msg);
+ break;
+ } else if (GetApSideModemStatus(BGS_STATUS_MASK) == false) {
+ PRINT_SPH_MSG(ALOGW, "ap bgs off now!! break", p_sph_msg);
+ break;
+ } else if (!mBgsBuf) {
+ PRINT_SPH_MSG(ALOGW, "mBgsBuf NULL!! break", p_sph_msg);
+ break;
+ } else {
+ PRINT_SPH_MSG(SPH_LOG_D, "bgs data request", p_sph_msg);
+ num_data_request = p_sph_msg->length;
+ if (num_data_request > kMaxApPayloadDataSize) {
+ num_data_request = kMaxApPayloadDataSize;
+ }
+ data_size = (uint16_t)pBGSPlayer->PutDataToSpeaker((char *)mBgsBuf, num_data_request);
+ if (getBGSLogEnableByLevel(BGS_LOG_LEVEL_MODEM)) {
+ ALOGD("%s(), bgs data request, id: 0x%x, data in md: %u, request: %d, bgs fill: %u",
+ __FUNCTION__, p_sph_msg->msg_id,
+ p_sph_msg->param_32bit, p_sph_msg->param_16bit, data_size);
+ }
+ }
+ // share memory
+ retval = mSpeechMessenger->writeApDataToShareMemory(mBgsBuf,
+ SHARE_BUFF_DATA_TYPE_CCCI_BGS_TYPE,
+ data_size,
+ &payload_length,
+ &write_idx);
+ // send data notify to modem side
+ if (retval == 0) { // via share memory
+ retval = sendMailbox(&sph_msg, MSG_A2M_BGSND_DATA_NOTIFY, payload_length, write_idx);
+ } else { // via payload
+ retval = sendPayload(&sph_msg, MSG_A2M_BGSND_DATA_NOTIFY,
+ SHARE_BUFF_DATA_TYPE_CCCI_BGS_TYPE,
+ mBgsBuf, data_size);
+ }
+
+ break;
+ }
+ case MSG_M2A_VM_REC_DATA_NOTIFY: {
+ if (getModemSideModemStatus(VM_RECORD_STATUS_MASK) == false) {
+ PRINT_SPH_MSG(ALOGW, "md vm rec off now!! drop it", p_sph_msg);
+ break;
+ } else if (GetApSideModemStatus(VM_RECORD_STATUS_MASK) == false) {
+ PRINT_SPH_MSG(ALOGW, "ap vm rec off now!! drop it", p_sph_msg);
+ dropMdDataInShareMemory(mSpeechMessenger, p_sph_msg);
+ break;
+ } else if (!mVmRecBuf) {
+ PRINT_SPH_MSG(ALOGW, "mVmRecBuf NULL!! drop it", p_sph_msg);
+ dropMdDataInShareMemory(mSpeechMessenger, p_sph_msg);
+ break;
+ } else {
+ PRINT_SPH_MSG(SPH_LOG_V, "vm rec data notify", p_sph_msg);
+ time_diff_shm = 0;
+ time_diff_vm = 0;
+
+ /* get vm data */
+ if (p_sph_msg->buffer_type == SPH_MSG_BUFFER_TYPE_MAILBOX) { // via share memory
+ data_size = MAX_VM_RECORD_SIZE;
+
+ audio_get_timespec_monotonic(&ts_start);
+ retval = mSpeechMessenger->readMdDataFromShareMemory(
+ mVmRecBuf,
+ &data_type,
+ &data_size,
+ p_sph_msg->length,
+ p_sph_msg->rw_index);
+ audio_get_timespec_monotonic(&ts_stop);
+ time_diff_shm = get_time_diff_ms(&ts_start, &ts_stop);
+
+ if (retval != 0) {
+ PRINT_SPH_MSG(ALOGW, "get share memory md data failed!! drop it", p_sph_msg);
+ } else {
+ sendMailbox(&sph_msg, MSG_A2M_VM_REC_DATA_READ_ACK,
+ p_sph_msg->length, p_sph_msg->rw_index);
+ }
+ } else if (p_sph_msg->buffer_type == SPH_MSG_BUFFER_TYPE_PAYLOAD) { // via payload
+ if (p_sph_msg->payload_data_size > kMaxMdPayloadDataSize) {
+ PRINT_SPH_MSG(ALOGW, "get share memory md data failed!! drop it", p_sph_msg);
+ retval = -ENOMEM;
+ } else {
+ memcpy(mVmRecBuf,
+ p_sph_msg->payload_data_addr,
+ p_sph_msg->payload_data_size);
+ data_type = p_sph_msg->payload_data_type;
+ data_size = p_sph_msg->payload_data_size;
+ if (p_sph_msg->payload_data_idx == p_sph_msg->payload_data_total_idx) {
+ sendMailbox(&sph_msg, MSG_A2M_VM_REC_DATA_READ_ACK, 0, 0);
+ }
+ }
+ } else {
+ PRINT_SPH_MSG(ALOGW, "bad buffer_type!!", p_sph_msg);
+ retval = -EINVAL;
+ }
+
+ /* copy vm data */
+ if (retval == 0) {
+ if (data_type != SHARE_BUFF_DATA_TYPE_CCCI_VM_TYPE) {
+ PRINT_SPH_MSG(ALOGW, "wrong data_type. drop it", p_sph_msg);
+ retval = -EINVAL;
+ } else if (data_size > 0) {
+ ringbuf.pBufBase = (char *)mVmRecBuf;
+ ringbuf.bufLen = data_size + 1; // +1: avoid pRead == pWrite
+ ringbuf.pRead = ringbuf.pBufBase;
+ ringbuf.pWrite = ringbuf.pBufBase + data_size;
+ audio_get_timespec_monotonic(&ts_start);
+ pSpeechVMRecorder->getVmDataFromModem(ringbuf);
+ audio_get_timespec_monotonic(&ts_stop);
+ time_diff_vm = get_time_diff_ms(&ts_start, &ts_stop);
+ }
+ }
+ if ((time_diff_shm + time_diff_vm) >= MAX_MSG_PROCESS_TIME_MS) {
+ ALOGW("%s(), time_diff_shm %ju, time_diff_vm %ju", __FUNCTION__, time_diff_shm, time_diff_vm);
+ }
+ }
+ break;
+ }
+#if !defined(MTK_YOCTO_AUDIO)
+ case MSG_M2A_RAW_PCM_REC_DATA_NOTIFY: {
+ if (getModemSideModemStatus(RAW_RECORD_STATUS_MASK) == false) {
+ PRINT_SPH_MSG(ALOGW, "md raw rec off now!! drop it", p_sph_msg);
+ break;
+ } else if (GetApSideModemStatus(RAW_RECORD_STATUS_MASK) == false) {
+ PRINT_SPH_MSG(ALOGW, "ap raw rec off now!! drop it", p_sph_msg);
+ dropMdDataInShareMemory(mSpeechMessenger, p_sph_msg);
+ break;
+ } else if (!mRawRecBuf || !mParsedRecBuf) {
+ PRINT_SPH_MSG(ALOGW, "mRawRecBuf or mParsedRecBuf NULL!! drop it", p_sph_msg);
+ dropMdDataInShareMemory(mSpeechMessenger, p_sph_msg);
+ break;
+ } else {
+ PRINT_SPH_MSG(SPH_LOG_V, "raw rec data notify", p_sph_msg);
+
+ /* get rec data */
+ if (p_sph_msg->buffer_type == SPH_MSG_BUFFER_TYPE_MAILBOX) { // via share memory
+ data_size = MAX_RAW_RECORD_SIZE;
+ retval = mSpeechMessenger->readMdDataFromShareMemory(
+ mRawRecBuf,
+ &data_type,
+ &data_size,
+ p_sph_msg->length,
+ p_sph_msg->rw_index);
+ if (retval != 0) {
+ PRINT_SPH_MSG(ALOGW, "get share memory md data failed!! drop it", p_sph_msg);
+ } else {
+ sendMailbox(&sph_msg, MSG_A2M_RAW_PCM_REC_DATA_READ_ACK,
+ p_sph_msg->length, p_sph_msg->rw_index);
+ }
+ } else if (p_sph_msg->buffer_type == SPH_MSG_BUFFER_TYPE_PAYLOAD) { // via payload
+ if (p_sph_msg->payload_data_size > kMaxMdPayloadDataSize) {
+ PRINT_SPH_MSG(ALOGW, "get share memory md data failed!! drop it", p_sph_msg);
+ retval = -ENOMEM;
+ } else {
+ memcpy(mRawRecBuf,
+ p_sph_msg->payload_data_addr,
+ p_sph_msg->payload_data_size);
+ data_type = p_sph_msg->payload_data_type;
+ data_size = p_sph_msg->payload_data_size;
+ if (p_sph_msg->payload_data_idx == p_sph_msg->payload_data_total_idx) {
+ sendMailbox(&sph_msg, MSG_A2M_RAW_PCM_REC_DATA_READ_ACK, 0, 0);
+ }
+ }
+ } else {
+ PRINT_SPH_MSG(ALOGW, "bad buffer_type!!", p_sph_msg);
+ retval = -EINVAL;
+ }
+
+ /* copy raw rec data */
+ if (retval == 0) {
+#if 0 // check
+ if (data_type != SHARE_BUFF_DATA_TYPE_CCCI_RAW_PCM_TYPE) {
+ PRINT_SPH_MSG(ALOGW, "wrong data_type. drop it", p_sph_msg);
+ retval = -EINVAL;
+ } else
+#endif
+ if (data_size > 0) {
+ data_size = MAX_PARSED_RECORD_SIZE;
+ retval = parseRawRecordPcmBuffer(mRawRecBuf, mParsedRecBuf, &data_size);
+ if (retval == 0) {
+ ringbuf.pBufBase = (char *)mParsedRecBuf;
+ ringbuf.bufLen = data_size + 1; // +1: avoid pRead == pWrite
+ ringbuf.pRead = ringbuf.pBufBase;
+ ringbuf.pWrite = ringbuf.pBufBase + data_size;
+
+ pSpeechDataProcessingHandler->provideModemRecordDataToProvider(ringbuf);
+ }
+ }
+ }
+ }
+ break;
+ }
+#endif
+ case MSG_M2A_PNW_UL_DATA_NOTIFY: {
+ if (getModemSideModemStatus(P2W_STATUS_MASK) == false) {
+ PRINT_SPH_MSG(ALOGW, "md p2w off now!! drop it", p_sph_msg);
+ break;
+ } else if (GetApSideModemStatus(P2W_STATUS_MASK) == false) {
+ PRINT_SPH_MSG(ALOGW, "ap p2w off now!! drop it", p_sph_msg);
+ dropMdDataInShareMemory(mSpeechMessenger, p_sph_msg);
+ break;
+ } else if (!mP2WUlBuf) {
+ PRINT_SPH_MSG(ALOGW, "mP2WUlBuf NULL!! drop it", p_sph_msg);
+ dropMdDataInShareMemory(mSpeechMessenger, p_sph_msg);
+ break;
+ } else {
+ PRINT_SPH_MSG(SPH_LOG_V, "p2w ul data notify", p_sph_msg);
+
+ /* get p2w ul data */
+ if (p_sph_msg->buffer_type == SPH_MSG_BUFFER_TYPE_MAILBOX) { // via share memory
+ data_size = MAX_PNW_UL_SIZE;
+ retval = mSpeechMessenger->readMdDataFromShareMemory(
+ mP2WUlBuf,
+ &data_type,
+ &data_size,
+ p_sph_msg->length,
+ p_sph_msg->rw_index);
+ if (retval != 0) {
+ PRINT_SPH_MSG(ALOGW, "get share memory md data failed!! drop it", p_sph_msg);
+ } else {
+ sendMailbox(&sph_msg, MSG_A2M_PNW_UL_DATA_READ_ACK,
+ p_sph_msg->length, p_sph_msg->rw_index);
+ }
+ } else if (p_sph_msg->buffer_type == SPH_MSG_BUFFER_TYPE_PAYLOAD) { // via payload
+ if (p_sph_msg->payload_data_size > kMaxMdPayloadDataSize) {
+ PRINT_SPH_MSG(ALOGW, "get share memory md data failed!! drop it", p_sph_msg);
+ retval = -ENOMEM;
+ } else {
+ memcpy(mP2WUlBuf,
+ p_sph_msg->payload_data_addr,
+ p_sph_msg->payload_data_size);
+ data_type = p_sph_msg->payload_data_type;
+ data_size = p_sph_msg->payload_data_size;
+ if (p_sph_msg->payload_data_idx == p_sph_msg->payload_data_total_idx) {
+ sendMailbox(&sph_msg, MSG_A2M_PNW_UL_DATA_READ_ACK, 0, 0);
+ }
+ }
+ } else {
+ PRINT_SPH_MSG(ALOGW, "bad buffer_type!!", p_sph_msg);
+ retval = -EINVAL;
+ }
+
+ /* copy p2w ul data */
+ if (retval == 0) {
+#if 0 // check
+ if (data_type != SHARE_BUFF_DATA_TYPE_PCM_GetFromMic) {
+ PRINT_SPH_MSG(ALOGW, "wrong data_type. drop it", p_sph_msg);
+ retval = -EINVAL;
+ } else
+#endif
+ if (data_size > 0) {
+ ringbuf.pBufBase = (char *)mP2WUlBuf;
+ ringbuf.bufLen = data_size + 1; // +1: avoid pRead == pWrite
+ ringbuf.pRead = ringbuf.pBufBase;
+ ringbuf.pWrite = ringbuf.pBufBase + data_size;
+ pRecord2Way->GetDataFromMicrophone(ringbuf);
+
+#if 0 // PCM2WAY: UL -> DL Loopback
+ // Used for debug and Speech DVT
+ uint16_t size_bytes = 320;
+ char buffer[320];
+ pRecord2Way->Read(buffer, size_bytes);
+ pPlay2Way->Write(buffer, size_bytes);
+#endif
+ }
+ }
+ }
+
+ break;
+ }
+ case MSG_M2A_PNW_DL_DATA_REQUEST: {
+ // fill p2w dl data
+ if (getModemSideModemStatus(P2W_STATUS_MASK) == false) {
+ PRINT_SPH_MSG(ALOGW, "md p2w off now!! break", p_sph_msg);
+ break;
+ } else if (GetApSideModemStatus(P2W_STATUS_MASK) == false) {
+ PRINT_SPH_MSG(ALOGW, "ap p2w off now!! break", p_sph_msg);
+ break;
+ } else if (!mP2WDlBuf) {
+ PRINT_SPH_MSG(ALOGW, "mP2WDlBuf NULL!! break", p_sph_msg);
+ break;
+ } else {
+ PRINT_SPH_MSG(SPH_LOG_D, "p2w dl data request", p_sph_msg);
+ num_data_request = p_sph_msg->length;
+ if (num_data_request > kMaxApPayloadDataSize) {
+ num_data_request = kMaxApPayloadDataSize;
+ }
+ data_size = (uint16_t)pPlay2Way->PutDataToSpeaker((char *)mP2WDlBuf, num_data_request);
+ if (data_size == 0) {
+ PRINT_SPH_MSG(ALOGW, "data_size == 0", p_sph_msg);
+#if 0
+ break;
+#endif
+ }
+ }
+ // share memory
+ retval = mSpeechMessenger->writeApDataToShareMemory(mP2WDlBuf,
+ SHARE_BUFF_DATA_TYPE_PCM_FillSpk,
+ data_size,
+ &payload_length,
+ &write_idx);
+ // send data notify to modem side
+ if (retval == 0) { // via share memory
+ retval = sendMailbox(&sph_msg, MSG_A2M_PNW_DL_DATA_NOTIFY, payload_length, write_idx);
+ } else { // via payload
+ retval = sendPayload(&sph_msg, MSG_A2M_PNW_DL_DATA_NOTIFY,
+ SHARE_BUFF_DATA_TYPE_PCM_FillSpk,
+ mP2WDlBuf, data_size);
+ }
+ break;
+ }
+#if defined(MTK_SPEECH_VOICE_MIXER_SUPPORT)
+ case MSG_M2A_PCMMIXER_DL_DATA_REQUEST: {
+ // fill p2w dl data
+ if (getModemSideModemStatus(PCM_MIXER_STATUS_MASK) == false) {
+ PRINT_SPH_MSG(ALOGW, "md pcm mixer off now!! break", p_sph_msg);
+ break;
+ } else if (GetApSideModemStatus(PCM_MIXER_STATUS_MASK) == false) {
+ PRINT_SPH_MSG(ALOGW, "ap pcm mixer off now!! break", p_sph_msg);
+ break;
+ } else if (!mPcmMixerDlBuf) {
+ PRINT_SPH_MSG(ALOGW, "mPcmMixerDlBuf NULL!! break", p_sph_msg);
+ break;
+ } else {
+ PRINT_SPH_MSG(SPH_LOG_D, "pcm mixer dl data request", p_sph_msg);
+ num_data_request = p_sph_msg->length;
+ if (num_data_request > kMaxApPayloadDataSize) {
+ num_data_request = kMaxApPayloadDataSize;
+ }
+ data_size = (uint16_t)voiceMixerPlayer->putDataToSpeaker((char *)mPcmMixerDlBuf, num_data_request);
+ if (data_size == 0) {
+ PRINT_SPH_MSG(ALOGW, "data_size == 0", p_sph_msg);
+ }
+ }
+ // share memory
+ retval = mSpeechMessenger->writeApDataToShareMemory(mPcmMixerDlBuf,
+ SHARE_BUFF_DATA_TYPE_CCCI_PCM_MIXER_DL,
+ data_size,
+ &payload_length,
+ &write_idx);
+ // send data notify to modem side
+ if (retval == 0) { // via share memory
+ retval = sendMailbox(&sph_msg, MSG_A2M_PCMMIXER_DL_DATA_NOTIFY, payload_length, write_idx);
+ } else { // via payload
+ retval = sendPayload(&sph_msg, MSG_A2M_PCMMIXER_DL_DATA_NOTIFY,
+ SHARE_BUFF_DATA_TYPE_PCM_FillSpk,
+ mPcmMixerDlBuf, data_size);
+ }
+ break;
+ }
+#endif
+
+ case MSG_M2A_CTM_DEBUG_DATA_NOTIFY: {
+ if (getModemSideModemStatus(TTY_STATUS_MASK) == false) {
+ PRINT_SPH_MSG(ALOGW, "md tty off now!! drop it", p_sph_msg);
+ break;
+ } else if (GetApSideModemStatus(TTY_STATUS_MASK) == false) {
+ PRINT_SPH_MSG(ALOGW, "ap tty off now!! drop it", p_sph_msg);
+ dropMdDataInShareMemory(mSpeechMessenger, p_sph_msg);
+ break;
+ } else if (!mTtyDebugBuf) {
+ PRINT_SPH_MSG(ALOGW, "mTtyDebugBuf NULL!! drop it", p_sph_msg);
+ dropMdDataInShareMemory(mSpeechMessenger, p_sph_msg);
+ break;
+ } else {
+ PRINT_SPH_MSG(SPH_LOG_V, "tty debug data notify", p_sph_msg);
+
+ /* get tty debug data */
+ if (p_sph_msg->buffer_type == SPH_MSG_BUFFER_TYPE_MAILBOX) { // via share memory
+ data_size = MAX_TTY_DEBUG_SIZE;
+ retval = mSpeechMessenger->readMdDataFromShareMemory(
+ mTtyDebugBuf,
+ &data_type,
+ &data_size,
+ p_sph_msg->length,
+ p_sph_msg->rw_index);
+
+ if (retval != 0) {
+ PRINT_SPH_MSG(ALOGW, "get share memory md data failed!! drop it", p_sph_msg);
+ } else {
+ sendMailbox(&sph_msg, MSG_A2M_CTM_DEBUG_DATA_READ_ACK,
+ p_sph_msg->length, p_sph_msg->rw_index);
+ }
+ } else if (p_sph_msg->buffer_type == SPH_MSG_BUFFER_TYPE_PAYLOAD) { // via payload
+ if (p_sph_msg->payload_data_size > kMaxMdPayloadDataSize) {
+ PRINT_SPH_MSG(ALOGW, "get share memory md data failed!! drop it", p_sph_msg);
+ retval = -ENOMEM;
+ } else {
+ memcpy(mTtyDebugBuf,
+ p_sph_msg->payload_data_addr,
+ p_sph_msg->payload_data_size);
+ data_type = p_sph_msg->payload_data_type;
+ data_size = p_sph_msg->payload_data_size;
+ if (p_sph_msg->payload_data_idx == p_sph_msg->payload_data_total_idx) {
+ sendMailbox(&sph_msg, MSG_A2M_CTM_DEBUG_DATA_READ_ACK, 0, 0);
+ }
+ }
+ } else {
+ PRINT_SPH_MSG(ALOGW, "bad buffer_type!!", p_sph_msg);
+ retval = -EINVAL;
+ }
+
+ /* copy tty debug data */
+ if (retval == 0) {
+ ringbuf.pBufBase = (char *)mTtyDebugBuf;
+ ringbuf.bufLen = data_size + 1; // +1: avoid pRead == pWrite
+ ringbuf.pRead = ringbuf.pBufBase;
+ ringbuf.pWrite = ringbuf.pBufBase + data_size;
+
+ switch (data_type) {
+ case SHARE_BUFF_DATA_TYPE_CCCI_CTM_UL_IN:
+ pSpeechVMRecorder->getCtmDebugDataFromModem(ringbuf, pSpeechVMRecorder->pCtmDumpFileUlIn);
+ break;
+ case SHARE_BUFF_DATA_TYPE_CCCI_CTM_DL_IN:
+ pSpeechVMRecorder->getCtmDebugDataFromModem(ringbuf, pSpeechVMRecorder->pCtmDumpFileDlIn);
+ break;
+ case SHARE_BUFF_DATA_TYPE_CCCI_CTM_UL_OUT:
+ pSpeechVMRecorder->getCtmDebugDataFromModem(ringbuf, pSpeechVMRecorder->pCtmDumpFileUlOut);
+ break;
+ case SHARE_BUFF_DATA_TYPE_CCCI_CTM_DL_OUT:
+ pSpeechVMRecorder->getCtmDebugDataFromModem(ringbuf, pSpeechVMRecorder->pCtmDumpFileDlOut);
+ break;
+ default:
+ PRINT_SPH_MSG(ALOGW, "wrong data_type. drop it", p_sph_msg);
+ retval = -EINVAL;
+ ASSERT(0);
+ }
+ }
+ }
+ break;
+ }
+#if defined(MTK_SPEECH_ECALL_SUPPORT)
+ case MSG_M2A_ECALL_RX_CTRL_PAR_NOTIFY: {
+ ALOGV("%s(), msg_id:0x%x ", __FUNCTION__, p_sph_msg->msg_id);
+
+ /* get ecall rx data */
+ if (p_sph_msg->buffer_type == SPH_MSG_BUFFER_TYPE_MAILBOX) { // via share memory
+ data_size = MAX_SPEECH_ECALL_BUF_LEN;
+ retval = mSpeechMessenger->readMdDataFromShareMemory(
+ mEcallRXCtrlData.data,
+ &data_type,
+ &data_size,
+ p_sph_msg->length,
+ p_sph_msg->rw_index);
+ if (retval != 0) {
+ PRINT_SPH_MSG(ALOGW, "get share memory md data failed!! drop it", p_sph_msg);
+ } else {
+ mEcallRXCtrlData.size = data_size;
+ AudioEventThreadManager::getInstance()->notifyCallback(AUDIO_EVENT_ECALL_RX, this);
+ }
+ } else if (p_sph_msg->buffer_type == SPH_MSG_BUFFER_TYPE_PAYLOAD) { // via payload
+ ASSERT(p_sph_msg->payload_data_idx == p_sph_msg->payload_data_total_idx);
+ if (p_sph_msg->payload_data_size <= MAX_SPEECH_ECALL_BUF_LEN) {
+ memcpy(mEcallRXCtrlData.data, p_sph_msg->payload_data_addr, p_sph_msg->payload_data_size);
+ AudioEventThreadManager::getInstance()->notifyCallback(AUDIO_EVENT_ECALL_RX, this);
+ } else {
+ ALOGE("%s(), buffer size(%d) > MAX SIZE(%d)", __FUNCTION__,
+ p_sph_msg->payload_data_size, MAX_SPEECH_ECALL_BUF_LEN);
+ }
+ }
+ break;
+ }
+#endif
+
+ default:
+ ALOGE("%s(), not supported msg_id 0x%x", __FUNCTION__, p_sph_msg->msg_id);
+ }
+
+
+ return 0;
+}
+
+
+
+/*==============================================================================
+ * Speech Control
+ *============================================================================*/
+
+status_t SpeechDriverNormal::SetSpeechMode(const audio_devices_t input_device, const audio_devices_t output_device) {
+ sph_msg_t sph_msg;
+ sph_info_t sph_info;
+
+ int retval = 0;
+
+ SLOG_ENG("%s(), input_device: 0x%x, output_device: 0x%x",
+ __FUNCTION__, input_device, output_device);
+
+ mInputDevice = input_device;
+ mOutputDevice = output_device;
+
+ // set a unreasonable gain value s.t. the reasonable gain can be set to modem next time
+ mDownlinkGain = kUnreasonableGainValue;
+ mDownlinkenh1Gain = kUnreasonableGainValue;
+ mUplinkGain = kUnreasonableGainValue;
+ mSideToneGain = kUnreasonableGainValue;
+
+ if (isSpeechApplicationOn()) {
+ AL_AUTOLOCK_MS(mSpeechParamLock, MAX_SPEECH_AUTO_LOCK_TIMEOUT_MS); // atomic: write shm & send msg
+ parseSpeechParam(SPEECH_SCENARIO_DEVICE_CHANGE);
+ configSpeechInfo(&sph_info);
+ retval = sendPayload(&sph_msg, MSG_A2M_SPH_DEV_CHANGE,
+ SHARE_BUFF_DATA_TYPE_CCCI_SPH_INFO,
+ &sph_info, sizeof(sph_info_t));
+ }
+
+ return 0;
+}
+
+
+status_t SpeechDriverNormal::setMDVolumeIndex(int stream, int device, int index) {
+ int param_arg[4];
+
+ //Android M Voice volume index: available index 1~7, 0 for mute
+ //Android L Voice volume index: available index 0~6
+ if (index <= 0) {
+ return 0;
+ } else {
+ mVolumeIndex = index - 1;
+ }
+
+ if (isSpeechApplicationOn() == false) {
+ ALOGD("%s(), stream: %d, device: 0x%x, index: %d, sph off, return",
+ __FUNCTION__, stream, device, index);
+ } else {
+ updateSpeechParam(SPEECH_SCENARIO_VOLUME_CHANGE);
+ }
+
+ return 0;
+}
+
+
+int SpeechDriverNormal::SpeechOnByApplication(const uint8_t application) {
+ sph_msg_t sph_msg;
+ sph_info_t sph_info;
+
+ SLOG_ENG("SpeechOn(), application: %d", application);
+
+ // reset mute/gain status
+ CleanGainValueAndMuteStatus();
+
+ // reset modem status
+ mModemResetDuringSpeech = false;
+ if (mModemDead == true) {
+ ALOGW("%s(), mModemDead not clear!! reset it!!", __FUNCTION__);
+ mModemDead = false;
+ }
+
+
+ // update phone call status to parser
+ SpeechParserBase::getInstance()->updatePhoneCallStatus(true);
+
+#if !defined(MTK_YOCTO_AUDIO)
+ // vibration speaker param
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_VIBRATION_SPEAKER)) {
+ PARAM_VIBSPK eVibSpkParam;
+ GetVibSpkParam((void *)&eVibSpkParam);
+ SetVibSpkParam((void *)&eVibSpkParam);
+ }
+#endif
+ // speech param
+ AL_AUTOLOCK_MS(mSpeechParamLock, MAX_SPEECH_AUTO_LOCK_TIMEOUT_MS); // atomic: write shm & send msg
+
+ if (application == SPH_APPLICATION_LOOPBACK) {
+ updateFeatureMask(SPEECH_FEATURE_LOOPBACK, true);
+ }
+ parseSpeechParam(SPEECH_SCENARIO_SPEECH_ON);
+ mApplication = application;
+ configSpeechInfo(&sph_info);
+
+ int retval = sendPayload(&sph_msg, MSG_A2M_SPH_ON,
+ SHARE_BUFF_DATA_TYPE_CCCI_SPH_INFO,
+ &sph_info, sizeof(sph_info_t));
+
+ createThreadsDuringSpeech();
+
+ return retval;
+}
+
+int SpeechDriverNormal::SpeechOffByApplication(const uint8_t application) {
+ sph_msg_t sph_msg;
+
+ SLOG_ENG("SpeechOff(), application: %d, mApplication: %d", application, mApplication);
+ if (application != mApplication) {
+ WARNING("speech off not in pair!!");
+ }
+ if (application == SPH_APPLICATION_LOOPBACK) {
+ updateFeatureMask(SPEECH_FEATURE_LOOPBACK, false);
+ }
+
+ int retval = sendMailbox(&sph_msg, MSG_A2M_SPH_OFF, 0, 0);
+
+ CleanGainValueAndMuteStatus();
+
+ mApplication = SPH_APPLICATION_INVALID;
+
+ mModemResetDuringSpeech = false;
+
+ // update phone call status to parser
+ SpeechParserBase::getInstance()->updatePhoneCallStatus(false);
+
+ return retval;
+}
+
+
+status_t SpeechDriverNormal::SpeechOn() {
+ CheckApSideModemStatusAllOffOrDie();
+ SetApSideModemStatus(SPEECH_STATUS_MASK);
+
+ return SpeechOnByApplication(SPH_APPLICATION_NORMAL);
+}
+
+
+status_t SpeechDriverNormal::SpeechOff() {
+ /* should send sph off first and then clean state */
+ int retval = SpeechOffByApplication(SPH_APPLICATION_NORMAL);
+
+ ResetApSideModemStatus(SPEECH_STATUS_MASK);
+ CheckApSideModemStatusAllOffOrDie();
+
+ return retval;
+}
+
+
+status_t SpeechDriverNormal::VideoTelephonyOn() {
+ CheckApSideModemStatusAllOffOrDie();
+ SetApSideModemStatus(VT_STATUS_MASK);
+
+ return SpeechOnByApplication(SPH_APPLICATION_VT_CALL);
+}
+
+
+status_t SpeechDriverNormal::VideoTelephonyOff() {
+ /* should send sph off first and then clean state */
+ int retval = SpeechOffByApplication(SPH_APPLICATION_VT_CALL);
+
+ ResetApSideModemStatus(VT_STATUS_MASK);
+ CheckApSideModemStatusAllOffOrDie();
+
+ return retval;
+}
+
+
+status_t SpeechDriverNormal::SpeechRouterOn() {
+ CheckApSideModemStatusAllOffOrDie();
+ SetApSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+
+ return SpeechOnByApplication(SPH_APPLICATION_ROUTER);
+}
+
+
+status_t SpeechDriverNormal::SpeechRouterOff() {
+ /* should send sph off first and then clean state */
+ int retval = SpeechOffByApplication(SPH_APPLICATION_ROUTER);
+
+ ResetApSideModemStatus(SPEECH_ROUTER_STATUS_MASK);
+ CheckApSideModemStatusAllOffOrDie();
+
+ return retval;
+}
+
+
+
+/*==============================================================================
+ * Recording Control
+ *============================================================================*/
+
+status_t SpeechDriverNormal::recordOn(SpcRecordTypeStruct typeRecord) {
+ AL_AUTOLOCK(mRecordTypeLock);
+ SLOG_ENG("%s(), Record direction: %d => %d, dlPosition: %d", __FUNCTION__,
+ mRecordType.direction, typeRecord.direction, typeRecord.dlPosition);
+
+ if (typeRecord.direction >= RECORD_TYPE_MAX ||
+ typeRecord.dlPosition >= RECORD_POS_DL_MAX) {
+ ALOGE("%s(), Wrong record type!! direction:%d, dlPosition:%d",
+ __FUNCTION__, typeRecord.direction, typeRecord.dlPosition);
+ }
+
+ SetApSideModemStatus(RAW_RECORD_STATUS_MASK);
+
+ mRecordType = typeRecord;
+ sph_msg_t sph_msg;
+ uint16_t param_16bit = typeRecord.dlPosition;
+ return sendMailbox(&sph_msg, MSG_A2M_RECORD_RAW_PCM_ON, param_16bit, 0);
+}
+
+
+status_t SpeechDriverNormal::recordOff(SpcRecordTypeStruct typeRecord) {
+ AL_AUTOLOCK(mRecordTypeLock);
+ SLOG_ENG("%s(), Record direction: %d => %d, dlPosition: %d", __FUNCTION__,
+ mRecordType.direction, typeRecord.direction, typeRecord.dlPosition);
+
+ if (typeRecord.direction >= RECORD_TYPE_MAX ||
+ typeRecord.dlPosition >= RECORD_POS_DL_MAX) {
+ ALOGE("%s(), Wrong record type!! direction:%d, dlPosition:%d",
+ __FUNCTION__, typeRecord.direction, typeRecord.dlPosition);
+ }
+
+ sph_msg_t sph_msg;
+ int retval = 0;
+
+ retval = sendMailbox(&sph_msg, MSG_A2M_RECORD_RAW_PCM_OFF, 0, 0);
+
+ ResetApSideModemStatus(RAW_RECORD_STATUS_MASK);
+ mRecordType = typeRecord;
+ return retval;
+}
+
+
+status_t SpeechDriverNormal::setPcmRecordType(SpcRecordTypeStruct typeRecord) {
+ AL_AUTOLOCK(mRecordTypeLock);
+ ALOGD("%s(), Record direction: %d => %d", __FUNCTION__,
+ mRecordType.direction, typeRecord.direction);
+ mRecordType = typeRecord;
+ return 0;
+}
+
+
+status_t SpeechDriverNormal::VoiceMemoRecordOn() {
+ // Dynamic allocate VM buffer
+ if (mVmRecBuf == NULL) {
+ AUDIO_ALLOC_BUFFER(mVmRecBuf, MAX_VM_RECORD_SIZE);
+ }
+ SetApSideModemStatus(VM_RECORD_STATUS_MASK);
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_VM_REC_ON, 0, 0);
+}
+
+
+status_t SpeechDriverNormal::VoiceMemoRecordOff() {
+ sph_msg_t sph_msg;
+ int retval = 0;
+ retval = sendMailbox(&sph_msg, MSG_A2M_VM_REC_OFF, 0, 0);
+
+ ResetApSideModemStatus(VM_RECORD_STATUS_MASK);
+ // Dynamic free VM buffer
+ AUDIO_FREE_POINTER(mVmRecBuf);
+ return retval;
+}
+
+
+uint16_t SpeechDriverNormal::GetRecordSampleRate() const {
+ uint16_t num_sample_rate = 0;
+
+ switch (mRecordSampleRateType) {
+ case RECORD_SAMPLE_RATE_08K:
+ num_sample_rate = 8000;
+ break;
+ case RECORD_SAMPLE_RATE_16K:
+ num_sample_rate = 16000;
+ break;
+ case RECORD_SAMPLE_RATE_32K:
+ num_sample_rate = 32000;
+ break;
+ case RECORD_SAMPLE_RATE_48K:
+ num_sample_rate = 48000;
+ break;
+ default:
+ num_sample_rate = 8000;
+ break;
+ }
+
+ return num_sample_rate;
+}
+
+
+uint16_t SpeechDriverNormal::GetRecordChannelNumber() const {
+ uint16_t num_channel = 0;
+
+ switch (mRecordChannelType) {
+ case RECORD_CHANNEL_MONO:
+ num_channel = 1;
+ break;
+ case RECORD_CHANNEL_STEREO:
+ num_channel = 2;
+ break;
+ default:
+ num_channel = 1;
+ break;
+ }
+
+ return num_channel;
+}
+
+/*==============================================================================
+ * Background Sound
+ *============================================================================*/
+
+status_t SpeechDriverNormal::BGSoundOn() {
+ SetApSideModemStatus(BGS_STATUS_MASK);
+ bool useModemNewBgsPatch = true;
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_BGSND_ON, useModemNewBgsPatch, 0);
+}
+
+
+status_t SpeechDriverNormal::BGSoundConfig(uint8_t ul_gain, uint8_t dl_gain) {
+ sph_msg_t sph_msg;
+ uint16_t param_16bit = (ul_gain << 8) | dl_gain;
+ return sendMailbox(&sph_msg, MSG_A2M_BGSND_CONFIG, param_16bit, 0);
+}
+
+
+status_t SpeechDriverNormal::BGSoundOff() {
+ sph_msg_t sph_msg;
+ int retval = 0;
+ retval = sendMailbox(&sph_msg, MSG_A2M_BGSND_OFF, 0, 0);
+
+ ResetApSideModemStatus(BGS_STATUS_MASK);
+ return retval;
+}
+
+
+
+/*==============================================================================
+ * PCM 2 Way
+ *============================================================================*/
+
+status_t SpeechDriverNormal::PCM2WayOn(const bool wideband_on) {
+ // Dynamic allocate P2W buffer
+ if (mP2WUlBuf == NULL) {
+ AUDIO_ALLOC_BUFFER(mP2WUlBuf, MAX_PNW_UL_SIZE);
+ }
+ if (mP2WDlBuf == NULL) {
+ AUDIO_ALLOC_BUFFER(mP2WDlBuf, kMaxApPayloadDataSize);
+ }
+ SetApSideModemStatus(P2W_STATUS_MASK);
+
+ mPCM2WayState = (SPC_PNW_MSG_BUFFER_SPK | SPC_PNW_MSG_BUFFER_MIC | (wideband_on << 4));
+ ALOGD("%s(), wideband_on: %d, mPCM2WayState: 0x%x", __FUNCTION__, wideband_on, mPCM2WayState);
+
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_PNW_ON, mPCM2WayState, 0);
+}
+
+
+status_t SpeechDriverNormal::PCM2WayOff() {
+ ALOGD("%s(), mPCM2WayState: 0x%x => 0", __FUNCTION__, mPCM2WayState);
+ mPCM2WayState = 0;
+
+ sph_msg_t sph_msg;
+ int retval = 0;
+ retval = sendMailbox(&sph_msg, MSG_A2M_PNW_OFF, 0, 0);
+
+ ResetApSideModemStatus(P2W_STATUS_MASK);
+ // Dynamic free P2W buffer
+ AUDIO_FREE_POINTER(mP2WUlBuf);
+ AUDIO_FREE_POINTER(mP2WDlBuf);
+ return retval;
+}
+
+/*==============================================================================
+ * Voice Mixer
+ *============================================================================*/
+status_t SpeechDriverNormal::pcmMixerOn() {
+#if !defined(MTK_SPEECH_VOICE_MIXER_SUPPORT)
+ ALOGW("%s() not support!!!", __FUNCTION__);
+ return 0;
+#else
+ sph_msg_t sph_msg;
+
+ // Dynamic allocate PcmMixer buffer
+ if (mP2WUlBuf == NULL) {
+ AUDIO_ALLOC_BUFFER(mPcmMixerUlBuf, MAX_PCMMIXER_UL_SIZE);
+ }
+ if (mP2WDlBuf == NULL) {
+ AUDIO_ALLOC_BUFFER(mPcmMixerDlBuf, kMaxApPayloadDataSize);
+ }
+ SetApSideModemStatus(PCM_MIXER_STATUS_MASK);
+ uint16_t param16bit = (mPcmMixerTypeUl << 2) | mPcmMixerTypeDl;
+ ALOGD("%s(), mPcmMixerTypeDl: %u, mPcmMixerTypeUl: %u, param16bit: %u",
+ __FUNCTION__, mPcmMixerTypeDl, mPcmMixerTypeUl, param16bit);
+ return sendMailbox(&sph_msg, MSG_A2M_PCMMIXER_ON, param16bit, 0);
+#endif
+}
+
+status_t SpeechDriverNormal::pcmMixerOff() {
+#if !defined(MTK_SPEECH_VOICE_MIXER_SUPPORT)
+ ALOGW("%s() not support!!!", __FUNCTION__);
+ return 0;
+#else
+ sph_msg_t sph_msg;
+ int retval = 0;
+ ALOGD("%s()", __FUNCTION__);
+
+ retval = sendMailbox(&sph_msg, MSG_A2M_PCMMIXER_OFF, 0, 0);
+ ResetApSideModemStatus(PCM_MIXER_STATUS_MASK);
+ // Dynamic free P2W buffer
+ AUDIO_FREE_POINTER(mPcmMixerUlBuf);
+ AUDIO_FREE_POINTER(mPcmMixerDlBuf);
+ return retval;
+#endif
+}
+
+status_t SpeechDriverNormal::pcmMixerConfig(const uint8_t direction, const uint8_t mixType) {
+#if !defined(MTK_SPEECH_VOICE_MIXER_SUPPORT)
+ ALOGW("%s() not support!!!direction: %u, mixType: %u",
+ __FUNCTION__, direction, mixType);
+ return 0;
+#else
+ sph_msg_t sph_msg;
+ if (direction == PCM_DIRECTION_UPLINK) {
+ mPcmMixerTypeUl = mixType;
+ } else {
+ mPcmMixerTypeDl = mixType;
+ }
+ uint16_t param16bit = (mPcmMixerTypeUl << 2) | mPcmMixerTypeDl;
+ ALOGD("%s(), direction: %u, mixType: %u, param16bit: %u",
+ __FUNCTION__, direction, mixType, param16bit);
+ return sendMailbox(&sph_msg, MSG_A2M_PCMMIXER_CONFIG, param16bit, 0);
+#endif
+}
+
+/*==============================================================================
+ * TTY-CTM Control
+ *============================================================================*/
+
+status_t SpeechDriverNormal::TtyCtmOn() {
+ SpeechVMRecorder *pSpeechVMRecorder = SpeechVMRecorder::getInstance();
+ const bool uplink_mute_on_copy = mUplinkMuteOn;
+
+ ALOGD("%s(), mTtyMode: %d", __FUNCTION__, mTtyMode);
+
+ // Dynamic allocate tty debug buffer
+ if (mTtyDebugBuf == NULL) {
+ AUDIO_ALLOC_BUFFER(mTtyDebugBuf, MAX_TTY_DEBUG_SIZE);
+ }
+ SetApSideModemStatus(TTY_STATUS_MASK);
+
+ SetUplinkMute(true);
+ TtyCtmDebugOn(pSpeechVMRecorder->getVmConfig() == SPEECH_VM_CTM4WAY);
+
+ sph_msg_t sph_msg;
+ int retval = sendMailbox(&sph_msg, MSG_A2M_CTM_ON, mTtyMode, 0);
+
+ SetUplinkMute(uplink_mute_on_copy);
+
+ return retval;
+}
+
+status_t SpeechDriverNormal::TtyCtmOff() {
+ ALOGD("%s()", __FUNCTION__);
+
+ sph_msg_t sph_msg;
+ int retval = 0;
+ mTtyMode = AUD_TTY_OFF;
+
+ if (mTtyDebugEnable == true) {
+ TtyCtmDebugOn(false);
+ }
+ retval = sendMailbox(&sph_msg, MSG_A2M_CTM_OFF, 0, 0);
+
+ ResetApSideModemStatus(TTY_STATUS_MASK);
+
+ // Dynamic free tty debug buffer
+ AUDIO_FREE_POINTER(mTtyDebugBuf);
+ return retval;
+}
+
+
+status_t SpeechDriverNormal::TtyCtmDebugOn(bool tty_debug_flag) {
+ SpeechVMRecorder *pSpeechVMRecorder = SpeechVMRecorder::getInstance();
+
+ ALOGD("%s(), tty_debug_flag: %d", __FUNCTION__, tty_debug_flag);
+
+ if (tty_debug_flag == true) {
+ mTtyDebugEnable = true;
+ pSpeechVMRecorder->startCtmDebug();
+ } else {
+ pSpeechVMRecorder->stopCtmDebug();
+ mTtyDebugEnable = false;
+ }
+
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_CTM_DUMP_DEBUG_FILE, tty_debug_flag, 0);
+}
+
+/*==============================================================================
+ * RTT
+ *============================================================================*/
+
+int SpeechDriverNormal::RttConfig(int rttMode) {
+ ALOGD("%s(), rttMode = %d, old mRttMode = %d", __FUNCTION__, rttMode, mRttMode);
+
+ if (rttMode == mRttMode) { return NO_ERROR; }
+ mRttMode = rttMode;
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_RTT_CONFIG, (uint16_t)mRttMode, 0);
+}
+
+
+/*==============================================================================
+ * Modem Audio DVT and Debug
+ *============================================================================*/
+
+status_t SpeechDriverNormal::SetModemLoopbackPoint(uint16_t loopback_point) {
+ ALOGD("%s(), loopback_point: %d", __FUNCTION__, loopback_point);
+
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_SET_LPBK_POINT_DVT, loopback_point, 0);
+}
+
+/*==============================================================================
+ * ECALL
+ *============================================================================*/
+
+status_t SpeechDriverNormal::eCallIvsSwitch(bool enable) {
+ ALOGD("%s(), enable: %d", __FUNCTION__, enable);
+
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_IVS_SWITCH, enable, 0);
+}
+
+status_t SpeechDriverNormal::eCallIvsSend() {
+ ALOGD("%s()", __FUNCTION__);
+
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_IVS_SEND, 0, 0);
+}
+
+status_t SpeechDriverNormal::eCallPsapSwitch(bool enable) {
+ ALOGD("%s(), enable: %d", __FUNCTION__, enable);
+
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_PSAP_SWITCH, enable, 0);
+}
+
+status_t SpeechDriverNormal::eCallPsapSend() {
+ ALOGD("%s()", __FUNCTION__);
+
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_PSAP_SEND, 0, 0);
+}
+
+status_t SpeechDriverNormal::eCallCtrlSeqSwitch(bool enable) {
+ ALOGD("%s(), enable: %d", __FUNCTION__, enable);
+
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_ECALL_CTL_SEQ_SWITCH, enable, 0);
+}
+
+status_t SpeechDriverNormal::eCallMsd(void *data, uint16_t len) {
+ ALOGD("%s()", __FUNCTION__);
+
+ sph_msg_t sph_msg;
+ return sendPayload(&sph_msg, MSG_A2M_ECALL_MSD, SHARE_BUFF_DATA_TYPE_CCCI_ECALL_MSD_TYPE, data, len);
+}
+
+status_t SpeechDriverNormal::eCallTxCtrlParam(void *data, uint16_t len) {
+ ALOGD("%s()", __FUNCTION__);
+
+ sph_msg_t sph_msg;
+ return sendPayload(&sph_msg, MSG_A2M_ECALL_TX_CTRL_PAR, SHARE_BUFF_DATA_TYPE_CCCI_ECALL_MSD_TYPE, data, len);
+}
+
+status_t SpeechDriverNormal::eCallInfo() {
+ ALOGD("%s()", __FUNCTION__);
+
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_ECALL_HANDSHAKE_INFO_READ_ACK, 0, 0);
+}
+
+status_t SpeechDriverNormal::eCallRxCtrl() {
+ ALOGD("%s()", __FUNCTION__);
+
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_ECALL_RX_CTRL_READ_ACK, 0, 0);
+}
+
+/*==============================================================================
+ * Acoustic Loopback
+ *============================================================================*/
+
+status_t SpeechDriverNormal::SetAcousticLoopback(bool loopback_on) {
+ ALOGD("%s(), loopback_on: %d, mModemLoopbackDelayFrames: %d, mUseBtCodec: %d",
+ __FUNCTION__, loopback_on, mModemLoopbackDelayFrames, mUseBtCodec);
+
+ int retval = 0;
+
+ if (loopback_on == true) {
+ CheckApSideModemStatusAllOffOrDie();
+ SetApSideModemStatus(LOOPBACK_STATUS_MASK);
+
+ retval = SpeechOnByApplication(SPH_APPLICATION_LOOPBACK);
+ } else {
+ mUseBtCodec = true;
+
+ /* should send sph off first and then clean state */
+ retval = SpeechOffByApplication(SPH_APPLICATION_LOOPBACK);
+
+ ResetApSideModemStatus(LOOPBACK_STATUS_MASK);
+ CheckApSideModemStatusAllOffOrDie();
+ }
+
+ return retval;
+}
+
+
+status_t SpeechDriverNormal::SetAcousticLoopbackBtCodec(bool enable_codec) {
+ ALOGD("%s(), mUseBtCodec: %d => %d", __FUNCTION__, mUseBtCodec, enable_codec);
+ mUseBtCodec = enable_codec;
+ return 0;
+}
+
+
+status_t SpeechDriverNormal::SetAcousticLoopbackDelayFrames(int32_t delay_frames) {
+ ALOGD("%s(), mModemLoopbackDelayFrames: %d => %d", __FUNCTION__,
+ mModemLoopbackDelayFrames, delay_frames);
+
+ if (delay_frames < 0) {
+ ALOGE("%s(), delay_frames(%d) < 0!! set 0 instead", __FUNCTION__, delay_frames);
+ delay_frames = 0;
+ }
+
+ mModemLoopbackDelayFrames = (uint8_t)delay_frames;
+ if (mModemLoopbackDelayFrames > MAX_LOOPBACK_DELAY_FRAMES) {
+ ALOGE("%s(), delay_frames(%d) > %d!! set %d instead.", __FUNCTION__,
+ mModemLoopbackDelayFrames, MAX_LOOPBACK_DELAY_FRAMES, MAX_LOOPBACK_DELAY_FRAMES);
+ mModemLoopbackDelayFrames = MAX_LOOPBACK_DELAY_FRAMES;
+ }
+
+ if (mApplication == SPH_APPLICATION_LOOPBACK) {
+ ALOGW("Loopback is enabled now! The new delay_frames will be applied next time");
+ }
+
+ return 0;
+}
+
+
+
+/*==============================================================================
+ * Volume Control
+ *============================================================================*/
+
+status_t SpeechDriverNormal::SetDownlinkGain(int16_t gain) {
+ static AudioLock gainLock;
+ AL_AUTOLOCK(gainLock);
+
+ if (isSpeechApplicationOn() == false) {
+ return 0;
+ }
+ if (gain != mDownlinkGain) {
+ ALOGD("%s(), mDownlinkGain: 0x%x => 0x%x", __FUNCTION__, mDownlinkGain, gain);
+ }
+ mDownlinkGain = gain;
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_SPH_DL_DIGIT_VOLUME, gain, 0);
+}
+
+
+status_t SpeechDriverNormal::SetEnh1DownlinkGain(int16_t gain) {
+ static AudioLock gainLock;
+ AL_AUTOLOCK(gainLock);
+
+ if (isSpeechApplicationOn() == false) {
+ return 0;
+ }
+ if (gain != mDownlinkenh1Gain) {
+ ALOGD("%s(), mDownlinkenh1Gain: 0x%x => 0x%x", __FUNCTION__, mDownlinkenh1Gain, gain);
+ }
+ mDownlinkenh1Gain = gain;
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_SPH_DL_ENH_REF_DIGIT_VOLUME, gain, 0);
+}
+
+
+status_t SpeechDriverNormal::SetUplinkGain(int16_t gain) {
+ static AudioLock gainLock;
+ AL_AUTOLOCK(gainLock);
+
+ if (isSpeechApplicationOn() == false) {
+ return 0;
+ }
+ if (gain != mUplinkGain) {
+ ALOGD("%s(), mUplinkGain: 0x%x => 0x%x", __FUNCTION__, mUplinkGain, gain);
+ }
+ mUplinkGain = gain;
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_SPH_UL_DIGIT_VOLUME, gain, 0);
+}
+
+
+status_t SpeechDriverNormal::SetDownlinkMute(bool mute_on) {
+ static AudioLock muteLock;
+ AL_AUTOLOCK(muteLock);
+
+ if (isSpeechApplicationOn() == false) {
+ return 0;
+ }
+ ALOGD("%s(), mDownlinkMuteOn: %d => %d", __FUNCTION__, mDownlinkMuteOn, mute_on);
+ mDownlinkMuteOn = mute_on;
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_MUTE_SPH_DL, mute_on, 0);
+}
+
+
+status_t SpeechDriverNormal::SetDownlinkMuteCodec(bool mute_on) {
+ static AudioLock muteLock;
+ AL_AUTOLOCK(muteLock);
+
+ if (isSpeechApplicationOn() == false) {
+ return 0;
+ }
+ ALOGD("%s(), mute_on: %d", __FUNCTION__, mute_on);
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_MUTE_SPH_DL_CODEC, mute_on, 0);
+}
+
+
+status_t SpeechDriverNormal::SetUplinkMute(bool mute_on) {
+ static AudioLock muteLock;
+ AL_AUTOLOCK(muteLock);
+
+ if (isSpeechApplicationOn() == false) {
+ return 0;
+ }
+ ALOGD("%s(), mUplinkMuteOn: %d => %d", __FUNCTION__, mUplinkMuteOn, mute_on);
+ mUplinkMuteOn = mute_on;
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_MUTE_SPH_UL, mute_on, 0);
+}
+
+
+status_t SpeechDriverNormal::SetUplinkSourceMute(bool mute_on) {
+ static AudioLock muteLock;
+ AL_AUTOLOCK(muteLock);
+
+ if (isSpeechApplicationOn() == false) {
+ return 0;
+ }
+ ALOGD("%s(), mUplinkSourceMuteOn: %d => %d", __FUNCTION__, mUplinkSourceMuteOn, mute_on);
+ mUplinkSourceMuteOn = mute_on;
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_MUTE_SPH_UL_SOURCE, mute_on, 0);
+}
+
+
+
+/*==============================================================================
+ * Device related Config
+ *============================================================================*/
+
+status_t SpeechDriverNormal::SetModemSideSamplingRate(uint16_t sample_rate) {
+ mSampleRateEnum = sph_sample_rate_value_to_enum(sample_rate);
+ return 0;
+}
+
+status_t SpeechDriverNormal::switchBTMode(uint32_t sample_rate) {
+ sph_msg_t sph_msg;
+ sph_info_t sph_info;
+
+ ALOGD("%s(), sample_rate: %u", __FUNCTION__, sample_rate);
+
+ // Set MD side sampling rate
+ SetModemSideSamplingRate(sample_rate);
+
+ // set bt mode no need to parse parameter
+ mIsBTSwitchConfig = true;
+ configSpeechInfo(&sph_info);
+ mIsBTSwitchConfig = false;
+
+ int retval = sendPayload(&sph_msg, MSG_A2M_SPH_DEV_CHANGE,
+ SHARE_BUFF_DATA_TYPE_CCCI_SPH_INFO,
+ &sph_info, sizeof(sph_info_t));
+
+ return NO_ERROR;
+}
+
+void SpeechDriverNormal::setBTMode(const int mode) {
+ ALOGD("%s(), mBTMode: %d => %d", __FUNCTION__, mBTMode, mode);
+ mBTMode = mode;
+}
+
+void SpeechDriverNormal::setBtSpkDevice(const bool flag) {
+ ALOGD("%s(), set BtSpkDevice : %d => %d", __FUNCTION__, isBtSpkDevice, flag);
+ isBtSpkDevice = flag;
+}
+
+
+/*==============================================================================
+ * Speech Enhancement Control
+ *============================================================================*/
+
+status_t SpeechDriverNormal::SetSpeechEnhancement(bool enhance_on) {
+ ALOGD("%s(), enhance_on = %d ", __FUNCTION__, enhance_on);
+ sph_msg_t sph_msg;
+ return sendMailbox(&sph_msg, MSG_A2M_CTRL_SPH_ENH, enhance_on, 0);
+}
+
+
+status_t SpeechDriverNormal::SetSpeechEnhancementMask(const sph_enh_mask_struct_t &mask) {
+ sph_msg_t sph_msg;
+
+ uint16_t enh_dynamic_ctrl = speechEnhancementMaskWrapper(mask.dynamic_func);
+
+ ALOGD("%s(), enh_dynamic_ctrl mask 0x%x", __FUNCTION__, enh_dynamic_ctrl);
+ return sendMailbox(&sph_msg, MSG_A2M_ENH_CTRL_SUPPORT, enh_dynamic_ctrl, 0);
+}
+
+/*
+ * from: sph_enh_dynamic_mask_t
+ * to: sph_enh_dynamic_ctrl_t
+ */
+uint16_t SpeechDriverNormal::speechEnhancementMaskWrapper(const uint32_t enh_dynamic_mask) {
+ uint16_t enh_dynamic_ctrl = 0;
+
+ /* DMNR */
+ if (enh_dynamic_mask & SPH_ENH_DYNAMIC_MASK_DMNR) {
+ enh_dynamic_ctrl |= SPH_ENH_DYNAMIC_CTRL_MASK_DMNR;
+ }
+
+ /* TDNC */
+ enh_dynamic_ctrl |= SPH_ENH_DYNAMIC_CTRL_MASK_TDNC; /* always on */
+
+ /* MAGIC CONFERENCE */
+ if (enh_dynamic_mask & SPH_ENH_DYNAMIC_MASK_LSPK_DMNR) {
+ enh_dynamic_ctrl |= SPH_ENH_DYNAMIC_CTRL_MASK_MAGIC_CONFERENCE;
+ }
+
+ /* DE REVERB */
+ if (enh_dynamic_mask & SPH_ENH_DYNAMIC_MASK_DE_REVERB) {
+ enh_dynamic_ctrl |= SPH_ENH_DYNAMIC_CTRL_MASK_DE_REVERB;
+ }
+
+ return enh_dynamic_ctrl;
+}
+
+
+status_t SpeechDriverNormal::SetBtHeadsetNrecOn(const bool bt_headset_nrec_on) {
+ ALOGD("%s(), mBtHeadsetNrecOn: %d => %d", __FUNCTION__, mBtHeadsetNrecOn, bt_headset_nrec_on);
+ mBtHeadsetNrecOn = bt_headset_nrec_on; /* will be applied later in SetSpeechMode() */
+ return 0;
+}
+
+
+
+/*==============================================================================
+ * Speech Enhancement Parameters
+ *============================================================================*/
+
+int SpeechDriverNormal::parseSpeechParam(const SpeechScenario scenario) {
+ int retval = 0;
+
+ static AudioLock parserAttrLock;
+ AL_AUTOLOCK(parserAttrLock);
+ mSpeechParserAttribute.inputDevice = mInputDevice;
+ mSpeechParserAttribute.outputDevice = mOutputDevice;
+ mSpeechParserAttribute.idxVolume = mVolumeIndex;
+ mSpeechParserAttribute.driverScenario = (SpeechScenario)scenario;
+ mSpeechParserAttribute.ttyMode = mTtyMode;
+ bool isHacOn = SpeechEnhancementController::GetInstance()->GetHACOn();
+ updateFeatureMask(SPEECH_FEATURE_HAC, isHacOn);
+ updateFeatureMask(SPEECH_FEATURE_BTNREC, mBtHeadsetNrecOn);
+
+ uint32_t parsed_size = 0;
+#if defined(MTK_SPEECH_USIP_EMI_SUPPORT)
+ char keyString[MAX_SPEECH_PARSER_KEY_LEN];
+ memset((void *)keyString, 0, MAX_SPEECH_PARSER_KEY_LEN);
+
+ SpeechStringBufType keyValuePair;
+ memset(&keyValuePair, 0, sizeof(SpeechStringBufType));
+ keyValuePair.stringAddr = keyString;
+ uint16_t mdVersion = mMdAliveInfo.mdVersion;
+
+ //"SPEECH_PARSER_SET_PARAM,MDVERSION="
+ sprintf(keyString, "%s,%s=%d", SPEECH_PARSER_SET_KEY_PREFIX, SPEECH_PARSER_MD_VERSION, mdVersion);
+ keyValuePair.memorySize = strlen(keyString) + 1;
+ keyValuePair.stringSize = strlen(keyString);
+ ALOGD("%s(), %s", __FUNCTION__, keyValuePair.stringAddr);
+ SpeechParserBase::getInstance()->setKeyValuePair(&keyValuePair);
+#endif
+
+ SpeechDataBufType outBuf;
+ retval = SpeechParserBase::getInstance()->getParamBuffer(mSpeechParserAttribute, &outBuf);
+ if (retval != 0) {
+ mIsParseFail = true;
+ outBuf.dataSize = 0;
+ ALOGE("%s(), parameter parse fail (retval = %d), return. md use default parameter.",
+ __FUNCTION__, retval);
+ retval = -EFAULT;
+ } else {
+ mIsParseFail = false;
+ if (outBuf.dataSize == 0) {
+ ALOGW("%s(), parsed_size 0, return. md use previous parameter.",
+ __FUNCTION__);
+ retval = -EFAULT;
+ }
+ }
+ if (outBuf.dataSize > outBuf.memorySize) {
+ ALOGW("%s(), parsed_size %u > memorySize %u",
+ __FUNCTION__, outBuf.dataSize, outBuf.memorySize);
+ WARNING("overflow!!");
+ retval = -ENOMEM;
+ }
+ if (mSpeechParam.bufferAddr == NULL || mSpeechParam.dataSize < outBuf.dataSize) {
+ if (mSpeechParam.dataSize < outBuf.dataSize) {
+ AUDIO_FREE_POINTER(mSpeechParam.bufferAddr);
+ }
+ AUDIO_ALLOC_BUFFER(mSpeechParam.bufferAddr, outBuf.dataSize);
+ }
+ mSpeechParam.dataSize = outBuf.dataSize;
+ mSpeechParam.memorySize = outBuf.memorySize;
+ memcpy(mSpeechParam.bufferAddr, outBuf.bufferAddr, outBuf.dataSize);
+
+ ALOGD("%s(), parsed_size=%d, mIsParseFail=%d", __FUNCTION__, outBuf.dataSize, mIsParseFail);
+ return retval;
+
+}
+
+int SpeechDriverNormal::writeAllSpeechParametersToModem(uint32_t *p_length, uint32_t *p_index) {
+ sph_msg_t sph_msg;
+
+ int retval = 0;
+ // write to share memory
+ uint32_t write_idx = 0;
+ retval = mSpeechMessenger->writeSphParamToShareMemory(mSpeechParam.bufferAddr,
+ mSpeechParam.dataSize,
+ &write_idx);
+ if (retval != 0) { // shm fail =>
+ ALOGE("%s(), dataSize %u, writeSphParamToShareMemory FAIIL!!",
+ __FUNCTION__, mSpeechParam.dataSize);
+ }
+ // update length & index
+ if (retval == 0) {
+ *p_length = mSpeechParam.dataSize;
+ *p_index = write_idx;
+ }
+ AUDIO_FREE_POINTER(mSpeechParam.bufferAddr);
+ mSpeechParam.memorySize = 0;
+ mSpeechParam.dataSize = 0;
+
+ return retval;
+}
+
+int SpeechDriverNormal::updateSpeechParam(const SpeechScenario scenario) {
+ AL_AUTOLOCK_MS(mSpeechParamLock, MAX_SPEECH_AUTO_LOCK_TIMEOUT_MS); // atomic: write shm & send msg
+
+ sph_msg_t sph_msg;
+ int retval = 0;
+
+ // parse
+ retval = parseSpeechParam(scenario);
+
+ // share memory
+ uint32_t write_idx = 0;
+ if (retval == 0) { //only transfer data if parse successfully
+#if defined(MTK_SPEECH_USIP_EMI_SUPPORT)
+ sph_info_t sph_info;
+ configSpeechInfo(&sph_info);
+ // send sph param to modem side
+ retval = sendPayload(&sph_msg, MSG_A2M_DYNAMIC_PAR_IN_STRUCT_SHM,
+ SHARE_BUFF_DATA_TYPE_CCCI_SPH_INFO,
+ &sph_info, sizeof(sph_info_t));
+#else
+ retval = mSpeechMessenger->writeSphParamToShareMemory(mSpeechParam.bufferAddr,
+ mSpeechParam.dataSize,
+ &write_idx);
+ // send sph param to modem side
+ if (retval == 0) { // via share memory
+ retval = sendMailbox(&sph_msg, MSG_A2M_DYNAMIC_PAR_IN_STRUCT_SHM,
+ mSpeechParam.dataSize, write_idx);
+ } else {
+ ALOGE("%s(), dataSize %u, writeSphParamToShareMemory Fail!!",
+ __FUNCTION__, mSpeechParam.dataSize);
+ }
+#endif
+ }
+ ALOGD("%s(), dataSize: %d", __FUNCTION__, mSpeechParam.dataSize);
+ AUDIO_FREE_POINTER(mSpeechParam.bufferAddr);
+ mSpeechParam.memorySize = 0;
+ mSpeechParam.dataSize = 0;
+ return retval;
+}
+
+status_t SpeechDriverNormal::GetVibSpkParam(void *eVibSpkParam) {
+ /* error handling */
+ if (eVibSpkParam == NULL) {
+ ALOGW("%s(), eVibSpkParam == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+#if !defined(MTK_YOCTO_AUDIO)
+ int32_t frequency;
+ AUDIO_ACF_CUSTOM_PARAM_STRUCT audioParam;
+ getAudioCompFltCustParam(AUDIO_COMP_FLT_VIBSPK, &audioParam);
+ PARAM_VIBSPK *pParamVibSpk = (PARAM_VIBSPK *)eVibSpkParam;
+ int dTableIndex;
+
+ if (audioParam.bes_loudness_WS_Gain_Max != VIBSPK_CALIBRATION_DONE && audioParam.bes_loudness_WS_Gain_Max != VIBSPK_SETDEFAULT_VALUE) {
+ frequency = VIBSPK_DEFAULT_FREQ;
+ } else {
+ frequency = audioParam.bes_loudness_WS_Gain_Min;
+ }
+
+ if (frequency < VIBSPK_FREQ_LOWBOUND) {
+ dTableIndex = 0;
+ } else {
+ dTableIndex = (frequency - VIBSPK_FREQ_LOWBOUND + 1) / VIBSPK_FILTER_FREQSTEP;
+ }
+
+ if (dTableIndex < VIBSPK_FILTER_NUM && dTableIndex >= 0) {
+ memcpy(pParamVibSpk->pParam, &SPH_VIBR_FILTER_COEF_Table[dTableIndex], sizeof(uint16_t)*VIBSPK_SPH_PARAM_SIZE);
+ }
+
+ if (IsAudioSupportFeature(AUDIO_SUPPORT_2IN1_SPEAKER)) {
+ pParamVibSpk->flag2in1 = false;
+ } else {
+ pParamVibSpk->flag2in1 = true;
+ }
+#endif
+ return 0;
+}
+
+
+status_t SpeechDriverNormal::SetVibSpkParam(void *eVibSpkParam) {
+ sph_msg_t sph_msg;
+
+ /* error handling */
+ if (eVibSpkParam == NULL) {
+ ALOGW("%s(), eVibSpkParam == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+#if defined(MTK_YOCTO_AUDIO)
+ return 0;
+#else
+ /* payload (keep lagacy code) */
+ return sendPayload(&sph_msg, MSG_A2M_VIBSPK_PARAMETER,
+ SHARE_BUFF_DATA_TYPE_CCCI_VIBSPK_PARAM,
+ eVibSpkParam, sizeof(PARAM_VIBSPK));
+#endif
+}
+
+
+status_t SpeechDriverNormal::GetSmartpaParam(void *eParamSmartpa) {
+ /* error handling */
+ if (eParamSmartpa == NULL) {
+ ALOGW("%s(), eParamSmartpa == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+
+status_t SpeechDriverNormal::SetSmartpaParam(void *eParamSmartpa) {
+ /* error handling */
+ if (eParamSmartpa == NULL) {
+ ALOGW("%s(), eParamSmartpa == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+
+
+/*==============================================================================
+ * Recover State
+ *============================================================================*/
+
+void SpeechDriverNormal::waitModemAckAfterApDie() {
+ AL_LOCK(mReadMsgThreadCreatedLock);
+ // wait until readSpeechMessageThread created
+ if (mReadMsgThreadCreated == false) {
+ AL_WAIT_NO_TIMEOUT(mReadMsgThreadCreatedLock);
+ }
+ AL_UNLOCK(mReadMsgThreadCreatedLock);
+
+ AL_LOCK(mWaitModemAckAfterApDieLock);
+ ALOGV("%s(), wait 1s for readthread bypass ack", __FUNCTION__);
+ if (AL_WAIT_MS(mWaitModemAckAfterApDieLock, 1000) != 0) {
+ ALOGW("wait time out, ack missed, make fake ack!");
+ sph_msg_t sph_msg;
+ configMailBox(&sph_msg, mApWaitAckMsgID | 0x8000, 0, 0);
+ // update mModemSideModemStatus
+ processModemAckMessage(&sph_msg);
+ mNeedWaitModemAckAfterApDie = false;
+ }
+ AL_UNLOCK(mWaitModemAckAfterApDieLock);
+}
+
+
+void SpeechDriverNormal::RecoverModemSideStatusToInitState() {
+ // send msg to MD but not get ack yet
+ if (mNeedWaitModemAckAfterApDie == true) {
+ ALOGD("%s(), mModemSideModemStatus: 0x%x, waitAckMsgId:0x%x, mReadMsgThreadCreated:0x%x",
+ __FUNCTION__, mModemSideModemStatus, mApWaitAckMsgID, mReadMsgThreadCreated);
+ waitModemAckAfterApDie();
+ }
+
+ if (mModemSideModemStatus != 0) {
+ ALOGD("%s(), mModemIndex: %d, mModemSideModemStatus: 0x%x", __FUNCTION__,
+ mModemIndex, mModemSideModemStatus);
+ }
+
+ // Raw Record
+ if (getModemSideModemStatus(RAW_RECORD_STATUS_MASK) == true) {
+ ALOGD("%s(), mModemIndex = %d, raw_record_on = true", __FUNCTION__, mModemIndex);
+ SetApSideModemStatus(RAW_RECORD_STATUS_MASK);
+ recordOff(mRecordType);
+ }
+
+ // VM Record
+ if (getModemSideModemStatus(VM_RECORD_STATUS_MASK) == true) {
+ ALOGD("%s(), mModemIndex = %d, vm_on = true", __FUNCTION__, mModemIndex);
+ SetApSideModemStatus(VM_RECORD_STATUS_MASK);
+ VoiceMemoRecordOff();
+ }
+
+ // BGS
+ if (getModemSideModemStatus(BGS_STATUS_MASK) == true) {
+ ALOGD("%s(), mModemIndex = %d, bgs_on = true", __FUNCTION__, mModemIndex);
+ SetApSideModemStatus(BGS_STATUS_MASK);
+ BGSoundOff();
+ }
+
+#if defined(MTK_SPEECH_VOICE_MIXER_SUPPORT)
+ // Voice Mixer
+ if (getModemSideModemStatus(PCM_MIXER_STATUS_MASK) == true) {
+ ALOGD("%s(), mModemIndex = %d, voice_mixer_on = true", __FUNCTION__, mModemIndex);
+ SetApSideModemStatus(PCM_MIXER_STATUS_MASK);
+ pcmMixerOff();
+ }
+#endif
+
+ // TTY
+ if (getModemSideModemStatus(TTY_STATUS_MASK) == true) {
+ ALOGD("%s(), mModemIndex = %d, tty_on = true", __FUNCTION__, mModemIndex);
+ SetApSideModemStatus(TTY_STATUS_MASK);
+ TtyCtmOff();
+ }
+
+ // P2W
+ if (getModemSideModemStatus(P2W_STATUS_MASK) == true) {
+ ALOGD("%s(), mModemIndex = %d, p2w_on = true", __FUNCTION__, mModemIndex);
+ SetApSideModemStatus(P2W_STATUS_MASK);
+ PCM2WayOff();
+ }
+
+ // SPH (Phone Call / VT / Loopback / ...)
+ if (getModemSideModemStatus(SPEECH_STATUS_MASK) == true) {
+ ALOGD("%s(), mModemIndex = %d, speech_on = true", __FUNCTION__, mModemIndex);
+ SetApSideModemStatus(SPEECH_STATUS_MASK);
+ mApplication = SPH_APPLICATION_NORMAL;
+ SpeechOff();
+ }
+ mApResetDuringSpeech = false;
+}
+
+
+
+/*==============================================================================
+ * Check Modem Status
+ *============================================================================*/
+
+bool SpeechDriverNormal::CheckModemIsReady() {
+ if (mSpeechMessenger == NULL) {
+ return false;
+ }
+
+ return (mSpeechMessenger->checkModemReady() == true &&
+ mModemResetDuringSpeech == false);
+}
+
+
+
+/*==============================================================================
+ * Delay sync
+ *============================================================================*/
+
+int SpeechDriverNormal::getBtDelayTime(uint16_t *p_bt_delay_ms) {
+ if (p_bt_delay_ms == NULL) {
+ ALOGW("%s(), p_bt_delay_ms == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ if (strlen(mBtHeadsetName) == 0) {
+ ALOGW("%s(), mBtHeadsetName invalid!!", __FUNCTION__);
+ *p_bt_delay_ms = 0;
+ return -ENODEV;
+ }
+
+ *p_bt_delay_ms = SpeechConfig::getInstance()->getBtDelayTime(mBtHeadsetName);
+ return 0;
+}
+
+int SpeechDriverNormal::getUsbDelayTime(uint8_t *usbDelayMs) {
+ int retVal = 0;
+ if (usbDelayMs == NULL) {
+ ALOGW("%s(), p_usb_delay_ms == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+#ifndef MTK_USB_PHONECALL
+ *usbDelayMs = 0;
+ return retVal;
+#else
+ uint8_t delayMs = 0;
+
+ /* SpeechEchoRef_AudioParam.xml */
+ retVal = SpeechConfig::getInstance()->getEchoRefParam(&delayMs);
+ if (retVal == 0) {
+ usbDelayMs = &delayMs;
+ } else {
+ *usbDelayMs = 0;
+ }
+ return retVal;
+#endif
+}
+
+int SpeechDriverNormal::getDriverParam(uint8_t paramType, void *paramBuf) {
+ int retVal = 0;
+ if (paramBuf == NULL) {
+ ALOGW("%s(), paramBuf == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+ if (paramType >= NUM_DRIVER_PARAM) {
+ ALOGW("%s(), paramType(%d) Invalid!! return", __FUNCTION__, paramType);
+ return -EFAULT;
+ }
+
+ /* SpeechGeneral_AudioParam.xml */
+ retVal = SpeechConfig::getInstance()->getDriverParam(paramType, paramBuf);
+ return retVal;
+}
+
+int SpeechDriverNormal::updateFeatureMask(const SpeechFeatureType featureType, const bool flagOn) {
+ AL_AUTOLOCK(mFeatureMaskLock);
+ uint16_t featureMaskType = 1 << featureType;
+
+ const bool currentFlagOn = ((mSpeechParserAttribute.speechFeatureOn & featureMaskType) > 0);
+ if (flagOn == currentFlagOn) {
+ ALOGD("%s(), featureMaskType(0x%x), flagOn(%d) == currentFeature(0x%x), return",
+ __FUNCTION__, featureMaskType, flagOn, mSpeechParserAttribute.speechFeatureOn);
+ return -ENOSYS;
+ }
+ if (flagOn == false) {
+ mSpeechParserAttribute.speechFeatureOn &= (~featureMaskType);
+ } else {
+ mSpeechParserAttribute.speechFeatureOn |= featureMaskType;
+ }
+ ALOGD("%s() featureType:%d, flagon:%d, speechFeatureOn:%d",
+ __FUNCTION__, featureType, flagOn, mSpeechParserAttribute.speechFeatureOn);
+ return 0;
+}
+
+int SpeechDriverNormal::updateSpeechFeature(const SpeechFeatureType featureType, const bool flagOn) {
+ int retVal = 0;
+ retVal = updateFeatureMask(featureType, flagOn);
+ if (retVal == 0) {
+ updateSpeechParam(SPEECH_SCENARIO_FEATURE_CHANGE);
+ }
+ return retVal;
+}
+
+int SpeechDriverNormal::setParameter(const char *keyParameter) {
+ char keySpeechParserSetParam[] = "SPH_PARSER_SET_PARAM,PHONE_CALL";
+
+ if (keyParameter == NULL) {
+ return 0;
+ } else {
+ ALOGD("%s(), %s", __FUNCTION__, keyParameter);
+ char keyString[MAX_SPEECH_PARSER_KEY_LEN];
+ if (strncmp(keySpeechParserSetParam, keyParameter, strlen(keySpeechParserSetParam)) == 0) {
+ strncpy(keyString, keyParameter + strlen(keySpeechParserSetParam) + 1, MAX_SPEECH_PARSER_KEY_LEN - 1);
+ ALOGV("%s(), %s", __FUNCTION__, keyString);
+ if (strstr(keyString, "=") != NULL) {
+ keyString[strstr(keyString, "=") - keyString] = '\0';
+ ALOGV("%s(), %s", __FUNCTION__, keyString);
+ }
+ SpeechStringBufType keyValuePair;
+ memset(&keyValuePair, 0, sizeof(SpeechStringBufType));
+ keyValuePair.stringAddr = keyString;
+ keyValuePair.memorySize = strlen(keyString) + 1;
+ keyValuePair.stringSize = strlen(keyString);
+ return SpeechParserBase::getInstance()->setKeyValuePair(&keyValuePair);
+ } else {
+ return 0;
+ }
+ }
+}
+
+const char *SpeechDriverNormal::getParameter(const char *keyParameter) {
+ char keySpeechParserGetParam[] = "SPH_PARSER_GET_PARAM,PHONE_CALL";
+
+ if (keyParameter == NULL) {
+ return NULL;
+ } else {
+ ALOGD("+%s(), %s", __FUNCTION__, keyParameter);
+ memset(keyStringBuf, 0, MAX_SPEECH_PARSER_KEY_LEN);
+ if (strncmp(keySpeechParserGetParam, keyParameter, strlen(keySpeechParserGetParam)) == 0) {
+ strncpy(keyStringBuf, keyParameter + strlen(keySpeechParserGetParam) + 1, MAX_SPEECH_PARSER_KEY_LEN - 1);
+ if (strstr(keyStringBuf, "=") != NULL) {
+ keyStringBuf[strstr(keyStringBuf, "=") - keyStringBuf] = '\0';
+ ALOGD("%s(), %s", __FUNCTION__, keyStringBuf);
+ }
+
+ SpeechStringBufType keyValuePair;
+ memset(&keyValuePair, 0, sizeof(SpeechStringBufType));
+ keyValuePair.stringAddr = keyStringBuf;
+ keyValuePair.memorySize = strlen(keyStringBuf) + 1;
+ keyValuePair.stringSize = strlen(keyStringBuf);
+ SpeechParserBase::getInstance()->getKeyValuePair(&keyValuePair);
+ ALOGD("-%s(), %s", __FUNCTION__, keyValuePair.stringAddr);
+ return keyValuePair.stringAddr;
+ } else {
+ return NULL;
+ }
+ }
+}
+
+} /* end of namespace android */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechEcallController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechEcallController.cpp
new file mode 100644
index 0000000..2bb6d30
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechEcallController.cpp
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <SpeechEcallController.h>
+#include <SpeechDriverNormal.h>
+
+#include <AudioAssert.h>//Mutex/assert
+#include <AudioLock.h>
+#include <AudioEventThreadManager.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechEcallController"
+namespace android {
+
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+#define ECALL_IPC_FOR_UPLINK "/tmp/ecall/ecall_flow_recv_from_lower"
+#define ECALL_IPC_FOR_INDICATION "/tmp/ecall/ecall_flow_report_indication"
+
+/*
+ * =============================================================================
+ * Callback
+ * =============================================================================
+ */
+static void callbackEcallIndication(int audioEventType, void *caller, void *arg) {
+
+ SpeechDriverNormal *speechDriver = NULL;
+ speechDriver = static_cast<SpeechDriverNormal *>(arg);
+
+ ALOGD("%s(), audioEventType = %d, notifier(%p)",
+ __FUNCTION__, audioEventType, arg);
+
+ int retval = 0;
+ int uplinkfd;
+ int retry = 0;
+ int bytesWritten = 0;
+ void *bufStart = NULL;
+ int bytesLeft = 0;
+ spcEcallIndicationStruct ecallIndication = speechDriver->mEcallIndication;
+
+ if (speechDriver == NULL) {
+ ALOGE("%s(), NULL!! speechDriver %p", __FUNCTION__, speechDriver);
+ return;
+ }
+ ALOGD("%s(), ecallIndication.header = %d, ecallIndication.data = %d",
+ __FUNCTION__, ecallIndication.header, ecallIndication.data);
+
+ uplinkfd = open(ECALL_IPC_FOR_INDICATION , O_WRONLY);
+ bufStart = &ecallIndication;
+ bytesLeft = sizeof(uint32_t)*2;
+ ALOGV("%s(), uplinkfd:0x%x, bufStart:0x%x, bytesLeft=%d", __FUNCTION__, uplinkfd, bufStart, bytesLeft);
+
+ while ((bytesLeft != 0) && (retry < 10)) {
+ bytesWritten = write(uplinkfd, bufStart, bytesLeft);
+ if((-1 == bytesWritten) && (EAGAIN != errno)) {
+ ALOGE("%s(), Write to server FIFO failed: errno(%d), bytes_write(%d)", __FUNCTION__, errno, bytesWritten);
+ close(uplinkfd);
+ }
+ bufStart += bytesWritten;
+ bytesLeft -= bytesWritten;
+ usleep(10 * 1000);
+ retry ++;
+ }
+
+ close(uplinkfd);
+}
+
+static void callbackEcallRx(int audioEventType, void *caller, void *arg) {
+
+ SpeechDriverNormal *speechDriver = NULL;
+ speechDriver = static_cast<SpeechDriverNormal *>(arg);
+
+ ALOGD("%s(), audioEventType = %d, notifier(%p)",
+ __FUNCTION__, audioEventType, arg);
+
+ int retval = 0;
+ int uplinkfd;
+ int retry = 0;
+ int bytesWritten = 0;
+ void *bufStart = NULL;
+ int bytesLeft = 0;
+
+ if (speechDriver == NULL) {
+ ALOGE("%s(), NULL!! speechDriver %p", __FUNCTION__, speechDriver);
+ return;
+ }
+
+ uplinkfd = open(ECALL_IPC_FOR_UPLINK , O_WRONLY);
+ bufStart = speechDriver->mEcallRXCtrlData.data;
+ bytesLeft = speechDriver->mEcallRXCtrlData.size;
+ ALOGV("%s(), uplinkfd:0x%x, bufStart:0x%x, bytesLeft=%d", __FUNCTION__, uplinkfd, bufStart, bytesLeft);
+
+ while ((bytesLeft != 0) && (retry < 10)) {
+ bytesWritten = write(uplinkfd, bufStart, bytesLeft);
+ if((-1 == bytesWritten) && (EAGAIN != errno)) {
+ ALOGE("%s(), Write to server FIFO failed: errno(%d), bytesWritten(%d)", __FUNCTION__, errno, bytesWritten);
+ close(uplinkfd);
+ }
+ bufStart += bytesWritten;
+ bytesLeft -= bytesWritten;
+ usleep(10 * 1000);
+ retry ++;
+ }
+
+ close(uplinkfd);
+}
+
+/*
+* =============================================================================
+* class implementation
+* =============================================================================
+*/
+SpeechEcallController::SpeechEcallController() {
+ ALOGD("%s()", __FUNCTION__);
+ AudioEventThreadManager::getInstance()->registerCallback(AUDIO_EVENT_ECALL_INDICATION, callbackEcallIndication, this);
+ AudioEventThreadManager::getInstance()->registerCallback(AUDIO_EVENT_ECALL_RX, callbackEcallRx, this);
+
+}
+
+SpeechEcallController::~SpeechEcallController() {
+ ALOGD("%s()", __FUNCTION__);
+
+}
+
+} /* end of namespace android */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechEnhancementController.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechEnhancementController.cpp
new file mode 100644
index 0000000..4056fb2
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechEnhancementController.cpp
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <inttypes.h>
+#include <SpeechEnhancementController.h>
+#include <SpeechDriverFactory.h>
+#include <SpeechDriverInterface.h>
+#include <SpeechType.h>
+#include <SpeechParserType.h>
+
+#include <AudioALSAHardwareResourceManager.h>
+
+#include <SpeechUtility.h>
+
+#include <utils/threads.h>
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechEnhancementController"
+
+static const char *PROPERTY_KEY_SPH_ENH_MASKS = "persist.vendor.audiohal.modem.sph_enh_mask";
+static const char *PROPERTY_KEY_BT_HEADSET_NREC_ON = "persist.vendor.audiohal.bt_headset_nrec_on";
+static const char *PROPERTY_KEY_HAC_ON = "persist.vendor.audiohal.hac_on";
+
+
+namespace android {
+
+SpeechEnhancementController *SpeechEnhancementController::mSpeechEnhancementController = NULL;
+SpeechEnhancementController *SpeechEnhancementController::GetInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+
+ if (mSpeechEnhancementController == NULL) {
+ mSpeechEnhancementController = new SpeechEnhancementController();
+ }
+ ASSERT(mSpeechEnhancementController != NULL);
+ return mSpeechEnhancementController;
+}
+
+
+SpeechEnhancementController::SpeechEnhancementController() {
+ // default value (all enhancement on)
+ char property_default_value[PROPERTY_VALUE_MAX];
+ sph_enh_mask_struct_t default_mask;
+
+ if (AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport() >= 2) {
+ default_mask.main_func = SPH_ENH_MAIN_MASK_ALL;
+ default_mask.dynamic_func = (SPH_ENH_DYNAMIC_MASK_ALL &
+ (~SPH_ENH_DYNAMIC_MASK_LSPK_DMNR) &
+ (~SPH_ENH_DYNAMIC_MASK_SIDEKEY_DGAIN));
+#if defined(MTK_INCALL_HANDSFREE_DMNR)
+ default_mask.dynamic_func |= SPH_ENH_DYNAMIC_MASK_LSPK_DMNR;
+#endif
+
+ } else {
+ default_mask.main_func = (SPH_ENH_MAIN_MASK_ALL & (~SPH_ENH_MAIN_MASK_DMNR));
+ default_mask.dynamic_func = (SPH_ENH_DYNAMIC_MASK_ALL &
+ (~SPH_ENH_DYNAMIC_MASK_DMNR) &
+ (~SPH_ENH_DYNAMIC_MASK_LSPK_DMNR) &
+ (~SPH_ENH_DYNAMIC_MASK_SIDEKEY_DGAIN));
+ }
+
+#if defined(MTK_INCALL_DE_REVERB)
+ default_mask.dynamic_func &= SPH_ENH_DYNAMIC_MASK_DE_REVERB;
+#endif
+
+ ALOGV("default_mask: main_func = 0x%x, sub_func = 0x%x",
+ default_mask.main_func,
+ default_mask.dynamic_func);
+ snprintf(property_default_value, sizeof(property_default_value),
+ "%d,%d", default_mask.main_func, default_mask.dynamic_func);
+
+ // get sph_enh_mask_struct from property
+ char property_value[PROPERTY_VALUE_MAX] = {0};
+ get_string_from_property(PROPERTY_KEY_SPH_ENH_MASKS, property_value, PROPERTY_VALUE_MAX);
+
+ // parse mask info from property_value
+ sscanf(property_value, "%" SCNd16 ",%" SCNd32,
+ &mSpeechEnhancementMask.main_func,
+ &mSpeechEnhancementMask.dynamic_func);
+
+
+ ALOGD("mSpeechEnhancementMask: main_func = 0x%x, sub_func = 0x%x",
+ mSpeechEnhancementMask.main_func,
+ mSpeechEnhancementMask.dynamic_func);
+
+ // Magic conference call
+ mMagicConferenceCallOn = (mSpeechEnhancementMask.dynamic_func & SPH_ENH_DYNAMIC_MASK_LSPK_DMNR) ? true : false;
+
+ // HAC
+ uint32 isHacOn = get_uint32_from_uci(PROPERTY_KEY_HAC_ON);
+ mHACOn = (isHacOn == 0) ? false : true;
+
+ // BT Headset NREC
+ uint32 isBtNrecOn = get_uint32_from_uci(PROPERTY_KEY_BT_HEADSET_NREC_ON);
+ mBtHeadsetNrecOn = (isBtNrecOn == 0) ? false : true;
+ mSMNROn = false;
+}
+
+SpeechEnhancementController::~SpeechEnhancementController() {
+
+}
+
+#if !defined(MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT)
+status_t SpeechEnhancementController::SetNBSpeechParametersToAllModem(const AUDIO_CUSTOM_PARAM_STRUCT *pSphParamNB) {
+ SpeechDriverFactory *pSpeechDriverFactory = SpeechDriverFactory::GetInstance();
+ SpeechDriverInterface *pSpeechDriver = NULL;
+ AUDIO_CUSTOM_PARAM_STRUCT mSphParamNB;
+
+ if (mSMNROn == true) {
+ //forcely set single mic setting
+ ALOGD("%s(), mSMNROn = %d, set single mic setting", __FUNCTION__, mSMNROn);
+ memcpy(&mSphParamNB, pSphParamNB, sizeof(AUDIO_CUSTOM_PARAM_STRUCT));
+ for (int speech_mode_index = 0; speech_mode_index < 8; speech_mode_index++) {
+ (mSphParamNB.speech_mode_para[speech_mode_index][13]) = 0;
+ (mSphParamNB.speech_mode_para[speech_mode_index][14]) = 0;
+
+ }
+ }
+
+ for (int modem_index = MODEM_1; modem_index < NUM_MODEM; modem_index++) {
+ pSpeechDriver = pSpeechDriverFactory->GetSpeechDriverByIndex((modem_index_t)modem_index);
+ if (pSpeechDriver != NULL) { // Might be single talk and some speech driver is NULL
+ if (mSMNROn != true) {
+ pSpeechDriver->SetNBSpeechParameters(pSphParamNB);
+ } else {
+ pSpeechDriver->SetNBSpeechParameters(&mSphParamNB);
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t SpeechEnhancementController::SetDualMicSpeechParametersToAllModem(const AUDIO_CUSTOM_EXTRA_PARAM_STRUCT *pSphParamDualMic) {
+ if (AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport() < 2) {
+ ALOGE("%s()", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ SpeechDriverFactory *pSpeechDriverFactory = SpeechDriverFactory::GetInstance();
+ SpeechDriverInterface *pSpeechDriver = NULL;
+
+ for (int modem_index = MODEM_1; modem_index < NUM_MODEM; modem_index++) {
+ pSpeechDriver = pSpeechDriverFactory->GetSpeechDriverByIndex((modem_index_t)modem_index);
+ if (pSpeechDriver != NULL) { // Might be single talk and some speech driver is NULL
+ pSpeechDriver->SetDualMicSpeechParameters(pSphParamDualMic);
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t SpeechEnhancementController::SetMagiConSpeechParametersToAllModem(const AUDIO_CUSTOM_MAGI_CONFERENCE_STRUCT *pSphParamMagiCon) {
+ if (AudioALSAHardwareResourceManager::getInstance()->getNumPhoneMicSupport() < 2) {
+ ALOGE("%s()", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+#if defined(MTK_MAGICONFERENCE_SUPPORT)
+ SpeechDriverFactory *pSpeechDriverFactory = SpeechDriverFactory::GetInstance();
+ SpeechDriverInterface *pSpeechDriver = NULL;
+
+ for (int modem_index = MODEM_1; modem_index < NUM_MODEM; modem_index++) {
+ pSpeechDriver = pSpeechDriverFactory->GetSpeechDriverByIndex((modem_index_t)modem_index);
+ if (pSpeechDriver != NULL) { // Might be single talk and some speech driver is NULL
+ pSpeechDriver->SetMagiConSpeechParameters(pSphParamMagiCon);
+ }
+ }
+
+ return NO_ERROR;
+#else
+ (void)pSphParamMagiCon;
+ ALOGE("%s()", __FUNCTION__);
+ return INVALID_OPERATION;
+#endif
+}
+
+status_t SpeechEnhancementController::SetHACSpeechParametersToAllModem(const AUDIO_CUSTOM_HAC_PARAM_STRUCT *pSphParamHAC) {
+#if defined(MTK_HAC_SUPPORT)
+ SpeechDriverFactory *pSpeechDriverFactory = SpeechDriverFactory::GetInstance();
+ SpeechDriverInterface *pSpeechDriver = NULL;
+
+ for (int modem_index = MODEM_1; modem_index < NUM_MODEM; modem_index++) {
+ pSpeechDriver = pSpeechDriverFactory->GetSpeechDriverByIndex((modem_index_t)modem_index);
+ if (pSpeechDriver != NULL) { // Might be single talk and some speech driver is NULL
+ pSpeechDriver->SetHACSpeechParameters(pSphParamHAC);
+ }
+ }
+ return NO_ERROR;
+#else
+ ALOGE("%s()", __FUNCTION__);
+ (void)pSphParamHAC;
+ return INVALID_OPERATION;
+#endif
+}
+
+
+#if defined(MTK_WB_SPEECH_SUPPORT)
+status_t SpeechEnhancementController::SetWBSpeechParametersToAllModem(const AUDIO_CUSTOM_WB_PARAM_STRUCT *pSphParamWB) {
+ SpeechDriverFactory *pSpeechDriverFactory = SpeechDriverFactory::GetInstance();
+ SpeechDriverInterface *pSpeechDriver = NULL;
+ AUDIO_CUSTOM_WB_PARAM_STRUCT mSphParamWB;
+
+ if (mSMNROn == true) {
+ //forcely set single mic setting
+ ALOGD("%s(), mSMNROn = %d, set single mic setting", __FUNCTION__, mSMNROn);
+ memcpy(&mSphParamWB, pSphParamWB, sizeof(AUDIO_CUSTOM_WB_PARAM_STRUCT));
+
+ for (int speech_mode_index = 0; speech_mode_index < 8; speech_mode_index++) {
+ (mSphParamWB.speech_mode_wb_para[speech_mode_index][13]) = 0;
+ (mSphParamWB.speech_mode_wb_para[speech_mode_index][14]) = 0;
+ }
+ }
+
+ for (int modem_index = MODEM_1; modem_index < NUM_MODEM; modem_index++) {
+ pSpeechDriver = pSpeechDriverFactory->GetSpeechDriverByIndex((modem_index_t)modem_index);
+ if (pSpeechDriver != NULL) { // Might be single talk and some speech driver is NULL
+ if (mSMNROn != true) {
+ pSpeechDriver->SetWBSpeechParameters(pSphParamWB);
+ } else {
+ pSpeechDriver->SetWBSpeechParameters(&mSphParamWB);
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+#else
+status_t SpeechEnhancementController::SetWBSpeechParametersToAllModem(const AUDIO_CUSTOM_WB_PARAM_STRUCT *pSphParamWB) {
+ ALOGE("%s()", __FUNCTION__);
+ return INVALID_OPERATION;
+}
+#endif
+
+status_t SpeechEnhancementController::SetNBSpeechLpbkParametersToAllModem(const AUDIO_CUSTOM_PARAM_STRUCT *pSphParamNB, AUDIO_CUSTOM_SPEECH_LPBK_PARAM_STRUCT *pSphParamNBLpbk) {
+ SpeechDriverFactory *pSpeechDriverFactory = SpeechDriverFactory::GetInstance();
+ SpeechDriverInterface *pSpeechDriver = NULL;
+ AUDIO_CUSTOM_PARAM_STRUCT mSphParamNB;
+
+ memcpy(&mSphParamNB, pSphParamNB, sizeof(AUDIO_CUSTOM_PARAM_STRUCT));
+ //replace receiver/headset/loudspk mode parameters
+ memcpy(&mSphParamNB.speech_mode_para[0][0], pSphParamNBLpbk, sizeof(AUDIO_CUSTOM_SPEECH_LPBK_PARAM_STRUCT));
+
+ // ALOGD("%s(), speech [0][0] (%d) ori253,lpbk224", __FUNCTION__, mSphParamNB.speech_mode_para[0][0]);
+ // ALOGD("%s(), speech [0][1] (%d) ori253,lpbk224", __FUNCTION__, mSphParamNB.speech_mode_para[0][1]);
+ // ALOGD("%s(), speech [0][2] (%d) ori253,lpbk224", __FUNCTION__, mSphParamNB.speech_mode_para[0][2]);
+ for (int modem_index = MODEM_1; modem_index < NUM_MODEM; modem_index++) {
+ pSpeechDriver = pSpeechDriverFactory->GetSpeechDriverByIndex((modem_index_t)modem_index);
+ if (pSpeechDriver != NULL) { // Might be single talk and some speech driver is NULL
+ pSpeechDriver->SetNBSpeechParameters(&mSphParamNB);
+ }
+ }
+
+ return NO_ERROR;
+}
+#endif
+
+status_t SpeechEnhancementController::SetSpeechEnhancementMaskToAllModem(const sph_enh_mask_struct_t &mask) {
+ char property_value[PROPERTY_VALUE_MAX];
+ snprintf(property_value, sizeof(property_value), "%d,%d",
+ mask.main_func, mask.dynamic_func);
+ set_string_to_property(PROPERTY_KEY_SPH_ENH_MASKS, property_value);
+
+ mSpeechEnhancementMask = mask;
+
+ SpeechDriverFactory *pSpeechDriverFactory = SpeechDriverFactory::GetInstance();
+ SpeechDriverInterface *pSpeechDriver = NULL;
+
+ for (int modem_index = MODEM_1; modem_index < NUM_MODEM; modem_index++) {
+ pSpeechDriver = pSpeechDriverFactory->GetSpeechDriverByIndex((modem_index_t)modem_index);
+ if (pSpeechDriver != NULL) { // Might be single talk and some speech driver is NULL
+ pSpeechDriver->SetSpeechEnhancementMask(mSpeechEnhancementMask);
+ }
+ }
+
+ return NO_ERROR;
+}
+
+
+status_t SpeechEnhancementController::SetDynamicMaskOnToAllModem(const sph_enh_dynamic_mask_t dynamic_mask_type, const bool new_flag_on) {
+ sph_enh_mask_struct_t mask = GetSpeechEnhancementMask();
+
+ const bool current_flag_on = ((mask.dynamic_func & dynamic_mask_type) > 0);
+ if (new_flag_on == current_flag_on) {
+ ALOGW("%s(), dynamic_mask_type(%x), new_flag_on(%d) == current_flag_on(%d), return",
+ __FUNCTION__, dynamic_mask_type, new_flag_on, current_flag_on);
+ return NO_ERROR;
+ }
+
+ if (new_flag_on == false) {
+ mask.dynamic_func &= (~dynamic_mask_type);
+ } else {
+ mask.dynamic_func |= dynamic_mask_type;
+ }
+
+#if defined(MTK_COMBO_MODEM_SUPPORT)
+ SpeechFeatureType speechFeature = SPEECH_FEATURE_DMNR;
+ bool needUpdate = false;
+ if (dynamic_mask_type == SPH_ENH_DYNAMIC_MASK_DMNR) {
+ speechFeature = SPEECH_FEATURE_DMNR;
+ needUpdate = true;
+ } else if (dynamic_mask_type == SPH_ENH_DYNAMIC_MASK_LSPK_DMNR) {
+ speechFeature = SPEECH_FEATURE_LSPK_DMNR;
+ needUpdate = true;
+ }
+ if (needUpdate) {
+ SpeechDriverFactory::GetInstance()->GetSpeechDriver()->updateSpeechFeature(speechFeature, new_flag_on);
+ }
+#endif
+
+ return SetSpeechEnhancementMaskToAllModem(mask);
+}
+
+void SpeechEnhancementController::SetMagicConferenceCallOn(const bool magic_conference_call_on) {
+ ALOGD("%s(), mMagicConferenceCallOn = %d, new magic_conference_call_on = %d",
+ __FUNCTION__, mMagicConferenceCallOn, magic_conference_call_on);
+
+ //always set
+ mMagicConferenceCallOn = magic_conference_call_on;
+
+ SetDynamicMaskOnToAllModem(SPH_ENH_DYNAMIC_MASK_LSPK_DMNR, mMagicConferenceCallOn);
+
+}
+
+void SpeechEnhancementController::SetHACOn(const bool hac_on) {
+ ALOGD("%s(), hac_on = %d, new hac_on = %d",
+ __FUNCTION__, mHACOn, hac_on);
+ set_uint32_to_uci(PROPERTY_KEY_HAC_ON, (hac_on == false) ? 0 : 1);
+
+ mHACOn = hac_on;
+
+}
+
+void SpeechEnhancementController::SetBtHeadsetNrecOnToAllModem(const bool bt_headset_nrec_on) {
+ SpeechDriverFactory *pSpeechDriverFactory = SpeechDriverFactory::GetInstance();
+ SpeechDriverInterface *pSpeechDriver = NULL;
+
+ set_uint32_to_uci(PROPERTY_KEY_BT_HEADSET_NREC_ON, (bt_headset_nrec_on == false) ? 0 : 1);
+ if (mBtHeadsetNrecOn == bt_headset_nrec_on) {
+ ALOGD("%s(), mBtHeadsetNrecOn(%d) status keeps the same, skip.", __FUNCTION__, mBtHeadsetNrecOn);
+ } else {
+ mBtHeadsetNrecOn = bt_headset_nrec_on;
+ for (int modem_index = MODEM_1; modem_index < NUM_MODEM; modem_index++) {
+ pSpeechDriver = pSpeechDriverFactory->GetSpeechDriverByIndex((modem_index_t)modem_index);
+ if (pSpeechDriver != NULL) { // Might be single talk and some speech driver is NULL
+ pSpeechDriver->SetBtHeadsetNrecOn(mBtHeadsetNrecOn);
+ }
+ }
+ }
+}
+
+bool SpeechEnhancementController::GetBtHeadsetNrecOn(void) {
+ ALOGD("%s(), mBtHeadsetNrecOn = %d", __FUNCTION__, mBtHeadsetNrecOn);
+ return mBtHeadsetNrecOn;
+}
+
+void SpeechEnhancementController::SetSMNROn(void) {
+ mSMNROn = true;
+ ALOGD("%s(), mSMNROn = %d", __FUNCTION__, mSMNROn);
+}
+
+}
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechExtMemCCCI.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechExtMemCCCI.cpp
new file mode 100644
index 0000000..434fc33
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechExtMemCCCI.cpp
@@ -0,0 +1,736 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechExtMemCCCI"
+#include <SpeechExtMemCCCI.h>
+#include <SpeechMessengerNormal.h>
+#include <utils/Log.h>
+#include <cutils/properties.h>
+
+#include <AudioAssert.h>//Mutex/assert
+#include <SpeechUtility.h>
+#include <SpeechCCCIType.h>
+
+
+namespace android {
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+
+#define SPEECH_CCCI_SHM_SIZE (52 * 1024)
+#define SPEECH_CCCI_SHM_GUARD_REGION_SIZE (32)
+#define SPEECH_CCCI_SHM_MD_DATA_SIZE ((32 * 1024) - 160) /* 160: SHM total 52K only... */
+#define SPEECH_CCCI_SHM_SPEECH_PARAM_SIZE (12 * 1024)
+#define SPEECH_CCCI_SHM_AP_DATA_SIZE (8 * 1024)
+
+typedef struct region_info_t {
+ uint32_t offset; /* ex: 0x1000 */ /* count from the address of sph_shm_t */
+ uint32_t size; /* ex: 0x100 */
+ uint32_t read_idx; /* ex: 0x0 ~ 0xFF */
+ uint32_t write_idx; /* ex: 0x0 ~ 0xFF */
+} region_info_t; /* 16 bytes */
+
+typedef struct sph_shm_region_t {
+ region_info_t sph_param_region;
+ region_info_t ap_data_region;
+ region_info_t md_data_region;
+ region_info_t reserve_1;
+ region_info_t reserve_2;
+} sph_shm_region_t; /* 80 bytes */
+
+typedef struct sph_shm_t {
+ /* 32 bytes gurard region */
+ uint8_t guard_region_pre[SPEECH_CCCI_SHM_GUARD_REGION_SIZE];
+
+ /* 8 bytes init flag */
+ uint32_t ap_flag; /* sph_shm_ap_flag_t: ap can r/w, md read only */
+ uint32_t md_flag; /* sph_shm_md_flag_t: md can r/w, ap read only */
+
+ /* 80 bytes SHM region base */
+ sph_shm_region_t region; /* sph_shm_region_t */
+
+ /* 4 bytes reserve */
+ uint32_t reserve;
+
+ /* 4 bytes strcut size check sum */
+ uint32_t struct_checksum; /* assert(shm->struct_checksum == (&shm->struct_checksum - shm)); */
+
+ /* 12K bytes speech param */
+ uint8_t sph_param[SPEECH_CCCI_SHM_SPEECH_PARAM_SIZE];
+
+ /* 8K bytes AP data */
+ uint8_t ap_data[SPEECH_CCCI_SHM_AP_DATA_SIZE];
+
+ /* 32K bytes MD data */
+ uint8_t md_data[SPEECH_CCCI_SHM_MD_DATA_SIZE];
+
+ /* 32 bytes gurard region */
+ uint8_t guard_region_post[SPEECH_CCCI_SHM_GUARD_REGION_SIZE];
+} sph_shm_t;
+
+typedef uint32_t sph_shm_ap_flag_t;
+enum { /* sph_shm_ap_flag_t */
+ /* AP init SHM ready or nor */
+ SPH_SHM_AP_FLAG_READY = (1 << 0),
+
+ /* AP is writing SHM speech param */
+ SPH_SHM_AP_FLAG_SPH_PARAM_WRITE = (1 << 1),
+
+ /* max 32 bit !! */
+ SPH_SHM_AP_FLAG_MAX = (1 << 31)
+};
+
+typedef uint32_t sph_shm_md_flag_t;
+enum { /* sph_shm_md_flag_t */
+ /* modem is alive or not */
+ SPH_SHM_MD_FLAG_ALIVE = (1 << 0),
+
+ /* MD is reading SHM speech param */
+ SPH_SHM_MD_FLAG_SPH_PARAM_READ = (1 << 1),
+
+ /* max 32 bit !! */
+ SPH_SHM_MD_FLAG_MAX = (1 << 31)
+};
+
+/*
+ * =============================================================================
+ * global value
+ * =============================================================================
+ */
+
+static const char kPropertyKeyShareMemoryInit[PROPERTY_KEY_MAX] = "vendor.audiohal.speech.shm_init";
+
+
+/*
+ * =============================================================================
+ * class implementation
+ * =============================================================================
+ */
+SpeechExtMemCCCI::SpeechExtMemCCCI() {
+ ALOGD("%s()", __FUNCTION__);
+ mModemIndex = MODEM_1;
+ mCcciShareMemoryHandler = -1;
+ mShareMemoryBase = NULL;
+ mShareMemoryLength = 0;
+ mShareMemory = NULL;
+}
+
+SpeechExtMemCCCI::~SpeechExtMemCCCI() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+int SpeechExtMemCCCI::openShareMemory(const modem_index_t modem_index) {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return 0;
+#endif
+ mModemIndex = modem_index;
+ struct timespec ts_start;
+ struct timespec ts_stop;
+ uint64_t time_diff_msg = 0;
+
+ if (mCcciShareMemoryHandler >= 0 &&
+ mShareMemoryBase != NULL &&
+ mShareMemoryLength >= sizeof(sph_shm_t)) {
+ ALOGD("%s(), mCcciShareMemoryHandler: %d, mShareMemoryBase: %p, "
+ "mShareMemoryLength: %u already open",
+ __FUNCTION__, mCcciShareMemoryHandler, mShareMemoryBase, (uint32_t)mShareMemoryLength);
+ return 0;
+ }
+
+ /* get time when get share momoey address start */
+ audio_get_timespec_monotonic(&ts_start);
+ // get share momoey address
+ mCcciShareMemoryHandler = speech_ccci_smem_get(&mShareMemoryBase, &mShareMemoryLength);
+ /* get time when get share momoey address done */
+ audio_get_timespec_monotonic(&ts_stop);
+ time_diff_msg = get_time_diff_ms(&ts_start, &ts_stop);
+
+ if (mCcciShareMemoryHandler < 0) {
+ ALOGE("%s(), ccci_smem_get() fail!! mCcciShareMemoryHandler: %d, errno: %d", __FUNCTION__,
+ (int32_t)mCcciShareMemoryHandler, errno);
+ return -ENODEV;
+ }
+
+ if (mShareMemoryBase == NULL || mShareMemoryLength == 0) {
+ ALOGE("%s(), mShareMemoryBase(%p) == NULL || mShareMemoryLength(%u) == 0", __FUNCTION__,
+ mShareMemoryBase, (uint32_t)mShareMemoryLength);
+ closeShareMemory();
+ return -EFAULT;
+ }
+
+ if (mShareMemoryLength < sizeof(sph_shm_t)) {
+ ALOGE("%s(), mShareMemoryLength(%u) < sizeof(sph_shm_t): %u", __FUNCTION__,
+ (uint32_t)mShareMemoryLength, (uint32_t)sizeof(sph_shm_t));
+ closeShareMemory();
+ return -ENOMEM;
+ }
+ ALOGD("%s(), mCcciShareMemoryHandler: %d, mShareMemoryBase: %p, "
+ "mShareMemoryLength: %u , get share momoey address time: %ju ms",
+ __FUNCTION__, mCcciShareMemoryHandler, mShareMemoryBase,
+ (uint32_t)mShareMemoryLength, time_diff_msg);
+
+ return mCcciShareMemoryHandler;
+}
+
+int SpeechExtMemCCCI::closeShareMemory() {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return 0;
+#endif
+
+ ALOGD("%s(), mCcciShareMemoryHandler: %d, mShareMemoryBase: %p, mShareMemoryLength: %u",
+ __FUNCTION__, mCcciShareMemoryHandler, mShareMemoryBase, mShareMemoryLength);
+
+ if (mCcciShareMemoryHandler >= 0) {
+ speech_ccci_smem_put(mCcciShareMemoryHandler, mShareMemoryBase, mShareMemoryLength);
+ mCcciShareMemoryHandler = -1;
+ mShareMemoryBase = NULL;
+ mShareMemoryLength = 0;
+ mShareMemory = NULL;
+ }
+
+ return 0;
+}
+
+int SpeechExtMemCCCI::formatShareMemory() {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return 0;
+#endif
+
+ AL_AUTOLOCK(mShareMemoryLock);
+
+ if (mShareMemoryBase == NULL || mShareMemoryLength < sizeof(sph_shm_t)) {
+ ALOGE("%s(), mShareMemoryBase(%p) == NULL || mShareMemoryLength(%u) < sizeof(sph_shm_t): %u",
+ __FUNCTION__, mShareMemoryBase, (uint32_t)mShareMemoryLength, (uint32_t)sizeof(sph_shm_t));
+ WARNING("EFAULT");
+ return -EFAULT;
+ }
+
+ mShareMemory = (sph_shm_t *)mShareMemoryBase;
+
+ /* only format share memory once after boot */
+ if (get_uint32_from_mixctrl(kPropertyKeyShareMemoryInit) != 0) {
+ ALOGD("%s(), bypass kPropertyKeyShareMemoryInit", __FUNCTION__);
+ goto FORMAT_SHARE_MEMORY_DONE;
+ }
+
+ /* 32 bytes gurard region */
+ sph_memset(mShareMemory->guard_region_pre, 0x0A, SPEECH_CCCI_SHM_GUARD_REGION_SIZE);
+
+ /* ap_flag */
+ mShareMemory->ap_flag = 0;
+
+ /* md_flag */
+ mShareMemory->md_flag = 0;
+
+ /* sph_param region */
+ mShareMemory->region.sph_param_region.offset = (uint8_t *)mShareMemory->sph_param - (uint8_t *)mShareMemory;
+ mShareMemory->region.sph_param_region.size = SPEECH_CCCI_SHM_SPEECH_PARAM_SIZE;
+ mShareMemory->region.sph_param_region.read_idx = 0;
+ mShareMemory->region.sph_param_region.write_idx = 0;
+ /* ap_data region */
+ mShareMemory->region.ap_data_region.offset = (uint8_t *)mShareMemory->ap_data - (uint8_t *)mShareMemory;
+ mShareMemory->region.ap_data_region.size = SPEECH_CCCI_SHM_AP_DATA_SIZE;
+ mShareMemory->region.ap_data_region.read_idx = 0;
+ mShareMemory->region.ap_data_region.write_idx = 0;
+
+ /* md_data region */
+ mShareMemory->region.md_data_region.offset = (uint8_t *)mShareMemory->md_data - (uint8_t *)mShareMemory;
+ mShareMemory->region.md_data_region.size = SPEECH_CCCI_SHM_MD_DATA_SIZE;
+ mShareMemory->region.md_data_region.read_idx = 0;
+ mShareMemory->region.md_data_region.write_idx = 0;
+
+ /* reserve_1 region */
+ mShareMemory->region.reserve_1.offset = 0;
+ mShareMemory->region.reserve_1.size = 0;
+ mShareMemory->region.reserve_1.read_idx = 0;
+ mShareMemory->region.reserve_1.write_idx = 0;
+
+ /* reserve_2 region */
+ mShareMemory->region.reserve_2.offset = 0;
+ mShareMemory->region.reserve_2.size = 0;
+ mShareMemory->region.reserve_2.read_idx = 0;
+ mShareMemory->region.reserve_2.write_idx = 0;
+
+ /* reserve */
+ mShareMemory->reserve = 0;
+
+ /* checksum */
+ mShareMemory->struct_checksum = (uint8_t *)(&mShareMemory->struct_checksum) - (uint8_t *)mShareMemory;
+
+ /* sph_param */
+ sph_memset(mShareMemory->sph_param, 0, SPEECH_CCCI_SHM_SPEECH_PARAM_SIZE);
+
+ /* ap_data */
+ sph_memset(mShareMemory->ap_data, 0, SPEECH_CCCI_SHM_AP_DATA_SIZE);
+
+ /* md_data */
+ sph_memset(mShareMemory->md_data, 0, SPEECH_CCCI_SHM_MD_DATA_SIZE);
+
+ /* 32 bytes gurard region */
+ sph_memset(mShareMemory->guard_region_post, 0x0A, SPEECH_CCCI_SHM_GUARD_REGION_SIZE);
+
+
+ /* share memory init ready */
+ mShareMemory->ap_flag |= SPH_SHM_AP_FLAG_READY;
+
+ /* init done flag */
+ set_uint32_to_mixctrl(kPropertyKeyShareMemoryInit, 1);
+
+
+
+FORMAT_SHARE_MEMORY_DONE:
+ ALOGD("%s(), mShareMemory: %p, ap_flag: 0x%x, md_flag: 0x%x, struct_checksum: %u",
+ __FUNCTION__,
+ mShareMemory,
+ mShareMemory->ap_flag,
+ mShareMemory->md_flag,
+ mShareMemory->struct_checksum);
+
+ ALOGD("%s(), [sph_param] offset: %u, size: %u, [ap_data] offset: %u, size: %u, [md_data] offset: %u, size: %u",
+ __FUNCTION__,
+ mShareMemory->region.sph_param_region.offset,
+ mShareMemory->region.sph_param_region.size,
+ mShareMemory->region.ap_data_region.offset,
+ mShareMemory->region.ap_data_region.size,
+ mShareMemory->region.md_data_region.offset,
+ mShareMemory->region.md_data_region.size);
+
+ ALOGD("%s(), [sph_param] read_idx: %u, write_idx: %u, [ap_data] read_idx: %u, write_idx: %u, "
+ "[md_data] read_idx: %u, write_idx: %u",
+ __FUNCTION__,
+ mShareMemory->region.sph_param_region.read_idx,
+ mShareMemory->region.sph_param_region.write_idx,
+ mShareMemory->region.ap_data_region.read_idx,
+ mShareMemory->region.ap_data_region.write_idx,
+ mShareMemory->region.md_data_region.read_idx,
+ mShareMemory->region.md_data_region.write_idx);
+
+ return 0;
+}
+
+int SpeechExtMemCCCI::resetShareMemoryIndex() {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return 0;
+#endif
+
+ AL_AUTOLOCK(mShareMemoryLock);
+
+ if (!mShareMemory) {
+ ALOGW("%s(), NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ /* enable ap write flag */
+ mShareMemory->ap_flag |= SPH_SHM_AP_FLAG_SPH_PARAM_WRITE;
+
+ if (mShareMemory->md_flag & SPH_SHM_MD_FLAG_SPH_PARAM_READ) {
+ ALOGE("%s(), modem still read!! md_flag: 0x%x", __FUNCTION__,
+ mShareMemory->md_flag);
+ WARNING("md_flag error!!");
+ mShareMemory->ap_flag &= (~SPH_SHM_AP_FLAG_SPH_PARAM_WRITE);
+ return -EBUSY;
+ }
+
+
+ /* sph_param */
+ mShareMemory->region.sph_param_region.read_idx = 0;
+ mShareMemory->region.sph_param_region.write_idx = 0;
+
+ /* ap data */
+ mShareMemory->region.ap_data_region.read_idx = 0;
+ mShareMemory->region.ap_data_region.write_idx = 0;
+
+ /* md data */
+ mShareMemory->region.md_data_region.read_idx = 0;
+ mShareMemory->region.md_data_region.write_idx = 0;
+
+ /* disable ap write flag */
+ mShareMemory->ap_flag &= (~SPH_SHM_AP_FLAG_SPH_PARAM_WRITE);
+
+ return 0;
+}
+
+int SpeechExtMemCCCI::writeSphParamToShareMemory(const void *p_sph_param,
+ uint32_t sph_param_length,
+ uint32_t *p_write_idx) {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return -ENODEV;
+#endif
+
+ AL_AUTOLOCK(mShareMemoryLock);
+
+ if (!p_sph_param) {
+ ALOGE("%s(), p_sph_param NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ if (!p_write_idx) {
+ ALOGE("%s(), p_write_idx NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ if (!mShareMemory) {
+ ALOGE("%s(), mShareMemory NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ mShareMemory->ap_flag |= SPH_SHM_AP_FLAG_SPH_PARAM_WRITE;
+
+ if (mShareMemory->md_flag & SPH_SHM_MD_FLAG_SPH_PARAM_READ) {
+ ALOGW("%s(), modem still read!! md_flag: 0x%x", __FUNCTION__,
+ mShareMemory->md_flag);
+ mShareMemory->ap_flag &= (~SPH_SHM_AP_FLAG_SPH_PARAM_WRITE);
+ return -EBUSY;
+ }
+
+ region_info_t *p_region = &mShareMemory->region.sph_param_region;
+ uint16_t free_space = (uint16_t)shm_region_free_space(p_region);
+
+ if (sph_param_length > free_space) {
+ ALOGW("%s(), sph_param_length %u > free_space %u!!", __FUNCTION__,
+ sph_param_length, free_space);
+ return -ENOMEM;
+ }
+
+ /* keep the data index before write */
+ *p_write_idx = (uint16_t)p_region->write_idx;
+
+ /* write sph param */
+ shm_region_write_from_linear(p_region, p_sph_param, sph_param_length);
+
+ mShareMemory->ap_flag &= (~SPH_SHM_AP_FLAG_SPH_PARAM_WRITE);
+ return 0;
+}
+
+
+int SpeechExtMemCCCI::writeApDataToShareMemory(const void *p_data_buf,
+ uint16_t data_type,
+ uint16_t data_size,
+ uint16_t *p_payload_length,
+ uint32_t *p_write_idx) {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return -ENODEV;
+#endif
+
+ AL_AUTOLOCK(mShareMemoryLock);
+
+ if (!p_data_buf) {
+ ALOGE("%s(), p_data_buf NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+ if (!p_payload_length) {
+ ALOGE("%s(), p_payload_length NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+ if (!p_write_idx) {
+ ALOGE("%s(), p_write_idx NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+ if (!mShareMemory) {
+ ALOGE("%s(), mShareMemory NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ region_info_t *p_region = &mShareMemory->region.ap_data_region;
+
+ uint16_t payload_length = CCCI_MAX_AP_PAYLOAD_HEADER_SIZE + data_size;
+ uint16_t free_space = (uint16_t)shm_region_free_space(p_region);
+
+ if (payload_length > free_space) {
+ ALOGW("%s(), payload_length %u > free_space %u!!", __FUNCTION__,
+ payload_length, free_space);
+ *p_payload_length = 0;
+ return -ENOMEM;
+ }
+
+ /* keep the data index before write */
+ *p_write_idx = p_region->write_idx;
+
+ /* write header */
+ uint16_t header[3] = {0};
+ header[0] = CCCI_AP_PAYLOAD_SYNC;
+ header[1] = data_type;
+ header[2] = data_size;
+ shm_region_write_from_linear(p_region, header, CCCI_MAX_AP_PAYLOAD_HEADER_SIZE);
+
+ /* write data */
+ shm_region_write_from_linear(p_region, p_data_buf, data_size);
+
+ *p_payload_length = payload_length;
+ return 0;
+}
+
+
+int SpeechExtMemCCCI::readMdDataFromShareMemory(void *p_data_buf,
+ uint16_t *p_data_type,
+ uint16_t *p_data_size,
+ uint16_t payload_length,
+ uint32_t read_idx) {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return -ENODEV;
+#endif
+
+ AL_AUTOLOCK(mShareMemoryLock);
+
+ if (!p_data_buf) {
+ ALOGE("%s(), p_data_buf NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+ if (!p_data_type) {
+ ALOGE("%s(), p_data_type NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+ if (!p_data_size) {
+ ALOGE("%s(), p_data_size NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+ if (!mShareMemory) {
+ ALOGE("%s(), mShareMemory NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ region_info_t *p_region = &mShareMemory->region.md_data_region;
+
+ uint16_t data_size = payload_length - CCCI_MAX_MD_PAYLOAD_HEADER_SIZE;
+ uint32_t available_count = shm_region_data_count(p_region);
+
+ if (data_size > *p_data_size) {
+ ALOGW("%s(), data_size %u > p_data_buf size %u!!", __FUNCTION__,
+ data_size, *p_data_size);
+ *p_data_size = 0;
+ WARNING("-ENOMEM");
+ return -ENOMEM;
+ }
+
+ if (payload_length > available_count) {
+ ALOGW("%s(), payload_length %u > available_count %u!!", __FUNCTION__,
+ payload_length, available_count);
+ *p_data_size = 0;
+ return -ENOMEM;
+ }
+
+ /* check read index */
+ if (read_idx != p_region->read_idx) {
+ ALOGW("%s(), read_idx 0x%x != p_region->read_idx 0x%x!!", __FUNCTION__,
+ read_idx, p_region->read_idx);
+ WARNING("bad read_idx!!");
+ ALOGE("%s(), [sph_param] read_idx: %u, write_idx: %u, [ap_data] read_idx: %u, write_idx: %u, "
+ "[md_data] read_idx: %u, write_idx: %u",
+ __FUNCTION__,
+ mShareMemory->region.sph_param_region.read_idx,
+ mShareMemory->region.sph_param_region.write_idx,
+ mShareMemory->region.ap_data_region.read_idx,
+ mShareMemory->region.ap_data_region.write_idx,
+ mShareMemory->region.md_data_region.read_idx,
+ mShareMemory->region.md_data_region.write_idx);
+
+ p_region->read_idx = read_idx;
+ }
+
+ /* read header */
+ uint16_t header[5] = {0};
+ shm_region_read_to_linear(header, p_region, CCCI_MAX_MD_PAYLOAD_HEADER_SIZE);
+
+ if (header[0] != CCCI_MD_PAYLOAD_SYNC ||
+ header[2] != data_size ||
+ header[3] != header[4]) {
+ ALOGE("%s(), sync: 0x%x, type: %d, size: 0x%x, idx: %d, total_idx: %d",
+ __FUNCTION__, header[0], header[1], header[2], header[3], header[4]);
+ WARNING("md data header error");
+ *p_data_size = 0;
+ return -EINVAL;
+ }
+
+ *p_data_type = header[1];
+
+
+ /* read data */
+ shm_region_read_to_linear(p_data_buf, p_region, data_size);
+
+ *p_data_size = data_size;
+ return 0;
+
+}
+
+uint32_t SpeechExtMemCCCI::shm_region_data_count(region_info_t *p_region) {
+ if (!p_region) {
+ ALOGE("%s(), p_region NULL!! return 0", __FUNCTION__);
+ return 0;
+ }
+
+ if (p_region->read_idx >= p_region->size) {
+ ALOGE("%s(), offset: 0x%x, size: 0x%x, read_idx : 0x%x, write_idx: 0x%x", __FUNCTION__,
+ p_region->offset, p_region->size, p_region->read_idx, p_region->write_idx);
+ WARNING("read idx error");
+ p_region->read_idx %= p_region->size;
+ } else if (p_region->write_idx >= p_region->size) {
+ ALOGE("%s(), offset: 0x%x, size: 0x%x, read_idx : 0x%x, write_idx: 0x%x", __FUNCTION__,
+ p_region->offset, p_region->size, p_region->read_idx, p_region->write_idx);
+ WARNING("write idx error");
+ p_region->write_idx %= p_region->size;
+ }
+
+ uint32_t count = 0;
+
+ if (p_region->write_idx >= p_region->read_idx) {
+ count = p_region->write_idx - p_region->read_idx;
+ } else {
+ count = p_region->size - (p_region->read_idx - p_region->write_idx);
+ }
+
+ return count;
+}
+
+
+uint32_t SpeechExtMemCCCI::shm_region_free_space(region_info_t *p_region) {
+ if (!p_region) {
+ ALOGE("%s(), p_region NULL!! return 0", __FUNCTION__);
+ return 0;
+ }
+
+ uint32_t count = p_region->size - shm_region_data_count(p_region);
+
+ if (count >= MAX_SIZE_OF_ONE_FRAME) {
+ count -= MAX_SIZE_OF_ONE_FRAME;
+ } else {
+ count = 0;
+ }
+
+ return count;
+}
+
+
+void SpeechExtMemCCCI::shm_region_write_from_linear(region_info_t *p_region,
+ const void *linear_buf,
+ uint32_t count) {
+ if (!p_region) {
+ ALOGE("%s(), p_region NULL!! return", __FUNCTION__);
+ return;
+ }
+ if (!linear_buf) {
+ ALOGE("%s(), linear_buf NULL!! return", __FUNCTION__);
+ return;
+ }
+ if (!mShareMemory) {
+ ALOGE("%s(), mShareMemory NULL!! return", __FUNCTION__);
+ return;
+ }
+
+ if (p_region->read_idx >= p_region->size) {
+ ALOGE("%s(), offset: 0x%x, size: 0x%x, read_idx : 0x%x, write_idx: 0x%x, count: 0x%x", __FUNCTION__,
+ p_region->offset, p_region->size, p_region->read_idx, p_region->write_idx, count);
+ WARNING("read idx error");
+ p_region->read_idx %= p_region->size;
+ } else if (p_region->write_idx >= p_region->size) {
+ ALOGE("%s(), offset: 0x%x, size: 0x%x, read_idx : 0x%x, write_idx: 0x%x, count: 0x%x", __FUNCTION__,
+ p_region->offset, p_region->size, p_region->read_idx, p_region->write_idx, count);
+ WARNING("write idx error");
+ p_region->write_idx %= p_region->size;
+ }
+
+
+ SPH_LOG_V("%s(+), offset: 0x%x, size: 0x%x, read_idx : 0x%x, write_idx: 0x%x, count: 0x%x", __FUNCTION__,
+ p_region->offset, p_region->size, p_region->read_idx, p_region->write_idx, count);
+
+ uint32_t free_space = shm_region_free_space(p_region);
+ uint8_t *p_buf = ((uint8_t *)mShareMemory) + p_region->offset;
+
+ ASSERT(free_space >= count);
+
+ if (p_region->read_idx <= p_region->write_idx) {
+ uint32_t w2e = p_region->size - p_region->write_idx;
+ if (count <= w2e) {
+ sph_memcpy(p_buf + p_region->write_idx, linear_buf, count);
+ p_region->write_idx += count;
+ if (p_region->write_idx == p_region->size) {
+ p_region->write_idx = 0;
+ }
+ } else {
+ sph_memcpy(p_buf + p_region->write_idx, linear_buf, w2e);
+ sph_memcpy(p_buf, (uint8_t *)linear_buf + w2e, count - w2e);
+ p_region->write_idx = count - w2e;
+ }
+ } else {
+ sph_memcpy(p_buf + p_region->write_idx, linear_buf, count);
+ p_region->write_idx += count;
+ }
+
+ SPH_LOG_V("%s(-), offset: 0x%x, size: 0x%x, read_idx : 0x%x, write_idx: 0x%x, count: 0x%x", __FUNCTION__,
+ p_region->offset, p_region->size, p_region->read_idx, p_region->write_idx, count);
+}
+
+
+
+
+void SpeechExtMemCCCI::shm_region_read_to_linear(void *linear_buf,
+ region_info_t *p_region,
+ uint32_t count) {
+ if (!p_region) {
+ ALOGE("%s(), p_region NULL!! return", __FUNCTION__);
+ return;
+ }
+ if (!linear_buf) {
+ ALOGE("%s(), linear_buf NULL!! return", __FUNCTION__);
+ return;
+ }
+ if (!mShareMemory) {
+ ALOGE("%s(), mShareMemory NULL!! return", __FUNCTION__);
+ return;
+ }
+
+ if (p_region->read_idx >= p_region->size) {
+ ALOGE("%s(), offset: 0x%x, size: 0x%x, read_idx : 0x%x, write_idx: 0x%x, count: 0x%x", __FUNCTION__,
+ p_region->offset, p_region->size, p_region->read_idx, p_region->write_idx, count);
+ WARNING("read idx error");
+ p_region->read_idx %= p_region->size;
+ } else if (p_region->write_idx >= p_region->size) {
+ ALOGE("%s(), offset: 0x%x, size: 0x%x, read_idx : 0x%x, write_idx: 0x%x, count: 0x%x", __FUNCTION__,
+ p_region->offset, p_region->size, p_region->read_idx, p_region->write_idx, count);
+ WARNING("write idx error");
+ p_region->write_idx %= p_region->size;
+ }
+
+
+ SPH_LOG_V("%s(+), offset: 0x%x, size: 0x%x, read_idx : 0x%x, write_idx: 0x%x, count: 0x%x", __FUNCTION__,
+ p_region->offset, p_region->size, p_region->read_idx, p_region->write_idx, count);
+
+ uint32_t available_count = shm_region_data_count(p_region);
+ uint8_t *p_buf = ((uint8_t *)mShareMemory) + p_region->offset;
+
+ ASSERT(count <= available_count);
+
+ if (p_region->read_idx <= p_region->write_idx) {
+ sph_memcpy(linear_buf, p_buf + p_region->read_idx, count);
+ p_region->read_idx += count;
+ } else {
+ uint32_t r2e = p_region->size - p_region->read_idx;
+ if (r2e >= count) {
+ sph_memcpy(linear_buf, p_buf + p_region->read_idx, count);
+ p_region->read_idx += count;
+ if (p_region->read_idx == p_region->size) {
+ p_region->read_idx = 0;
+ }
+ } else {
+ sph_memcpy(linear_buf, p_buf + p_region->read_idx, r2e);
+ sph_memcpy((uint8_t *)linear_buf + r2e, p_buf, count - r2e);
+ p_region->read_idx = count - r2e;
+ }
+ }
+
+ SPH_LOG_V("%s(-), offset: 0x%x, size: 0x%x, read_idx : 0x%x, write_idx: 0x%x, count: 0x%x", __FUNCTION__,
+ p_region->offset, p_region->size, p_region->read_idx, p_region->write_idx, count);
+}
+
+bool SpeechExtMemCCCI::checkModemAlive() {
+ if (!mShareMemory) {
+ ALOGW("%s(), mShareMemory NULL!! return false", __FUNCTION__);
+ return false;
+ }
+
+ return ((mShareMemory->md_flag & SPH_SHM_MD_FLAG_ALIVE) > 0);
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechExtMemUSIP.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechExtMemUSIP.cpp
new file mode 100644
index 0000000..c0c93ae
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechExtMemUSIP.cpp
@@ -0,0 +1,431 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechExtMemUSIP"
+#include <SpeechExtMemUSIP.h>
+#include <SpeechMessengerNormal.h>
+#include <utils/Log.h>
+#include <cutils/properties.h>
+
+#include <sys/mman.h>
+#include <AudioAssert.h>//Mutex/assert
+#include <SpeechUtility.h>
+#include <SpeechCCCIType.h>
+#include <AudioUtility.h>
+
+
+namespace android {
+
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+//#define ENABLE_SPH_USIP_DUMP
+#define SPH_DUMP_STR_SIZE (1024)
+#define USIP_EMP_IOC_MAGIC 'D'
+#define GET_USIP_EMI_SIZE _IOWR(USIP_EMP_IOC_MAGIC, 0xF0, unsigned long long)
+
+#define SPEECH_USIP_SHM_SIZE (192* 1024)
+#define SPEECH_USIP_SHM_CACHE_RESERVE_SIZE (3072)
+#define SPEECH_USIP_SHM_GUARD_REGION_SIZE (32)
+#define SPEECH_USIP_SHM_SPEECH_PARAM_SIZE (180192)//184k-32
+#define SPEECH_USIP_SHM_MD_PRIVATE_SIZE (13272)//16k-3k-40
+
+typedef struct region_info_t {
+ uint32_t offset; /* ex: 0x1000 */ /* count from the address of sph_usip_shm_t */
+ uint32_t size; /* ex: 0x100 */
+ uint32_t read_idx; /* ex: 0x0 ~ 0xFF */
+ uint32_t write_idx; /* ex: 0x0 ~ 0xFF */
+} region_info_t; /* 16 bytes */
+
+typedef struct sph_usip_shm_t {
+
+ /* 3072 bytes reserve */
+ uint8_t cache_reserved[SPEECH_USIP_SHM_CACHE_RESERVE_SIZE];
+
+ /*32 bytes gurard region */
+ uint8_t guard_region_pre[SPEECH_USIP_SHM_GUARD_REGION_SIZE];
+
+ /* 8 bytes memory block offset */
+ uint32_t md_private_range_offset; /* offset of md_private_range*/
+ uint32_t sph_param_offset; /* offset of sph_param*/
+
+ /* 13272 bytes reserve */
+ uint8_t md_private_range[SPEECH_USIP_SHM_MD_PRIVATE_SIZE];
+
+ /* 184K-32 bytes speech param */
+ uint8_t sph_param[SPEECH_USIP_SHM_SPEECH_PARAM_SIZE];
+
+ /*32 bytes gurard region */
+ uint8_t guard_region_post[SPEECH_USIP_SHM_GUARD_REGION_SIZE];
+} sph_usip_shm_t;
+
+/*
+ * =============================================================================
+ * global value
+ * =============================================================================
+ */
+
+static const char kPropertyKeyShareMemoryInit[PROPERTY_KEY_MAX] = "vendor.audiohal.speech.shm_usip";
+static char const *const kUsipDeviceName = "/dev/usip";
+static const char kPropertyKeySphParamWriteIdx[PROPERTY_KEY_MAX] = "vendor.audiohal.speech.shm_widx";
+
+/*
+ * =============================================================================
+ * class implementation
+ * =============================================================================
+ */
+SpeechExtMemUSIP::SpeechExtMemUSIP() {
+ ALOGD("%s()", __FUNCTION__);
+ mModemIndex = MODEM_1;
+ mCcciShareMemoryHandler = -1;
+ mShareMemoryBase = NULL;
+ mShareMemoryLength = 0;
+ mShareMemory = NULL;
+ mSpeechParamRegion = NULL;
+ AUDIO_ALLOC_STRUCT(region_info_t, mSpeechParamRegion);
+}
+
+SpeechExtMemUSIP::~SpeechExtMemUSIP() {
+ ALOGD("%s()", __FUNCTION__);
+ AUDIO_FREE_POINTER(mSpeechParamRegion);
+}
+
+int SpeechExtMemUSIP::openShareMemory(const modem_index_t modem_index) {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return 0;
+#endif
+ mModemIndex = modem_index;
+
+ if (mCcciShareMemoryHandler >= 0 &&
+ mShareMemoryBase != NULL &&
+ mShareMemoryLength >= sizeof(sph_usip_shm_t)) {
+ ALOGD("%s(), modem_index: %d, mCcciShareMemoryHandler: %d, mShareMemoryBase: %p, "
+ "mShareMemoryLength: %u already open",
+ __FUNCTION__, modem_index, mCcciShareMemoryHandler, mShareMemoryBase, (uint32_t)mShareMemoryLength);
+ return 0;
+ }
+
+ // get share momoey address
+ mCcciShareMemoryHandler = open(kUsipDeviceName, O_RDWR);
+ ALOGD("%s(), mCcciShareMemoryHandler = %d", __FUNCTION__, mCcciShareMemoryHandler);
+ unsigned long long byteMemory = 0;
+
+ if (mCcciShareMemoryHandler < 0) {
+ ALOGE("%s(), open(%s) fail, mCcciShareMemoryHandler = %d, errno: %d",
+ __FUNCTION__, kUsipDeviceName, mCcciShareMemoryHandler, errno);
+ return -ENODEV;
+ }
+
+ ::ioctl(mCcciShareMemoryHandler, GET_USIP_EMI_SIZE, &byteMemory);
+ ALOGD("%s(), GET_USIP_EMI_SIZE byteMemory = %llu", __FUNCTION__, byteMemory);
+ if (byteMemory == 0) {
+ ALOGE("%s(), byteMemory(%u) == 0", __FUNCTION__,
+ (uint32_t)byteMemory);
+ closeShareMemory();
+ return -EFAULT;
+ }
+
+ mShareMemoryLength = (unsigned int)byteMemory;
+ mShareMemoryBase = (unsigned char *)mmap(NULL, byteMemory,
+ PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, mCcciShareMemoryHandler, 0);
+
+ if (mShareMemoryBase == NULL || mShareMemoryBase == MAP_FAILED) {
+ ALOGE("%s(), failed to mmap buffer %d bytes, errno %d\n",
+ __FUNCTION__, 0x1000, errno);
+ closeShareMemory();
+ return -EFAULT;
+ }
+
+ ALOGD("%s(), mShareMemoryBase = %p, mShareMemoryLength=%d", __FUNCTION__, mShareMemoryBase, mShareMemoryLength);
+ ALOGD("%s(), mShareMemoryBase[0] = 0x%x", __FUNCTION__, mShareMemoryBase[0]);
+ ALOGD("%s(), mShareMemoryBase[1] = 0x%x", __FUNCTION__, mShareMemoryBase[1]);
+ ALOGD("%s(), mShareMemoryBase[2] = 0x%x", __FUNCTION__, mShareMemoryBase[2]);
+ ALOGD("%s(), mShareMemoryBase[3] = 0x%x", __FUNCTION__, mShareMemoryBase[3]);
+ ALOGD("%s(), mShareMemoryBase[4] = 0x%x", __FUNCTION__, mShareMemoryBase[4]);
+
+ if (mShareMemoryLength < sizeof(sph_usip_shm_t)) {
+ ALOGE("%s(), mShareMemoryLength(%u) < sizeof(sph_usip_shm_t): %u", __FUNCTION__,
+ (uint32_t)mShareMemoryLength, (uint32_t)sizeof(sph_usip_shm_t));
+ closeShareMemory();
+ return -ENOMEM;
+ }
+
+ int retval = 0;
+ if (get_uint32_from_mixctrl(kPropertyKeyShareMemoryInit) != 0) {
+ mShareMemory = (sph_usip_shm_t *)mShareMemoryBase;
+
+ } else {
+ retval = formatShareMemory();
+ }
+
+ return retval;
+}
+
+
+int SpeechExtMemUSIP::closeShareMemory() {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return 0;
+#endif
+
+ ALOGD("%s(), mCcciShareMemoryHandler: %d, mShareMemoryBase: %p, mShareMemoryLength: %u",
+ __FUNCTION__, mCcciShareMemoryHandler, mShareMemoryBase, mShareMemoryLength);
+
+ if (mCcciShareMemoryHandler >= 0) {
+
+ ::close(mCcciShareMemoryHandler);
+ mCcciShareMemoryHandler = -1;
+ mShareMemoryBase = NULL;
+ mShareMemoryLength = 0;
+ mShareMemory = NULL;
+ }
+
+ return 0;
+}
+
+int SpeechExtMemUSIP::formatShareMemory() {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return 0;
+#endif
+
+ AL_AUTOLOCK(mShareMemoryLock);
+
+ if (mShareMemoryBase == NULL || mShareMemoryLength < sizeof(sph_usip_shm_t)) {
+ ALOGE("%s(), mShareMemoryBase(%p) == NULL || mShareMemoryLength(%u) < sizeof(sph_usip_shm_t): %u",
+ __FUNCTION__, mShareMemoryBase, (uint32_t)mShareMemoryLength, (uint32_t)sizeof(sph_usip_shm_t));
+ WARNING("EFAULT");
+ return -EFAULT;
+ }
+
+ mShareMemory = (sph_usip_shm_t *)mShareMemoryBase;
+ /* sph_param region */
+ mSpeechParamRegion->offset = (uint8_t *)mShareMemory->sph_param - (uint8_t *)mShareMemory;
+ mSpeechParamRegion->size = SPEECH_USIP_SHM_SPEECH_PARAM_SIZE;
+ mSpeechParamRegion->read_idx = 0;
+
+ /* only format share memory once after boot */
+ if (get_uint32_from_mixctrl(kPropertyKeyShareMemoryInit) != 0) {
+ mSpeechParamRegion->write_idx = get_uint32_from_mixctrl(kPropertyKeySphParamWriteIdx);
+ goto FORMAT_SHARE_MEMORY_DONE;
+ }
+ /*32 bytes gurard region */
+ sph_memset(mShareMemory->guard_region_pre, 0x0A, SPEECH_USIP_SHM_GUARD_REGION_SIZE);
+
+ /* md_private_range_offset */
+ mShareMemory->md_private_range_offset = (uint8_t *)mShareMemory->md_private_range - (uint8_t *)mShareMemory;
+
+ /* sph_param_offset */
+ mShareMemory->sph_param_offset = (uint8_t *)mShareMemory->sph_param - (uint8_t *)mShareMemory;
+
+ /*32 bytes gurard region */
+ sph_memset(mShareMemory->guard_region_post, 0x0A, SPEECH_USIP_SHM_GUARD_REGION_SIZE);
+
+ mSpeechParamRegion->write_idx = 0;
+ // save write_idx in kernel to avoid medieserver die
+ set_uint32_to_mixctrl(kPropertyKeySphParamWriteIdx, 0);
+
+ /* init done flag */
+ set_uint32_to_mixctrl(kPropertyKeyShareMemoryInit, 1);
+
+
+FORMAT_SHARE_MEMORY_DONE:
+ ALOGD("%s(), [md_private_range] offset: %u, [sph_param] offset: %u",
+ __FUNCTION__,
+ mShareMemory->md_private_range_offset,
+ mShareMemory->sph_param_offset);
+
+ return 0;
+}
+
+int SpeechExtMemUSIP::resetShareMemoryIndex() {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return 0;
+#endif
+
+ AL_AUTOLOCK(mShareMemoryLock);
+
+ if (!mShareMemory) {
+ ALOGW("%s(), NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ /* sph_param */
+ mSpeechParamRegion->read_idx = 0;
+ mSpeechParamRegion->write_idx = 0;
+ // save write_idx in kernel to avoid medieserver die
+ set_uint32_to_mixctrl(kPropertyKeySphParamWriteIdx, 0);
+
+ return 0;
+}
+
+int SpeechExtMemUSIP::writeSphParamToShareMemory(const void *p_sph_param,
+ uint32_t sph_param_length,
+ uint32_t *p_write_idx) {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return -ENODEV;
+#endif
+
+ int retval = 0;
+ ALOGV("%s()", __FUNCTION__);
+
+ AL_AUTOLOCK(mShareMemoryLock);
+
+ if (!p_sph_param || !p_write_idx || !mShareMemory) {
+ ALOGW("%s(), NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+ if (sph_param_length == 0) {
+ ALOGW("%s(), sph_param_length=%d return", __FUNCTION__, sph_param_length);
+ return 0;
+ }
+
+ region_info_t *p_region = mSpeechParamRegion;
+
+ updateWriteIndex(p_region, sph_param_length);
+
+ /* keep the data index before write */
+ *p_write_idx = p_region->write_idx;
+
+#if defined(ENABLE_SPH_USIP_DUMP)
+ uint32_t dumpWriteIdx = p_region->write_idx / 2; //word
+ int idxDump = 10, numDump = 40, skipOffset = 3072 / 2;
+ char sphDumpStr[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphDumpStr, SPH_DUMP_STR_SIZE, "dump param[%p]= ", mSpeechParamRegion + p_region->write_idx);
+#endif
+
+ /* write sph param */
+ shm_region_write_from_linear(p_region, p_sph_param, sph_param_length);
+
+#if defined(ENABLE_SPH_USIP_DUMP)
+ for (int idxDump = 0; idxDump < numDump; idxDump++) {
+ char sphDumpTemp[100];
+ snprintf(sphDumpTemp, 100, "[%d]=0x%x,", idxDump,
+ *((uint16_t *)mSpeechParamRegion + dumpWriteIdx + skipOffset + idxDump));
+ audio_strncat(sphDumpStr, sphDumpTemp, SPH_DUMP_STR_SIZE);
+ }
+ if (idxDump != 0) {
+ ALOGD("%s(), %s", __FUNCTION__, sphDumpStr);
+ }
+#endif
+
+ return 0;
+}
+
+
+uint32_t SpeechExtMemUSIP::shm_region_data_count(region_info_t *p_region) {
+ if (!p_region) {
+ return 0;
+ }
+
+ if (p_region->read_idx >= p_region->size) {
+ ALOGE("%s(), offset: 0x%x, size: 0x%x, read_idx : 0x%x, write_idx: 0x%x", __FUNCTION__,
+ p_region->offset, p_region->size, p_region->read_idx, p_region->write_idx);
+ WARNING("read idx error");
+ p_region->read_idx %= p_region->size;
+ } else if (p_region->write_idx >= p_region->size) {
+ ALOGE("%s(), offset: 0x%x, size: 0x%x, read_idx : 0x%x, write_idx: 0x%x", __FUNCTION__,
+ p_region->offset, p_region->size, p_region->read_idx, p_region->write_idx);
+ WARNING("write idx error");
+ p_region->write_idx %= p_region->size;
+ }
+
+ uint32_t count = 0;
+ if (p_region->write_idx >= p_region->read_idx) {
+ count = p_region->write_idx - p_region->read_idx;
+ } else {
+ count = p_region->size - (p_region->read_idx - p_region->write_idx);
+ }
+
+ return count;
+}
+
+
+uint32_t SpeechExtMemUSIP::shm_region_free_space(region_info_t *p_region) {
+ if (!p_region) {
+ return 0;
+ }
+
+ uint32_t count = p_region->size - shm_region_data_count(p_region);
+
+ if (count >= MAX_SIZE_OF_ONE_FRAME) {
+ count -= MAX_SIZE_OF_ONE_FRAME;
+ } else {
+ count = 0;
+ }
+
+ return count;
+}
+
+int SpeechExtMemUSIP::updateWriteIndex(region_info_t *p_region,
+ uint32_t count) {
+ if (!p_region) {
+ return 0;
+ }
+
+ uint32_t leftBytes = p_region->size - p_region->write_idx;
+
+ if (count > leftBytes) {
+ p_region->write_idx = 0;
+ // save write_idx in kernel to avoid medieserver die
+ set_uint32_to_mixctrl(kPropertyKeySphParamWriteIdx, p_region->write_idx);
+ }
+ ALOGD("%s(), offset: 0x%x, size: 0x%x, read_idx : 0x%x, write_idx: 0x%x, count: 0x%x, leftBytes: 0x%x",
+ __FUNCTION__, p_region->offset, p_region->size, p_region->read_idx, p_region->write_idx, count, leftBytes);
+ return 0;
+}
+
+void SpeechExtMemUSIP::shm_region_write_from_linear(region_info_t *p_region,
+ const void *linear_buf,
+ uint32_t count) {
+ if (!p_region || !linear_buf || !mShareMemory) {
+ return;
+ }
+
+ if (p_region->read_idx >= p_region->size) {
+ ALOGE("%s(), offset: 0x%x, size: 0x%x, read_idx : 0x%x, write_idx: 0x%x, count: 0x%x", __FUNCTION__,
+ p_region->offset, p_region->size, p_region->read_idx, p_region->write_idx, count);
+ WARNING("read idx error");
+ p_region->read_idx %= p_region->size;
+ } else if (p_region->write_idx >= p_region->size) {
+ ALOGE("%s(), offset: 0x%x, size: 0x%x, read_idx : 0x%x, write_idx: 0x%x, count: 0x%x", __FUNCTION__,
+ p_region->offset, p_region->size, p_region->read_idx, p_region->write_idx, count);
+ WARNING("write idx error");
+ p_region->write_idx %= p_region->size;
+ }
+
+ SPH_LOG_V("%s(+), offset: 0x%x, size: 0x%x, read_idx : 0x%x, write_idx: 0x%x, count: 0x%x", __FUNCTION__,
+ p_region->offset, p_region->size, p_region->read_idx, p_region->write_idx, count);
+
+ uint32_t free_space = shm_region_free_space(p_region);
+ uint8_t *p_buf = ((uint8_t *)mShareMemory) + p_region->offset;
+
+ ASSERT(free_space >= count);
+
+ if (p_region->read_idx <= p_region->write_idx) {
+ uint32_t w2e = p_region->size - p_region->write_idx;
+ if (count <= w2e) {
+ sph_memcpy(p_buf + p_region->write_idx, linear_buf, count);
+ p_region->write_idx += count;
+ if (p_region->write_idx == p_region->size) {
+ p_region->write_idx = 0;
+ }
+ } else {
+ sph_memcpy(p_buf + p_region->write_idx, linear_buf, w2e);
+ sph_memcpy(p_buf, (uint8_t *)linear_buf + w2e, count - w2e);
+ p_region->write_idx = count - w2e;
+ }
+ } else {
+ sph_memcpy(p_buf + p_region->write_idx, linear_buf, count);
+ p_region->write_idx += count;
+ }
+ // save write_idx in kernel to avoid medieserver die
+ set_uint32_to_mixctrl(kPropertyKeySphParamWriteIdx, p_region->write_idx);
+
+ SPH_LOG_V("%s(-), offset: 0x%x, size: 0x%x, read_idx : 0x%x, write_idx: 0x%x, count: 0x%x", __FUNCTION__,
+ p_region->offset, p_region->size, p_region->read_idx, p_region->write_idx, count);
+}
+
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechMessageID.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechMessageID.cpp
new file mode 100644
index 0000000..df1b623
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechMessageID.cpp
@@ -0,0 +1,436 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <SpeechMessageID.h>
+
+#include <errno.h>
+
+#include <log/log.h>
+
+#include <SpeechType.h>
+
+#include <AudioAssert.h>
+
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechMessageID"
+
+
+namespace android {
+
+
+uint16_t getSyncType(const uint16_t msg_id) {
+ sph_msg_handshake_t handshake = SPH_MSG_HANDSHAKE_INVALID;
+
+ switch (msg_id) {
+ /**
+ * =========================================================================
+ * ap control
+ * =========================================================================
+ */
+ /* ap bypass ack */
+ case MSG_A2M_SPH_DL_DIGIT_VOLUME:
+ case MSG_A2M_SPH_UL_DIGIT_VOLUME:
+ case MSG_A2M_SPH_DL_ENH_REF_DIGIT_VOLUME:
+ case MSG_A2M_MUTE_SPH_DL_CODEC:
+ case MSG_A2M_SET_LPBK_POINT_DVT:
+ case MSG_A2M_CTRL_SPH_ENH:
+ case MSG_A2M_ENH_CTRL_SUPPORT:
+ case MSG_A2M_CTM_DUMP_DEBUG_FILE:
+ case MSG_A2M_BGSND_CONFIG:
+ case MSG_A2M_PCMMIXER_CONFIG:
+ handshake = SPH_MSG_HANDSHAKE_AP_CTRL_BYPASS_ACK;
+ break;
+ /* ap need ack */
+ case MSG_A2M_MUTE_SPH_UL:
+ case MSG_A2M_MUTE_SPH_DL:
+ case MSG_A2M_MUTE_SPH_UL_SOURCE:
+ case MSG_A2M_SPH_ON:
+ case MSG_A2M_SPH_OFF:
+ case MSG_A2M_SPH_DEV_CHANGE:
+ case MSG_A2M_PNW_ON:
+ case MSG_A2M_PNW_OFF:
+ case MSG_A2M_VM_REC_ON:
+ case MSG_A2M_VM_REC_OFF:
+ case MSG_A2M_RECORD_RAW_PCM_ON:
+ case MSG_A2M_RECORD_RAW_PCM_OFF:
+ case MSG_A2M_CTM_ON:
+ case MSG_A2M_CTM_OFF:
+ case MSG_A2M_BGSND_ON:
+ case MSG_A2M_BGSND_OFF:
+ case MSG_A2M_EM_DYNAMIC_SPH:
+ case MSG_A2M_DYNAMIC_PAR_IN_STRUCT_SHM:
+ case MSG_A2M_VIBSPK_PARAMETER:
+ case MSG_A2M_PCMMIXER_ON:
+ case MSG_A2M_PCMMIXER_OFF:
+ case MSG_A2M_ECALL_CTL_SEQ_SWITCH:
+ case MSG_A2M_IVS_SWITCH:
+ case MSG_A2M_PSAP_SWITCH:
+ case MSG_A2M_ECALL_MSD:
+ case MSG_A2M_ECALL_TX_CTRL_PAR:
+ handshake = SPH_MSG_HANDSHAKE_AP_CTRL_NEED_ACK;
+ break;
+ /* modem ack back */
+ case MSG_M2A_MUTE_SPH_UL_ACK:
+ case MSG_M2A_MUTE_SPH_DL_ACK:
+ case MSG_M2A_MUTE_SPH_UL_SOURCE_ACK:
+ case MSG_M2A_SPH_ON_ACK:
+ case MSG_M2A_SPH_OFF_ACK:
+ case MSG_M2A_SPH_DEV_CHANGE_ACK:
+ case MSG_M2A_PNW_ON_ACK:
+ case MSG_M2A_PNW_OFF_ACK:
+ case MSG_M2A_VM_REC_ON_ACK:
+ case MSG_M2A_VM_REC_OFF_ACK:
+ case MSG_M2A_RECORD_RAW_PCM_ON_ACK:
+ case MSG_M2A_RECORD_RAW_PCM_OFF_ACK:
+ case MSG_M2A_CTM_ON_ACK:
+ case MSG_M2A_CTM_OFF_ACK:
+ case MSG_M2A_BGSND_ON_ACK:
+ case MSG_M2A_BGSND_OFF_ACK:
+ case MSG_M2A_EM_DYNAMIC_SPH_ACK:
+ case MSG_M2A_DYNAMIC_PAR_IN_STRUCT_SHM_ACK:
+ case MSG_M2A_VIBSPK_PARAMETER_ACK:
+ case MSG_M2A_SMARTPA_PARAMETER_ACK:
+ case MSG_M2A_PCMMIXER_ON_ACK:
+ case MSG_M2A_PCMMIXER_OFF_ACK:
+ case MSG_M2A_ECALL_CTL_SEQ_SWITCH_ACK:
+ case MSG_M2A_IVS_SWITCH_ACK:
+ case MSG_M2A_PSAP_SWITCH_ACK:
+ case MSG_M2A_ECALL_MSD_ACK:
+ case MSG_M2A_ECALL_TX_CTRL_PAR_ACK:
+ handshake = SPH_MSG_HANDSHAKE_MD_ACK_BACK_AP_CTRL;
+ break;
+
+ /**
+ * =========================================================================
+ * md control
+ * =========================================================================
+ */
+ /* md bypass ack */
+ case MSG_M2A_NETWORK_STATUS_NOTIFY:
+ case MSG_M2A_EM_DATA_REQUEST:
+ handshake = SPH_MSG_HANDSHAKE_MD_CTRL_BYPASS_ACK;
+ break;
+ /* md need ack */
+ case MSG_M2A_EPOF_NOTIFY:
+ case MSG_M2A_MD_ALIVE:
+ case MSG_M2A_NW_CODEC_INFO_NOTIFY:
+ case MSG_M2A_ECALL_HANDSHAKE_INFO:
+ handshake = SPH_MSG_HANDSHAKE_MD_CTRL_NEED_ACK;
+ break;
+ /* ap ack back */
+ case MSG_A2M_EPOF_ACK:
+ case MSG_A2M_MD_ALIVE_ACK_BACK:
+ case MSG_A2M_NW_CODEC_INFO_READ_ACK:
+ case MSG_A2M_ECALL_HANDSHAKE_INFO_READ_ACK:
+ handshake = SPH_MSG_HANDSHAKE_AP_ACK_BACK_MD_CTRL;
+ break;
+
+ /**
+ * =========================================================================
+ * ap data
+ * =========================================================================
+ */
+ /* modem request data */
+ case MSG_M2A_PNW_DL_DATA_REQUEST:
+ case MSG_M2A_BGSND_DATA_REQUEST:
+ case MSG_M2A_PCMMIXER_DL_DATA_REQUEST:
+ case MSG_M2A_PCMMIXER_UL_DATA_REQUEST:
+ handshake = SPH_MSG_HANDSHAKE_MD_REQUEST_DATA;
+ break;
+ /* ap notify data */
+ case MSG_A2M_PNW_DL_DATA_NOTIFY:
+ case MSG_A2M_BGSND_DATA_NOTIFY:
+ case MSG_A2M_PCMMIXER_DL_DATA_NOTIFY:
+ case MSG_A2M_PCMMIXER_UL_DATA_NOTIFY:
+ handshake = SPH_MSG_HANDSHAKE_AP_NOTIFY_DATA;
+ break;
+
+ /**
+ * =========================================================================
+ * md data
+ * =========================================================================
+ */
+ /* md notify data */
+ case MSG_M2A_PNW_UL_DATA_NOTIFY:
+ case MSG_M2A_CTM_DEBUG_DATA_NOTIFY:
+ case MSG_M2A_VM_REC_DATA_NOTIFY:
+ case MSG_M2A_RAW_PCM_REC_DATA_NOTIFY:
+ case MSG_M2A_CUST_DUMP_NOTIFY:
+ case MSG_M2A_ECALL_RX_CTRL_PAR_NOTIFY:
+ handshake = SPH_MSG_HANDSHAKE_MD_NOTIFY_DATA;
+ break;
+ /* ap read data done */
+ case MSG_A2M_PNW_UL_DATA_READ_ACK:
+ case MSG_A2M_CTM_DEBUG_DATA_READ_ACK:
+ case MSG_A2M_VM_REC_DATA_READ_ACK:
+ case MSG_A2M_RAW_PCM_REC_DATA_READ_ACK:
+ case MSG_A2M_CUST_DUMP_READ_ACK:
+ case MSG_A2M_ECALL_RX_CTRL_READ_ACK:
+ handshake = SPH_MSG_HANDSHAKE_AP_READ_DATA_DONE;
+ break;
+ /**
+ * =========================================================================
+ * error handling
+ * =========================================================================
+ */
+ default:
+ ALOGD("%s(), not supported msg_id 0x%x", __FUNCTION__, msg_id);
+ handshake = SPH_MSG_HANDSHAKE_INVALID;
+ }
+
+ return handshake;
+}
+
+
+bool isApMsgBypassQueue(const struct sph_msg_t *p_sph_msg) {
+ bool retval = false;
+
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return 0;
+ }
+
+ switch (getSyncType(p_sph_msg->msg_id)) {
+ case SPH_MSG_HANDSHAKE_AP_ACK_BACK_MD_CTRL:
+ case SPH_MSG_HANDSHAKE_AP_NOTIFY_DATA:
+ case SPH_MSG_HANDSHAKE_AP_READ_DATA_DONE:
+ retval = true;
+ break;
+ default:
+ retval = false;
+ }
+
+ return retval;
+}
+
+
+bool isApNeedAck(const struct sph_msg_t *p_sph_msg) {
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return false;
+ }
+
+ return (getSyncType(p_sph_msg->msg_id) == SPH_MSG_HANDSHAKE_AP_CTRL_NEED_ACK);
+}
+
+bool isMdAckBack(const struct sph_msg_t *p_sph_msg) {
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return false;
+ }
+
+ return (getSyncType(p_sph_msg->msg_id) == SPH_MSG_HANDSHAKE_MD_ACK_BACK_AP_CTRL);
+}
+
+
+bool isApMsg(const struct sph_msg_t *p_sph_msg) {
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return false;
+ }
+
+ return ((p_sph_msg->msg_id & 0xFF00) == 0x2F00);
+}
+
+
+bool isMdMsg(const struct sph_msg_t *p_sph_msg) {
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return false;
+ }
+
+ return ((p_sph_msg->msg_id & 0xFF00) == 0xAF00);
+}
+
+
+int makeFakeMdAckMsgFromApMsg(struct sph_msg_t *p_sph_msg) {
+ int retval = 0;
+
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ if (isApMsg(p_sph_msg) == false) {
+ ALOGW("%s(), 0x%x not AP msg!! return", __FUNCTION__, p_sph_msg->msg_id);
+ return -EINVAL;
+ }
+
+ if (getSyncType(p_sph_msg->msg_id) != SPH_MSG_HANDSHAKE_AP_CTRL_NEED_ACK) {
+ ALOGW("%s(), 0x%x no need ack!! return", __FUNCTION__, p_sph_msg->msg_id);
+ return -EINVAL;
+ }
+
+ p_sph_msg->msg_id |= 0x8000;
+ if (getSyncType(p_sph_msg->msg_id) != SPH_MSG_HANDSHAKE_MD_ACK_BACK_AP_CTRL) {
+ ALOGE("%s(), 0x%x not MD msg ack!!", __FUNCTION__, p_sph_msg->msg_id);
+ ASSERT(getSyncType(p_sph_msg->msg_id) == SPH_MSG_HANDSHAKE_MD_ACK_BACK_AP_CTRL);
+ retval = -EBADMSG;
+ }
+
+ return retval;
+}
+
+
+bool isAckMessageInPair(const struct sph_msg_t *p_sph_msg,
+ const struct sph_msg_t *p_sph_msg_ack) {
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return false;
+ }
+ if (p_sph_msg_ack == NULL) {
+ ALOGW("%s(), p_sph_msg_ack == NULL!! return", __FUNCTION__);
+ return false;
+ }
+
+ if (isApMsg(p_sph_msg) && isMdMsg(p_sph_msg_ack)) {
+ return ((p_sph_msg->msg_id | 0x8000) == p_sph_msg_ack->msg_id);
+ } else {
+ return false;
+ }
+}
+
+
+bool isAckMessageInPairByID(const uint16_t ap_msg_id, const uint16_t md_msg_id) {
+ /* for ack match when AP recovery */
+ if ((ap_msg_id & 0xFF00) == 0x2F00 && (md_msg_id & 0xFF00) == 0xAF00) {
+ return ((ap_msg_id | 0x8000) == md_msg_id);
+ } else {
+ return false;
+ }
+}
+
+
+uint32_t getBlockThreadTimeMsByID(struct sph_msg_t *p_sph_msg) {
+ uint32_t block_thread_ms = 0;
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return 0;
+ }
+
+ switch (p_sph_msg->msg_id) {
+ case MSG_A2M_SPH_ON:
+ case MSG_A2M_SPH_OFF:
+ block_thread_ms = 500;
+ break;
+ case MSG_A2M_SPH_DEV_CHANGE:
+ block_thread_ms = 300;
+ break;
+ case MSG_A2M_BGSND_ON:
+ case MSG_A2M_BGSND_OFF:
+ case MSG_A2M_PCMMIXER_ON:
+ case MSG_A2M_PCMMIXER_OFF:
+ block_thread_ms = 100;
+ break;
+ case MSG_A2M_VM_REC_ON:
+ case MSG_A2M_VM_REC_OFF:
+ block_thread_ms = 300;
+ break;
+ case MSG_A2M_EM_DYNAMIC_SPH:
+ case MSG_A2M_DYNAMIC_PAR_IN_STRUCT_SHM:
+ case MSG_A2M_VIBSPK_PARAMETER:
+ block_thread_ms = 300;
+ break;
+ case MSG_A2M_CTRL_SPH_ENH:
+ case MSG_A2M_ENH_CTRL_SUPPORT:
+ block_thread_ms = 0;
+ break;
+ case MSG_A2M_PNW_ON:
+ case MSG_A2M_PNW_OFF:
+ case MSG_A2M_RECORD_RAW_PCM_ON:
+ case MSG_A2M_RECORD_RAW_PCM_OFF:
+ case MSG_A2M_CTM_ON:
+ case MSG_A2M_CTM_OFF:
+ block_thread_ms = 50;
+ break;
+ case MSG_A2M_EPOF_ACK:
+ block_thread_ms = 50;
+ break;
+ case MSG_A2M_SET_LPBK_POINT_DVT:
+ block_thread_ms = 50;
+ break;
+ case MSG_A2M_CTM_DUMP_DEBUG_FILE:
+ block_thread_ms = 50;
+ break;
+ case MSG_A2M_PNW_DL_DATA_NOTIFY:
+ case MSG_A2M_BGSND_DATA_NOTIFY:
+ case MSG_A2M_PCMMIXER_DL_DATA_NOTIFY:
+ case MSG_A2M_PCMMIXER_UL_DATA_NOTIFY:
+ block_thread_ms = 0;
+ break;
+ case MSG_A2M_MUTE_SPH_UL:
+ case MSG_A2M_MUTE_SPH_DL:
+ case MSG_A2M_MUTE_SPH_UL_SOURCE:
+ case MSG_A2M_MUTE_SPH_DL_CODEC:
+ block_thread_ms = 50;
+ break;
+ case MSG_A2M_PNW_UL_DATA_READ_ACK:
+ case MSG_A2M_CTM_DEBUG_DATA_READ_ACK:
+ case MSG_A2M_VM_REC_DATA_READ_ACK:
+ case MSG_A2M_RAW_PCM_REC_DATA_READ_ACK:
+ case MSG_A2M_CUST_DUMP_READ_ACK:
+ case MSG_A2M_NW_CODEC_INFO_READ_ACK:
+ block_thread_ms = 0;
+ break;
+ case MSG_A2M_SPH_DL_DIGIT_VOLUME:
+ case MSG_A2M_SPH_UL_DIGIT_VOLUME:
+ case MSG_A2M_SPH_DL_ENH_REF_DIGIT_VOLUME:
+ case MSG_A2M_BGSND_CONFIG:
+ case MSG_A2M_PCMMIXER_CONFIG:
+ block_thread_ms = 0;
+ break;
+
+ default:
+ ALOGW("%s(), non-block for msg_id 0x%x", __FUNCTION__, p_sph_msg->msg_id);
+ block_thread_ms = 0;
+ }
+
+ return block_thread_ms;
+}
+
+
+
+bool isNeedDumpMsg(const struct sph_msg_t *p_sph_msg) {
+ bool retval = true;
+
+ if (p_sph_msg == NULL) {
+ ALOGW("%s(), p_sph_msg == NULL!! return", __FUNCTION__);
+ return 0;
+ }
+
+ switch (getSyncType(p_sph_msg->msg_id)) {
+ /* Do not print msg w/o ack!! */
+ case SPH_MSG_HANDSHAKE_AP_CTRL_BYPASS_ACK:
+ case SPH_MSG_HANDSHAKE_MD_CTRL_BYPASS_ACK:
+ retval = false;
+ break;
+ /* Do not print data message!! */
+ case SPH_MSG_HANDSHAKE_AP_NOTIFY_DATA:
+ case SPH_MSG_HANDSHAKE_AP_READ_DATA_DONE:
+ case SPH_MSG_HANDSHAKE_MD_REQUEST_DATA:
+ case SPH_MSG_HANDSHAKE_MD_NOTIFY_DATA:
+ retval = false;
+ break;
+ default:
+ retval = true;
+ }
+
+#ifndef CONFIG_MT_ENG_BUILD
+ /* reduce log */
+ if (p_sph_msg->msg_id == MSG_A2M_MUTE_SPH_UL ||
+ p_sph_msg->msg_id == MSG_A2M_MUTE_SPH_DL ||
+ p_sph_msg->msg_id == MSG_A2M_MUTE_SPH_UL_SOURCE) {
+ retval = false;
+ }
+#endif
+
+ return retval;
+}
+
+
+
+
+} /* end namespace android */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechMessageQueue.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechMessageQueue.cpp
new file mode 100644
index 0000000..76088b0
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechMessageQueue.cpp
@@ -0,0 +1,631 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <SpeechMessageQueue.h>
+
+#include <errno.h>
+
+#include <pthread.h>
+
+#include <utils/threads.h> // for ANDROID_PRIORITY_AUDIO
+
+#include <cutils/properties.h> /* for PROPERTY_KEY_MAX */
+
+
+#include <SpeechType.h>
+
+#include <SpeechUtility.h>
+
+#include <AudioLock.h>
+
+#include <AudioAssert.h>
+
+#include <SpeechMessageID.h>
+
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechMessageQueue"
+
+
+
+namespace android {
+
+/*
+ * =============================================================================
+ * MACRO
+ * =============================================================================
+ */
+
+#define MIN_SPH_MSG_QUEUE_SIZE (32)
+#define MAX_SPH_MSG_QUEUE_SIZE (64)
+
+#define MAX_SPEECH_QUEUE_AUTO_LOCK_TIMEOUT_MS (2000)
+#define MAX_SPEECH_QUEUE_WAIT_ELEMENT_LOCK_TIMEOUT_MS (2000)
+
+#define MAX_SPEECH_QUEUE_WAIT_ACK_TIMEOUT_MS (60000)
+
+static const char *kPropertyKeyLowRam = "ro.vendor.config.low_ram";
+
+
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+
+class SpeechQueueElement {
+public:
+ SpeechQueueElement() {
+ p_sph_msg_client = NULL;
+ memset(&sph_msg, 0, sizeof(sph_msg_t));
+ wait_in_thread = false;
+ signal_arrival = false;
+ send_msg_to_modem_retval = 0;
+ }
+ virtual ~SpeechQueueElement() { }
+
+ sph_msg_t *p_sph_msg_client; /* the address of client's message */
+ sph_msg_t sph_msg; /* the copy msg in queue */
+ AudioLock mElementLock; /* wait/signal */
+ bool wait_in_thread;
+ bool signal_arrival;
+ int send_msg_to_modem_retval;
+};
+
+
+/*
+ * =============================================================================
+ * create/destroy/init/deinit functions
+ * =============================================================================
+ */
+
+SpeechMessageQueue::SpeechMessageQueue(
+ send_message_wrapper_fp_t send_message_wrapper,
+ error_handle_message_wrapper_fp_t error_handle_message_wrapper,
+ void *wrapper_arg) {
+
+ int ret = 0;
+ char lowRam[PROPERTY_VALUE_MAX] = {0};
+
+ /* init var */
+ get_string_from_property(kPropertyKeyLowRam, lowRam, PROPERTY_VALUE_MAX);
+ if (strcmp(lowRam, "true") == 0) { /* low memory project */
+ mQueueSize = MIN_SPH_MSG_QUEUE_SIZE;
+ } else {
+ mQueueSize = MAX_SPH_MSG_QUEUE_SIZE;
+ }
+ mQueue = new SpeechQueueElement[mQueueSize];
+ mQueueIndexRead = 0;
+ mQueueIndexWrite = 0;
+
+ mWaitAckFlag = false;
+ mStopWaitAck = false;
+
+ mSphMsgAck = NULL;
+ AUDIO_ALLOC_STRUCT(sph_msg_t, mSphMsgAck);
+
+ /* callback to send msg to modem */
+ sendMessageWrapper = send_message_wrapper;
+ errorHandleMessageWrapper = error_handle_message_wrapper;
+ mWrapperArg = wrapper_arg;
+
+ mEnableThread = true;
+ hProcessElementThread = 0;
+ ret = pthread_create(&hProcessElementThread, NULL,
+ SpeechMessageQueue::processElementThread,
+ (void *)this);
+ ASSERT(ret == 0);
+
+}
+
+
+SpeechMessageQueue::~SpeechMessageQueue() {
+ mEnableThread = false;
+ pthread_join(hProcessElementThread, NULL);
+ ALOGD("pthread_join hProcessElementThread done");
+
+ /* init var */
+ if (mQueue) {
+ delete mQueue;
+ }
+
+ AUDIO_FREE(mSphMsgAck);
+}
+
+
+bool SpeechMessageQueue::checkQueueEmpty() const {
+ return (mQueueIndexRead == mQueueIndexWrite);
+}
+
+
+bool SpeechMessageQueue::checkQueueToBeFull() const {
+ uint8_t idx_w_to_be = 0;
+
+ idx_w_to_be = mQueueIndexWrite + 1;
+ if (idx_w_to_be == mQueueSize) {
+ idx_w_to_be = 0;
+ }
+
+ return (idx_w_to_be == mQueueIndexRead) ? true : false;
+}
+
+
+bool SpeechMessageQueue::checkQueueIndexValid(const uint32_t index) const {
+ return (index < mQueueSize) ? true : false;
+}
+
+
+uint32_t SpeechMessageQueue::getQueueSize() const {
+ return mQueueSize;
+}
+
+
+uint32_t SpeechMessageQueue::getQueueNumElements() const {
+ return (mQueueIndexWrite >= mQueueIndexRead) ?
+ (mQueueIndexWrite - mQueueIndexRead) :
+ ((mQueueSize - mQueueIndexRead) + mQueueIndexWrite);
+}
+
+
+int SpeechMessageQueue::pushElement(sph_msg_t *p_sph_msg, uint32_t *idx_msg) {
+ /* error handling */
+ if (p_sph_msg == NULL || idx_msg == NULL) {
+ ALOGE("%s(), NULL!! p_sph_msg: %p, idx_msg: %p", __FUNCTION__,
+ p_sph_msg, idx_msg);
+ return -EFAULT;
+ }
+
+
+ *idx_msg = 0xFFFFFFFF;
+ AL_AUTOLOCK_MS(mQueueLock, MAX_SPEECH_QUEUE_AUTO_LOCK_TIMEOUT_MS);
+
+ /* check mQueue not full */
+ if (checkQueueToBeFull() == true) {
+ ALOGW("%s(), Queue FULL!! mQueueIndexRead: %u, mQueueIndexWrite: %u", __FUNCTION__, mQueueIndexRead, mQueueIndexWrite);
+ PRINT_SPH_MSG(ALOGE, "Queue FULL!! drop msg", p_sph_msg);
+ return -EOVERFLOW;
+ }
+
+ /* push */
+ AL_LOCK_MS(mQueue[mQueueIndexWrite].mElementLock, MAX_SPEECH_QUEUE_AUTO_LOCK_TIMEOUT_MS);
+ mQueue[mQueueIndexWrite].p_sph_msg_client = p_sph_msg;
+ memcpy(&mQueue[mQueueIndexWrite].sph_msg, p_sph_msg, sizeof(sph_msg_t));
+ mQueue[mQueueIndexWrite].wait_in_thread = true;
+ mQueue[mQueueIndexWrite].signal_arrival = false;
+ mQueue[mQueueIndexWrite].send_msg_to_modem_retval = 0;
+
+ /* memory copy speech info buffer */
+ if (p_sph_msg->buffer_type == SPH_MSG_BUFFER_TYPE_PAYLOAD) {
+ ALOGV("%s(), memory copy speech info buffer, msg_id:0x%x", __FUNCTION__, p_sph_msg->msg_id);
+ mQueue[mQueueIndexWrite].sph_msg.payload_data_addr = NULL;
+ AUDIO_ALLOC_BUFFER(mQueue[mQueueIndexWrite].sph_msg.payload_data_addr,
+ p_sph_msg->payload_data_size);
+ memcpy(mQueue[mQueueIndexWrite].sph_msg.payload_data_addr,
+ p_sph_msg->payload_data_addr, p_sph_msg->payload_data_size);
+ }
+
+ AL_UNLOCK(mQueue[mQueueIndexWrite].mElementLock);
+
+ *idx_msg = mQueueIndexWrite;
+ mQueueIndexWrite++;
+ if (mQueueIndexWrite == mQueueSize) {
+ mQueueIndexWrite = 0;
+ }
+ AL_SIGNAL(mQueueLock);
+
+ SPH_LOG_T("%s(), push msg: 0x%x, read_idx: %u, write_idx: %u, queue(%u/%u), idx_msg: %u",
+ __FUNCTION__,
+ mQueue[*idx_msg].sph_msg.msg_id,
+ mQueueIndexRead, mQueueIndexWrite,
+ getQueueNumElements(), getQueueSize(), *idx_msg);
+ return 0;
+}
+
+
+int SpeechMessageQueue::popElement() {
+ uint16_t msg_id = 0;
+
+ AL_AUTOLOCK_MS(mQueueLock, MAX_SPEECH_QUEUE_AUTO_LOCK_TIMEOUT_MS);
+
+ /* check mQueue not empty */
+ if (checkQueueEmpty() == true) {
+ ALOGW("%s(), Queue EMPTY!! mQueueIndexRead: %u, mQueueIndexWrite: %u", __FUNCTION__, mQueueIndexRead, mQueueIndexWrite);
+ return -ENOMEM;
+ }
+
+ /* get msg_id for debug log */
+ msg_id = mQueue[mQueueIndexRead].sph_msg.msg_id;
+
+ /* free speech info buffer*/
+ if (mQueue[mQueueIndexRead].sph_msg.buffer_type == SPH_MSG_BUFFER_TYPE_PAYLOAD) {
+ ALOGV("%s(), free speech info buffer of Queue element, msg_id:0x%x",
+ __FUNCTION__, msg_id);
+ AUDIO_FREE_POINTER(mQueue[mQueueIndexRead].sph_msg.payload_data_addr);
+ }
+
+ /* pop */
+ mQueueIndexRead++;
+ if (mQueueIndexRead == mQueueSize) {
+ mQueueIndexRead = 0;
+ }
+
+ SPH_LOG_T("%s(), pop msg: 0x%x, read_idx: %u, write_idx: %u, queue(%u/%u)",
+ __FUNCTION__,
+ msg_id, mQueueIndexRead, mQueueIndexWrite,
+ getQueueNumElements(), getQueueSize());
+ return 0;
+}
+
+
+int SpeechMessageQueue::frontElement(sph_msg_t **pp_sph_msg, uint32_t *idx_msg) {
+ ASSERT(AL_TRYLOCK(mQueueLock) != 0);
+
+ /* error handling */
+ if (pp_sph_msg == NULL) {
+ ALOGE("%s(), pp_sph_msg = NULL, return", __FUNCTION__);
+ return -EFAULT;
+ }
+ *pp_sph_msg = NULL;
+
+ if (idx_msg == NULL) {
+ ALOGE("%s(), idx_msg = NULL, return", __FUNCTION__);
+ return -EFAULT;
+ }
+ *idx_msg = 0xFFFFFFFF;
+
+ /* check mQueue empty */
+ if (checkQueueEmpty() == true) {
+ ALOGW("%s(), Queue EMPTY!! mQueueIndexRead: %u, mQueueIndexWrite: %u", __FUNCTION__, mQueueIndexRead, mQueueIndexWrite);
+ return -ENOMEM;
+ }
+
+ *pp_sph_msg = &mQueue[mQueueIndexRead].sph_msg;
+ *idx_msg = mQueueIndexRead;
+
+ return 0;
+}
+
+
+int SpeechMessageQueue::waitUntilElementProcessDone(const uint32_t idx_msg, const uint32_t ms) {
+ int retval = 0;
+
+ if (checkQueueIndexValid(idx_msg) == false) {
+ ALOGW("%s(), idx_msg %d is invalid!! return", __FUNCTION__, idx_msg);
+ return -EOVERFLOW;
+ }
+
+ if (ms == 0) {
+ AL_LOCK_MS(mQueue[idx_msg].mElementLock, MAX_SPEECH_QUEUE_WAIT_ELEMENT_LOCK_TIMEOUT_MS);
+ mQueue[idx_msg].wait_in_thread = false;
+ AL_UNLOCK(mQueue[idx_msg].mElementLock);
+ return 0;
+ }
+
+
+ CLEANUP_PUSH_ALOCK(mQueue[idx_msg].mElementLock.getAlock());
+ AL_LOCK_MS(mQueue[idx_msg].mElementLock, MAX_SPEECH_QUEUE_WAIT_ELEMENT_LOCK_TIMEOUT_MS);
+
+ if (mQueue[idx_msg].signal_arrival == false) {
+ retval = AL_WAIT_MS(mQueue[idx_msg].mElementLock, ms);
+ }
+ mQueue[idx_msg].wait_in_thread = false;
+
+ if (retval == 0) { /* retval of SpeechDriverNormal::sendSpeechMessageToModem() */
+ retval = mQueue[idx_msg].send_msg_to_modem_retval;
+ }
+
+ AL_UNLOCK(mQueue[idx_msg].mElementLock);
+ CLEANUP_POP_ALOCK(mQueue[idx_msg].mElementLock.getAlock());
+
+ return retval;
+}
+
+
+int SpeechMessageQueue::signalElementProcessDone(const uint32_t idx_msg) {
+ int retval = 0;
+
+ if (checkQueueIndexValid(idx_msg) == false) {
+ ALOGW("%s(), idx_msg %d is invalid!! return", __FUNCTION__, idx_msg);
+ return -EOVERFLOW;
+ }
+
+ AL_LOCK_MS(mQueue[idx_msg].mElementLock, MAX_SPEECH_QUEUE_WAIT_ELEMENT_LOCK_TIMEOUT_MS);
+ mQueue[idx_msg].signal_arrival = true;
+ AL_SIGNAL(mQueue[idx_msg].mElementLock); /* => waitUntilElementProcessDone */
+ AL_UNLOCK(mQueue[idx_msg].mElementLock);
+ return retval;
+}
+
+
+int SpeechMessageQueue::getQueueElementUntilPushed(sph_msg_t **pp_sph_msg, uint32_t *idx_msg) {
+ int retval = 0;
+
+ CLEANUP_PUSH_ALOCK(mQueueLock.getAlock());
+ AL_LOCK_MS(mQueueLock, MAX_SPEECH_QUEUE_WAIT_ELEMENT_LOCK_TIMEOUT_MS);
+ if (checkQueueEmpty() == true) {
+ AL_WAIT_NO_TIMEOUT(mQueueLock);
+ }
+ retval = frontElement(pp_sph_msg, idx_msg); /* not p_sph_msg_client!!! */
+ AL_UNLOCK(mQueueLock);
+ CLEANUP_POP_ALOCK(mQueueLock.getAlock());
+
+ return retval;
+}
+
+
+int SpeechMessageQueue::sendSpeechMessageToQueue(
+ sph_msg_t *p_sph_msg,
+ const uint32_t block_thread_ms) {
+
+ uint32_t idx_msg = 0xFFFFFFFF;
+ uint32_t idx_msg_head = 0xFFFFFFFF;
+ int retval = 0;
+
+ /* error handling */
+ if (p_sph_msg == NULL) {
+ ALOGE("%s(), p_sph_msg = NULL, return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ /* push message to mQueue */
+ retval = pushElement(p_sph_msg, &idx_msg);
+ if (retval != 0) {
+ ALOGW("%s(), pushElement fail!! return", __FUNCTION__);
+ PRINT_SPH_MSG(ALOGE, "pushElement fail!! drop msg", p_sph_msg);
+ WARNING("pushElement fail");
+ return retval;
+ }
+
+ if (checkQueueIndexValid(idx_msg) == false) {
+ ALOGW("%s(), idx_msg %u invalid!! return", __FUNCTION__, idx_msg);
+ PRINT_SPH_MSG(ALOGE, "idx_msg invalid!!drop msg", p_sph_msg);
+ WARNING("checkQueueIndexValid fail");
+ return -EOVERFLOW;
+ }
+
+
+ /* wait until message processed */
+ retval = waitUntilElementProcessDone(idx_msg, block_thread_ms);
+ if (retval == -ETIMEDOUT) {
+ idx_msg_head = mQueueIndexRead;
+ PRINT_SPH_MSG(ALOGW, "block thread timeout", p_sph_msg);
+ PRINT_SPH_MSG(ALOGW, "=> queue head info", &mQueue[idx_msg_head].sph_msg);
+#if 0
+ WARNING("block queue timeout");
+#endif
+ }
+
+ return retval;
+}
+
+
+int SpeechMessageQueue::sendSpeechMessageAckToQueue(sph_msg_t *p_sph_msg_ack) {
+ /* error handling */
+ if (p_sph_msg_ack == NULL) {
+ ALOGE("%s(), p_sph_msg_ack = NULL, return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ if (isMdAckBack(p_sph_msg_ack) == false) {
+ ALOGE("%s(), p_sph_msg_ack: 0x%x is not ack, return", __FUNCTION__, p_sph_msg_ack->msg_id);
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_MT_ENG_BUILD
+ PRINT_SPH_MSG(ALOGD, "ack back", p_sph_msg_ack);
+#else
+ /* reduce log */
+ if (p_sph_msg_ack->msg_id != MSG_M2A_MUTE_SPH_UL_ACK &&
+ p_sph_msg_ack->msg_id != MSG_M2A_MUTE_SPH_DL_ACK &&
+ p_sph_msg_ack->msg_id != MSG_M2A_MUTE_SPH_UL_SOURCE_ACK) {
+ PRINT_SPH_MSG(ALOGD, "ack back", p_sph_msg_ack);
+ }
+#endif
+
+
+ /* get msg ack & wake up queue */
+ AL_LOCK_MS(mWaitAckLock, MAX_SPEECH_QUEUE_AUTO_LOCK_TIMEOUT_MS);
+ if (mSphMsgAck->msg_id != 0) {
+ ALOGE("%s(), p_sph_msg_ack: 0x%x, mSphMsgAck msg_id: 0x%x != 0", __FUNCTION__,
+ p_sph_msg_ack->msg_id, mSphMsgAck->msg_id);
+ }
+ memcpy(mSphMsgAck, p_sph_msg_ack, sizeof(sph_msg_t));
+ AL_SIGNAL(mWaitAckLock);
+ AL_UNLOCK(mWaitAckLock);
+ return 0;
+}
+
+
+void SpeechMessageQueue::notifyQueueToStopWaitingAck() {
+ AL_LOCK_MS(mWaitAckLock, MAX_SPEECH_QUEUE_AUTO_LOCK_TIMEOUT_MS);
+ if (mWaitAckFlag == true) { /* someone is waiting */
+ ALOGW("%s(), stop waiting ack", __FUNCTION__);
+ mWaitAckFlag = false;
+ AL_SIGNAL(mWaitAckLock); /* notify to stop waiting ack */
+ } else {
+ /* no msg is waiting, set flag to prevent msg wait */
+ ALOGW("%s(), no msg is waiting ack, set mStopWaitAck = true", __FUNCTION__);
+ mStopWaitAck = true;
+ }
+ AL_UNLOCK(mWaitAckLock);
+}
+
+
+int SpeechMessageQueue::waitUntilModemAckBack(sph_msg_t *p_sph_msg, uint32_t idx_msg) {
+ int retval = 0;
+ sph_msg_t *p_sph_msg_client = NULL;
+
+ /* error handling */
+ if (p_sph_msg == NULL) {
+ ALOGE("%s(), p_sph_msg = NULL, return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ if (checkQueueIndexValid(idx_msg) == false) {
+ ALOGW("%s(), idx_msg %d is invalid!! return", __FUNCTION__, idx_msg);
+ return -EOVERFLOW;
+ }
+
+
+ CLEANUP_PUSH_ALOCK(mWaitAckLock.getAlock());
+ AL_LOCK_MS(mWaitAckLock, MAX_SPEECH_QUEUE_AUTO_LOCK_TIMEOUT_MS);
+
+ /* should no ack before wait */
+ if (mSphMsgAck->msg_id != 0) {
+ if (isAckMessageInPair(p_sph_msg, mSphMsgAck) == false) {
+ ALOGE("%s(), p_sph_msg: 0x%x, mSphMsgAck msg_id: 0x%x != 0!! drop previous ack", __FUNCTION__,
+ p_sph_msg->msg_id, mSphMsgAck->msg_id);
+ memset(mSphMsgAck, 0, sizeof(sph_msg_t));
+ }
+ }
+
+ /* wait ack if need */
+ if (mSphMsgAck->msg_id == 0) {
+ if (mStopWaitAck) {
+ PRINT_SPH_MSG(ALOGW, "MD status error, no need to wait ack!!", p_sph_msg);
+ mStopWaitAck = false;
+ retval = -ECANCELED;
+ goto WAIT_ACK_DONE;
+ }
+ PRINT_SPH_MSG(ALOGV, "wait(+)", p_sph_msg);
+ mWaitAckFlag = true;
+ retval = AL_WAIT_MS(mWaitAckLock, MAX_SPEECH_QUEUE_WAIT_ACK_TIMEOUT_MS);
+ PRINT_SPH_MSG(ALOGV, "wait(-)", p_sph_msg);
+
+ if (mWaitAckFlag == false) { /* canceled */
+ PRINT_SPH_MSG(ALOGW, "wait ack canceled!!", p_sph_msg);
+ retval = -ECANCELED;
+ goto WAIT_ACK_DONE;
+ }
+
+ if (retval != 0) { /* timeout */
+ PRINT_SPH_MSG(ALOGE, "wait ack timeout!!", p_sph_msg);
+ retval = -ETIMEDOUT;
+ goto WAIT_ACK_DONE;
+ }
+ }
+
+ /* should be in pair after wait */
+ if (isAckMessageInPair(p_sph_msg, mSphMsgAck) == false) {
+ ALOGE("%s(), msg_id: 0x%x, ack msg id: 0x%x not in pair!!", __FUNCTION__,
+ p_sph_msg->msg_id, mSphMsgAck->msg_id);
+ WARNING("ack not in pair");
+ retval = -EINVAL;
+ goto WAIT_ACK_DONE;
+ }
+
+ /* copy return mailbox value to original thread */
+ AL_LOCK_MS(mQueue[idx_msg].mElementLock, MAX_SPEECH_QUEUE_WAIT_ELEMENT_LOCK_TIMEOUT_MS);
+ if (mQueue[idx_msg].wait_in_thread == true) {
+ p_sph_msg_client = mQueue[idx_msg].p_sph_msg_client;
+ if (p_sph_msg_client->buffer_type == SPH_MSG_BUFFER_TYPE_MAILBOX &&
+ mSphMsgAck->buffer_type == SPH_MSG_BUFFER_TYPE_MAILBOX) {
+ p_sph_msg_client->param_16bit = mSphMsgAck->param_16bit;
+ p_sph_msg_client->param_32bit = mSphMsgAck->param_32bit;
+ }
+ }
+ AL_UNLOCK(mQueue[idx_msg].mElementLock);
+
+
+WAIT_ACK_DONE:
+ mWaitAckFlag = false;
+ memset(mSphMsgAck, 0, sizeof(sph_msg_t));
+ AL_UNLOCK(mWaitAckLock);
+ CLEANUP_POP_ALOCK(mWaitAckLock.getAlock());
+
+ if (retval == -ETIMEDOUT) {
+ WARNING("wait ack timeout");
+ }
+ return retval;
+}
+
+
+
+void *SpeechMessageQueue::processElementThread(void *arg) {
+ char thread_name[128];
+
+ SpeechMessageQueue *pSpeechMessageQueue = NULL;
+
+ sph_msg_t *p_sph_msg = NULL;
+ uint32_t idx_msg = 0xFFFFFFFF;
+
+ int retval = 0;
+
+
+ CONFIG_THREAD(thread_name, ANDROID_PRIORITY_AUDIO);
+
+ pSpeechMessageQueue = static_cast<SpeechMessageQueue *>(arg);
+ if (pSpeechMessageQueue == NULL) {
+ ALOGE("%s(), NULL!! pSpeechMessageQueue %p", __FUNCTION__, pSpeechMessageQueue);
+ goto PROCESS_ELEMENT_THREAD_DONE;
+ }
+
+
+ while (pSpeechMessageQueue->mEnableThread == true) {
+ /* wait until element pushed */
+ retval = pSpeechMessageQueue->getQueueElementUntilPushed(&p_sph_msg, &idx_msg);
+ if (retval != 0 ||
+ p_sph_msg == NULL ||
+ pSpeechMessageQueue->checkQueueIndexValid(idx_msg) == false) {
+ ALOGW("%s(), getQueueElementUntilPushed fail!!", __FUNCTION__);
+ usleep(5 * 1000);
+ continue;
+ }
+
+ /* send to modem */
+ retval = pSpeechMessageQueue->sendSpeechMessage(p_sph_msg);
+
+ /* need ack, wait */
+ if (isApNeedAck(p_sph_msg) == true) {
+ if (retval != 0) {
+ PRINT_SPH_MSG(ALOGE, "send fail, don't wait ack", p_sph_msg);
+ } else {
+ retval = pSpeechMessageQueue->waitUntilModemAckBack(p_sph_msg, idx_msg);
+ }
+ }
+
+ /* error handing for send/wait_ack fail */
+ if (retval != 0) {
+ pSpeechMessageQueue->errorHandleSpeechMessage(p_sph_msg);
+ }
+
+ /* signal */
+ pSpeechMessageQueue->mQueue[idx_msg].send_msg_to_modem_retval = retval;
+ pSpeechMessageQueue->signalElementProcessDone(idx_msg);
+
+ /* pop message from mQueue */
+ pSpeechMessageQueue->popElement();
+ }
+
+
+PROCESS_ELEMENT_THREAD_DONE:
+ ALOGV("%s terminated", thread_name);
+ pthread_exit(NULL);
+ return NULL;
+}
+
+
+int SpeechMessageQueue::sendSpeechMessage(sph_msg_t *p_sph_msg) {
+ /* => SpeechDriverNormal::sendSpeechMessageToModem() */
+ if (!sendMessageWrapper) {
+ ASSERT(sendMessageWrapper != NULL);
+ return -EFAULT;
+ }
+ return sendMessageWrapper(mWrapperArg, p_sph_msg);
+}
+
+
+int SpeechMessageQueue::errorHandleSpeechMessage(sph_msg_t *p_sph_msg) {
+ /* => SpeechDriverNormal::errorHandleSpeechMessage() */
+ if (!errorHandleMessageWrapper) {
+ ASSERT(errorHandleMessageWrapper != NULL);
+ return -EFAULT;
+ }
+ return errorHandleMessageWrapper(mWrapperArg, p_sph_msg);
+}
+
+
+
+} /* end of namespace android */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechMessengerNormal.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechMessengerNormal.cpp
new file mode 100644
index 0000000..c65692c
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechMessengerNormal.cpp
@@ -0,0 +1,788 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <SpeechMessengerNormal.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <errno.h>
+
+#include <pthread.h>
+
+#include <cutils/properties.h> /* for PROPERTY_KEY_MAX */
+
+#include <log/log.h>
+
+#include <audio_memory_control.h>
+
+#include <AudioAssert.h>
+
+#include <SpeechType.h>
+
+#include <SpeechUtility.h>
+
+#include <SpeechMessageID.h>
+
+#include <SpeechShareMemBase.h>
+
+#include <SpeechCCCIType.h>
+
+#include <time.h>
+#include <fcntl.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechMessengerNormal"
+
+
+namespace android {
+
+
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+
+typedef uint32_t ccci_channel_t;
+
+enum { /* ccci_channel_t */
+#if 0 /* 80020004 or 0x80030004 */
+ CCCI_M2A_CHANNEL_NUMBER = 4,
+#endif
+ CCCI_A2M_CHANNEL_NUMBER = 5
+};
+
+
+typedef uint8_t ccci_msg_buffer_t;
+
+enum { /* ccci_msg_buffer_t */
+ CCCI_MSG_BUFFER_TYPE_MAILBOX = 0,
+ CCCI_MSG_BUFFER_TYPE_AP_PAYLOAD = 1,
+ CCCI_MSG_BUFFER_TYPE_MD_PAYLOAD = 2
+};
+
+
+typedef struct ccci_mail_box_t {
+ uint32_t magic;
+ uint16_t param_16bit;
+ uint16_t msg_id; /* sph_msg_id_t */
+ uint32_t ch; /* ccci_channel_t */
+ uint32_t param_32bit;
+} ccci_mail_box_t;
+
+
+typedef struct ccci_ap_payload_t {
+ uint32_t offset; /* always 0 */
+ uint32_t payload_size;
+ uint32_t ch;
+ uint16_t param_16bit;
+ uint16_t msg_id; /* sph_msg_id_t */
+
+ uint16_t data_sync; /* CCCI_AP_PAYLOAD_SYNC */
+ uint16_t data_type; /* share_buff_data_type_t */
+ uint16_t data_size;
+
+ uint8_t payload_data[CCCI_MAX_AP_PAYLOAD_DATA_SIZE];
+} ccci_ap_payload_t;
+
+
+typedef struct ccci_md_payload_t {
+ uint32_t offset;
+ uint32_t message_size;
+ uint32_t ch;
+ uint16_t param_16bit;
+ uint16_t msg_id; /* sph_msg_id_t */
+
+ uint16_t data_sync; /* CCCI_MD_PAYLOAD_SYNC */
+ uint16_t data_type; /* share_buff_data_type_t */
+ uint16_t data_size;
+ uint16_t idx;
+ uint16_t total_idx;
+
+ uint8_t data[CCCI_MAX_MD_PAYLOAD_DATA_SIZE];
+} ccci_md_payload_t;
+
+
+typedef struct ccci_msg_t {
+ union {
+ uint8_t buffer[CCCI_MAX_BUF_SIZE]; /* for ccci read/write */
+ ccci_mail_box_t mail_box;
+ ccci_ap_payload_t ap_payload;
+ ccci_md_payload_t md_payload;
+ };
+
+ uint8_t buffer_type; /* ccci_msg_buffer_t */
+ uint16_t buffer_size;
+} ccci_msg_t;
+
+#define MAX_CCCI_TIMEOUT_MS (100)
+
+/*
+ * =============================================================================
+ * class implementation
+ * =============================================================================
+ */
+
+SpeechMessengerNormal::SpeechMessengerNormal(const modem_index_t modem_index) {
+ int retval = 0;
+
+ ALOGV("%s(), modem_index: %d", __FUNCTION__, modem_index);
+ mModemIndex = modem_index;
+
+ mCcciDeviceHandler = -1;
+ mSpeechShareMem = NULL;
+ mCcciShareMemoryHandler = -1;
+ hFormatShareMemoryThread = 0;
+
+ mCcciMsgSend = NULL;
+ mCcciMsgRead = NULL;
+
+ AUDIO_ALLOC_STRUCT(ccci_msg_t, mCcciMsgSend);
+ AUDIO_ALLOC_STRUCT(ccci_msg_t, mCcciMsgRead);
+
+#ifdef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ mSpeechShareMem = SpeechShareMemBase::createInstance();
+ if (mSpeechShareMem == NULL) {
+ ALOGE("%s(), mSpeechShareMem == NULL!!", __FUNCTION__);
+ }
+#endif
+
+ retval = checkCcciStatusAndRecovery();
+ if (retval != 0) {
+ ALOGW("%s(), ccci open fail!!", __FUNCTION__);
+ }
+}
+
+
+SpeechMessengerNormal::~SpeechMessengerNormal() {
+#ifdef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ AL_LOCK(mShareMemoryHandlerLock);
+ closeShareMemory();
+ AL_UNLOCK(mShareMemoryHandlerLock);
+ SpeechShareMemBase::destroyInstance(mSpeechShareMem);
+ mSpeechShareMem = NULL;
+#endif
+
+ AL_LOCK(mCcciHandlerLock);
+ closeCcciDriver();
+ AL_UNLOCK(mCcciHandlerLock);
+
+ AUDIO_FREE_POINTER(mCcciMsgSend);
+ AUDIO_FREE_POINTER(mCcciMsgRead);
+}
+
+
+int SpeechMessengerNormal::openCcciDriver() {
+
+ const uint32_t k_max_device_name_size = 32;
+ char dev_name[k_max_device_name_size];
+ memset(dev_name, 0, sizeof(dev_name));
+
+ if (mCcciDeviceHandler >= 0) {
+ ALOGD("%s(), mCcciDeviceHandler: %d already open",
+ __FUNCTION__, mCcciDeviceHandler);
+ return 0;
+ }
+
+ ASSERT(mModemIndex != MODEM_2);
+ // open ccci device driver
+ strncpy(dev_name,
+ CCCI_DEV_NODE_DRIVER,
+ sizeof(dev_name) - 1);
+
+ mCcciDeviceHandler = open(dev_name, O_RDWR);
+ if (mCcciDeviceHandler < 0) {
+ ALOGE("%s(), open(%s) fail!! mCcciDeviceHandler: %d, errno: %d", __FUNCTION__,
+ dev_name, (int32_t)mCcciDeviceHandler, errno);
+ return -ENODEV;
+ }
+
+ ALOGD("%s(), dev_name: \"%s\", mCcciDeviceHandler: %d",
+ __FUNCTION__, dev_name, mCcciDeviceHandler);
+ return 0;
+}
+
+
+int SpeechMessengerNormal::closeCcciDriver() {
+ ALOGD("%s(), mCcciDeviceHandler: %d", __FUNCTION__, mCcciDeviceHandler);
+
+ if (mCcciDeviceHandler >= 0) {
+ close(mCcciDeviceHandler);
+ mCcciDeviceHandler = -1;
+ }
+ return 0;
+}
+
+
+int SpeechMessengerNormal::openShareMemory() {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return 0;
+#endif
+
+ if (mCcciShareMemoryHandler >= 0) {
+ ALOGD("%s(), mModemIndex: %d, mCcciShareMemoryHandler: %d already open",
+ __FUNCTION__, mModemIndex, mCcciShareMemoryHandler);
+ return 0;
+ }
+
+ // get share momoey address
+ if (mSpeechShareMem == NULL) {
+ ALOGE("%s(), mSpeechShareMem == NULL!!", __FUNCTION__);
+ return -ENODEV;
+ }
+
+ ASSERT(mModemIndex != MODEM_2);
+ mCcciShareMemoryHandler = mSpeechShareMem->openShareMemory(mModemIndex);
+ if (mCcciShareMemoryHandler < 0) {
+ ALOGE("%s(), mModemIndex(%d) fail!! mCcciShareMemoryHandler: %d, errno: %d", __FUNCTION__,
+ mModemIndex, (int32_t)mCcciShareMemoryHandler, errno);
+ return -ENODEV;
+ }
+
+ int retval = 0;
+ if (checkModemReady() == true) {
+ retval = formatShareMemory();
+ } else {
+ retval = pthread_create(&hFormatShareMemoryThread, NULL,
+ SpeechMessengerNormal::formatShareMemoryThread,
+ (void *)this);
+ ASSERT(retval == 0);
+ }
+
+ return retval;
+}
+
+
+int SpeechMessengerNormal::closeShareMemory() {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return 0;
+#endif
+ if (mSpeechShareMem == NULL) {
+ ALOGE("%s(), mSpeechShareMem == NULL!!", __FUNCTION__);
+ return -ENODEV;
+ }
+ mSpeechShareMem->closeShareMemory();
+ mCcciShareMemoryHandler = -1;
+
+
+ return 0;
+}
+
+
+int SpeechMessengerNormal::checkCcciStatusAndRecovery() {
+ const uint8_t k_max_try_cnt = 200;
+ uint8_t try_cnt = 0;
+
+ int retval = 0;
+
+ for (try_cnt = 0; try_cnt < k_max_try_cnt; try_cnt++) {
+ AL_LOCK(mCcciHandlerLock);
+ if (mCcciDeviceHandler >= 0) {
+ retval = 0;
+ } else {
+ if (try_cnt == 0) {
+ ALOGW("%s() mCcciDeviceHandler: %d", __FUNCTION__, mCcciDeviceHandler);
+ }
+ retval = openCcciDriver();
+ }
+ AL_UNLOCK(mCcciHandlerLock);
+
+ if (retval == 0) {
+ break;
+ } else {
+ ALOGW("%s(), #%d, sleep 10 ms & retry openCcciDriver", __FUNCTION__, try_cnt);
+ usleep(10 * 1000); /* 10 ms */
+ }
+ }
+
+ if (retval != 0) {
+ ALOGW("%s(), ccci driver not init!!", __FUNCTION__);
+ return retval;
+ }
+
+#ifdef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ for (try_cnt = 0; try_cnt < k_max_try_cnt; try_cnt++) {
+ AL_LOCK(mShareMemoryHandlerLock);
+ if (mCcciShareMemoryHandler >= 0) {
+ retval = 0;
+ } else {
+ if (try_cnt == 0) {
+ ALOGW("%s() mCcciShareMemoryHandler: %d", __FUNCTION__, mCcciShareMemoryHandler);
+ }
+ retval = openShareMemory();
+ }
+ AL_UNLOCK(mShareMemoryHandlerLock);
+
+ if (retval == 0) {
+ break;
+ } else {
+ ALOGW("%s(), #%d, sleep 10 ms & retry openShareMemory", __FUNCTION__, try_cnt);
+ usleep(10 * 1000); /* 10 ms */
+ }
+ }
+
+ if (retval != 0) {
+ ALOGW("%s(), ccci share memory not init", __FUNCTION__);
+ return retval;
+ }
+#endif
+
+ return 0;
+}
+
+
+void *SpeechMessengerNormal::formatShareMemoryThread(void *arg) {
+ SpeechMessengerNormal *pSpeechMessenger = NULL;
+
+ uint32_t try_cnt = 0;
+ const uint32_t k_max_try_cnt = 3000; /* (5min == 300sec) / 100 ms */
+
+ /* detach pthread */
+ pthread_detach(pthread_self());
+
+ pSpeechMessenger = static_cast<SpeechMessengerNormal *>(arg);
+ if (pSpeechMessenger == NULL) {
+ ALOGE("%s(), NULL!! pSpeechMessenger %p", __FUNCTION__, pSpeechMessenger);
+ WARNING("cast fail!!");
+ goto FORMAT_SHM_THREAD_DONE;
+ }
+
+ /* wait until modem ready */
+ for (try_cnt = 0; try_cnt < k_max_try_cnt; try_cnt++) {
+ if (pSpeechMessenger->checkModemReady() == true) {
+ break;
+ }
+
+ if (try_cnt == 0) { /* only print once at beginning */
+ ALOGW("%s(), modem not ready...retry start", __FUNCTION__);
+ }
+
+ usleep(100 * 1000); /* 100 ms */
+ }
+
+ if (try_cnt == k_max_try_cnt) {
+ ALOGW("%s(), #%u checkModemReady retry fail...", __FUNCTION__, try_cnt);
+ } else if (try_cnt != 0) {
+ ALOGW("%s(), #%u checkModemReady done", __FUNCTION__, try_cnt);
+ }
+
+ /* format share memory */
+ pSpeechMessenger->formatShareMemory();
+
+
+
+FORMAT_SHM_THREAD_DONE:
+ ALOGD("%s(), terminated", __FUNCTION__);
+ pthread_exit(NULL);
+ return NULL;
+}
+
+
+int SpeechMessengerNormal::formatShareMemory() {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return -ENODEV;
+#endif
+ if (checkModemReady() == false) {
+ ALOGW("%s(), checkModemReady fail...", __FUNCTION__);
+ return -EFAULT;
+ }
+ if (mSpeechShareMem == NULL) {
+ ALOGE("%s(), mSpeechShareMem == NULL!!", __FUNCTION__);
+ return -ENODEV;
+ }
+ return mSpeechShareMem->formatShareMemory();
+}
+
+
+bool SpeechMessengerNormal::checkModemReady() {
+ modem_status_t modem_status = MODEM_STATUS_INVALID;
+ unsigned int status_value = 0;
+ int retval = 0;
+ struct timespec ts_start;
+ struct timespec ts_stop;
+ uint64_t time_diff_msg = 0;
+
+ if (mCcciDeviceHandler < 0) {
+ ALOGW("%s(), ccci not init!!", __FUNCTION__);
+ return false; // -ENODEV;
+ }
+
+ audio_get_timespec_monotonic(&ts_start);
+ retval = ::ioctl(mCcciDeviceHandler, CCCI_IOC_GET_MD_STATE, &status_value);
+ audio_get_timespec_monotonic(&ts_stop);
+ time_diff_msg = get_time_diff_ms(&ts_start, &ts_stop);
+ if (time_diff_msg >= MAX_CCCI_TIMEOUT_MS) {
+ ALOGE("%s(), check MD ready ioctl time %ju ms is too long", __FUNCTION__,
+ time_diff_msg);
+ }
+
+ if (retval < 0) {
+ ALOGW("%s(), ioctl CCCI_IOC_GET_MD_STATE fail!! retval: %d, errno: %d",
+ __FUNCTION__, retval, errno);
+ return false; // retval;
+ }
+
+ if (status_value <= MODEM_STATUS_EXPT) {
+ modem_status = (modem_status_t)(status_value & 0xFF);
+ }
+
+ static bool dump_modem_fail_log = false; /* avoid to dump too much error log */
+ if (modem_status == MODEM_STATUS_READY) {
+ dump_modem_fail_log = false;
+ } else {
+ if (dump_modem_fail_log == false) {
+ ALOGW("%s(), modem_status %d != MODEM_STATUS_READY", __FUNCTION__, modem_status);
+ dump_modem_fail_log = true;
+ }
+ }
+
+ return (modem_status == MODEM_STATUS_READY);
+}
+
+
+bool SpeechMessengerNormal::checkModemAlive() {
+ if (mSpeechShareMem == NULL) {
+ ALOGE("%s(), mSpeechShareMem == NULL!!", __FUNCTION__);
+ return false;
+ }
+ return mSpeechShareMem->checkModemAlive();
+}
+
+
+uint32_t SpeechMessengerNormal::getMaxApPayloadDataSize() {
+ return CCCI_MAX_AP_PAYLOAD_DATA_SIZE;
+}
+
+
+uint32_t SpeechMessengerNormal::getMaxMdPayloadDataSize() {
+ return CCCI_MAX_MD_PAYLOAD_DATA_SIZE;
+}
+
+
+int SpeechMessengerNormal::sendSpeechMessage(sph_msg_t *p_sph_msg) {
+ AL_AUTOLOCK(mCcciMsgSendLock);
+
+ struct timespec ts_start;
+ struct timespec ts_stop;
+ uint64_t time_diff_msg = 0;
+
+ int length_write = 0;
+ int retval = 0;
+ int try_cnt = 0;
+ const int k_max_try_cnt = 20;
+
+ if (p_sph_msg == NULL) {
+ ALOGE("%s(), p_sph_msg = NULL, return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ audio_get_timespec_monotonic(&ts_start);
+ retval = checkCcciStatusAndRecovery();
+ audio_get_timespec_monotonic(&ts_stop);
+ time_diff_msg = get_time_diff_ms(&ts_start, &ts_stop);
+ if (time_diff_msg >= MAX_CCCI_TIMEOUT_MS) {
+ ALOGE("%s(), msg 0x%x check ccci time %ju ms is too long", __FUNCTION__,
+ p_sph_msg->msg_id, time_diff_msg);
+ }
+
+ if (retval != 0) {
+ PRINT_SPH_MSG(ALOGE, "send msg failed!! ccci not ready", p_sph_msg);
+ return retval;
+ }
+
+ if (checkModemReady() == false) {
+ PRINT_SPH_MSG(ALOGE, "send msg failed!! modem not ready", p_sph_msg);
+ return -EPIPE;
+ }
+
+ /* parsing speech message */
+ memset(mCcciMsgSend, 0, sizeof(ccci_msg_t));
+ retval = speechMessageToCcciMessage(p_sph_msg, mCcciMsgSend);
+
+ if (retval != 0) {
+ ALOGE("%s(), speechMessageToCcciMessage fail!! return", __FUNCTION__);
+ return retval;
+ }
+
+ audio_get_timespec_monotonic(&ts_start);
+ /* send message */
+ for (try_cnt = 0; try_cnt < k_max_try_cnt; try_cnt++) {
+ length_write = write(mCcciDeviceHandler,
+ mCcciMsgSend->buffer,
+ mCcciMsgSend->buffer_size);
+ if (length_write == mCcciMsgSend->buffer_size) {
+ retval = 0;
+ break;
+ }
+
+ if (checkModemReady() == false) {
+ PRINT_SPH_MSG(ALOGE, "write msg failed!! modem not ready", p_sph_msg);
+ retval = -EPIPE;
+ break;
+ }
+
+ retval = -EBADMSG;
+ ALOGW("%s(), try_cnt: #%d, msg_id: 0x%x, length_write: %d, errno: %d",
+ __FUNCTION__, try_cnt, p_sph_msg->msg_id, length_write, errno);
+ usleep(2 * 1000);
+ }
+ audio_get_timespec_monotonic(&ts_stop);
+ time_diff_msg = get_time_diff_ms(&ts_start, &ts_stop);
+ if (time_diff_msg >= MAX_CCCI_TIMEOUT_MS) {
+ ALOGE("%s(), msg 0x%x write through ccci time %ju ms is too long", __FUNCTION__,
+ p_sph_msg->msg_id, time_diff_msg);
+ }
+ return retval;
+}
+
+
+int SpeechMessengerNormal::readSpeechMessage(sph_msg_t *p_sph_msg) {
+ AL_AUTOLOCK(mCcciMsgReadLock);
+
+ int length_read = 0;
+ int retval = 0;
+
+ if (p_sph_msg == NULL) {
+ ALOGE("%s(), p_sph_msg = NULL, return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ retval = checkCcciStatusAndRecovery();
+ if (retval != 0) {
+ PRINT_SPH_MSG(ALOGE, "read msg failed!! ccci not ready", p_sph_msg);
+ return retval;
+ }
+
+ /* read message */
+ memset(mCcciMsgRead->buffer, 0, sizeof(mCcciMsgRead->buffer));
+ length_read = read(mCcciDeviceHandler, mCcciMsgRead->buffer, sizeof(mCcciMsgRead->buffer));
+ if (length_read < CCCI_MAILBOX_SIZE) { /* at least one mailbox at once */
+ if (checkModemReady() == true) {
+ ALOGV("%s(), read ccci fail!! modem ready, length_read: %d, errno: %d",
+ __FUNCTION__, (int32_t)length_read, errno);
+ return -ETIMEDOUT;
+ } else {
+ ALOGW("%s(), read ccci fail!! modem invalid, length_read: %d, errno: %d",
+ __FUNCTION__, (int32_t)length_read, errno);
+ return -EPIPE;
+ }
+ }
+
+ mCcciMsgRead->buffer_size = length_read;
+
+ /* parsing ccci message */
+ if (mCcciMsgRead->mail_box.magic == CCCI_MAILBOX_MAGIC) {
+ mCcciMsgRead->buffer_type = CCCI_MSG_BUFFER_TYPE_MAILBOX;
+ } else {
+ mCcciMsgRead->buffer_type = CCCI_MSG_BUFFER_TYPE_MD_PAYLOAD;
+ }
+ retval = ccciMessageToSpeechMessage(mCcciMsgRead, p_sph_msg);
+
+ return retval;
+}
+
+
+int SpeechMessengerNormal::speechMessageToCcciMessage(
+ sph_msg_t *p_sph_msg, ccci_msg_t *p_ccci_msg) {
+
+ int retval = 0;
+
+ if (!p_ccci_msg || !p_sph_msg) {
+ ALOGW("%s(), NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ ccci_mail_box_t *p_mail_box = &p_ccci_msg->mail_box;
+ ccci_ap_payload_t *p_ap_payload = &p_ccci_msg->ap_payload;
+
+ switch (p_sph_msg->buffer_type) {
+ case SPH_MSG_BUFFER_TYPE_MAILBOX:
+ p_mail_box->magic = CCCI_MAILBOX_MAGIC;
+ p_mail_box->param_16bit = p_sph_msg->param_16bit;
+ p_mail_box->msg_id = p_sph_msg->msg_id;
+ p_mail_box->ch = CCCI_A2M_CHANNEL_NUMBER;
+ p_mail_box->param_32bit = p_sph_msg->param_32bit;
+
+ /* date size to be writed */
+ p_ccci_msg->buffer_size = CCCI_MAILBOX_SIZE;
+ retval = 0;
+ break;
+ case SPH_MSG_BUFFER_TYPE_PAYLOAD:
+ p_ap_payload->offset = 0; /* always 0 */
+ p_ap_payload->payload_size = CCCI_MAX_AP_PAYLOAD_HEADER_SIZE + p_sph_msg->payload_data_size;
+ p_ap_payload->ch = CCCI_A2M_CHANNEL_NUMBER;
+ p_ap_payload->param_16bit = CCCI_MAX_AP_PAYLOAD_HEADER_SIZE + p_sph_msg->payload_data_size;
+ p_ap_payload->msg_id = p_sph_msg->msg_id;
+
+
+ p_ap_payload->data_sync = CCCI_AP_PAYLOAD_SYNC;
+ p_ap_payload->data_type = p_sph_msg->payload_data_type;
+ p_ap_payload->data_size = p_sph_msg->payload_data_size;
+
+ if (p_sph_msg->payload_data_addr == NULL) {
+ ALOGE("%s(), payload_data_addr == NULL!!", __FUNCTION__);
+ retval = -ENODEV;
+ break;
+ }
+
+ if (p_sph_msg->payload_data_size > CCCI_MAX_AP_PAYLOAD_DATA_SIZE) {
+ ALOGE("%s(), payload_data_size %d > %d!!", __FUNCTION__,
+ p_sph_msg->payload_data_size,
+ CCCI_MAX_AP_PAYLOAD_DATA_SIZE);
+ retval = -ENOMEM;
+ break;
+ }
+ memcpy(p_ap_payload->payload_data,
+ p_sph_msg->payload_data_addr,
+ p_sph_msg->payload_data_size);
+
+ /* date size to be writed */
+ p_ccci_msg->buffer_size = CCCI_MAILBOX_SIZE + p_ap_payload->payload_size;
+ retval = 0;
+ break;
+ default:
+ ALOGW("%s(), not support type %d!!", __FUNCTION__, p_sph_msg->buffer_type);
+ retval = -EINVAL;
+ }
+
+ return retval;
+}
+
+
+int SpeechMessengerNormal::ccciMessageToSpeechMessage(
+ ccci_msg_t *p_ccci_msg, sph_msg_t *p_sph_msg) {
+
+ int retval = 0;
+
+ if (!p_ccci_msg || !p_sph_msg) {
+ ALOGW("%s(), NULL!! return", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ ccci_mail_box_t *p_mail_box = &p_ccci_msg->mail_box;
+ ccci_md_payload_t *p_md_payload = &p_ccci_msg->md_payload;
+
+ switch (p_ccci_msg->buffer_type) {
+ case CCCI_MSG_BUFFER_TYPE_MAILBOX:
+ ALOGV("%s(), id:0x%x, mailbox, buffer_size: %d, ch:0x%x",
+ __FUNCTION__, p_mail_box->msg_id, p_ccci_msg->buffer_size, p_mail_box->ch);
+ ASSERT(p_ccci_msg->buffer_size == CCCI_MAILBOX_SIZE);
+
+ p_sph_msg->buffer_type = SPH_MSG_BUFFER_TYPE_MAILBOX;
+ p_sph_msg->msg_id = p_mail_box->msg_id;
+ p_sph_msg->param_16bit = p_mail_box->param_16bit;
+ p_sph_msg->param_32bit = p_mail_box->param_32bit;
+ retval = 0;
+ break;
+ case CCCI_MSG_BUFFER_TYPE_MD_PAYLOAD:
+ ALOGV("%s(), id:0x%x, payload, buffer_size: %d, ch:0x%x",
+ __FUNCTION__, p_md_payload->msg_id, p_ccci_msg->buffer_size, p_md_payload->ch);
+ ASSERT(p_ccci_msg->buffer_size == p_md_payload->message_size);
+ ASSERT(p_md_payload->message_size == (CCCI_MAILBOX_SIZE + CCCI_MAX_MD_PAYLOAD_HEADER_SIZE + p_md_payload->data_size));
+ ASSERT(p_md_payload->data_sync == CCCI_MD_PAYLOAD_SYNC);
+ ASSERT(p_md_payload->data_size <= CCCI_MAX_MD_PAYLOAD_DATA_SIZE);
+
+ p_sph_msg->buffer_type = SPH_MSG_BUFFER_TYPE_PAYLOAD;
+ p_sph_msg->msg_id = p_md_payload->msg_id;
+
+ p_sph_msg->payload_data_type = p_md_payload->data_type;
+ p_sph_msg->payload_data_size = p_md_payload->data_size;
+ p_sph_msg->payload_data_addr = p_md_payload->data;
+ p_sph_msg->payload_data_idx = p_md_payload->idx;
+ p_sph_msg->payload_data_total_idx = p_md_payload->total_idx;
+
+ retval = 0;
+ break;
+
+ default:
+ ALOGW("%s(), not support type %d!!", __FUNCTION__, p_ccci_msg->buffer_type);
+ retval = -EINVAL;
+ }
+
+ return retval;
+}
+
+
+int SpeechMessengerNormal::resetShareMemoryIndex() {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return 0;
+#endif
+ if (mSpeechShareMem == NULL) {
+ ALOGE("%s(), mSpeechShareMem == NULL!!", __FUNCTION__);
+ return 0;
+ }
+ return mSpeechShareMem->resetShareMemoryIndex();
+}
+
+
+int SpeechMessengerNormal::writeSphParamToShareMemory(const void *p_sph_param,
+ uint32_t sph_param_length,
+ uint32_t *p_write_idx) {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return -ENODEV;
+#endif
+ if (mSpeechShareMem == NULL) {
+ ALOGE("%s(), mSpeechShareMem == NULL!!", __FUNCTION__);
+ return -ENODEV;
+ }
+ return mSpeechShareMem->writeSphParamToShareMemory(p_sph_param,
+ sph_param_length,
+ p_write_idx);
+}
+
+
+int SpeechMessengerNormal::writeApDataToShareMemory(const void *p_data_buf,
+ uint16_t data_type,
+ uint16_t data_size,
+ uint16_t *p_payload_length,
+ uint32_t *p_write_idx) {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return -ENODEV;
+#endif
+ if (mSpeechShareMem == NULL) {
+ ALOGE("%s(), mSpeechShareMem == NULL!!", __FUNCTION__);
+ return -ENODEV;
+ }
+ return mSpeechShareMem->writeApDataToShareMemory(p_data_buf,
+ data_type,
+ data_size,
+ p_payload_length,
+ p_write_idx);
+}
+
+
+int SpeechMessengerNormal::readMdDataFromShareMemory(void *p_data_buf,
+ uint16_t *p_data_type,
+ uint16_t *p_data_size,
+ uint16_t payload_length,
+ uint32_t read_idx) {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return -ENODEV;
+#endif
+ if (mSpeechShareMem == NULL) {
+ ALOGE("%s(), mSpeechShareMem == NULL!!", __FUNCTION__);
+ return -ENODEV;
+ }
+ return mSpeechShareMem->readMdDataFromShareMemory(p_data_buf,
+ p_data_type,
+ p_data_size,
+ payload_length,
+ read_idx);
+}
+
+
+int SpeechMessengerNormal::getShareMemoryType() {
+#ifndef MTK_CCCI_SHARE_BUFFER_SUPPORT
+ return -ENODEV;
+#endif
+ if (mSpeechShareMem == NULL) {
+ ALOGE("%s(), mSpeechShareMem == NULL!!", __FUNCTION__);
+ return -ENODEV;
+ }
+ return mSpeechShareMem->getShareMemoryType();
+}
+
+
+} // end of namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechParserBase.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechParserBase.cpp
new file mode 100644
index 0000000..19c960c
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechParserBase.cpp
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechParserBase"
+#include <SpeechParserBase.h>
+#include <utils/Log.h>
+#if defined(MTK_SPEECH_USIP_EMI_SUPPORT)
+#include <SpeechParserGen95.h>
+#else
+#include <SpeechParserGen93.h>
+#endif
+
+#include <AudioLock.h>
+#include <AudioUtility.h>//Mutex/assert
+
+
+namespace android {
+
+/*
+ * =============================================================================
+ * Singleton Pattern
+ * =============================================================================
+ */
+SpeechParserBase *SpeechParserBase::uniqueSpeechParser = NULL;
+
+
+SpeechParserBase *SpeechParserBase::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ ALOGV("%s()", __FUNCTION__);
+
+ if (uniqueSpeechParser == NULL) {
+#if defined(MTK_SPEECH_USIP_EMI_SUPPORT)
+ uniqueSpeechParser = SpeechParserGen95::getInstance();
+#else
+ uniqueSpeechParser = SpeechParserGen93::getInstance();
+#endif
+ }
+ ASSERT(uniqueSpeechParser != NULL);
+ return uniqueSpeechParser;
+}
+
+} // end namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechParserGen93.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechParserGen93.cpp
new file mode 100644
index 0000000..6d8c5a5
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechParserGen93.cpp
@@ -0,0 +1,1591 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechParserGen93"
+#include <SpeechParserGen93.h>
+#include <stdlib.h> /* atoi */
+
+#include <utils/Log.h>
+#include <inttypes.h>
+
+#include <media/AudioParameter.h>
+
+#include <AudioLock.h>
+#include <AudioUtility.h>//Mutex/assert
+#include <AudioEventThreadManager.h>
+#include <audio_memory_control.h>
+
+
+namespace android {
+
+#define MAX_BYTE_PARAM_SPEECH 3434
+
+#define SPH_DUMP_STR_SIZE (500)
+#define SPH_PARAM_UNIT_DUMP_STR_SIZE (1024)
+
+static const uint32_t kSphParamSize = 0x3520; // AUDIO_TYPE_SPEECH, => 13K
+
+/*
+ * =============================================================================
+ * ref struct
+ * =============================================================================
+ */
+
+struct SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT {
+ uint16_t sphParserVer;
+ uint16_t numLayer ;
+ uint16_t numEachLayer ;
+ uint16_t paramHeader[4] ;//Network, VoiceBand, Reserved, Reserved
+ uint16_t sphUnitMagiNum;
+
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT() : sphParserVer(0), numLayer(0),
+ numEachLayer(0), paramHeader(), sphUnitMagiNum(0) {}
+};
+
+struct AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT {
+ char *audioTypeName;
+ char numCategoryType;//4
+ std::vector<String8> categoryType;
+ std::vector<String8> categoryName;
+ char numParam;//4
+ std::vector<String8> paramName;
+ char *logPrintParamUnit;
+
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT() : audioTypeName(NULL), numCategoryType(0),
+ categoryType(), categoryName(), numParam(0), paramName(),
+ logPrintParamUnit(NULL) {}
+};
+
+struct SPEECH_PARAM_INFO_STRUCT {
+ speech_mode_t speechMode;
+ unsigned int idxVolume;
+ bool isBtNrecOn;
+ bool isLPBK;
+ unsigned char numHeadsetPole;
+ bool isSingleBandTransfer;
+ unsigned char idxVoiceBandStart;
+ bool isSV;
+ unsigned char idxTTY;
+
+ SPEECH_PARAM_INFO_STRUCT() : speechMode(SPEECH_MODE_NORMAL), idxVolume(0), isBtNrecOn(0),
+ isLPBK(0), numHeadsetPole(0), isSingleBandTransfer(0), idxVoiceBandStart(0),
+ isSV(0), idxTTY(0) {}
+};
+
+struct SPEECH_PARAM_SUPPORT_STRUCT {
+ bool isNetworkSupport;
+ bool isTTYSupport;
+ bool isSuperVolumeSupport;
+
+ SPEECH_PARAM_SUPPORT_STRUCT() : isNetworkSupport(0), isTTYSupport(0),
+ isSuperVolumeSupport(0) {}
+};
+
+struct SPEECH_NETWORK_STRUCT {
+ char name[128];
+ uint16_t supportBit;//4
+
+ SPEECH_NETWORK_STRUCT() : name(), supportBit(0) {}
+};
+
+enum speech_profile_t {
+ SPEECH_PROFILE_HANDSET = 0,
+ SPEECH_PROFILE_4_POLE_HEADSET = 1,
+ SPEECH_PROFILE_HANDSFREE = 2,
+ SPEECH_PROFILE_BT_EARPHONE = 3,
+ SPEECH_PROFILE_BT_NREC_OFF = 4,
+ SPEECH_PROFILE_MAGICONFERENCE = 5,
+ SPEECH_PROFILE_HAC = 6,
+ SPEECH_PROFILE_LPBK_HANDSET = 7,
+ SPEECH_PROFILE_LPBK_HEADSET = 8,
+ SPEECH_PROFILE_LPBK_HANDSFREE = 9,
+ SPEECH_PROFILE_3_POLE_HEADSET = 10,
+ SPEECH_PROFILE_5_POLE_HEADSET = 11,
+ SPEECH_PROFILE_5_POLE_HEADSET_ANC = 12,
+ SPEECH_PROFILE_USB_HEADSET = 13,
+ SPEECH_PROFILE_HANDSET_SV = 14,
+ SPEECH_PROFILE_HANDSFREE_SV = 15,
+ SPEECH_PROFILE_TTY_HCO_HANDSET = 16,
+ SPEECH_PROFILE_TTY_HCO_HANDSFREE = 17,
+ SPEECH_PROFILE_TTY_VCO_HANDSET = 18,
+ SPEECH_PROFILE_TTY_VCO_HANDSFREE = 19,
+
+ SPEECH_PROFILE_MAX_NUM = 20
+};
+
+//--------------------------------------------------------------------------------
+/* XML name */
+const char audioTypeNameList[8][128] = {
+ "Speech",
+ "SpeechDMNR",
+ "SpeechGeneral",
+ "SpeechMagiClarity",
+ "SpeechNetwork",
+ "SpeechEchoRef"
+};
+
+//audio type: Speech
+#define MAX_NUM_CATEGORY_TYPE_SPEECH 4
+#define MAX_NUM_PARAM_SPEECH 3
+const String8 audioType_Speech_CategoryType[ ] = {
+ String8("Band"),
+ String8("Profile"),
+ String8("VolIndex"),
+ String8("Network")
+};
+
+const String8 audioType_Speech_ParamName[ ] = {
+ String8("speech_mode_para"),
+ String8("sph_in_fir"),
+ String8("sph_out_fir"),
+ String8("sph_in_iir_mic1_dsp"),
+ String8("sph_in_iir_mic2_dsp"),
+ String8("sph_in_iir_enh_dsp"),
+ String8("sph_out_iir_enh_dsp")
+};
+
+#define NUM_VOLUME_SPEECH 7
+const char audioType_Speech_CategoryName3[NUM_VOLUME_SPEECH][128] = {"0", "1", "2", "3", "4", "5", "6"};
+const char audioType_Speech_CategoryName2[SPEECH_PROFILE_MAX_NUM][128] = {
+ "Normal",
+ "4_pole_Headset",
+ "Handsfree",
+ "BT_Earphone",
+ "BT_NREC_Off",
+ "MagiConference",
+ "HAC",
+ "Lpbk_Handset",
+ "Lpbk_Headset",
+ "Lpbk_Handsfree",
+ "3_pole_Headset",
+ "5_pole_Headset",
+ "5_pole_Headset+ANC",
+ "Usb_Headset",
+ "Handset_SV",
+ "Handsfree_SV",
+ "Tty_HCO_Handset",
+ "Tty_HCO_Handsfree",
+ "Tty_VCO_Handset",
+ "Tty_VCO_Handsfree"
+};
+
+//--------------------------------------------------------------------------------
+//audio type: SpeechDMNR
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_DMNR 2
+#define MAX_NUM_PARAM_SPEECH_DMNR 1
+const String8 audioType_SpeechDMNR_CategoryType[ ] = {String8("Band"), String8("Profile")};
+const char audioType_SpeechDMNR_CategoryName2[2][128] = {"Handset", "MagiConference"};
+const String8 audioType_SpeechDMNR_ParamName[ ] = {String8("dmnr_para")};
+
+//--------------------------------------------------------------------------------
+//audio type: SpeechGeneral
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_GENERAL 1
+#define MAX_NUM_PARAM_SPEECH_GENERAL 2
+const String8 audioType_SpeechGeneral_CategoryType[ ] = {String8("CategoryLayer")};
+const char audioType_SpeechGeneral_CategoryName1[1][128] = {"Common"};
+const String8 audioType_SpeechGeneral_ParamName[ ] = {String8("speech_common_para"), String8("debug_info")};
+
+//--------------------------------------------------------------------------------
+//audio type: SpeechMagiClarity
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_MAGICLARITY 1
+#define MAX_NUM_PARAM_SPEECH_MAGICLARITY 1
+const String8 audioType_SpeechMagiClarity_CategoryType[ ] = {String8("CategoryLayer")};
+const char audioType_SpeechMagiClarity_CategoryName1[1][128] = {"Common"};
+const String8 audioType_SpeechMagiClarity_ParamName[ ] = {String8("shape_rx_fir_para")};
+
+//--------------------------------------------------------------------------------
+//audio type: SpeechNetwork
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_NETWORK 1
+#define MAX_NUM_PARAM_SPEECH_NETWORK 1
+const String8 audioType_SpeechNetwork_CategoryType[ ] = {String8("Network")};
+const String8 audioType_SpeechNetwork_ParamName[ ] = {String8("speech_network_support")};
+
+
+//--------------------------------------------------------------------------------
+//audio type: SpeechEchoRef
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_ECHOREF 1
+#define MAX_NUM_PARAM_SPEECH_ECHOREF 1
+const String8 audioType_SpeechEchoRef_CategoryType[ ] = {String8("Device")};
+const char audioType_SpeechEchoRef_CategoryName1[1][128] = {"USBAudio"};
+const String8 audioType_SpeechEchoRef_ParamName[ ] = {String8("EchoRef_para")};
+
+#define NUM_NEED_UPDATE_XML 3
+#define LEN_XML_NAME 128
+const char needUpdateXmlList[NUM_NEED_UPDATE_XML][LEN_XML_NAME] = {
+ "Speech",
+ "SpeechDMNR",
+ "SpeechGeneral",
+};
+
+/*==============================================================================
+ * Property keys
+ *============================================================================*/
+
+const char *PROPERTY_KEY_SPEECHLOG_ON = "persist.vendor.audiohal.speech_log_on";
+
+
+/*==============================================================================
+ * Callback Function
+ *============================================================================*/
+void callbackAudioXmlChanged(AppHandle *appHandle, const char *audioTypeName) {
+ ALOGD("+%s(), audioType = %s", __FUNCTION__, audioTypeName);
+
+ // reload XML file
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return;
+ }
+ bool isSpeechParamChanged = false, onlyUpdatedDuringCall = false;
+ int idxXmlNeedUpdate = 0;
+
+ if (appOps->appHandleReloadAudioType(appHandle, audioTypeName) != APP_ERROR) {
+ for (idxXmlNeedUpdate = 0; idxXmlNeedUpdate < NUM_NEED_UPDATE_XML; idxXmlNeedUpdate++) {
+ if (strcmp(audioTypeName, needUpdateXmlList[idxXmlNeedUpdate]) == 0) {
+ isSpeechParamChanged = true;
+ break;
+ }
+ }
+ if (strcmp(audioTypeName, "Speech") == 0) {
+ onlyUpdatedDuringCall = true;
+ }
+
+ if (isSpeechParamChanged) {
+ if (!onlyUpdatedDuringCall) {
+ SpeechParserGen93::getInstance()->mChangedXMLQueue.push_back((speech_type_dynamic_param_t)idxXmlNeedUpdate);
+ AudioEventThreadManager::getInstance()->notifyCallback(AUDIO_EVENT_SPEECH_PARAM_CHANGE, SpeechParserGen93::getInstance());
+ } else if (SpeechParserGen93::getInstance()->mCallOn) {
+ SpeechParserGen93::getInstance()->mChangedXMLQueue.push_back((speech_type_dynamic_param_t)idxXmlNeedUpdate);
+ AudioEventThreadManager::getInstance()->notifyCallback(AUDIO_EVENT_SPEECH_PARAM_CHANGE, SpeechParserGen93::getInstance());
+ }
+ }
+ } else {
+ (void) appHandle;
+ ALOGE("%s(), Reload xml fail!(audioType = %s)", __FUNCTION__, audioTypeName);
+ }
+}
+
+/*
+ * =============================================================================
+ * Singleton Pattern
+ * =============================================================================
+ */
+
+SpeechParserGen93 *SpeechParserGen93::uniqueSpeechParser = NULL;
+
+
+SpeechParserGen93 *SpeechParserGen93::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+ if (uniqueSpeechParser == NULL) {
+ uniqueSpeechParser = new SpeechParserGen93();
+ }
+ ASSERT(uniqueSpeechParser != NULL);
+ return uniqueSpeechParser;
+}
+
+/*
+ * =============================================================================
+ * Constructor / Destructor / Init / Deinit
+ * =============================================================================
+ */
+
+SpeechParserGen93::SpeechParserGen93() {
+ ALOGD("%s()", __FUNCTION__);
+ mSpeechParserAttribute.inputDevice = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ mSpeechParserAttribute.outputDevice = AUDIO_DEVICE_OUT_EARPIECE;
+ mSpeechParserAttribute.idxVolume = 3;
+ mSpeechParserAttribute.driverScenario = SPEECH_SCENARIO_SPEECH_ON;
+ mSpeechParserAttribute.ttyMode = AUD_TTY_OFF;
+ mSpeechParserAttribute.speechFeatureOn = 0;
+ mCallOn = false;
+ AUDIO_ALLOC_STRUCT(SPEECH_PARAM_SUPPORT_STRUCT, mSphParamSupport);
+ AUDIO_ALLOC_STRUCT(SPEECH_PARAM_INFO_STRUCT, mSphParamInfo);
+ AUDIO_ALLOC_STRUCT_ARRAY(SPEECH_NETWORK_STRUCT, 12, mListSpeechNetwork);
+ AUDIO_ALLOC_STRUCT_ARRAY(SPEECH_NETWORK_STRUCT, 12, mNameForEachSpeechNetwork);
+ mChangedXMLQueue.clear();
+
+ mParamBufSize = getMaxBufferSize();
+ if (mParamBufSize <= 0) {
+ ALOGW("%s() mParamBufSize:%d, get buffer size fail!", __FUNCTION__, mParamBufSize);
+ }
+ init();
+}
+
+SpeechParserGen93::~SpeechParserGen93() {
+ ALOGD("%s()", __FUNCTION__);
+ AUDIO_FREE_POINTER(mParamBuf);
+ AUDIO_FREE_POINTER(mNameForEachSpeechNetwork);
+ AUDIO_FREE_POINTER(mListSpeechNetwork);
+ AUDIO_FREE_POINTER(mSphParamInfo);
+ AUDIO_FREE_POINTER(mSphParamSupport);
+}
+
+void SpeechParserGen93::init() {
+ ALOGD("%s()", __FUNCTION__);
+ initAppParser();
+ initSpeechNetwork();
+
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ } else {
+ const char *strSphVersion = appOps->appHandleGetFeatureOptionValue(mAppHandle, "SPH_PARAM_VERSION");
+ if (strSphVersion != NULL) {
+ sscanf(strSphVersion, "%" SCNd8 ".%" SCNd8, &mSpeechParamVerFirst, &mSpeechParamVerLast);
+ switch (mSpeechParamVerFirst) {
+ case 2:
+ mSphParamSupport->isNetworkSupport = true;
+ mNumSpeechParam = 7;
+ break;
+ case 1:
+ mSphParamSupport->isNetworkSupport = true;
+ mNumSpeechParam = 3;
+ break;
+ default:
+ mSphParamSupport->isNetworkSupport = false;
+ mNumSpeechParam = 3;
+ break;
+ }
+ } else {
+ mSpeechParamVerFirst = 0;
+ mSpeechParamVerLast = 0;
+ mSphParamSupport->isNetworkSupport = false;
+ mNumSpeechParam = 3;
+ }
+ const char *strSphTTY = appOps->appHandleGetFeatureOptionValue(mAppHandle, "SPH_PARAM_TTY");
+ if (strSphTTY != NULL) {
+ if (strcmp(strSphTTY, "yes") == 0) {
+ mSphParamSupport->isTTYSupport = true;
+ } else {
+ mSphParamSupport->isTTYSupport = false;
+ }
+ } else {
+ mSphParamSupport->isTTYSupport = false;
+ }
+
+ const char *strSphSV = appOps->appHandleGetFeatureOptionValue(mAppHandle, "SPH_PARAM_SV");
+ if (strSphSV != NULL) {
+ if (strcmp(strSphSV, "yes") == 0) {
+ mSphParamSupport->isSuperVolumeSupport = true;
+ } else {
+ mSphParamSupport->isSuperVolumeSupport = false;
+ }
+ } else {
+ mSphParamSupport->isSuperVolumeSupport = false;
+ }
+
+ ALOGD("%s() appHandleRegXmlChangedCb", __FUNCTION__);
+ /* XML changed callback process */
+ appOps->appHandleRegXmlChangedCb(mAppHandle, callbackAudioXmlChanged);
+ }
+}
+
+void SpeechParserGen93::deInit() {
+ ALOGD("%s()", __FUNCTION__);
+}
+
+
+/*==============================================================================
+ * SpeechParserGen93 Imeplementation
+ *============================================================================*/
+
+/**
+ * =========================================================================
+ * @brief Parsing param file to get parameters into pOutBuf
+ *
+ * @param speechParserAttribute: the attribute for parser
+ * @param pOutBuf: the output buffer
+ * @param sizeByteOutBuf: the size byte of output buffer
+ *
+ * @return int
+ * =========================================================================
+ */
+
+int SpeechParserGen93::getParamBuffer(SpeechParserAttribute speechParserAttribute, SpeechDataBufType *outBuf) {
+ ALOGV("%s() XML scenario: 0x%x", __FUNCTION__, speechParserAttribute.driverScenario);
+
+ mSpeechParserAttribute.inputDevice = speechParserAttribute.inputDevice;
+ mSpeechParserAttribute.outputDevice = speechParserAttribute.outputDevice;
+ mSpeechParserAttribute.idxVolume = speechParserAttribute.idxVolume;
+ mSpeechParserAttribute.driverScenario = speechParserAttribute.driverScenario;
+ mSpeechParserAttribute.speechFeatureOn = speechParserAttribute.speechFeatureOn;
+ mSpeechParserAttribute.ttyMode = speechParserAttribute.ttyMode;
+ ALOGD("%s() inputDevice:0x%x, outputDevice:0x%x, idxVolume:0x%x, Scenario:0x%x, FeatureOn:0x%x, ttyMode:0x%x",
+ __FUNCTION__, mSpeechParserAttribute.inputDevice, mSpeechParserAttribute.outputDevice,
+ mSpeechParserAttribute.idxVolume, mSpeechParserAttribute.driverScenario,
+ mSpeechParserAttribute.speechFeatureOn, mSpeechParserAttribute.ttyMode);
+
+ if (mSpeechParserAttribute.ttyMode != AUD_TTY_OFF && mSphParamSupport->isTTYSupport == false) {
+ mSpeechParserAttribute.ttyMode = AUD_TTY_OFF;
+ ALOGW("%s(), TTY not support! TTY mode: %d -> %d", __FUNCTION__,
+ speechParserAttribute.ttyMode, mSpeechParserAttribute.ttyMode);
+ }
+
+ if (getFeatureOn(SPEECH_FEATURE_SUPERVOLUME) && mSphParamSupport->isSuperVolumeSupport == false) {
+ mSpeechParserAttribute.speechFeatureOn &= ~(1 << SPEECH_FEATURE_SUPERVOLUME);
+ ALOGW("%s(), SuperVolume not support! FeatureOn: %d -> %d", __FUNCTION__,
+ speechParserAttribute.speechFeatureOn, mSpeechParserAttribute.speechFeatureOn);
+ }
+
+ /* dynamic allocate parser buffer */
+ AUDIO_FREE_POINTER(mParamBuf);
+ AUDIO_ALLOC_BUFFER(mParamBuf, mParamBufSize);
+ if (mParamBuf == NULL) {
+ ALOGW("%s() Allocate Parser Buffer Fail!! expect:%d", __FUNCTION__, mParamBufSize);
+ outBuf->memorySize = 0;
+ outBuf->dataSize = 0;
+ return -ENOMEM;
+ }
+ char *param_buf = (char *)mParamBuf;
+
+ uint32_t concateSize = 0, sizeByte = 0;
+
+ switch (mSpeechParserAttribute.driverScenario) {
+ case SPEECH_SCENARIO_SPEECH_ON:
+ sizeByte = (uint32_t)getSpeechParamUnit(param_buf);
+ concateSize += sizeByte;
+ sizeByte = (uint32_t)getDmnrParamUnit(param_buf + concateSize);
+ concateSize += sizeByte;
+ sizeByte = (uint32_t)getGeneralParamUnit(param_buf + concateSize);
+ concateSize += sizeByte;
+ sizeByte = (uint32_t)getMagiClarityParamUnit(param_buf + concateSize);
+ concateSize += sizeByte;
+ break;
+ case SPEECH_SCENARIO_PARAM_CHANGE:
+ if (mChangedXMLQueue.empty() != true) {
+ mIdxAudioType = mChangedXMLQueue.front();
+ mChangedXMLQueue.erase(mChangedXMLQueue.begin());
+ } else {
+ ALOGW("%s() Parameter changed XML queue empty!", __FUNCTION__);
+ }
+ if (mIdxAudioType == AUDIO_TYPE_SPEECH) {
+ sizeByte = (uint32_t)getSpeechParamUnit(param_buf);
+ } else if (mIdxAudioType == AUDIO_TYPE_SPEECH_DMNR) {
+ sizeByte = (uint32_t)getDmnrParamUnit(param_buf);
+ } else if (mIdxAudioType == AUDIO_TYPE_SPEECH_GENERAL) {
+ sizeByte = (uint32_t)getGeneralParamUnit(param_buf + concateSize);
+ } else {
+ ALOGW("%s(), Param Change type not support:%d", __FUNCTION__, mIdxAudioType);
+ }
+ concateSize += sizeByte;
+ break;
+ case SPEECH_SCENARIO_DEVICE_CHANGE:
+ case SPEECH_SCENARIO_VOLUME_CHANGE:
+ case SPEECH_SCENARIO_FEATURE_CHANGE:
+ sizeByte = (uint32_t)getSpeechParamUnit(param_buf);
+ concateSize += sizeByte;
+ break;
+ default:
+ ALOGW("%s(), not support scenario: %d", __FUNCTION__, mSpeechParserAttribute.driverScenario);
+ sizeByte = 0;
+ break;
+ }
+ outBuf->memorySize = kSphParamSize;
+ outBuf->dataSize = concateSize;
+ outBuf->bufferAddr = mParamBuf;
+
+ ALOGV("%s() XML scenario: 0x%x, outBufSize:%d", __FUNCTION__, speechParserAttribute.driverScenario, concateSize);
+
+ return 0;
+}
+
+/**
+ * =========================================================================
+ * @brief set keyString string to library
+ *
+ * @param keyString the "key=value" string
+ * @param sizeKeyString the size byte of string
+ *
+ * @return int
+ * =========================================================================
+ */
+
+int SpeechParserGen93::setKeyValuePair(const SpeechStringBufType *keyValuePair) {
+
+ ALOGD("+%s(): %s", __FUNCTION__, keyValuePair->stringAddr);
+
+ char *keyHeader = NULL;
+ char *keyString = NULL;
+ keyHeader = strtok_r(keyValuePair->stringAddr, ",", &keyString);
+
+ if (strcmp(keyHeader, SPEECH_PARSER_SET_KEY_PREFIX) != 0) {
+ ALOGE("%s(), Wrong Header: %s, expect:%s", __FUNCTION__, keyHeader, SPEECH_PARSER_SET_KEY_PREFIX);
+ return -EINVAL;
+ }
+
+ AudioParameter param = AudioParameter(String8(keyString));
+
+ ALOGV("-%s(): %s", __FUNCTION__, keyValuePair->stringAddr);
+ return 0;
+}
+
+/**
+ * =========================================================================
+ * @brief get keyString string from library
+ *
+ * @param keyString there is only "key" when input,
+ and then library need rewrite "key=value" to keyString
+ * @param sizeKeyString the size byte of string
+ *
+ * @return int
+ * =========================================================================
+ */
+
+int SpeechParserGen93::getKeyValuePair(SpeechStringBufType *keyValuePair) {
+ ALOGV("%s(), keyString:%s", __FUNCTION__, keyValuePair->stringAddr);
+
+ char *keyHeader = NULL;
+ char *keyString = NULL;
+ keyHeader = strtok_r(keyValuePair->stringAddr, ",", &keyString);
+
+ if (strcmp(keyHeader, SPEECH_PARSER_GET_KEY_PREFIX) != 0) {
+ ALOGE("%s(), Wrong Header: %s, expect:%s", __FUNCTION__, keyHeader, SPEECH_PARSER_GET_KEY_PREFIX);
+ return -EINVAL;
+ }
+ char keyValueString[MAX_SPEECH_PARSER_KEY_LEN];
+ memset((void *)keyValueString, 0, MAX_SPEECH_PARSER_KEY_LEN);
+ if (strcmp(keyString, SPEECH_PARSER_PARAMBUF_SIZE) == 0) {
+ sprintf(keyValueString, "%d", kSphParamSize);
+ }
+ keyValuePair->stringAddr = keyValueString;
+ ALOGD("%s(),key:%s , return keyValue:%s", __FUNCTION__, keyString, keyValuePair->stringAddr);
+ return 0;
+}
+/**
+ * =========================================================================
+ * @brief update phone call status from driver
+ *
+ * @param callOn: the phone call status: true(On), false(Off)
+ *
+ * @return int
+ * =========================================================================
+ */
+int SpeechParserGen93::updatePhoneCallStatus(bool callOn) {
+ ALOGV("%s(), callOn:%d", __FUNCTION__, callOn);
+ if (callOn == false) {
+ AUDIO_FREE_POINTER(mParamBuf);
+ }
+ if (mCallOn == callOn) {
+ ALOGW("%s(), callOn(%d) == mCallOn(%d), return",
+ __FUNCTION__, callOn, mCallOn);
+ return 0;
+ }
+ mCallOn = callOn;
+ return 0;
+}
+
+uint32_t SpeechParserGen93::getMaxBufferSize() {
+ uint32_t paramBufSize = 0;
+ char keyString[MAX_SPEECH_PARSER_KEY_LEN];
+ memset((void *)keyString, 0, MAX_SPEECH_PARSER_KEY_LEN);
+
+ SpeechStringBufType keyValuePair;
+ memset(&keyValuePair, 0, sizeof(SpeechStringBufType));
+ keyValuePair.memorySize = strlen(keyString) + 1;
+ keyValuePair.stringSize = strlen(keyString);
+ keyValuePair.stringAddr = keyString;
+
+ sprintf(keyString, "%s,%s", SPEECH_PARSER_GET_KEY_PREFIX, SPEECH_PARSER_PARAMBUF_SIZE);//"SPEECH_PARSER_GET_PARAM,PARAMBUF_SIZE"
+ //get from default parser
+ getKeyValuePair(&keyValuePair);
+ paramBufSize += (uint32_t) atoi(keyValuePair.stringAddr);
+
+ //get from customized parser
+#if defined(CUSTOMIZED_PARSER)
+ SpOps *spOps = spOpsGetInstance();
+ SpHandle *spHandle = spOps->spHandleGetInstance();
+ spOps->getKeyValuePair(spHandle, &keyValuePair);
+ paramBufSize += (uint32_t) atoi(keyValuePair.stringAddr);
+#endif
+
+ ALOGV("%s() paramBufSize:%d", __FUNCTION__, paramBufSize);
+ return paramBufSize;
+
+}
+
+int SpeechParserGen93::getSpeechProfile(const SpeechParserAttribute speechParserAttribute) {
+ speech_profile_t idxSphProfile;
+
+ if (getFeatureOn(SPEECH_FEATURE_LOOPBACK)) {
+ switch (speechParserAttribute.outputDevice) {
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ idxSphProfile = SPEECH_PROFILE_LPBK_HANDSFREE;
+ break;
+ case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+ case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+ idxSphProfile = SPEECH_PROFILE_LPBK_HEADSET;
+ break;
+ default:
+ idxSphProfile = SPEECH_PROFILE_LPBK_HANDSET;
+ break;
+ }
+ } else if (audio_is_bluetooth_sco_device(speechParserAttribute.outputDevice)) {
+ if (getFeatureOn(SPEECH_FEATURE_BTNREC)) {
+
+ idxSphProfile = SPEECH_PROFILE_BT_EARPHONE;
+ } else {
+
+ idxSphProfile = SPEECH_PROFILE_BT_NREC_OFF;
+ }
+ } else {
+
+ switch (speechParserAttribute.outputDevice) {
+ case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+ idxSphProfile = SPEECH_PROFILE_3_POLE_HEADSET;
+ break;
+ case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+ idxSphProfile = SPEECH_PROFILE_4_POLE_HEADSET;
+ break;
+
+ case AUDIO_DEVICE_OUT_SPEAKER:
+#if defined(MTK_INCALL_HANDSFREE_DMNR)
+ idxSphProfile = SPEECH_PROFILE_MAGICONFERENCE;
+#else
+ if (speechParserAttribute.ttyMode == AUD_TTY_OFF) {
+ if (getFeatureOn(SPEECH_FEATURE_SUPERVOLUME)) {
+ idxSphProfile = SPEECH_PROFILE_HANDSFREE_SV;
+ } else {
+ idxSphProfile = SPEECH_PROFILE_HANDSFREE;
+ }
+ } else {
+ switch (speechParserAttribute.ttyMode) {
+ case AUD_TTY_HCO:
+ idxSphProfile = SPEECH_PROFILE_TTY_HCO_HANDSFREE;
+ break;
+ case AUD_TTY_VCO:
+ idxSphProfile = SPEECH_PROFILE_TTY_VCO_HANDSFREE;
+ break;
+ default:
+ idxSphProfile = SPEECH_PROFILE_TTY_HCO_HANDSFREE;
+ break;
+ }
+ }
+#endif
+ break;
+
+ case AUDIO_DEVICE_OUT_USB_DEVICE:
+ idxSphProfile = SPEECH_PROFILE_USB_HEADSET;
+ break;
+
+ default:
+ if (getFeatureOn(SPEECH_FEATURE_HAC)) {
+ idxSphProfile = SPEECH_PROFILE_HAC;
+
+ } else {
+ if (speechParserAttribute.ttyMode == AUD_TTY_OFF) {
+ if (getFeatureOn(SPEECH_FEATURE_SUPERVOLUME)) {
+ idxSphProfile = SPEECH_PROFILE_HANDSET_SV;
+ } else {
+ idxSphProfile = SPEECH_PROFILE_HANDSET;
+ }
+ } else {
+ switch (speechParserAttribute.ttyMode) {
+ case AUD_TTY_HCO:
+ idxSphProfile = SPEECH_PROFILE_TTY_HCO_HANDSET;
+ break;
+ case AUD_TTY_VCO:
+ idxSphProfile = SPEECH_PROFILE_TTY_VCO_HANDSET;
+ break;
+ default:
+ idxSphProfile = SPEECH_PROFILE_TTY_HCO_HANDSET;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ ALOGV("%s(), idxSphProfile = %d", __FUNCTION__, idxSphProfile);
+ return idxSphProfile;
+}
+
+/*==============================================================================
+ * Original SpeechParserGen93 Imeplementation
+ *============================================================================*/
+
+void SpeechParserGen93::initAppParser() {
+ ALOGV("+%s()", __FUNCTION__);
+ /* Init AppHandle */
+ ALOGV("%s() appHandleGetInstance", __FUNCTION__);
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return;
+ }
+ mAppHandle = appOps->appHandleGetInstance();
+ ALOGD("%s() appHandleRegXmlChangedCb", __FUNCTION__);
+
+}
+
+status_t SpeechParserGen93::speechDataDump(char *bufDump,
+ uint16_t idxSphType,
+ const char *nameParam,
+ const char *speechParamData) {
+ if (nameParam == NULL) {
+ return NO_ERROR;
+ }
+ // Speech Log system property
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_SPEECHLOG_ON, property_value, "0"); //"0": default off
+ if (property_value[0] == '0') {
+#if !defined(CONFIG_MT_ENG_BUILD) // user or user debug load
+ return NO_ERROR;
+#endif
+ }
+
+ ALOGV("+%s(), idxSphType=%d", __FUNCTION__, idxSphType);
+ char sphDumpStr[SPH_DUMP_STR_SIZE] = {0};
+ int idxDump = 0, sizeDump = 0, DataTypePrint = 0;
+ //speech parameter dump
+
+ switch (idxSphType) {
+ case AUDIO_TYPE_SPEECH: {
+ if (strcmp(nameParam, "speech_mode_para") == 0) {
+ sizeDump = 16;
+ } else if (strcmp(nameParam, "sph_in_fir") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_out_fir") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_in_iir_mic1_dsp") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_in_iir_mic2_dsp") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_in_iir_enh_dsp") == 0) {
+ sizeDump = 5;
+ } else if (strcmp(nameParam, "sph_out_iir_enh_dsp") == 0) {
+ sizeDump = 5;
+ }
+ break;
+ }
+ case AUDIO_TYPE_SPEECH_GENERAL: {
+ if (strcmp(nameParam, "speech_common_para") == 0) {
+ sizeDump = 12;
+ } else if (strcmp(nameParam, "debug_info") == 0) {
+ sizeDump = 8;
+ }
+ break;
+ }
+ case AUDIO_TYPE_SPEECH_NETWORK: {
+ if (strcmp(nameParam, "speech_network_support") == 0) {
+ DataTypePrint = 1;
+ sizeDump = 1;
+ }
+ break;
+ }
+ case AUDIO_TYPE_SPEECH_ECHOREF: {
+ if (strcmp(nameParam, "USBAudio") == 0) {
+ sizeDump = 3;
+ }
+ break;
+ }
+
+ }
+ snprintf(sphDumpStr, SPH_DUMP_STR_SIZE, "%s[%d]=", nameParam, sizeDump);
+
+ for (idxDump = 0; idxDump < sizeDump; idxDump++) {
+ char sphDumpTemp[100] = {0};
+ if (DataTypePrint == 1) {
+ snprintf(sphDumpTemp, 100, "[%d]0x%x,", idxDump, *((uint16_t *)speechParamData + idxDump));
+ } else {
+ snprintf(sphDumpTemp, 100, "[%d]%d,", idxDump, *((uint16_t *)speechParamData + idxDump));
+ }
+ audio_strncat(sphDumpStr, sphDumpTemp, SPH_DUMP_STR_SIZE);
+ }
+
+ if (idxDump != 0 && bufDump != NULL) {
+ audio_strncat(bufDump, sphDumpStr, SPH_DUMP_STR_SIZE);
+ }
+ return NO_ERROR;
+}
+
+status_t SpeechParserGen93::getSpeechParamFromAppParser(uint16_t idxSphType,
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT *paramLayerInfo,
+ char *bufParamUnit,
+ uint16_t *sizeByteTotal) {
+ ALOGV("+%s(), paramLayerInfo->numCategoryType=0x%x", __FUNCTION__, paramLayerInfo->numCategoryType);
+
+ if (mAppHandle == NULL) {
+ ALOGE("%s() mAppHandle == NULL, Assert!!!", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ char *categoryPath = NULL;
+ ParamUnit *paramUnit = NULL;
+ uint16_t sizeByteParam = 0, idxCount;
+ Param *SpeechParam;
+ UT_string *uts_categoryPath = NULL;
+
+ /* If user select a category path, just like "NarrowBand / Normal of Handset / Level0" */
+ utstring_new(uts_categoryPath);
+
+ ALOGV("%s(), categoryType.size=%zu, paramName.size=%zu", __FUNCTION__, paramLayerInfo->categoryType.size(), paramLayerInfo->paramName.size());
+ for (idxCount = 0; idxCount < paramLayerInfo->categoryType.size() ; idxCount++) {
+ ALOGV("%s(), categoryType[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo->categoryType.at(idxCount).string());
+ }
+ for (idxCount = 0; idxCount < paramLayerInfo->categoryName.size() ; idxCount++) {
+ ALOGV("%s(), categoryName[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo->categoryName.at(idxCount).string());
+ }
+
+
+ for (idxCount = 0; idxCount < paramLayerInfo->numCategoryType ; idxCount++) {
+ if (idxCount == paramLayerInfo->numCategoryType - 1) {
+ //last time concat
+ utstring_printf(uts_categoryPath, "%s,%s", (char *)(paramLayerInfo->categoryType.at(idxCount).string()), (char *)(paramLayerInfo->categoryName.at(idxCount).string()));
+ } else {
+ utstring_printf(uts_categoryPath, "%s,%s,", (char *)(paramLayerInfo->categoryType.at(idxCount).string()), (char *)(paramLayerInfo->categoryName.at(idxCount).string()));
+ }
+ }
+ categoryPath = strdup(utstring_body(uts_categoryPath));
+ utstring_free(uts_categoryPath);
+
+ ALOGV("%s() audioTypeName=%s", __FUNCTION__, paramLayerInfo->audioTypeName);
+ /* Query AudioType */
+ AppOps *appOps = appOpsGetInstance();
+ AudioType *audioType = NULL;
+ if (appOps == NULL) {
+ free(categoryPath);
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ } else {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo->audioTypeName);
+ }
+ if (!audioType) {
+ free(categoryPath);
+ ALOGE("%s() can't find audioTypeName=%s, Assert!!!", __FUNCTION__, paramLayerInfo->audioTypeName);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ /* Query the ParamUnit */
+ appOps->audioTypeReadLock(audioType, __FUNCTION__);
+ paramUnit = appOps->audioTypeGetParamUnit(audioType, categoryPath);
+ if (!paramUnit) {
+ appOps->audioTypeUnlock(audioType);
+ ALOGE("%s() can't find paramUnit, Assert!!! audioType=%s, categoryPath=%s", __FUNCTION__, audioType->name, categoryPath);
+ free(categoryPath);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "(path=%s,id=%d),", categoryPath, paramUnit->paramId);
+ audio_strncat(paramLayerInfo->logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+
+ //for speech param dump
+ char *bufParamDump = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(bufParamDump, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ for (idxCount = 0; idxCount < (*paramLayerInfo).numParam ; idxCount++) {
+
+ SpeechParam = appOps->paramUnitGetParamByName(paramUnit, (const char *)paramLayerInfo->paramName.at(idxCount).string());
+ if (SpeechParam) {
+ sizeByteParam = sizeByteParaData((DATA_TYPE)SpeechParam->paramInfo->dataType, SpeechParam->arraySize);
+ memcpy(bufParamUnit + *sizeByteTotal, SpeechParam->data, sizeByteParam);
+ *sizeByteTotal += sizeByteParam;
+ ALOGV("%s() paramName=%s, sizeByteParam=%d",
+ __FUNCTION__, paramLayerInfo->paramName.at(idxCount).string(), sizeByteParam);
+ //speech parameter dump
+ speechDataDump(bufParamDump, idxSphType, (const char *)paramLayerInfo->paramName.at(idxCount).string(), (const char *)SpeechParam->data);
+ }
+ }
+
+ if (bufParamDump != NULL) {
+ if (bufParamDump[0] != 0) {
+ ALOGD("%s(),dump: %s", __FUNCTION__, bufParamDump);
+ }
+ delete[] bufParamDump;
+ }
+
+ appOps->audioTypeUnlock(audioType);
+ free(categoryPath);
+
+ return NO_ERROR;
+}
+
+uint16_t SpeechParserGen93::sizeByteParaData(uint16_t dataType, uint16_t arraySize) {
+ uint16_t sizeUnit = 4;
+ switch (dataType) {
+ case TYPE_INT:
+ sizeUnit = 4;
+ break;
+ case TYPE_UINT:
+ sizeUnit = 4;
+ break;
+ case TYPE_FLOAT:
+ sizeUnit = 4;
+ break;
+ case TYPE_BYTE_ARRAY:
+ sizeUnit = arraySize;
+ break;
+ case TYPE_UBYTE_ARRAY:
+ sizeUnit = arraySize;
+ break;
+ case TYPE_SHORT_ARRAY:
+ sizeUnit = arraySize << 1;
+ break;
+ case TYPE_USHORT_ARRAY:
+ sizeUnit = arraySize << 1;
+ break;
+ case TYPE_INT_ARRAY:
+ sizeUnit = arraySize << 2;
+ break;
+ case TYPE_UINT_ARRAY:
+ sizeUnit = arraySize << 2;
+ break;
+ default:
+ ALOGE("%s(), Not an available dataType(%d)", __FUNCTION__, dataType);
+
+ break;
+
+ }
+
+ ALOGV("-%s(), arraySize=%d, sizeUnit=%d", __FUNCTION__, arraySize, sizeUnit);
+
+ return sizeUnit;
+
+
+}
+
+status_t SpeechParserGen93::setMDParamUnitHdr(speech_type_dynamic_param_t idxAudioType,
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT *paramUnitHdr,
+ uint16_t configValue) {
+ switch (idxAudioType) {
+ case AUDIO_TYPE_SPEECH:
+ paramUnitHdr->sphUnitMagiNum = 0xAA01;
+ paramUnitHdr->sphParserVer = 1;
+ paramUnitHdr->numLayer = 0x2;
+ paramUnitHdr->paramHeader[0] = 0x1F;//all network use, while modem not check it
+ //Network: bit0: GSM, bit1: WCDMA,.bit2: CDMA, bit3: VoLTE, bit4:C2K
+ if (mSphParamInfo->isSingleBandTransfer) {
+ switch (configValue) {
+ case 0:
+ paramUnitHdr->paramHeader[1] = 0x1;//voice band:NB
+ break;
+ case 1:
+ paramUnitHdr->paramHeader[1] = 0x2;//voice band:WB
+ break;
+
+ default:
+ paramUnitHdr->paramHeader[1] = 0x1;//voice band:NB
+ break;
+ }
+ } else {
+ switch (configValue) {
+ case 1:
+ paramUnitHdr->paramHeader[1] = 0x1;//voice band:NB
+ break;
+ case 2:
+ paramUnitHdr->paramHeader[1] = 0x3;//voice band:NB,WB
+ break;
+ case 3:
+ paramUnitHdr->paramHeader[1] = 0x7;//voice band:NB,WB,SWB
+ break;
+ case 4:
+ paramUnitHdr->paramHeader[1] = 0xF;//voice band:NB,WB,SWB,FB
+ break;
+ default:
+ paramUnitHdr->paramHeader[1] = 0x3;//voice band:NB,WB
+ break;
+ }
+ }
+ paramUnitHdr->paramHeader[2] = (mSpeechParamVerFirst << 4) + mSpeechParamVerLast;
+ ALOGV("%s(), sphUnitMagiNum = 0x%x, SPH_PARAM_VERSION(0x%x)",
+ __FUNCTION__, paramUnitHdr->sphUnitMagiNum, paramUnitHdr->paramHeader[2]);
+ break;
+ case AUDIO_TYPE_SPEECH_DMNR:
+ paramUnitHdr->sphUnitMagiNum = 0xAA03;
+ paramUnitHdr->sphParserVer = 1;
+ paramUnitHdr->numLayer = 0x2;
+ paramUnitHdr->paramHeader[0] = 0x3;//OutputDeviceType
+ switch (configValue) {
+ case 1:
+ paramUnitHdr->paramHeader[1] = 0x1;//voice band:NB
+ break;
+ case 2:
+ paramUnitHdr->paramHeader[1] = 0x3;//voice band:NB,WB
+ break;
+ case 3:
+ paramUnitHdr->paramHeader[1] = 0x7;//voice band:NB,WB,SWB
+ break;
+ case 4:
+ paramUnitHdr->paramHeader[1] = 0xF;//voice band:NB,WB,SWB,FB
+ break;
+ default:
+ paramUnitHdr->paramHeader[1] = 0x3;//voice band:NB,WB
+ break;
+ }
+ paramUnitHdr->paramHeader[2] = (mSpeechParamVerFirst << 4) + mSpeechParamVerLast;
+ ALOGV("%s(), sphUnitMagiNum = 0x%x, Version = 0x%x",
+ __FUNCTION__, paramUnitHdr->sphUnitMagiNum, paramUnitHdr->paramHeader[2]);
+ break;
+
+ default:
+ break;
+ }
+
+ // Speech Log system property
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_SPEECHLOG_ON, property_value, "0"); //"0": default off
+ if (property_value[0] == '0') {
+ return NO_ERROR;
+ } else {
+ char sphDumpStr[SPH_DUMP_STR_SIZE] = "MDParamUnitHdr ";
+ int idxDump = 0;
+ for (idxDump = 0; idxDump < (int)(sizeof(paramUnitHdr) >> 1); idxDump++) { //uint16_t
+ char sphDumpTemp[100] = {0};
+ snprintf(sphDumpTemp, 100, "[%d]0x%x, ", idxDump, *((uint16_t *)¶mUnitHdr + idxDump));
+ audio_strncat(sphDumpStr, sphDumpTemp, SPH_DUMP_STR_SIZE);
+ }
+ if (idxDump != 0) {
+ ALOGD("%s(), %s", __FUNCTION__, sphDumpStr);
+ }
+ }
+ return NO_ERROR;
+}
+
+uint16_t SpeechParserGen93::setMDParamDataHdr(SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT paramUnitHdr,
+ const char *cateBandName, const char *cateNetworkName) {
+ uint16_t idxCount = 0;
+ uint16_t dataHeader = 0, MaskNetwork = 0;
+ bool bNetworkMatch = false;
+
+ if (cateBandName != NULL) {
+ if (strcmp(cateBandName, "NB") == 0) { //All netwrok use
+ dataHeader = 0x1000;
+ } else if (strcmp(cateBandName, "WB") == 0) {
+ dataHeader = 0x2000;
+ } else if (strcmp(cateBandName, "SWB") == 0) {
+ dataHeader = 0x3000;
+ } else if (strcmp(cateBandName, "FB") == 0) {
+ dataHeader = 0x4000;
+ }
+ } else {
+ dataHeader = 0x1000;
+ }
+ //search matched network
+ if (cateNetworkName != NULL) {
+ for (idxCount = 0; idxCount < mNumSpeechNetwork ; idxCount++) {
+ ALOGV("%s(), cateNetwork= %s, mListSpeechNetwork[%d]=%s",
+ __FUNCTION__, cateNetworkName, idxCount, mListSpeechNetwork[idxCount].name);
+ if (strcmp(cateNetworkName, mListSpeechNetwork[idxCount].name) == 0) {
+ MaskNetwork = mListSpeechNetwork[idxCount].supportBit;
+ ALOGV("%s(), cateNetwork= %s, mListSpeechNetwork[%d]=%s, MaskNetwork=0x%x",
+ __FUNCTION__, cateNetworkName, idxCount, mListSpeechNetwork[idxCount].name, MaskNetwork);
+ bNetworkMatch = true;
+ break;
+ }
+ }
+ if (!bNetworkMatch) {
+ ALOGE("%s(), cateNetwork= %s, mListSpeechNetwork[%d]=%s, bNetworkMatch=%d, NO match!!!",
+ __FUNCTION__, cateNetworkName, idxCount, mListSpeechNetwork[idxCount].name, bNetworkMatch);
+ }
+ }
+ if (!mSphParamSupport->isNetworkSupport) {
+ dataHeader = dataHeader >> 8;
+ MaskNetwork = 0xF;
+ }
+ dataHeader |= MaskNetwork;
+ ALOGV("-%s(), sphUnitMagiNum=0x%x, dataHeader=0x%x, MaskNetwork=0x%x, cateBand=%s",
+ __FUNCTION__, paramUnitHdr.sphUnitMagiNum, dataHeader, MaskNetwork, cateBandName);
+
+ return dataHeader;
+}
+
+int SpeechParserGen93::initSpeechNetwork(void) {
+ uint16_t size = 0, idxCount, sizeByteFromApp = 0;
+ char *packedParamUnitFromApp = new char [10];
+ memset(packedParamUnitFromApp, 0, 10);
+
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+
+ //-------------
+ paramLayerInfo.audioTypeName = (char *) audioTypeNameList[AUDIO_TYPE_SPEECH_NETWORK];
+
+ if (mAppHandle == NULL) {
+ ALOGE("%s() mAppHandle == NULL, Assert!!!", __FUNCTION__);
+ ASSERT(0);
+ }
+
+ /* Query AudioType */
+ AppOps *appOps = appOpsGetInstance();
+ AudioType *audioType = NULL;
+ if (appOps != NULL) {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo.audioTypeName);
+ paramLayerInfo.numCategoryType = appOps->audioTypeGetNumOfCategoryType(audioType);//1
+
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_NETWORK;//4
+
+ paramLayerInfo.categoryType.assign(audioType_SpeechNetwork_CategoryType, audioType_SpeechNetwork_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechNetwork_ParamName, audioType_SpeechNetwork_ParamName + paramLayerInfo.numParam);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ ALOGV("%s(), categoryType.size=%zu, paramName.size=%zu", __FUNCTION__, paramLayerInfo.categoryType.size(), paramLayerInfo.paramName.size());
+ for (idxCount = 0; idxCount < paramLayerInfo.categoryType.size() ; idxCount++) {
+ ALOGV("%s(), categoryType[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.categoryType.at(idxCount).string());
+ }
+ for (idxCount = 0; idxCount < paramLayerInfo.paramName.size() ; idxCount++) {
+ ALOGV("%s(), paramName[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.paramName.at(idxCount).string());
+ }
+ //-----------
+ //parse layer
+ CategoryType *categoryNetwork = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_SpeechNetwork_CategoryType[0].string());
+ mNumSpeechNetwork = appOps->categoryTypeGetNumOfCategory(categoryNetwork);
+
+ //parse network
+ for (int i = 0; i < mNumSpeechNetwork; i++) {
+ Category *CateNetwork = appOps->categoryTypeGetCategoryByIndex(categoryNetwork, i);
+ sizeByteFromApp = 0;
+ //clear
+ while (!paramLayerInfo.categoryName.empty()) {
+ paramLayerInfo.categoryName.pop_back();
+ }
+ audio_strncpy(mListSpeechNetwork[i].name, CateNetwork->name, 128);
+
+ paramLayerInfo.categoryName.push_back(String8(CateNetwork->name));//Network
+
+ getSpeechParamFromAppParser(AUDIO_TYPE_SPEECH_NETWORK, ¶mLayerInfo, packedParamUnitFromApp, &sizeByteFromApp);
+ mListSpeechNetwork[i].supportBit = *((uint16_t *)packedParamUnitFromApp);
+ size += sizeByteFromApp;
+
+ ALOGV("%s(), i=%d, sizeByteFromApp=%d, supportBit=0x%x",
+ __FUNCTION__, i, sizeByteFromApp, mListSpeechNetwork[i].supportBit);
+ }
+ ALOGV("-%s(), total size byte=%d", __FUNCTION__, size);
+ } else {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ }
+ //init the Name mapping table for each SpeechNetwork
+ bool IsNetworkFound = false;
+ for (int bitIndex = 0; bitIndex < 12; bitIndex++) {
+ IsNetworkFound = false;
+ for (int NetworkIndex = 0; NetworkIndex < mNumSpeechNetwork; NetworkIndex++) {
+ if (((mListSpeechNetwork[NetworkIndex].supportBit >> bitIndex) & 1) == 1) {
+ audio_strncpy(mNameForEachSpeechNetwork[bitIndex].name, mListSpeechNetwork[NetworkIndex].name, 128);
+ IsNetworkFound = true;
+ break;
+ }
+ }
+ if (!IsNetworkFound) {
+ audio_strncpy(mNameForEachSpeechNetwork[bitIndex].name, mListSpeechNetwork[0].name, 128);
+ }
+ ALOGV("%s(), mNameForEachSpeechNetwork[%d].name = %s",
+ __FUNCTION__, bitIndex, mNameForEachSpeechNetwork[bitIndex].name);
+ }
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+ return size;
+}
+
+
+int SpeechParserGen93::getSpeechParamUnit(char *bufParamUnit) {
+ uint16_t size = 0, idxCount, sizeByteFromApp = 0;
+ uint16_t dataHeader, idxInfo = 0, idxTmp = 0, numBand = 0, numNetwork = 0, numVolume = 0;
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT headerParamUnit;
+ int idxProfile = 0, parserOption = 0;
+
+ idxProfile = getSpeechProfile(mSpeechParserAttribute);
+ int idxVolume = mSpeechParserAttribute.idxVolume;
+ bool btHeadsetNrecOn = getFeatureOn(SPEECH_FEATURE_BTNREC);
+ mSphParamInfo->isBtNrecOn = btHeadsetNrecOn;
+ mSphParamInfo->idxVolume = idxVolume;
+
+ speech_mode_t sphMode = getSpeechModeByOutputDevice(mSpeechParserAttribute.outputDevice);
+
+ /* 93MD unused */
+ parserOption = 0;
+ //bit 0: dv profile, bit 1: single band, bit 4~7: band number
+ mSphParamInfo->isSingleBandTransfer = (bool)(parserOption & 0x2);
+ mSphParamInfo->idxVoiceBandStart = (unsigned char)((parserOption & 0xf0) >> 4);
+ //-----------------
+
+ ALOGD("+%s(), Volume=0x%x, BtNrecOn=0x%x, Profile=%d, parserOption=0x%x",
+ __FUNCTION__, idxVolume, btHeadsetNrecOn, idxProfile, parserOption);
+
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+ //-------------
+ paramLayerInfo.audioTypeName = (char *) audioTypeNameList[AUDIO_TYPE_SPEECH];
+
+ if (mAppHandle == NULL) {
+ ALOGE("%s() mAppHandle == NULL, Assert!!!", __FUNCTION__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ }
+
+ /* Query AudioType */
+ AppOps *appOps = appOpsGetInstance();
+ AudioType *audioType = NULL;
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ } else {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo.audioTypeName);
+ }
+
+ char *packedParamUnitFromApp = new char [MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp, 0, MAX_BYTE_PARAM_SPEECH);
+
+ paramLayerInfo.numCategoryType = appOps->audioTypeGetNumOfCategoryType(audioType);
+ paramLayerInfo.numParam = mNumSpeechParam;//4
+
+ paramLayerInfo.categoryType.assign(audioType_Speech_CategoryType, audioType_Speech_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_Speech_ParamName, audioType_Speech_ParamName + paramLayerInfo.numParam);
+
+ ALOGV("%s(), categoryType.size=%zu, paramName.size=%zu",
+ __FUNCTION__, paramLayerInfo.categoryType.size(), paramLayerInfo.paramName.size());
+ for (idxCount = 0; idxCount < paramLayerInfo.categoryType.size() ; idxCount++) {
+ ALOGV("%s(), categoryType[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.categoryType.at(idxCount).string());
+ }
+ for (idxCount = 0; idxCount < paramLayerInfo.paramName.size() ; idxCount++) {
+ ALOGV("%s(), paramName[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.paramName.at(idxCount).string());
+ }
+ //-----------
+
+ //parse layer
+ CategoryType *categoryNetwork = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_Speech_CategoryType[3].string());
+ CategoryType *categoryBand = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_Speech_CategoryType[0].string());
+ numNetwork = appOps->categoryTypeGetNumOfCategory(categoryNetwork);
+ numBand = appOps->categoryTypeGetNumOfCategory(categoryBand);
+
+ CategoryType *categoryVolume = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_Speech_CategoryType[2].string());
+ CategoryGroup *categoryGroupVolume = appOps->categoryTypeGetCategoryGroupByIndex(categoryVolume, 0);
+ numVolume = appOps->categoryGroupGetNumOfCategory(categoryGroupVolume);
+ idxTmp = (numBand & 0xF) << 4;
+ headerParamUnit.numEachLayer = idxTmp + (numNetwork & 0xF);
+ ALOGV("%s(), sphUnitMagiNum= 0x%x, numEachLayer=0x%x", __FUNCTION__, headerParamUnit.sphUnitMagiNum, headerParamUnit.numEachLayer);
+ if (mSphParamInfo->isSingleBandTransfer) {
+ setMDParamUnitHdr(AUDIO_TYPE_SPEECH, &headerParamUnit, mSphParamInfo->idxVoiceBandStart);
+ } else {
+ setMDParamUnitHdr(AUDIO_TYPE_SPEECH, &headerParamUnit, numBand);
+ }
+ ALOGV("%s(), sphUnitMagiNum= 0x%x, numEachLayer=0x%x", __FUNCTION__, headerParamUnit.sphUnitMagiNum, headerParamUnit.numEachLayer);
+ ALOGV("%s(), categoryNetwork= %s, categoryBand = %s, categoryVolume = %s",
+ __FUNCTION__, categoryNetwork->name, categoryBand->name, categoryVolume->name);
+ ALOGV("%s(), numNetwork= %d, numBand = %d, numVolume = %d", __FUNCTION__, numNetwork, numBand, numVolume);
+
+ memcpy(bufParamUnit + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ idxInfo = sphMode & 0xF;
+ ALOGV("%s(), add mode idxInfo=0x%x", __FUNCTION__, idxInfo);
+ idxTmp = idxVolume << 4;
+ idxInfo += idxTmp;
+ ALOGV("%s(), add volume<<4 idxInfo=0x%x, idxTmp=0x%x", __FUNCTION__, idxInfo, idxTmp);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ memcpy(bufParamUnit + size, &idxInfo, sizeof(idxInfo));
+ size += sizeof(idxInfo);
+ //parse network
+ for (int idxNetwork = 0; idxNetwork < numNetwork; idxNetwork++) {
+ Category *CateNetwork = appOps->categoryTypeGetCategoryByIndex(categoryNetwork, idxNetwork);
+ //parse band
+ for (int idxBand = mSphParamInfo->idxVoiceBandStart; idxBand < mSphParamInfo->idxVoiceBandStart + numBand; idxBand++) {
+ sizeByteFromApp = 0;
+ Category *CateBand = appOps->categoryTypeGetCategoryByIndex(categoryBand, idxBand);
+
+ dataHeader = setMDParamDataHdr(headerParamUnit, CateBand->name, CateNetwork->name);
+ memcpy(bufParamUnit + size, &dataHeader, sizeof(dataHeader));
+ size += sizeof(dataHeader);
+ while (!paramLayerInfo.categoryName.empty()) {
+ paramLayerInfo.categoryName.pop_back();
+ }
+ //Band
+ paramLayerInfo.categoryName.push_back(String8(CateBand->name));//Band
+ //Profile
+ paramLayerInfo.categoryName.push_back(String8(audioType_Speech_CategoryName2[idxProfile]));
+ //Volume
+ if (idxVolume > 6 || idxVolume < 0) {
+ paramLayerInfo.categoryName.push_back(String8(audioType_Speech_CategoryName3[3]));//volume
+ ALOGE("%s(), Invalid IdxVolume=0x%x, use 3 !!!", __FUNCTION__, idxVolume);
+ } else {
+ paramLayerInfo.categoryName.push_back(String8(audioType_Speech_CategoryName3[idxVolume]));
+ }
+ paramLayerInfo.categoryName.push_back(String8(CateNetwork->name));//Network
+
+ for (idxCount = 0; idxCount < paramLayerInfo.categoryName.size() ; idxCount++) {
+ ALOGV("%s(), categoryName[%d]= %s",
+ __FUNCTION__, idxCount, paramLayerInfo.categoryName.at(idxCount).string());
+ }
+
+ getSpeechParamFromAppParser(AUDIO_TYPE_SPEECH, ¶mLayerInfo, packedParamUnitFromApp, &sizeByteFromApp);
+
+ memcpy(bufParamUnit + size, packedParamUnitFromApp, sizeByteFromApp);
+ size += sizeByteFromApp;
+
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "size(b)=%d; total size(b)=%d", sizeByteFromApp, size);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ }
+
+ ALOGD("-%s(), MagiNum(0x%x),xml(%s),version(0x%x),%s", __FUNCTION__, headerParamUnit.sphUnitMagiNum,
+ paramLayerInfo.audioTypeName, headerParamUnit.paramHeader[2], paramLayerInfo.logPrintParamUnit);
+ //reset buffer pointer
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+ paramLayerInfo.logPrintParamUnit[0] = '\0';
+ }
+
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+
+ return size;
+}
+
+int SpeechParserGen93::getGeneralParamUnit(char *bufParamUnit) {
+ ALOGV("+%s()", __FUNCTION__);
+ uint16_t size = 0, idxCount = 0, idxCount2 = 0, sizeByteFromApp = 0;
+ uint16_t dataHeader;
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT headerParamUnit;
+
+ headerParamUnit.sphParserVer = 1;
+ headerParamUnit.numLayer = 0x1;
+ headerParamUnit.numEachLayer = 0x1;
+ headerParamUnit.paramHeader[0] = 0x1;//Common
+ headerParamUnit.sphUnitMagiNum = 0xAA02;
+
+ memcpy(bufParamUnit + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ char *packedParamUnitFromApp = new char [MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp, 0, MAX_BYTE_PARAM_SPEECH);
+
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+
+ paramLayerInfo.audioTypeName = (char *) audioTypeNameList[AUDIO_TYPE_SPEECH_GENERAL];
+ paramLayerInfo.numCategoryType = MAX_NUM_CATEGORY_TYPE_SPEECH_GENERAL;//4
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_GENERAL;//4
+
+ paramLayerInfo.categoryType.assign(audioType_SpeechGeneral_CategoryType, audioType_SpeechGeneral_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechGeneral_ParamName, audioType_SpeechGeneral_ParamName + paramLayerInfo.numParam);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ ALOGD("%s(), eParamUnitHdr.sphUnitMagiNum= 0x%x, categoryType.size=%zu, paramName.size=%zu",
+ __FUNCTION__, headerParamUnit.sphUnitMagiNum, paramLayerInfo.categoryType.size(), paramLayerInfo.paramName.size());
+ for (idxCount = 0; idxCount < paramLayerInfo.paramName.size() ; idxCount++) {
+ ALOGV("%s(), paramName[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.paramName.at(idxCount).string());
+ }
+
+ dataHeader = 0x000F;
+ memcpy(bufParamUnit + size, &dataHeader, sizeof(dataHeader));
+ size += sizeof(dataHeader);
+
+ paramLayerInfo.categoryName.push_back(String8(audioType_SpeechGeneral_CategoryName1[0]));
+
+ getSpeechParamFromAppParser(AUDIO_TYPE_SPEECH_GENERAL, ¶mLayerInfo, packedParamUnitFromApp, &sizeByteFromApp);
+
+ memcpy(bufParamUnit + size, packedParamUnitFromApp, sizeByteFromApp);
+ size += sizeByteFromApp;
+
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "total size(b)=%d", size);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ ALOGD("%s(),MagiNum(0x%x),xml(%s), %s",
+ __FUNCTION__, headerParamUnit.sphUnitMagiNum, paramLayerInfo.audioTypeName, paramLayerInfo.logPrintParamUnit);
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+
+ return size;
+}
+
+int SpeechParserGen93::getMagiClarityParamUnit(char *bufParamUnit) {
+ ALOGV("+%s()", __FUNCTION__);
+ uint16_t size = 0, idxCount = 0, idxCount2 = 0, sizeByteFromApp = 0;
+ uint16_t dataHeader;
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT headerParamUnit;
+
+ headerParamUnit.sphParserVer = 1;
+ headerParamUnit.numLayer = 0x1;
+ headerParamUnit.numEachLayer = 0x1;
+ headerParamUnit.paramHeader[0] = 0x1;//Common
+ headerParamUnit.sphUnitMagiNum = 0xAA04;
+
+ memcpy(bufParamUnit + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ char *packedParamUnitFromApp = new char [MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp, 0, MAX_BYTE_PARAM_SPEECH);
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+
+ paramLayerInfo.audioTypeName = (char *) audioTypeNameList[AUDIO_TYPE_SPEECH_MAGICLARITY];
+ paramLayerInfo.numCategoryType = MAX_NUM_CATEGORY_TYPE_SPEECH_MAGICLARITY;//4
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_MAGICLARITY;//4
+
+ paramLayerInfo.categoryType.assign(audioType_SpeechMagiClarity_CategoryType, audioType_SpeechMagiClarity_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechMagiClarity_ParamName, audioType_SpeechMagiClarity_ParamName + paramLayerInfo.numParam);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ for (idxCount = 0; idxCount < paramLayerInfo.paramName.size() ; idxCount++) {
+ ALOGD("%s(), paramName[%d]= %s", __FUNCTION__, idxCount, paramLayerInfo.paramName.at(idxCount).string());
+ }
+ dataHeader = 0x000F;
+ memcpy(bufParamUnit + size, &dataHeader, sizeof(dataHeader));
+ size += sizeof(dataHeader);
+
+ paramLayerInfo.categoryName.push_back(String8(audioType_SpeechMagiClarity_CategoryName1[0]));
+
+ getSpeechParamFromAppParser(AUDIO_TYPE_SPEECH_MAGICLARITY, ¶mLayerInfo, packedParamUnitFromApp, &sizeByteFromApp);
+
+ memcpy(bufParamUnit + size, packedParamUnitFromApp, sizeByteFromApp);
+ size += sizeByteFromApp;
+
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "total size(b)=%d", size);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ ALOGD("%s(),MagiNum(0x%x),xml(%s), %s", __FUNCTION__,
+ headerParamUnit.sphUnitMagiNum, paramLayerInfo.audioTypeName, paramLayerInfo.logPrintParamUnit);
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+
+ return size;
+}
+
+int SpeechParserGen93::getDmnrParamUnit(char *bufParamUnit) {
+ ALOGV("+%s()", __FUNCTION__);
+ uint16_t size = 0, idxBand = 0, idxProfile = 0, sizeByteFromApp = 0;
+ uint16_t dataHeader, idxTmp = 0, numBand = 0, numProfile = 0;
+ SPEECH_DYNAMIC_PARAM_UNIT_HDR_STRUCT headerParamUnit;
+ AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT paramLayerInfo;
+
+ paramLayerInfo.audioTypeName = (char *) audioTypeNameList[AUDIO_TYPE_SPEECH_DMNR];
+ paramLayerInfo.numCategoryType = MAX_NUM_CATEGORY_TYPE_SPEECH_DMNR;//4
+ paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_DMNR;//4
+ paramLayerInfo.categoryType.assign(audioType_SpeechDMNR_CategoryType, audioType_SpeechDMNR_CategoryType + paramLayerInfo.numCategoryType);
+ paramLayerInfo.paramName.assign(audioType_SpeechDMNR_ParamName, audioType_SpeechDMNR_ParamName + paramLayerInfo.numParam);
+ paramLayerInfo.logPrintParamUnit = new char[SPH_PARAM_UNIT_DUMP_STR_SIZE];
+ memset(paramLayerInfo.logPrintParamUnit, 0, SPH_PARAM_UNIT_DUMP_STR_SIZE);
+
+ ALOGD("%s(), categoryType.size=%zu, paramName.size=%zu",
+ __FUNCTION__, paramLayerInfo.categoryType.size(), paramLayerInfo.paramName.size());
+ /* Query AudioType */
+ AppOps *appOps = appOpsGetInstance();
+ AudioType *audioType = NULL;
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ return UNKNOWN_ERROR;
+ } else {
+ audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo.audioTypeName);
+ }
+ char *packedParamUnitFromApp = new char [MAX_BYTE_PARAM_SPEECH];
+ memset(packedParamUnitFromApp, 0, MAX_BYTE_PARAM_SPEECH);
+
+ CategoryType *categoryBand = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_SpeechDMNR_CategoryType[0].string());
+ numBand = appOps->categoryTypeGetNumOfCategory(categoryBand);
+ CategoryType *categoryProfile = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_SpeechDMNR_CategoryType[1].string());
+ numProfile = appOps->categoryTypeGetNumOfCategory(categoryProfile);
+ idxTmp = (numBand & 0xF) << 4;
+ headerParamUnit.numEachLayer = idxTmp + (numProfile & 0xF);
+ setMDParamUnitHdr(AUDIO_TYPE_SPEECH_DMNR, &headerParamUnit, numBand);
+
+ memcpy(bufParamUnit + size, &headerParamUnit, sizeof(headerParamUnit));
+ size += sizeof(headerParamUnit);
+
+ for (idxBand = 0; idxBand < numBand; idxBand++) { //NB, WB, SWB
+ for (idxProfile = 0; idxProfile < numProfile; idxProfile++) {
+ sizeByteFromApp = 0;
+ dataHeader = ((idxBand + 1) << 4) + (idxProfile + 1);
+ memcpy(bufParamUnit + size, &dataHeader, sizeof(dataHeader));
+ size += sizeof(dataHeader);
+ Category *CateBand = appOps->categoryTypeGetCategoryByIndex(categoryBand, idxBand);
+ paramLayerInfo.categoryName.push_back(String8(CateBand->name));//Band
+ paramLayerInfo.categoryName.push_back(String8(audioType_SpeechDMNR_CategoryName2[idxProfile]));//Profile
+
+ getSpeechParamFromAppParser(AUDIO_TYPE_SPEECH_DMNR, ¶mLayerInfo, packedParamUnitFromApp, &sizeByteFromApp);
+
+ memcpy(bufParamUnit + size, packedParamUnitFromApp, sizeByteFromApp);
+ size += sizeByteFromApp;
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "header=0x%x[%d,%d], size(b)=%d;", dataHeader, idxBand, idxProfile, sizeByteFromApp);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ paramLayerInfo.categoryName.pop_back();
+ paramLayerInfo.categoryName.pop_back();
+
+ }
+ }
+
+ if (packedParamUnitFromApp != NULL) {
+ delete[] packedParamUnitFromApp;
+ }
+
+ char sphLogTemp[SPH_DUMP_STR_SIZE] = {0};
+ snprintf(sphLogTemp, SPH_DUMP_STR_SIZE, "total size(b)=%d", size);
+ audio_strncat(paramLayerInfo.logPrintParamUnit, sphLogTemp, SPH_DUMP_STR_SIZE);
+ ALOGD("%s(),MagiNum(0x%x),xml(%s), %s",
+ __FUNCTION__, headerParamUnit.sphUnitMagiNum, paramLayerInfo.audioTypeName, paramLayerInfo.logPrintParamUnit);
+ if (paramLayerInfo.logPrintParamUnit != NULL) {
+ delete[] paramLayerInfo.logPrintParamUnit;
+ }
+
+ return size;
+}
+
+speech_mode_t SpeechParserGen93::getSpeechModeByOutputDevice(const audio_devices_t output_device) {
+ speech_mode_t speech_mode = SPEECH_MODE_NORMAL;
+
+ if (audio_is_bluetooth_sco_device(output_device)) {
+ speech_mode = SPEECH_MODE_BT_EARPHONE;
+ } else if (output_device == AUDIO_DEVICE_OUT_SPEAKER) {
+#if defined(MTK_INCALL_HANDSFREE_DMNR)
+ speech_mode = SPEECH_MODE_MAGIC_CON_CALL;
+#else
+ speech_mode = SPEECH_MODE_LOUD_SPEAKER;
+#endif
+ } else if (output_device == AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+ speech_mode = SPEECH_MODE_EARPHONE;
+ } else if (output_device == AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+ speech_mode = SPEECH_MODE_EARPHONE;
+ }
+#ifdef MTK_USB_PHONECALL
+ else if (output_device == AUDIO_DEVICE_OUT_USB_DEVICE) {
+ speech_mode = SPEECH_MODE_USB_AUDIO;
+ }
+#endif
+ else if (output_device == AUDIO_DEVICE_OUT_EARPIECE) {
+ if (getFeatureOn(SPEECH_FEATURE_HAC)) {
+ speech_mode = SPEECH_MODE_HAC;
+ } else {
+ speech_mode = SPEECH_MODE_NORMAL;
+ }
+ }
+ return speech_mode;
+}
+
+bool SpeechParserGen93::getFeatureOn(const SpeechFeatureType featureType) {
+ uint16_t featureMaskType = 1 << featureType;
+ const bool featureOn = mSpeechParserAttribute.speechFeatureOn & featureMaskType;
+ ALOGV("%s() featureMaskType: 0x%x, featureOn=%d", __FUNCTION__, featureMaskType, featureOn);
+ return featureOn;
+}
+
+
+} // end namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechParserGen95.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechParserGen95.cpp
new file mode 100644
index 0000000..e1805d3
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechParserGen95.cpp
@@ -0,0 +1,283 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechParserGen95"
+#include <SpeechParserGen95.h>
+#include <stdlib.h> /* atoi */
+#include <utils/Log.h>
+#include <AudioLock.h>
+#include <AudioAssert.h>//Mutex/assert
+#include <AudioParamParser.h>
+#include <SpeechParser.h>//external/AudioSpeechEnhancement
+#include <AudioEventThreadManager.h>
+
+
+namespace android {
+
+/*
+* =============================================================================
+* define/enum
+* =============================================================================
+*/
+#define NUM_NEED_UPDATE_XML 3
+#define LEN_XML_NAME 128
+const char needUpdateXmlList[NUM_NEED_UPDATE_XML][LEN_XML_NAME] = {
+ "Speech",
+ "SpeechDMNR",
+ "SpeechGeneral",
+};
+/*==============================================================================
+* Callback Function
+*============================================================================*/
+void callbackAudioXmlChanged(AppHandle *appHandle, const char *audioTypeName) {
+ ALOGD("%s(), audioType = %s", __FUNCTION__, audioTypeName);
+
+ // reload XML file
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("%s(), Error: AppOps == NULL", __FUNCTION__);
+ ASSERT(0);
+ return;
+ }
+ bool isSpeechParamChanged = false, onlyUpdatedDuringCall = false;
+ int idxXmlNeedUpdate = 0;
+
+ if (appOps->appHandleReloadAudioType(appHandle, audioTypeName) != APP_ERROR) {
+ for (idxXmlNeedUpdate = 0; idxXmlNeedUpdate < NUM_NEED_UPDATE_XML; idxXmlNeedUpdate++) {
+ if (strcmp(audioTypeName, needUpdateXmlList[idxXmlNeedUpdate]) == 0) {
+ isSpeechParamChanged = true;
+ break;
+ }
+ }
+ if (strcmp(audioTypeName, "Speech") == 0) {
+ onlyUpdatedDuringCall = true;
+ }
+ if (isSpeechParamChanged) {
+ if (!onlyUpdatedDuringCall) {
+ SpeechParserGen95::getInstance()->mChangedXMLQueue.push_back((char *)needUpdateXmlList[idxXmlNeedUpdate]);
+ AudioEventThreadManager::getInstance()->notifyCallback(AUDIO_EVENT_SPEECH_PARAM_CHANGE,
+ SpeechParserGen95::getInstance());
+ } else if (SpeechParserGen95::getInstance()->mCallOn) {
+ SpeechParserGen95::getInstance()->mChangedXMLQueue.push_back((char *)needUpdateXmlList[idxXmlNeedUpdate]);
+ AudioEventThreadManager::getInstance()->notifyCallback(AUDIO_EVENT_SPEECH_PARAM_CHANGE,
+ SpeechParserGen95::getInstance());
+ }
+ }
+ } else {
+ (void) appHandle;
+ ALOGE("%s(), reload xml fail!(audioType = %s)", __FUNCTION__, audioTypeName);
+ }
+}
+
+/*
+* =============================================================================
+* Singleton Pattern
+* =============================================================================
+*/
+SpeechParserGen95 *SpeechParserGen95::uniqueSpeechParser = NULL;
+
+SpeechParserGen95 *SpeechParserGen95::getInstance() {
+ static AudioLock mGetInstanceLock;
+ AL_AUTOLOCK(mGetInstanceLock);
+
+ ALOGV("%s()", __FUNCTION__);
+ if (uniqueSpeechParser == NULL) {
+ uniqueSpeechParser = new SpeechParserGen95();
+ }
+ ASSERT(uniqueSpeechParser != NULL);
+ return uniqueSpeechParser;
+}
+
+/*
+* =============================================================================
+* class implementation
+* =============================================================================
+*/
+SpeechParserGen95::SpeechParserGen95() {
+ ALOGD("%s()", __FUNCTION__);
+ mSpeechParserAttribute.inputDevice = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ mSpeechParserAttribute.outputDevice = AUDIO_DEVICE_OUT_EARPIECE;
+ mSpeechParserAttribute.idxVolume = 3;
+ mSpeechParserAttribute.driverScenario = SPEECH_SCENARIO_SPEECH_ON;
+ mSpeechParserAttribute.ttyMode = AUD_TTY_OFF;
+ mSpeechParserAttribute.speechFeatureOn = 0;
+ mCallOn = false;
+ mMonitoredXmlName = new char[128];
+ mChangedXMLQueue.clear();
+ mParamBufSize = getMaxBufferSize();
+ if (mParamBufSize <= 0) {
+ ALOGW("%s() mParamBufSize:%d, get buffer size fail!", __FUNCTION__, mParamBufSize);
+ }
+ AppHandle *appHandle = NULL;
+ AppOps *appOps = appOpsGetInstance();
+ if (appOps == NULL) {
+ ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+ ASSERT(0);
+ } else {
+ appHandle = appOps->appHandleGetInstance();
+ ALOGD("%s() appHandleRegXmlChangedCb", __FUNCTION__);
+ /* XML changed callback process */
+ appOps->appHandleRegXmlChangedCb(appHandle, callbackAudioXmlChanged);
+ }
+}
+
+SpeechParserGen95::~SpeechParserGen95() {
+ ALOGD("%s()", __FUNCTION__);
+ if (mMonitoredXmlName != NULL) {
+ delete(mMonitoredXmlName);
+ mMonitoredXmlName = NULL;
+ }
+ AUDIO_FREE_POINTER(mParamBuf);
+ mChangedXMLQueue.clear();
+
+}
+/**
+* =========================================================================
+* @brief Parsing param file to get parameters into pOutBuf
+*
+* @param speechParserAttribute: the attribute for parser
+* @param pOutBuf: the output buffer
+*
+* @return int
+* =========================================================================
+*/
+int SpeechParserGen95::getParamBuffer(SpeechParserAttribute speechParserAttribute, SpeechDataBufType *outBuf) {
+ int retval = 0;
+ mSpeechParserAttribute.inputDevice = speechParserAttribute.inputDevice;
+ mSpeechParserAttribute.outputDevice = speechParserAttribute.outputDevice;
+ mSpeechParserAttribute.idxVolume = speechParserAttribute.idxVolume;
+ mSpeechParserAttribute.driverScenario = speechParserAttribute.driverScenario;
+ mSpeechParserAttribute.speechFeatureOn = speechParserAttribute.speechFeatureOn;
+ mSpeechParserAttribute.ttyMode = speechParserAttribute.ttyMode;
+ ALOGD("%s() inputDevice: 0x%x, outputDevice: 0x%x, Volume: 0x%x, Scenario: 0x%x, FeatureOn: 0x%x, ttyMode: 0x%x",
+ __FUNCTION__, mSpeechParserAttribute.inputDevice, mSpeechParserAttribute.outputDevice,
+ mSpeechParserAttribute.idxVolume, mSpeechParserAttribute.driverScenario,
+ mSpeechParserAttribute.speechFeatureOn, mSpeechParserAttribute.ttyMode);
+
+ /* dynamic allocate parser buffer */
+ AUDIO_FREE_POINTER(mParamBuf);
+ AUDIO_ALLOC_BUFFER(mParamBuf, mParamBufSize);
+ if (mParamBuf == NULL) {
+ ALOGW("%s() Allocate Parser Buffer Fail!! expect:%d", __FUNCTION__, mParamBufSize);
+ outBuf->memorySize = 0;
+ outBuf->dataSize = 0;
+ return -ENOMEM;
+ }
+ outBuf->bufferAddr = (char *)mParamBuf;
+ outBuf->memorySize = mParamBufSize;
+ outBuf->dataSize = 0;
+
+ if (mSpeechParserAttribute.driverScenario == SPEECH_SCENARIO_PARAM_CHANGE) {
+ if (mChangedXMLQueue.empty() != true) {
+ mMonitoredXmlName = mChangedXMLQueue.front();
+ mChangedXMLQueue.erase(mChangedXMLQueue.begin());
+ ALOGD("%s() parameter changed (%s)!", __FUNCTION__, mMonitoredXmlName);
+ } else {
+ ALOGW("%s() parameter changed XML queue empty!", __FUNCTION__);
+ }
+ }
+ SpOps *spOps = spOpsGetInstance();
+ SpHandle *spHandle = spOps->spHandleGetInstance();
+ retval = spOps->getParamBuffer(spHandle, mSpeechParserAttribute, outBuf);
+ ALOGD("%s(), scenario: 0x%x, dataSize:%d, retval:%d",
+ __FUNCTION__, speechParserAttribute.driverScenario, outBuf->dataSize, retval);
+
+ return retval;
+}
+
+/**
+* =========================================================================
+* @brief set keyString string to library
+*
+* @param keyString the "key = value" string
+* @param sizeKeyString the size byte of string
+*
+* @return int
+* =========================================================================
+*/
+int SpeechParserGen95::setKeyValuePair(const SpeechStringBufType *keyValuePair) {
+ ALOGD("+%s(), %s stringAddr =%p, memorySize = 0x%x, dataSize = 0x%x",
+ __FUNCTION__,
+ keyValuePair->stringAddr,
+ keyValuePair->stringAddr,
+ keyValuePair->memorySize,
+ keyValuePair->stringSize);
+
+ SpOps *spOps = spOpsGetInstance();
+ SpHandle *spHandle = spOps->spHandleGetInstance();
+ spOps->setKeyValuePair(spHandle, keyValuePair);
+ ALOGD("-%s(), %s", __FUNCTION__, keyValuePair->stringAddr);
+ return 0;
+}
+
+/**
+* =========================================================================
+* @brief get keyString string from library
+*
+* @param keyString there is only "key" when input,
+and then library need rewrite "key = value" to keyString
+* @param sizeKeyString the size byte of string
+*
+* @return int
+* =========================================================================
+*/
+int SpeechParserGen95::getKeyValuePair(SpeechStringBufType *keyValuePair) {
+ ALOGD("+%s(), %s stringAddr = 0x%p, memorySize = 0x%x, dataSize = 0x%x",
+ __FUNCTION__,
+ keyValuePair->stringAddr,
+ keyValuePair->stringAddr,
+ keyValuePair->memorySize,
+ keyValuePair->stringSize);
+ SpOps *spOps = spOpsGetInstance();
+ SpHandle *spHandle = spOps->spHandleGetInstance();
+ spOps->getKeyValuePair(spHandle, keyValuePair);
+ ALOGD("-%s(),%s", __FUNCTION__, keyValuePair->stringAddr);
+ return 0;
+}
+
+/**
+* =========================================================================
+* @brief update phone call status from driver
+*
+* @param callOn: the phone call status: true(On), false(Off)
+*
+* @return int
+* =========================================================================
+*/
+int SpeechParserGen95::updatePhoneCallStatus(bool callOn) {
+ ALOGD("%s(), callOn:%d", __FUNCTION__, callOn);
+ if (callOn == false) {
+ AUDIO_FREE_POINTER(mParamBuf);
+ }
+ if (mCallOn == callOn) {
+ ALOGW("%s(), callOn(%d) == mCallOn(%d), return",
+ __FUNCTION__, callOn, mCallOn);
+ return 0;
+ }
+ mCallOn = callOn;
+ return 0;
+}
+
+uint32_t SpeechParserGen95::getMaxBufferSize() {
+ uint32_t paramBufSize = 0;
+ char keyString[MAX_SPEECH_PARSER_KEY_LEN];
+ memset((void *)keyString, 0, MAX_SPEECH_PARSER_KEY_LEN);
+
+ SpeechStringBufType keyValuePair;
+ memset(&keyValuePair, 0, sizeof(SpeechStringBufType));
+ keyValuePair.memorySize = strlen(keyString) + 1;
+ keyValuePair.stringSize = strlen(keyString);
+ keyValuePair.stringAddr = keyString;
+
+ snprintf(keyString, MAX_SPEECH_PARSER_KEY_LEN, "%s,%s", SPEECH_PARSER_GET_KEY_PREFIX, SPEECH_PARSER_PARAMBUF_SIZE);
+ //get from default parser
+ SpOps *spOps = spOpsGetInstance();
+ SpHandle *spHandle = spOps->spHandleGetInstance();
+ spOps->getKeyValuePair(spHandle, &keyValuePair);
+ paramBufSize = (uint32_t) atoi(keyValuePair.stringAddr);
+ return paramBufSize;
+
+}
+} // end namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechPcm2way.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechPcm2way.cpp
new file mode 100644
index 0000000..b2385c9
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechPcm2way.cpp
@@ -0,0 +1,504 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "Play2Way"
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <utils/threads.h>
+
+#include "SpeechPcm2way.h"
+#include "SpeechType.h"
+
+/*****************************************************************************
+* C O N S T A N T S
+******************************************************************************
+*/
+#define AUDIO_INPUT_BUFFER_SIZE (16384) // 16k
+#define AUDIO_OUTPUT_BUFFER_SIZE (16384) // 16k
+
+namespace android {
+/*==============================================================================
+ * Property keys
+ *============================================================================*/
+const char* PROPERTY_KEY_P2W_DUMP_ON = "persist.vendor.audiohal.p2w_dump_on";
+
+/*==============================================================================
+ * Constant
+ *============================================================================*/
+static const char kFileNamePlay2Way[] = "/data/vendor/audiohal/audio_dump/Play2Way";
+static const char kFileNameRecord2Way[] = "/data/vendor/audiohal/audio_dump/Record2Way";
+static const uint32_t kMaxSizeOfFileName = 128;
+static const uint32_t kSizeOfPrefixFileNamePlay2Way = sizeof(kFileNamePlay2Way) - 1;
+static const uint32_t kSizeOfPrefixFileNameRecord2Way = sizeof(kFileNameRecord2Way) - 1;
+
+/***********************************************************
+*
+* PCM2WAY Interface - Play2Way
+*
+***********************************************************/
+
+#ifdef PLAY2WAY_USE_SINE_WAVE
+static const uint16_t table_1k_tone_8000_hz[] = {
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F,
+ 0x0000, 0x5A81, 0x7FFF, 0x5A81,
+ 0x0000, 0xA57E, 0x8001, 0xA57F
+};
+static const uint32_t kSizeSinewaveTable = sizeof(table_1k_tone_8000_hz);
+#endif
+
+static bool IsPcm2WayDumpEnable() {
+ // P2W Log system property
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_P2W_DUMP_ON, property_value, "0"); //"0": default off
+ if (property_value[0] == '1') {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+Play2Way *Play2Way::mPlay2Way = NULL;
+Play2Way *Play2Way::GetInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+
+ if (mPlay2Way == NULL) {
+ mPlay2Way = new Play2Way();
+ }
+ ASSERT(mPlay2Way != NULL);
+ return mPlay2Way;
+}
+
+Play2Way::Play2Way() {
+ // Internal Output Buffer Initialization
+ memset((void *)&m_OutputBuf, 0, sizeof(m_OutputBuf));
+ m_OutputBuf.pBufBase = new char[AUDIO_OUTPUT_BUFFER_SIZE];
+ m_OutputBuf.bufLen = AUDIO_OUTPUT_BUFFER_SIZE;
+ m_OutputBuf.pRead = m_OutputBuf.pBufBase;
+ m_OutputBuf.pWrite = m_OutputBuf.pBufBase;
+
+ ASSERT(m_OutputBuf.pBufBase != NULL);
+ memset(m_OutputBuf.pBufBase, 0, m_OutputBuf.bufLen);
+
+ mPlay2WayStarted = false;
+ mIsPlay2WayDumpEnable = false;
+ pPlay2WayDumpFile = NULL;
+}
+
+Play2Way::~Play2Way() {
+ //if (pLad != NULL) pLad->pCCCI->Play2WayLock();
+
+ AL_LOCK(mPlay2WayLock);
+ if (m_OutputBuf.pBufBase != NULL) {
+ delete[] m_OutputBuf.pBufBase;
+ m_OutputBuf.pBufBase = NULL;
+ m_OutputBuf.bufLen = 0;
+ m_OutputBuf.pRead = NULL;
+ m_OutputBuf.pWrite = NULL;
+ }
+ AL_UNLOCK(mPlay2WayLock);
+
+ //if (pLad != NULL) pLad->pCCCI->Play2WayUnLock();
+}
+
+
+int Play2Way::Start() {
+ ALOGD("%s()", __FUNCTION__);
+
+ // Reset read and write pointer of Output buffer
+ AL_LOCK(mPlay2WayLock);
+
+ m_OutputBuf.bufLen = AUDIO_OUTPUT_BUFFER_SIZE;
+ m_OutputBuf.pRead = m_OutputBuf.pBufBase;
+ m_OutputBuf.pWrite = m_OutputBuf.pBufBase;
+ mPlay2WayStarted = true;
+
+ AL_UNLOCK(mPlay2WayLock);
+ mIsPlay2WayDumpEnable = IsPcm2WayDumpEnable();
+
+ if (mIsPlay2WayDumpEnable) {
+ char fileNamePlay2Way[kMaxSizeOfFileName];
+ memset((void *)fileNamePlay2Way, 0, kMaxSizeOfFileName);
+
+ time_t rawtime;
+ time(&rawtime);
+ struct tm *timeinfo = localtime(&rawtime);
+ audio_strncpy(fileNamePlay2Way, kFileNamePlay2Way, kMaxSizeOfFileName);
+ strftime(fileNamePlay2Way + kSizeOfPrefixFileNamePlay2Way, kMaxSizeOfFileName - kSizeOfPrefixFileNamePlay2Way - 1, "_%Y_%m_%d_%H%M%S.pcm", timeinfo);
+
+ if (pPlay2WayDumpFile == NULL) {
+ AudiocheckAndCreateDirectory(fileNamePlay2Way);
+ pPlay2WayDumpFile = fopen(fileNamePlay2Way, "wb");
+ }
+ if (pPlay2WayDumpFile == NULL) {
+ ALOGW("%s(), Fail to open %s", __FUNCTION__, fileNamePlay2Way);
+ } else {
+ ALOGD("%s(), open %s", __FUNCTION__, fileNamePlay2Way);
+ }
+ }
+ return true;
+}
+
+int Play2Way::Stop() {
+ ALOGD("%s()", __FUNCTION__);
+ AL_LOCK(mPlay2WayLock);
+
+ mPlay2WayStarted = false;
+
+ AL_UNLOCK(mPlay2WayLock);
+
+ if (pPlay2WayDumpFile != NULL) {
+ fclose(pPlay2WayDumpFile);
+ pPlay2WayDumpFile = NULL;
+ }
+ return true;
+}
+
+int Play2Way::Write(void *buffer, int size_bytes) {
+ ALOGD("+%s(), size_bytes=%d", __FUNCTION__, size_bytes);
+ if (mPlay2WayStarted == false) {
+ ALOGE("%s(), mPlay2WayStarted == false, return", __FUNCTION__);
+ return 0;
+ }
+
+ AL_LOCK(mPlay2WayLock);
+
+ int num_free_space = RingBuf_getFreeSpace(&m_OutputBuf);
+ if (size_bytes > num_free_space) {
+ ALOGE("%s(), size_bytes(%u) > num_free_space(%u), drop", __FUNCTION__, size_bytes, num_free_space);
+ AL_UNLOCK(mPlay2WayLock);
+ return 0;
+ }
+
+ RingBuf_copyFromLinear(&m_OutputBuf, (char *)buffer, size_bytes);
+
+ AL_UNLOCK(mPlay2WayLock);
+
+ return size_bytes;
+}
+
+/** get free space of internal buffer */
+int Play2Way::GetFreeBufferCount() {
+ int freeSpaceInpBuf = m_OutputBuf.bufLen - RingBuf_getDataCount(&m_OutputBuf) - 8;//left additional 1 byte for ringbuf read/write ptr
+ SLOGV("%s(), buf_cnt:%d, free_cnt:%d", __FUNCTION__, RingBuf_getDataCount(&m_OutputBuf), freeSpaceInpBuf);
+ return freeSpaceInpBuf;
+}
+
+
+uint16_t Play2Way::PutDataToSpeaker(char *target_ptr, uint16_t num_data_request) {
+ SLOGV("%s(), pcm_dataRequest=%d", __FUNCTION__, num_data_request);
+
+ AL_LOCK(mPlay2WayLock);
+
+#ifndef PLAY2WAY_USE_SINE_WAVE
+ // check the output buffer data count
+ int OutputBufDataCount = RingBuf_getDataCount(&m_OutputBuf);
+ SLOGV("%s(), OutputBufDataCount=%d", __FUNCTION__, OutputBufDataCount);
+
+ // if output buffer's data is not enough, fill it with zero to PCMdataToModemSize (ex: 320 bytes)
+ if (OutputBufDataCount < num_data_request) {
+ RingBuf_writeDataValue(&m_OutputBuf, 0, num_data_request - OutputBufDataCount);
+ ALOGW("%s(), underflow OutBufSize:%d", __FUNCTION__, OutputBufDataCount);
+ }
+
+ // fill downlink data to share buffer
+ RingBuf_copyToLinear(target_ptr, &m_OutputBuf, num_data_request);
+
+ SLOGV("OutputBuf B:0x%p, R:%d, W:%d, L:%d", m_OutputBuf.pBufBase, (int)(m_OutputBuf.pRead - m_OutputBuf.pBufBase), (int)(m_OutputBuf.pWrite - m_OutputBuf.pBufBase), m_OutputBuf.bufLen);
+#else
+ static uint32_t i4Count = 0;
+ uint32_t current_count = 0, remain_count = 0;
+ char *tmp_ptr = NULL;
+
+ remain_count = num_data_request;
+ tmp_ptr = target_ptr;
+
+ if (remain_count > (kSizeSinewaveTable - i4Count)) {
+ memcpy(tmp_ptr, table_1k_tone_8000_hz + (i4Count >> 1), kSizeSinewaveTable - i4Count);
+ tmp_ptr += (kSizeSinewaveTable - i4Count);
+ remain_count -= (kSizeSinewaveTable - i4Count);
+ i4Count = 0;
+ }
+ //while (remain_count > kSizeSinewaveTable)
+ if (remain_count > kSizeSinewaveTable) {
+ memcpy(tmp_ptr, table_1k_tone_8000_hz, kSizeSinewaveTable);
+ tmp_ptr += kSizeSinewaveTable;
+ remain_count -= kSizeSinewaveTable;
+ }
+ if (remain_count > 0) {
+ memcpy(tmp_ptr, table_1k_tone_8000_hz, remain_count);
+ i4Count = remain_count;
+ }
+#endif
+ if (mIsPlay2WayDumpEnable) {
+ if (pPlay2WayDumpFile != NULL) {
+ fwrite(target_ptr, sizeof(char), num_data_request, pPlay2WayDumpFile);
+ } else {
+ ALOGW("%s(), pPlay2WayDumpFile == NULL!!!!!", __FUNCTION__);
+ }
+ }
+ AL_UNLOCK(mPlay2WayLock);
+ return num_data_request;
+}
+
+
+/***********************************************************
+*
+* PCM2WAY Interface - Record2Way
+*
+***********************************************************/
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "Record2Way"
+
+Record2Way *Record2Way::mRecord2Way = NULL;
+
+Record2Way *Record2Way::GetInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+
+ if (mRecord2Way == NULL) {
+ mRecord2Way = new Record2Way();
+ }
+ return mRecord2Way;
+}
+
+Record2Way::Record2Way() {
+ // Internal Input Buffer Initialization
+ memset((void *)&m_InputBuf, 0, sizeof(RingBuf));
+ m_InputBuf.pBufBase = new char[AUDIO_INPUT_BUFFER_SIZE];
+ m_InputBuf.bufLen = AUDIO_INPUT_BUFFER_SIZE;
+ m_InputBuf.pRead = m_InputBuf.pBufBase;
+ m_InputBuf.pWrite = m_InputBuf.pBufBase;
+
+ ASSERT(m_InputBuf.pBufBase != NULL);
+ memset(m_InputBuf.pBufBase, 0, m_InputBuf.bufLen);
+
+ m_Rec2Way_Started = false;
+ mIsRecord2WayDumpEnable = false;
+ pRecord2WayDumpFile = NULL;
+}
+
+Record2Way::~Record2Way() {
+ //if (pLad != NULL) pLad->pCCCI->Record2WayLock();
+
+ AL_LOCK(mRec2WayLock);
+ if (m_InputBuf.pBufBase != NULL) {
+ delete []m_InputBuf.pBufBase;
+ m_InputBuf.pBufBase = NULL;
+ m_InputBuf.bufLen = 0;
+ m_InputBuf.pRead = NULL;
+ m_InputBuf.pWrite = NULL;
+ }
+ AL_UNLOCK(mRec2WayLock);
+
+ //if (pLad != NULL) pLad->pCCCI->Record2WayUnLock();
+}
+
+
+int Record2Way::Start() {
+ ALOGD("%s()", __FUNCTION__);
+ AL_LOCK(mRec2WayLock);
+ mIsRecord2WayDumpEnable = IsPcm2WayDumpEnable();
+
+ if (mIsRecord2WayDumpEnable) {
+ char fileNameRecord2Way[kMaxSizeOfFileName];
+ memset((void *)fileNameRecord2Way, 0, kMaxSizeOfFileName);
+
+ time_t rawtime;
+ time(&rawtime);
+ struct tm *timeinfo = localtime(&rawtime);
+ audio_strncpy(fileNameRecord2Way, kFileNameRecord2Way, kMaxSizeOfFileName);
+ strftime(fileNameRecord2Way + kSizeOfPrefixFileNameRecord2Way, kMaxSizeOfFileName - kSizeOfPrefixFileNameRecord2Way - 1, "_%Y_%m_%d_%H%M%S.pcm", timeinfo);
+ if (pRecord2WayDumpFile == NULL) {
+ AudiocheckAndCreateDirectory(fileNameRecord2Way);
+ pRecord2WayDumpFile = fopen(fileNameRecord2Way, "wb");
+ }
+ if (pRecord2WayDumpFile == NULL) {
+ ALOGW("%s(), Fail to open %s", __FUNCTION__, fileNameRecord2Way);
+ } else {
+ ALOGD("%s(), open %s", __FUNCTION__, fileNameRecord2Way);
+ }
+ }
+ m_Rec2Way_Started = true;
+
+ // Reset read and write pointer of Input buffer
+ m_InputBuf.bufLen = AUDIO_INPUT_BUFFER_SIZE;
+ m_InputBuf.pRead = m_InputBuf.pBufBase;
+ m_InputBuf.pWrite = m_InputBuf.pBufBase;
+
+ AL_UNLOCK(mRec2WayLock);
+ return true;
+}
+
+int Record2Way::Stop() {
+ ALOGD("%s()", __FUNCTION__);
+ AL_LOCK(mRec2WayLock);
+
+ m_Rec2Way_Started = false;
+
+ AL_UNLOCK(mRec2WayLock);
+
+ if (pRecord2WayDumpFile != NULL) {
+ fclose(pRecord2WayDumpFile);
+ pRecord2WayDumpFile = NULL;
+ }
+ return true;
+}
+
+#define READ_DATA_FROM_MODEM_FAIL_CNT 10
+
+int Record2Way::Read(void *buffer, int size_bytes) {
+ int ret = 0;
+ int InputBuf_dataCnt = 0;
+ int ReadDataAgain = 0;
+ int consume_byte = size_bytes;
+ char *buf = (char *)buffer;
+ ALOGD("+%s(), size_bytes=%d", __FUNCTION__, size_bytes);
+
+ if (m_Rec2Way_Started == false) {
+ ALOGD("Record2Way_Read, m_Rec2Way_Started=false");
+ return 0;
+ }
+
+ // if internal input buffer has enough data for this read, do it and return
+ AL_LOCK(mRec2WayLock);
+ InputBuf_dataCnt = RingBuf_getDataCount(&m_InputBuf);
+ if (InputBuf_dataCnt >= consume_byte) {
+ RingBuf_copyToLinear(buf, &m_InputBuf, consume_byte);
+ AL_UNLOCK(mRec2WayLock);
+ return consume_byte;
+ }
+ AL_UNLOCK(mRec2WayLock);
+
+
+ // if internal input buffer is not enough, keep on trying
+ while (ReadDataAgain++ < READ_DATA_FROM_MODEM_FAIL_CNT) {
+ if (ReadDataAgain > (READ_DATA_FROM_MODEM_FAIL_CNT - 1)) {
+ ALOGW("Record2Way_Read, fail, No data from modem: %d (%d)", ReadDataAgain, InputBuf_dataCnt);
+ }
+ // Interrupt period of pcm2way driver is 20ms.
+ // If wait too long time (150 ms),
+ // -- Modem side has problem, the no interrupt is issued.
+ // -- pcm2way driver is stop. So AP can't read the data from modem.
+
+ //wait some time then get data again from modem.
+ usleep(15 * 1000);
+ //Read data from modem again
+ AL_LOCK(mRec2WayLock);
+ InputBuf_dataCnt = RingBuf_getDataCount(&m_InputBuf);
+ if (InputBuf_dataCnt >= consume_byte) {
+ RingBuf_copyToLinear((char *)buf, &m_InputBuf, consume_byte);
+ AL_UNLOCK(mRec2WayLock);
+ return consume_byte;
+ }
+ AL_UNLOCK(mRec2WayLock);
+ }
+
+ ALOGD("Record2Way_Read, Modem fail");
+ return 0;
+}
+
+int Record2Way::GetBufferDataCount() {
+ AL_LOCK(mRec2WayLock);
+ int InputBuf_dataCnt = RingBuf_getDataCount(&m_InputBuf);
+ AL_UNLOCK(mRec2WayLock);
+
+ return InputBuf_dataCnt;
+}
+
+void Record2Way::GetDataFromMicrophone(RingBuf ul_ring_buf) {
+ size_t InpBuf_freeSpace = 0;
+ size_t ShareBuf_dataCnt = 0;
+
+ AL_LOCK(mRec2WayLock);
+
+ // get free space of internal input buffer
+ InpBuf_freeSpace = (size_t)RingBuf_getFreeSpace(&m_InputBuf);
+ SLOGV("%s(), input_Buf data_cnt:%d, freeSpace:%zu", __FUNCTION__, RingBuf_getDataCount(&m_InputBuf), InpBuf_freeSpace);
+
+ // get data count in share buffer
+ ShareBuf_dataCnt = (size_t) RingBuf_getDataCount(&ul_ring_buf);
+ SLOGV("%s(), share_Buf data_count:%zu", __FUNCTION__, ShareBuf_dataCnt);
+
+ if (mIsRecord2WayDumpEnable) {
+ char linear_buffer[ShareBuf_dataCnt];
+
+ char *pM2AShareBufEnd = ul_ring_buf.pBufBase + ul_ring_buf.bufLen;
+ if (ul_ring_buf.pRead + ShareBuf_dataCnt <= pM2AShareBufEnd) {
+ memcpy(linear_buffer, ul_ring_buf.pRead, ShareBuf_dataCnt);
+ } else {
+ uint32 r2e = pM2AShareBufEnd - ul_ring_buf.pRead;
+ memcpy(linear_buffer, ul_ring_buf.pRead, r2e);
+ memcpy((void *)(linear_buffer + r2e), ul_ring_buf.pBufBase, ShareBuf_dataCnt - r2e);
+ }
+ if (pRecord2WayDumpFile != NULL) {
+ fwrite(linear_buffer, sizeof(char), ShareBuf_dataCnt, pRecord2WayDumpFile);
+ } else {
+ ALOGW("%s(), pRecord2WayDumpFile == NULL!!!!!", __FUNCTION__);
+ }
+ }
+ // check the data count in share buffer
+ if (ShareBuf_dataCnt > 320) {
+ SLOGV("%s(), ul_ring_buf size(%zu) > 320", __FUNCTION__, ShareBuf_dataCnt);
+ }
+
+ // check free space for internal input buffer
+ if (ShareBuf_dataCnt > InpBuf_freeSpace) {
+ SLOGV("%s(), uplink buffer full", __FUNCTION__);
+ AL_UNLOCK(mRec2WayLock);
+ return;
+ }
+
+ // copy data from modem share buffer to internal input buffer
+ RingBuf_copyEmpty(&m_InputBuf, &ul_ring_buf);
+
+ SLOGV("%s(), InputBuf B:0x%p, R:%d, W:%d, L:%u", __FUNCTION__, m_InputBuf.pBufBase, (int)(m_InputBuf.pRead - m_InputBuf.pBufBase), (int)(m_InputBuf.pWrite - m_InputBuf.pBufBase), m_InputBuf.bufLen);
+ SLOGV("%s(), M2A_ShareBuf B:0x%p, R:%d, W:%d, L:%d", __FUNCTION__, ul_ring_buf.pBufBase, (int)(ul_ring_buf.pRead - ul_ring_buf.pBufBase), (int)(ul_ring_buf.pWrite - ul_ring_buf.pBufBase), ul_ring_buf.bufLen);
+
+ AL_UNLOCK(mRec2WayLock);
+}
+
+} // end of namespace android
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechShareMemBase.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechShareMemBase.cpp
new file mode 100644
index 0000000..0586e7c
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechShareMemBase.cpp
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechShareMemBase"
+#include <SpeechShareMemBase.h>
+#include <utils/Log.h>
+#include <AudioLock.h>
+#include <AudioAssert.h>//Mutex/assert
+#if defined(MTK_SPEECH_USIP_EMI_SUPPORT)
+#include <SpeechShareMemGen95.h>
+#else
+#include <SpeechShareMemGen93.h>
+#endif
+
+
+namespace android {
+
+/*
+ * =============================================================================
+ * Singleton Pattern
+ * =============================================================================
+ */
+
+SpeechShareMemBase *SpeechShareMemBase::createInstance() {
+#if defined(MTK_SPEECH_USIP_EMI_SUPPORT)
+ SpeechShareMemBase *speechShareMem = new SpeechShareMemGen95();
+#else
+ SpeechShareMemBase *speechShareMem = new SpeechShareMemGen93();
+#endif
+ ASSERT(speechShareMem != NULL);
+ return speechShareMem;
+}
+
+SpeechShareMemBase *SpeechShareMemBase::destroyInstance(SpeechShareMemBase *speechShareMem) {
+ if (speechShareMem != NULL) {
+ delete speechShareMem;
+ }
+ return 0;
+}
+
+SpeechShareMemBase::SpeechShareMemBase() {
+ mModemIndex = MODEM_1;
+ mCcciShareMemoryHandler = 0;
+ mShareMemoryBase = NULL;
+ mShareMemoryLength = 0;
+}
+
+
+} // end namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechShareMemGen93.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechShareMemGen93.cpp
new file mode 100644
index 0000000..7db7efd
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechShareMemGen93.cpp
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechShareMemGen93"
+#include <SpeechShareMemGen93.h>
+#include <SpeechExtMemCCCI.h>
+#include <utils/Log.h>
+#include <AudioLock.h>
+#include <AudioAssert.h>//Mutex/assert
+
+
+namespace android {
+
+/*
+ * =============================================================================
+ * class implementation
+ * =============================================================================
+ */
+SpeechShareMemGen93::SpeechShareMemGen93() {
+ mSpeechExtMemCCCI = new SpeechExtMemCCCI();
+ if (mSpeechExtMemCCCI == NULL) {
+ ALOGE("%s(), mSpeechExtMemCCCI == NULL!!", __FUNCTION__);
+ }
+}
+
+SpeechShareMemGen93::~SpeechShareMemGen93() {
+ if (mSpeechExtMemCCCI != NULL) {
+ delete mSpeechExtMemCCCI;
+ }
+}
+
+int SpeechShareMemGen93::resetShareMemoryIndex() {
+ return mSpeechExtMemCCCI->resetShareMemoryIndex();
+}
+
+int SpeechShareMemGen93::writeSphParamToShareMemory(const void *p_sph_param,
+ uint32_t sph_param_length,
+ uint32_t *p_write_idx) {
+ return mSpeechExtMemCCCI->writeSphParamToShareMemory(p_sph_param,
+ sph_param_length,
+ p_write_idx);
+}
+
+int SpeechShareMemGen93::writeApDataToShareMemory(const void *data_buf,
+ uint16_t data_type,
+ uint16_t data_size,
+ uint16_t *p_payload_length,
+ uint32_t *p_write_idx) {
+ return mSpeechExtMemCCCI->writeApDataToShareMemory(data_buf,
+ data_type,
+ data_size,
+ p_payload_length,
+ p_write_idx);
+}
+
+int SpeechShareMemGen93::readMdDataFromShareMemory(void *p_data_buf,
+ uint16_t *p_data_type,
+ uint16_t *p_data_size,
+ uint16_t payload_length,
+ uint32_t read_idx) {
+ return mSpeechExtMemCCCI->readMdDataFromShareMemory(p_data_buf,
+ p_data_type,
+ p_data_size,
+ payload_length,
+ read_idx);
+}
+
+int SpeechShareMemGen93::openShareMemory(const modem_index_t modem_index) {
+ mModemIndex = modem_index;
+ return mSpeechExtMemCCCI->openShareMemory(mModemIndex);
+}
+
+int SpeechShareMemGen93::closeShareMemory() {
+ return mSpeechExtMemCCCI->closeShareMemory();
+}
+
+int SpeechShareMemGen93::formatShareMemory() {
+ return mSpeechExtMemCCCI->formatShareMemory();
+}
+
+int SpeechShareMemGen93::getShareMemoryType() {
+ return SPH_PARAM_VIA_SHM_CCCI;
+}
+
+bool SpeechShareMemGen93::checkModemAlive() {
+ return mSpeechExtMemCCCI->checkModemAlive();
+}
+
+} // end namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechShareMemGen95.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechShareMemGen95.cpp
new file mode 100644
index 0000000..942c8b6
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechShareMemGen95.cpp
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechShareMemGen95"
+#include <SpeechShareMemGen95.h>
+#include <SpeechExtMemCCCI.h>
+#include <SpeechExtMemUSIP.h>
+#include <utils/Log.h>
+#include <AudioLock.h>
+#include <AudioAssert.h>//Mutex/assert
+
+
+namespace android {
+
+/*
+ * =============================================================================
+ * class implementation
+ * =============================================================================
+ */
+SpeechShareMemGen95::SpeechShareMemGen95() {
+ ALOGD("%s()", __FUNCTION__);
+ mSpeechExtMemCCCI = new SpeechExtMemCCCI();
+ if (mSpeechExtMemCCCI == NULL) {
+ ALOGE("%s(), mSpeechExtMemCCCI == NULL!!", __FUNCTION__);
+ }
+#ifndef MTK_AUDIO_BYPASS_USIP
+ mSpeechExtMemUSIP = new SpeechExtMemUSIP();
+ if (mSpeechExtMemUSIP == NULL) {
+ ALOGE("%s(), mSpeechExtMemUSIP == NULL!!", __FUNCTION__);
+ }
+#endif
+}
+
+SpeechShareMemGen95::~SpeechShareMemGen95() {
+ if (mSpeechExtMemCCCI != NULL) {
+ delete mSpeechExtMemCCCI;
+ mSpeechExtMemCCCI = NULL;
+ }
+ if (mSpeechExtMemUSIP != NULL) {
+ delete mSpeechExtMemUSIP;
+ mSpeechExtMemUSIP = NULL;
+ }
+}
+
+int SpeechShareMemGen95::resetShareMemoryIndex() {
+ int retval = 0;
+ retval = mSpeechExtMemCCCI->resetShareMemoryIndex();
+ if (retval < 0) {
+ ALOGE("%s(), open CCCI Fail.", __FUNCTION__);
+ return retval;
+ }
+#ifndef MTK_AUDIO_BYPASS_USIP
+ retval = mSpeechExtMemUSIP->resetShareMemoryIndex();
+ if (retval < 0) {
+ ALOGE("%s(), open USIP Fail.", __FUNCTION__);
+ }
+#endif
+ return retval;
+}
+
+int SpeechShareMemGen95::writeSphParamToShareMemory(const void *p_sph_param,
+ uint32_t sph_param_length,
+ uint32_t *p_write_idx) {
+#ifndef MTK_AUDIO_BYPASS_USIP
+ int retval = 0;
+ ALOGV("%s()", __FUNCTION__);
+ retval = mSpeechExtMemUSIP->writeSphParamToShareMemory(p_sph_param,
+ sph_param_length,
+ p_write_idx);
+ return retval;
+#else
+ return false;
+#endif
+
+}
+
+int SpeechShareMemGen95::writeApDataToShareMemory(const void *data_buf,
+ uint16_t data_type,
+ uint16_t data_size,
+ uint16_t *p_payload_length,
+ uint32_t *p_write_idx) {
+ int retval = 0;
+ retval = mSpeechExtMemCCCI->writeApDataToShareMemory(data_buf,
+ data_type,
+ data_size,
+ p_payload_length,
+ p_write_idx);
+ return retval;
+}
+
+int SpeechShareMemGen95::readMdDataFromShareMemory(void *p_data_buf,
+ uint16_t *p_data_type,
+ uint16_t *p_data_size,
+ uint16_t payload_length,
+ uint32_t read_idx) {
+ int retval = 0;
+ retval = mSpeechExtMemCCCI->readMdDataFromShareMemory(p_data_buf,
+ p_data_type,
+ p_data_size,
+ payload_length,
+ read_idx);
+ return retval;
+}
+
+int SpeechShareMemGen95::openShareMemory(const modem_index_t modem_index) {
+ int retval = 0;
+ mModemIndex = modem_index;
+ retval = mSpeechExtMemCCCI->openShareMemory(mModemIndex);
+ if (retval < 0) {
+ ALOGE("%s(), open CCCI Fail.", __FUNCTION__);
+ return retval;
+ }
+#ifndef MTK_AUDIO_BYPASS_USIP
+ retval = mSpeechExtMemUSIP->openShareMemory(mModemIndex);
+ if (retval < 0) {
+ ALOGE("%s(), open USIP Fail.", __FUNCTION__);
+ }
+#endif
+ return retval;
+}
+
+int SpeechShareMemGen95::closeShareMemory() {
+ int retval = 0;
+ retval = mSpeechExtMemCCCI->closeShareMemory();
+ if (retval < 0) {
+ ALOGE("%s(), open CCCI Fail.", __FUNCTION__);
+ return retval;
+ }
+#ifndef MTK_AUDIO_BYPASS_USIP
+ retval = mSpeechExtMemUSIP->closeShareMemory();
+ if (retval < 0) {
+ ALOGE("%s(), open USIP Fail.", __FUNCTION__);
+ }
+#endif
+ return retval;
+
+}
+
+int SpeechShareMemGen95::formatShareMemory() {
+ int retval = 0;
+ retval = mSpeechExtMemCCCI->formatShareMemory();
+ if (retval < 0) {
+ ALOGE("%s(), open CCCI Fail.", __FUNCTION__);
+ return retval;
+ }
+#ifndef MTK_AUDIO_BYPASS_USIP
+ retval = mSpeechExtMemUSIP->formatShareMemory();
+ if (retval < 0) {
+ ALOGE("%s(), open USIP Fail.", __FUNCTION__);
+ }
+#endif
+ return retval;
+}
+
+bool SpeechShareMemGen95::checkModemAlive() {
+ bool isAlive = 0;
+ isAlive = mSpeechExtMemCCCI->checkModemAlive();
+ return isAlive;
+}
+
+int SpeechShareMemGen95::getShareMemoryType() {
+ return SPH_PARAM_VIA_SHM_USIP;
+}
+
+
+} // end namespace android
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechUtility.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechUtility.cpp
new file mode 100644
index 0000000..5640699
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechUtility.cpp
@@ -0,0 +1,569 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <SpeechUtility.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string.h>
+#include <stdarg.h> /* va_list, va_start, va_arg, va_end */
+
+#include <cutils/properties.h>
+
+#include <audio_log.h>
+#include <audio_time.h>
+
+#include <AudioALSADriverUtility.h>
+#include <AudioLock.h>
+
+#include <sys/mman.h>
+#include <fcntl.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SpeechUtility"
+
+namespace android {
+
+typedef struct {
+ char const *kPropertyKey;
+ char const *kMixctrlKey;
+
+} mixctrl_table;
+
+const mixctrl_table prop_mix_table[] = {
+ {"vendor.audiohal.modem_1.epof", "Speech_MD_EPOF"},
+ {"vendor.audiohal.modem_1.status", "Speech_MD_Status"},
+ {"vendor.audiohal.wait.ack.msgid", "Speech_A2M_Msg_ID"},
+ {"vendor.audiohal.recovery.mic_mute_on", "Speech_Mic_Mute"},
+ {"vendor.audiohal.recovery.dl_mute_on", "Speech_DL_Mute"},
+ {"vendor.audiohal.recovery.ul_mute_on", "Speech_UL_Mute"},
+ {"vendor.audiohal.recovery.phone1.md", "Speech_Phone1_MD_Idx"},
+ {"vendor.audiohal.recovery.phone2.md", "Speech_Phone2_MD_Idx"},
+ {"vendor.audiohal.recovery.phone_id", "Speech_Phone_ID"},
+ {"vendor.streamout.btscowb", "Speech_BT_SCO_WB"},
+ {"vendor.audiohal.speech.shm_init", "Speech_SHM_Init"},
+ {"vendor.audiohal.speech.shm_usip", "Speech_SHM_USIP"},
+ {"vendor.audiohal.speech.shm_widx", "Speech_SHM_Widx"}
+};
+
+#ifndef NUM_MIXCTRL_KEY
+#define NUM_MIXCTRL_KEY (sizeof(prop_mix_table) / sizeof(prop_mix_table[0]))
+#endif
+
+/* dynamic enable log */
+static const char *kPropertyKeySpeechLogMask = "vendor.audiohal.speech.log.mask";
+
+
+void sph_memcpy(void *des, const void *src, uint32_t size) {
+
+ char *p_src = (char *)src;
+ char *p_des = (char *)des;
+ uint32_t i = 0;
+
+ for (i = 0; i < size; i++) {
+ p_des[i] = p_src[i];
+ asm("" ::: "memory");
+ }
+ asm volatile("dsb ish": : : "memory");
+}
+
+
+void sph_memset(void *dest, uint8_t value, uint32_t size) {
+
+ char *p_des = (char *)dest;
+ uint32_t i = 0;
+
+ for (i = 0; i < size; i++) {
+ p_des[i] = value;
+ asm("" ::: "memory");
+ }
+ asm volatile("dsb ish": : : "memory");
+}
+
+uint32_t get_uint32_from_mixctrl(const char *property_name) {
+
+ static AudioLock mixctrlLock;
+ AL_AUTOLOCK(mixctrlLock);
+
+ uint32_t value;
+ char mixctrl_name[PROPERTY_KEY_MAX];
+ uint32_t idx = 0;
+
+ static struct mixer *mMixer = AudioALSADriverUtility::getInstance()->getMixer();
+ if (mMixer == NULL) {
+ return get_uint32_from_property(property_name);
+ }
+
+ for (idx = 0; idx < NUM_MIXCTRL_KEY; ++idx) {
+ if (strcmp(prop_mix_table[idx].kPropertyKey, property_name) == 0) {
+ strncpy(mixctrl_name, prop_mix_table[idx].kMixctrlKey, PROPERTY_KEY_MAX - 1);
+ break;
+ }
+ }
+ if (idx == NUM_MIXCTRL_KEY) {
+ ALOGE("%s(), Invalid property name:%s", __FUNCTION__, property_name);
+ return -EINVAL;
+ }
+
+ struct mixer_ctl *ctl = AudioALSADriverUtility::getInstance()->getMixerCtrlByName(mMixer, mixctrl_name);
+ if (ctl == NULL) {
+ value = get_uint32_from_property(property_name);
+ } else {
+ value = AudioALSADriverUtility::getInstance()->mixerCtrlGetValue(ctl, 0);
+ }
+ ALOGV("%s(), property:%s, mixctrl:%s, value:0x%x", __FUNCTION__, property_name, mixctrl_name, value);
+ return value;
+}
+
+void set_uint32_to_mixctrl(const char *property_name, const uint32_t value) {
+
+ static AudioLock mixctrlLock;
+ AL_AUTOLOCK(mixctrlLock);
+
+ char mixctrl_name[PROPERTY_KEY_MAX];
+ uint32_t idx = 0;
+
+ static struct mixer *mMixer = AudioALSADriverUtility::getInstance()->getMixer();
+ if (mMixer == NULL) {
+ set_uint32_to_property(property_name, value);
+ return;
+ }
+
+ for (idx = 0; idx < NUM_MIXCTRL_KEY; ++idx) {
+ if (strcmp(prop_mix_table[idx].kPropertyKey, property_name) == 0) {
+ strncpy(mixctrl_name, prop_mix_table[idx].kMixctrlKey, PROPERTY_KEY_MAX - 1);
+ break;
+ }
+ }
+ if (idx == NUM_MIXCTRL_KEY) {
+ ALOGE("%s(), Invalid property name:%s", __FUNCTION__, property_name);
+ return;
+ }
+
+ struct mixer_ctl *ctl = AudioALSADriverUtility::getInstance()->getMixerCtrlByName(mMixer, mixctrl_name);
+ if (ctl == NULL) {
+ set_uint32_to_property(property_name, value);
+ } else {
+ if (AudioALSADriverUtility::getInstance()->mixerCtrlSetValue(ctl, 0, value)) {
+ ALOGE("%s() , Error: %s %d", __FUNCTION__, mixctrl_name, value);
+ }
+ }
+ ALOGV("%s(), property:%s, mixctrl:%s, value:0x%x", __FUNCTION__, property_name, mixctrl_name, value);
+ return;
+}
+
+uint32_t get_uint32_from_property(const char *property_name) {
+ uint32_t retval = 0;
+ char property_value[PROPERTY_VALUE_MAX] = {0};
+ struct timespec ts_start;
+ struct timespec ts_stop;
+ uint64_t time_diff_msg = 0;
+
+ audio_get_timespec_monotonic(&ts_start);
+ property_get_tmp(property_name, property_value, "0"); // default 0
+ audio_get_timespec_monotonic(&ts_stop);
+
+ time_diff_msg = get_time_diff_ms(&ts_start, &ts_stop);
+ if ((time_diff_msg) >= 300) {
+ ALOGE("%s(), property_name: %s, get %ju ms is too long",
+ __FUNCTION__, property_name, time_diff_msg);
+ }
+ int ret = sscanf(property_value, "%u", &retval);
+ if (ret != 1) {
+ ALOGE("%s(), sscanf fail! ret:%d", __FUNCTION__, ret);
+ }
+ return retval;
+}
+
+void set_uint32_to_property(const char *property_name, const uint32_t value) {
+ if (!property_name) {
+ return;
+ }
+ char property_value[PROPERTY_VALUE_MAX] = {0};
+ snprintf(property_value, sizeof(property_value), "%u", value);
+
+ struct timespec ts_start;
+ struct timespec ts_stop;
+ uint64_t time_diff_msg = 0;
+
+ audio_get_timespec_monotonic(&ts_start);
+ property_set_tmp(property_name, property_value);
+ audio_get_timespec_monotonic(&ts_stop);
+
+ time_diff_msg = get_time_diff_ms(&ts_start, &ts_stop);
+ if ((time_diff_msg) >= 300) {
+ ALOGE("%s(), property_name: %s, set %ju ms is too long",
+ __FUNCTION__, property_name, time_diff_msg);
+ }
+}
+
+uint32_t get_uint32_from_uci(const char *property_name) {
+ uint32_t retval = 0;
+ char property_value[PROPERTY_VALUE_MAX] = {0};
+ struct timespec ts_start;
+ struct timespec ts_stop;
+ uint64_t time_diff_msg = 0;
+
+ audio_get_timespec_monotonic(&ts_start);
+ property_get(property_name, property_value, "0"); // default 0
+ audio_get_timespec_monotonic(&ts_stop);
+
+ time_diff_msg = get_time_diff_ms(&ts_start, &ts_stop);
+ if ((time_diff_msg) >= 300) {
+ ALOGE("%s(), property_name: %s, get %ju ms is too long",
+ __FUNCTION__, property_name, time_diff_msg);
+ }
+ int ret = sscanf(property_value, "%u", &retval);
+ if (ret != 1) {
+ ALOGE("%s(), sscanf fail! ret:%d", __FUNCTION__, ret);
+ }
+ return retval;
+}
+
+void set_uint32_to_uci(const char *property_name, const uint32_t value) {
+ if (!property_name) {
+ return;
+ }
+ char property_value[PROPERTY_VALUE_MAX] = {0};
+ snprintf(property_value, sizeof(property_value), "%u", value);
+
+ struct timespec ts_start;
+ struct timespec ts_stop;
+ uint64_t time_diff_msg = 0;
+
+ audio_get_timespec_monotonic(&ts_start);
+ property_set(property_name, property_value);
+ audio_get_timespec_monotonic(&ts_stop);
+
+ time_diff_msg = get_time_diff_ms(&ts_start, &ts_stop);
+ if ((time_diff_msg) >= 300) {
+ ALOGE("%s(), property_name: %s, set %ju ms is too long",
+ __FUNCTION__, property_name, time_diff_msg);
+ }
+}
+
+void get_string_from_property(const char *property_name, char *string, const uint32_t string_size) {
+ if (!property_name || !string || !string_size) {
+ return;
+ }
+
+ char property_string[PROPERTY_VALUE_MAX] = {0};
+ struct timespec ts_start;
+ struct timespec ts_stop;
+ uint64_t time_diff_msg = 0;
+
+ audio_get_timespec_monotonic(&ts_start);
+ property_get(property_name, property_string, ""); // default none
+ audio_get_timespec_monotonic(&ts_stop);
+
+ time_diff_msg = get_time_diff_ms(&ts_start, &ts_stop);
+ if ((time_diff_msg) >= 300) {
+ ALOGE("%s(), property_name: %s, get %ju ms is too long",
+ __FUNCTION__, property_name, time_diff_msg);
+ }
+ strncpy(string, property_string, string_size - 1);
+}
+
+
+void set_string_to_property(const char *property_name, const char *string) {
+ char property_string[PROPERTY_VALUE_MAX] = {0};
+ strncpy(property_string, string, sizeof(property_string) - 1);
+
+ struct timespec ts_start;
+ struct timespec ts_stop;
+ uint64_t time_diff_msg = 0;
+
+ audio_get_timespec_monotonic(&ts_start);
+ property_set(property_name, property_string);
+ audio_get_timespec_monotonic(&ts_stop);
+
+ time_diff_msg = get_time_diff_ms(&ts_start, &ts_stop);
+ if ((time_diff_msg) >= 300) {
+ ALOGE("%s(), property_name:%s, set %ju ms is too long",
+ __FUNCTION__, property_name, time_diff_msg);
+ }
+}
+
+
+uint16_t sph_sample_rate_enum_to_value(const sph_sample_rate_t sample_rate_enum) {
+ uint16_t sample_rate_value = 32000;
+
+ switch (sample_rate_enum) {
+ case SPH_SAMPLE_RATE_08K:
+ sample_rate_value = 8000;
+ break;
+ case SPH_SAMPLE_RATE_16K:
+ sample_rate_value = 16000;
+ break;
+ case SPH_SAMPLE_RATE_32K:
+ sample_rate_value = 32000;
+ break;
+ case SPH_SAMPLE_RATE_48K:
+ sample_rate_value = 48000;
+ break;
+ default:
+ ALOGW("%s(), sample_rate_enum %d not support!! use 32000 instead",
+ __FUNCTION__, sample_rate_enum);
+ sample_rate_value = 32000;
+ }
+
+ return sample_rate_value;
+}
+
+
+sph_sample_rate_t sph_sample_rate_value_to_enum(const uint16_t sample_rate_value) {
+ sph_sample_rate_t sample_rate_enum = SPH_SAMPLE_RATE_32K;
+
+ switch (sample_rate_value) {
+ case 8000:
+ sample_rate_enum = SPH_SAMPLE_RATE_08K;
+ break;
+ case 16000:
+ sample_rate_enum = SPH_SAMPLE_RATE_16K;
+ break;
+ case 32000:
+ sample_rate_enum = SPH_SAMPLE_RATE_32K;
+ break;
+ case 48000:
+ sample_rate_enum = SPH_SAMPLE_RATE_48K;
+ break;
+ default:
+ ALOGW("%s(), sample_rate_value %d not support!! use 32000 instead",
+ __FUNCTION__, sample_rate_value);
+ sample_rate_enum = SPH_SAMPLE_RATE_32K;
+ }
+
+ return sample_rate_enum;
+}
+
+
+void dynamic_speech_log(uint32_t sph_log_level_mask, const char *file_path, const char *message, ...) {
+ if (!file_path || !message) {
+ return;
+ }
+
+ if ((sph_log_level_mask & get_uint32_from_uci(kPropertyKeySpeechLogMask)) == 0) {
+ return;
+ }
+
+ char printf_msg[256];
+ const char *slash = strrchr(file_path, '/');
+ const char *file_name = (slash) ? slash + 1 : file_path;
+
+ va_list args;
+ va_start(args, message);
+ vsnprintf(printf_msg, sizeof(printf_msg), message, args);
+ ALOGD("[%s] %s", file_name, printf_msg);
+ va_end(args);
+}
+
+// CCCI control
+/*============================================================================*/
+
+int speech_ccci_smem_put(int fd, unsigned char *address, unsigned int length) {
+ if (fd < 0) {
+ return -EINVAL;
+ }
+ close(fd);
+ ALOGD("munmap on (%d) for addr=%p, len=%d\n", fd, address, length);
+ return munmap(address, length);
+}
+
+int speech_ccci_smem_get(unsigned char **address, unsigned int *length) {
+ char dev_port[32];
+ int fd, ret;
+ unsigned int addr = 0, len = 0;
+ snprintf(dev_port, 32, "%s", CCCI_DEV_NODE_SMEM);
+ fd = open(dev_port, O_RDWR);
+ if (fd < 0) {
+ ALOGE("open %s failed, errno=%d", dev_port, errno);
+ return -ENODEV;
+ }
+ ret = ioctl(fd, CCCI_IOC_SMEM_BASE, &addr);
+ if (ret) {
+ ALOGE("CCCI_IOC_SMEM_BASE fail on %s, err=%d\n", dev_port, errno);
+ close(fd);
+ fd = -1;
+ return ret;
+ }
+ ret = ioctl(fd, CCCI_IOC_SMEM_LEN, &len);
+ if (ret) {
+ ALOGE("CCCI_IOC_SMEM_LEN fail on %s, err=%d\n", dev_port, errno);
+ close(fd);
+ fd = -1;
+ return ret;
+ }
+ ALOGD("mmap on %s(%d) for addr=0x%x, len=%d\n", dev_port, fd, addr, len);
+ *address = (unsigned char *)mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ *length = len;
+ if (*address == MAP_FAILED) {
+ ALOGE("mmap on %s failed, %d\n", dev_port, errno);
+ close(fd);
+ fd = -1;
+ return -EFAULT;
+ }
+ return fd;
+}
+
+
+#define SPEECH_CONFIG_FILE "/tmp/ap_speech/speech.config"
+#define SPEECH_CONFIG_FILE_TMP "/tmp/ap_speech/speech.config.tmp"
+
+typedef struct speech_property {
+ char name[PROPERTY_KEY_MAX];
+ char value[PROPERTY_VALUE_MAX];
+} speech_property;
+
+speech_property prop_speech_cache[30];
+
+#define NUM_SPEECH_PROP (sizeof(prop_speech_cache) / sizeof(prop_speech_cache[0]))
+
+int property_set_tmp(const char *key, const char *new_value) {
+ FILE *mFile = NULL;
+ FILE *mFileNew = NULL;
+ char buffer[PROPERTY_FULL_MAX] = {0};
+ const char * const delimiter = "=";
+ char *substr = NULL;
+ char *dest = NULL;
+ char *orig = NULL;
+ bool is_found = false;
+ int32_t i = 0;
+
+ if (key == NULL || new_value == NULL) {
+ ALOGE("NULL key or value");
+ return 0;
+ }
+ //Set to cache.
+ ALOGD("property_set_tmp key:%s, value:%s", key, new_value);
+ for (i = 0; i < NUM_SPEECH_PROP; i++) {
+ if (strlen(prop_speech_cache[i].name) <= 0) {
+ break;
+ }
+ if (strcmp(key, prop_speech_cache[i].name) == 0) {
+ memset(prop_speech_cache[i].value, 0, sizeof(prop_speech_cache[i].value));
+ strncpy(prop_speech_cache[i].value, new_value, strlen(new_value));
+ prop_speech_cache[i].value[strlen(new_value)] = '\0';
+ is_found = true;
+ break;
+ }
+ }
+ if (!is_found && i < NUM_SPEECH_PROP) {
+ memset(prop_speech_cache[i].name, 0, sizeof(prop_speech_cache[i].name));
+ memset(prop_speech_cache[i].value, 0, sizeof(prop_speech_cache[i].value));
+ strncpy(prop_speech_cache[i].name, key, strlen(key));
+ prop_speech_cache[i].name[strlen(key)] = '\0';
+ strncpy(prop_speech_cache[i].value, new_value, strlen(new_value));
+ prop_speech_cache[i].value[strlen(new_value)] = '\0';
+ ALOGD("add new key cache: %s, value: %s", prop_speech_cache[i].name, prop_speech_cache[i].value);
+ }
+ // Set to tmp/ file.
+ if (is_found) {
+ mFile = fopen(SPEECH_CONFIG_FILE, "r");
+ if (!mFile) {
+ ALOGE("Can not open speech.config errno=%d", errno);
+ return 0;
+ }
+ mFileNew = fopen(SPEECH_CONFIG_FILE_TMP, "w");
+ if (!mFileNew) {
+ ALOGE("Can not open speech.config.tmp errno=%d", errno);
+ fclose(mFile);
+ return 0;
+ }
+ while(fgets(buffer, PROPERTY_FULL_MAX, mFile) != NULL) {
+ asprintf(&orig, "%s", buffer);
+ substr = strtok(buffer, delimiter);
+ if (strcmp(substr, key) == 0) {
+ fprintf(mFileNew, "%s=%s\n", key, new_value);
+ } else {
+ fprintf(mFileNew, "%s", orig);
+ }
+ memset(buffer, 0, sizeof(char) * PROPERTY_FULL_MAX);
+ free(orig);
+ }
+ fclose(mFile);
+ fclose(mFileNew);
+ remove(SPEECH_CONFIG_FILE);
+ rename(SPEECH_CONFIG_FILE_TMP, SPEECH_CONFIG_FILE);
+ } else {
+ ALOGD("append to EOF.");
+ mFile = fopen(SPEECH_CONFIG_FILE, "a");
+ if (!mFile) {
+ ALOGE("Can not open speech.config errno=%d", errno);
+ return 0;
+ }
+ fprintf(mFile, "%s=%s\n", key, new_value);
+ fclose(mFile);
+ }
+ return 1;
+}
+
+int property_reload_tmp() {
+ FILE *mFile = NULL;
+ char buffer[PROPERTY_FULL_MAX] = {0};
+ const char * const delimiter = "=";
+ char *substr = NULL;
+ char *substr2 = NULL;
+ int32_t i = 0;
+
+ mFile = fopen(SPEECH_CONFIG_FILE, "r");
+
+ if (!mFile) {
+ ALOGE("Can not open speech.config errno=%d", errno);
+ return 0;
+ }
+ ALOGD("property_reload_tmp start");
+ while(fgets(buffer, PROPERTY_FULL_MAX, mFile) != NULL) {
+ if (i >= NUM_SPEECH_PROP) {
+ ALOGE("Out of prop cache size %d", NUM_SPEECH_PROP);
+ break;
+ }
+ substr = strtok(buffer, delimiter);
+ substr2 = strtok(NULL, delimiter);
+ memset(prop_speech_cache[i].name, 0, sizeof(prop_speech_cache[i].name));
+ memset(prop_speech_cache[i].value, 0, sizeof(prop_speech_cache[i].value));
+ strncpy(prop_speech_cache[i].name, substr, strlen(substr));
+ prop_speech_cache[i].name[strlen(substr)] = '\0';
+ strncpy(prop_speech_cache[i].value, substr2, strlen(substr2));
+ prop_speech_cache[i].value[strlen(substr2)] = '\0';
+ memset(buffer, 0, sizeof(char) * PROPERTY_FULL_MAX);
+ i++;
+ }
+ fclose(mFile);
+ return 1;
+}
+
+int property_get_tmp(const char *key, char *value, const char *default_value) {
+ int retValue = 0;
+ bool is_found = false;
+
+ if (NULL == key || NULL == value) {
+ ALOGE("NULL key or value");
+ return retValue;
+ }
+
+ for (int i = 0; i < NUM_SPEECH_PROP; i++) {
+ if (strcmp(key, prop_speech_cache[i].name) == 0) {
+ strncpy(value, prop_speech_cache[i].value, strlen(prop_speech_cache[i].value));
+ value[strlen(prop_speech_cache[i].value)] = '\0';
+ is_found = true;
+ }
+ }
+ if (!is_found) {
+ if (default_value) {
+ int len = strlen(default_value);
+ memcpy(value, default_value, len);
+ value[len] = '\0';
+ ALOGD("property_get_tmp default: %s, value: %s, len:%d", key, value, strlen(value));
+ }
+ }
+ retValue = 1;
+ ALOGD("property_get_tmp key: %s, value: %s", key, value);
+ return retValue;
+}
+
+void reload_property() {
+ property_reload_tmp();
+}
+
+} /* end namespace android */
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechVoiceMixer.cpp b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechVoiceMixer.cpp
new file mode 100644
index 0000000..7107f08
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/speech_driver/SpeechVoiceMixer.cpp
@@ -0,0 +1,606 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "VoiceMixerPlayer"
+#include "SpeechVoiceMixer.h"
+#include <sys/time.h>
+#include <utils/threads.h>
+#include <audio_utils/primitives.h>
+#include "SpeechDriverInterface.h"
+#include <SpeechUtility.h>
+
+#ifndef VOICEMIXER_msleep
+#define VOICEMIXER_msleep(ms) usleep((ms)*1000)
+#endif
+#define VOICEMIXER_RETRY_TIMES 5
+//Maximum Latency between two modem data request: 200ms
+//AP sould fill data to buffer in 60ms while receiving request
+
+
+namespace android {
+/*
+ * =============================================================================
+ * Property keys
+ * =============================================================================
+ */
+// property name exceed original max length PROPERTY_KEY_MAX in system/core/include/cutils/Properties.h
+// use pointer instead
+const char *PROPERTY_KEY_VOICEMIXER_DUMP_ON = "persist.vendor.audiohal.voicemixer_dump_on";
+const char *PROPERTY_KEY_VOICEMIXER_BLISRC_DUMP_ON = "persist.vendor.audiohal.voicemixer_blisrc_dump_on";
+const char *PROPERTY_KEY_VOICEMIXER_LOG_LEVEL = "persist.vendor.audiohal.speech.voicemixer.log";
+
+/*
+ * =============================================================================
+ * typedef
+ * =============================================================================
+ */
+// for debug
+//#define VOICEMIXER_USE_SINE_WAVE
+
+#define VOICEMIXER_EXTRA_NUM_FRAME (3)
+
+#if VOICEMIXER_KEEP_NUM_FRAME < VOICEMIXER_EXTRA_NUM_FRAME
+#error VOICEMIXER_KEEP_NUM_FRAME >= VOICEMIXER_EXTRA_NUM_FRAME
+#endif
+
+//5128
+#define VOICEMIXER_RECORD_BUFFER_LEN 16384
+#define VOICEMIXER_CHANNEL_NUM (1)
+
+// PROPERTY_KEY_VOICEMIXER_DUMP_ON
+// VoiceMixerPlayer::putDataToSpeaker()
+static const char kFileNameVoiceMixer[] = "/data/vendor/audiohal/audio_dump/VoiceMixer";
+static const char kFileNameVoiceMixerRec[] = "/data/vendor/audiohal/audio_dump/VoiceMixerRecord";
+
+// PROPERTY_KEY_VOICEMIXER_BLISRC_DUMP_ON
+// VoiceMixerPlayBuffer::write()
+// before SRC, same as AudioALSAPlaybackHandlerVoiceMixer dump
+static const char kFileNameBefBlisrc[] = "/data/vendor/audiohal/audio_dump/VoiceMixer_before_Blisrc";
+
+static const uint32_t kMaxSizeOfFileName = 128;
+static const uint32_t kSizeOfPrefixFileNameVoiceMixer = sizeof(kFileNameVoiceMixer) - 1;
+static const uint32_t kSizeOfPrefixFileNameBefBlisrc = sizeof(kFileNameBefBlisrc) - 1;
+static const uint32_t kSizeOfPrefixFileNameVoiceMixerRec = sizeof(kFileNameVoiceMixerRec) - 1;
+
+static const uint16_t table_1k_tone_16000_hz[] = {
+ 0x0000, 0x30FC, 0x5A82, 0x7641,
+ 0x7FFF, 0x7641, 0x5A82, 0x30FB,
+ 0x0001, 0xCF05, 0xA57E, 0x89C0,
+ 0x8001, 0x89BF, 0xA57E, 0xCF05
+};
+static const uint32_t kSizeSinewaveTable = sizeof(table_1k_tone_16000_hz);
+static uint32_t gLogLevel;
+
+
+/*
+ * =============================================================================
+ * VoiceMixerPlayBuffer
+ * =============================================================================
+ */
+bool getLogEnableByLevel(const uint32_t logLevel) {
+ return ((gLogLevel & logLevel) != 0);
+}
+
+
+VoiceMixerPlayBuffer::VoiceMixerPlayBuffer() :
+ mExitRequest(false) {
+
+ mFormat = AUDIO_FORMAT_DEFAULT;
+ mRingBuf.pBufBase = NULL;
+ mRingBuf.bufLen = 0;
+ mRingBuf.pRead = NULL;
+ mRingBuf.pWrite = NULL;
+ mRingBuf.pBufEnd = NULL;
+ mBliSrc = NULL;
+ mIsBlisrcDumpEnable = false;
+ mBliOutputLinearBuffer = NULL;
+ pDumpFile = NULL;
+}
+
+bool VoiceMixerPlayBuffer::isBlisrcDumpEnable() {
+ // Dump before Blisrc system property
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_VOICEMIXER_BLISRC_DUMP_ON, property_value, "0"); //"0": default off
+ if (property_value[0] == '1') {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+status_t VoiceMixerPlayBuffer::initPlayBuffer(VoiceMixerPlayer *playPointer,
+ uint32_t sampleRate,
+ uint32_t chNum,
+ int32_t format) {
+ ALOGV("initPlayBuffer sampleRate=%d, ch=%d, format=%d", sampleRate, chNum, format);
+ (void)playPointer;
+ // keep the format
+ ASSERT(format == AUDIO_FORMAT_PCM_16_BIT);
+ mFormat = format;
+
+ // set internal ring buffer
+ mRingBuf.pBufBase = new char[VOICEMIXER_PLAY_BUFFER_LEN];
+ mRingBuf.bufLen = VOICEMIXER_PLAY_BUFFER_LEN;
+ mRingBuf.pRead = mRingBuf.pBufBase;
+ mRingBuf.pWrite = mRingBuf.pBufBase + (VOICEMIXER_EXTRA_NUM_FRAME * VOICEMIXER_PERIOD_SIZE);
+ memset((void *)mRingBuf.pBufBase, 0, mRingBuf.bufLen);
+
+ ALOGV("%s(), pBufBase: %p, pRead: 0x%x, pWrite: 0x%x, bufLen:%u", __FUNCTION__,
+ mRingBuf.pBufBase, (int)(mRingBuf.pRead - mRingBuf.pBufBase), (int)(mRingBuf.pWrite - mRingBuf.pBufBase),
+ mRingBuf.bufLen);
+
+ mIsBlisrcDumpEnable = isBlisrcDumpEnable();
+ if (mIsBlisrcDumpEnable) {
+ char fileNameBlisrc[kMaxSizeOfFileName];
+ memset((void *)fileNameBlisrc, 0, kMaxSizeOfFileName);
+
+ time_t rawtime;
+ time(&rawtime);
+ struct tm *timeinfo = localtime(&rawtime);
+ audio_strncpy(fileNameBlisrc, kFileNameBefBlisrc, kMaxSizeOfFileName);
+ strftime(fileNameBlisrc + kSizeOfPrefixFileNameBefBlisrc,
+ kMaxSizeOfFileName - kSizeOfPrefixFileNameBefBlisrc - 1, "_%Y_%m_%d_%H%M%S.pcm", timeinfo);
+ if (pDumpFile == NULL) {
+ AudiocheckAndCreateDirectory(fileNameBlisrc);
+ pDumpFile = fopen(fileNameBlisrc, "wb");
+ }
+ if (pDumpFile == NULL) {
+ ALOGW("%s(), Fail to open %s", __FUNCTION__, fileNameBlisrc);
+ } else {
+ ALOGD("%s(), open %s", __FUNCTION__, fileNameBlisrc);
+ }
+ }
+ // set blisrc
+ mBliSrc = newMtkAudioSrc(sampleRate, chNum, VOICEMIXER_TARGET_SAMPLE_RATE, VOICEMIXER_CHANNEL_NUM,
+ SRC_IN_Q1P15_OUT_Q1P15);
+ mBliSrc->open();
+
+ ASSERT(mBliSrc != NULL);
+
+ // set blisrc converted buffer
+ mBliOutputLinearBuffer = new char[VOICEMIXER_PLAY_BUFFER_LEN];
+ ALOGV("%s(), mBliOutputLinearBuffer = %p, size = %u",
+ __FUNCTION__, mBliOutputLinearBuffer, VOICEMIXER_PLAY_BUFFER_LEN);
+
+ return NO_ERROR;
+}
+
+VoiceMixerPlayBuffer::~VoiceMixerPlayBuffer() {
+ mExitRequest = true;
+
+ AL_LOCK(mPlayBufferRuningMutex);
+ AL_LOCK(mPlayBufferMutex);
+
+ // delete blisrc handler buffer
+ if (mBliSrc) {
+ mBliSrc->close();
+ deleteMtkAudioSrc(mBliSrc);
+ mBliSrc = NULL;
+ }
+
+ // delete blisrc converted buffer
+ delete[] mBliOutputLinearBuffer;
+
+ // delete internal ring buffer
+ delete[] mRingBuf.pBufBase;
+
+ if (pDumpFile != NULL) {
+ fclose(pDumpFile);
+ pDumpFile = NULL;
+ }
+
+ AL_SIGNAL(mPlayBufferMutex);
+ AL_UNLOCK(mPlayBufferMutex);
+ AL_UNLOCK(mPlayBufferRuningMutex);
+}
+
+uint32_t VoiceMixerPlayBuffer::write(char *buf, uint32_t num) {
+ // lock
+ AL_LOCK(mPlayBufferRuningMutex);
+ AL_LOCK(mPlayBufferMutex);
+
+ ALOGD("%s(), num = %u", __FUNCTION__, num);
+
+ if (mIsBlisrcDumpEnable) {
+ if (pDumpFile != NULL) {
+ fwrite(buf, sizeof(char), num, pDumpFile);
+ }
+ }
+ uint32_t leftCount = num;
+ uint16_t dataCountInBuf = 0;
+ uint32_t tryCount = 0;
+ // max mLatency = 200, max sleep (20 * 10) ms here
+ while (tryCount < VOICEMIXER_RETRY_TIMES && !mExitRequest) {
+ // BLISRC: output buffer: buf => local buffer: mRingBuf
+ if (leftCount > 0) {
+ // get free space in ring buffer
+ uint32_t outCount = RingBuf_getFreeSpace(&mRingBuf);
+
+ // do conversion
+ ASSERT(mBliSrc != NULL);
+ uint32_t consumed = leftCount;
+ mBliSrc->process((int16_t *)buf, &leftCount, (int16_t *)mBliOutputLinearBuffer, &outCount);
+ consumed -= leftCount;
+
+ buf += consumed;
+ ALOGD("%s(), buf consumed = %u, leftCount = %u, outCount = %u",
+ __FUNCTION__, consumed, leftCount, outCount);
+
+ // copy converted data to ring buffer //TODO(Harvey): try to reduce additional one memcpy here
+ RingBuf_copyFromLinear(&mRingBuf, mBliOutputLinearBuffer, outCount);
+ if (getLogEnableByLevel(VOICEMIXER_LOG_LEVEL_PLAYER)) {
+ ALOGD("%s(), pRead: 0x%x, pWrite: 0x%x, leftCount: %u, dataCount: %u",
+ __FUNCTION__,
+ (int)(mRingBuf.pRead - mRingBuf.pBufBase),
+ (int)(mRingBuf.pWrite - mRingBuf.pBufBase),
+ leftCount,
+ RingBuf_getDataCount(&mRingBuf));
+ }
+ }
+
+ // leave while loop
+ if (leftCount <= 0) {
+ break;
+ }
+
+ // wait modem side to retrieve data
+ int retval = AL_WAIT_MS(mPlayBufferMutex, 40);
+ if (!mExitRequest) {
+ dataCountInBuf = RingBuf_getDataCount(&mRingBuf);
+ }
+ if (retval != 0) {
+ ALOGD("%s(), tryCount = %u, leftCount = %u, dataCountInBuf = %u",
+ __FUNCTION__, tryCount, leftCount, dataCountInBuf);
+ tryCount++;
+ }
+
+ }
+
+ // leave warning message if need
+ if (leftCount != 0) {
+ dataCountInBuf = RingBuf_getDataCount(&mRingBuf);
+ ALOGW("%s(), still leftCount = %u, dataCountInBuf = %u", __FUNCTION__, leftCount, dataCountInBuf);
+ }
+
+ // unlock
+ AL_UNLOCK(mPlayBufferMutex);
+ AL_UNLOCK(mPlayBufferRuningMutex);
+
+ return num - leftCount;
+}
+
+
+bool VoiceMixerPlayBuffer::isBufferEnough(void) {
+ uint16_t dataCountInBuf = 0;
+
+ dataCountInBuf = RingBuf_getDataCount(&mRingBuf);
+ if (dataCountInBuf < (VOICEMIXER_PERIOD_SIZE * VOICEMIXER_EXTRA_NUM_FRAME)) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * =============================================================================
+ * VoiceMixerPlayer
+ * =============================================================================
+ */
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "VoiceMixerPlayer"
+
+VoiceMixerPlayer *VoiceMixerPlayer::mVoiceMixerPlayer = NULL;
+VoiceMixerPlayer *VoiceMixerPlayer::getInstance() {
+ static Mutex mGetInstanceLock;
+ Mutex::Autolock _l(mGetInstanceLock);
+
+ if (mVoiceMixerPlayer == NULL) {
+ mVoiceMixerPlayer = new VoiceMixerPlayer();
+ }
+ ASSERT(mVoiceMixerPlayer != NULL);
+ return mVoiceMixerPlayer;
+}
+
+VoiceMixerPlayer::VoiceMixerPlayer() {
+ // initial all table entry to zero, means non of them are occupied
+ mCount = 0;
+ mBufBaseTemp = new char[VOICEMIXER_PLAY_BUFFER_LEN];
+ mSpeechDriver = NULL;
+ mIsDumpEnable = false;
+ pDumpFile = NULL;
+ mPeriodSize = 0;
+ mUnderflowCount = 0;
+ mMixTypeDl = VOICE_MIXER_TYPE_REPLACE;
+}
+
+VoiceMixerPlayer::~VoiceMixerPlayer() {
+ AL_AUTOLOCK(mPlayBufferVectorLock);
+
+ size_t count = mPlayBufferVector.size();
+ for (size_t i = 0 ; i < count ; i++) {
+ VoiceMixerPlayBuffer *playBuffer = mPlayBufferVector.itemAt(i);
+ delete playBuffer;
+ }
+ mPlayBufferVector.clear();
+
+ delete[] mBufBaseTemp;
+
+ if (pDumpFile != NULL) {
+ fclose(pDumpFile);
+ pDumpFile = NULL;
+ }
+}
+
+VoiceMixerPlayBuffer *VoiceMixerPlayer::createPlayBuffer(uint32_t sampleRate, uint32_t chNum, int32_t format) {
+ ALOGV("CreatePlayBuffer sampleRate=%u, ch=%u, format=%d", sampleRate, chNum, format);
+
+ // protection
+ ASSERT(format == AUDIO_FORMAT_PCM_16_BIT);
+
+ // create PlayBuffer
+ VoiceMixerPlayBuffer *playBuffer = new VoiceMixerPlayBuffer();
+ playBuffer->initPlayBuffer(this, sampleRate, chNum, format);
+
+ AL_LOCK(mPlayBufferVectorLock);
+ mPlayBufferVector.add(playBuffer);
+ AL_UNLOCK(mPlayBufferVectorLock);
+
+ return playBuffer;
+}
+
+static bool isDumpEnable() {
+ // VoiceMixer Dump system property
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_KEY_VOICEMIXER_DUMP_ON, property_value, "0"); //"0": default off
+ if (property_value[0] == '1') {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+uint32_t VoiceMixerPlayer::write(VoiceMixerPlayBuffer *playBuffer, void *buf, uint32_t num) {
+ ASSERT(playBuffer != NULL);
+ return playBuffer->write((char *)buf, num);
+}
+
+void VoiceMixerPlayer::destroyPlayBuffer(VoiceMixerPlayBuffer *playBuffer) {
+ ASSERT(playBuffer != NULL);
+ AL_LOCK(mPlayBufferVectorLock);
+ mPlayBufferVector.remove(playBuffer);
+ AL_UNLOCK(mPlayBufferVectorLock);
+
+ delete playBuffer;
+}
+
+bool VoiceMixerPlayer::open(SpeechDriverInterface *pSpeechDriver, uint8_t mixTypeDl) {
+ AL_AUTOLOCK(mCountLock);
+
+ if (NULL != mSpeechDriver && mSpeechDriver != pSpeechDriver) {
+ ALOGE("VoiceMixerPlayer can't support differ SpeechDriver");
+ return false;
+ }
+ mCount++;
+ if (1 != mCount) {
+ SLOG_ENG("%s(), already open. mCount %d", __FUNCTION__, mCount);
+ return true;
+ }
+ mPeriodSize = VOICEMIXER_PERIOD_SIZE;
+ mUnderflowCount = 0;
+
+ SLOG_ENG("%s(), first open, mCount %d, mPeriodSize: %u",
+ __FUNCTION__, mCount, mPeriodSize);
+ mMixTypeDl = mixTypeDl;
+
+ // get Speech Driver (to open/close)
+ mSpeechDriver = pSpeechDriver;
+ mIsDumpEnable = isDumpEnable();
+
+ gLogLevel = get_uint32_from_property(PROPERTY_KEY_VOICEMIXER_LOG_LEVEL);
+
+ if (mIsDumpEnable) {
+ char fileName[kMaxSizeOfFileName];
+ memset((void *)fileName, 0, kMaxSizeOfFileName);
+
+ time_t rawtime;
+ time(&rawtime);
+ struct tm *timeinfo = localtime(&rawtime);
+ audio_strncpy(fileName, kFileNameVoiceMixer, kMaxSizeOfFileName);
+ strftime(fileName + kSizeOfPrefixFileNameVoiceMixer, kMaxSizeOfFileName - kSizeOfPrefixFileNameVoiceMixer - 1,
+ "_%Y_%m_%d_%H%M%S.pcm", timeinfo);
+ if (pDumpFile == NULL) {
+ AudiocheckAndCreateDirectory(fileName);
+ pDumpFile = fopen(fileName, "wb");
+ }
+ if (pDumpFile == NULL) {
+ ALOGW("%s(), Fail to open %s", __FUNCTION__, fileName);
+ } else {
+ ALOGD("%s(), open %s", __FUNCTION__, fileName);
+ }
+ }
+ mSpeechDriver->pcmMixerConfig(PCM_DIRECTION_DOWNLINK, mMixTypeDl);
+ //turn on pcm mixer
+ mSpeechDriver->pcmMixerOn();
+
+ return true;
+}
+
+
+bool VoiceMixerPlayer::configMixType(SpeechDriverInterface *pSpeechDriver, uint8_t mixTypeDl) {
+ AL_AUTOLOCK(mCountLock);
+
+ if (NULL != mSpeechDriver && mSpeechDriver != pSpeechDriver) {
+ ALOGE("%s(), VoiceMixerPlayer can't support differ SpeechDriver.", __FUNCTION__);
+ return false;
+ }
+
+ mMixTypeDl = mixTypeDl;
+ mSpeechDriver = pSpeechDriver;
+ return mSpeechDriver->pcmMixerConfig(PCM_DIRECTION_DOWNLINK, mMixTypeDl);
+}
+
+
+uint32_t VoiceMixerPlayer::putData(VoiceMixerPlayBuffer *playBuffer, char *targetBuf, uint16_t numDataRequest) {
+ uint16_t writeCount = 0;
+
+ if (playBuffer == NULL) {
+ ALOGW("%s(), playBuffer == NULL, return 0.", __FUNCTION__);
+ return 0;
+ }
+
+ AL_LOCK(playBuffer->mPlayBufferMutex);
+
+ // check data count in playBuffer
+ uint16_t dataCountInBuf = RingBuf_getDataCount(&playBuffer->mRingBuf);
+ if (dataCountInBuf == 0) { // no data in buffer, just return 0
+ ALOGV("%s(), dataCountInBuf == 0, return 0.", __FUNCTION__);
+ AL_UNLOCK(playBuffer->mPlayBufferMutex);
+ return 0;
+ }
+
+ writeCount = (dataCountInBuf >= numDataRequest) ? numDataRequest : dataCountInBuf;
+
+ // copy to share buffer
+ RingBuf_copyToLinear(targetBuf, &playBuffer->mRingBuf, writeCount);
+ if (getLogEnableByLevel(VOICEMIXER_LOG_LEVEL_PLAYER)) {
+ ALOGD("%s(), pRead: 0x%x, pWrite: 0x%x, write_count:%u, remain dataCount:%u",
+ __FUNCTION__,
+ (int)(playBuffer->mRingBuf.pRead - playBuffer->mRingBuf.pBufBase),
+ (int)(playBuffer->mRingBuf.pWrite - playBuffer->mRingBuf.pBufBase),
+ writeCount,
+ RingBuf_getDataCount(&playBuffer->mRingBuf));
+ }
+
+ AL_SIGNAL(playBuffer->mPlayBufferMutex);
+ AL_UNLOCK(playBuffer->mPlayBufferMutex);
+
+ return writeCount;
+}
+
+uint16_t VoiceMixerPlayer::putDataToSpeaker(char *targetBuf, uint16_t numDataRequest) {
+ ALOGD("+%s(), numDataRequest =%d.", __FUNCTION__, numDataRequest);
+ uint16_t writeCount = 0;
+ uint16_t numFrames = 0;
+ uint16_t needFrames = 0;
+
+#if !defined(VOICEMIXER_USE_SINE_WAVE)
+ AL_AUTOLOCK(mPlayBufferVectorLock);
+
+ size_t count = mPlayBufferVector.size();
+
+ if (count == 0) {
+ ALOGW("%s(), mPlayBufferVector == NULL, return 0.", __FUNCTION__);
+ return 0;
+ }
+ uint16_t dataCountInBuf, dataCountInBufMin = 65535;
+ for (size_t i = 0 ; i < count ; i++) {
+ VoiceMixerPlayBuffer *playBuffer = mPlayBufferVector.itemAt(i);
+
+ AL_LOCK(playBuffer->mPlayBufferMutex);
+ dataCountInBuf = RingBuf_getDataCount(&playBuffer->mRingBuf);
+ AL_UNLOCK(playBuffer->mPlayBufferMutex);
+
+ if (dataCountInBuf < dataCountInBufMin) {
+ dataCountInBufMin = dataCountInBuf;
+ }
+ }
+ // check data count in playBuffer
+ if (dataCountInBufMin < mPeriodSize) { // data not enough in buffer, just return 0
+ ALOGE("%s(), dataCountInBufMin: %d!! numDataRequest %d, underflow!!",
+ __FUNCTION__, dataCountInBufMin, numDataRequest);
+ mUnderflowCount++;
+ return 0;
+ }
+ if (numDataRequest < mPeriodSize) { // modem still have enough data...
+ ALOGW("%s(), dataCountInBufMin: %d, num_data_request %d, modem have enough data",
+ __FUNCTION__, dataCountInBufMin, numDataRequest);
+ return 0;
+ }
+ writeCount = (dataCountInBufMin >= numDataRequest) ? numDataRequest : dataCountInBufMin;
+ // align frame size
+ if (mUnderflowCount == 0) { // offer 1 frame to modem per time
+ writeCount = mPeriodSize;
+ } else { // underflow before!! offer underflow cnt + 1 frame to modem
+ numFrames = writeCount / mPeriodSize;
+ needFrames = mUnderflowCount + 1;
+ if (numFrames >= needFrames) {
+ writeCount = needFrames * mPeriodSize;
+ mUnderflowCount = 0;
+ } else {
+ writeCount = numFrames * mPeriodSize;
+ mUnderflowCount -= (numFrames - 1);
+ }
+ }
+ memset(targetBuf, 0, numDataRequest);
+ for (size_t i = 0 ; i < count ; i++) {
+ VoiceMixerPlayBuffer *playBuffer = mPlayBufferVector.itemAt(i);
+ if (count == 1) {
+ putData(playBuffer, targetBuf, writeCount);
+ continue;
+ }
+ putData(playBuffer, mBufBaseTemp, writeCount);
+ // mixer
+ int16_t *in = (int16_t *)mBufBaseTemp;
+ int16_t *out = (int16_t *)targetBuf;
+ int16_t frameCnt = writeCount / VOICEMIXER_CHANNEL_NUM / audio_bytes_per_sample(AUDIO_FORMAT_PCM_16_BIT);
+ for (int16_t j = 0; j < frameCnt; j++) {
+ out[j] = clamp16((int32_t)out[j] + (int32_t)in[j]);
+ }
+ }
+#else
+ static uint32_t i4Count = 0;
+ uint32_t current_count = 0, remain_count = 0;
+ char *tmp_ptr = NULL;
+ remain_count = writeCount = numDataRequest;
+ tmp_ptr = targetBuf;
+ if (remain_count > (kSizeSinewaveTable - i4Count)) {
+ memcpy(tmp_ptr, table_1k_tone_16000_hz + (i4Count >> 1), kSizeSinewaveTable - i4Count);
+ tmp_ptr += (kSizeSinewaveTable - i4Count);
+ remain_count -= (kSizeSinewaveTable - i4Count);
+ i4Count = 0;
+ }
+ while (remain_count > kSizeSinewaveTable) {
+ memcpy(tmp_ptr, table_1k_tone_16000_hz, kSizeSinewaveTable);
+ tmp_ptr += kSizeSinewaveTable;
+ remain_count -= kSizeSinewaveTable;
+ }
+ if (remain_count > 0) {
+ memcpy(tmp_ptr, table_1k_tone_16000_hz, remain_count);
+ i4Count = remain_count;
+ }
+#endif
+
+ if (mIsDumpEnable) {
+ if (pDumpFile != NULL) {
+ fwrite(targetBuf, sizeof(char), writeCount, pDumpFile);
+ }
+ }
+ ALOGD("-%s(), num_data_request =%d.", __FUNCTION__, numDataRequest);
+ return writeCount;
+}
+
+
+bool VoiceMixerPlayer::close() {
+ AL_AUTOLOCK(mCountLock);
+ mCount--;
+ if (0 != mCount) {
+ SLOG_ENG("%s, has other user, return. mCount %d", __FUNCTION__, mCount);
+ return true;
+ }
+ SLOG_ENG("%s(), mCount %d, stop", __FUNCTION__, mCount);
+ // tell modem side to close BGS
+ mSpeechDriver->pcmMixerOff();
+ mSpeechDriver = NULL;
+ if (pDumpFile != NULL) {
+ fclose(pDumpFile);
+ pDumpFile = NULL;
+ }
+ return true;
+}
+
+}; // namespace android
+
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/AudioLock.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/AudioLock.h
new file mode 100644
index 0000000..8ef4ff0
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/AudioLock.h
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_AUTO_LOCK_H
+#define AUDIO_AUTO_LOCK_H
+
+#include <audio_log.h>
+
+#include <audio_lock.h>
+
+
+/*
+ * =============================================================================
+ * MACRO
+ * =============================================================================
+ */
+
+#define MAX_AUDIO_LOCK_TIMEOUT_MS (3000)
+
+#define AUTO_CAT_STR_STR(a, b) a ## b
+#define AUTO_CAT_STR_MACRO(a, b) AUTO_CAT_STR_STR(a, b)
+
+#define AUTO_LOCK_NAME AUTO_CAT_STR_MACRO(__auto_name_lock_, __LINE__)
+#define AUTO_RET_NAME AUTO_CAT_STR_MACRO(__auto_name_ret_, __LINE__)
+
+
+/*
+ * =============================================================================
+ * class definition
+ * =============================================================================
+ */
+
+class AudioLock { /* new/free alock automatically */
+public:
+ inline AudioLock() : mAlock(NULL) {
+ if (alock_new(&mAlock, "", "", "", 0) != 0) {
+ mAlock = NULL;
+ }
+ }
+
+ virtual inline ~AudioLock() {
+ if (mAlock) {
+ alock_free(&mAlock, "", "", "", 0);
+ }
+ }
+
+ inline struct alock_t *getAlock() { return mAlock; }
+
+
+
+private:
+ /* A mutex cannot be copied */
+ AudioLock(const AudioLock &);
+ AudioLock &operator = (const AudioLock &);
+
+ struct alock_t *mAlock;
+};
+
+
+/* DO NOT DIRECT USE NormalAlock!! */
+class NormalAlock {
+public:
+ inline NormalAlock(AudioLock *al) : mAlock(al->getAlock()) { }
+
+ inline NormalAlock(AudioLock &al) : mAlock(al.getAlock()) { }
+
+ virtual inline ~NormalAlock() { }
+
+
+ inline int lock(const char *alock_name, const uint32_t ms,
+ const char *file, const char *func, const uint32_t line) {
+ return alock_lock_ms(mAlock, alock_name, ms, file, func, line);
+ }
+
+ inline int trylock(const char *alock_name,
+ const char *file, const char *func, const uint32_t line) {
+ return alock_trylock(mAlock, alock_name, file, func, line);
+ }
+
+ inline int unlock(const char *alock_name,
+ const char *file, const char *func, const uint32_t line) {
+ return alock_unlock(mAlock, alock_name, file, func, line);
+ }
+
+ inline int wait_no_timeout(const char *alock_name,
+ const char *file, const char *func, const uint32_t line) {
+ return alock_wait_no_timeout(mAlock, alock_name, file, func, line);
+ }
+
+ inline int wait(const char *alock_name, const uint32_t ms,
+ const char *file, const char *func, const uint32_t line) {
+ return alock_wait_ms(mAlock, alock_name, ms, file, func, line);
+ }
+
+ inline int signal(const char *alock_name,
+ const char *file, const char *func, const uint32_t line) {
+ return alock_signal(mAlock, alock_name, file, func, line);
+ }
+
+
+protected:
+ NormalAlock() : mAlock(NULL) { }
+
+ struct alock_t *mAlock;
+};
+
+
+/* DO NOT DIRECT USE AutoAlock!! */
+class AutoAlock : public NormalAlock {
+public:
+ inline AutoAlock(AudioLock *lock) : NormalAlock(lock) { }
+
+ inline AutoAlock(AudioLock &lock) : NormalAlock(lock) { }
+
+ /* unlock automatically in dtor */
+ inline ~AutoAlock() { if (unlock("", "", "", 0) != 0) { ALOGW("FAIL"); } }
+
+
+protected:
+ AutoAlock() { }
+};
+
+
+
+/* use the following MACRO for AudioLock (but not NormalAlock/AutoAlock) */
+
+#define AL_LOCK_MS(al, ms) \
+ ({ \
+ NormalAlock AUTO_LOCK_NAME(al); \
+ int AUTO_RET_NAME = AUTO_LOCK_NAME.lock(#al, ms, \
+ get_filename(__FILE__), \
+ (const char *)__FUNCTION__, \
+ __LINE__); \
+ if (AUTO_RET_NAME != 0) { AUD_WARNING_FT("lock timeout!!"); } \
+ AUTO_RET_NAME; \
+ })
+
+#define AL_LOCK_MS_NO_ASSERT(al, ms) \
+ ({ \
+ NormalAlock AUTO_LOCK_NAME(al); \
+ int AUTO_RET_NAME = AUTO_LOCK_NAME.lock(#al, ms, \
+ get_filename(__FILE__), \
+ (const char *)__FUNCTION__, \
+ __LINE__); \
+ if (AUTO_RET_NAME != 0) { \
+ ALOGW("AUD_WARNING(lock timeout): \"" __FILE__ "\", %uL", __LINE__); \
+ } \
+ AUTO_RET_NAME; \
+ })
+
+#define AL_LOCK(al) \
+ AL_LOCK_MS(al, MAX_AUDIO_LOCK_TIMEOUT_MS)
+
+
+#define AL_TRYLOCK(al) \
+ ({ \
+ NormalAlock AUTO_LOCK_NAME(al); \
+ int AUTO_RET_NAME = AUTO_LOCK_NAME.trylock(#al, \
+ get_filename(__FILE__), \
+ (const char *)__FUNCTION__, \
+ __LINE__); \
+ AUTO_RET_NAME; \
+ })
+
+
+#define AL_UNLOCK(al) \
+ ({ \
+ NormalAlock AUTO_LOCK_NAME(al); \
+ int AUTO_RET_NAME = AUTO_LOCK_NAME.unlock(#al, \
+ get_filename(__FILE__), \
+ (const char *)__FUNCTION__, \
+ __LINE__); \
+ if (AUTO_RET_NAME != 0) { AUD_WARNING_FT("unlock fail!!"); } \
+ AUTO_RET_NAME; \
+ })
+
+
+#define AL_AUTOLOCK_MS(al, ms) \
+ AutoAlock AUTO_LOCK_NAME(al); \
+ int AUTO_RET_NAME = AUTO_LOCK_NAME.lock(#al, ms, \
+ get_filename(__FILE__), \
+ (const char *)__FUNCTION__, \
+ __LINE__); \
+ if (AUTO_RET_NAME != 0) { AUD_WARNING_FT("lock timeout!!"); }
+
+
+
+#define AL_AUTOLOCK(al) \
+ AL_AUTOLOCK_MS(al, MAX_AUDIO_LOCK_TIMEOUT_MS)
+
+
+#define AL_WAIT_NO_TIMEOUT(al) \
+ ({ \
+ NormalAlock AUTO_LOCK_NAME(al); \
+ int AUTO_RET_NAME = AUTO_LOCK_NAME.wait_no_timeout(#al, \
+ get_filename(__FILE__), \
+ (const char *)__FUNCTION__, \
+ __LINE__); \
+ AUTO_RET_NAME; \
+ })
+
+
+/* ms: 0 => will not wait!! */
+#define AL_WAIT_MS(al, ms) \
+ ({ \
+ NormalAlock AUTO_LOCK_NAME(al); \
+ int AUTO_RET_NAME = AUTO_LOCK_NAME.wait(#al, ms, \
+ get_filename(__FILE__), \
+ (const char *)__FUNCTION__, \
+ __LINE__); \
+ AUTO_RET_NAME; \
+ })
+
+
+#define AL_SIGNAL(al) \
+ ({ \
+ NormalAlock AUTO_LOCK_NAME(al); \
+ int AUTO_RET_NAME = AUTO_LOCK_NAME.signal(#al, \
+ get_filename(__FILE__), \
+ (const char *)__FUNCTION__, \
+ __LINE__); \
+ if (AUTO_RET_NAME != 0) { AUD_WARNING_FT("signal fail!!"); } \
+ AUTO_RET_NAME; \
+ })
+
+
+
+#endif /* end of AUDIO_AUTO_LOCK_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_assert.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_assert.h
new file mode 100644
index 0000000..492edfe
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_assert.h
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_ASSERT_H
+#define AUDIO_ASSERT_H
+
+#include <string.h>
+
+#include <audio_log.h>
+
+
+#ifdef HAVE_AEE_FEATURE
+#include <aee.h>
+#define audio_aee_exception(x...) aee_system_exception(x)
+#define audio_aee_warning(x...) aee_system_warning(x)
+#else
+#define audio_aee_exception(x...)
+#define audio_aee_warning(x...)
+#endif /* end of HAVE_AEE_FEATURE */
+
+
+#define AUD_ASSERT_OPT(exp, db_opt) \
+ do { \
+ if (!(exp)) { \
+ AUD_LOG_E("AUD_ASSERT("#exp") fail: \"" __FILE__ "\", %uL", __LINE__); \
+ audio_aee_exception("[Audio]", NULL, (db_opt), " %s, %uL", \
+ strrchr(__FILE__, '/') + 1, __LINE__); \
+ } \
+ } while(0)
+
+
+#define AUD_ASSERT(exp) AUD_ASSERT_OPT(exp, DB_OPT_DEFAULT)
+#define AUD_ASSERT_FT(exp) AUD_ASSERT_OPT(exp, DB_OPT_DEFAULT | DB_OPT_FTRACE)
+
+
+
+#define AUD_WARNING_OPT(string, db_opt) \
+ do { \
+ AUD_LOG_W("AUD_WARNING(" string"): \"" __FILE__ "\", %uL", __LINE__); \
+ audio_aee_warning("[Audio]", NULL, (db_opt), string"! %s, %uL", \
+ strrchr(__FILE__, '/') + 1, __LINE__); \
+ } while(0)
+
+
+#define AUD_WARNING(string) AUD_WARNING_OPT(string, DB_OPT_DEFAULT)
+#define AUD_WARNING_FT(string) AUD_WARNING_OPT(string, DB_OPT_DEFAULT | DB_OPT_FTRACE)
+
+
+
+#endif /* end of AUDIO_ASSERT_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_lock.c b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_lock.c
new file mode 100644
index 0000000..50b59c5
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_lock.c
@@ -0,0 +1,545 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "audio_lock.h"
+
+#include <string.h>
+
+#include <errno.h>
+
+#include <sys/time.h>
+#include <sys/prctl.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <audio_log.h>
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * =============================================================================
+ * MACRO
+ * =============================================================================
+ */
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "[ALOCK]"
+
+#define MAX_SYS_TIME_TRY_COUNT (10)
+#define MAX_WAIT_BLOCKED_BY_LOCK_MS (20)
+
+
+#ifndef ANDROID
+#define pthread_mutex_timedlock(a,b) pthread_mutex_lock(a)
+#define pthread_mutex_trylock(a) pthread_mutex_lock(a)
+#endif
+
+
+enum {
+ ALOCK_LOCK,
+ ALOCK_TRYLOCK,
+ ALOCK_UNLOCK,
+ ALOCK_WAIT_IN,
+ ALOCK_WAIT_OUT,
+ ALOCK_SIGNAL,
+ NUM_ALOCK_TYPE
+};
+
+
+static const char *alock_type_name[NUM_ALOCK_TYPE] = {
+ "lock",
+ "trylock",
+ "unlock",
+ "+wait",
+ "-wait",
+ "signal"
+};
+
+
+/*
+ * =============================================================================
+ * utilities implementation
+ * =============================================================================
+ */
+
+#ifdef MTK_AUDIO_LOCK_ENABLE_TRACE
+static void alock_update_trace_info(
+ const uint8_t type, struct alock_t *p_alock, const char *alock_name,
+ const char *file, const char *func, const uint32_t line) {
+ if (type >= NUM_ALOCK_TYPE) {
+ AUD_LOG_E("%s(), %p: %s, %s, %s(), %uL, type %d FAIL!!",
+ __FUNCTION__, p_alock, alock_name, file, func, line, type);
+ return;
+ }
+
+ pthread_mutex_lock(&p_alock->trace_info.idx_lock);
+ uint8_t idx = p_alock->trace_info.idx;
+ p_alock->trace_info.idx++;
+ if (p_alock->trace_info.idx == MAX_TRACE_NUM) {
+ p_alock->trace_info.idx = 0;
+ }
+
+ struct alock_log_unit_t *log_unit = &p_alock->trace_info.log[idx];
+
+ log_unit->type = alock_type_name[type];
+ log_unit->name = alock_name;
+ log_unit->file = file;
+ log_unit->func = func;
+
+ char time_h[4] = {0};
+ char time_m[4] = {0};
+ char time_s[4] = {0};
+
+ struct timespec ts;
+ struct tm t;
+
+ uint32_t ms = 0;
+
+ audio_get_timespec_realtime(&ts);
+ ms = ts.tv_nsec / 1000000L;
+ if (ms > 999) {
+ AUD_LOG_E("%s(), %p: %s, %s, %s(), %uL, ms %u FAIL!!",
+ __FUNCTION__, p_alock, alock_name, file, func, line, ms);
+ ms = 0;
+ }
+
+ if (localtime_r(&ts.tv_sec, &t) == NULL) {
+ memset(&log_unit->time, 0, sizeof(struct alock_time_t));
+ } else if (strftime(time_h, 3, "%H", &t) == 0 ||
+ strftime(time_m, 3, "%M", &t) == 0 ||
+ strftime(time_s, 3, "%S", &t) == 0) {
+ memset(&log_unit->time, 0, sizeof(struct alock_time_t));
+ } else {
+ log_unit->time.h = (uint8_t)atoi(time_h);
+ log_unit->time.m = (uint8_t)atoi(time_m);
+ log_unit->time.s = (uint8_t)atoi(time_s);
+ log_unit->time.ms = ms;
+ }
+
+ log_unit->line = line;
+ log_unit->pid = getpid();
+ log_unit->tid = gettid();
+
+ pthread_mutex_unlock(&p_alock->trace_info.idx_lock);
+}
+#endif
+
+
+#ifdef MTK_AUDIO_LOCK_ENABLE_TRACE
+static void alock_dump_trace_info(struct alock_t *p_alock) {
+ p_alock->trace_info.timeout = true;
+
+ pthread_mutex_lock(&p_alock->trace_info.idx_lock);
+
+ struct alock_log_unit_t *log_unit = NULL;
+
+ uint8_t idx = p_alock->trace_info.idx + 1;
+ if (idx == MAX_TRACE_NUM) {
+ idx = 0;
+ }
+
+ AUD_LOG_E("%p: ========================= dump(+) =========================", p_alock);
+
+ while (idx != p_alock->trace_info.idx) {
+ log_unit = &p_alock->trace_info.log[idx];
+ if (log_unit->type != NULL &&
+ log_unit->name != NULL &&
+ log_unit->file != NULL &&
+ log_unit->func != NULL) {
+ AUD_LOG_E("%p: time: \"%02u:%02u:%02u.%03u\", pid tid: \" %5d %5d \", %s(%s), %s, %s(), %uL",
+ p_alock,
+ log_unit->time.h,
+ log_unit->time.m,
+ log_unit->time.s,
+ log_unit->time.ms,
+ log_unit->pid,
+ log_unit->tid,
+ log_unit->type,
+ log_unit->name,
+ log_unit->file,
+ log_unit->func,
+ log_unit->line);
+ }
+
+ idx++;
+ if (idx == MAX_TRACE_NUM) {
+ idx = 0;
+ }
+ }
+
+ AUD_LOG_E("%p: ========================= dump(-) =========================", p_alock);
+
+ pthread_mutex_unlock(&p_alock->trace_info.idx_lock);
+}
+#endif
+
+
+void alock_cleanup_handler(void *arg) {
+ if (arg == NULL) {
+ return;
+ }
+
+ struct alock_t *p_alock = (struct alock_t *)arg;
+ UNLOCK_ALOCK(p_alock);
+}
+
+
+const char *get_filename(const char *file) {
+ const char *slash = strrchr(file, '/');
+ return (slash) ? slash + 1 : file;
+}
+
+
+
+int alock_new(
+ struct alock_t **pp_alock, const char *alock_name,
+ const char *file, const char *func, const uint32_t line) {
+ struct alock_t *p_alock = (struct alock_t *)AUDIO_MALLOC(sizeof(struct alock_t));
+ if (p_alock == NULL) {
+ AUD_LOG_E("%p: new(%s), %s, %s(), %uL FAIL!!",
+ p_alock, alock_name, file, func, line);
+ *pp_alock = NULL;
+ return -1;
+ }
+ *pp_alock = p_alock;
+
+ pthread_mutex_init(&p_alock->mutex, NULL);
+ pthread_cond_init(&p_alock->cond, NULL);
+
+#ifdef MTK_AUDIO_LOCK_ENABLE_TRACE
+ memset(&p_alock->trace_info, 0, sizeof(struct alock_trace_info_t));
+ pthread_mutex_init(&p_alock->trace_info.idx_lock, NULL);
+#endif
+
+ ALOCK_LOG("%p: new(%s), %s, %s(), %uL",
+ p_alock, alock_name, file, func, line);
+ return 0;
+}
+
+
+int alock_free(
+ struct alock_t **pp_alock, const char *alock_name,
+ const char *file, const char *func, const uint32_t line) {
+ struct alock_t *p_alock = (struct alock_t *)*pp_alock;
+ if (p_alock == NULL) {
+ AUD_LOG_E("%p: free(%s), %s, %s(), %uL FAIL!!",
+ p_alock, alock_name, file, func, line);
+ return -1;
+ }
+
+ ALOCK_LOG("%p: free(%s), %s, %s(), %uL",
+ p_alock, alock_name, file, func, line);
+
+#ifdef MTK_AUDIO_LOCK_ENABLE_TRACE
+ pthread_mutex_destroy(&p_alock->trace_info.idx_lock);
+#endif
+
+ pthread_mutex_destroy(&p_alock->mutex);
+ pthread_cond_destroy(&p_alock->cond);
+
+ AUDIO_FREE(p_alock);
+ p_alock = NULL;
+ *pp_alock = NULL;
+
+ return 0;
+}
+
+
+int alock_lock_no_timeout(
+ struct alock_t *p_alock, const char *alock_name,
+ const char *file, const char *func, const uint32_t line) {
+ if (p_alock == NULL) {
+ AUD_LOG_E("%p: lock(%s), %s, %s(), %uL FAIL!!",
+ p_alock, alock_name, file, func, line);
+ return -1;
+ }
+
+ ALOCK_LOG("%p: lock(%s), %s, %s(), %uL",
+ p_alock, alock_name, file, func, line);
+
+ pthread_mutex_lock(&p_alock->mutex);
+
+#ifdef MTK_AUDIO_LOCK_ENABLE_TRACE
+ alock_update_trace_info(ALOCK_LOCK, p_alock, alock_name, file, func, line);
+ audio_get_timespec_monotonic(&p_alock->trace_info.ts_start);
+#endif
+
+ return 0;
+}
+
+
+int alock_trylock(
+ struct alock_t *p_alock, const char *alock_name,
+ const char *file, const char *func, const uint32_t line) {
+ int retval = 0;
+
+ if (p_alock == NULL) {
+ AUD_LOG_E("%p: trylock(%s), %s, %s(), %uL FAIL!!",
+ p_alock, alock_name, file, func, line);
+ return -1;
+ }
+
+#if defined(MTK_AUDIO_TRYLOCK_NOT_SUPPORT)
+ retval = -1;
+#else
+ retval = -pthread_mutex_trylock(&p_alock->mutex);
+#endif
+
+#ifdef MTK_AUDIO_LOCK_ENABLE_TRACE
+ if (retval == 0) {
+ alock_update_trace_info(ALOCK_TRYLOCK, p_alock, alock_name, file, func, line);
+ audio_get_timespec_monotonic(&p_alock->trace_info.ts_start);
+ }
+#endif
+
+ ALOCK_LOG("%p: trylock(%s), %s, %s(), %uL, retval: %d",
+ p_alock, alock_name, file, func, line, retval);
+
+ return retval;
+}
+
+
+int alock_lock_ms(
+ struct alock_t *p_alock, const char *alock_name, const uint32_t ms,
+ const char *file, const char *func, const uint32_t line) {
+ struct timespec ts_timeout;
+
+ struct timespec ts_start;
+ struct timespec ts_stop;
+
+ uint32_t ms_spend = 0;
+ uint32_t ms_left = ms;
+
+ int try_count = 0;
+
+ int retval = 0;
+
+ if (p_alock == NULL) {
+ AUD_LOG_E("%p: lock(%s, %u), %s, %s(), %uL FAIL!!",
+ p_alock, alock_name, ms, file, func, line);
+ return -1;
+ }
+
+ if (ms == 0) {
+ AUD_LOG_W("%p: lock(%s, %u), %s, %s(), %uL call alock_lock_no_timeout() due to ms = 0!!",
+ p_alock, alock_name, ms, file, func, line);
+ return alock_lock_no_timeout(p_alock, alock_name, file, func, line);
+ }
+
+ ALOCK_LOG("%p: lock(%s, %u), %s, %s(), %uL",
+ p_alock, alock_name, ms, file, func, line);
+
+ do {
+ audio_get_timespec_monotonic(&ts_start);
+ audio_get_timespec_timeout(&ts_timeout, ms_left);
+ retval = -pthread_mutex_timedlock(&p_alock->mutex, &ts_timeout);
+ audio_get_timespec_monotonic(&ts_stop);
+
+ /* pass or other error which is not timeout */
+ if (retval == 0 || retval != -ETIMEDOUT) {
+ break;
+ }
+
+ /* -ETIMEDOUT */
+ ms_spend += get_time_diff_ms(&ts_start, &ts_stop);
+ if (ms_spend >= ms) { /* monotonic also timeout */
+ break;
+ }
+ ms_left = ms - ms_spend;
+
+ /* AlarmManagerService: Setting time of day to sec=xxx */
+ /* SimStateMonitor: onReceive action : android.intent.action.ACTION_SUBINFO_RECORD_UPDATED */
+ AUD_LOG_W("%p: lock(%s, %u), %s, %s(), %uL, systime changed, ms_left: %u",
+ p_alock, alock_name, ms, file, func, line, ms_left);
+ } while (++try_count < MAX_SYS_TIME_TRY_COUNT);
+
+ if (retval == 0) {
+#ifdef MTK_AUDIO_LOCK_ENABLE_TRACE
+ alock_update_trace_info(ALOCK_LOCK, p_alock, alock_name, file, func, line);
+ audio_get_timespec_monotonic(&p_alock->trace_info.ts_start);
+#endif
+ } else {
+ AUD_LOG_E("%p: lock(%s, %u), %s, %s(), %uL FAIL!! retval: %d",
+ p_alock, alock_name, ms, file, func, line, retval);
+#ifdef MTK_AUDIO_LOCK_ENABLE_TRACE
+ alock_dump_trace_info(p_alock);
+#endif
+ }
+
+ return retval;
+}
+
+
+int alock_unlock(
+ struct alock_t *p_alock, const char *alock_name,
+ const char *file, const char *func, const uint32_t line) {
+ if (p_alock == NULL) {
+ AUD_LOG_E("%p: unlock(%s), %s, %s(), %uL FAIL!!",
+ p_alock, alock_name, file, func, line);
+ return -1;
+ }
+
+ ALOCK_LOG("%p: unlock(%s), %s, %s(), %uL",
+ p_alock, alock_name, file, func, line);
+
+#ifdef MTK_AUDIO_LOCK_ENABLE_TRACE
+ audio_get_timespec_monotonic(&p_alock->trace_info.ts_stop);
+ alock_update_trace_info(ALOCK_UNLOCK, p_alock, alock_name, file, func, line);
+
+ if (p_alock->trace_info.timeout == true) {
+ p_alock->trace_info.timeout = false;
+ AUD_LOG_W("%p: unlock(%s), %s, %s(), %uL, lock time %u ms",
+ p_alock, alock_name, file, func, line,
+ (uint32_t)get_time_diff_ms(&p_alock->trace_info.ts_start,
+ &p_alock->trace_info.ts_stop));
+ }
+#endif
+
+ pthread_mutex_unlock(&p_alock->mutex);
+
+ return 0;
+}
+
+
+
+int alock_wait_no_timeout(
+ struct alock_t *p_alock, const char *alock_name,
+ const char *file, const char *func, const uint32_t line) {
+ if (p_alock == NULL) {
+ AUD_LOG_E("%p: wait(%s), %s, %s(), %uL FAIL!!",
+ p_alock, alock_name, file, func, line);
+ return -1;
+ }
+
+ ALOCK_LOG("%p: +wait(%s), %s, %s(), %uL",
+ p_alock, alock_name, file, func, line);
+
+#ifdef MTK_AUDIO_LOCK_ENABLE_TRACE
+ alock_update_trace_info(ALOCK_WAIT_IN, p_alock, alock_name, file, func, line);
+#endif
+
+ pthread_cond_wait(&p_alock->cond, &p_alock->mutex);
+
+#ifdef MTK_AUDIO_LOCK_ENABLE_TRACE
+ alock_update_trace_info(ALOCK_WAIT_OUT, p_alock, alock_name, file, func, line);
+#endif
+
+ ALOCK_LOG("%p: -wait(%s), %s, %s(), %uL",
+ p_alock, alock_name, file, func, line);
+
+ return 0;
+}
+
+
+int alock_wait_ms(
+ struct alock_t *p_alock, const char *alock_name, const uint32_t ms,
+ const char *file, const char *func, const uint32_t line) {
+ struct timespec ts_timeout;
+
+ struct timespec ts_start;
+ struct timespec ts_stop;
+
+ uint32_t ms_spend = 0;
+ uint32_t ms_left = ms;
+
+ int try_count = 0;
+
+ int retval = 0;
+
+ if (p_alock == NULL) {
+ AUD_LOG_E("%p: wait(%s, %u), %s, %s(), %uL FAIL!!",
+ p_alock, alock_name, ms, file, func, line);
+ return -1;
+ }
+
+ if (ms == 0) {
+ AUD_LOG_W("%p: wait(%s, %u), %s, %s(), %uL not wait due to ms = 0!!",
+ p_alock, alock_name, ms, file, func, line);
+ return -1;
+ }
+
+ ALOCK_LOG("%p: +wait(%s, %u), %s, %s(), %uL",
+ p_alock, alock_name, ms, file, func, line);
+
+#ifdef MTK_AUDIO_LOCK_ENABLE_TRACE
+ alock_update_trace_info(ALOCK_WAIT_IN, p_alock, alock_name, file, func, line);
+#endif
+
+ do {
+ audio_get_timespec_monotonic(&ts_start);
+ audio_get_timespec_timeout(&ts_timeout, ms_left);
+ retval = -pthread_cond_timedwait(&p_alock->cond, &p_alock->mutex, &ts_timeout);
+ audio_get_timespec_monotonic(&ts_stop);
+
+ /* pass or other error which is not timeout */
+ if (retval == 0 || retval != -ETIMEDOUT) {
+ break;
+ }
+
+ /* -ETIMEDOUT */
+ ms_spend += get_time_diff_ms(&ts_start, &ts_stop);
+ if (ms_spend >= ms) { /* monotonic also timeout */
+ break;
+ }
+ ms_left = ms - ms_spend;
+
+ /* AlarmManagerService: Setting time of day to sec=xxx */
+ /* SimStateMonitor: onReceive action : android.intent.action.ACTION_SUBINFO_RECORD_UPDATED */
+ AUD_LOG_W("%p: wait(%s, %u), %s, %s(), %uL, systime changed, ms_left: %u",
+ p_alock, alock_name, ms, file, func, line, ms_left);
+ } while (++try_count < MAX_SYS_TIME_TRY_COUNT);
+
+#ifdef MTK_AUDIO_LOCK_ENABLE_TRACE
+ alock_update_trace_info(ALOCK_WAIT_OUT, p_alock, alock_name, file, func, line);
+#endif
+
+ if (retval == 0) {
+ ALOCK_LOG("%p: -wait(%s, %u), %s, %s(), %uL",
+ p_alock, alock_name, ms, file, func, line);
+ } else if (retval == -ETIMEDOUT) {
+ if (ms_spend > ms + MAX_WAIT_BLOCKED_BY_LOCK_MS) {
+ AUD_LOG_W("%p: -wait(%s, %u), %s, %s(), %uL FAIL!! retval: %d, ms_spend: %u",
+ p_alock, alock_name, ms, file, func, line, retval, ms_spend);
+ }
+ } else {
+ AUD_LOG_E("%p: -wait(%s, %u), %s, %s(), %uL FAIL!! retval: %d",
+ p_alock, alock_name, ms, file, func, line, retval);
+ }
+
+ return retval;
+}
+
+
+int alock_signal(
+ struct alock_t *p_alock, const char *alock_name,
+ const char *file, const char *func, const uint32_t line) {
+ if (p_alock == NULL) {
+ AUD_LOG_E("%p: signal(%s), %s, %s(), %uL FAIL!!",
+ p_alock, alock_name, file, func, line);
+ return -1;
+ }
+
+ ALOCK_LOG("%p: signal(%s), %s, %s(), %uL",
+ p_alock, alock_name, file, func, line);
+
+ pthread_cond_signal(&p_alock->cond);
+
+#ifdef MTK_AUDIO_LOCK_ENABLE_TRACE
+ alock_update_trace_info(ALOCK_SIGNAL, p_alock, alock_name, file, func, line);
+#endif
+
+ return 0;
+}
+
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_lock.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_lock.h
new file mode 100644
index 0000000..d78cb86
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_lock.h
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_LOCK_H
+#define AUDIO_LOCK_H
+
+/* TODO: kernel & scp */
+#include <string.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <pthread.h>
+#include <time.h>
+
+#include <audio_log.h>
+#include <audio_assert.h>
+#include <audio_memory_control.h>
+
+#include <audio_time.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/*
+ * =============================================================================
+ * MACRO
+ * =============================================================================
+ */
+
+#define MAX_LOCK_TIMEOUT_MS (1000)
+
+#ifdef MTK_AUDIO_LOCK_ENABLE_LOG
+#ifdef ALOCK_LOG
+#undef ALOCK_LOG
+#endif
+#define ALOCK_LOG(x...) AUD_LOG_D(x)
+#else
+#define ALOCK_LOG(x...)
+#endif
+
+#ifdef MTK_AUDIO_LOCK_ENABLE_TRACE
+#define MAX_TRACE_NUM (8)
+#endif
+
+
+/*
+ * =============================================================================
+ * struct definition
+ * =============================================================================
+ */
+
+#ifdef MTK_AUDIO_LOCK_ENABLE_TRACE
+
+struct alock_time_t {
+ uint32_t h: 5; /* [0, 24) in [0, 32) */
+ uint32_t m: 6; /* [0, 60) in [0, 64) */
+ uint32_t s: 6; /* [0, 60) in [0, 64) */
+ uint32_t ms: 10; /* [0, 1000) in [0, 1024) */
+};
+
+struct alock_log_unit_t {
+ const char *type;
+ const char *name;
+ const char *file;
+ const char *func;
+ struct alock_time_t time;
+ uint32_t line;
+ uint16_t pid;
+ uint16_t tid;
+};
+
+struct alock_trace_info_t {
+ struct alock_log_unit_t log[MAX_TRACE_NUM];
+ struct timespec ts_start;
+ struct timespec ts_stop;
+ pthread_mutex_t idx_lock;
+ uint8_t idx;
+ bool timeout;
+};
+#endif
+
+
+struct alock_t {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+#ifdef MTK_AUDIO_LOCK_ENABLE_TRACE
+ struct alock_trace_info_t trace_info;
+#endif
+};
+
+
+
+/*
+ * =============================================================================
+ * public function
+ * =============================================================================
+ */
+
+void alock_cleanup_handler(void *arg);
+
+const char *get_filename(const char *file);
+
+
+int alock_new(
+ struct alock_t **pp_alock, const char *alock_name,
+ const char *file, const char *func, const uint32_t line);
+
+int alock_free(
+ struct alock_t **pp_alock, const char *alock_name,
+ const char *file, const char *func, const uint32_t line);
+
+int alock_lock_no_timeout(
+ struct alock_t *p_alock, const char *alock_name,
+ const char *file, const char *func, const uint32_t line);
+
+int alock_trylock(
+ struct alock_t *p_alock, const char *alock_name,
+ const char *file, const char *func, const uint32_t line);
+
+int alock_lock_ms(
+ struct alock_t *p_alock, const char *alock_name, const uint32_t ms,
+ const char *file, const char *func, const uint32_t line);
+
+int alock_unlock(
+ struct alock_t *p_alock, const char *alock_name,
+ const char *file, const char *func, const uint32_t line);
+
+int alock_wait_no_timeout(
+ struct alock_t *p_alock, const char *alock_name,
+ const char *file, const char *func, const uint32_t line);
+
+int alock_wait_ms(
+ struct alock_t *p_alock, const char *alock_name, const uint32_t ms,
+ const char *file, const char *func, const uint32_t line);
+
+int alock_signal(
+ struct alock_t *p_alock, const char *alock_name,
+ const char *file, const char *func, const uint32_t line);
+
+
+
+
+#define NEW_ALOCK(alock) \
+ ({ \
+ int __ret = alock_new(&(alock), #alock, \
+ get_filename(__FILE__), \
+ (const char *)__FUNCTION__, \
+ __LINE__); \
+ if (__ret != 0) { AUD_WARNING_FT("new lock fail!!"); } \
+ __ret; \
+ })
+
+
+#define FREE_ALOCK(alock) \
+ ({ \
+ int __ret = alock_free(&(alock), #alock, \
+ get_filename(__FILE__), \
+ (const char *)__FUNCTION__, \
+ __LINE__); \
+ if (__ret != 0) { AUD_WARNING_FT("free lock fail!!"); } \
+ __ret; \
+ })
+
+
+#define LOCK_ALOCK_NO_TIMEOUT(alock) \
+ ({ \
+ int __ret = alock_lock_no_timeout((alock), #alock, \
+ get_filename(__FILE__), \
+ (const char *)__FUNCTION__, \
+ __LINE__); \
+ if (__ret != 0) { AUD_WARNING_FT("lock fail!!"); } \
+ __ret; \
+ })
+
+
+#define LOCK_ALOCK_TRYLOCK(alock) \
+ ({ \
+ int __ret = alock_trylock((alock), #alock, \
+ get_filename(__FILE__), \
+ (const char *)__FUNCTION__, \
+ __LINE__); \
+ __ret; \
+ })
+
+
+#define LOCK_ALOCK_MS(alock, ms) \
+ ({ \
+ int __ret = alock_lock_ms((alock), #alock, ms, \
+ get_filename(__FILE__), \
+ (const char *)__FUNCTION__, \
+ __LINE__); \
+ if (__ret != 0) { AUD_WARNING_FT("lock timeout!!"); } \
+ __ret; \
+ })
+
+
+#define LOCK_ALOCK(alock) \
+ LOCK_ALOCK_MS((alock), MAX_LOCK_TIMEOUT_MS)
+
+
+#define UNLOCK_ALOCK(alock) \
+ ({ \
+ int __ret = alock_unlock((alock), #alock, \
+ get_filename(__FILE__), \
+ (const char *)__FUNCTION__, \
+ __LINE__); \
+ if (__ret != 0) { AUD_WARNING_FT("unlock fail!!"); } \
+ __ret; \
+ })
+
+
+#define WAIT_ALOCK(alock) \
+ ({ \
+ int __ret = alock_wait_no_timeout((alock), #alock, \
+ get_filename(__FILE__), \
+ (const char *)__FUNCTION__, \
+ __LINE__); \
+ __ret; \
+ })
+
+
+#define WAIT_ALOCK_MS(alock, ms) \
+ ({ \
+ int __ret = alock_wait_ms((alock), #alock, ms, \
+ get_filename(__FILE__), \
+ (const char *)__FUNCTION__, \
+ __LINE__); \
+ __ret; \
+ })
+
+
+#define SIGNAL_ALOCK(alock) \
+ ({ \
+ int __ret = alock_signal((alock), #alock, \
+ get_filename(__FILE__), \
+ (const char *)__FUNCTION__, \
+ __LINE__); \
+ if (__ret != 0) { AUD_WARNING_FT("signal fail!!"); } \
+ __ret; \
+ })
+
+
+#define CLEANUP_PUSH_ALOCK(alock) \
+ pthread_cleanup_push(alock_cleanup_handler, (alock))
+
+
+#define CLEANUP_POP_ALOCK(alock) \
+ pthread_cleanup_pop(0)
+
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* end of AUDIO_LOCK_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_log.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_log.h
new file mode 100644
index 0000000..0cc7c6b
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_log.h
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_LOG_H
+#define AUDIO_LOG_H
+
+#ifdef ANDROID
+#include <log/log.h>
+#else
+#include <stdio.h>
+#include <stdarg.h> /* va_list, va_start, va_arg, va_end */
+
+inline void audio_printf(const char *message, ...) {
+ static char printf_msg[512];
+ va_list args;
+ va_start(args, message);
+ vsnprintf(printf_msg, sizeof(printf_msg), message, args);
+ printf("%s\n", printf_msg);
+ va_end(args);
+}
+
+#define ALOGV audio_printf
+#define ALOGD audio_printf
+#define ALOGI audio_printf
+#define ALOGW audio_printf
+#define ALOGE audio_printf
+
+#endif /*end of ANDROID */
+
+
+
+
+#ifndef AUD_LOG_VV
+#define AUD_LOG_VV(x...)
+#endif
+
+#ifndef AUD_LOG_V
+#if 0
+#define AUD_LOG_V(x...) ALOGD(x)
+#else
+#define AUD_LOG_V(x...)
+#endif
+#endif
+
+#ifndef AUD_LOG_D
+#define AUD_LOG_D ALOGD
+#endif
+
+#ifndef AUD_LOG_I
+#define AUD_LOG_I ALOGI
+#endif
+
+#ifndef AUD_LOG_W
+#define AUD_LOG_W ALOGW
+#endif
+
+#ifndef AUD_LOG_E
+#define AUD_LOG_E ALOGE
+#endif
+
+
+#endif /* end of AUDIO_LOG_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_memory_control.c b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_memory_control.c
new file mode 100644
index 0000000..5543a4c
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_memory_control.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <audio_memory_control.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <errno.h>
+
+#include <log/log.h>
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * =============================================================================
+ * log
+ * =============================================================================
+ */
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "audio_memory_control"
+
+
+
+/*
+ * =============================================================================
+ * dynamic memory management
+ * =============================================================================
+ */
+
+int dynamic_change_buf_size(
+ void **ptr,
+ uint32_t *current_size,
+ uint32_t target_size)
+{
+ uint32_t change_size = 0;
+
+ if (!ptr || !current_size || !target_size) {
+ ALOGW("%s(), %p %p %u fail!!", __FUNCTION__,
+ ptr, current_size, target_size);
+ return -EINVAL;
+ }
+
+ if (target_size > *current_size) { /* increase size */
+ change_size = target_size * 2;
+ if (*ptr != NULL) {
+ ALOGD("%s(), %p: %u -> %u", __FUNCTION__,
+ *ptr, *current_size, change_size);
+ AUDIO_FREE_POINTER(*ptr);
+ }
+ AUDIO_ALLOC_BUFFER(*ptr, change_size);
+ *current_size = change_size;
+ } else if ((4 * target_size) < *current_size) { /* decrease size */
+ change_size = target_size * 2;
+ if (*ptr != NULL) {
+ ALOGD("%s(), %p: %u -> %u", __FUNCTION__,
+ *ptr, *current_size, change_size);
+ AUDIO_FREE_POINTER(*ptr);
+ }
+ AUDIO_ALLOC_BUFFER(*ptr, change_size);
+ *current_size = change_size;
+ }
+
+ if (*ptr == NULL) {
+ *current_size = 0;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * =============================================================================
+ * string
+ * =============================================================================
+ */
+
+char *strcpy_safe(char *target, char *source, uint32_t target_size)
+{
+ char *ret = target;
+
+ if (target != NULL && source != NULL && target_size > 0) {
+ if (target_size < (strlen(source) + 1)) {
+ ALOGE("size %u < %s", target_size, source);
+ }
+ ret = strncpy(target, source, target_size);
+ target[target_size - 1] = '\0';
+ } else {
+ ALOGE("%p %p %u fail!!", target, source, target_size);
+ }
+ return ret;
+}
+
+
+char *strcat_safe(char *target, char *source, uint32_t target_size)
+{
+ uint32_t target_len = 0;
+ uint32_t source_len = 0;
+
+ char *ret = target;
+
+ if (target != NULL && source != NULL && target_size > 0) {
+ target_len = strlen(target);
+ source_len = strlen(source);
+ if (target_size < (target_len + source_len + 1)) {
+ ALOGE("size %u < %s + %s", target_size, target, source);
+ }
+ if (target_size > (target_len + 1)) {
+ ret = strncat(target, source, (target_size - target_len - 1));
+ }
+ } else {
+ ALOGE("%p %p %u fail!!", target, source, target_size);
+ }
+
+ return ret;
+}
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_memory_control.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_memory_control.h
new file mode 100644
index 0000000..df20913
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_memory_control.h
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_MEMORY_CONTROL_H
+#define AUDIO_MEMORY_CONTROL_H
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <audio_log.h>
+#include <audio_assert.h>
+
+/*
+ * =============================================================================
+ * MACRO
+ * =============================================================================
+ */
+
+#define GET_MAX_VALUE(x, y) ((x) > (y)) ? (x) : (y);
+#define GET_MIN_VALUE(x, y) ((x) < (y)) ? (x) : (y);
+
+#define GET_FILENAME() \
+ ({ \
+ const char *__slash = strrchr(__FILE__, '/'); \
+ const char *__filename = (__slash) ? __slash + 1 : __FILE__; \
+ __filename; \
+ })
+
+
+
+/*
+ * =============================================================================
+ * AUDIO_MALLOC & AUDIO_FREE
+ * =============================================================================
+ */
+
+#define AUDIO_MALLOC(sz) \
+ ({ \
+ void *__ptr = malloc((sz)); \
+ AUD_LOG_V("AUDIO_MALLOC(%u) => %p, \"" __FILE__ "\", %uL", \
+ (uint32_t)(sz), __ptr, __LINE__); \
+ __ptr; \
+ })
+
+
+#define AUDIO_FREE(ptr) \
+ ({ \
+ AUD_LOG_V("AUDIO_FREE(%p), \"" __FILE__ "\", %uL", (ptr), __LINE__); \
+ free((ptr)); \
+ })
+
+
+
+/*
+ * =============================================================================
+ * utilities
+ * =============================================================================
+ */
+
+#define AUDIO_ALLOC_BUFFER(ptr, len) \
+ do { \
+ if (ptr != NULL) { \
+ AUD_LOG_W("mem leak!! \"%s\", %uL", GET_FILENAME(), __LINE__); \
+ } \
+ ptr = (void *)AUDIO_MALLOC(len); \
+ AUD_ASSERT(ptr != NULL); \
+ memset(ptr, 0, len); \
+ } while(0)
+
+
+#define AUDIO_ALLOC_CHAR_BUFFER(ptr, len) \
+ do { \
+ if (ptr != NULL) { \
+ AUD_LOG_W("mem leak!! \"%s\", %uL", GET_FILENAME(), __LINE__); \
+ } \
+ ptr = (char *)AUDIO_MALLOC(len); \
+ AUD_ASSERT(ptr != NULL); \
+ memset(ptr, 0, len); \
+ } while(0)
+
+
+#define AUDIO_ALLOC_STRUCT(type, ptr) \
+ do { \
+ if (ptr != NULL) { \
+ AUD_LOG_W("mem leak!! \"%s\", %uL", GET_FILENAME(), __LINE__); \
+ } \
+ ptr = (type *)AUDIO_MALLOC(sizeof(type)); \
+ AUD_ASSERT(ptr != NULL); \
+ memset(ptr, 0, sizeof(type)); \
+ } while(0)
+
+
+#define AUDIO_ALLOC_STRUCT_ARRAY(type, num, ptr) \
+ do { \
+ if (ptr != NULL) { \
+ AUD_LOG_W("mem leak!! \"%s\", %uL", GET_FILENAME(), __LINE__); \
+ } \
+ ptr = (type *)AUDIO_MALLOC(sizeof(type) * num); \
+ AUD_ASSERT(ptr != NULL); \
+ memset(ptr, 0, sizeof(type) * num); \
+ } while(0)
+
+
+#define AUDIO_FREE_POINTER(ptr) \
+ do { \
+ if (ptr != NULL) { \
+ AUDIO_FREE(ptr); \
+ ptr = NULL; \
+ } \
+ } while(0)
+
+
+
+
+/*
+ * =============================================================================
+ * dynamic memory management
+ * =============================================================================
+ */
+
+int dynamic_change_buf_size(
+ void **ptr,
+ uint32_t *current_size,
+ uint32_t target_size);
+
+
+
+/*
+ * =============================================================================
+ * string
+ * =============================================================================
+ */
+
+char *strcpy_safe(char *target, char *source, uint32_t target_size);
+char *strcat_safe(char *target, char *source, uint32_t target_size);
+
+
+
+
+#endif /* AUDIO_MEMORY_CONTROL_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_ringbuf.c b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_ringbuf.c
new file mode 100644
index 0000000..817fb90
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_ringbuf.c
@@ -0,0 +1,618 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include <audio_ringbuf.h>
+
+#include <string.h>
+
+#include <audio_log.h>
+#include <audio_assert.h>
+#include <audio_memory_control.h>
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "audio_ringbuf"
+
+#ifdef AURISYS_DUMP_LOG_V
+#undef AUD_LOG_V
+#define AUD_LOG_V(x...) AUD_LOG_D(x)
+#endif
+
+
+
+#define MAX_SIZE_OF_ONE_FRAME (16) /* 32-bits * 4ch */
+
+
+#define DUMP_RINGBUF(LOG_F, description, rb, count) \
+ do { \
+ if (rb && description) { \
+ LOG_F("%s(), %s, base %p, read %p, write %p, size %u" \
+ ", data %u, free %u, count %u", \
+ __FUNCTION__, \
+ description, \
+ (rb)->base, \
+ (rb)->read, \
+ (rb)->write, \
+ (rb)->size, \
+ audio_ringbuf_count(rb), \
+ audio_ringbuf_free_space(rb), \
+ count); \
+ } else { \
+ AUD_LOG_W("%s(), %uL, %p %p", \
+ __FUNCTION__, __LINE__, rb, description); \
+ } \
+ } while (0)
+
+
+
+uint32_t audio_ringbuf_count(const struct audio_ringbuf_t *rb) {
+ uint32_t count = 0;
+ uint32_t w2r = 0;
+
+ if (!rb) {
+ AUD_WARNING("null");
+ return 0;
+ }
+ if (!rb->base || !rb->size) {
+ return 0;
+ }
+
+
+ if (rb->write >= rb->read) {
+ count = rb->write - rb->read;
+ } else {
+ w2r = rb->read - rb->write;
+ if (rb->size > w2r) {
+ count = rb->size - w2r;
+ } else {
+ count = 0;
+ }
+ }
+
+ return count;
+}
+
+
+uint32_t audio_ringbuf_free_space(const struct audio_ringbuf_t *rb) {
+ uint32_t count = 0;
+ uint32_t free_spece = 0;
+
+ if (!rb) {
+ AUD_WARNING("null");
+ return 0;
+ }
+ if (!rb->base || !rb->size) {
+ return 0;
+ }
+
+ count = audio_ringbuf_count(rb);
+ free_spece = (rb->size > count) ? (rb->size - count) : 0;
+
+ /* avoid to copy data s.t. read == write */
+ if (free_spece > MAX_SIZE_OF_ONE_FRAME) {
+ free_spece -= MAX_SIZE_OF_ONE_FRAME;
+ } else {
+ free_spece = 0;
+ }
+
+ return free_spece;
+}
+
+
+void audio_ringbuf_copy_to_linear(
+ char *linear,
+ struct audio_ringbuf_t *rb,
+ uint32_t count) {
+ char *end = NULL;
+ uint32_t r2e = 0;
+
+ if (!count) {
+ return;
+ }
+ if (!linear || !rb) {
+ AUD_WARNING("null");
+ return;
+ }
+ if (!rb->base || !rb->size) {
+ DUMP_RINGBUF(AUD_LOG_W, "no init", rb, count);
+ AUD_WARNING("no init");
+ return;
+ }
+ if (count > audio_ringbuf_count(rb)) {
+ DUMP_RINGBUF(AUD_LOG_W, "underflow", rb, count);
+ AUD_WARNING("underflow");
+ return;
+ }
+
+
+ if (rb->read <= rb->write) {
+ memcpy(linear, rb->read, count);
+ rb->read += count;
+ } else {
+ end = rb->base + rb->size;
+ r2e = end - rb->read;
+ if (count <= r2e) {
+ memcpy(linear, rb->read, count);
+ rb->read += count;
+ if (rb->read == end) {
+ rb->read = rb->base;
+ }
+ } else {
+ memcpy(linear, rb->read, r2e);
+ memcpy(linear + r2e, rb->base, count - r2e);
+ rb->read = rb->base + count - r2e;
+ }
+ }
+}
+
+
+void audio_ringbuf_copy_from_linear_impl(
+ struct audio_ringbuf_t *rb,
+ const char *linear,
+ uint32_t count) {
+ char *end = NULL;
+ uint32_t w2e = 0;
+
+ if (!count) {
+ return;
+ }
+ if (!rb || !linear) {
+ AUD_WARNING("null");
+ return;
+ }
+ if (!rb->base || !rb->size) {
+ DUMP_RINGBUF(AUD_LOG_W, "no init", rb, count);
+ AUD_WARNING("no init");
+ return;
+ }
+ if (count > audio_ringbuf_free_space(rb)) {
+ DUMP_RINGBUF(AUD_LOG_W, "overflow", rb, count);
+ AUD_WARNING("overflow");
+ return;
+ }
+
+
+ end = rb->base + rb->size;
+
+ if (rb->read <= rb->write) {
+ w2e = end - rb->write;
+ if (count <= w2e) {
+ memcpy(rb->write, linear, count);
+ rb->write += count;
+ if (rb->write == end) {
+ rb->write = rb->base;
+ }
+ } else {
+ memcpy(rb->write, linear, w2e);
+ memcpy(rb->base, linear + w2e, count - w2e);
+ rb->write = rb->base + count - w2e;
+ }
+ } else {
+ memcpy(rb->write, linear, count);
+ rb->write += count;
+ }
+}
+
+
+void audio_ringbuf_copy_from_linear(
+ struct audio_ringbuf_t *rb,
+ const char *linear,
+ uint32_t count) {
+ if (!count) {
+ return;
+ }
+ if (!rb || !linear) {
+ AUD_WARNING("null");
+ return;
+ }
+
+
+ dynamic_change_ring_buf_size(rb, count);
+ audio_ringbuf_copy_from_linear_impl(rb, linear, count);
+}
+
+
+void audio_ringbuf_copy_from_ringbuf_impl(
+ struct audio_ringbuf_t *rb_des,
+ struct audio_ringbuf_t *rb_src,
+ uint32_t count) {
+ char *end = NULL;
+ uint32_t r2e = 0;
+
+ if (!count) {
+ return;
+ }
+ if (!rb_des || !rb_src) {
+ AUD_WARNING("null");
+ return;
+ }
+ if (!rb_src->base || !rb_src->size) {
+ DUMP_RINGBUF(AUD_LOG_W, "no init", rb_src, count);
+ AUD_WARNING("no init");
+ return;
+ }
+ if (count > audio_ringbuf_count(rb_src)) {
+ DUMP_RINGBUF(AUD_LOG_W, "underflow", rb_src, count);
+ AUD_WARNING("underflow");
+ return;
+ }
+ if (count > audio_ringbuf_free_space(rb_des)) {
+ DUMP_RINGBUF(AUD_LOG_W, "overflow", rb_des, count);
+ AUD_WARNING("overflow");
+ return;
+ }
+
+
+ if (rb_src->read <= rb_src->write) {
+ audio_ringbuf_copy_from_linear_impl(
+ rb_des,
+ rb_src->read,
+ count);
+ rb_src->read += count;
+ } else {
+ end = rb_src->base + rb_src->size;
+ r2e = end - rb_src->read;
+ if (r2e >= count) {
+ audio_ringbuf_copy_from_linear_impl(
+ rb_des,
+ rb_src->read,
+ count);
+ rb_src->read += count;
+ if (rb_src->read == end) {
+ rb_src->read = rb_src->base;
+ }
+ } else {
+ audio_ringbuf_copy_from_linear_impl(
+ rb_des,
+ rb_src->read,
+ r2e);
+ audio_ringbuf_copy_from_linear_impl(
+ rb_des,
+ rb_src->base,
+ count - r2e);
+ rb_src->read = rb_src->base + count - r2e;
+ }
+ }
+}
+
+
+void audio_ringbuf_copy_from_ringbuf(
+ struct audio_ringbuf_t *rb_des,
+ struct audio_ringbuf_t *rb_src,
+ uint32_t count) {
+ if (!count) {
+ return;
+ }
+ if (!rb_des || !rb_src) {
+ AUD_WARNING("null");
+ return;
+ }
+ if (!rb_src->base || !rb_src->size) {
+ DUMP_RINGBUF(AUD_LOG_W, "no init", rb_src, count);
+ AUD_WARNING("no init");
+ return;
+ }
+ if (count > audio_ringbuf_count(rb_src)) {
+ DUMP_RINGBUF(AUD_LOG_W, "underflow", rb_src, count);
+ AUD_WARNING("underflow");
+ return;
+ }
+
+ dynamic_change_ring_buf_size(rb_des, count);
+ audio_ringbuf_copy_from_ringbuf_impl(rb_des, rb_src, count);
+}
+
+
+void audio_ringbuf_copy_from_ringbuf_all(
+ struct audio_ringbuf_t *rb_des,
+ struct audio_ringbuf_t *rb_src) {
+ if (!rb_des || !rb_src) {
+ AUD_WARNING("null");
+ return;
+ }
+ audio_ringbuf_copy_from_ringbuf(
+ rb_des,
+ rb_src,
+ audio_ringbuf_count(rb_src));
+}
+
+
+void audio_ringbuf_write_value(
+ struct audio_ringbuf_t *rb,
+ const uint8_t value,
+ const uint32_t count) {
+ char *end = NULL;
+ uint32_t w2e = 0;
+
+ if (!count) {
+ return;
+ }
+ if (!rb) {
+ AUD_WARNING("null");
+ return;
+ }
+
+ dynamic_change_ring_buf_size(rb, count);
+ if (!rb->base || !rb->size) {
+ DUMP_RINGBUF(AUD_LOG_W, "no init", rb, count);
+ AUD_WARNING("no init");
+ return;
+ }
+ if (count > audio_ringbuf_free_space(rb)) {
+ DUMP_RINGBUF(AUD_LOG_W, "overflow", rb, count);
+ AUD_WARNING("overflow");
+ return;
+ }
+
+
+ end = rb->base + rb->size;
+
+ if (rb->read <= rb->write) {
+ w2e = end - rb->write;
+ if (count <= w2e) {
+ memset(rb->write, value, count);
+ rb->write += count;
+ if (rb->write == end) {
+ rb->write = rb->base;
+ }
+ } else {
+ memset(rb->write, value, w2e);
+ memset(rb->base, value, count - w2e);
+ rb->write = rb->base + count - w2e;
+ }
+ } else {
+ memset(rb->write, value, count);
+ rb->write += count;
+ }
+}
+
+
+void audio_ringbuf_write_zero(struct audio_ringbuf_t *rb, uint32_t count) {
+ if (!count) {
+ return;
+ }
+ if (!rb) {
+ AUD_WARNING("null");
+ return;
+ }
+
+ audio_ringbuf_write_value(rb, 0, count);
+}
+
+
+void audio_ringbuf_drop_data(struct audio_ringbuf_t *rb, const uint32_t count) {
+ char *end = NULL;
+ uint32_t r2e = 0;
+
+ if (!count) {
+ return;
+ }
+ if (!rb) {
+ AUD_WARNING("null");
+ return;
+ }
+ if (count > audio_ringbuf_count(rb)) {
+ DUMP_RINGBUF(AUD_LOG_W, "underflow", rb, count);
+ AUD_WARNING("underflow");
+ return;
+ }
+
+ if (rb->read <= rb->write) {
+ rb->read += count;
+ } else {
+ end = rb->base + rb->size;
+ r2e = end - rb->read;
+ if (count <= r2e) {
+ rb->read += count;
+ if (rb->read == end) {
+ rb->read = rb->base;
+ }
+ } else {
+ rb->read = rb->base + count - r2e;
+ }
+ }
+}
+
+
+void audio_ringbuf_drop_all(struct audio_ringbuf_t *rb) {
+ if (!rb) {
+ AUD_WARNING("null");
+ return;
+ }
+
+ rb->read = 0;
+ rb->write = 0;
+}
+
+
+void audio_ringbuf_compensate_value_impl(
+ struct audio_ringbuf_t *rb,
+ const uint8_t value,
+ const uint32_t count) {
+ char *end = NULL;
+
+ uint32_t b2r = 0;
+ uint32_t left_data = 0;
+
+ if (!count) {
+ return;
+ }
+ if (!rb) {
+ AUD_WARNING("null");
+ return;
+ }
+
+ if (!rb->base || !rb->size) {
+ DUMP_RINGBUF(AUD_LOG_W, "no init", rb, count);
+ AUD_WARNING("no init");
+ return;
+ }
+ if (count > audio_ringbuf_free_space(rb)) {
+ DUMP_RINGBUF(AUD_LOG_W, "overflow", rb, count);
+ AUD_WARNING("overflow");
+ return;
+ }
+
+ end = rb->base + rb->size;
+
+ if (rb->read <= rb->write) {
+ b2r = rb->read - rb->base;
+ if (b2r >= count) {
+ rb->read -= count;
+ memset(rb->read, value, count);
+ } else {
+ if (b2r > 0) { /* in case read == base */
+ memset(rb->base, value, b2r);
+ left_data = count - b2r;
+ rb->read = end - left_data;
+ memset(rb->read, value, left_data);
+ } else {
+ rb->read = end - count;
+ memset(rb->read, value, count);
+ }
+ }
+ } else {
+ rb->read -= count;
+ memset(rb->read, value, count);
+ }
+}
+
+
+void audio_ringbuf_compensate_value(
+ struct audio_ringbuf_t *rb,
+ const uint8_t value,
+ const uint32_t count) {
+ if (!count) {
+ return;
+ }
+ if (!rb) {
+ AUD_WARNING("null");
+ return;
+ }
+
+ dynamic_change_ring_buf_size(rb, count);
+ audio_ringbuf_compensate_value_impl(rb, value, count);
+}
+
+
+void audio_ringbuf_rollback(struct audio_ringbuf_t *rb, const uint32_t count) {
+ char *end = NULL;
+
+ uint32_t b2r = 0;
+ uint32_t left_data = 0;
+
+ if (!count) {
+ return;
+ }
+ if (!rb) {
+ AUD_WARNING("null");
+ return;
+ }
+ if (count > audio_ringbuf_free_space(rb)) {
+ AUD_WARNING("overflow");
+ return;
+ }
+
+
+ b2r = rb->read - rb->base;
+ end = rb->base + rb->size;
+
+ if (rb->read <= rb->write) {
+ b2r = rb->read - rb->base;
+ if (b2r >= count) {
+ rb->read -= count;
+ } else {
+ if (b2r > 0) { /* in case read == base */
+ left_data = count - b2r;
+ rb->read = end - left_data;
+ } else {
+ rb->read = end - count;
+ }
+ }
+ } else {
+ rb->read -= count;
+ }
+}
+
+
+void dynamic_change_ring_buf_size(
+ struct audio_ringbuf_t *rb,
+ uint32_t write_size) {
+ uint32_t data_count = 0;
+ uint32_t free_space = 0;
+
+ uint32_t change_size = 0;
+ struct audio_ringbuf_t new_ringbuf;
+
+ if (!rb) {
+ AUD_WARNING("null");
+ return;
+ }
+ if (!write_size) {
+ return;
+ }
+
+ memset(&new_ringbuf, 0, sizeof(struct audio_ringbuf_t));
+
+ if (!rb->base || !rb->size) { /* init */
+ change_size = (2 * write_size);
+ change_size += MAX_SIZE_OF_ONE_FRAME;
+
+ AUDIO_ALLOC_CHAR_BUFFER(rb->base, change_size);
+ rb->read = rb->base;
+ rb->write = rb->base;
+ rb->size = change_size;
+ } else { /* update size */
+ data_count = audio_ringbuf_count(rb);
+ free_space = audio_ringbuf_free_space(rb);
+
+ if ((free_space < write_size) ||
+ (free_space > (8 * (data_count + write_size)))) {
+ change_size = (2 * (data_count + write_size));
+ change_size += MAX_SIZE_OF_ONE_FRAME;
+
+ AUD_LOG_D("%s(), %p: %u -> %u, data_count %u, write_size %u, free_space %u",
+ __FUNCTION__,
+ rb->base,
+ rb->size,
+ change_size,
+ data_count,
+ write_size,
+ free_space);
+
+ AUDIO_ALLOC_CHAR_BUFFER(new_ringbuf.base, change_size);
+ new_ringbuf.read = new_ringbuf.base;
+ new_ringbuf.write = new_ringbuf.base;
+ new_ringbuf.size = change_size;
+
+ /* copy old data */
+ audio_ringbuf_copy_from_ringbuf_impl(
+ &new_ringbuf,
+ rb,
+ data_count);
+
+ /* delete old ringbuf */
+ AUDIO_FREE_POINTER(rb->base);
+
+ /* update info */
+ rb->base = new_ringbuf.base;
+ rb->read = new_ringbuf.read;
+ rb->write = new_ringbuf.write;
+ rb->size = new_ringbuf.size;
+
+ memset(&new_ringbuf, 0, sizeof(struct audio_ringbuf_t));
+ }
+ }
+}
+
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_ringbuf.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_ringbuf.h
new file mode 100644
index 0000000..ce93044
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_ringbuf.h
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_RING_BUF_H
+#define AUDIO_RING_BUF_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct audio_ringbuf_t {
+ char *base;
+ char *read;
+ char *write;
+ uint32_t size;
+} audio_ringbuf_t;
+
+
+uint32_t audio_ringbuf_count(const struct audio_ringbuf_t *rb);
+
+uint32_t audio_ringbuf_free_space(const struct audio_ringbuf_t *rb);
+
+
+void audio_ringbuf_copy_to_linear(
+ char *linear,
+ struct audio_ringbuf_t *rb,
+ uint32_t count);
+
+void audio_ringbuf_copy_from_linear(
+ struct audio_ringbuf_t *rb,
+ const char *linear,
+ uint32_t count);
+
+void audio_ringbuf_copy_from_linear_impl(
+ struct audio_ringbuf_t *rb,
+ const char *linear,
+ uint32_t count);
+
+
+void audio_ringbuf_copy_from_ringbuf(
+ struct audio_ringbuf_t *rb_des,
+ struct audio_ringbuf_t *rb_src,
+ uint32_t count);
+
+void audio_ringbuf_copy_from_ringbuf_impl(
+ struct audio_ringbuf_t *rb_des,
+ struct audio_ringbuf_t *rb_src,
+ uint32_t count);
+
+void audio_ringbuf_copy_from_ringbuf_all(
+ struct audio_ringbuf_t *rb_des,
+ struct audio_ringbuf_t *rb_src);
+
+
+void audio_ringbuf_write_value(
+ struct audio_ringbuf_t *rb,
+ const uint8_t value,
+ const uint32_t count);
+
+void audio_ringbuf_write_zero(struct audio_ringbuf_t *rb, uint32_t count);
+
+
+void audio_ringbuf_drop_data(struct audio_ringbuf_t *rb, const uint32_t count);
+
+void audio_ringbuf_drop_all(struct audio_ringbuf_t *rb);
+
+
+void audio_ringbuf_compensate_value(
+ struct audio_ringbuf_t *rb,
+ const uint8_t value,
+ const uint32_t count);
+
+void audio_ringbuf_compensate_value_impl(
+ struct audio_ringbuf_t *rb,
+ const uint8_t value,
+ const uint32_t count);
+
+
+void audio_ringbuf_rollback(struct audio_ringbuf_t *rb, const uint32_t count);
+
+
+void dynamic_change_ring_buf_size(
+ struct audio_ringbuf_t *rb,
+ uint32_t write_size);
+
+
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* end of AUDIO_RING_BUF_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_sample_rate.c b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_sample_rate.c
new file mode 100644
index 0000000..d35c065
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_sample_rate.c
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "audio_sample_rate.h"
+
+#include <string.h>
+
+#include <audio_log.h>
+#include <audio_assert.h>
+#include <audio_memory_control.h>
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * =============================================================================
+ * MACRO
+ * =============================================================================
+ */
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AudioSampleRate"
+
+
+/* http://stackoverflow.com/questions/53161/find-the-highest-order-bit-in-c */
+static int highest_order_bit(uint32_t n) {
+ n |= (n >> 1);
+ n |= (n >> 2);
+ n |= (n >> 4);
+ n |= (n >> 8);
+ n |= (n >> 16);
+ return n - (n >> 1);
+}
+
+
+/* FROM: <cutils/bitops.h> */
+/* use emulated popcount optimization */
+/* http://www.df.lth.se/~john_e/gems/gem002d.html */
+#define AUDIO_POP_COUNT(u32_value) \
+ ({ \
+ uint32_t __ret = (u32_value); \
+ __ret = ((__ret & 0x55555555) + ((__ret >> 1) & 0x55555555)); \
+ __ret = ((__ret & 0x33333333) + ((__ret >> 2) & 0x33333333)); \
+ __ret = ((__ret & 0x0f0f0f0f) + ((__ret >> 4) & 0x0f0f0f0f)); \
+ __ret = ((__ret & 0x00ff00ff) + ((__ret >> 8) & 0x00ff00ff)); \
+ __ret = (__ret & 0x0000ffff) + (__ret >> 16); \
+ __ret; \
+ })
+
+
+/*
+ * =============================================================================
+ * utilities implementation
+ * =============================================================================
+ */
+
+audio_sample_rate_mask_t audio_sample_rate_string_to_masks(const char *string) {
+ audio_sample_rate_mask_t mask = 0;
+
+ char *copy_string = NULL;
+ uint32_t copy_size = 0;
+
+ char *current = NULL;
+ char *comma = NULL;
+
+ if (string == NULL) {
+ AUD_LOG_W("%s(), string == NULL!! return 0", __FUNCTION__);
+ return 0;
+ }
+ if (strlen(string) == 0) {
+ AUD_LOG_W("%s(), strlen(string) == 0!! return 0", __FUNCTION__);
+ return 0;
+ }
+
+ AUD_LOG_V("%s", string);
+
+
+ copy_size = strlen(string) + 1;
+ AUDIO_ALLOC_CHAR_BUFFER(copy_string, copy_size + 1);
+ strncpy(copy_string, string, copy_size);
+
+ current = copy_string;
+ comma = strstr(current, ",");
+ while (comma != NULL) {
+ *comma = '\0';
+ mask |= audio_sample_rate_num_to_mask(atoi(current));
+
+ current = comma + 1;
+ comma = strstr(current, ",");
+ }
+ mask |= audio_sample_rate_num_to_mask(atoi(current));
+
+
+ AUDIO_FREE(copy_string);
+ return mask;
+}
+
+
+audio_sample_rate_mask_t audio_sample_rate_num_to_mask(const uint32_t rate) {
+ audio_sample_rate_mask_t mask = AUDIO_SAMPLE_RATE_MASK_INVALID;
+
+ switch (rate) {
+ case 8000:
+ mask = AUDIO_SAMPLE_RATE_MASK_8000;
+ break;
+ case 11025:
+ mask = AUDIO_SAMPLE_RATE_MASK_11025;
+ break;
+ case 12000:
+ mask = AUDIO_SAMPLE_RATE_MASK_12000;
+ break;
+ case 16000:
+ mask = AUDIO_SAMPLE_RATE_MASK_16000;
+ break;
+ case 22050:
+ mask = AUDIO_SAMPLE_RATE_MASK_22050;
+ break;
+ case 24000:
+ mask = AUDIO_SAMPLE_RATE_MASK_24000;
+ break;
+ case 32000:
+ mask = AUDIO_SAMPLE_RATE_MASK_32000;
+ break;
+ case 44100:
+ mask = AUDIO_SAMPLE_RATE_MASK_44100;
+ break;
+ case 48000:
+ mask = AUDIO_SAMPLE_RATE_MASK_48000;
+ break;
+ case 64000:
+ mask = AUDIO_SAMPLE_RATE_MASK_64000;
+ break;
+ case 88200:
+ mask = AUDIO_SAMPLE_RATE_MASK_88200;
+ break;
+ case 96000:
+ mask = AUDIO_SAMPLE_RATE_MASK_96000;
+ break;
+ case 128000:
+ mask = AUDIO_SAMPLE_RATE_MASK_128000;
+ break;
+ case 176400:
+ mask = AUDIO_SAMPLE_RATE_MASK_176400;
+ break;
+ case 192000:
+ mask = AUDIO_SAMPLE_RATE_MASK_192000;
+ break;
+ default:
+ AUD_LOG_W("%s() not support rate %u", __FUNCTION__, rate);
+ mask = AUDIO_SAMPLE_RATE_MASK_INVALID;
+ break;
+ }
+
+ AUD_LOG_V("%u -> 0x%x", rate, mask);
+
+ AUD_ASSERT(mask != AUDIO_SAMPLE_RATE_MASK_INVALID);
+ return mask;
+}
+
+
+uint32_t audio_sample_rate_mask_to_num(const audio_sample_rate_mask_t mask) {
+ uint32_t rate = 0;
+
+ AUD_ASSERT(AUDIO_POP_COUNT(mask) == 1);
+
+ switch (mask) {
+ case AUDIO_SAMPLE_RATE_MASK_8000:
+ rate = 8000;
+ break;
+ case AUDIO_SAMPLE_RATE_MASK_11025:
+ rate = 11025;
+ break;
+ case AUDIO_SAMPLE_RATE_MASK_12000:
+ rate = 12000;
+ break;
+ case AUDIO_SAMPLE_RATE_MASK_16000:
+ rate = 16000;
+ break;
+ case AUDIO_SAMPLE_RATE_MASK_22050:
+ rate = 22050;
+ break;
+ case AUDIO_SAMPLE_RATE_MASK_24000:
+ rate = 24000;
+ break;
+ case AUDIO_SAMPLE_RATE_MASK_32000:
+ rate = 32000;
+ break;
+ case AUDIO_SAMPLE_RATE_MASK_44100:
+ rate = 44100;
+ break;
+ case AUDIO_SAMPLE_RATE_MASK_48000:
+ rate = 48000;
+ break;
+ case AUDIO_SAMPLE_RATE_MASK_64000:
+ rate = 64000;
+ break;
+ case AUDIO_SAMPLE_RATE_MASK_88200:
+ rate = 88200;
+ break;
+ case AUDIO_SAMPLE_RATE_MASK_96000:
+ rate = 96000;
+ break;
+ case AUDIO_SAMPLE_RATE_MASK_128000:
+ rate = 128000;
+ break;
+ case AUDIO_SAMPLE_RATE_MASK_176400:
+ rate = 176400;
+ break;
+ case AUDIO_SAMPLE_RATE_MASK_192000:
+ rate = 192000;
+ break;
+ default:
+ AUD_LOG_W("%s() not support mask 0x%x", __FUNCTION__, mask);
+ rate = 0;
+ break;
+ }
+
+ AUD_ASSERT(rate != 0);
+ return rate;
+}
+
+
+uint32_t audio_sample_rate_get_max_rate(const audio_sample_rate_mask_t masks) {
+ return audio_sample_rate_mask_to_num(highest_order_bit(masks));
+}
+
+
+uint32_t audio_sample_rate_get_match_rate(
+ const audio_sample_rate_mask_t masks,
+ const uint32_t rate) {
+ uint32_t ret_rate = 0;
+
+ audio_sample_rate_mask_t mask = audio_sample_rate_num_to_mask(rate);
+
+ AUD_LOG_V("%s(), masks 0x%x, rate %u, mask 0x%x", __FUNCTION__,
+ masks, rate, mask);
+
+ if (mask & masks) { /* support */
+ ret_rate = rate;
+ } else { /* not support -> get highest supported rate */
+ ret_rate = audio_sample_rate_get_max_rate(masks);
+ }
+
+ return ret_rate;
+}
+
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_sample_rate.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_sample_rate.h
new file mode 100644
index 0000000..744cd28
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_sample_rate.h
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_SAMPLE_RATE_H
+#define AUDIO_SAMPLE_RATE_H
+
+#include <stdint.h>
+
+enum {
+ AUDIO_SAMPLE_RATE_BIT_8000,
+ AUDIO_SAMPLE_RATE_BIT_11025,
+ AUDIO_SAMPLE_RATE_BIT_12000,
+ AUDIO_SAMPLE_RATE_BIT_16000,
+ AUDIO_SAMPLE_RATE_BIT_22050,
+ AUDIO_SAMPLE_RATE_BIT_24000,
+ AUDIO_SAMPLE_RATE_BIT_32000,
+ AUDIO_SAMPLE_RATE_BIT_44100,
+ AUDIO_SAMPLE_RATE_BIT_48000,
+ AUDIO_SAMPLE_RATE_BIT_64000,
+ AUDIO_SAMPLE_RATE_BIT_88200,
+ AUDIO_SAMPLE_RATE_BIT_96000,
+ AUDIO_SAMPLE_RATE_BIT_128000,
+ AUDIO_SAMPLE_RATE_BIT_176400,
+ AUDIO_SAMPLE_RATE_BIT_192000,
+
+ AUDIO_SAMPLE_RATE_BIT_INVALID
+};
+
+
+enum {
+ AUDIO_SAMPLE_RATE_MASK_8000 = (1 << AUDIO_SAMPLE_RATE_BIT_8000),
+ AUDIO_SAMPLE_RATE_MASK_11025 = (1 << AUDIO_SAMPLE_RATE_BIT_11025),
+ AUDIO_SAMPLE_RATE_MASK_12000 = (1 << AUDIO_SAMPLE_RATE_BIT_12000),
+ AUDIO_SAMPLE_RATE_MASK_16000 = (1 << AUDIO_SAMPLE_RATE_BIT_16000),
+ AUDIO_SAMPLE_RATE_MASK_22050 = (1 << AUDIO_SAMPLE_RATE_BIT_22050),
+ AUDIO_SAMPLE_RATE_MASK_24000 = (1 << AUDIO_SAMPLE_RATE_BIT_24000),
+ AUDIO_SAMPLE_RATE_MASK_32000 = (1 << AUDIO_SAMPLE_RATE_BIT_32000),
+ AUDIO_SAMPLE_RATE_MASK_44100 = (1 << AUDIO_SAMPLE_RATE_BIT_44100),
+ AUDIO_SAMPLE_RATE_MASK_48000 = (1 << AUDIO_SAMPLE_RATE_BIT_48000),
+ AUDIO_SAMPLE_RATE_MASK_64000 = (1 << AUDIO_SAMPLE_RATE_BIT_64000),
+ AUDIO_SAMPLE_RATE_MASK_88200 = (1 << AUDIO_SAMPLE_RATE_BIT_88200),
+ AUDIO_SAMPLE_RATE_MASK_96000 = (1 << AUDIO_SAMPLE_RATE_BIT_96000),
+ AUDIO_SAMPLE_RATE_MASK_128000 = (1 << AUDIO_SAMPLE_RATE_BIT_128000),
+ AUDIO_SAMPLE_RATE_MASK_176400 = (1 << AUDIO_SAMPLE_RATE_BIT_176400),
+ AUDIO_SAMPLE_RATE_MASK_192000 = (1 << AUDIO_SAMPLE_RATE_BIT_192000),
+
+ AUDIO_SAMPLE_RATE_MASK_INVALID = (1 << AUDIO_SAMPLE_RATE_BIT_INVALID)
+};
+
+typedef uint32_t audio_sample_rate_mask_t;
+
+
+
+audio_sample_rate_mask_t audio_sample_rate_string_to_masks(const char *string);
+
+audio_sample_rate_mask_t audio_sample_rate_num_to_mask(const uint32_t rate);
+
+uint32_t audio_sample_rate_mask_to_num(const audio_sample_rate_mask_t mask);
+
+uint32_t audio_sample_rate_get_max_rate(const audio_sample_rate_mask_t masks);
+
+uint32_t audio_sample_rate_get_match_rate(
+ const audio_sample_rate_mask_t masks,
+ const uint32_t rate);
+
+
+#endif /* end of AUDIO_SAMPLE_RATE_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_time.c b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_time.c
new file mode 100644
index 0000000..2d93738
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_time.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "audio_time.h"
+
+#include <time.h>
+
+#include <audio_log.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void audio_get_timespec_realtime(struct timespec *ts) {
+ clock_gettime(CLOCK_REALTIME, ts);
+}
+
+
+void audio_get_timespec_monotonic(struct timespec *ts) {
+ clock_gettime(CLOCK_MONOTONIC, ts);
+}
+
+
+void audio_get_timespec_timeout(struct timespec *ts, uint32_t ms) {
+ audio_get_timespec_realtime(ts);
+
+ ts->tv_sec += ms / 1000;
+ ts->tv_nsec += (ms % 1000) * 1000000;
+ if (ts->tv_nsec >= 1000000000L) {
+ ts->tv_nsec -= 1000000000L;
+ ts->tv_sec += 1;
+ }
+}
+
+
+uint64_t audio_timespec_to_ns(struct timespec *ts) {
+ return ((uint64_t)ts->tv_sec * 1000000000L) + ts->tv_nsec;
+}
+
+
+uint64_t audio_timespec_to_ms(struct timespec *ts) {
+ return audio_timespec_to_ns(ts) / 1000000L;
+}
+
+
+bool t1_older_then_t2(struct timespec *t1, struct timespec *t2) {
+ return (audio_timespec_to_ns(t1) < audio_timespec_to_ns(t2));
+}
+
+
+uint64_t get_time_diff_ns(struct timespec *t_old, struct timespec *t_new) {
+ uint64_t t_old_ns = audio_timespec_to_ns(t_old);
+ uint64_t t_new_ns = audio_timespec_to_ns(t_new);
+
+ return ((t_new_ns > t_old_ns)
+ ? (t_new_ns - t_old_ns)
+ : ((UINTMAX_MAX - t_old_ns) + t_new_ns + 1));
+}
+
+
+uint64_t get_time_diff_ms(struct timespec *t_old, struct timespec *t_new) {
+ uint64_t t_old_ms = audio_timespec_to_ms(t_old);
+ uint64_t t_new_ms = audio_timespec_to_ms(t_new);
+
+ return ((t_new_ms > t_old_ms)
+ ? (t_new_ms - t_old_ms)
+ : ((UINTMAX_MAX - t_old_ms) + t_new_ms + 1));
+}
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_time.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_time.h
new file mode 100644
index 0000000..add8827
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/audio_time.h
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#ifndef AUDIO_TIME_H
+#define AUDIO_TIME_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct timespec;
+
+void audio_get_timespec_realtime(struct timespec *ts);
+
+void audio_get_timespec_monotonic(struct timespec *ts);
+
+void audio_get_timespec_timeout(struct timespec *ts, uint32_t ms);
+
+uint64_t audio_timespec_to_ns(struct timespec *ts);
+
+uint64_t audio_timespec_to_ms(struct timespec *ts);
+
+bool t1_older_then_t2(struct timespec *t1, struct timespec *t2);
+
+uint64_t get_time_diff_ns(struct timespec *t_old, struct timespec *t_new);
+
+uint64_t get_time_diff_ms(struct timespec *t_old, struct timespec *t_new);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* end of AUDIO_TIME_H */
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/LICENSE b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/LICENSE
new file mode 100644
index 0000000..088f613
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/LICENSE
@@ -0,0 +1,21 @@
+Copyright (c) 2005-2014, Troy D. Hanson http://troydhanson.github.com/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/NOTICE b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/NOTICE
new file mode 100644
index 0000000..a186099
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/NOTICE
@@ -0,0 +1,23 @@
+Copyright (c) 2005-2016, Troy D. Hanson http://troydhanson.github.com/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/README b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/README
new file mode 100644
index 0000000..3adebca
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/README
@@ -0,0 +1,6 @@
+
+Documentation for uthash is available at:
+
+http://troydhanson.github.com/uthash/
+
+
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/utarray.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/utarray.h
new file mode 100644
index 0000000..39abcf2
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/utarray.h
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+Copyright (c) 2008-2017, Troy D. Hanson http://troydhanson.github.com/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* a dynamic array implementation using macros
+ */
+#ifndef UTARRAY_H
+#define UTARRAY_H
+
+#define UTARRAY_VERSION 2.0.2
+
+#include <stddef.h> /* size_t */
+#include <string.h> /* memset, etc */
+#include <stdlib.h> /* exit */
+
+#include <audio_memory_control.h>
+
+#ifndef uthash_malloc
+#define uthash_malloc(sz) AUDIO_MALLOC(sz) /* malloc fcn */
+#endif
+#ifndef uthash_free
+#define uthash_free(ptr) AUDIO_FREE(ptr) /* free fcn */
+#endif
+
+#ifdef __GNUC__
+#define UTARRAY_UNUSED __attribute__((__unused__))
+#else
+#define UTARRAY_UNUSED
+#endif
+
+#ifndef oom
+#define oom() exit(-1)
+#endif
+
+typedef void (ctor_f)(void *dst, const void *src);
+typedef void (dtor_f)(void *elt);
+typedef void (init_f)(void *elt);
+typedef struct {
+ size_t sz;
+ init_f *init;
+ ctor_f *copy;
+ dtor_f *dtor;
+} UT_icd;
+
+typedef struct {
+ unsigned i,n;/* i: index of next available slot, n: num slots */
+ UT_icd icd; /* initializer, copy and destructor functions */
+ char *d; /* n slots of size icd->sz*/
+} UT_array;
+
+#define utarray_init(a,_icd) do { \
+ memset(a,0,sizeof(UT_array)); \
+ (a)->icd = *(_icd); \
+} while(0)
+
+#define utarray_done(a) do { \
+ if ((a)->n) { \
+ if ((a)->icd.dtor) { \
+ unsigned _ut_i; \
+ for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \
+ (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \
+ } \
+ } \
+ uthash_free((a)->d); \
+ } \
+ (a)->n=0; \
+} while(0)
+
+#define utarray_new(a,_icd) do { \
+ (a) = (UT_array*)uthash_malloc(sizeof(UT_array)); \
+ if ((a) == NULL) oom(); \
+ utarray_init(a,_icd); \
+} while(0)
+
+#define utarray_free(a) do { \
+ utarray_done(a); \
+ uthash_free(a); \
+} while(0)
+
+#define utarray_reserve(a,by) do { \
+ if (((a)->i+(by)) > (a)->n) { \
+ char *utarray_tmp; \
+ while (((a)->i+(by)) > (a)->n) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \
+ utarray_tmp=(char*)realloc((a)->d, (a)->n*(a)->icd.sz); \
+ if (utarray_tmp == NULL) oom(); \
+ (a)->d=utarray_tmp; \
+ } \
+} while(0)
+
+#define utarray_push_back(a,p) do { \
+ utarray_reserve(a,1); \
+ if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \
+ else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \
+} while(0)
+
+#define utarray_pop_back(a) do { \
+ if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \
+ else { (a)->i--; } \
+} while(0)
+
+#define utarray_extend_back(a) do { \
+ utarray_reserve(a,1); \
+ if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \
+ else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \
+ (a)->i++; \
+} while(0)
+
+#define utarray_len(a) ((a)->i)
+
+#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL)
+#define _utarray_eltptr(a,j) ((a)->d + ((a)->icd.sz * (j)))
+
+#define utarray_insert(a,p,j) do { \
+ if ((j) > (a)->i) utarray_resize(a,j); \
+ utarray_reserve(a,1); \
+ if ((j) < (a)->i) { \
+ memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \
+ ((a)->i - (j))*((a)->icd.sz)); \
+ } \
+ if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \
+ else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \
+ (a)->i++; \
+} while(0)
+
+#define utarray_inserta(a,w,j) do { \
+ if (utarray_len(w) == 0) break; \
+ if ((j) > (a)->i) utarray_resize(a,j); \
+ utarray_reserve(a,utarray_len(w)); \
+ if ((j) < (a)->i) { \
+ memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \
+ _utarray_eltptr(a,j), \
+ ((a)->i - (j))*((a)->icd.sz)); \
+ } \
+ if ((a)->icd.copy) { \
+ unsigned _ut_i; \
+ for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \
+ (a)->icd.copy(_utarray_eltptr(a, (j) + _ut_i), _utarray_eltptr(w, _ut_i)); \
+ } \
+ } else { \
+ memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \
+ utarray_len(w)*((a)->icd.sz)); \
+ } \
+ (a)->i += utarray_len(w); \
+} while(0)
+
+#define utarray_resize(dst,num) do { \
+ unsigned _ut_i; \
+ if ((dst)->i > (unsigned)(num)) { \
+ if ((dst)->icd.dtor) { \
+ for (_ut_i = (num); _ut_i < (dst)->i; ++_ut_i) { \
+ (dst)->icd.dtor(_utarray_eltptr(dst, _ut_i)); \
+ } \
+ } \
+ } else if ((dst)->i < (unsigned)(num)) { \
+ utarray_reserve(dst, (num) - (dst)->i); \
+ if ((dst)->icd.init) { \
+ for (_ut_i = (dst)->i; _ut_i < (unsigned)(num); ++_ut_i) { \
+ (dst)->icd.init(_utarray_eltptr(dst, _ut_i)); \
+ } \
+ } else { \
+ memset(_utarray_eltptr(dst, (dst)->i), 0, (dst)->icd.sz*((num) - (dst)->i)); \
+ } \
+ } \
+ (dst)->i = (num); \
+} while(0)
+
+#define utarray_concat(dst,src) do { \
+ utarray_inserta(dst, src, utarray_len(dst)); \
+} while(0)
+
+#define utarray_erase(a,pos,len) do { \
+ if ((a)->icd.dtor) { \
+ unsigned _ut_i; \
+ for (_ut_i = 0; _ut_i < (len); _ut_i++) { \
+ (a)->icd.dtor(utarray_eltptr(a, (pos) + _ut_i)); \
+ } \
+ } \
+ if ((a)->i > ((pos) + (len))) { \
+ memmove(_utarray_eltptr(a, pos), _utarray_eltptr(a, (pos) + (len)), \
+ ((a)->i - ((pos) + (len))) * (a)->icd.sz); \
+ } \
+ (a)->i -= (len); \
+} while(0)
+
+#define utarray_renew(a,u) do { \
+ if (a) utarray_clear(a); \
+ else utarray_new(a, u); \
+} while(0)
+
+#define utarray_clear(a) do { \
+ if ((a)->i > 0) { \
+ if ((a)->icd.dtor) { \
+ unsigned _ut_i; \
+ for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \
+ (a)->icd.dtor(_utarray_eltptr(a, _ut_i)); \
+ } \
+ } \
+ (a)->i = 0; \
+ } \
+} while(0)
+
+#define utarray_sort(a,cmp) do { \
+ qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \
+} while(0)
+
+#define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp)
+
+#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL)
+#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL))
+#define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) > 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL))
+#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL)
+#define utarray_eltidx(a,e) (((char*)(e) >= (a)->d) ? (((char*)(e) - (a)->d)/(a)->icd.sz) : -1)
+
+/* last we pre-define a few icd for common utarrays of ints and strings */
+static void utarray_str_cpy(void *dst, const void *src) {
+ char **_src = (char**)src, **_dst = (char**)dst;
+ *_dst = (*_src == NULL) ? NULL : strdup(*_src);
+}
+static void utarray_str_dtor(void *elt) {
+ char **eltc = (char**)elt;
+ if (*eltc != NULL) uthash_free(*eltc);
+}
+static const UT_icd ut_str_icd UTARRAY_UNUSED = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor};
+static const UT_icd ut_int_icd UTARRAY_UNUSED = {sizeof(int),NULL,NULL,NULL};
+static const UT_icd ut_ptr_icd UTARRAY_UNUSED = {sizeof(void*),NULL,NULL,NULL};
+
+
+#endif /* UTARRAY_H */
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/uthash.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/uthash.h
new file mode 100644
index 0000000..a867dde
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/uthash.h
@@ -0,0 +1,1220 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+Copyright (c) 2003-2017, Troy D. Hanson http://troydhanson.github.com/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef UTHASH_H
+#define UTHASH_H
+
+#define UTHASH_VERSION 2.0.2
+
+#include <string.h> /* memcmp, memset, strlen */
+#include <stddef.h> /* ptrdiff_t */
+#include <stdlib.h> /* exit */
+
+#include <audio_memory_control.h>
+
+/* These macros use decltype or the earlier __typeof GNU extension.
+ As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+ when compiling c++ source) this code uses whatever method is needed
+ or, for VS2008 where neither is available, uses casting workarounds. */
+#if !defined(DECLTYPE) && !defined(NO_DECLTYPE)
+#if defined(_MSC_VER) /* MS compiler */
+#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
+#define DECLTYPE(x) (decltype(x))
+#else /* VS2008 or older (or VS2010 in C mode) */
+#define NO_DECLTYPE
+#endif
+#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__)
+#define NO_DECLTYPE
+#else /* GNU, Sun and other compilers */
+#define DECLTYPE(x) (__typeof(x))
+#endif
+#endif
+
+#ifdef NO_DECLTYPE
+#define DECLTYPE(x)
+#define DECLTYPE_ASSIGN(dst,src) \
+do { \
+ char **_da_dst = (char**)(&(dst)); \
+ *_da_dst = (char*)(src); \
+} while (0)
+#else
+#define DECLTYPE_ASSIGN(dst,src) \
+do { \
+ (dst) = DECLTYPE(dst)(src); \
+} while (0)
+#endif
+
+/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */
+#if defined(_WIN32)
+#if defined(_MSC_VER) && _MSC_VER >= 1600
+#include <stdint.h>
+#elif defined(__WATCOMC__) || defined(__MINGW32__) || defined(__CYGWIN__)
+#include <stdint.h>
+#else
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+#endif
+#elif defined(__GNUC__) && !defined(__VXWORKS__)
+#include <stdint.h>
+#else
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+#endif
+
+#ifndef uthash_malloc
+#define uthash_malloc(sz) AUDIO_MALLOC(sz) /* malloc fcn */
+#endif
+#ifndef uthash_free
+#define uthash_free(ptr,sz) AUDIO_FREE(ptr) /* free fcn */
+#endif
+#ifndef uthash_bzero
+#define uthash_bzero(a,n) memset(a,'\0',n)
+#endif
+#ifndef uthash_memcmp
+#define uthash_memcmp(a,b,n) memcmp(a,b,n)
+#endif
+#ifndef uthash_strlen
+#define uthash_strlen(s) strlen(s)
+#endif
+
+#ifndef uthash_noexpand_fyi
+#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */
+#endif
+#ifndef uthash_expand_fyi
+#define uthash_expand_fyi(tbl) /* can be defined to log expands */
+#endif
+
+#ifndef HASH_NONFATAL_OOM
+#define HASH_NONFATAL_OOM 0
+#endif
+
+#if HASH_NONFATAL_OOM
+/* malloc failures can be recovered from */
+
+#ifndef uthash_nonfatal_oom
+#define uthash_nonfatal_oom(obj) do {} while (0) /* non-fatal OOM error */
+#endif
+
+#define HASH_RECORD_OOM(oomed) do { (oomed) = 1; } while (0)
+#define IF_HASH_NONFATAL_OOM(x) x
+
+#else
+/* malloc failures result in lost memory, hash tables are unusable */
+
+#ifndef uthash_fatal
+#define uthash_fatal(msg) exit(-1) /* fatal OOM error */
+#endif
+
+#define HASH_RECORD_OOM(oomed) uthash_fatal("out of memory")
+#define IF_HASH_NONFATAL_OOM(x)
+
+#endif
+
+/* initial number of buckets */
+#define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */
+#define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */
+#define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */
+
+/* calculate the element whose hash handle address is hhp */
+#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
+/* calculate the hash handle from element address elp */
+#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle *)(((char*)(elp)) + ((tbl)->hho)))
+
+#define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \
+do { \
+ struct UT_hash_handle *_hd_hh_item = (itemptrhh); \
+ unsigned _hd_bkt; \
+ HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
+ (head)->hh.tbl->buckets[_hd_bkt].count++; \
+ _hd_hh_item->hh_next = NULL; \
+ _hd_hh_item->hh_prev = NULL; \
+} while (0)
+
+#define HASH_VALUE(keyptr,keylen,hashv) \
+do { \
+ HASH_FCN(keyptr, keylen, hashv); \
+} while (0)
+
+#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \
+do { \
+ (out) = NULL; \
+ if (head) { \
+ unsigned _hf_bkt; \
+ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \
+ if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) { \
+ HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \
+ } \
+ } \
+} while (0)
+
+#define HASH_FIND(hh,head,keyptr,keylen,out) \
+do { \
+ unsigned _hf_hashv; \
+ HASH_VALUE(keyptr, keylen, _hf_hashv); \
+ HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \
+} while (0)
+
+#ifdef HASH_BLOOM
+#define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM)
+#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL)
+#define HASH_BLOOM_MAKE(tbl,oomed) \
+do { \
+ (tbl)->bloom_nbits = HASH_BLOOM; \
+ (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \
+ if (!(tbl)->bloom_bv) { \
+ HASH_RECORD_OOM(oomed); \
+ } else { \
+ uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \
+ (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \
+ } \
+} while (0)
+
+#define HASH_BLOOM_FREE(tbl) \
+do { \
+ uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \
+} while (0)
+
+#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U)))
+#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U)))
+
+#define HASH_BLOOM_ADD(tbl,hashv) \
+ HASH_BLOOM_BITSET((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U)))
+
+#define HASH_BLOOM_TEST(tbl,hashv) \
+ HASH_BLOOM_BITTEST((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U)))
+
+#else
+#define HASH_BLOOM_MAKE(tbl,oomed)
+#define HASH_BLOOM_FREE(tbl)
+#define HASH_BLOOM_ADD(tbl,hashv)
+#define HASH_BLOOM_TEST(tbl,hashv) (1)
+#define HASH_BLOOM_BYTELEN 0U
+#endif
+
+#define HASH_MAKE_TABLE(hh,head,oomed) \
+do { \
+ (head)->hh.tbl = (UT_hash_table*)uthash_malloc(sizeof(UT_hash_table)); \
+ if (!(head)->hh.tbl) { \
+ HASH_RECORD_OOM(oomed); \
+ } else { \
+ uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \
+ (head)->hh.tbl->tail = &((head)->hh); \
+ (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \
+ (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \
+ (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \
+ (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \
+ HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \
+ (head)->hh.tbl->signature = HASH_SIGNATURE; \
+ if (!(head)->hh.tbl->buckets) { \
+ HASH_RECORD_OOM(oomed); \
+ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
+ } else { \
+ uthash_bzero((head)->hh.tbl->buckets, \
+ HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \
+ HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \
+ IF_HASH_NONFATAL_OOM( \
+ if (oomed) { \
+ uthash_free((head)->hh.tbl->buckets, \
+ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
+ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
+ } \
+ ) \
+ } \
+ } \
+} while (0)
+
+#define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \
+do { \
+ (replaced) = NULL; \
+ HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \
+ if (replaced) { \
+ HASH_DELETE(hh, head, replaced); \
+ } \
+ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \
+} while (0)
+
+#define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \
+do { \
+ (replaced) = NULL; \
+ HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \
+ if (replaced) { \
+ HASH_DELETE(hh, head, replaced); \
+ } \
+ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \
+} while (0)
+
+#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \
+do { \
+ unsigned _hr_hashv; \
+ HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \
+ HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \
+} while (0)
+
+#define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \
+do { \
+ unsigned _hr_hashv; \
+ HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \
+ HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \
+} while (0)
+
+#define HASH_APPEND_LIST(hh, head, add) \
+do { \
+ (add)->hh.next = NULL; \
+ (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \
+ (head)->hh.tbl->tail->next = (add); \
+ (head)->hh.tbl->tail = &((add)->hh); \
+} while (0)
+
+#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \
+do { \
+ do { \
+ if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) { \
+ break; \
+ } \
+ } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \
+} while (0)
+
+#ifdef NO_DECLTYPE
+#undef HASH_AKBI_INNER_LOOP
+#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \
+do { \
+ char *_hs_saved_head = (char*)(head); \
+ do { \
+ DECLTYPE_ASSIGN(head, _hs_iter); \
+ if (cmpfcn(head, add) > 0) { \
+ DECLTYPE_ASSIGN(head, _hs_saved_head); \
+ break; \
+ } \
+ DECLTYPE_ASSIGN(head, _hs_saved_head); \
+ } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \
+} while (0)
+#endif
+
+#if HASH_NONFATAL_OOM
+
+#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \
+do { \
+ if (!(oomed)) { \
+ unsigned _ha_bkt; \
+ (head)->hh.tbl->num_items++; \
+ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \
+ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \
+ if (oomed) { \
+ HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \
+ HASH_DELETE_HH(hh, head, &(add)->hh); \
+ (add)->hh.tbl = NULL; \
+ uthash_nonfatal_oom(add); \
+ } else { \
+ HASH_BLOOM_ADD((head)->hh.tbl, hashval); \
+ HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \
+ } \
+ } else { \
+ (add)->hh.tbl = NULL; \
+ uthash_nonfatal_oom(add); \
+ } \
+} while (0)
+
+#else
+
+#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \
+do { \
+ unsigned _ha_bkt; \
+ (head)->hh.tbl->num_items++; \
+ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \
+ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \
+ HASH_BLOOM_ADD((head)->hh.tbl, hashval); \
+ HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \
+} while (0)
+
+#endif
+
+
+#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \
+do { \
+ IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \
+ (add)->hh.hashv = (hashval); \
+ (add)->hh.key = (char*) (keyptr); \
+ (add)->hh.keylen = (unsigned) (keylen_in); \
+ if (!(head)) { \
+ (add)->hh.next = NULL; \
+ (add)->hh.prev = NULL; \
+ HASH_MAKE_TABLE(hh, add, _ha_oomed); \
+ IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \
+ (head) = (add); \
+ IF_HASH_NONFATAL_OOM( } ) \
+ } else { \
+ void *_hs_iter = (head); \
+ (add)->hh.tbl = (head)->hh.tbl; \
+ HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \
+ if (_hs_iter) { \
+ (add)->hh.next = _hs_iter; \
+ if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \
+ HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \
+ } else { \
+ (head) = (add); \
+ } \
+ HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \
+ } else { \
+ HASH_APPEND_LIST(hh, head, add); \
+ } \
+ } \
+ HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \
+ HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \
+} while (0)
+
+#define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \
+do { \
+ unsigned _hs_hashv; \
+ HASH_VALUE(keyptr, keylen_in, _hs_hashv); \
+ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \
+} while (0)
+
+#define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \
+ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn)
+
+#define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \
+ HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn)
+
+#define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \
+do { \
+ IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \
+ (add)->hh.hashv = (hashval); \
+ (add)->hh.key = (char*) (keyptr); \
+ (add)->hh.keylen = (unsigned) (keylen_in); \
+ if (!(head)) { \
+ (add)->hh.next = NULL; \
+ (add)->hh.prev = NULL; \
+ HASH_MAKE_TABLE(hh, add, _ha_oomed); \
+ IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \
+ (head) = (add); \
+ IF_HASH_NONFATAL_OOM( } ) \
+ } else { \
+ (add)->hh.tbl = (head)->hh.tbl; \
+ HASH_APPEND_LIST(hh, head, add); \
+ } \
+ HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \
+ HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \
+} while (0)
+
+#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \
+do { \
+ unsigned _ha_hashv; \
+ HASH_VALUE(keyptr, keylen_in, _ha_hashv); \
+ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \
+} while (0)
+
+#define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \
+ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add)
+
+#define HASH_ADD(hh,head,fieldname,keylen_in,add) \
+ HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add)
+
+#define HASH_TO_BKT(hashv,num_bkts,bkt) \
+do { \
+ bkt = ((hashv) & ((num_bkts) - 1U)); \
+} while (0)
+
+/* delete "delptr" from the hash table.
+ * "the usual" patch-up process for the app-order doubly-linked-list.
+ * The use of _hd_hh_del below deserves special explanation.
+ * These used to be expressed using (delptr) but that led to a bug
+ * if someone used the same symbol for the head and deletee, like
+ * HASH_DELETE(hh,users,users);
+ * We want that to work, but by changing the head (users) below
+ * we were forfeiting our ability to further refer to the deletee (users)
+ * in the patch-up process. Solution: use scratch space to
+ * copy the deletee pointer, then the latter references are via that
+ * scratch pointer rather than through the repointed (users) symbol.
+ */
+#define HASH_DELETE(hh,head,delptr) \
+ HASH_DELETE_HH(hh, head, &(delptr)->hh)
+
+#define HASH_DELETE_HH(hh,head,delptrhh) \
+do { \
+ struct UT_hash_handle *_hd_hh_del = (delptrhh); \
+ if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \
+ HASH_BLOOM_FREE((head)->hh.tbl); \
+ uthash_free((head)->hh.tbl->buckets, \
+ (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
+ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
+ (head) = NULL; \
+ } else { \
+ unsigned _hd_bkt; \
+ if (_hd_hh_del == (head)->hh.tbl->tail) { \
+ (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \
+ } \
+ if (_hd_hh_del->prev != NULL) { \
+ HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \
+ } else { \
+ DECLTYPE_ASSIGN(head, _hd_hh_del->next); \
+ } \
+ if (_hd_hh_del->next != NULL) { \
+ HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \
+ } \
+ HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
+ HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \
+ (head)->hh.tbl->num_items--; \
+ } \
+ HASH_FSCK(hh, head, "HASH_DELETE_HH"); \
+} while (0)
+
+/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
+#define HASH_FIND_STR(head,findstr,out) \
+do { \
+ unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \
+ HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \
+} while (0)
+#define HASH_ADD_STR(head,strfield,add) \
+do { \
+ unsigned _uthash_hastr_keylen = (unsigned)uthash_strlen((add)->strfield); \
+ HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \
+} while (0)
+#define HASH_REPLACE_STR(head,strfield,add,replaced) \
+do { \
+ unsigned _uthash_hrstr_keylen = (unsigned)uthash_strlen((add)->strfield); \
+ HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, replaced); \
+} while (0)
+#define HASH_FIND_INT(head,findint,out) \
+ HASH_FIND(hh,head,findint,sizeof(int),out)
+#define HASH_ADD_INT(head,intfield,add) \
+ HASH_ADD(hh,head,intfield,sizeof(int),add)
+#define HASH_REPLACE_INT(head,intfield,add,replaced) \
+ HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced)
+#define HASH_FIND_PTR(head,findptr,out) \
+ HASH_FIND(hh,head,findptr,sizeof(void *),out)
+#define HASH_ADD_PTR(head,ptrfield,add) \
+ HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
+#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \
+ HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced)
+#define HASH_DEL(head,delptr) \
+ HASH_DELETE(hh,head,delptr)
+
+/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
+ * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
+ */
+#ifdef HASH_DEBUG
+#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
+#define HASH_FSCK(hh,head,where) \
+do { \
+ struct UT_hash_handle *_thh; \
+ if (head) { \
+ unsigned _bkt_i; \
+ unsigned _count = 0; \
+ char *_prev; \
+ for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \
+ unsigned _bkt_count = 0; \
+ _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \
+ _prev = NULL; \
+ while (_thh) { \
+ if (_prev != (char*)(_thh->hh_prev)) { \
+ HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \
+ (where), (void*)_thh->hh_prev, (void*)_prev); \
+ } \
+ _bkt_count++; \
+ _prev = (char*)(_thh); \
+ _thh = _thh->hh_next; \
+ } \
+ _count += _bkt_count; \
+ if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \
+ HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \
+ (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \
+ } \
+ } \
+ if (_count != (head)->hh.tbl->num_items) { \
+ HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \
+ (where), (head)->hh.tbl->num_items, _count); \
+ } \
+ _count = 0; \
+ _prev = NULL; \
+ _thh = &(head)->hh; \
+ while (_thh) { \
+ _count++; \
+ if (_prev != (char*)_thh->prev) { \
+ HASH_OOPS("%s: invalid prev %p, actual %p\n", \
+ (where), (void*)_thh->prev, (void*)_prev); \
+ } \
+ _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \
+ _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \
+ } \
+ if (_count != (head)->hh.tbl->num_items) { \
+ HASH_OOPS("%s: invalid app item count %u, actual %u\n", \
+ (where), (head)->hh.tbl->num_items, _count); \
+ } \
+ } \
+} while (0)
+#else
+#define HASH_FSCK(hh,head,where)
+#endif
+
+/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
+ * the descriptor to which this macro is defined for tuning the hash function.
+ * The app can #include <unistd.h> to get the prototype for write(2). */
+#ifdef HASH_EMIT_KEYS
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \
+do { \
+ unsigned _klen = fieldlen; \
+ write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \
+ write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \
+} while (0)
+#else
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)
+#endif
+
+/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
+#ifdef HASH_FUNCTION
+#define HASH_FCN HASH_FUNCTION
+#else
+#define HASH_FCN HASH_JEN
+#endif
+
+/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */
+#define HASH_BER(key,keylen,hashv) \
+do { \
+ unsigned _hb_keylen = (unsigned)keylen; \
+ const unsigned char *_hb_key = (const unsigned char*)(key); \
+ (hashv) = 0; \
+ while (_hb_keylen-- != 0U) { \
+ (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \
+ } \
+} while (0)
+
+
+/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
+ * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
+#define HASH_SAX(key,keylen,hashv) \
+do { \
+ unsigned _sx_i; \
+ const unsigned char *_hs_key = (const unsigned char*)(key); \
+ hashv = 0; \
+ for (_sx_i=0; _sx_i < keylen; _sx_i++) { \
+ hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \
+ } \
+} while (0)
+/* FNV-1a variation */
+#define HASH_FNV(key,keylen,hashv) \
+do { \
+ unsigned _fn_i; \
+ const unsigned char *_hf_key = (const unsigned char*)(key); \
+ (hashv) = 2166136261U; \
+ for (_fn_i=0; _fn_i < keylen; _fn_i++) { \
+ hashv = hashv ^ _hf_key[_fn_i]; \
+ hashv = hashv * 16777619U; \
+ } \
+} while (0)
+
+#define HASH_OAT(key,keylen,hashv) \
+do { \
+ unsigned _ho_i; \
+ const unsigned char *_ho_key=(const unsigned char*)(key); \
+ hashv = 0; \
+ for(_ho_i=0; _ho_i < keylen; _ho_i++) { \
+ hashv += _ho_key[_ho_i]; \
+ hashv += (hashv << 10); \
+ hashv ^= (hashv >> 6); \
+ } \
+ hashv += (hashv << 3); \
+ hashv ^= (hashv >> 11); \
+ hashv += (hashv << 15); \
+} while (0)
+
+#define HASH_JEN_MIX(a,b,c) \
+do { \
+ a -= b; a -= c; a ^= ( c >> 13 ); \
+ b -= c; b -= a; b ^= ( a << 8 ); \
+ c -= a; c -= b; c ^= ( b >> 13 ); \
+ a -= b; a -= c; a ^= ( c >> 12 ); \
+ b -= c; b -= a; b ^= ( a << 16 ); \
+ c -= a; c -= b; c ^= ( b >> 5 ); \
+ a -= b; a -= c; a ^= ( c >> 3 ); \
+ b -= c; b -= a; b ^= ( a << 10 ); \
+ c -= a; c -= b; c ^= ( b >> 15 ); \
+} while (0)
+
+#define HASH_JEN(key,keylen,hashv) \
+do { \
+ unsigned _hj_i,_hj_j,_hj_k; \
+ unsigned const char *_hj_key=(unsigned const char*)(key); \
+ hashv = 0xfeedbeefu; \
+ _hj_i = _hj_j = 0x9e3779b9u; \
+ _hj_k = (unsigned)(keylen); \
+ while (_hj_k >= 12U) { \
+ _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \
+ + ( (unsigned)_hj_key[2] << 16 ) \
+ + ( (unsigned)_hj_key[3] << 24 ) ); \
+ _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \
+ + ( (unsigned)_hj_key[6] << 16 ) \
+ + ( (unsigned)_hj_key[7] << 24 ) ); \
+ hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \
+ + ( (unsigned)_hj_key[10] << 16 ) \
+ + ( (unsigned)_hj_key[11] << 24 ) ); \
+ \
+ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
+ \
+ _hj_key += 12; \
+ _hj_k -= 12U; \
+ } \
+ hashv += (unsigned)(keylen); \
+ switch ( _hj_k ) { \
+ case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \
+ case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \
+ case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \
+ case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \
+ case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \
+ case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \
+ case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \
+ case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \
+ case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \
+ case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \
+ case 1: _hj_i += _hj_key[0]; \
+ } \
+ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
+} while (0)
+
+/* The Paul Hsieh hash function */
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
+ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
+ +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+#define HASH_SFH(key,keylen,hashv) \
+do { \
+ unsigned const char *_sfh_key=(unsigned const char*)(key); \
+ uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \
+ \
+ unsigned _sfh_rem = _sfh_len & 3U; \
+ _sfh_len >>= 2; \
+ hashv = 0xcafebabeu; \
+ \
+ /* Main loop */ \
+ for (;_sfh_len > 0U; _sfh_len--) { \
+ hashv += get16bits (_sfh_key); \
+ _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \
+ hashv = (hashv << 16) ^ _sfh_tmp; \
+ _sfh_key += 2U*sizeof (uint16_t); \
+ hashv += hashv >> 11; \
+ } \
+ \
+ /* Handle end cases */ \
+ switch (_sfh_rem) { \
+ case 3: hashv += get16bits (_sfh_key); \
+ hashv ^= hashv << 16; \
+ hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \
+ hashv += hashv >> 11; \
+ break; \
+ case 2: hashv += get16bits (_sfh_key); \
+ hashv ^= hashv << 11; \
+ hashv += hashv >> 17; \
+ break; \
+ case 1: hashv += *_sfh_key; \
+ hashv ^= hashv << 10; \
+ hashv += hashv >> 1; \
+ } \
+ \
+ /* Force "avalanching" of final 127 bits */ \
+ hashv ^= hashv << 3; \
+ hashv += hashv >> 5; \
+ hashv ^= hashv << 4; \
+ hashv += hashv >> 17; \
+ hashv ^= hashv << 25; \
+ hashv += hashv >> 6; \
+} while (0)
+
+#ifdef HASH_USING_NO_STRICT_ALIASING
+/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads.
+ * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
+ * MurmurHash uses the faster approach only on CPU's where we know it's safe.
+ *
+ * Note the preprocessor built-in defines can be emitted using:
+ *
+ * gcc -m64 -dM -E - < /dev/null (on gcc)
+ * cc -## a.c (where a.c is a simple test file) (Sun Studio)
+ */
+#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86))
+#define MUR_GETBLOCK(p,i) p[i]
+#else /* non intel */
+#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 3UL) == 0UL)
+#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 3UL) == 1UL)
+#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 3UL) == 2UL)
+#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 3UL) == 3UL)
+#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL))
+#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__))
+#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24))
+#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16))
+#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8))
+#else /* assume little endian non-intel */
+#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24))
+#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16))
+#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8))
+#endif
+#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \
+ (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \
+ (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \
+ MUR_ONE_THREE(p))))
+#endif
+#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r))))
+#define MUR_FMIX(_h) \
+do { \
+ _h ^= _h >> 16; \
+ _h *= 0x85ebca6bu; \
+ _h ^= _h >> 13; \
+ _h *= 0xc2b2ae35u; \
+ _h ^= _h >> 16; \
+} while (0)
+
+#define HASH_MUR(key,keylen,hashv) \
+do { \
+ const uint8_t *_mur_data = (const uint8_t*)(key); \
+ const int _mur_nblocks = (int)(keylen) / 4; \
+ uint32_t _mur_h1 = 0xf88D5353u; \
+ uint32_t _mur_c1 = 0xcc9e2d51u; \
+ uint32_t _mur_c2 = 0x1b873593u; \
+ uint32_t _mur_k1 = 0; \
+ const uint8_t *_mur_tail; \
+ const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+(_mur_nblocks*4)); \
+ int _mur_i; \
+ for (_mur_i = -_mur_nblocks; _mur_i != 0; _mur_i++) { \
+ _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \
+ _mur_k1 *= _mur_c1; \
+ _mur_k1 = MUR_ROTL32(_mur_k1,15); \
+ _mur_k1 *= _mur_c2; \
+ \
+ _mur_h1 ^= _mur_k1; \
+ _mur_h1 = MUR_ROTL32(_mur_h1,13); \
+ _mur_h1 = (_mur_h1*5U) + 0xe6546b64u; \
+ } \
+ _mur_tail = (const uint8_t*)(_mur_data + (_mur_nblocks*4)); \
+ _mur_k1=0; \
+ switch ((keylen) & 3U) { \
+ case 0: break; \
+ case 3: _mur_k1 ^= (uint32_t)_mur_tail[2] << 16; /* FALLTHROUGH */ \
+ case 2: _mur_k1 ^= (uint32_t)_mur_tail[1] << 8; /* FALLTHROUGH */ \
+ case 1: _mur_k1 ^= (uint32_t)_mur_tail[0]; \
+ _mur_k1 *= _mur_c1; \
+ _mur_k1 = MUR_ROTL32(_mur_k1,15); \
+ _mur_k1 *= _mur_c2; \
+ _mur_h1 ^= _mur_k1; \
+ } \
+ _mur_h1 ^= (uint32_t)(keylen); \
+ MUR_FMIX(_mur_h1); \
+ hashv = _mur_h1; \
+} while (0)
+#endif /* HASH_USING_NO_STRICT_ALIASING */
+
+/* iterate over items in a known bucket to find desired item */
+#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \
+do { \
+ if ((head).hh_head != NULL) { \
+ DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \
+ } else { \
+ (out) = NULL; \
+ } \
+ while ((out) != NULL) { \
+ if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \
+ if (uthash_memcmp((out)->hh.key, keyptr, keylen_in) == 0) { \
+ break; \
+ } \
+ } \
+ if ((out)->hh.hh_next != NULL) { \
+ DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \
+ } else { \
+ (out) = NULL; \
+ } \
+ } \
+} while (0)
+
+/* add an item to a bucket */
+#define HASH_ADD_TO_BKT(head,hh,addhh,oomed) \
+do { \
+ UT_hash_bucket *_ha_head = &(head); \
+ _ha_head->count++; \
+ (addhh)->hh_next = _ha_head->hh_head; \
+ (addhh)->hh_prev = NULL; \
+ if (_ha_head->hh_head != NULL) { \
+ _ha_head->hh_head->hh_prev = (addhh); \
+ } \
+ _ha_head->hh_head = (addhh); \
+ if ((_ha_head->count >= ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) \
+ && !(addhh)->tbl->noexpand) { \
+ HASH_EXPAND_BUCKETS(addhh,(addhh)->tbl, oomed); \
+ IF_HASH_NONFATAL_OOM( \
+ if (oomed) { \
+ HASH_DEL_IN_BKT(head,addhh); \
+ } \
+ ) \
+ } \
+} while (0)
+
+/* remove an item from a given bucket */
+#define HASH_DEL_IN_BKT(head,delhh) \
+do { \
+ UT_hash_bucket *_hd_head = &(head); \
+ _hd_head->count--; \
+ if (_hd_head->hh_head == (delhh)) { \
+ _hd_head->hh_head = (delhh)->hh_next; \
+ } \
+ if ((delhh)->hh_prev) { \
+ (delhh)->hh_prev->hh_next = (delhh)->hh_next; \
+ } \
+ if ((delhh)->hh_next) { \
+ (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \
+ } \
+} while (0)
+
+/* Bucket expansion has the effect of doubling the number of buckets
+ * and redistributing the items into the new buckets. Ideally the
+ * items will distribute more or less evenly into the new buckets
+ * (the extent to which this is true is a measure of the quality of
+ * the hash function as it applies to the key domain).
+ *
+ * With the items distributed into more buckets, the chain length
+ * (item count) in each bucket is reduced. Thus by expanding buckets
+ * the hash keeps a bound on the chain length. This bounded chain
+ * length is the essence of how a hash provides constant time lookup.
+ *
+ * The calculation of tbl->ideal_chain_maxlen below deserves some
+ * explanation. First, keep in mind that we're calculating the ideal
+ * maximum chain length based on the *new* (doubled) bucket count.
+ * In fractions this is just n/b (n=number of items,b=new num buckets).
+ * Since the ideal chain length is an integer, we want to calculate
+ * ceil(n/b). We don't depend on floating point arithmetic in this
+ * hash, so to calculate ceil(n/b) with integers we could write
+ *
+ * ceil(n/b) = (n/b) + ((n%b)?1:0)
+ *
+ * and in fact a previous version of this hash did just that.
+ * But now we have improved things a bit by recognizing that b is
+ * always a power of two. We keep its base 2 log handy (call it lb),
+ * so now we can write this with a bit shift and logical AND:
+ *
+ * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
+ *
+ */
+#define HASH_EXPAND_BUCKETS(hh,tbl,oomed) \
+do { \
+ unsigned _he_bkt; \
+ unsigned _he_bkt_i; \
+ struct UT_hash_handle *_he_thh, *_he_hh_nxt; \
+ UT_hash_bucket *_he_new_buckets, *_he_newbkt; \
+ _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \
+ 2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \
+ if (!_he_new_buckets) { \
+ HASH_RECORD_OOM(oomed); \
+ } else { \
+ uthash_bzero(_he_new_buckets, \
+ 2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \
+ (tbl)->ideal_chain_maxlen = \
+ ((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \
+ ((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \
+ (tbl)->nonideal_items = 0; \
+ for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) { \
+ _he_thh = (tbl)->buckets[ _he_bkt_i ].hh_head; \
+ while (_he_thh != NULL) { \
+ _he_hh_nxt = _he_thh->hh_next; \
+ HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \
+ _he_newbkt = &(_he_new_buckets[_he_bkt]); \
+ if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \
+ (tbl)->nonideal_items++; \
+ _he_newbkt->expand_mult = _he_newbkt->count / (tbl)->ideal_chain_maxlen; \
+ } \
+ _he_thh->hh_prev = NULL; \
+ _he_thh->hh_next = _he_newbkt->hh_head; \
+ if (_he_newbkt->hh_head != NULL) { \
+ _he_newbkt->hh_head->hh_prev = _he_thh; \
+ } \
+ _he_newbkt->hh_head = _he_thh; \
+ _he_thh = _he_hh_nxt; \
+ } \
+ } \
+ uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \
+ (tbl)->num_buckets *= 2U; \
+ (tbl)->log2_num_buckets++; \
+ (tbl)->buckets = _he_new_buckets; \
+ (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? \
+ ((tbl)->ineff_expands+1U) : 0U; \
+ if ((tbl)->ineff_expands > 1U) { \
+ (tbl)->noexpand = 1; \
+ uthash_noexpand_fyi(tbl); \
+ } \
+ uthash_expand_fyi(tbl); \
+ } \
+} while (0)
+
+
+/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
+/* Note that HASH_SORT assumes the hash handle name to be hh.
+ * HASH_SRT was added to allow the hash handle name to be passed in. */
+#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)
+#define HASH_SRT(hh,head,cmpfcn) \
+do { \
+ unsigned _hs_i; \
+ unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \
+ struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \
+ if (head != NULL) { \
+ _hs_insize = 1; \
+ _hs_looping = 1; \
+ _hs_list = &((head)->hh); \
+ while (_hs_looping != 0U) { \
+ _hs_p = _hs_list; \
+ _hs_list = NULL; \
+ _hs_tail = NULL; \
+ _hs_nmerges = 0; \
+ while (_hs_p != NULL) { \
+ _hs_nmerges++; \
+ _hs_q = _hs_p; \
+ _hs_psize = 0; \
+ for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \
+ _hs_psize++; \
+ _hs_q = ((_hs_q->next != NULL) ? \
+ HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \
+ if (_hs_q == NULL) { \
+ break; \
+ } \
+ } \
+ _hs_qsize = _hs_insize; \
+ while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) { \
+ if (_hs_psize == 0U) { \
+ _hs_e = _hs_q; \
+ _hs_q = ((_hs_q->next != NULL) ? \
+ HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \
+ _hs_qsize--; \
+ } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \
+ _hs_e = _hs_p; \
+ if (_hs_p != NULL) { \
+ _hs_p = ((_hs_p->next != NULL) ? \
+ HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \
+ } \
+ _hs_psize--; \
+ } else if ((cmpfcn( \
+ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \
+ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)) \
+ )) <= 0) { \
+ _hs_e = _hs_p; \
+ if (_hs_p != NULL) { \
+ _hs_p = ((_hs_p->next != NULL) ? \
+ HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \
+ } \
+ _hs_psize--; \
+ } else { \
+ _hs_e = _hs_q; \
+ _hs_q = ((_hs_q->next != NULL) ? \
+ HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \
+ _hs_qsize--; \
+ } \
+ if ( _hs_tail != NULL ) { \
+ _hs_tail->next = ((_hs_e != NULL) ? \
+ ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \
+ } else { \
+ _hs_list = _hs_e; \
+ } \
+ if (_hs_e != NULL) { \
+ _hs_e->prev = ((_hs_tail != NULL) ? \
+ ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \
+ } \
+ _hs_tail = _hs_e; \
+ } \
+ _hs_p = _hs_q; \
+ } \
+ if (_hs_tail != NULL) { \
+ _hs_tail->next = NULL; \
+ } \
+ if (_hs_nmerges <= 1U) { \
+ _hs_looping = 0; \
+ (head)->hh.tbl->tail = _hs_tail; \
+ DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \
+ } \
+ _hs_insize *= 2U; \
+ } \
+ HASH_FSCK(hh, head, "HASH_SRT"); \
+ } \
+} while (0)
+
+/* This function selects items from one hash into another hash.
+ * The end result is that the selected items have dual presence
+ * in both hashes. There is no copy of the items made; rather
+ * they are added into the new hash through a secondary hash
+ * hash handle that must be present in the structure. */
+#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \
+do { \
+ unsigned _src_bkt, _dst_bkt; \
+ void *_last_elt = NULL, *_elt; \
+ UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \
+ ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \
+ if ((src) != NULL) { \
+ for (_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \
+ for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \
+ _src_hh != NULL; \
+ _src_hh = _src_hh->hh_next) { \
+ _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \
+ if (cond(_elt)) { \
+ IF_HASH_NONFATAL_OOM( int _hs_oomed = 0; ) \
+ _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \
+ _dst_hh->key = _src_hh->key; \
+ _dst_hh->keylen = _src_hh->keylen; \
+ _dst_hh->hashv = _src_hh->hashv; \
+ _dst_hh->prev = _last_elt; \
+ _dst_hh->next = NULL; \
+ if (_last_elt_hh != NULL) { \
+ _last_elt_hh->next = _elt; \
+ } \
+ if ((dst) == NULL) { \
+ DECLTYPE_ASSIGN(dst, _elt); \
+ HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \
+ IF_HASH_NONFATAL_OOM( \
+ if (_hs_oomed) { \
+ uthash_nonfatal_oom(_elt); \
+ (dst) = NULL; \
+ continue; \
+ } \
+ ) \
+ } else { \
+ _dst_hh->tbl = (dst)->hh_dst.tbl; \
+ } \
+ HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \
+ HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, _hs_oomed); \
+ (dst)->hh_dst.tbl->num_items++; \
+ IF_HASH_NONFATAL_OOM( \
+ if (_hs_oomed) { \
+ HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \
+ HASH_DELETE_HH(hh_dst, dst, _dst_hh); \
+ _dst_hh->tbl = NULL; \
+ uthash_nonfatal_oom(_elt); \
+ continue; \
+ } \
+ ) \
+ HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \
+ _last_elt = _elt; \
+ _last_elt_hh = _dst_hh; \
+ } \
+ } \
+ } \
+ } \
+ HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \
+} while (0)
+
+#define HASH_CLEAR(hh,head) \
+do { \
+ if ((head) != NULL) { \
+ HASH_BLOOM_FREE((head)->hh.tbl); \
+ uthash_free((head)->hh.tbl->buckets, \
+ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \
+ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
+ (head) = NULL; \
+ } \
+} while (0)
+
+#define HASH_OVERHEAD(hh,head) \
+ (((head) != NULL) ? ( \
+ (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \
+ ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \
+ sizeof(UT_hash_table) + \
+ (HASH_BLOOM_BYTELEN))) : 0U)
+
+#ifdef NO_DECLTYPE
+#define HASH_ITER(hh,head,el,tmp) \
+for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \
+ (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL)))
+#else
+#define HASH_ITER(hh,head,el,tmp) \
+for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \
+ (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL)))
+#endif
+
+/* obtain a count of items in the hash */
+#define HASH_COUNT(head) HASH_CNT(hh,head)
+#define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U)
+
+typedef struct UT_hash_bucket {
+ struct UT_hash_handle *hh_head;
+ unsigned count;
+
+ /* expand_mult is normally set to 0. In this situation, the max chain length
+ * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
+ * the bucket's chain exceeds this length, bucket expansion is triggered).
+ * However, setting expand_mult to a non-zero value delays bucket expansion
+ * (that would be triggered by additions to this particular bucket)
+ * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
+ * (The multiplier is simply expand_mult+1). The whole idea of this
+ * multiplier is to reduce bucket expansions, since they are expensive, in
+ * situations where we know that a particular bucket tends to be overused.
+ * It is better to let its chain length grow to a longer yet-still-bounded
+ * value, than to do an O(n) bucket expansion too often.
+ */
+ unsigned expand_mult;
+
+} UT_hash_bucket;
+
+/* random signature used only to find hash tables in external analysis */
+#define HASH_SIGNATURE 0xa0111fe1u
+#define HASH_BLOOM_SIGNATURE 0xb12220f2u
+
+typedef struct UT_hash_table {
+ UT_hash_bucket *buckets;
+ unsigned num_buckets, log2_num_buckets;
+ unsigned num_items;
+ struct UT_hash_handle *tail; /* tail hh in app order, for fast append */
+ ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */
+
+ /* in an ideal situation (all buckets used equally), no bucket would have
+ * more than ceil(#items/#buckets) items. that's the ideal chain length. */
+ unsigned ideal_chain_maxlen;
+
+ /* nonideal_items is the number of items in the hash whose chain position
+ * exceeds the ideal chain maxlen. these items pay the penalty for an uneven
+ * hash distribution; reaching them in a chain traversal takes >ideal steps */
+ unsigned nonideal_items;
+
+ /* ineffective expands occur when a bucket doubling was performed, but
+ * afterward, more than half the items in the hash had nonideal chain
+ * positions. If this happens on two consecutive expansions we inhibit any
+ * further expansion, as it's not helping; this happens when the hash
+ * function isn't a good fit for the key domain. When expansion is inhibited
+ * the hash will still work, albeit no longer in constant time. */
+ unsigned ineff_expands, noexpand;
+
+ uint32_t signature; /* used only to find hash tables in external analysis */
+#ifdef HASH_BLOOM
+ uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
+ uint8_t *bloom_bv;
+ uint8_t bloom_nbits;
+#endif
+
+} UT_hash_table;
+
+typedef struct UT_hash_handle {
+ struct UT_hash_table *tbl;
+ void *prev; /* prev element in app order */
+ void *next; /* next element in app order */
+ struct UT_hash_handle *hh_prev; /* previous hh in bucket order */
+ struct UT_hash_handle *hh_next; /* next hh in bucket order */
+ void *key; /* ptr to enclosing struct's key */
+ unsigned keylen; /* enclosing struct's key len */
+ unsigned hashv; /* result of hash-fcn(key) */
+} UT_hash_handle;
+
+#endif /* UTHASH_H */
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/utlist.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/utlist.h
new file mode 100644
index 0000000..4ee4cd3
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/utlist.h
@@ -0,0 +1,1074 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+Copyright (c) 2007-2017, Troy D. Hanson http://troydhanson.github.com/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef UTLIST_H
+#define UTLIST_H
+
+#define UTLIST_VERSION 2.0.2
+
+#include <assert.h>
+
+/*
+ * This file contains macros to manipulate singly and doubly-linked lists.
+ *
+ * 1. LL_ macros: singly-linked lists.
+ * 2. DL_ macros: doubly-linked lists.
+ * 3. CDL_ macros: circular doubly-linked lists.
+ *
+ * To use singly-linked lists, your structure must have a "next" pointer.
+ * To use doubly-linked lists, your structure must "prev" and "next" pointers.
+ * Either way, the pointer to the head of the list must be initialized to NULL.
+ *
+ * ----------------.EXAMPLE -------------------------
+ * struct item {
+ * int id;
+ * struct item *prev, *next;
+ * }
+ *
+ * struct item *list = NULL:
+ *
+ * int main() {
+ * struct item *item;
+ * ... allocate and populate item ...
+ * DL_APPEND(list, item);
+ * }
+ * --------------------------------------------------
+ *
+ * For doubly-linked lists, the append and delete macros are O(1)
+ * For singly-linked lists, append and delete are O(n) but prepend is O(1)
+ * The sort macro is O(n log(n)) for all types of single/double/circular lists.
+ */
+
+/* These macros use decltype or the earlier __typeof GNU extension.
+ As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+ when compiling c++ source) this code uses whatever method is needed
+ or, for VS2008 where neither is available, uses casting workarounds. */
+#if !defined(LDECLTYPE) && !defined(NO_DECLTYPE)
+#if defined(_MSC_VER) /* MS compiler */
+#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
+#define LDECLTYPE(x) decltype(x)
+#else /* VS2008 or older (or VS2010 in C mode) */
+#define NO_DECLTYPE
+#endif
+#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__)
+#define NO_DECLTYPE
+#else /* GNU, Sun and other compilers */
+#define LDECLTYPE(x) __typeof(x)
+#endif
+#endif
+
+/* for VS2008 we use some workarounds to get around the lack of decltype,
+ * namely, we always reassign our tmp variable to the list head if we need
+ * to dereference its prev/next pointers, and save/restore the real head.*/
+#ifdef NO_DECLTYPE
+#define IF_NO_DECLTYPE(x) x
+#define LDECLTYPE(x) char*
+#define UTLIST_SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); }
+#define UTLIST_NEXT(elt,list,next) ((char*)((list)->next))
+#define UTLIST_NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); }
+/* #define UTLIST_PREV(elt,list,prev) ((char*)((list)->prev)) */
+#define UTLIST_PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); }
+#define UTLIST_RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; }
+#define UTLIST_CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); }
+#else
+#define IF_NO_DECLTYPE(x)
+#define UTLIST_SV(elt,list)
+#define UTLIST_NEXT(elt,list,next) ((elt)->next)
+#define UTLIST_NEXTASGN(elt,list,to,next) ((elt)->next)=(to)
+/* #define UTLIST_PREV(elt,list,prev) ((elt)->prev) */
+#define UTLIST_PREVASGN(elt,list,to,prev) ((elt)->prev)=(to)
+#define UTLIST_RS(list)
+#define UTLIST_CASTASGN(a,b) (a)=(b)
+#endif
+
+/******************************************************************************
+ * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort *
+ * Unwieldy variable names used here to avoid shadowing passed-in variables. *
+ *****************************************************************************/
+#define LL_SORT(list, cmp) \
+ LL_SORT2(list, cmp, next)
+
+#define LL_SORT2(list, cmp, next) \
+do { \
+ LDECLTYPE(list) _ls_p; \
+ LDECLTYPE(list) _ls_q; \
+ LDECLTYPE(list) _ls_e; \
+ LDECLTYPE(list) _ls_tail; \
+ IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \
+ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
+ if (list) { \
+ _ls_insize = 1; \
+ _ls_looping = 1; \
+ while (_ls_looping) { \
+ UTLIST_CASTASGN(_ls_p,list); \
+ (list) = NULL; \
+ _ls_tail = NULL; \
+ _ls_nmerges = 0; \
+ while (_ls_p) { \
+ _ls_nmerges++; \
+ _ls_q = _ls_p; \
+ _ls_psize = 0; \
+ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
+ _ls_psize++; \
+ UTLIST_SV(_ls_q,list); _ls_q = UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); \
+ if (!_ls_q) break; \
+ } \
+ _ls_qsize = _ls_insize; \
+ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
+ if (_ls_psize == 0) { \
+ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \
+ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \
+ } else if (_ls_qsize == 0 || !_ls_q) { \
+ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \
+ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \
+ } else if (cmp(_ls_p,_ls_q) <= 0) { \
+ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \
+ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \
+ } else { \
+ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \
+ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \
+ } \
+ if (_ls_tail) { \
+ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \
+ } else { \
+ UTLIST_CASTASGN(list,_ls_e); \
+ } \
+ _ls_tail = _ls_e; \
+ } \
+ _ls_p = _ls_q; \
+ } \
+ if (_ls_tail) { \
+ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,NULL,next); UTLIST_RS(list); \
+ } \
+ if (_ls_nmerges <= 1) { \
+ _ls_looping=0; \
+ } \
+ _ls_insize *= 2; \
+ } \
+ } \
+} while (0)
+
+
+#define DL_SORT(list, cmp) \
+ DL_SORT2(list, cmp, prev, next)
+
+#define DL_SORT2(list, cmp, prev, next) \
+do { \
+ LDECLTYPE(list) _ls_p; \
+ LDECLTYPE(list) _ls_q; \
+ LDECLTYPE(list) _ls_e; \
+ LDECLTYPE(list) _ls_tail; \
+ IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \
+ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
+ if (list) { \
+ _ls_insize = 1; \
+ _ls_looping = 1; \
+ while (_ls_looping) { \
+ UTLIST_CASTASGN(_ls_p,list); \
+ (list) = NULL; \
+ _ls_tail = NULL; \
+ _ls_nmerges = 0; \
+ while (_ls_p) { \
+ _ls_nmerges++; \
+ _ls_q = _ls_p; \
+ _ls_psize = 0; \
+ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
+ _ls_psize++; \
+ UTLIST_SV(_ls_q,list); _ls_q = UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); \
+ if (!_ls_q) break; \
+ } \
+ _ls_qsize = _ls_insize; \
+ while ((_ls_psize > 0) || ((_ls_qsize > 0) && _ls_q)) { \
+ if (_ls_psize == 0) { \
+ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \
+ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \
+ } else if ((_ls_qsize == 0) || (!_ls_q)) { \
+ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \
+ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \
+ } else if (cmp(_ls_p,_ls_q) <= 0) { \
+ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \
+ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \
+ } else { \
+ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \
+ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \
+ } \
+ if (_ls_tail) { \
+ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \
+ } else { \
+ UTLIST_CASTASGN(list,_ls_e); \
+ } \
+ UTLIST_SV(_ls_e,list); UTLIST_PREVASGN(_ls_e,list,_ls_tail,prev); UTLIST_RS(list); \
+ _ls_tail = _ls_e; \
+ } \
+ _ls_p = _ls_q; \
+ } \
+ UTLIST_CASTASGN((list)->prev, _ls_tail); \
+ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,NULL,next); UTLIST_RS(list); \
+ if (_ls_nmerges <= 1) { \
+ _ls_looping=0; \
+ } \
+ _ls_insize *= 2; \
+ } \
+ } \
+} while (0)
+
+#define CDL_SORT(list, cmp) \
+ CDL_SORT2(list, cmp, prev, next)
+
+#define CDL_SORT2(list, cmp, prev, next) \
+do { \
+ LDECLTYPE(list) _ls_p; \
+ LDECLTYPE(list) _ls_q; \
+ LDECLTYPE(list) _ls_e; \
+ LDECLTYPE(list) _ls_tail; \
+ LDECLTYPE(list) _ls_oldhead; \
+ LDECLTYPE(list) _tmp; \
+ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
+ if (list) { \
+ _ls_insize = 1; \
+ _ls_looping = 1; \
+ while (_ls_looping) { \
+ UTLIST_CASTASGN(_ls_p,list); \
+ UTLIST_CASTASGN(_ls_oldhead,list); \
+ (list) = NULL; \
+ _ls_tail = NULL; \
+ _ls_nmerges = 0; \
+ while (_ls_p) { \
+ _ls_nmerges++; \
+ _ls_q = _ls_p; \
+ _ls_psize = 0; \
+ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
+ _ls_psize++; \
+ UTLIST_SV(_ls_q,list); \
+ if (UTLIST_NEXT(_ls_q,list,next) == _ls_oldhead) { \
+ _ls_q = NULL; \
+ } else { \
+ _ls_q = UTLIST_NEXT(_ls_q,list,next); \
+ } \
+ UTLIST_RS(list); \
+ if (!_ls_q) break; \
+ } \
+ _ls_qsize = _ls_insize; \
+ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
+ if (_ls_psize == 0) { \
+ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \
+ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \
+ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
+ } else if (_ls_qsize == 0 || !_ls_q) { \
+ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \
+ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \
+ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
+ } else if (cmp(_ls_p,_ls_q) <= 0) { \
+ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \
+ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \
+ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
+ } else { \
+ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \
+ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \
+ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
+ } \
+ if (_ls_tail) { \
+ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \
+ } else { \
+ UTLIST_CASTASGN(list,_ls_e); \
+ } \
+ UTLIST_SV(_ls_e,list); UTLIST_PREVASGN(_ls_e,list,_ls_tail,prev); UTLIST_RS(list); \
+ _ls_tail = _ls_e; \
+ } \
+ _ls_p = _ls_q; \
+ } \
+ UTLIST_CASTASGN((list)->prev,_ls_tail); \
+ UTLIST_CASTASGN(_tmp,list); \
+ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_tmp,next); UTLIST_RS(list); \
+ if (_ls_nmerges <= 1) { \
+ _ls_looping=0; \
+ } \
+ _ls_insize *= 2; \
+ } \
+ } \
+} while (0)
+
+/******************************************************************************
+ * singly linked list macros (non-circular) *
+ *****************************************************************************/
+#define LL_PREPEND(head,add) \
+ LL_PREPEND2(head,add,next)
+
+#define LL_PREPEND2(head,add,next) \
+do { \
+ (add)->next = (head); \
+ (head) = (add); \
+} while (0)
+
+#define LL_CONCAT(head1,head2) \
+ LL_CONCAT2(head1,head2,next)
+
+#define LL_CONCAT2(head1,head2,next) \
+do { \
+ LDECLTYPE(head1) _tmp; \
+ if (head1) { \
+ _tmp = (head1); \
+ while (_tmp->next) { _tmp = _tmp->next; } \
+ _tmp->next=(head2); \
+ } else { \
+ (head1)=(head2); \
+ } \
+} while (0)
+
+#define LL_APPEND(head,add) \
+ LL_APPEND2(head,add,next)
+
+#define LL_APPEND2(head,add,next) \
+do { \
+ LDECLTYPE(head) _tmp; \
+ (add)->next=NULL; \
+ if (head) { \
+ _tmp = (head); \
+ while (_tmp->next) { _tmp = _tmp->next; } \
+ _tmp->next=(add); \
+ } else { \
+ (head)=(add); \
+ } \
+} while (0)
+
+#define LL_INSERT_INORDER(head,add,cmp) \
+ LL_INSERT_INORDER2(head,add,cmp,next)
+
+#define LL_INSERT_INORDER2(head,add,cmp,next) \
+do { \
+ LDECLTYPE(head) _tmp; \
+ if (head) { \
+ LL_LOWER_BOUND(head, _tmp, add, cmp); \
+ LL_APPEND_ELEM(head, _tmp, add); \
+ } else { \
+ (head) = (add); \
+ (head)->next = NULL; \
+ } \
+} while (0)
+
+#define LL_LOWER_BOUND(head,elt,like,cmp) \
+ LL_LOWER_BOUND2(head,elt,like,cmp,next)
+
+#define LL_LOWER_BOUND2(head,elt,like,cmp,next) \
+ do { \
+ if ((head) == NULL || (cmp(head, like)) >= 0) { \
+ (elt) = NULL; \
+ } else { \
+ for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) { \
+ if (cmp((elt)->next, like) >= 0) { \
+ break; \
+ } \
+ } \
+ } \
+ } while (0)
+
+#define LL_DELETE(head,del) \
+ LL_DELETE2(head,del,next)
+
+#define LL_DELETE2(head,del,next) \
+do { \
+ LDECLTYPE(head) _tmp; \
+ if ((head) == (del)) { \
+ (head)=(head)->next; \
+ } else { \
+ _tmp = (head); \
+ while (_tmp->next && (_tmp->next != (del))) { \
+ _tmp = _tmp->next; \
+ } \
+ if (_tmp->next) { \
+ _tmp->next = (del)->next; \
+ } \
+ } \
+} while (0)
+
+#define LL_COUNT(head,el,counter) \
+ LL_COUNT2(head,el,counter,next) \
+
+#define LL_COUNT2(head,el,counter,next) \
+do { \
+ (counter) = 0; \
+ LL_FOREACH2(head,el,next) { ++(counter); } \
+} while (0)
+
+#define LL_FOREACH(head,el) \
+ LL_FOREACH2(head,el,next)
+
+#define LL_FOREACH2(head,el,next) \
+ for ((el) = (head); el; (el) = (el)->next)
+
+#define LL_FOREACH_SAFE(head,el,tmp) \
+ LL_FOREACH_SAFE2(head,el,tmp,next)
+
+#define LL_FOREACH_SAFE2(head,el,tmp,next) \
+ for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp))
+
+#define LL_SEARCH_SCALAR(head,out,field,val) \
+ LL_SEARCH_SCALAR2(head,out,field,val,next)
+
+#define LL_SEARCH_SCALAR2(head,out,field,val,next) \
+do { \
+ LL_FOREACH2(head,out,next) { \
+ if ((out)->field == (val)) break; \
+ } \
+} while (0)
+
+#define LL_SEARCH(head,out,elt,cmp) \
+ LL_SEARCH2(head,out,elt,cmp,next)
+
+#define LL_SEARCH2(head,out,elt,cmp,next) \
+do { \
+ LL_FOREACH2(head,out,next) { \
+ if ((cmp(out,elt))==0) break; \
+ } \
+} while (0)
+
+#define LL_REPLACE_ELEM2(head, el, add, next) \
+do { \
+ LDECLTYPE(head) _tmp; \
+ assert((head) != NULL); \
+ assert((el) != NULL); \
+ assert((add) != NULL); \
+ (add)->next = (el)->next; \
+ if ((head) == (el)) { \
+ (head) = (add); \
+ } else { \
+ _tmp = (head); \
+ while (_tmp->next && (_tmp->next != (el))) { \
+ _tmp = _tmp->next; \
+ } \
+ if (_tmp->next) { \
+ _tmp->next = (add); \
+ } \
+ } \
+} while (0)
+
+#define LL_REPLACE_ELEM(head, el, add) \
+ LL_REPLACE_ELEM2(head, el, add, next)
+
+#define LL_PREPEND_ELEM2(head, el, add, next) \
+do { \
+ if (el) { \
+ LDECLTYPE(head) _tmp; \
+ assert((head) != NULL); \
+ assert((add) != NULL); \
+ (add)->next = (el); \
+ if ((head) == (el)) { \
+ (head) = (add); \
+ } else { \
+ _tmp = (head); \
+ while (_tmp->next && (_tmp->next != (el))) { \
+ _tmp = _tmp->next; \
+ } \
+ if (_tmp->next) { \
+ _tmp->next = (add); \
+ } \
+ } \
+ } else { \
+ LL_APPEND2(head, add, next); \
+ } \
+} while (0) \
+
+#define LL_PREPEND_ELEM(head, el, add) \
+ LL_PREPEND_ELEM2(head, el, add, next)
+
+#define LL_APPEND_ELEM2(head, el, add, next) \
+do { \
+ if (el) { \
+ assert((head) != NULL); \
+ assert((add) != NULL); \
+ (add)->next = (el)->next; \
+ (el)->next = (add); \
+ } else { \
+ LL_PREPEND2(head, add, next); \
+ } \
+} while (0) \
+
+#define LL_APPEND_ELEM(head, el, add) \
+ LL_APPEND_ELEM2(head, el, add, next)
+
+#ifdef NO_DECLTYPE
+/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */
+
+#undef LL_CONCAT2
+#define LL_CONCAT2(head1,head2,next) \
+do { \
+ char *_tmp; \
+ if (head1) { \
+ _tmp = (char*)(head1); \
+ while ((head1)->next) { (head1) = (head1)->next; } \
+ (head1)->next = (head2); \
+ UTLIST_RS(head1); \
+ } else { \
+ (head1)=(head2); \
+ } \
+} while (0)
+
+#undef LL_APPEND2
+#define LL_APPEND2(head,add,next) \
+do { \
+ if (head) { \
+ (add)->next = head; /* use add->next as a temp variable */ \
+ while ((add)->next->next) { (add)->next = (add)->next->next; } \
+ (add)->next->next=(add); \
+ } else { \
+ (head)=(add); \
+ } \
+ (add)->next=NULL; \
+} while (0)
+
+#undef LL_INSERT_INORDER2
+#define LL_INSERT_INORDER2(head,add,cmp,next) \
+do { \
+ if ((head) == NULL || (cmp(head, add)) >= 0) { \
+ (add)->next = (head); \
+ (head) = (add); \
+ } else { \
+ char *_tmp = (char*)(head); \
+ while ((head)->next != NULL && (cmp((head)->next, add)) < 0) { \
+ (head) = (head)->next; \
+ } \
+ (add)->next = (head)->next; \
+ (head)->next = (add); \
+ UTLIST_RS(head); \
+ } \
+} while (0)
+
+#undef LL_DELETE2
+#define LL_DELETE2(head,del,next) \
+do { \
+ if ((head) == (del)) { \
+ (head)=(head)->next; \
+ } else { \
+ char *_tmp = (char*)(head); \
+ while ((head)->next && ((head)->next != (del))) { \
+ (head) = (head)->next; \
+ } \
+ if ((head)->next) { \
+ (head)->next = ((del)->next); \
+ } \
+ UTLIST_RS(head); \
+ } \
+} while (0)
+
+#undef LL_REPLACE_ELEM2
+#define LL_REPLACE_ELEM2(head, el, add, next) \
+do { \
+ assert((head) != NULL); \
+ assert((el) != NULL); \
+ assert((add) != NULL); \
+ if ((head) == (el)) { \
+ (head) = (add); \
+ } else { \
+ (add)->next = head; \
+ while ((add)->next->next && ((add)->next->next != (el))) { \
+ (add)->next = (add)->next->next; \
+ } \
+ if ((add)->next->next) { \
+ (add)->next->next = (add); \
+ } \
+ } \
+ (add)->next = (el)->next; \
+} while (0)
+
+#undef LL_PREPEND_ELEM2
+#define LL_PREPEND_ELEM2(head, el, add, next) \
+do { \
+ if (el) { \
+ assert((head) != NULL); \
+ assert((add) != NULL); \
+ if ((head) == (el)) { \
+ (head) = (add); \
+ } else { \
+ (add)->next = (head); \
+ while ((add)->next->next && ((add)->next->next != (el))) { \
+ (add)->next = (add)->next->next; \
+ } \
+ if ((add)->next->next) { \
+ (add)->next->next = (add); \
+ } \
+ } \
+ (add)->next = (el); \
+ } else { \
+ LL_APPEND2(head, add, next); \
+ } \
+} while (0) \
+
+#endif /* NO_DECLTYPE */
+
+/******************************************************************************
+ * doubly linked list macros (non-circular) *
+ *****************************************************************************/
+#define DL_PREPEND(head,add) \
+ DL_PREPEND2(head,add,prev,next)
+
+#define DL_PREPEND2(head,add,prev,next) \
+do { \
+ (add)->next = (head); \
+ if (head) { \
+ (add)->prev = (head)->prev; \
+ (head)->prev = (add); \
+ } else { \
+ (add)->prev = (add); \
+ } \
+ (head) = (add); \
+} while (0)
+
+#define DL_APPEND(head,add) \
+ DL_APPEND2(head,add,prev,next)
+
+#define DL_APPEND2(head,add,prev,next) \
+do { \
+ if (head) { \
+ (add)->prev = (head)->prev; \
+ (head)->prev->next = (add); \
+ (head)->prev = (add); \
+ (add)->next = NULL; \
+ } else { \
+ (head)=(add); \
+ (head)->prev = (head); \
+ (head)->next = NULL; \
+ } \
+} while (0)
+
+#define DL_INSERT_INORDER(head,add,cmp) \
+ DL_INSERT_INORDER2(head,add,cmp,next)
+
+#define DL_INSERT_INORDER2(head,add,cmp,next) \
+do { \
+ LDECLTYPE(head) _tmp; \
+ if (head) { \
+ DL_LOWER_BOUND(head, _tmp, add, cmp); \
+ DL_APPEND_ELEM(head, _tmp, add); \
+ } else { \
+ (head) = (add); \
+ (head)->prev = (head); \
+ (head)->next = NULL; \
+ } \
+} while (0)
+
+#define DL_LOWER_BOUND(head,elt,like,cmp) \
+ DL_LOWER_BOUND2(head,elt,like,cmp,next)
+
+#define DL_LOWER_BOUND2(head,elt,like,cmp,next) \
+do { \
+ if ((head) == NULL || (cmp(head, like)) >= 0) { \
+ (elt) = NULL; \
+ } else { \
+ for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) { \
+ if ((cmp((elt)->next, like)) >= 0) { \
+ break; \
+ } \
+ } \
+ } \
+} while (0)
+
+#define DL_CONCAT(head1,head2) \
+ DL_CONCAT2(head1,head2,prev,next)
+
+#define DL_CONCAT2(head1,head2,prev,next) \
+do { \
+ LDECLTYPE(head1) _tmp; \
+ if (head2) { \
+ if (head1) { \
+ UTLIST_CASTASGN(_tmp, (head2)->prev); \
+ (head2)->prev = (head1)->prev; \
+ (head1)->prev->next = (head2); \
+ UTLIST_CASTASGN((head1)->prev, _tmp); \
+ } else { \
+ (head1)=(head2); \
+ } \
+ } \
+} while (0)
+
+#define DL_DELETE(head,del) \
+ DL_DELETE2(head,del,prev,next)
+
+#define DL_DELETE2(head,del,prev,next) \
+do { \
+ assert((head) != NULL); \
+ assert((del)->prev != NULL); \
+ if ((del)->prev == (del)) { \
+ (head)=NULL; \
+ } else if ((del)==(head)) { \
+ (del)->next->prev = (del)->prev; \
+ (head) = (del)->next; \
+ } else { \
+ (del)->prev->next = (del)->next; \
+ if ((del)->next) { \
+ (del)->next->prev = (del)->prev; \
+ } else { \
+ (head)->prev = (del)->prev; \
+ } \
+ } \
+} while (0)
+
+#define DL_COUNT(head,el,counter) \
+ DL_COUNT2(head,el,counter,next) \
+
+#define DL_COUNT2(head,el,counter,next) \
+do { \
+ (counter) = 0; \
+ DL_FOREACH2(head,el,next) { ++(counter); } \
+} while (0)
+
+#define DL_FOREACH(head,el) \
+ DL_FOREACH2(head,el,next)
+
+#define DL_FOREACH2(head,el,next) \
+ for ((el) = (head); el; (el) = (el)->next)
+
+/* this version is safe for deleting the elements during iteration */
+#define DL_FOREACH_SAFE(head,el,tmp) \
+ DL_FOREACH_SAFE2(head,el,tmp,next)
+
+#define DL_FOREACH_SAFE2(head,el,tmp,next) \
+ for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp))
+
+/* these are identical to their singly-linked list counterparts */
+#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR
+#define DL_SEARCH LL_SEARCH
+#define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2
+#define DL_SEARCH2 LL_SEARCH2
+
+#define DL_REPLACE_ELEM2(head, el, add, prev, next) \
+do { \
+ assert((head) != NULL); \
+ assert((el) != NULL); \
+ assert((add) != NULL); \
+ if ((head) == (el)) { \
+ (head) = (add); \
+ (add)->next = (el)->next; \
+ if ((el)->next == NULL) { \
+ (add)->prev = (add); \
+ } else { \
+ (add)->prev = (el)->prev; \
+ (add)->next->prev = (add); \
+ } \
+ } else { \
+ (add)->next = (el)->next; \
+ (add)->prev = (el)->prev; \
+ (add)->prev->next = (add); \
+ if ((el)->next == NULL) { \
+ (head)->prev = (add); \
+ } else { \
+ (add)->next->prev = (add); \
+ } \
+ } \
+} while (0)
+
+#define DL_REPLACE_ELEM(head, el, add) \
+ DL_REPLACE_ELEM2(head, el, add, prev, next)
+
+#define DL_PREPEND_ELEM2(head, el, add, prev, next) \
+do { \
+ if (el) { \
+ assert((head) != NULL); \
+ assert((add) != NULL); \
+ (add)->next = (el); \
+ (add)->prev = (el)->prev; \
+ (el)->prev = (add); \
+ if ((head) == (el)) { \
+ (head) = (add); \
+ } else { \
+ (add)->prev->next = (add); \
+ } \
+ } else { \
+ DL_APPEND2(head, add, prev, next); \
+ } \
+} while (0) \
+
+#define DL_PREPEND_ELEM(head, el, add) \
+ DL_PREPEND_ELEM2(head, el, add, prev, next)
+
+#define DL_APPEND_ELEM2(head, el, add, prev, next) \
+do { \
+ if (el) { \
+ assert((head) != NULL); \
+ assert((add) != NULL); \
+ (add)->next = (el)->next; \
+ (add)->prev = (el); \
+ (el)->next = (add); \
+ if ((add)->next) { \
+ (add)->next->prev = (add); \
+ } else { \
+ (head)->prev = (add); \
+ } \
+ } else { \
+ DL_PREPEND2(head, add, prev, next); \
+ } \
+} while (0) \
+
+#define DL_APPEND_ELEM(head, el, add) \
+ DL_APPEND_ELEM2(head, el, add, prev, next)
+
+#ifdef NO_DECLTYPE
+/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */
+
+#undef DL_INSERT_INORDER2
+#define DL_INSERT_INORDER2(head,add,cmp,next) \
+do { \
+ if ((head) == NULL) { \
+ (add)->prev = (add); \
+ (add)->next = NULL; \
+ (head) = (add); \
+ } else if ((cmp(head, add)) >= 0) { \
+ (add)->prev = (head)->prev; \
+ (add)->next = (head); \
+ (head)->prev = (add); \
+ (head) = (add); \
+ } else { \
+ char *_tmp = (char*)(head); \
+ while ((char*)(head)->next != _tmp && (cmp((head)->next, add)) < 0) { \
+ (head) = (head)->next; \
+ } \
+ (add)->prev = (head); \
+ (add)->next = (head)->next; \
+ (head)->next = (add); \
+ UTLIST_RS(head); \
+ if ((add)->next) { \
+ (add)->next->prev = (add); \
+ } else { \
+ (head)->prev = (add); \
+ } \
+ } \
+} while (0)
+#endif /* NO_DECLTYPE */
+
+/******************************************************************************
+ * circular doubly linked list macros *
+ *****************************************************************************/
+#define CDL_APPEND(head,add) \
+ CDL_APPEND2(head,add,prev,next)
+
+#define CDL_APPEND2(head,add,prev,next) \
+do { \
+ if (head) { \
+ (add)->prev = (head)->prev; \
+ (add)->next = (head); \
+ (head)->prev = (add); \
+ (add)->prev->next = (add); \
+ } else { \
+ (add)->prev = (add); \
+ (add)->next = (add); \
+ (head) = (add); \
+ } \
+} while (0)
+
+#define CDL_PREPEND(head,add) \
+ CDL_PREPEND2(head,add,prev,next)
+
+#define CDL_PREPEND2(head,add,prev,next) \
+do { \
+ if (head) { \
+ (add)->prev = (head)->prev; \
+ (add)->next = (head); \
+ (head)->prev = (add); \
+ (add)->prev->next = (add); \
+ } else { \
+ (add)->prev = (add); \
+ (add)->next = (add); \
+ } \
+ (head) = (add); \
+} while (0)
+
+#define CDL_INSERT_INORDER(head,add,cmp) \
+ CDL_INSERT_INORDER2(head,add,cmp,next)
+
+#define CDL_INSERT_INORDER2(head,add,cmp,next) \
+do { \
+ LDECLTYPE(head) _tmp; \
+ if (head) { \
+ CDL_LOWER_BOUND(head, _tmp, add, cmp); \
+ CDL_APPEND_ELEM(head, _tmp, add); \
+ } else { \
+ (head) = (add); \
+ (head)->next = (head); \
+ (head)->prev = (head); \
+ } \
+} while (0)
+
+#define CDL_LOWER_BOUND(head,elt,like,cmp) \
+ CDL_LOWER_BOUND2(head,elt,like,cmp,next)
+
+#define CDL_LOWER_BOUND2(head,elt,like,cmp,next) \
+do { \
+ if ((head) == NULL || (cmp(head, like)) >= 0) { \
+ (elt) = NULL; \
+ } else { \
+ for ((elt) = (head); (elt)->next != (head); (elt) = (elt)->next) { \
+ if ((cmp((elt)->next, like)) >= 0) { \
+ break; \
+ } \
+ } \
+ } \
+} while (0)
+
+#define CDL_DELETE(head,del) \
+ CDL_DELETE2(head,del,prev,next)
+
+#define CDL_DELETE2(head,del,prev,next) \
+do { \
+ if (((head)==(del)) && ((head)->next == (head))) { \
+ (head) = NULL; \
+ } else { \
+ (del)->next->prev = (del)->prev; \
+ (del)->prev->next = (del)->next; \
+ if ((del) == (head)) (head)=(del)->next; \
+ } \
+} while (0)
+
+#define CDL_COUNT(head,el,counter) \
+ CDL_COUNT2(head,el,counter,next) \
+
+#define CDL_COUNT2(head, el, counter,next) \
+do { \
+ (counter) = 0; \
+ CDL_FOREACH2(head,el,next) { ++(counter); } \
+} while (0)
+
+#define CDL_FOREACH(head,el) \
+ CDL_FOREACH2(head,el,next)
+
+#define CDL_FOREACH2(head,el,next) \
+ for ((el)=(head);el;(el)=(((el)->next==(head)) ? NULL : (el)->next))
+
+#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \
+ CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next)
+
+#define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \
+ for ((el) = (head), (tmp1) = (head) ? (head)->prev : NULL; \
+ (el) && ((tmp2) = (el)->next, 1); \
+ (el) = ((el) == (tmp1) ? NULL : (tmp2)))
+
+#define CDL_SEARCH_SCALAR(head,out,field,val) \
+ CDL_SEARCH_SCALAR2(head,out,field,val,next)
+
+#define CDL_SEARCH_SCALAR2(head,out,field,val,next) \
+do { \
+ CDL_FOREACH2(head,out,next) { \
+ if ((out)->field == (val)) break; \
+ } \
+} while (0)
+
+#define CDL_SEARCH(head,out,elt,cmp) \
+ CDL_SEARCH2(head,out,elt,cmp,next)
+
+#define CDL_SEARCH2(head,out,elt,cmp,next) \
+do { \
+ CDL_FOREACH2(head,out,next) { \
+ if ((cmp(out,elt))==0) break; \
+ } \
+} while (0)
+
+#define CDL_REPLACE_ELEM2(head, el, add, prev, next) \
+do { \
+ assert((head) != NULL); \
+ assert((el) != NULL); \
+ assert((add) != NULL); \
+ if ((el)->next == (el)) { \
+ (add)->next = (add); \
+ (add)->prev = (add); \
+ (head) = (add); \
+ } else { \
+ (add)->next = (el)->next; \
+ (add)->prev = (el)->prev; \
+ (add)->next->prev = (add); \
+ (add)->prev->next = (add); \
+ if ((head) == (el)) { \
+ (head) = (add); \
+ } \
+ } \
+} while (0)
+
+#define CDL_REPLACE_ELEM(head, el, add) \
+ CDL_REPLACE_ELEM2(head, el, add, prev, next)
+
+#define CDL_PREPEND_ELEM2(head, el, add, prev, next) \
+do { \
+ if (el) { \
+ assert((head) != NULL); \
+ assert((add) != NULL); \
+ (add)->next = (el); \
+ (add)->prev = (el)->prev; \
+ (el)->prev = (add); \
+ (add)->prev->next = (add); \
+ if ((head) == (el)) { \
+ (head) = (add); \
+ } \
+ } else { \
+ CDL_APPEND2(head, add, prev, next); \
+ } \
+} while (0)
+
+#define CDL_PREPEND_ELEM(head, el, add) \
+ CDL_PREPEND_ELEM2(head, el, add, prev, next)
+
+#define CDL_APPEND_ELEM2(head, el, add, prev, next) \
+do { \
+ if (el) { \
+ assert((head) != NULL); \
+ assert((add) != NULL); \
+ (add)->next = (el)->next; \
+ (add)->prev = (el); \
+ (el)->next = (add); \
+ (add)->next->prev = (add); \
+ } else { \
+ CDL_PREPEND2(head, add, prev, next); \
+ } \
+} while (0)
+
+#define CDL_APPEND_ELEM(head, el, add) \
+ CDL_APPEND_ELEM2(head, el, add, prev, next)
+
+#ifdef NO_DECLTYPE
+/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */
+
+#undef CDL_INSERT_INORDER2
+#define CDL_INSERT_INORDER2(head,add,cmp,next) \
+do { \
+ if ((head) == NULL) { \
+ (add)->prev = (add); \
+ (add)->next = (add); \
+ (head) = (add); \
+ } else if ((cmp(head, add)) >= 0) { \
+ (add)->prev = (head)->prev; \
+ (add)->next = (head); \
+ (add)->prev->next = (add); \
+ (head)->prev = (add); \
+ (head) = (add); \
+ } else { \
+ char *_tmp = (char*)(head); \
+ while ((char*)(head)->next != _tmp && (cmp((head)->next, add)) < 0) { \
+ (head) = (head)->next; \
+ } \
+ (add)->prev = (head); \
+ (add)->next = (head)->next; \
+ (add)->next->prev = (add); \
+ (head)->next = (add); \
+ UTLIST_RS(head); \
+ } \
+} while (0)
+#endif /* NO_DECLTYPE */
+
+#endif /* UTLIST_H */
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/utringbuffer.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/utringbuffer.h
new file mode 100644
index 0000000..ae15d7f
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/utringbuffer.h
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+Copyright (c) 2008-2017, Troy D. Hanson http://troydhanson.github.com/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* a ring-buffer implementation using macros
+ */
+#ifndef UTRINGBUFFER_H
+#define UTRINGBUFFER_H
+
+#define UTRINGBUFFER_VERSION 2.0.2
+
+#include <stdlib.h>
+#include <string.h>
+#include "utarray.h" // for "UT_icd"
+
+#include <audio_memory_control.h>
+
+#ifndef uthash_malloc
+#define uthash_malloc(sz) AUDIO_MALLOC(sz) /* malloc fcn */
+#endif
+#ifndef uthash_free
+#define uthash_free(ptr) AUDIO_FREE(ptr) /* free fcn */
+#endif
+
+
+typedef struct {
+ unsigned i; /* index of next available slot; wraps at n */
+ unsigned n; /* capacity */
+ unsigned char f; /* full */
+ UT_icd icd; /* initializer, copy and destructor functions */
+ char *d; /* n slots of size icd->sz */
+} UT_ringbuffer;
+
+#define utringbuffer_init(a, _n, _icd) do { \
+ memset(a, 0, sizeof(UT_ringbuffer)); \
+ (a)->icd = *(_icd); \
+ (a)->n = (_n); \
+ if ((a)->n) { (a)->d = (char*)uthash_malloc((a)->n * (_icd)->sz); } \
+} while(0)
+
+#define utringbuffer_clear(a) do { \
+ if ((a)->icd.dtor) { \
+ if ((a)->f) { \
+ unsigned _ut_i; \
+ for (_ut_i = 0; _ut_i < (a)->n; ++_ut_i) { \
+ (a)->icd.dtor(utringbuffer_eltptr(a, _ut_i)); \
+ } \
+ } else { \
+ unsigned _ut_i; \
+ for (_ut_i = 0; _ut_i < (a)->i; ++_ut_i) { \
+ (a)->icd.dtor(utringbuffer_eltptr(a, _ut_i)); \
+ } \
+ } \
+ } \
+ (a)->i = 0; \
+ (a)->f = 0; \
+} while(0)
+
+#define utringbuffer_done(a) do { \
+ utringbuffer_clear(a); \
+ uthash_free((a)->d); (a)->d = NULL; \
+ (a)->n = 0; \
+} while(0)
+
+#define utringbuffer_new(a,n,_icd) do { \
+ a = (UT_ringbuffer*)uthash_malloc(sizeof(UT_ringbuffer)); \
+ utringbuffer_init(a, n, _icd); \
+} while(0)
+
+#define utringbuffer_free(a) do { \
+ utringbuffer_done(a); \
+ uthash_free(a); \
+} while(0)
+
+#define utringbuffer_push_back(a,p) do { \
+ if ((a)->icd.dtor && (a)->f) { (a)->icd.dtor(_utringbuffer_internalptr(a,(a)->i)); } \
+ if ((a)->icd.copy) { (a)->icd.copy( _utringbuffer_internalptr(a,(a)->i), p); } \
+ else { memcpy(_utringbuffer_internalptr(a,(a)->i), p, (a)->icd.sz); }; \
+ if (++(a)->i == (a)->n) { (a)->i = 0; (a)->f = 1; } \
+} while(0)
+
+#define utringbuffer_len(a) ((a)->f ? (a)->n : (a)->i)
+#define utringbuffer_empty(a) ((a)->i == 0 && !(a)->f)
+#define utringbuffer_full(a) ((a)->f != 0)
+
+#define _utringbuffer_real_idx(a,j) ((a)->f ? ((j) + (a)->i) % (a)->n : (j))
+#define _utringbuffer_internalptr(a,j) ((void*)((a)->d + ((a)->icd.sz * (j))))
+#define utringbuffer_eltptr(a,j) ((0 <= (j) && (j) < utringbuffer_len(a)) ? _utringbuffer_internalptr(a,_utringbuffer_real_idx(a,j)) : NULL)
+
+#define _utringbuffer_fake_idx(a,j) ((a)->f ? ((j) + (a)->n - (a)->i) % (a)->n : (j))
+#define _utringbuffer_internalidx(a,e) (((char*)(e) >= (a)->d) ? (((char*)(e) - (a)->d)/(a)->icd.sz) : -1)
+#define utringbuffer_eltidx(a,e) _utringbuffer_fake_idx(a, _utringbuffer_internalidx(a,e))
+
+#define utringbuffer_front(a) utringbuffer_eltptr(a,0)
+#define utringbuffer_next(a,e) ((e)==NULL ? utringbuffer_front(a) : utringbuffer_eltptr(a, utringbuffer_eltidx(a,e)+1))
+#define utringbuffer_prev(a,e) ((e)==NULL ? utringbuffer_back(a) : utringbuffer_eltptr(a, utringbuffer_eltidx(a,e)-1))
+#define utringbuffer_back(a) (utringbuffer_empty(a) ? NULL : utringbuffer_eltptr(a, utringbuffer_len(a) - 1))
+
+#endif /* UTRINGBUFFER_H */
diff --git a/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/utstring.h b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/utstring.h
new file mode 100644
index 0000000..66cc052
--- /dev/null
+++ b/src/multimedia/libspeech_drv/audio_big_sw/sp_hal/utility/uthash/utstring.h
@@ -0,0 +1,408 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+Copyright (c) 2008-2017, Troy D. Hanson http://troydhanson.github.com/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* a dynamic string implementation using macros
+ */
+#ifndef UTSTRING_H
+#define UTSTRING_H
+
+#define UTSTRING_VERSION 2.0.2
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <audio_memory_control.h>
+
+#ifndef uthash_malloc
+#define uthash_malloc(sz) AUDIO_MALLOC(sz) /* malloc fcn */
+#endif
+#ifndef uthash_free
+#define uthash_free(ptr) AUDIO_FREE(ptr) /* free fcn */
+#endif
+
+#ifdef __GNUC__
+#define UTSTRING_UNUSED __attribute__((__unused__))
+#else
+#define UTSTRING_UNUSED
+#endif
+
+#ifndef oom
+#define oom() exit(-1)
+#endif
+
+typedef struct {
+ char *d; /* pointer to allocated buffer */
+ size_t n; /* allocated capacity */
+ size_t i; /* index of first unused byte */
+} UT_string;
+
+#define utstring_reserve(s,amt) \
+do { \
+ if (((s)->n - (s)->i) < (size_t)(amt)) { \
+ char *utstring_tmp = (char*)realloc( \
+ (s)->d, (s)->n + (amt)); \
+ if (utstring_tmp == NULL) oom(); \
+ (s)->d = utstring_tmp; \
+ (s)->n += (amt); \
+ } \
+} while(0)
+
+#define utstring_init(s) \
+do { \
+ (s)->n = 0; (s)->i = 0; (s)->d = NULL; \
+ utstring_reserve(s,100); \
+ (s)->d[0] = '\0'; \
+} while(0)
+
+#define utstring_done(s) \
+do { \
+ if ((s)->d != NULL) uthash_free((s)->d); \
+ (s)->n = 0; \
+} while(0)
+
+#define utstring_free(s) \
+do { \
+ utstring_done(s); \
+ uthash_free(s); \
+} while(0)
+
+#define utstring_new(s) \
+do { \
+ (s) = (UT_string*)uthash_malloc(sizeof(UT_string)); \
+ if (!(s)) oom(); \
+ utstring_init(s); \
+} while(0)
+
+#define utstring_renew(s) \
+do { \
+ if (s) { \
+ utstring_clear(s); \
+ } else { \
+ utstring_new(s); \
+ } \
+} while(0)
+
+#define utstring_clear(s) \
+do { \
+ (s)->i = 0; \
+ (s)->d[0] = '\0'; \
+} while(0)
+
+#define utstring_bincpy(s,b,l) \
+do { \
+ utstring_reserve((s),(l)+1); \
+ if (l) memcpy(&(s)->d[(s)->i], b, l); \
+ (s)->i += (l); \
+ (s)->d[(s)->i]='\0'; \
+} while(0)
+
+#define utstring_concat(dst,src) \
+do { \
+ utstring_reserve((dst),((src)->i)+1); \
+ if ((src)->i) memcpy(&(dst)->d[(dst)->i], (src)->d, (src)->i); \
+ (dst)->i += (src)->i; \
+ (dst)->d[(dst)->i]='\0'; \
+} while(0)
+
+#define utstring_len(s) ((s)->i)
+
+#define utstring_body(s) ((s)->d)
+
+UTSTRING_UNUSED static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) {
+ int n;
+ va_list cp;
+ for (;;) {
+#ifdef _WIN32
+ cp = ap;
+#else
+ va_copy(cp, ap);
+#endif
+ n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp);
+ va_end(cp);
+
+ if ((n > -1) && ((size_t) n < (s->n-s->i))) {
+ s->i += n;
+ return;
+ }
+
+ /* Else try again with more space. */
+ if (n > -1) utstring_reserve(s,n+1); /* exact */
+ else utstring_reserve(s,(s->n)*2); /* 2x */
+ }
+}
+#ifdef __GNUC__
+/* support printf format checking (2=the format string, 3=start of varargs) */
+static void utstring_printf(UT_string *s, const char *fmt, ...)
+ __attribute__ (( format( printf, 2, 3) ));
+#endif
+UTSTRING_UNUSED static void utstring_printf(UT_string *s, const char *fmt, ...) {
+ va_list ap;
+ va_start(ap,fmt);
+ utstring_printf_va(s,fmt,ap);
+ va_end(ap);
+}
+
+/*******************************************************************************
+ * begin substring search functions *
+ ******************************************************************************/
+/* Build KMP table from left to right. */
+UTSTRING_UNUSED static void _utstring_BuildTable(
+ const char *P_Needle,
+ size_t P_NeedleLen,
+ long *P_KMP_Table)
+{
+ long i, j;
+
+ i = 0;
+ j = i - 1;
+ P_KMP_Table[i] = j;
+ while (i < (long) P_NeedleLen)
+ {
+ while ( (j > -1) && (P_Needle[i] != P_Needle[j]) )
+ {
+ j = P_KMP_Table[j];
+ }
+ i++;
+ j++;
+ if (i < (long) P_NeedleLen)
+ {
+ if (P_Needle[i] == P_Needle[j])
+ {
+ P_KMP_Table[i] = P_KMP_Table[j];
+ }
+ else
+ {
+ P_KMP_Table[i] = j;
+ }
+ }
+ else
+ {
+ P_KMP_Table[i] = j;
+ }
+ }
+
+ return;
+}
+
+
+/* Build KMP table from right to left. */
+UTSTRING_UNUSED static void _utstring_BuildTableR(
+ const char *P_Needle,
+ size_t P_NeedleLen,
+ long *P_KMP_Table)
+{
+ long i, j;
+
+ i = P_NeedleLen - 1;
+ j = i + 1;
+ P_KMP_Table[i + 1] = j;
+ while (i >= 0)
+ {
+ while ( (j < (long) P_NeedleLen) && (P_Needle[i] != P_Needle[j]) )
+ {
+ j = P_KMP_Table[j + 1];
+ }
+ i--;
+ j--;
+ if (i >= 0)
+ {
+ if (P_Needle[i] == P_Needle[j])
+ {
+ P_KMP_Table[i + 1] = P_KMP_Table[j + 1];
+ }
+ else
+ {
+ P_KMP_Table[i + 1] = j;
+ }
+ }
+ else
+ {
+ P_KMP_Table[i + 1] = j;
+ }
+ }
+
+ return;
+}
+
+
+/* Search data from left to right. ( Multiple search mode. ) */
+UTSTRING_UNUSED static long _utstring_find(
+ const char *P_Haystack,
+ size_t P_HaystackLen,
+ const char *P_Needle,
+ size_t P_NeedleLen,
+ long *P_KMP_Table)
+{
+ long i, j;
+ long V_FindPosition = -1;
+
+ /* Search from left to right. */
+ i = j = 0;
+ while ( (j < (int)P_HaystackLen) && (((P_HaystackLen - j) + i) >= P_NeedleLen) )
+ {
+ while ( (i > -1) && (P_Needle[i] != P_Haystack[j]) )
+ {
+ i = P_KMP_Table[i];
+ }
+ i++;
+ j++;
+ if (i >= (int)P_NeedleLen)
+ {
+ /* Found. */
+ V_FindPosition = j - i;
+ break;
+ }
+ }
+
+ return V_FindPosition;
+}
+
+
+/* Search data from right to left. ( Multiple search mode. ) */
+UTSTRING_UNUSED static long _utstring_findR(
+ const char *P_Haystack,
+ size_t P_HaystackLen,
+ const char *P_Needle,
+ size_t P_NeedleLen,
+ long *P_KMP_Table)
+{
+ long i, j;
+ long V_FindPosition = -1;
+
+ /* Search from right to left. */
+ j = (P_HaystackLen - 1);
+ i = (P_NeedleLen - 1);
+ while ( (j >= 0) && (j >= i) )
+ {
+ while ( (i < (int)P_NeedleLen) && (P_Needle[i] != P_Haystack[j]) )
+ {
+ i = P_KMP_Table[i + 1];
+ }
+ i--;
+ j--;
+ if (i < 0)
+ {
+ /* Found. */
+ V_FindPosition = j + 1;
+ break;
+ }
+ }
+
+ return V_FindPosition;
+}
+
+
+/* Search data from left to right. ( One time search mode. ) */
+UTSTRING_UNUSED static long utstring_find(
+ UT_string *s,
+ long P_StartPosition, /* Start from 0. -1 means last position. */
+ const char *P_Needle,
+ size_t P_NeedleLen)
+{
+ long V_StartPosition;
+ long V_HaystackLen;
+ long *V_KMP_Table = NULL;
+ long V_FindPosition = -1;
+
+ if (P_StartPosition < 0)
+ {
+ V_StartPosition = s->i + P_StartPosition;
+ }
+ else
+ {
+ V_StartPosition = P_StartPosition;
+ }
+ V_HaystackLen = s->i - V_StartPosition;
+ if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) )
+ {
+ V_KMP_Table = (long *)uthash_malloc(sizeof(long) * (P_NeedleLen + 1));
+ if (V_KMP_Table != NULL)
+ {
+ _utstring_BuildTable(P_Needle, P_NeedleLen, V_KMP_Table);
+
+ V_FindPosition = _utstring_find(s->d + V_StartPosition,
+ V_HaystackLen,
+ P_Needle,
+ P_NeedleLen,
+ V_KMP_Table);
+ if (V_FindPosition >= 0)
+ {
+ V_FindPosition += V_StartPosition;
+ }
+
+ uthash_free(V_KMP_Table);
+ }
+ }
+
+ return V_FindPosition;
+}
+
+
+/* Search data from right to left. ( One time search mode. ) */
+UTSTRING_UNUSED static long utstring_findR(
+ UT_string *s,
+ long P_StartPosition, /* Start from 0. -1 means last position. */
+ const char *P_Needle,
+ size_t P_NeedleLen)
+{
+ long V_StartPosition;
+ long V_HaystackLen;
+ long *V_KMP_Table = NULL;
+ long V_FindPosition = -1;
+
+ if (P_StartPosition < 0)
+ {
+ V_StartPosition = s->i + P_StartPosition;
+ }
+ else
+ {
+ V_StartPosition = P_StartPosition;
+ }
+ V_HaystackLen = V_StartPosition + 1;
+ if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) )
+ {
+ V_KMP_Table = (long *)uthash_malloc(sizeof(long) * (P_NeedleLen + 1));
+ if (V_KMP_Table != NULL)
+ {
+ _utstring_BuildTableR(P_Needle, P_NeedleLen, V_KMP_Table);
+
+ V_FindPosition = _utstring_findR(s->d,
+ V_HaystackLen,
+ P_Needle,
+ P_NeedleLen,
+ V_KMP_Table);
+
+ uthash_free(V_KMP_Table);
+ }
+ }
+
+ return V_FindPosition;
+}
+/*******************************************************************************
+ * end substring search functions *
+ ******************************************************************************/
+
+#endif /* UTSTRING_H */
diff --git a/src/telephonyware/3.0/mipc/mt2735_ivt_nlwg_wide_temp_b30rx_custom/mipc.release.tar.gz b/src/telephonyware/3.0/mipc/mt2735_ivt_nlwg_wide_temp_b30rx_custom/mipc.release.tar.gz
new file mode 100644
index 0000000..0680cd4
--- /dev/null
+++ b/src/telephonyware/3.0/mipc/mt2735_ivt_nlwg_wide_temp_b30rx_custom/mipc.release.tar.gz
Binary files differ