/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2019. All rights reserved. * Description: MPI function file for Huanglong audio output * Author: audio * Create: 2019-05-30 */ #include #include #include #include #include #include #include #include #include #include #include "mpi_ao_debug.h" #include "mpi_ao.h" #include "securec.h" #include "mpi_memory_ext.h" #include "mpi_ao_ext.h" #include "mpi_ao_vir.h" #include "mpi_ao_lowlatency.h" #include "mpi_ao_effect.h" #include "mpi_ao_plugin.h" #ifdef __cplusplus #if __cplusplus extern "C" { #endif #endif /* __cplusplus */ static td_s32 g_ao_fd = -1; #define SOC_DEV_AO_NAME "soc_ao" #define DEVNAME_AO "/dev/" SOC_DEV_AO_NAME static td_u32 g_ao_init_cnt = 0; static pthread_mutex_t g_ao_mutex = PTHREAD_MUTEX_INITIALIZER; static td_handle g_ad_master_track = TD_NULL; static td_handle g_ad_slave_track = TD_NULL; #define ao_lock(ao_mutex) \ do { \ (td_void)pthread_mutex_lock(&(ao_mutex)); \ } while (0) #define ao_unlock(ao_mutex) \ do { \ (td_void)pthread_mutex_unlock(&(ao_mutex)); \ } while (0) static ext_ao_ext_module_info g_ao_ext_modules[] = { { .module_id = SOC_ID_AVPLAY, { .attach = TD_NULL, .detach = TD_NULL, }, }, { .module_id = SOC_ID_AI, { .attach = TD_NULL, .detach = TD_NULL, }, }, }; td_s32 ext_mpi_ao_register_extern_func(const td_u32 module_id, const ext_ao_ext_module_fn *func) { td_u32 i; check_ao_null_ptr(func); for (i = 0; i < sizeof(g_ao_ext_modules) / sizeof(g_ao_ext_modules[0]); i++) { if (g_ao_ext_modules[i].module_id != module_id) { continue; } ao_lock(g_ao_mutex); g_ao_ext_modules[i].func.attach = func->attach; g_ao_ext_modules[i].func.detach = func->detach; ao_unlock(g_ao_mutex); return TD_SUCCESS; } return SOC_ERR_AO_INVALID_PARA; } td_s32 ext_mpi_ao_unregister_extern_func(const td_u32 module_id) { td_u32 i; for (i = 0; i < sizeof(g_ao_ext_modules) / sizeof(g_ao_ext_modules[0]); i++) { if (g_ao_ext_modules[i].module_id != module_id) { continue; } ao_lock(g_ao_mutex); g_ao_ext_modules[i].func.attach = TD_NULL; g_ao_ext_modules[i].func.detach = TD_NULL; ao_unlock(g_ao_mutex); return TD_SUCCESS; } return SOC_ERR_AO_INVALID_PARA; } td_s32 ext_mpi_ao_get_extern_func(const td_u32 module_id, ext_ao_ext_module_fn *func) { td_u32 i; check_ao_null_ptr(func); for (i = 0; i < sizeof(g_ao_ext_modules) / sizeof(g_ao_ext_modules[0]); i++) { if (g_ao_ext_modules[i].module_id != module_id) { continue; } ao_lock(g_ao_mutex); func->attach = g_ao_ext_modules[i].func.attach; func->detach = g_ao_ext_modules[i].func.detach; ao_unlock(g_ao_mutex); return TD_SUCCESS; } return SOC_ERR_AO_INVALID_PARA; } static td_s32 create_ad_track(td_handle track) { td_s32 ret; td_handle track_ad = TD_INVALID_HANDLE; ext_ao_track_attr attr = { 0 }; ret = ext_mpi_ao_track_get_default_open_attr(EXT_AO_TRACK_TYPE_SLAVE, &attr); if (ret != TD_SUCCESS) { soc_log_err("get_default_open_attr failed\n"); return ret; } ret = ext_mpi_ao_track_create(AO_SND_0, &attr, &track_ad); if (ret != TD_SUCCESS) { soc_log_err("create ad track failed\n"); return ret; } g_ad_master_track = track; g_ad_slave_track = track_ad; ret = ext_mpi_ao_track_start(g_ad_slave_track); if (ret != TD_SUCCESS) { soc_log_err("ext_mpi_ao_track_track for AD start failed(%x).\n", ret); return ret; } return TD_SUCCESS; } static td_s32 destroy_ad_track(td_handle track) { td_s32 ret; check_ao_track_id(track); if (track != g_ad_master_track) { soc_log_err("track is not AD track\n"); return TD_FAILURE; } if (g_ad_slave_track != TD_NULL) { ret = ext_mpi_ao_track_destroy(g_ad_slave_track); if (ret != TD_SUCCESS) { soc_log_err("ext_mpi_ao_track_destroy failed\n"); return ret; } g_ad_master_track = TD_NULL; g_ad_slave_track = TD_NULL; } else { soc_log_err("set AD disable before this\n"); } return TD_SUCCESS; } static td_void audio_iapi_frame_to_drv_frame(const ext_ao_frame *iapi_frame, ao_frame *drv_frame) { drv_frame->pts = iapi_frame->pts; drv_frame->bit_depth = iapi_frame->bit_depth; drv_frame->interleaved = iapi_frame->interleaved; drv_frame->sample_rate = iapi_frame->sample_rate; drv_frame->channels = iapi_frame->channels; drv_frame->frame_index = iapi_frame->frame_index; drv_frame->pcm_samples = iapi_frame->pcm_samples; drv_frame->bits_bytes = iapi_frame->bits_bytes; drv_frame->md_and_obj_bytes = iapi_frame->md_and_obj_bytes; drv_frame->iec_data_type = iapi_frame->iec_data_type; drv_frame->pcm_buffer = (td_u64)(uintptr_t)iapi_frame->pcm_buffer; drv_frame->bits_buffer = (td_u64)(uintptr_t)iapi_frame->bits_buffer; drv_frame->md_and_obj_buffer = (td_u64)(uintptr_t)iapi_frame->md_and_obj_buffer; } static td_void audio_drv_frame_to_iapi_frame(const ao_frame *drv_frame, ext_ao_frame *iapi_frame) { iapi_frame->pts = drv_frame->pts; iapi_frame->bit_depth = drv_frame->bit_depth; iapi_frame->interleaved = drv_frame->interleaved; iapi_frame->sample_rate = drv_frame->sample_rate; iapi_frame->channels = drv_frame->channels; iapi_frame->frame_index = drv_frame->frame_index; iapi_frame->pcm_samples = drv_frame->pcm_samples; iapi_frame->bits_bytes = drv_frame->bits_bytes; iapi_frame->iec_data_type = drv_frame->iec_data_type; iapi_frame->pcm_buffer = TD_NULL; iapi_frame->bits_buffer = TD_NULL; } td_s32 ext_mpi_ao_init(td_void) { ao_lock(g_ao_mutex); if (g_ao_init_cnt != 0) { g_ao_init_cnt++; ao_unlock(g_ao_mutex); return TD_SUCCESS; } if (g_ao_fd < 0) { g_ao_fd = open(DEVNAME_AO, O_RDWR, 0); if (g_ao_fd < 0) { soc_log_fatal("open_ao_device err\n"); g_ao_fd = -1; ao_unlock(g_ao_mutex); return SOC_ERR_AO_CREATE_FAIL; } } vir_init_rs(); ext_mpi_ao_aef_init(); g_ao_init_cnt++; ao_unlock(g_ao_mutex); return TD_SUCCESS; } td_s32 ext_mpi_ao_de_init(td_void) { td_s32 ret; ao_lock(g_ao_mutex); if (g_ao_init_cnt == 0) { ao_unlock(g_ao_mutex); return TD_SUCCESS; } g_ao_init_cnt--; if (g_ao_init_cnt == 0) { if (g_ao_fd >= 0) { ret = close(g_ao_fd); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(close, ret); soc_err_print_s32(g_ao_fd); } g_ao_fd = -1; } ext_mpi_ao_aef_deinit(); vir_de_init_rs(); } ao_unlock(g_ao_mutex); return TD_SUCCESS; } td_s32 mpi_ao_get_fd(td_void) { td_s32 fd; ao_lock(g_ao_mutex); if ((g_ao_init_cnt == 0) || (g_ao_fd < 0)) { fd = -1; } else { fd = g_ao_fd; } ao_unlock(g_ao_mutex); return fd; } td_s32 ext_mpi_ao_snd_get_default_open_attr(const ao_snd_id sound, ext_ao_attr *attr) { td_s32 ret; ao_snd_open_default_param default_param = { .sound = sound, }; check_ao_null_ptr(attr); ret = ioctl(g_ao_fd, CMD_AO_GETSNDDEFOPENATTR, &default_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_GETSNDDEFOPENATTR failed(0x%x)\n", ret); return ret; } ret = memcpy_s(attr, sizeof(*attr), &default_param.attr, sizeof(ext_ao_attr)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_open(const ao_snd_id sound, const ext_ao_attr *attr) { td_s32 ret; ao_snd_open_param snd = { .sound = sound, }; check_ao_null_ptr(attr); ret = memcpy_s(&snd.attr, sizeof(ext_ao_attr), attr, sizeof(*attr)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return ioctl(g_ao_fd, CMD_AO_SND_OPEN, &snd); } td_s32 ext_mpi_ao_snd_close(const ao_snd_id sound) { return ioctl(g_ao_fd, CMD_AO_SND_CLOSE, &sound); } td_s32 ext_mpi_ao_snd_set_mute(const ao_snd_id sound, const ext_ao_port port, const td_bool mute) { ao_snd_mute_param mute_param = { .sound = sound, .out_port = port, .mute = mute, }; return ioctl(g_ao_fd, CMD_AO_SND_SETMUTE, &mute_param); } td_s32 ext_mpi_ao_snd_get_mute(const ao_snd_id sound, const ext_ao_port port, td_bool *mute) { td_s32 ret; ao_snd_mute_param mute_param = { .sound = sound, .out_port = port, .mute = TD_FALSE, }; check_ao_null_ptr(mute); ret = ioctl(g_ao_fd, CMD_AO_SND_GETMUTE, &mute_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETMUTE failed\n"); soc_err_print_err_code(ret); return ret; } *mute = mute_param.mute; return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_soft_mute(const ao_snd_id sound, const ext_ao_port port, const td_bool mute) { ao_snd_mute_param mute_param = { .sound = sound, .out_port = port, .mute = mute, }; return ioctl(g_ao_fd, CMD_AO_SND_SET_SOFTMUTE, &mute_param); } td_s32 ext_mpi_ao_snd_get_soft_mute(const ao_snd_id sound, const ext_ao_port port, td_bool *mute) { td_s32 ret; ao_snd_mute_param mute_param = { .sound = sound, .out_port = port, .mute = TD_FALSE, }; check_ao_null_ptr(mute); ret = ioctl(g_ao_fd, CMD_AO_SND_GET_SOFTMUTE, &mute_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETMUTE failed\n"); soc_err_print_err_code(ret); return ret; } *mute = mute_param.mute; return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_output_mode(const ao_snd_id sound, const ext_ao_port port, const ext_ao_ouput_mode mode) { ao_snd_output_mode_param param = { .sound = sound, .ao_port = port, .mode = mode, }; return ioctl(g_ao_fd, CMD_AO_SND_SETOUTPUTMODE, ¶m); } td_s32 ext_mpi_ao_snd_get_output_mode(const ao_snd_id sound, const ext_ao_port port, ext_ao_ouput_mode *mode) { td_s32 ret; ao_snd_output_mode_param param = { .sound = sound, .ao_port = port, .mode = EXT_AO_OUTPUT_MODE_MAX, }; check_ao_null_ptr(mode); ret = ioctl(g_ao_fd, CMD_AO_SND_GETOUTPUTMODE, ¶m); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETOUTPUTMODE failed\n"); soc_err_print_err_code(ret); return ret; } *mode = param.mode; return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_volume(const ao_snd_id sound, const ext_ao_port port, const ext_ao_gain *gain) { td_s32 ret; ao_snd_volume_param volume = { .sound = sound, .out_port = port, }; check_ao_null_ptr(gain); ret = memcpy_s(&volume.gain, sizeof(ext_ao_gain), gain, sizeof(*gain)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } ret = ioctl(g_ao_fd, CMD_AO_SND_SETVOLUME, &volume); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_SETVOLUME failed(0x%x)", ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_get_volume(ao_snd_id sound, ext_ao_port port, ext_ao_gain *gain) { td_s32 ret; ao_snd_volume_param volume = { .sound = sound, .out_port = port, }; check_ao_null_ptr(gain); ret = ioctl(g_ao_fd, CMD_AO_SND_GETVOLUME, &volume); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETVOLUME failed(0x%x)", ret); return ret; } ret = memcpy_s(gain, sizeof(*gain), &volume.gain, sizeof(ext_ao_gain)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_spdif_category_code(ao_snd_id sound, ext_ao_port port, ext_ao_spdif_category_code spdif_category_code) { ao_snd_spdif_category_code_param param = { .sound = sound, .out_port = port, .category_code = spdif_category_code, }; return ioctl(g_ao_fd, CMD_AO_SND_SETSPDIFCATEGORYCODE, ¶m); } td_s32 ext_mpi_ao_snd_get_spdif_category_code(ao_snd_id sound, ext_ao_port port, ext_ao_spdif_category_code *spdif_category_code) { td_s32 ret; ao_snd_spdif_category_code_param param = { .sound = sound, .out_port = port, .category_code = EXT_AO_SPDIF_CATEGORY_MAX, }; check_ao_null_ptr(spdif_category_code); ret = ioctl(g_ao_fd, CMD_AO_SND_GETSPDIFCATEGORYCODE, ¶m); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETSPDIFCATEGORYCODE failed\n"); soc_err_print_err_code(ret); return ret; } *spdif_category_code = param.category_code; return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_spdif_scms_mode(ao_snd_id sound, ext_ao_port port, ext_ao_spdif_scms_mode spdif_scms_mode) { ao_snd_spdif_scms_mode_param param = { .sound = sound, .out_port = port, .scms_mode = spdif_scms_mode, }; return ioctl(g_ao_fd, CMD_AO_SND_SETSPDIFSCMSMODE, ¶m); } td_s32 ext_mpi_ao_snd_get_spdif_scms_mode(ao_snd_id sound, ext_ao_port port, ext_ao_spdif_scms_mode *spdif_scms_mode) { td_s32 ret; ao_snd_spdif_scms_mode_param param = { .sound = sound, .out_port = port, .scms_mode = EXT_AO_SPDIF_SCMS_MODE_MAX, }; check_ao_null_ptr(spdif_scms_mode); ret = ioctl(g_ao_fd, CMD_AO_SND_GETSPDIFSCMSMODE, ¶m); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETSPDIFSCMSMODE failed\n"); soc_err_print_err_code(ret); return ret; } *spdif_scms_mode = param.scms_mode; return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_track_mode(ao_snd_id sound, ext_ao_port port, ext_track_mode mode) { ao_snd_track_mode_param track_mode = { .sound = sound, .out_port = port, .mode = mode, }; return ioctl(g_ao_fd, CMD_AO_SND_SETTRACKMODE, &track_mode); } td_s32 ext_mpi_ao_snd_get_track_mode(ao_snd_id sound, ext_ao_port port, ext_track_mode *mode) { td_s32 ret; ao_snd_track_mode_param track_mode = { .sound = sound, .out_port = port, .mode = EXT_TRACK_MODE_MAX, }; check_ao_null_ptr(mode); ret = ioctl(g_ao_fd, CMD_AO_SND_GETTRACKMODE, &track_mode); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETTRACKMODE failed\n"); soc_err_print_err_code(ret); return ret; } *mode = track_mode.mode; return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_get_xrun_count(ao_snd_id sound, td_u32 *count) { td_s32 ret; ao_snd_get_xrun_param xun_param = { .sound = sound, .count = 0, }; check_ao_null_ptr(count); ret = ioctl(g_ao_fd, CMD_AO_SND_GETXRUNCOUNT, &xun_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETXRUNCOUNT failed\n"); soc_err_print_err_code(ret); return ret; } *count = xun_param.count; return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_all_track_mute(ao_snd_id sound, td_bool mute) { ao_snd_all_track_mute_param all_track_mute = { .sound = sound, .mute = mute, }; return ioctl(g_ao_fd, CMD_AO_SND_SETALLTRACKMUTE, &all_track_mute); } td_s32 ext_mpi_ao_snd_get_all_track_mute(ao_snd_id sound, td_bool *mute) { td_s32 ret; ao_snd_all_track_mute_param all_track_mute = { .sound = sound, .mute = TD_FALSE, }; check_ao_null_ptr(mute); ret = ioctl(g_ao_fd, CMD_AO_SND_GETALLTRACKMUTE, &all_track_mute); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETALLTRACKMUTE failed\n"); soc_err_print_err_code(ret); return ret; } *mute = all_track_mute.mute; return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_low_latency(ao_snd_id sound, ext_ao_port port, td_u32 latecny_ms) { ao_snd_set_low_latency_param low_latency_param = { .sound = sound, .out_port = port, .latency_ms = latecny_ms, }; return ioctl(g_ao_fd, CMD_AO_SND_SETLOWLATENCY, &low_latency_param); } td_s32 ext_mpi_ao_snd_get_low_latency(ao_snd_id sound, ext_ao_port port, td_u32 *latecny_ms) { td_s32 ret; ao_snd_set_low_latency_param low_latency_param = { .sound = sound, .out_port = port, .latency_ms = 0, }; check_ao_null_ptr(latecny_ms); ret = ioctl(g_ao_fd, CMD_AO_SND_GETLOWLATENCY, &low_latency_param); if (ret == TD_SUCCESS) { *latecny_ms = low_latency_param.latency_ms; } return ret; } td_s32 ext_mpi_ao_snd_set_precision_volume(ao_snd_id sound, ext_ao_port port, const ext_ao_preci_gain *gain) { td_s32 ret; ao_snd_preci_volume_param preci_vol = { .sound = sound, .out_port = port, }; check_ao_null_ptr(gain); ret = memcpy_s(&preci_vol.preci_gain, sizeof(ext_ao_preci_gain), gain, sizeof(*gain)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } ret = ioctl(g_ao_fd, CMD_AO_SND_SETPRECIVOL, &preci_vol); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_SETPRECIVOL failed(0x%x)", ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_get_precision_volume(ao_snd_id sound, ext_ao_port port, ext_ao_preci_gain *preci_gain) { td_s32 ret; ao_snd_preci_volume_param preci_vol = { .sound = sound, .out_port = port, }; check_ao_null_ptr(preci_gain); ret = ioctl(g_ao_fd, CMD_AO_SND_GETPRECIVOL, &preci_vol); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETPRECIVOL failed(0x%x)", ret); return ret; } ret = memcpy_s(preci_gain, sizeof(*preci_gain), &preci_vol.preci_gain, sizeof(ext_ao_preci_gain)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_balance(ao_snd_id sound, ext_ao_port out_port, td_s32 balance) { ao_snd_balance_param balance_param = { .sound = sound, .out_port = out_port, .balance = balance, }; return ioctl(g_ao_fd, CMD_AO_SND_SETBALANCE, &balance_param); } td_s32 ext_mpi_ao_snd_get_balance(ao_snd_id sound, ext_ao_port out_port, td_s32 *balance) { td_s32 ret; ao_snd_balance_param balance_param = { .sound = sound, .out_port = out_port, .balance = 0, }; check_ao_null_ptr(balance); ret = ioctl(g_ao_fd, CMD_AO_SND_GETBALANCE, &balance_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETBALANCE failed\n"); soc_err_print_err_code(ret); return ret; } *balance = balance_param.balance; return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_arc_cap(ao_snd_id sound, ext_ao_port out_port, const ext_ao_arc_audio_cap *arc_cap) { td_s32 ret; ao_snd_arc_cap_param arc_cap_param = { .sound = sound, .out_port = out_port, }; check_ao_null_ptr(arc_cap); ret = memcpy_s(&arc_cap_param.cap, sizeof(ext_ao_arc_audio_cap), arc_cap, sizeof(*arc_cap)); if (ret != EOK) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } return ioctl(g_ao_fd, CMD_AO_SND_SETARCCAP, &arc_cap_param); } td_s32 ext_mpi_ao_snd_get_arc_cap(ao_snd_id sound, ext_ao_port out_port, ext_ao_arc_audio_cap *arc_cap) { td_s32 ret; ao_snd_arc_cap_param arc_cap_param = { .sound = sound, .out_port = out_port, }; check_ao_null_ptr(arc_cap); ret = ioctl(g_ao_fd, CMD_AO_SND_GETARCCAP, &arc_cap); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETARCCAP failed\n"); soc_err_print_err_code(ret); return ret; } ret = memcpy_s(arc_cap, sizeof(*arc_cap), &arc_cap_param.cap, sizeof(ext_ao_arc_audio_cap)); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_ad_output_enable(ao_snd_id sound, ext_ao_port out_port, td_bool enable) { ao_snd_ad_output_enable ad_output_enable = { .sound = sound, .out_port = out_port, .ad_output_enable = enable, }; return ioctl(g_ao_fd, CMD_AO_SND_SETADOUTPUTENABLE, &ad_output_enable); } td_s32 ext_mpi_ao_snd_get_ad_output_enable(ao_snd_id sound, ext_ao_port out_port, td_bool *enable) { td_s32 ret; ao_snd_ad_output_enable ad_output_enable = { .sound = sound, .out_port = out_port, .ad_output_enable = TD_FALSE, }; check_ao_null_ptr(enable); ret = ioctl(g_ao_fd, CMD_AO_SND_GETADOUTPUTENABLE, &ad_output_enable); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETADOUTPUTENABLE failed\n"); soc_err_print_err_code(ret); return ret; } *enable = ad_output_enable.ad_output_enable; return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_alsa_prescale(ao_snd_id sound, const ext_ao_preci_gain *preci_gain) { td_s32 ret; ao_snd_set_alsa_prescale alsa_prescale = { .sound = sound, }; check_ao_null_ptr(preci_gain); ret = memcpy_s(&alsa_prescale.preci_gain, sizeof(ext_ao_preci_gain), preci_gain, sizeof(*preci_gain)); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } return ioctl(g_ao_fd, CMD_AO_SND_SETALSAPRESCALE, &alsa_prescale); } td_s32 ext_mpi_ao_snd_set_alsa_mute(ao_snd_id sound, td_bool mute) { ao_snd_set_alsa_mute alsa_mute = { .sound = sound, .mute = mute, }; return ioctl(g_ao_fd, CMD_AO_SND_SETALSAMUTE, &alsa_mute); } td_s32 ext_mpi_ao_snd_get_track_info(ao_snd_id sound, ext_ao_track_info *track_info) { td_s32 ret; ao_snd_track_info_param track_info_param = { .sound = sound, }; check_ao_null_ptr(track_info); ret = ioctl(g_ao_fd, CMD_AO_SND_GETTRACKINFO, &track_info_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETTRACKINFO failed\n"); soc_err_print_err_code(ret); return ret; } ret = memcpy_s(track_info, sizeof(*track_info), &track_info_param.track_info, sizeof(ext_ao_track_info)); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_track_config_init(ao_snd_id sound, const ext_ao_track_config *track_config) { td_s32 ret; ao_snd_track_config_param track_config_param = { .sound = sound, }; check_ao_null_ptr(track_config); ret = memcpy_s(&track_config_param.track_config, sizeof(ext_ao_track_config), track_config, sizeof(*track_config)); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } return ioctl(g_ao_fd, CMD_AO_SND_TRACKCONFIGINIT, &track_config_param); } td_s32 ext_mpi_ao_set_track_direct_out(ao_snd_id sound, td_handle track, ext_ao_port out_port, td_bool enable) { ao_snd_track_duplicate_param param = { .sound = sound, .out_port = out_port, .h_track = track, .enable = enable, }; return ioctl(g_ao_fd, CMD_AO_SND_DUPLICATETRACK, ¶m); } td_s32 ext_mpi_ao_snd_set_avc_attr(ao_snd_id sound, const ext_ao_avc_attr *attr) { td_s32 ret; ao_snd_avc_param avc_param = { .sound = sound, }; check_ao_null_ptr(attr); ret = memcpy_s(&avc_param.avc_attr, sizeof(ext_ao_avc_attr), attr, sizeof(*attr)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } ret = ioctl(g_ao_fd, CMD_AO_SND_SETAVCATTR, &avc_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_SETAVCATTR failed(0x%x)\n", ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_get_avc_attr(ao_snd_id sound, ext_ao_avc_attr *attr) { td_s32 ret; ao_snd_avc_param avc_param = { .sound = sound, }; check_ao_null_ptr(attr); ret = ioctl(g_ao_fd, CMD_AO_SND_GETAVCATTR, &avc_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETAVCATTR failed(0x%x)\n", ret); return ret; } ret = memcpy_s(attr, sizeof(*attr), &avc_param.avc_attr, sizeof(ext_ao_avc_attr)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_set_avc_enable(ao_snd_id sound, td_bool enable) { ao_snd_avc_enable avc_enable = { .sound = sound, .avc_enable = enable, }; return ioctl(g_ao_fd, CMD_AO_SND_SETAVCENABLE, &avc_enable); } td_s32 ext_mpi_ao_get_avc_enable(ao_snd_id sound, td_bool *enable) { td_s32 ret; ao_snd_avc_enable avc_enable = { .sound = sound, .avc_enable = TD_FALSE, }; check_ao_null_ptr(enable); ret = ioctl(g_ao_fd, CMD_AO_SND_GETAVCENABLE, &avc_enable); if (ret == TD_SUCCESS) { *enable = avc_enable.avc_enable; } return ret; } td_s32 ext_mpi_ao_snd_set_geq_attr(ao_snd_id sound, const ext_ao_geq_attr *geq_attr) { td_s32 ret; ao_snd_geq_param geq_param = { .sound = sound, }; check_ao_null_ptr(geq_attr); ret = memcpy_s(&geq_param.eq_attr, sizeof(ext_ao_geq_attr), geq_attr, sizeof(*geq_attr)); if (ret != TD_SUCCESS) { soc_log_err("memcpy_s failed\n"); return ret; } return ioctl(g_ao_fd, CMD_AO_SND_SETGEQATTR, &geq_param); } td_s32 ext_mpi_ao_snd_get_geq_attr(ao_snd_id sound, ext_ao_geq_attr *geq_attr) { td_s32 ret; ao_snd_geq_param geq_param = { .sound = sound, }; check_ao_null_ptr(geq_attr); ret = ioctl(g_ao_fd, CMD_AO_SND_GETGEQATTR, &geq_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETGEQATTR failed\n"); soc_err_print_err_code(ret); return ret; } ret = memcpy_s(geq_attr, sizeof(*geq_attr), &geq_param.eq_attr, sizeof(ext_ao_geq_attr)); if (ret != EOK) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_set_geq_enable(ao_snd_id sound, td_bool enable) { ao_snd_eq_enable geq_enable = { .sound = sound, .out_port = EXT_AO_PORT_MAX, .eq_enable = enable, }; return ioctl(g_ao_fd, CMD_AO_SND_SETGEQENABLE, &geq_enable); } td_s32 ext_mpi_ao_get_geq_enable(ao_snd_id sound, td_bool *enable) { td_s32 ret; ao_snd_eq_enable geq_enable = { .sound = sound, .out_port = EXT_AO_PORT_MAX, .eq_enable = TD_FALSE, }; check_ao_null_ptr(enable); ret = ioctl(g_ao_fd, CMD_AO_SND_GETGEQENABLE, &geq_enable); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETGEQENABLE failed\n"); soc_err_print_err_code(ret); return ret; } *enable = geq_enable.eq_enable; return TD_SUCCESS; } td_s32 ext_mpi_ao_set_geq_gain(ao_snd_id sound, td_u32 band, td_s32 gain) { ao_snd_geq_gain geq_gain = { .sound = sound, .band = band, .gain = gain, }; return ioctl(g_ao_fd, CMD_AO_SND_SETGEQGAIN, &geq_gain); } td_s32 ext_mpi_ao_get_geq_gain(ao_snd_id sound, td_u32 band, td_s32 *gain) { td_s32 ret; ao_snd_geq_gain geq_gain = { .sound = sound, .band = band, .gain = 0, }; check_ao_null_ptr(gain); ret = ioctl(g_ao_fd, CMD_AO_SND_GETGEQGAIN, &geq_gain); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETGEQGAIN failed\n"); soc_err_print_err_code(ret); return ret; } *gain = geq_gain.gain; return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_drc_enable(ao_snd_id sound, ext_ao_port port, td_bool enable) { ao_snd_drc_enable drc_enable = { .sound = sound, .out_port = port, .drc_enable = enable, }; return ioctl(g_ao_fd, CMD_AO_SND_SETDRCENABLE, &drc_enable); } td_s32 ext_mpi_ao_snd_get_drc_enable(ao_snd_id sound, ext_ao_port port, td_bool *enable) { td_s32 ret; ao_snd_drc_enable drc_enable = { .sound = sound, .out_port = port, .drc_enable = TD_FALSE, }; check_ao_null_ptr(enable); ret = ioctl(g_ao_fd, CMD_AO_SND_GETDRCENABLE, &drc_enable); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETDRCENABLE failed\n"); soc_err_print_err_code(ret); return ret; } *enable = drc_enable.drc_enable; return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_drc_attr(ao_snd_id sound, ext_ao_port port, const ext_ao_drc_attr *attr) { td_s32 ret; ao_snd_drc_param drc_param = { .sound = sound, .out_port = port, }; check_ao_null_ptr(attr); ret = memcpy_s(&drc_param.drc_attr, sizeof(ext_ao_drc_attr), attr, sizeof(*attr)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return ioctl(g_ao_fd, CMD_AO_SND_SETDRCATTR, &drc_param); } td_s32 ext_mpi_ao_snd_get_drc_attr(ao_snd_id sound, ext_ao_port port, ext_ao_drc_attr *attr) { td_s32 ret; ao_snd_drc_param drc_param = { .sound = sound, .out_port = port, }; check_ao_null_ptr(attr); ret = ioctl(g_ao_fd, CMD_AO_SND_GETDRCATTR, &drc_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETDRCATTR failed(0x%x)", ret); return ret; } ret = memcpy_s(attr, sizeof(*attr), &drc_param.drc_attr, sizeof(ext_ao_drc_attr)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_set_peq_enable(ao_snd_id sound, ext_ao_port port, td_bool enable) { ao_snd_eq_enable peq_enable = { .sound = sound, .out_port = port, .eq_enable = enable, }; return ioctl(g_ao_fd, CMD_AO_SND_SETPEQENABLE, &peq_enable); } td_s32 ext_mpi_ao_get_peq_enable(ao_snd_id sound, ext_ao_port port, td_bool *enable) { td_s32 ret; ao_snd_eq_enable peq_enable = { .sound = sound, .out_port = port, .eq_enable = TD_FALSE, }; check_ao_null_ptr(enable); ret = ioctl(g_ao_fd, CMD_AO_SND_GETPEQENABLE, &peq_enable); if (ret == TD_SUCCESS) { *enable = peq_enable.eq_enable; } return ret; } td_s32 ext_mpi_ao_snd_set_peq_attr(ao_snd_id sound, ext_ao_port port, const ext_ao_peq_attr *attr) { td_s32 ret; ao_snd_peq_param peq_param = { .sound = sound, .out_port = port, }; check_ao_null_ptr(attr); ret = memcpy_s(&peq_param.eq_attr, sizeof(ext_ao_peq_attr), attr, sizeof(*attr)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return ioctl(g_ao_fd, CMD_AO_SND_SETPEQATTR, &peq_param); } td_s32 ext_mpi_ao_snd_get_peq_attr(ao_snd_id sound, ext_ao_port port, ext_ao_peq_attr *attr) { td_s32 ret; ao_snd_peq_param peq_param = { .sound = sound, .out_port = port, }; check_ao_null_ptr(attr); ret = ioctl(g_ao_fd, CMD_AO_SND_GETPEQATTR, &peq_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETPEQATTR failed(0x%x)", ret); return ret; } ret = memcpy_s(attr, sizeof(*attr), &peq_param.eq_attr, sizeof(ext_ao_peq_attr)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_port_enable(ao_snd_id sound, ext_ao_port port, td_bool enable) { ao_snd_port_enable_param param = { .sound = sound, .out_port = port, .enable = enable, }; return ioctl(g_ao_fd, CMD_AO_SND_SETPORTENABLE, ¶m); } td_s32 ext_mpi_ao_snd_get_port_enable(ao_snd_id sound, ext_ao_port port, td_bool *enable) { td_s32 ret; ao_snd_port_enable_param param = { .sound = sound, .out_port = port, .enable = TD_FALSE, }; check_ao_null_ptr(enable); ret = ioctl(g_ao_fd, CMD_AO_SND_GETPORTENABLE, ¶m); if (ret == TD_SUCCESS) { *enable = param.enable; } return ret; } /* create SND directional memory access(DMA) */ td_s32 ext_mpi_ao_snd_dma_create(ao_snd_id sound) { return snd_dma_create(sound); } /* destory SND directional memory access(DMA) */ td_s32 ext_mpi_ao_snd_dma_destory(ao_snd_id sound) { return snd_dma_destroy(sound); } td_s32 ext_mpi_ao_snd_dma_send_data(const ext_ao_frame *frame, td_u32 latency_ms) { check_ao_null_ptr(frame); return snd_dma_send_data(frame, latency_ms); } td_s32 ext_mpi_ao_snd_dma_get_delay_ms(td_u32 *delay_ms) { check_ao_null_ptr(delay_ms); *delay_ms = 0; return snd_dma_get_delay_ms(delay_ms); } td_s32 ext_mpi_ao_set_sink_delay(ao_snd_id sound, td_u32 sink_delay) { ao_snd_sink_delay_param param = { .sound = sound, .sink_delay = sink_delay, }; return ioctl(g_ao_fd, CMD_AO_SND_SETSINKDELAY, ¶m); } td_s32 ext_mpi_ao_get_sink_delay(ao_snd_id sound, td_u32 *sink_delay) { td_s32 ret; ao_snd_sink_delay_param param = { .sound = sound, .sink_delay = 0, }; check_ao_null_ptr(sink_delay); ret = ioctl(g_ao_fd, CMD_AO_SND_GETSINKDELAY, ¶m); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETSINKDELAY failed\n"); soc_err_print_err_code(ret); return ret; } *sink_delay = param.sink_delay; return TD_SUCCESS; } td_s32 ext_mpi_ao_get_stream_info(ao_snd_id sound, ext_audio_stream_info *stream_info) { td_s32 ret; ao_snd_stream_info_param param = { .sound = sound, }; check_ao_null_ptr(stream_info); ret = ioctl(g_ao_fd, CMD_AO_SND_GETSTREAMINFO, ¶m); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETSTREAMINFO failed\n"); soc_err_print_err_code(ret); return ret; } ret = memcpy_s(stream_info, sizeof(*stream_info), ¶m.stream_info, sizeof(ext_audio_stream_info)); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } return TD_SUCCESS; } /* ao track mpi function */ td_s32 ext_mpi_ao_track_get_default_open_attr(ext_ao_track_type track_type, ext_ao_track_attr *attr) { check_ao_null_ptr(attr); attr->track_type = track_type; return ioctl(g_ao_fd, CMD_AO_TRACK_GETDEFATTR, attr); } td_s32 ext_mpi_ao_track_get_attr(td_handle track, ext_ao_track_attr *attr) { td_s32 ret; ao_track_attr_param track_attr; check_ao_null_ptr(attr); check_ao_track_id(track); if ((track & AO_TRACK_CHNID_MASK) >= AO_MAX_REAL_TRACK_NUM) { return vir_get_attr(track, attr); } track_attr.h_track = track; ret = ioctl(g_ao_fd, CMD_AO_TRACK_GETATTR, &track_attr); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_GETATTR failed(0x%x)", ret); return ret; } ret = memcpy_s(attr, sizeof(*attr), &track_attr.attr, sizeof(ext_ao_track_attr)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_track_set_attr(td_handle track, const ext_ao_track_attr *attr) { td_s32 ret; ao_track_attr_param track_attr; check_ao_null_ptr(attr); check_ao_track_id(track); if ((track & AO_TRACK_CHNID_MASK) >= AO_MAX_REAL_TRACK_NUM) { return TD_FAILURE; } track_attr.h_track = track; ret = memcpy_s(&track_attr.attr, sizeof(ext_ao_track_attr), attr, sizeof(*attr)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return ioctl(g_ao_fd, CMD_AO_TRACK_SETATTR, &track_attr); } td_bool ext_mpi_ao_track_check_is_low_latency(td_handle track) { return llt_check(track); } td_s32 ext_mpi_ao_track_create(ao_snd_id sound, const ext_ao_track_attr *attr, td_handle *track) { td_s32 ret; td_handle h_track = TD_INVALID_HANDLE; ao_track_create_param track_param = { .sound = sound, .alsa_track = TD_FALSE, .h_track = TD_INVALID_HANDLE, }; check_ao_null_ptr(attr); check_ao_null_ptr(track); soc_log_warn("track_type:0x%x\n", attr->track_type); if (attr->track_type == EXT_AO_TRACK_TYPE_VIRTUAL) { ret = vir_create_track(attr, &h_track); if (ret == TD_SUCCESS) { *track = h_track; } return ret; } ret = memcpy_s(&track_param.attr, sizeof(ext_ao_track_attr), attr, sizeof(*attr)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } ret = ioctl(g_ao_fd, CMD_AO_TRACK_CREATE, &track_param); h_track = track_param.h_track; if (ret == TD_SUCCESS) { *track = h_track; } if (attr->track_type == EXT_AO_TRACK_TYPE_LOW_LATENCY) { ret = llt_enable(h_track); if (ret != TD_SUCCESS) { ioctl(g_ao_fd, CMD_AO_TRACK_DESTROY, &h_track); soc_err_print_call_fun_err(llt_enable, ret); return ret; } ret = ext_mpi_ao_track_start(h_track); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ext_mpi_ao_track_start, ret); } } return ret; } td_s32 ext_mpi_ao_track_destroy(td_handle track) { td_s32 ret; check_ao_track_id(track); if ((track & AO_TRACK_CHNID_MASK) >= AO_MAX_REAL_TRACK_NUM) { return vir_destroy_track(track); } if (llt_check(track) == TD_TRUE) { llt_disable(track); } if (g_ad_master_track == track) { destroy_ad_track(g_ad_master_track); } ret = ioctl(g_ao_fd, CMD_AO_TRACK_DESTROY, &track); return ret; } td_s32 ext_mpi_ao_track_start(td_handle track) { td_s32 ret; check_ao_track_id(track); check_virtual_track(track); if (g_ad_master_track == track) { ret = ioctl(g_ao_fd, CMD_AO_TRACK_START, &g_ad_slave_track); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_START failed(g_ad_slave_track = 0x%x)\n", g_ad_slave_track); return ret; } } ret = ioctl(g_ao_fd, CMD_AO_TRACK_START, &track); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_START failed(track = 0x%x)\n", track); return ret; } return ret; } td_s32 ext_mpi_ao_track_stop(td_handle track) { td_s32 ret; td_handle src_track; check_ao_track_id(track); check_virtual_track(track); src_track = track; if (g_ad_master_track == track) { ret = ioctl(g_ao_fd, CMD_AO_TRACK_STOP, &g_ad_slave_track); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_STOP failed(g_ad_slave_track = 0x%x)\n", g_ad_slave_track); return ret; } } ret = ioctl(g_ao_fd, CMD_AO_TRACK_STOP, &src_track); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_STOP failed(track = 0x%x)\n", track); } return ret; } td_s32 ext_mpi_ao_track_pause(td_handle track) { td_s32 ret; check_ao_track_id(track); check_virtual_track(track); if (g_ad_master_track == track) { ret = ioctl(g_ao_fd, CMD_AO_TRACK_PAUSE, &g_ad_slave_track); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_PAUSE failed(g_ad_slave_track = 0x%x)\n", g_ad_slave_track); return ret; } } ret = ioctl(g_ao_fd, CMD_AO_TRACK_PAUSE, &track); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_PAUSE failed(track = 0x%x)\n", track); } return ret; } td_s32 ext_mpi_ao_track_flush(td_handle track) { td_s32 ret; check_ao_track_id(track); check_virtual_track(track); if (g_ad_master_track == track) { ret = ioctl(g_ao_fd, CMD_AO_TRACK_FLUSH, g_ad_slave_track); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_FLUSH failed(g_ad_slave_track = 0x%x)\n", g_ad_slave_track); return ret; } } ret = ioctl(g_ao_fd, CMD_AO_TRACK_FLUSH, &track); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_FLUSH failed(track = 0x%x)\n", track); } return ret; } td_s32 ext_mpi_ao_track_set_fifo_bypass(td_handle track, td_bool enable) { ao_track_fifo_bypass_param param; check_ao_track_id(track); check_virtual_track(track); param.h_track = track; param.enable = enable; return ioctl(g_ao_fd, CMD_AO_TRACK_SETFIFOBYPASS, ¶m); } td_s32 ext_mpi_ao_track_set_priority(td_handle track, td_bool enable) { ao_track_priority_param param; check_ao_track_id(track); check_virtual_track(track); param.h_track = track; param.enable = enable; return ioctl(g_ao_fd, CMD_AO_TRACK_SETPRIORITY, ¶m); } td_s32 ext_mpi_ao_track_get_priority(td_handle track, td_bool *enable) { td_s32 ret; ao_track_priority_param track_priority; check_ao_track_id(track); check_virtual_track(track); check_ao_null_ptr(enable); track_priority.h_track = track; ret = ioctl(g_ao_fd, CMD_AO_TRACK_GETPRIORITY, &track_priority); if (ret == TD_SUCCESS) { *enable = track_priority.enable; } return ret; } td_s32 ext_mpi_ao_track_send_data(td_handle track, const ext_ao_frame *frame) { check_ao_null_ptr(frame); check_ao_track_id(track); if ((track & AO_TRACK_CHNID_MASK) >= AO_MAX_REAL_TRACK_NUM) { return vir_send_data(track, frame); } if (llt_check(track) == TD_TRUE) { return llt_send_data(track, frame); } ao_track_send_data_param track_ao_frame; track_ao_frame.h_track = track; audio_iapi_frame_to_drv_frame(frame, &track_ao_frame.ao_frame); return ioctl(g_ao_fd, CMD_AO_TRACK_SENDDATA, &track_ao_frame); } td_s32 ext_mpi_ao_track_send_data_ad(td_handle track, const ext_ao_frame *frame) { td_s32 ret; check_ao_null_ptr(frame); check_ao_track_id(track); if (g_ad_slave_track == TD_NULL) { ret = create_ad_track(track); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(create_ad_track, ret); return ret; } } if (g_ad_slave_track != TD_NULL) { ret = ext_mpi_ao_track_send_data(g_ad_slave_track, frame); if (ret != TD_SUCCESS) { soc_warn_print_call_fun_err(ext_mpi_ao_track_send_data, ret); return ret; } } return TD_SUCCESS; } td_s32 ext_mpi_ao_track_set_weight(td_handle track, const ext_ao_gain *gain) { td_s32 ret; ao_track_weight_param weight; check_ao_null_ptr(gain); check_ao_track_id(track); check_virtual_track(track); weight.h_track = track; ret = memcpy_s(&weight.track_gain, sizeof(ext_ao_gain), gain, sizeof(*gain)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return ioctl(g_ao_fd, CMD_AO_TRACK_SETWEITHT, &weight); } td_s32 ext_mpi_ao_track_get_weight(td_handle track, ext_ao_gain *gain) { td_s32 ret; ao_track_weight_param weight = { .h_track = track, }; check_ao_null_ptr(gain); check_ao_track_id(track); check_virtual_track(track); ret = ioctl(g_ao_fd, CMD_AO_TRACK_GETWEITHT, &weight); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_GETWEITHT failed(0x%x)\n", ret); return ret; } ret = memcpy_s(gain, sizeof(*gain), &weight.track_gain, sizeof(ext_ao_gain)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_track_set_abs_weight(td_handle track, const ext_ao_abs_gain *gain) { td_s32 ret; ao_track_abs_gain_param abs_gain = { .h_track = track, }; check_ao_null_ptr(gain); check_ao_track_id(track); check_virtual_track(track); ret = memcpy_s(&abs_gain.track_abs_gain, sizeof(ext_ao_abs_gain), gain, sizeof(*gain)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return ioctl(g_ao_fd, CMD_AO_TRACK_SETABSGAIN, &abs_gain); } td_s32 ext_mpi_ao_track_get_abs_weight(td_handle track, ext_ao_abs_gain *gain) { td_s32 ret; ao_track_abs_gain_param abs_gain = { .h_track = track, }; check_ao_null_ptr(gain); check_ao_track_id(track); check_virtual_track(track); ret = ioctl(g_ao_fd, CMD_AO_TRACK_GETABSGAIN, &abs_gain); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_GETABSGAIN failed(0x%x)\n", ret); return ret; } ret = memcpy_s(gain, sizeof(*gain), &abs_gain.track_abs_gain, sizeof(ext_ao_abs_gain)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_track_set_prescale(td_handle track, const ext_ao_preci_gain *prescale) { td_s32 ret; ao_track_prescale_param param = { .h_track = track, }; check_ao_null_ptr(prescale); check_ao_track_id(track); check_virtual_track(track); ret = memcpy_s(¶m.preci_gain, sizeof(ext_ao_preci_gain), prescale, sizeof(*prescale)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return ioctl(g_ao_fd, CMD_AO_TRACK_SETPRESCALE, ¶m); } td_s32 ext_mpi_ao_track_get_prescale(td_handle track, ext_ao_preci_gain *prescale) { td_s32 ret; ao_track_prescale_param param = { .h_track = track, }; check_ao_null_ptr(prescale); check_ao_track_id(track); check_virtual_track(track); ret = ioctl(g_ao_fd, CMD_AO_TRACK_GETPRESCALE, ¶m); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_GETPRESCALE failed(0x%x)\n", ret); return ret; } ret = memcpy_s(prescale, sizeof(*prescale), ¶m.preci_gain, sizeof(ext_ao_preci_gain)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_track_set_mute(td_handle track, td_bool mute) { ao_track_mute_param mute_param = { .h_track = track, .mute = mute, }; check_ao_track_id(track); check_virtual_track(track); return ioctl(g_ao_fd, CMD_AO_TRACK_SETMUTE, &mute_param); } td_s32 ext_mpi_ao_track_get_mute(td_handle track, td_bool *mute) { td_s32 ret; ao_track_mute_param mute_param = { .h_track = track, .mute = TD_FALSE, }; check_ao_null_ptr(mute); check_ao_track_id(track); check_virtual_track(track); ret = ioctl(g_ao_fd, CMD_AO_TRACK_GETMUTE, &mute_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_GETMUTE failed\n"); soc_err_print_err_code(ret); return ret; } *mute = mute_param.mute; return TD_SUCCESS; } td_s32 ext_mpi_ao_track_set_channel_mode(td_handle track, ext_track_mode mode) { ao_track_channel_mode_param track_mode; check_ao_track_id(track); check_virtual_track(track); track_mode.h_track = track; track_mode.mode = mode; return ioctl(g_ao_fd, CMD_AO_TRACK_SETCHANNELMODE, &track_mode); } td_s32 ext_mpi_ao_track_get_channel_mode(td_handle track, ext_track_mode *mode) { td_s32 ret; ao_track_channel_mode_param track_mode; check_ao_null_ptr(mode); check_ao_track_id(track); check_virtual_track(track); track_mode.h_track = track; ret = ioctl(g_ao_fd, CMD_AO_TRACK_GETCHANNELMODE, &track_mode); if (ret == TD_SUCCESS) { *mode = track_mode.mode; } return ret; } td_s32 ext_mpi_ao_track_acquire_frame(td_handle track, ext_ao_frame *frame, td_u32 timeout_ms) { td_u32 sleep_cnt; td_s32 ret; struct timespec slp_tm; check_ao_null_ptr(frame); check_ao_track_id(track); check_real_track(track); ret = vir_acquire_frame(track, frame); if (ret == SOC_ERR_AO_VIRTUALBUF_EMPTY) { for (sleep_cnt = 0; sleep_cnt < timeout_ms; sleep_cnt++) { slp_tm.tv_sec = 0; slp_tm.tv_nsec = 1000 * 1000; /* this 1000*1000 means ms to ns */ if (nanosleep(&slp_tm, TD_NULL) != 0) { soc_log_err("nanosleep err.\n"); } ret = vir_acquire_frame(track, frame); if (ret != SOC_ERR_AO_VIRTUALBUF_EMPTY) { break; } } } return ret; } td_s32 ext_mpi_ao_track_release_frame(td_handle track, ext_ao_frame *frame) { check_ao_null_ptr(frame); check_ao_track_id(track); check_real_track(track); return vir_release_frame(track, frame); } td_s32 ext_mpi_ao_track_set_eos(td_handle track, td_bool eos) { ao_track_eos_flag_param param = { .h_track = track, .eos_flag = eos, }; check_ao_track_id(track); check_virtual_track(track); return ioctl(g_ao_fd, CMD_AO_TRACK_SETEOSFLAG, ¶m); } td_s32 ext_mpi_ao_track_set_speed_adjust(td_handle track, ext_ao_speed *speed) { td_s32 ret; ao_track_speed_adjust_param param = { .h_track = track, }; check_ao_null_ptr(speed); check_ao_track_id(track); check_virtual_track(track); ret = memcpy_s(¶m.speed, sizeof(param.speed), speed, sizeof(*speed)); if (ret != EOK) { soc_log_err("call memcpy_s failed(0x%x)\n", ret); return ret; } ret = ioctl(g_ao_fd, CMD_AO_TRACK_SETSPEEDADJUST, ¶m); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_SETSPEEDADJUST failed(0x%x)\n", ret); } return ret; } td_s32 ext_mpi_ao_track_set_speed(td_handle track, ext_ao_speed *speed) { return ext_mpi_ao_track_set_speed_adjust(track, speed); } td_s32 ext_mpi_ao_track_get_delay(const td_handle track, td_u32 *delay_ms) { td_s32 ret; ao_track_delay_ms_param param = { .h_track = track, .delay_ms = 0, }; check_ao_track_id(track); check_virtual_track(track); check_ao_null_ptr(delay_ms); if (llt_check(track) == TD_TRUE) { return llt_get_aip_delay_ms(track, delay_ms); } ret = ioctl(g_ao_fd, CMD_AO_TRACK_GETDELAYMS, ¶m); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_GETDELAYMS failed\n"); soc_err_print_err_code(ret); return ret; } *delay_ms = param.delay_ms; return TD_SUCCESS; } td_s32 ext_mpi_ao_track_get_buf_delay(const td_handle track, td_u32 *delay_ms) { check_ao_track_id(track); check_virtual_track(track); check_ao_null_ptr(delay_ms); if (llt_check(track) == TD_TRUE) { return llt_get_aip_delay_ms(track, delay_ms); } soc_log_err("ext_mpi_ao_track_get_buf_delay only support lowlatency track\n"); return SOC_ERR_AO_NOTSUPPORT; } td_s32 ext_mpi_ao_track_is_buf_empty(const td_handle track, td_bool *empty) { td_s32 ret; ao_track_buf_empty_param param = { .h_track = track, .empty = TD_FALSE, }; check_ao_track_id(track); check_virtual_track(track); check_ao_null_ptr(empty); ret = ioctl(g_ao_fd, CMD_AO_TRACK_ISBUFEMPTY, ¶m); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_ISBUFEMPTY failed\n"); soc_err_print_err_code(ret); return ret; } *empty = param.empty; return TD_SUCCESS; } td_s32 ext_mpi_ao_track_attach_ai(const td_handle ai, const td_handle track) { ao_track_att_ai_param param = { .h_track = track, .h_ai = ai, }; check_ao_track_id(track); return ioctl(g_ao_fd, CMD_AO_TRACK_ATTACHAI, ¶m); } td_s32 ext_mpi_ao_track_detach_ai(const td_handle ai, const td_handle track) { td_s32 ret; ao_track_att_ai_param param = { .h_track = track, .h_ai = ai, }; check_ao_track_id(track); ret = ioctl(g_ao_fd, CMD_AO_TRACK_DETACHAI, ¶m); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_DETACHAI failed\n"); soc_err_print_err_code(ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_track_set_source(td_handle track, ext_ao_source source) { td_s32 ret; ao_track_source_param source_param = { .h_track = track, .source = source, }; check_ao_track_id(track); check_virtual_track(track); /* except alsa track */ if ((source < EXT_AO_SOURCE_ATV) || (source >= EXT_AO_SOURCE_MAX)) { soc_log_err("source invalid!\n"); soc_err_print_u32(source); return SOC_ERR_AO_INVALID_PARA; } ret = ioctl(g_ao_fd, CMD_AO_TRACK_SETSOURCE, &source_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_TRACK_SETSOURCE failed\n"); soc_err_print_err_code(ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_track_get_source_mute(ao_snd_id sound, ext_ao_source source, td_bool *mute) { td_s32 ret; ao_snd_track_source_mute track_src_mute = { .sound = sound, .source = source, .mute = TD_FALSE, }; check_ao_null_ptr(mute); if ((source < EXT_AO_SOURCE_ATV) || (source >= EXT_AO_SOURCE_MAX)) { soc_log_err("source invalid!\n"); soc_err_print_s32(source); return SOC_ERR_AO_INVALID_PARA; } track_src_mute.sound = sound; track_src_mute.source = source; ret = ioctl(g_ao_fd, CMD_AO_SND_TRACKGETSOURCEMUTE, &track_src_mute); if (ret == TD_SUCCESS) { *mute = track_src_mute.mute; } return ret; } td_s32 ext_mpi_ao_track_set_source_mute(ao_snd_id sound, ext_ao_source source, td_bool mute) { ao_snd_track_source_mute track_src_mute = { .sound = sound, .source = source, .mute = mute, }; if ((source < EXT_AO_SOURCE_ATV) || (source >= EXT_AO_SOURCE_MAX)) { soc_log_err("source invalid!\n"); soc_err_print_s32(source); return SOC_ERR_AO_INVALID_PARA; } return ioctl(g_ao_fd, CMD_AO_SND_TRACKSETSOURCEMUTE, &track_src_mute); } td_s32 ext_mpi_ao_snd_set_all_cast_mute(ao_snd_id sound, td_bool mute) { ao_snd_all_cast_mute_param mute_param = { .sound = sound, .mute = mute, }; return ioctl(g_ao_fd, CMD_AO_SND_SETALLCASTMUTE, &mute_param); } td_s32 ext_mpi_ao_snd_get_all_cast_mute(ao_snd_id sound, td_bool *mute) { td_s32 ret; ao_snd_all_cast_mute_param mute_param = { .sound = sound, .mute = TD_FALSE, }; check_ao_null_ptr(mute); ret = ioctl(g_ao_fd, CMD_AO_SND_GETALLCASTMUTE, &mute_param); if (ret == TD_SUCCESS) { *mute = mute_param.mute; } return ret; } td_s32 ext_mpi_ao_snd_get_cast_default_open_attr(ext_ao_cast_attr *attr) { check_ao_null_ptr(attr); return ioctl(g_ao_fd, CMD_AO_CAST_GETDEFATTR, attr); } static td_void mpi_ao_munmap_cast_buf(td_void *buf, td_u32 size) { td_s32 err_ret; if (buf == TD_NULL) { return; } err_ret = munmap(buf, size); if (err_ret != TD_SUCCESS) { soc_err_print_call_fun_err(munmap, err_ret); return; } } static td_void *mpi_ao_mmap_cast_buf(td_s32 fd, td_u32 size, td_u64 phys_addr) { td_void *buf = TD_NULL; if ((fd < 0) || (phys_addr == 0)) { return TD_NULL; } buf = (td_void *)mmap((td_void *)0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (buf == MAP_FAILED) { soc_log_err("mmap failed\n"); return TD_NULL; } return buf; } static td_s32 mpi_ao_create_cast(ao_snd_id sound, const ext_ao_cast_attr *attr, td_handle *cast) { td_s32 ret; ao_cast_create_param cast_param = { .sound = sound, .h_cast = TD_INVALID_HANDLE, }; ret = memcpy_s(&cast_param.cast_attr, sizeof(ext_ao_cast_attr), attr, sizeof(*attr)); if (ret != EOK) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } ret = ioctl(g_ao_fd, CMD_AO_CAST_CREATE, &cast_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_CAST_CREATE failed(0x%x)\n", ret); return ret; } *cast = cast_param.h_cast; return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_create_cast(ao_snd_id sound, const ext_ao_cast_attr *attr, td_handle *cast) { td_s32 ret; td_void *virt_addr = TD_NULL; ao_cast_info_param cast_info = { .h_cast = TD_INVALID_HANDLE, .buf_size = 0, .phy_addr = 0, .map_fd = -1, }; check_ao_null_ptr(cast); check_ao_null_ptr(attr); ret = mpi_ao_create_cast(sound, attr, cast); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(mpi_ao_create_cast, ret); return ret; } cast_info.h_cast = *cast; ret = ioctl(g_ao_fd, CMD_AO_CAST_GETINFO, &cast_info); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_CAST_GETINFO failed(0x%x)\n", ret); goto out0; } virt_addr = mpi_ao_mmap_cast_buf(cast_info.map_fd, cast_info.buf_size, cast_info.phy_addr); if (virt_addr == TD_NULL) { soc_log_err("call mpi_ao_mmap_cast_buf failed\n"); ret = SOC_ERR_AO_NULL_PTR; goto out0; } cast_info.user_virt_addr = (uintptr_t)virt_addr; ret = ioctl(g_ao_fd, CMD_AO_CAST_SETINFO, &cast_info); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_CAST_SETINFO failed(0x%x)\n", ret); goto out1; } return TD_SUCCESS; out1: mpi_ao_munmap_cast_buf(virt_addr, cast_info.buf_size); out0: if (ioctl(g_ao_fd, CMD_AO_CAST_DESTROY, &cast_info.h_cast) != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_CAST_DESTROY failed\n"); } *cast = TD_INVALID_HANDLE; return ret; } td_s32 ext_mpi_ao_snd_destroy_cast(td_handle h_cast) { td_s32 ret; td_void *buf = TD_NULL; ao_cast_info_param cast_info = { .h_cast = h_cast, .map_fd = -1, .user_virt_addr = 0, .buf_size = 0, }; check_ao_cast_handle(h_cast); ret = ioctl(g_ao_fd, CMD_AO_CAST_GETINFO, &cast_info); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_CAST_GETINFO failed(0x%x)\n", ret); return ret; } buf = (td_void *)(uintptr_t)cast_info.user_virt_addr; if (buf != TD_NULL) { mpi_ao_munmap_cast_buf(buf, cast_info.buf_size); } ret = ioctl(g_ao_fd, CMD_AO_CAST_DESTROY, &h_cast); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_CAST_DESTROY failed(0x%x)\n", ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_cast_enable(td_handle h_cast, td_bool enable) { td_s32 ret; ao_cast_enable_param enable_attr = { .h_cast = h_cast, .cast_enable = enable, }; check_ao_cast_handle(h_cast); ret = ioctl(g_ao_fd, CMD_AO_CAST_SETENABLE, &enable_attr); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_CAST_SETENABLE failed(0x%x)\n", ret); } return ret; } td_s32 ext_mpi_ao_snd_get_cast_enable(td_handle h_cast, td_bool *enable) { td_s32 ret; ao_cast_enable_param enable_attr = { .h_cast = h_cast, }; check_ao_cast_handle(h_cast); check_ao_null_ptr(enable); ret = ioctl(g_ao_fd, CMD_AO_CAST_GETENABLE, &enable_attr); if (ret == TD_SUCCESS) { *enable = enable_attr.cast_enable; } return ret; } td_s32 ext_mpi_ao_snd_set_cast_mute(td_handle h_cast, td_bool mute) { ao_cast_mute_param mute_param = { .h_cast = h_cast, .mute = mute, }; check_ao_cast_handle(h_cast); return ioctl(g_ao_fd, CMD_AO_CAST_SETMUTE, &mute_param); } td_s32 ext_mpi_ao_snd_get_cast_mute(td_handle h_cast, td_bool *mute) { td_s32 ret; ao_cast_mute_param mute_param = { .h_cast = h_cast, }; check_ao_cast_handle(h_cast); check_ao_null_ptr(mute); ret = ioctl(g_ao_fd, CMD_AO_CAST_GETMUTE, &mute_param); if (ret == TD_SUCCESS) { *mute = mute_param.mute; } return ret; } td_s32 ext_mpi_ao_snd_set_cast_abs_gain(td_handle h_cast, const ext_ao_abs_gain *gain) { td_s32 ret; ao_cast_abs_gain_param abs_gain = { .h_cast = h_cast, }; check_ao_cast_handle(h_cast); check_ao_null_ptr(gain); ret = memcpy_s(&abs_gain.cast_abs_gain, sizeof(ext_ao_abs_gain), gain, sizeof(*gain)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return ioctl(g_ao_fd, CMD_AO_CAST_SETABSGAIN, &abs_gain); } td_s32 ext_mpi_ao_snd_get_cast_abs_gain(td_handle h_cast, ext_ao_abs_gain *gain) { td_s32 ret; ao_cast_abs_gain_param abs_gain = { .h_cast = h_cast, }; check_ao_cast_handle(h_cast); check_ao_null_ptr(gain); ret = ioctl(g_ao_fd, CMD_AO_CAST_GETABSGAIN, &abs_gain); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_CAST_GETABSGAIN failed(0x%x)\n", ret); return ret; } ret = memcpy_s(gain, sizeof(*gain), &abs_gain.cast_abs_gain, sizeof(ext_ao_abs_gain)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_cast_balance(td_handle cast, td_s32 balance) { ao_cast_balance_param param = { .cast = cast, .balance = balance, }; return ioctl(g_ao_fd, CMD_AO_CAST_SETBALANCE, ¶m); } td_s32 ext_mpi_ao_snd_get_cast_balance(td_handle cast, td_s32 *balance) { td_s32 ret; ao_cast_balance_param param = { .cast = cast, .balance = 0, }; check_ao_null_ptr(balance); ret = ioctl(g_ao_fd, CMD_AO_CAST_GETBALANCE, ¶m); if (ret == TD_SUCCESS) { *balance = param.balance; } return ret; } td_s32 ext_mpi_ao_snd_set_cast_preci_volume(td_handle cast, const ext_ao_preci_gain *preci_gain) { td_s32 ret; ao_cast_preci_volume_param preci_volume = { 0 }; check_ao_null_ptr(preci_gain); preci_volume.cast = cast; ret = memcpy_s(&preci_volume.preci_gain, sizeof(ext_ao_preci_gain), preci_gain, sizeof(*preci_gain)); if (ret != TD_SUCCESS) { soc_log_err("memcpy_s failed\n"); return ret; } return ioctl(g_ao_fd, CMD_AO_CAST_SETPRECIVOLUME, &preci_volume); } td_s32 ext_mpi_ao_snd_get_cast_preci_volume(td_handle cast, ext_ao_preci_gain *preci_gain) { td_s32 ret; ao_cast_preci_volume_param preci_volume = { .cast = cast, }; check_ao_null_ptr(preci_gain); ret = ioctl(g_ao_fd, CMD_AO_CAST_GETPRECIVOLUME, &preci_volume); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_CAST_GETPRECIVOLUME failed\n"); soc_err_print_err_code(ret); return ret; } ret = memcpy_s(preci_gain, sizeof(*preci_gain), &preci_volume.preci_gain, sizeof(ext_ao_preci_gain)); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_cast_config(td_handle cast, const ext_ao_cast_config *cast_config) { td_s32 ret; ao_cast_config_param config_param = { .cast = cast, }; check_ao_null_ptr(cast_config); ret = memcpy_s(&config_param.cast_config, sizeof(ext_ao_cast_config), cast_config, sizeof(*cast_config)); if (ret != EOK) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } ret = ioctl(g_ao_fd, CMD_AO_CAST_SETCONFIG, &config_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_CAST_SETCONFIG failed\n"); soc_err_print_err_code(ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_get_cast_config(td_handle cast, ext_ao_cast_config *cast_config) { td_s32 ret; ao_cast_config_param config_param = { .cast = cast, }; check_ao_null_ptr(cast_config); ret = ioctl(g_ao_fd, CMD_AO_CAST_GETCONFIG, &config_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_CAST_GETCONFIG failed\n"); soc_err_print_err_code(ret); return ret; } ret = memcpy_s(cast_config, sizeof(*cast_config), &config_param.cast_config, sizeof(ext_ao_cast_config)); if (ret != EOK) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_acquire_cast_frame(td_handle h_cast, ext_ao_frame *frame) { td_s32 ret; ao_cast_info_param cast_info = { .h_cast = h_cast, }; ao_cast_data_param cast_data = { .h_cast = h_cast, }; check_ao_cast_handle(h_cast); check_ao_null_ptr(frame); ret = ioctl(g_ao_fd, CMD_AO_CAST_GETINFO, &cast_info); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_CAST_GETINFO failed(0x%x)\n", ret); return ret; } cast_data.frame_bytes = cast_info.frame_bytes; ret = ioctl(g_ao_fd, CMD_AO_CAST_ACQUIREFRAME, &cast_data); if (ret != TD_SUCCESS) { frame->pcm_samples = 0; return ret; } audio_drv_frame_to_iapi_frame(&cast_data.ao_frame, frame); frame->pcm_buffer = (td_s32 *)(uintptr_t)cast_data.ao_frame.pcm_buffer; if (frame->pcm_samples == 0) { return SOC_ERR_AO_CAST_TIMEOUT; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_release_cast_frame(td_handle h_cast, const ext_ao_frame *frame) { td_s32 ret; ao_cast_info_param cast_info; ao_cast_data_param cast_data; check_ao_null_ptr(frame); check_ao_cast_handle(h_cast); if (frame->pcm_samples == 0) { return TD_SUCCESS; } cast_info.h_cast = h_cast; ret = ioctl(g_ao_fd, CMD_AO_CAST_GETINFO, &cast_info); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_CAST_GETINFO failed(0x%x)\n", ret); return ret; } if ((frame->pcm_samples != cast_info.frame_samples) || (frame->channels != cast_info.channels) || (frame->bit_depth != cast_info.bit_per_sample)) { soc_log_err("release cast frame error: pcm_samples_per_frame(0x%x) channels(0x%x) sample_rate(0x%x)\n", frame->pcm_samples, frame->channels, frame->sample_rate); return TD_FAILURE; } cast_data.h_cast = h_cast; cast_data.frame_bytes = cast_info.frame_bytes; audio_iapi_frame_to_drv_frame(frame, &cast_data.ao_frame); ret = ioctl(g_ao_fd, CMD_AO_CAST_RELEASEFRAME, &cast_data); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_CAST_RELEASEFRAME failed(0x%x)\n", ret); } return ret; } td_s32 ext_mpi_ao_snd_attach_aef(ao_snd_id sound, ao_aef_attr *aef_attr) { td_s32 ret; ao_snd_att_aef_param param = { .sound = sound, }; check_ao_null_ptr(aef_attr); ret = memcpy_s(¶m.aef_attr, sizeof(ao_aef_attr), aef_attr, sizeof(*aef_attr)); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } ret = ioctl(g_ao_fd, CMD_AO_SND_ATTACHAEF, ¶m); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_ATTACHAEF failed\n"); soc_err_print_err_code(ret); return ret; } ret = memcpy_s(aef_attr, sizeof(*aef_attr), ¶m.aef_attr, sizeof(ao_aef_attr)); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_detach_aef(ao_snd_id sound, const ao_aef_attr *aef_attr) { td_s32 ret; ao_snd_att_aef_param aef_param = { .sound = sound, }; check_ao_null_ptr(aef_attr); ret = memcpy_s(&aef_param.aef_attr, sizeof(ao_aef_attr), aef_attr, sizeof(*aef_attr)); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } return ioctl(g_ao_fd, CMD_AO_SND_DETACHAEF, &aef_param); } td_s32 ext_mpi_ao_snd_set_aef_bypass(ao_snd_id sound, ext_ao_port out_port, td_bool bypass) { ao_snd_aef_bypass_param param = { .sound = sound, .out_port = out_port, .bypass = bypass, }; return ioctl(g_ao_fd, CMD_AO_SND_SETAEFBYPASS, ¶m); } td_s32 ext_mpi_ao_snd_get_aef_bypass(ao_snd_id sound, ext_ao_port out_port, td_bool *bypass) { td_s32 ret; ao_snd_aef_bypass_param param = { .sound = sound, .out_port = out_port, .bypass = TD_FALSE, }; check_ao_null_ptr(bypass); ret = ioctl(g_ao_fd, CMD_AO_SND_GETAEFBYPASS, ¶m); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETAEFBYPASS failed\n"); soc_err_print_err_code(ret); return ret; } *bypass = param.bypass; return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_get_aef_handle(ao_snd_id sound, td_u32 aef_type, td_handle *aflt) { td_s32 ret; ao_snd_aef_handle_param ioctl_param = { .sound = sound, .aef_type = aef_type, .aflt = TD_INVALID_HANDLE, }; check_ao_null_ptr(aflt); ret = ioctl(g_ao_fd, CMD_AO_SND_GETAEFHANDLE, &ioctl_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETAEFHANDLE failed\n"); soc_err_print_err_code(ret); return ret; } *aflt = ioctl_param.aflt; return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_port_delay(ao_snd_id sound, ext_ao_port port, td_u32 delay) { td_s32 ret; ao_snd_op_delay_param op_delay = { .sound = sound, .out_port = port, .delay_ms = delay, }; ret = ioctl(g_ao_fd, CMD_AO_SND_SETSOUNDDELAY, &op_delay); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_SETSOUNDDELAY failed\n"); soc_err_print_err_code(ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_get_port_delay(ao_snd_id sound, ext_ao_port port, td_u32 *delay) { td_s32 ret; ao_snd_op_delay_param op_delay = { .sound = sound, .out_port = port, .delay_ms = 0, }; check_ao_null_ptr(delay); ret = ioctl(g_ao_fd, CMD_AO_SND_GETSOUNDDELAY, &op_delay); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETSOUNDDELAY failed\n"); soc_err_print_err_code(ret); return ret; } *delay = op_delay.delay_ms; return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_set_ext_delay_ms(ao_snd_id sound, td_u32 delay) { ao_snd_set_ext_delay_ms_param ext_delay_ms_param = { .sound = sound, .delay_ms = delay, }; return ioctl(g_ao_fd, CMD_AO_SND_SETEXTDELAYMS, &ext_delay_ms_param); } td_s32 ext_mpi_ao_track_set_ad_balance(const td_handle track, td_s16 ad_balance) { td_s32 ret; td_s32 main_volume; td_s32 ad_volume; ext_ao_gain main_gain = { 0 }; ext_ao_gain ad_gain = { 0 }; check_ao_track_id(track); if ((ad_balance > MAX_AD_BALANCE) || (ad_balance < MIN_AD_BALANCE)) { return SOC_ERR_AO_INVALID_PARA; } if (g_ad_slave_track == TD_NULL) { ret = create_ad_track(track); if (ret != TD_SUCCESS) { soc_log_err("set AD enable failed\n"); return ret; } } if (ad_balance > 0) { main_volume = MAX_VOLUME; ad_volume = (MAX_AD_BALANCE - ad_balance) * MAX_VOLUME / MAX_AD_BALANCE; } else { ad_volume = MAX_VOLUME; main_volume = (MAX_AD_BALANCE + ad_balance) * MAX_VOLUME / MAX_AD_BALANCE; } main_gain.linear_mode = TD_TRUE; ad_gain.linear_mode = TD_TRUE; main_gain.gain = main_volume; ad_gain.gain = ad_volume; ret = ext_mpi_ao_track_set_weight(track, &main_gain); if (ret != TD_SUCCESS) { soc_log_err("set AO track failed\n"); return ret; } ret = ext_mpi_ao_track_set_weight(g_ad_slave_track, &ad_gain); if (ret != TD_SUCCESS) { soc_log_err("set AO track failed\n"); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_set_continue_output_status(ao_snd_id sound, td_bool enable) { ao_snd_con_output_enable con_output_enable = { .sound = sound, .con_output_enable = enable, }; return ioctl(g_ao_fd, CMD_AO_SND_SETCONOUTPUTSTATUS, &con_output_enable); } td_s32 ext_mpi_ao_get_continue_output_status(ao_snd_id sound, td_bool *enable) { td_s32 ret; ao_snd_con_output_enable con_output_enable = { .sound = sound, .con_output_enable = TD_FALSE, }; check_ao_null_ptr(enable); ret = ioctl(g_ao_fd, CMD_AO_SND_GETCONOUTPUTSTATUS, &con_output_enable); if (ret == TD_SUCCESS) { *enable = con_output_enable.con_output_enable; } return ret; } td_s32 ext_mpi_ao_set_output_latency_mode(ao_snd_id sound, ext_ao_output_latency mode) { ao_snd_output_latency_mode output_mode = { .sound = sound, .output_mode = mode, }; return ioctl(g_ao_fd, CMD_AO_SND_SETOUTPUTLATENCYMODE, &output_mode); } td_s32 ext_mpi_ao_get_output_latency_mode(ao_snd_id sound, ext_ao_output_latency *mode) { td_s32 ret; ao_snd_output_latency_mode output_mode = { .sound = sound, .output_mode = EXT_AO_OUTPUT_LATENCY_MAX, }; check_ao_null_ptr(mode); ret = ioctl(g_ao_fd, CMD_AO_SND_GETOUTPUTLATENCYMODE, &output_mode); if (ret == TD_SUCCESS) { *mode = output_mode.output_mode; } return ret; } td_s32 ext_mpi_ao_track_set_config(td_handle track, const td_void *config) { TD_UNUSED(track); check_ao_null_ptr(config); return SOC_ERR_AO_NOTSUPPORT; } td_s32 ext_mpi_ao_track_get_config(td_handle track, td_void *config) { TD_UNUSED(track); check_ao_null_ptr(config); return SOC_ERR_AO_NOTSUPPORT; } td_s32 ext_mpi_ao_snd_set_atmos_lock_enable(ao_snd_id sound, td_bool atmos_lock_enable) { TD_UNUSED(sound); TD_UNUSED(atmos_lock_enable); return SOC_ERR_AO_NOTSUPPORT; } td_s32 ext_mpi_ao_snd_get_atmos_lock_enable(ao_snd_id sound, td_bool *atmos_lock_enable) { TD_UNUSED(sound); check_ao_null_ptr(atmos_lock_enable); return SOC_ERR_AO_NOTSUPPORT; } td_s32 ext_mpi_ao_snd_start_render(ao_snd_id sound, ext_ao_render_attr *attr) { TD_UNUSED(sound); check_ao_null_ptr(attr); return SOC_ERR_AO_NOTSUPPORT; } td_s32 ext_mpi_ao_snd_stop_render(ao_snd_id sound) { TD_UNUSED(sound); return SOC_ERR_AO_NOTSUPPORT; } td_s32 ext_mpi_ao_snd_set_all_track_prescale(ao_snd_id sound, const ext_ao_preci_gain *prescale) { td_s32 ret; ao_snd_all_track_prescale_param prescale_param = { .sound = sound, }; check_ao_null_ptr(prescale); ret = memcpy_s(&prescale_param.all_track_prescale, sizeof(ext_ao_preci_gain), prescale, sizeof(*prescale)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } ret = ioctl(g_ao_fd, CMD_AO_SND_SETALLTRACKPRESCALE, &prescale_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_SETALLTRACKPRESCALE failed(0x%x)\n", ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_snd_get_all_track_prescale(ao_snd_id sound, ext_ao_preci_gain *prescale) { td_s32 ret; ao_snd_all_track_prescale_param prescale_param = { .sound = sound, }; check_ao_null_ptr(prescale); ret = ioctl(g_ao_fd, CMD_AO_SND_GETALLTRACKPRESCALE, &prescale_param); if (ret != TD_SUCCESS) { soc_log_err("ioctl CMD_AO_SND_GETALLTRACKPRESCALE failed(0x%x)\n", ret); return ret; } ret = memcpy_s(prescale, sizeof(*prescale), &prescale_param.all_track_prescale, sizeof(ext_ao_preci_gain)); if (ret != EOK) { soc_log_err("memcpy_s failed(0x%x)\n", ret); return ret; } return TD_SUCCESS; } /* this api is called by adec and avplay */ td_s32 ext_mpi_ao_track_is_codec_support(td_u32 codec_id, td_bool *support) { TD_UNUSED(codec_id); check_ao_null_ptr(support); *support = TD_FALSE; return TD_SUCCESS; } td_s32 ext_mpi_ao_track_is_render_support(td_bool *support) { check_ao_null_ptr(support); *support = TD_FALSE; return TD_SUCCESS; } static td_s32 mpi_ao_attach(td_u32 module_id, td_handle track, td_handle source) { td_s32 ret; ext_ao_ext_module_fn ao_func = { TD_NULL, TD_NULL }; ret = ext_mpi_ao_get_extern_func(module_id, &ao_func); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ext_mpi_ao_get_extern_func, ret); return ret; } if (ao_func.attach == TD_NULL) { return SOC_ERR_AO_NOTSUPPORT; } return ao_func.attach(source, track); } static td_s32 mpi_ao_detach(td_u32 module_id, td_handle track, td_handle source) { td_s32 ret; ext_ao_ext_module_fn ao_func = { TD_NULL, TD_NULL }; ret = ext_mpi_ao_get_extern_func(module_id, &ao_func); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ext_mpi_ao_get_extern_func, ret); return ret; } if (ao_func.detach == TD_NULL) { return SOC_ERR_AO_NOTSUPPORT; } return ao_func.detach(source, track); } #define check_ai_handle(ai) (((ai) >> 16) == SOC_ID_AI) #define check_avplay_handle(avplay) (((avplay) >> 24) == SOC_ID_AVPLAY) td_s32 ext_mpi_ao_attach(td_handle track, td_handle source) { td_s32 ret; td_u32 module_id; if (check_avplay_handle(source)) { module_id = SOC_ID_AVPLAY; } else if (check_ai_handle(source)) { module_id = SOC_ID_AI; } else { return SOC_ERR_AO_INVALID_PARA; } ret = mpi_ao_attach(module_id, track, source); if (ret != TD_SUCCESS) { soc_err_print_h32(source); soc_err_print_call_fun_err(mpi_ao_attach, ret); return ret; } return TD_SUCCESS; } td_s32 ext_mpi_ao_detach(td_handle track, td_handle source) { td_u32 module_id; td_s32 ret; if (check_avplay_handle(source)) { module_id = SOC_ID_AVPLAY; } else if (check_ai_handle(source)) { module_id = SOC_ID_AI; } else { return SOC_ERR_AO_INVALID_PARA; } ret = mpi_ao_detach(module_id, track, source); if (ret != TD_SUCCESS) { soc_err_print_h32(source); soc_err_print_call_fun_err(mpi_ao_detach, ret); return ret; } ret = ext_mpi_ao_track_stop(track); if (ret != TD_SUCCESS) { soc_err_print_h32(track); soc_err_print_call_fun_err(ext_mpi_ao_track_stop, ret); return ret; } return TD_SUCCESS; } /* mixer plugin */ td_s32 ext_mpi_ao_set_mixer_plugin_enable(ao_snd_id sound, td_bool enable) { return snd_mixer_set_engine_plugin_enable(sound, enable); } td_s32 ext_mpi_ao_get_mixer_plugin_enable(ao_snd_id sound, td_bool *enable) { return snd_mixer_get_engine_plugin_enable(sound, enable); } td_s32 ext_mpi_ao_acquire_mixer_plugin_frontout_stream(ao_snd_id sound, td_u32 require_size, ext_audio_mixer_plugin_frame *frontout_frame, td_u32 timeout_ms) { check_ao_null_ptr(frontout_frame); return snd_mixer_acquire_engine_plugin_frontout_stream(sound, require_size, frontout_frame, timeout_ms); } td_s32 ext_mpi_ao_release_mixer_plugin_frontout_stream(ao_snd_id sound, const ext_audio_mixer_plugin_frame *frontout_frame) { check_ao_null_ptr(frontout_frame); return snd_mixer_release_engine_plugin_frontout_stream(sound, frontout_frame); } td_s32 ext_mpi_ao_get_mixer_plugin_backin_buffer(ao_snd_id sound, td_u32 require_size, ext_audio_mixer_plugin_frame *backin_frame, td_u32 timeout_ms) { check_ao_null_ptr(backin_frame); return snd_mixer_get_engine_plugin_backin_buffer(sound, require_size, backin_frame, timeout_ms); } td_s32 ext_mpi_ao_put_mixer_plugin_backin_buffer(ao_snd_id sound, const ext_audio_mixer_plugin_frame *backin_frame) { check_ao_null_ptr(backin_frame); return snd_mixer_put_engine_plugin_backin_buffer(sound, backin_frame); } td_s32 ext_mpi_ao_set_mixer_plugin_param(ao_snd_id sound, const ext_ao_mixer_plugin_param *param) { TD_UNUSED(sound); check_ao_null_ptr(param); return SOC_ERR_AO_NOTSUPPORT; } td_s32 ext_mpi_ao_get_mixer_plugin_param(ao_snd_id sound, ext_ao_mixer_plugin_param *param) { TD_UNUSED(sound); check_ao_null_ptr(param); return SOC_ERR_AO_NOTSUPPORT; } #ifdef __cplusplus #if __cplusplus } #endif #endif /* __cplusplus */