/* * Copyright (c) 2016 Actions Semi Co., Inc. * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief audio stream. */ #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_BLUETOOTH #include #endif #define SYS_LOG_NO_NEWLINE #ifdef SYS_LOG_DOMAIN #undef SYS_LOG_DOMAIN #endif #define SYS_LOG_DOMAIN "audio_aps" #define AUDIO_APS_ADJUST_INTERVAL 30 static aps_monitor_info_t aps_monitor; aps_monitor_info_t *audio_aps_monitor_get_instance(void) { return &aps_monitor; } void audio_aps_monitor_set_aps(void *audio_handle, uint8_t status, int level) { aps_monitor_info_t *handle = audio_aps_monitor_get_instance(); uint8_t aps_mode = APS_LEVEL_AUDIOPLL; uint8_t set_aps = false; if (status & APS_OPR_SET) { handle->dest_level = level; } if (status & APS_OPR_FAST_SET) { handle->dest_level = level; handle->current_level = level; set_aps = true; } if (handle->current_level > handle->dest_level) { handle->current_level--; set_aps = true; } if (handle->current_level < handle->dest_level) { handle->current_level++; set_aps = true; } if (set_aps) { SYS_LOG_DBG("adjust mode %d: %d\n", aps_mode, handle->current_level); hal_aout_channel_set_aps(audio_handle, handle->current_level, aps_mode); } } void audio_aps_monitor_normal(aps_monitor_info_t *handle, int stream_length, uint8_t aps_max_level, uint8_t aps_min_level, uint8_t aps_level) { void *audio_handle = handle->audio_track->audio_handle; uint16_t mid_threshold = 0; uint16_t diff_threshold = 0; /* SYS_LOG_INF("---in stream --- %d out stream %d\n",stream_length, stream_get_length(audio_track_get_stream(handle->audio_track))); */ if (!handle->need_aps) { return; } diff_threshold = (handle->aps_increase_water_mark - handle->aps_reduce_water_mark); mid_threshold = handle->aps_increase_water_mark - (diff_threshold / 2); switch (handle->aps_status) { case APS_STATUS_DEFAULT: if (stream_length > handle->aps_increase_water_mark) { SYS_LOG_DBG("inc aps\n"); audio_aps_monitor_set_aps(audio_handle, APS_OPR_FAST_SET, aps_max_level); handle->aps_status = APS_STATUS_INC; } else if (stream_length < handle->aps_reduce_water_mark) { SYS_LOG_DBG("fast dec aps\n"); audio_aps_monitor_set_aps(audio_handle, APS_OPR_FAST_SET, aps_min_level); handle->aps_status = APS_STATUS_DEC; } else { audio_aps_monitor_set_aps(audio_handle, APS_OPR_ADJUST, 0); } break; case APS_STATUS_INC: if (stream_length < handle->aps_reduce_water_mark) { SYS_LOG_DBG("fast dec aps\n"); audio_aps_monitor_set_aps(audio_handle, APS_OPR_FAST_SET, aps_min_level); handle->aps_status = APS_STATUS_DEC; } else if (stream_length <= mid_threshold) { SYS_LOG_DBG("default aps\n"); audio_aps_monitor_set_aps(audio_handle, APS_OPR_SET, aps_level); handle->aps_status = APS_STATUS_DEFAULT; } else { audio_aps_monitor_set_aps(audio_handle, APS_OPR_ADJUST, 0); } break; case APS_STATUS_DEC: if (stream_length > handle->aps_increase_water_mark) { SYS_LOG_DBG("fast inc aps\n"); audio_aps_monitor_set_aps(audio_handle, APS_OPR_FAST_SET, aps_max_level); handle->aps_status = APS_STATUS_INC; } else if (stream_length >= mid_threshold) { SYS_LOG_DBG("default aps\n"); audio_aps_monitor_set_aps(audio_handle, APS_OPR_SET, aps_level); handle->aps_status = APS_STATUS_DEFAULT; } else { audio_aps_monitor_set_aps(audio_handle, APS_OPR_ADJUST, 0); } break; } } extern void audio_aps_monitor_slave(aps_monitor_info_t *handle, int stream_length, uint8_t aps_max_level, uint8_t aps_min_level, uint8_t slave_aps_level); extern void audio_aps_monitor_master(aps_monitor_info_t *handle, int stream_length, uint8_t aps_max_level, uint8_t aps_min_level, uint8_t slave_aps_level); /* Run interval DATA_PROCESS_PERIOD = (4) */ void audio_aps_monitor(int pcm_time) { aps_monitor_info_t *handle = audio_aps_monitor_get_instance(); static uint32_t s_time; /* Adjust aps every AUDIO_APS_ADJUST_INTERVAL */ if ((k_uptime_get_32() - s_time) < handle->duration) { return; } s_time = k_uptime_get_32(); #ifdef CONFIG_TWS if (handle->role == BTSRV_TWS_NONE) { audio_aps_monitor_normal(handle, pcm_time, handle->aps_max_level, handle->aps_min_level, handle->aps_default_level); } else if (handle->role == BTSRV_TWS_MASTER) { audio_aps_monitor_master(handle, pcm_time, handle->aps_max_level, handle->aps_min_level, handle->aps_default_level); } else if (handle->role == BTSRV_TWS_SLAVE) { audio_aps_monitor_slave(handle, pcm_time, handle->aps_max_level, handle->aps_min_level, handle->current_level); } #else audio_aps_monitor_normal(handle, pcm_time, handle->aps_max_level, handle->aps_min_level, handle->aps_default_level); #endif } void audio_aps_monitor_init(int format, void *tws_observer, struct audio_track_t *audio_track) { aps_monitor_info_t *handle = audio_aps_monitor_get_instance(); SYS_LOG_INF("tws_observer %p audio_track %p\n", tws_observer, audio_track); memset(handle, 0, sizeof(aps_monitor_info_t)); handle->audio_track = audio_track; handle->aps_status = APS_STATUS_DEFAULT; handle->aps_min_level = APS_LEVEL_1; handle->aps_max_level = APS_LEVEL_8; handle->aps_default_level = APS_LEVEL_4; /* Default water mark: no aps adjustment */ handle->aps_increase_water_mark = UINT16_MAX; handle->aps_reduce_water_mark = 0; handle->need_aps = 1; handle->aps_increase_water_mark = audio_policy_get_increase_threshold(format); handle->aps_reduce_water_mark = audio_policy_get_reduce_threshold(format); handle->duration = AUDIO_APS_ADJUST_INTERVAL; switch (format) { case SBC_TYPE: { if (system_check_low_latencey_mode()) { handle->aps_min_level = APS_LEVEL_3; handle->aps_max_level = APS_LEVEL_6; handle->duration = 6; } #ifdef CONFIG_TWS if (tws_observer) { audio_aps_monitor_tws_init(tws_observer); audio_track_set_waitto_start(audio_track, true); } #endif break; } case AAC_TYPE: { if (system_check_low_latencey_mode()) { handle->aps_min_level = APS_LEVEL_3; handle->aps_max_level = APS_LEVEL_6; handle->duration = 6; } #ifdef CONFIG_TWS if (tws_observer) { audio_aps_monitor_tws_init(tws_observer); audio_track_set_waitto_start(audio_track, true); } #endif break; } case MSBC_TYPE: case CVSD_TYPE: { if (system_check_low_latencey_mode()) { handle->aps_min_level = APS_LEVEL_3; handle->aps_max_level = APS_LEVEL_6; handle->duration = 6; } handle->aps_default_level = APS_LEVEL_5; break; } case ACT_TYPE: { break; } case PCM_TYPE: { handle->aps_min_level = APS_LEVEL_3; handle->aps_max_level = APS_LEVEL_6; if (system_check_low_latencey_mode()) { handle->aps_default_level = APS_LEVEL_4; } #ifdef CONFIG_TWS if (tws_observer) { audio_aps_monitor_tws_init(tws_observer); audio_track_set_waitto_start(audio_track, true); } #endif break; } case NAV_TYPE: { handle->aps_min_level = APS_LEVEL_2; handle->aps_max_level = APS_LEVEL_6; if (system_check_low_latencey_mode()) { handle->aps_default_level = APS_LEVEL_3; } #ifdef CONFIG_TWS if (tws_observer) { audio_aps_monitor_tws_init(tws_observer); audio_track_set_waitto_start(audio_track, true); } #endif audio_track_set_waitto_start(audio_track, true); break; } default: { handle->need_aps = 0; handle->current_level = handle->aps_default_level; audio_aps_monitor_set_aps(audio_track->audio_handle, APS_OPR_FAST_SET, handle->current_level); #ifdef CONFIG_TWS if (tws_observer) { audio_aps_monitor_tws_init(tws_observer); audio_track_set_waitto_start(audio_track, true); } #endif break; } } handle->current_level = handle->aps_default_level; handle->dest_level = handle->current_level; } void audio_aps_notify_decode_err(uint16_t err_cnt) { #ifdef CONFIG_TWS audio_aps_tws_notify_decode_err(err_cnt); #endif } void audio_aps_monitor_deinit(int format, void *tws_observer, struct audio_track_t *audio_track) { #ifdef CONFIG_TWS /* Be consistent with audio_aps_monitor_init */ switch (format) { case ACT_TYPE: case MSBC_TYPE: case CVSD_TYPE: break; case SBC_TYPE: case AAC_TYPE: default: if (tws_observer) { audio_aps_monitor_tws_deinit(tws_observer); } break; } #endif }